diff --git a/dev/tools/localization/bin/gen_date_localizations.dart b/dev/tools/localization/bin/gen_date_localizations.dart index 7507648407..5da786a05e 100644 --- a/dev/tools/localization/bin/gen_date_localizations.dart +++ b/dev/tools/localization/bin/gen_date_localizations.dart @@ -75,6 +75,7 @@ Future main(List rawArgs) async { final Directory datePatternsDirectory = Directory(path.join(pathToIntl, 'src', 'data', 'dates', 'patterns')); final Map patternFiles = _listIntlData(datePatternsDirectory); final StringBuffer buffer = StringBuffer(); + final Set supportedLocales = _supportedLocales(); buffer.writeln( ''' @@ -94,7 +95,7 @@ Future main(List rawArgs) async { buffer.writeln('const Map dateSymbols = {'); symbolFiles.forEach((String locale, File data) { currentLocale = locale; - if (_supportedLocales().contains(locale)) + if (supportedLocales.contains(locale)) buffer.writeln(_jsonToMapEntry(locale, json.decode(data.readAsStringSync()))); }); currentLocale = null; @@ -107,7 +108,7 @@ Future main(List rawArgs) async { /// supported by flutter_localizations.'''); buffer.writeln('const Map> datePatterns = > {'); patternFiles.forEach((String locale, File data) { - if (_supportedLocales().contains(locale)) { + if (supportedLocales.contains(locale)) { final Map patterns = json.decode(data.readAsStringSync()) as Map; buffer.writeln("'$locale': {"); patterns.forEach((String key, dynamic value) { @@ -164,13 +165,21 @@ String _jsonToMap(dynamic json) { } Set _supportedLocales() { - final Set supportedLocales = {}; + // Assumes that en_US is a supported locale by default. Without this, usage + // of the intl package APIs before Flutter populates its set of supported i18n + // date patterns and symbols may cause problems. + // + // For more context, see https://github.com/flutter/flutter/issues/67644. + final Set supportedLocales = { + 'en_US', + }; final RegExp filenameRE = RegExp(r'(?:material|cupertino)_(\w+)\.arb$'); final Directory supportedLocalesDirectory = Directory(path.join('packages', 'flutter_localizations', 'lib', 'src', 'l10n')); for (final FileSystemEntity entity in supportedLocalesDirectory.listSync()) { final String filePath = entity.path; - if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath)) + if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath)) { supportedLocales.add(filenameRE.firstMatch(filePath)[1]); + } } return supportedLocales; diff --git a/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart b/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart index dde7b2ac3c..04f1869599 100644 --- a/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart +++ b/packages/flutter_localizations/lib/src/l10n/generated_date_localizations.dart @@ -4001,6 +4001,196 @@ const Map dateSymbols = { '{1}, {0}', ], }, + 'en_US': { + 'NAME': 'en_US', + 'ERAS': [ + 'BC', + 'AD', + ], + 'ERANAMES': [ + 'Before Christ', + 'Anno Domini', + ], + 'NARROWMONTHS': [ + 'J', + 'F', + 'M', + 'A', + 'M', + 'J', + 'J', + 'A', + 'S', + 'O', + 'N', + 'D', + ], + 'STANDALONENARROWMONTHS': [ + 'J', + 'F', + 'M', + 'A', + 'M', + 'J', + 'J', + 'A', + 'S', + 'O', + 'N', + 'D', + ], + 'MONTHS': [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + 'STANDALONEMONTHS': [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + 'SHORTMONTHS': [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], + 'STANDALONESHORTMONTHS': [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], + 'WEEKDAYS': [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], + 'STANDALONEWEEKDAYS': [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], + 'SHORTWEEKDAYS': [ + 'Sun', + 'Mon', + 'Tue', + 'Wed', + 'Thu', + 'Fri', + 'Sat', + ], + 'STANDALONESHORTWEEKDAYS': [ + 'Sun', + 'Mon', + 'Tue', + 'Wed', + 'Thu', + 'Fri', + 'Sat', + ], + 'NARROWWEEKDAYS': [ + 'S', + 'M', + 'T', + 'W', + 'T', + 'F', + 'S', + ], + 'STANDALONENARROWWEEKDAYS': [ + 'S', + 'M', + 'T', + 'W', + 'T', + 'F', + 'S', + ], + 'SHORTQUARTERS': [ + 'Q1', + 'Q2', + 'Q3', + 'Q4', + ], + 'QUARTERS': [ + '1st quarter', + '2nd quarter', + '3rd quarter', + '4th quarter', + ], + 'AMPMS': [ + 'AM', + 'PM', + ], + 'DATEFORMATS': [ + 'EEEE, MMMM d, y', + 'MMMM d, y', + 'MMM d, y', + 'M/d/yy', + ], + 'TIMEFORMATS': [ + 'h:mm:ss a zzzz', + 'h:mm:ss a z', + 'h:mm:ss a', + 'h:mm a', + ], + 'AVAILABLEFORMATS': null, + 'FIRSTDAYOFWEEK': 6, + 'WEEKENDRANGE': [ + 5, + 6, + ], + 'FIRSTWEEKCUTOFFDAY': 5, + 'DATETIMEFORMATS': [ + '{1} \'at\' {0}', + '{1} \'at\' {0}', + '{1}, {0}', + '{1}, {0}', + ], + }, 'en_ZA': { 'NAME': 'en_ZA', 'ERAS': [ @@ -18658,6 +18848,52 @@ const Map> datePatterns = 'zzzz': 'zzzz', 'ZZZZ': 'ZZZZ', }, + 'en_US': { + 'd': 'd', + 'E': 'ccc', + 'EEEE': 'cccc', + 'LLL': 'LLL', + 'LLLL': 'LLLL', + 'M': 'L', + 'Md': 'M/d', + 'MEd': 'EEE, M/d', + 'MMM': 'LLL', + 'MMMd': 'MMM d', + 'MMMEd': 'EEE, MMM d', + 'MMMM': 'LLLL', + 'MMMMd': 'MMMM d', + 'MMMMEEEEd': 'EEEE, MMMM d', + 'QQQ': 'QQQ', + 'QQQQ': 'QQQQ', + 'y': 'y', + 'yM': 'M/y', + 'yMd': 'M/d/y', + 'yMEd': 'EEE, M/d/y', + 'yMMM': 'MMM y', + 'yMMMd': 'MMM d, y', + 'yMMMEd': 'EEE, MMM d, y', + 'yMMMM': 'MMMM y', + 'yMMMMd': 'MMMM d, y', + 'yMMMMEEEEd': 'EEEE, MMMM d, y', + 'yQQQ': 'QQQ y', + 'yQQQQ': 'QQQQ y', + 'H': 'HH', + 'Hm': 'HH:mm', + 'Hms': 'HH:mm:ss', + 'j': 'h a', + 'jm': 'h:mm a', + 'jms': 'h:mm:ss a', + 'jmv': 'h:mm a v', + 'jmz': 'h:mm a z', + 'jz': 'h a z', + 'm': 'm', + 'ms': 'mm:ss', + 's': 's', + 'v': 'v', + 'z': 'z', + 'zzzz': 'zzzz', + 'ZZZZ': 'ZZZZ', + }, 'en_ZA': { 'd': 'd', 'E': 'ccc', diff --git a/packages/flutter_localizations/lib/src/utils/date_localizations.dart b/packages/flutter_localizations/lib/src/utils/date_localizations.dart index 9b0abd856b..b6768090a6 100644 --- a/packages/flutter_localizations/lib/src/utils/date_localizations.dart +++ b/packages/flutter_localizations/lib/src/utils/date_localizations.dart @@ -9,17 +9,18 @@ import '../l10n/generated_date_localizations.dart' as date_localizations; /// Tracks if date i18n data has been loaded. bool _dateIntlDataInitialized = false; -/// Loads i18n data for dates if it hasn't be loaded yet. +/// Loads i18n data for dates if it hasn't been loaded yet. /// -/// Only the first invocation of this function has the effect of loading the -/// data. Subsequent invocations have no effect. +/// Only the first invocation of this function loads the data. Subsequent +/// invocations have no effect. void loadDateIntlDataIfNotLoaded() { if (!_dateIntlDataInitialized) { // TODO(garyq): Add support for scriptCodes. Do not strip scriptCode from string. - // Keep track of initialzed locales, or will fail on attempted double init. - // This can only happen if a locale with a stripped scriptCode has already - // been initialzed. This should be removed when scriptCode stripping is removed. + // Keeps track of initialized locales. This can only happen if a locale + // with a stripped scriptCode has already been initialzed. The set of + // initialized locales should be removed when scriptCode stripping is + // removed. final Set initializedLocales = {}; date_localizations.dateSymbols .cast>() diff --git a/packages/flutter_localizations/test/material/date_time_test.dart b/packages/flutter_localizations/test/material/date_time_test.dart index 0b7960630a..1b475f27d8 100644 --- a/packages/flutter_localizations/test/material/date_time_test.dart +++ b/packages/flutter_localizations/test/material/date_time_test.dart @@ -7,6 +7,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:intl/intl.dart'; void main() { group(GlobalMaterialLocalizations, () { @@ -159,6 +160,28 @@ void main() { }); }); }); + + // Regression test for https://github.com/flutter/flutter/issues/67644. + testWidgets('en_US is initialized correctly by Flutter when DateFormat is used', (WidgetTester tester) async { + DateFormat dateFormat; + + await tester.pumpWidget(MaterialApp( + supportedLocales: const [ + Locale('en', 'US'), + ], + locale: const Locale('en', 'US'), + localizationsDelegates: const >[ + GlobalMaterialLocalizations.delegate, + ], + home: Builder(builder: (BuildContext context) { + dateFormat = DateFormat('EEE, d MMM yyyy HH:mm:ss', 'en_US'); + + return Container(); + }), + )); + + expect(dateFormat?.locale, 'en_US'); + }); } enum DateType { year, medium, full, monthYear }