Migrate flutter_localizations to null safety. (#68645)

Migrate flutter_localizations to null safety.
This commit is contained in:
Darren Austin 2020-11-12 15:13:51 -08:00 committed by GitHub
parent 2a5aa29442
commit 1c7e34bb20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 5532 additions and 5401 deletions

View File

@ -704,7 +704,7 @@ Future<void> _runFrameworkTests() async {
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tableData: bigqueryApi?.tabledata, tests: <String>[path.join('test', 'src', 'real_tests')]); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_driver'), tableData: bigqueryApi?.tabledata, tests: <String>[path.join('test', 'src', 'real_tests')]);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'integration_test'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'integration_test'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_goldens'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata, options: soundNullSafetyOptions);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata, options: soundNullSafetyOptions); await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata, options: soundNullSafetyOptions);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), tableData: bigqueryApi?.tabledata); await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'), options: mixedModeNullSafetyOptions); await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'), options: mixedModeNullSafetyOptions);

View File

@ -382,15 +382,20 @@ $factoryDeclaration
/// ///
/// Used by [generateGetter] below. /// Used by [generateGetter] below.
String generateType(Map<String, dynamic> attributes) { String generateType(Map<String, dynamic> attributes) {
bool optional = false;
String type = 'String';
if (attributes != null) { if (attributes != null) {
optional = attributes.containsKey('optional');
switch (attributes['x-flutter-type'] as String) { switch (attributes['x-flutter-type'] as String) {
case 'icuShortTimePattern': case 'icuShortTimePattern':
return 'TimeOfDayFormat'; type = 'TimeOfDayFormat';
break;
case 'scriptCategory': case 'scriptCategory':
return 'ScriptCategory'; type = 'ScriptCategory';
break;
} }
} }
return 'String'; return type + (optional ? '?' : '');
} }
/// Returns the appropriate name for getters with the given attributes. /// Returns the appropriate name for getters with the given attributes.

View File

@ -16,7 +16,6 @@ HeaderGenerator generateCupertinoHeader = (String regenerateInstructions) {
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:intl/intl.dart' as intl; import 'package:intl/intl.dart' as intl;
@ -40,14 +39,14 @@ ConstructorGenerator generateCupertinoConstructor = (LocaleInfo locale) {
/// For details on the meaning of the arguments, see [GlobalCupertinoLocalizations]. /// For details on the meaning of the arguments, see [GlobalCupertinoLocalizations].
const CupertinoLocalization${locale.camelCase()}({ const CupertinoLocalization${locale.camelCase()}({
String localeName = '$localeName', String localeName = '$localeName',
@required intl.DateFormat fullYearFormat, required intl.DateFormat fullYearFormat,
@required intl.DateFormat dayFormat, required intl.DateFormat dayFormat,
@required intl.DateFormat mediumDateFormat, required intl.DateFormat mediumDateFormat,
@required intl.DateFormat singleDigitHourFormat, required intl.DateFormat singleDigitHourFormat,
@required intl.DateFormat singleDigitMinuteFormat, required intl.DateFormat singleDigitMinuteFormat,
@required intl.DateFormat doubleDigitMinuteFormat, required intl.DateFormat doubleDigitMinuteFormat,
@required intl.DateFormat singleDigitSecondFormat, required intl.DateFormat singleDigitSecondFormat,
@required intl.NumberFormat decimalFormat, required intl.NumberFormat decimalFormat,
}) : super( }) : super(
localeName: localeName, localeName: localeName,
fullYearFormat: fullYearFormat, fullYearFormat: fullYearFormat,
@ -64,7 +63,7 @@ ConstructorGenerator generateCupertinoConstructor = (LocaleInfo locale) {
const String cupertinoFactoryName = 'getCupertinoTranslation'; const String cupertinoFactoryName = 'getCupertinoTranslation';
const String cupertinoFactoryDeclaration = ''' const String cupertinoFactoryDeclaration = '''
GlobalCupertinoLocalizations getCupertinoTranslation( GlobalCupertinoLocalizations? getCupertinoTranslation(
Locale locale, Locale locale,
intl.DateFormat fullYearFormat, intl.DateFormat fullYearFormat,
intl.DateFormat dayFormat, intl.DateFormat dayFormat,

View File

@ -16,7 +16,6 @@ HeaderGenerator generateMaterialHeader = (String regenerateInstructions) {
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl; import 'package:intl/intl.dart' as intl;
@ -40,15 +39,15 @@ ConstructorGenerator generateMaterialConstructor = (LocaleInfo locale) {
/// For details on the meaning of the arguments, see [GlobalMaterialLocalizations]. /// For details on the meaning of the arguments, see [GlobalMaterialLocalizations].
const MaterialLocalization${locale.camelCase()}({ const MaterialLocalization${locale.camelCase()}({
String localeName = '$localeName', String localeName = '$localeName',
@required intl.DateFormat fullYearFormat, required intl.DateFormat fullYearFormat,
@required intl.DateFormat compactDateFormat, required intl.DateFormat compactDateFormat,
@required intl.DateFormat shortDateFormat, required intl.DateFormat shortDateFormat,
@required intl.DateFormat mediumDateFormat, required intl.DateFormat mediumDateFormat,
@required intl.DateFormat longDateFormat, required intl.DateFormat longDateFormat,
@required intl.DateFormat yearMonthFormat, required intl.DateFormat yearMonthFormat,
@required intl.DateFormat shortMonthDayFormat, required intl.DateFormat shortMonthDayFormat,
@required intl.NumberFormat decimalFormat, required intl.NumberFormat decimalFormat,
@required intl.NumberFormat twoDigitZeroPaddedFormat, required intl.NumberFormat twoDigitZeroPaddedFormat,
}) : super( }) : super(
localeName: localeName, localeName: localeName,
fullYearFormat: fullYearFormat, fullYearFormat: fullYearFormat,
@ -66,7 +65,7 @@ ConstructorGenerator generateMaterialConstructor = (LocaleInfo locale) {
const String materialFactoryName = 'getMaterialTranslation'; const String materialFactoryName = 'getMaterialTranslation';
const String materialFactoryDeclaration = ''' const String materialFactoryDeclaration = '''
GlobalMaterialLocalizations getMaterialTranslation( GlobalMaterialLocalizations? getMaterialTranslation(
Locale locale, Locale locale,
intl.DateFormat fullYearFormat, intl.DateFormat fullYearFormat,
intl.DateFormat compactDateFormat, intl.DateFormat compactDateFormat,

View File

@ -67,8 +67,9 @@ void validateEnglishLocalizations(File file) {
continue; continue;
} }
final bool optional = atResource.containsKey('optional');
final String description = atResource['description'] as String; final String description = atResource['description'] as String;
if (description == null) if (description == null && !optional)
errorMessages.writeln('No description specified for $atResourceId'); errorMessages.writeln('No description specified for $atResourceId');
final String plural = atResource['plural'] as String; final String plural = atResource['plural'] as String;
@ -78,7 +79,7 @@ void validateEnglishLocalizations(File file) {
if (!bundle.containsKey(resourceIdOther)) if (!bundle.containsKey(resourceIdOther))
errorMessages.writeln('Default plural resource $resourceIdOther undefined'); errorMessages.writeln('Default plural resource $resourceIdOther undefined');
} else { } else {
if (!bundle.containsKey(resourceId)) if (!optional && !bundle.containsKey(resourceId))
errorMessages.writeln('No matching $resourceId defined for $atResourceId'); errorMessages.writeln('No matching $resourceId defined for $atResourceId');
} }
} }

View File

@ -1763,9 +1763,10 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
}); });
}, },
children: List<Widget>.generate(24, (int index) { children: List<Widget>.generate(24, (int index) {
final String label = localizations.timerPickerHourLabel(index) ?? '';
final String semanticsLabel = textDirectionFactor == 1 final String semanticsLabel = textDirectionFactor == 1
? localizations.timerPickerHour(index) + localizations.timerPickerHourLabel(index) ? localizations.timerPickerHour(index) + label
: localizations.timerPickerHourLabel(index) + localizations.timerPickerHour(index); : label + localizations.timerPickerHour(index);
return Semantics( return Semantics(
label: semanticsLabel, label: semanticsLabel,
@ -1793,7 +1794,7 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
child: _buildHourPicker(additionalPadding, selectionOverlay), child: _buildHourPicker(additionalPadding, selectionOverlay),
), ),
_buildLabel( _buildLabel(
localizations.timerPickerHourLabel(lastSelectedHour ?? selectedHour!), localizations.timerPickerHourLabel(lastSelectedHour ?? selectedHour!) ?? '',
additionalPadding, additionalPadding,
), ),
], ],
@ -1826,10 +1827,10 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
}, },
children: List<Widget>.generate(60 ~/ widget.minuteInterval, (int index) { children: List<Widget>.generate(60 ~/ widget.minuteInterval, (int index) {
final int minute = index * widget.minuteInterval; final int minute = index * widget.minuteInterval;
final String label = localizations.timerPickerMinuteLabel(minute) ?? '';
final String semanticsLabel = textDirectionFactor == 1 final String semanticsLabel = textDirectionFactor == 1
? localizations.timerPickerMinute(minute) + localizations.timerPickerMinuteLabel(minute) ? localizations.timerPickerMinute(minute) + label
: localizations.timerPickerMinuteLabel(minute) + localizations.timerPickerMinute(minute); : label + localizations.timerPickerMinute(minute);
return Semantics( return Semantics(
label: semanticsLabel, label: semanticsLabel,
@ -1857,7 +1858,7 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
child: _buildMinutePicker(additionalPadding, selectionOverlay), child: _buildMinutePicker(additionalPadding, selectionOverlay),
), ),
_buildLabel( _buildLabel(
localizations.timerPickerMinuteLabel(lastSelectedMinute ?? selectedMinute), localizations.timerPickerMinuteLabel(lastSelectedMinute ?? selectedMinute) ?? '',
additionalPadding, additionalPadding,
), ),
], ],
@ -1890,10 +1891,10 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
}, },
children: List<Widget>.generate(60 ~/ widget.secondInterval, (int index) { children: List<Widget>.generate(60 ~/ widget.secondInterval, (int index) {
final int second = index * widget.secondInterval; final int second = index * widget.secondInterval;
final String label = localizations.timerPickerSecondLabel(second) ?? '';
final String semanticsLabel = textDirectionFactor == 1 final String semanticsLabel = textDirectionFactor == 1
? localizations.timerPickerSecond(second) + localizations.timerPickerSecondLabel(second) ? localizations.timerPickerSecond(second) + label
: localizations.timerPickerSecondLabel(second) + localizations.timerPickerSecond(second); : label + localizations.timerPickerSecond(second);
return Semantics( return Semantics(
label: semanticsLabel, label: semanticsLabel,
@ -1921,7 +1922,7 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> {
child: _buildSecondPicker(additionalPadding, selectionOverlay), child: _buildSecondPicker(additionalPadding, selectionOverlay),
), ),
_buildLabel( _buildLabel(
localizations.timerPickerSecondLabel(lastSelectedSecond ?? selectedSecond!), localizations.timerPickerSecondLabel(lastSelectedSecond ?? selectedSecond!) ?? '',
additionalPadding, additionalPadding,
), ),
], ],

View File

@ -108,7 +108,7 @@ abstract class CupertinoLocalizations {
/// Semantics label for the given hour value in [CupertinoDatePicker]. /// Semantics label for the given hour value in [CupertinoDatePicker].
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String datePickerHourSemanticsLabel(int hour); String? datePickerHourSemanticsLabel(int hour);
/// Minute that is shown in [CupertinoDatePicker] spinner corresponding /// Minute that is shown in [CupertinoDatePicker] spinner corresponding
/// to the given minute value. /// to the given minute value.
@ -122,7 +122,7 @@ abstract class CupertinoLocalizations {
/// Semantics label for the given minute value in [CupertinoDatePicker]. /// Semantics label for the given minute value in [CupertinoDatePicker].
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String datePickerMinuteSemanticsLabel(int minute); String? datePickerMinuteSemanticsLabel(int minute);
/// The order of the date elements that will be shown in [CupertinoDatePicker]. /// The order of the date elements that will be shown in [CupertinoDatePicker].
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
@ -190,7 +190,7 @@ abstract class CupertinoLocalizations {
/// [CupertinoTimerPicker] when selected hour value is `hour`. /// [CupertinoTimerPicker] when selected hour value is `hour`.
/// This function will deal with pluralization based on the `hour` parameter. /// This function will deal with pluralization based on the `hour` parameter.
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String timerPickerHourLabel(int hour); String? timerPickerHourLabel(int hour);
/// All possible hour labels that appears next to the hour picker in /// All possible hour labels that appears next to the hour picker in
/// [CupertinoTimerPicker] /// [CupertinoTimerPicker]
@ -200,7 +200,7 @@ abstract class CupertinoLocalizations {
/// [CupertinoTimerPicker] when selected minute value is `minute`. /// [CupertinoTimerPicker] when selected minute value is `minute`.
/// This function will deal with pluralization based on the `minute` parameter. /// This function will deal with pluralization based on the `minute` parameter.
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String timerPickerMinuteLabel(int minute); String? timerPickerMinuteLabel(int minute);
/// All possible minute labels that appears next to the minute picker in /// All possible minute labels that appears next to the minute picker in
/// [CupertinoTimerPicker] /// [CupertinoTimerPicker]
@ -210,7 +210,7 @@ abstract class CupertinoLocalizations {
/// [CupertinoTimerPicker] when selected minute value is `second`. /// [CupertinoTimerPicker] when selected minute value is `second`.
/// This function will deal with pluralization based on the `second` parameter. /// This function will deal with pluralization based on the `second` parameter.
// The global version uses the translated string from the arb file. // The global version uses the translated string from the arb file.
String timerPickerSecondLabel(int second); String? timerPickerSecondLabel(int second);
/// All possible second labels that appears next to the second picker in /// All possible second labels that appears next to the second picker in
/// [CupertinoTimerPicker] /// [CupertinoTimerPicker]

View File

@ -0,0 +1,11 @@
# Use the parent analysis options settings and enable null-experiment.
include: ../analysis_options.yaml
analyzer:
errors:
always_require_non_null_named_parameters: false # not needed with nnbd
type_init_formals: false # https://github.com/dart-lang/linter/issues/2192
unrelated_type_equality_checks: false # https://github.com/dart-lang/linter/issues/2196
void_checks: false # https://github.com/dart-lang/linter/issues/2185
unnecessary_null_comparison: false # Turned off until null-safe rollout is complete.

View File

@ -54,15 +54,15 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
/// The remaining '*Format' arguments uses the intl package to provide /// The remaining '*Format' arguments uses the intl package to provide
/// [DateFormat] configurations for the `localeName`. /// [DateFormat] configurations for the `localeName`.
const GlobalCupertinoLocalizations({ const GlobalCupertinoLocalizations({
@required String localeName, required String localeName,
@required intl.DateFormat fullYearFormat, required intl.DateFormat fullYearFormat,
@required intl.DateFormat dayFormat, required intl.DateFormat dayFormat,
@required intl.DateFormat mediumDateFormat, required intl.DateFormat mediumDateFormat,
@required intl.DateFormat singleDigitHourFormat, required intl.DateFormat singleDigitHourFormat,
@required intl.DateFormat singleDigitMinuteFormat, required intl.DateFormat singleDigitMinuteFormat,
@required intl.DateFormat doubleDigitMinuteFormat, required intl.DateFormat doubleDigitMinuteFormat,
@required intl.DateFormat singleDigitSecondFormat, required intl.DateFormat singleDigitSecondFormat,
@required intl.NumberFormat decimalFormat, required intl.NumberFormat decimalFormat,
}) : assert(localeName != null), }) : assert(localeName != null),
_localeName = localeName, _localeName = localeName,
assert(fullYearFormat != null), assert(fullYearFormat != null),
@ -127,20 +127,20 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
} }
/// Subclasses should provide the optional zero pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional zero pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelZero => null; @protected String? get datePickerHourSemanticsLabelZero => null;
/// Subclasses should provide the optional one pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional one pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelOne => null; @protected String? get datePickerHourSemanticsLabelOne => null;
/// Subclasses should provide the optional two pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional two pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelTwo => null; @protected String? get datePickerHourSemanticsLabelTwo => null;
/// Subclasses should provide the optional few pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional few pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelFew => null; @protected String? get datePickerHourSemanticsLabelFew => null;
/// Subclasses should provide the optional many pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional many pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelMany => null; @protected String? get datePickerHourSemanticsLabelMany => null;
/// Subclasses should provide the required other pluralization of [datePickerHourSemanticsLabel] based on the ARB file. /// Subclasses should provide the required other pluralization of [datePickerHourSemanticsLabel] based on the ARB file.
@protected String get datePickerHourSemanticsLabelOther; @protected String? get datePickerHourSemanticsLabelOther;
@override @override
String datePickerHourSemanticsLabel(int hour) { String? datePickerHourSemanticsLabel(int hour) {
return intl.Intl.pluralLogic( return intl.Intl.pluralLogic(
hour, hour,
zero: datePickerHourSemanticsLabelZero, zero: datePickerHourSemanticsLabelZero,
@ -150,24 +150,24 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
many: datePickerHourSemanticsLabelMany, many: datePickerHourSemanticsLabelMany,
other: datePickerHourSemanticsLabelOther, other: datePickerHourSemanticsLabelOther,
locale: _localeName, locale: _localeName,
).replaceFirst(r'$hour', _decimalFormat.format(hour)); )?.replaceFirst(r'$hour', _decimalFormat.format(hour));
} }
/// Subclasses should provide the optional zero pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional zero pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelZero => null; @protected String? get datePickerMinuteSemanticsLabelZero => null;
/// Subclasses should provide the optional one pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional one pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelOne => null; @protected String? get datePickerMinuteSemanticsLabelOne => null;
/// Subclasses should provide the optional two pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional two pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelTwo => null; @protected String? get datePickerMinuteSemanticsLabelTwo => null;
/// Subclasses should provide the optional few pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional few pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelFew => null; @protected String? get datePickerMinuteSemanticsLabelFew => null;
/// Subclasses should provide the optional many pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the optional many pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelMany => null; @protected String? get datePickerMinuteSemanticsLabelMany => null;
/// Subclasses should provide the required other pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file. /// Subclasses should provide the required other pluralization of [datePickerMinuteSemanticsLabel] based on the ARB file.
@protected String get datePickerMinuteSemanticsLabelOther; @protected String? get datePickerMinuteSemanticsLabelOther;
@override @override
String datePickerMinuteSemanticsLabel(int minute) { String? datePickerMinuteSemanticsLabel(int minute) {
return intl.Intl.pluralLogic( return intl.Intl.pluralLogic(
minute, minute,
zero: datePickerMinuteSemanticsLabelZero, zero: datePickerMinuteSemanticsLabelZero,
@ -177,7 +177,7 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
many: datePickerMinuteSemanticsLabelMany, many: datePickerMinuteSemanticsLabelMany,
other: datePickerMinuteSemanticsLabelOther, other: datePickerMinuteSemanticsLabelOther,
locale: _localeName, locale: _localeName,
).replaceFirst(r'$minute', _decimalFormat.format(minute)); )?.replaceFirst(r'$minute', _decimalFormat.format(minute));
} }
/// A string describing the [DatePickerDateOrder] enum value. /// A string describing the [DatePickerDateOrder] enum value.
@ -210,7 +210,7 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
"locale $_localeName.\nNon conforming string for $_localeName's " "locale $_localeName.\nNon conforming string for $_localeName's "
'.arb file', '.arb file',
); );
return null; return DatePickerDateOrder.mdy;
} }
} }
@ -244,7 +244,7 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
"for locale $_localeName.\nNon conforming string for $_localeName's " "for locale $_localeName.\nNon conforming string for $_localeName's "
'.arb file', '.arb file',
); );
return null; return DatePickerDateTimeOrder.date_time_dayPeriod;
} }
} }
@ -254,7 +254,7 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
String get tabSemanticsLabelRaw; String get tabSemanticsLabelRaw;
@override @override
String tabSemanticsLabel({ int tabIndex, int tabCount }) { String tabSemanticsLabel({ required int tabIndex, required int tabCount }) {
assert(tabIndex >= 1); assert(tabIndex >= 1);
assert(tabCount >= 1); assert(tabCount >= 1);
final String template = tabSemanticsLabelRaw; final String template = tabSemanticsLabelRaw;
@ -279,20 +279,20 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
} }
/// Subclasses should provide the optional zero pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the optional zero pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelZero => null; @protected String? get timerPickerHourLabelZero => null;
/// Subclasses should provide the optional one pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the optional one pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelOne => null; @protected String? get timerPickerHourLabelOne => null;
/// Subclasses should provide the optional two pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the optional two pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelTwo => null; @protected String? get timerPickerHourLabelTwo => null;
/// Subclasses should provide the optional few pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the optional few pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelFew => null; @protected String? get timerPickerHourLabelFew => null;
/// Subclasses should provide the optional many pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the optional many pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelMany => null; @protected String? get timerPickerHourLabelMany => null;
/// Subclasses should provide the required other pluralization of [timerPickerHourLabel] based on the ARB file. /// Subclasses should provide the required other pluralization of [timerPickerHourLabel] based on the ARB file.
@protected String get timerPickerHourLabelOther; @protected String? get timerPickerHourLabelOther;
@override @override
String timerPickerHourLabel(int hour) { String? timerPickerHourLabel(int hour) {
return intl.Intl.pluralLogic( return intl.Intl.pluralLogic(
hour, hour,
zero: timerPickerHourLabelZero, zero: timerPickerHourLabelZero,
@ -302,34 +302,34 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
many: timerPickerHourLabelMany, many: timerPickerHourLabelMany,
other: timerPickerHourLabelOther, other: timerPickerHourLabelOther,
locale: _localeName, locale: _localeName,
).replaceFirst(r'$hour', _decimalFormat.format(hour)); )?.replaceFirst(r'$hour', _decimalFormat.format(hour));
} }
@override @override
List<String> get timerPickerHourLabels => <String>[ List<String> get timerPickerHourLabels => <String>[
timerPickerHourLabelZero, if (timerPickerHourLabelZero != null) timerPickerHourLabelZero!,
timerPickerHourLabelOne, if (timerPickerHourLabelOne != null) timerPickerHourLabelOne!,
timerPickerHourLabelTwo, if (timerPickerHourLabelTwo != null) timerPickerHourLabelTwo!,
timerPickerHourLabelFew, if (timerPickerHourLabelFew != null) timerPickerHourLabelFew!,
timerPickerHourLabelMany, if (timerPickerHourLabelMany != null) timerPickerHourLabelMany!,
timerPickerHourLabelOther, if (timerPickerHourLabelOther != null) timerPickerHourLabelOther!,
]; ];
/// Subclasses should provide the optional zero pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the optional zero pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelZero => null; @protected String? get timerPickerMinuteLabelZero => null;
/// Subclasses should provide the optional one pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the optional one pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelOne => null; @protected String? get timerPickerMinuteLabelOne => null;
/// Subclasses should provide the optional two pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the optional two pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelTwo => null; @protected String? get timerPickerMinuteLabelTwo => null;
/// Subclasses should provide the optional few pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the optional few pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelFew => null; @protected String? get timerPickerMinuteLabelFew => null;
/// Subclasses should provide the optional many pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the optional many pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelMany => null; @protected String? get timerPickerMinuteLabelMany => null;
/// Subclasses should provide the required other pluralization of [timerPickerMinuteLabel] based on the ARB file. /// Subclasses should provide the required other pluralization of [timerPickerMinuteLabel] based on the ARB file.
@protected String get timerPickerMinuteLabelOther; @protected String? get timerPickerMinuteLabelOther;
@override @override
String timerPickerMinuteLabel(int minute) { String? timerPickerMinuteLabel(int minute) {
return intl.Intl.pluralLogic( return intl.Intl.pluralLogic(
minute, minute,
zero: timerPickerMinuteLabelZero, zero: timerPickerMinuteLabelZero,
@ -339,34 +339,34 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
many: timerPickerMinuteLabelMany, many: timerPickerMinuteLabelMany,
other: timerPickerMinuteLabelOther, other: timerPickerMinuteLabelOther,
locale: _localeName, locale: _localeName,
).replaceFirst(r'$minute', _decimalFormat.format(minute)); )?.replaceFirst(r'$minute', _decimalFormat.format(minute));
} }
@override @override
List<String> get timerPickerMinuteLabels => <String>[ List<String> get timerPickerMinuteLabels => <String>[
timerPickerMinuteLabelZero, if (timerPickerMinuteLabelZero != null) timerPickerMinuteLabelZero!,
timerPickerMinuteLabelOne, if (timerPickerMinuteLabelOne != null) timerPickerMinuteLabelOne!,
timerPickerMinuteLabelTwo, if (timerPickerMinuteLabelTwo != null) timerPickerMinuteLabelTwo!,
timerPickerMinuteLabelFew, if (timerPickerMinuteLabelFew != null) timerPickerMinuteLabelFew!,
timerPickerMinuteLabelMany, if (timerPickerMinuteLabelMany != null) timerPickerMinuteLabelMany!,
timerPickerMinuteLabelOther, if (timerPickerMinuteLabelOther != null) timerPickerMinuteLabelOther!,
]; ];
/// Subclasses should provide the optional zero pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the optional zero pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelZero => null; @protected String? get timerPickerSecondLabelZero => null;
/// Subclasses should provide the optional one pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the optional one pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelOne => null; @protected String? get timerPickerSecondLabelOne => null;
/// Subclasses should provide the optional two pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the optional two pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelTwo => null; @protected String? get timerPickerSecondLabelTwo => null;
/// Subclasses should provide the optional few pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the optional few pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelFew => null; @protected String? get timerPickerSecondLabelFew => null;
/// Subclasses should provide the optional many pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the optional many pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelMany => null; @protected String? get timerPickerSecondLabelMany => null;
/// Subclasses should provide the required other pluralization of [timerPickerSecondLabel] based on the ARB file. /// Subclasses should provide the required other pluralization of [timerPickerSecondLabel] based on the ARB file.
@protected String get timerPickerSecondLabelOther; @protected String? get timerPickerSecondLabelOther;
@override @override
String timerPickerSecondLabel(int second) { String? timerPickerSecondLabel(int second) {
return intl.Intl.pluralLogic( return intl.Intl.pluralLogic(
second, second,
zero: timerPickerSecondLabelZero, zero: timerPickerSecondLabelZero,
@ -376,17 +376,17 @@ abstract class GlobalCupertinoLocalizations implements CupertinoLocalizations {
many: timerPickerSecondLabelMany, many: timerPickerSecondLabelMany,
other: timerPickerSecondLabelOther, other: timerPickerSecondLabelOther,
locale: _localeName, locale: _localeName,
).replaceFirst(r'$second', _decimalFormat.format(second)); )?.replaceFirst(r'$second', _decimalFormat.format(second));
} }
@override @override
List<String> get timerPickerSecondLabels => <String>[ List<String> get timerPickerSecondLabels => <String>[
timerPickerSecondLabelZero, if (timerPickerSecondLabelZero != null) timerPickerSecondLabelZero!,
timerPickerSecondLabelOne, if (timerPickerSecondLabelOne != null) timerPickerSecondLabelOne!,
timerPickerSecondLabelTwo, if (timerPickerSecondLabelTwo != null) timerPickerSecondLabelTwo!,
timerPickerSecondLabelFew, if (timerPickerSecondLabelFew != null) timerPickerSecondLabelFew!,
timerPickerSecondLabelMany, if (timerPickerSecondLabelMany != null) timerPickerSecondLabelMany!,
timerPickerSecondLabelOther, if (timerPickerSecondLabelOther != null) timerPickerSecondLabelOther!,
]; ];
/// A [LocalizationsDelegate] for [CupertinoLocalizations]. /// A [LocalizationsDelegate] for [CupertinoLocalizations].
@ -444,18 +444,18 @@ class _GlobalCupertinoLocalizationsDelegate extends LocalizationsDelegate<Cupert
'might be $localeName', 'might be $localeName',
); );
intl.DateFormat fullYearFormat; late intl.DateFormat fullYearFormat;
intl.DateFormat dayFormat; late intl.DateFormat dayFormat;
intl.DateFormat mediumDateFormat; late intl.DateFormat mediumDateFormat;
// We don't want any additional decoration here. The am/pm is handled in // We don't want any additional decoration here. The am/pm is handled in
// the date picker. We just want an hour number localized. // the date picker. We just want an hour number localized.
intl.DateFormat singleDigitHourFormat; late intl.DateFormat singleDigitHourFormat;
intl.DateFormat singleDigitMinuteFormat; late intl.DateFormat singleDigitMinuteFormat;
intl.DateFormat doubleDigitMinuteFormat; late intl.DateFormat doubleDigitMinuteFormat;
intl.DateFormat singleDigitSecondFormat; late intl.DateFormat singleDigitSecondFormat;
intl.NumberFormat decimalFormat; late intl.NumberFormat decimalFormat;
void loadFormats(String locale) { void loadFormats(String? locale) {
fullYearFormat = intl.DateFormat.y(locale); fullYearFormat = intl.DateFormat.y(locale);
dayFormat = intl.DateFormat.d(locale); dayFormat = intl.DateFormat.d(locale);
mediumDateFormat = intl.DateFormat.MMMEd(locale); mediumDateFormat = intl.DateFormat.MMMEd(locale);
@ -485,7 +485,7 @@ class _GlobalCupertinoLocalizationsDelegate extends LocalizationsDelegate<Cupert
doubleDigitMinuteFormat, doubleDigitMinuteFormat,
singleDigitSecondFormat, singleDigitSecondFormat,
decimalFormat, decimalFormat,
)); )!);
}); });
} }

View File

@ -1,12 +1,42 @@
{ {
"@datePickerHourSemanticsLabelZero": {
"optional": true
},
"datePickerHourSemanticsLabelOne": "$hour o'clock", "datePickerHourSemanticsLabelOne": "$hour o'clock",
"@datePickerHourSemanticsLabelOne": {
"optional": true
},
"@datePickerHourSemanticsLabelTwo": {
"optional": true
},
"@datePickerHourSemanticsLabelFew": {
"optional": true
},
"@datePickerHourSemanticsLabelMany": {
"optional": true
},
"datePickerHourSemanticsLabelOther": "$hour o'clock", "datePickerHourSemanticsLabelOther": "$hour o'clock",
"@datePickerHourSemanticsLabel": { "@datePickerHourSemanticsLabel": {
"description": "Accessibility announcement for the selected hour on a time picker such as '5 o'clock' or '5点'", "description": "Accessibility announcement for the selected hour on a time picker such as '5 o'clock' or '5点'",
"plural": "hour" "plural": "hour"
}, },
"@datePickerMinuteSemanticsLabelZero": {
"optional": true
},
"datePickerMinuteSemanticsLabelOne": "1 minute", "datePickerMinuteSemanticsLabelOne": "1 minute",
"@datePickerMinuteSemanticsLabelOne": {
"optional": true
},
"@datePickerMinuteSemanticsLabelTwo": {
"optional": true
},
"@datePickerMinuteSemanticsLabelFew": {
"optional": true
},
"@datePickerMinuteSemanticsLabelMany": {
"optional": true
},
"datePickerMinuteSemanticsLabelOther": "$minute minutes", "datePickerMinuteSemanticsLabelOther": "$minute minutes",
"@datePickerMinuteSemanticsLabel": { "@datePickerMinuteSemanticsLabel": {
"description": "Accessibility announcement for the selected minute on a time picker such as '15 minutes' or '15分'", "description": "Accessibility announcement for the selected minute on a time picker such as '15 minutes' or '15分'",
@ -49,21 +79,66 @@
"parameters": "tabIndex, tabCount" "parameters": "tabIndex, tabCount"
}, },
"@timerPickerHourLabelZero": {
"optional": true
},
"timerPickerHourLabelOne": "hour", "timerPickerHourLabelOne": "hour",
"@timerPickerHourLabelOne": {
"optional": true
},
"@timerPickerHourLabelTwo": {
"optional": true
},
"@timerPickerHourLabelFew": {
"optional": true
},
"@timerPickerHourLabelMany": {
"optional": true
},
"timerPickerHourLabelOther": "hours", "timerPickerHourLabelOther": "hours",
"@timerPickerHourLabel": { "@timerPickerHourLabel": {
"description": "The label adjacent to an hour integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.", "description": "The label adjacent to an hour integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.",
"plural": "hour" "plural": "hour"
}, },
"@timerPickerMinuteLabelZero": {
"optional": true
},
"timerPickerMinuteLabelOne": "min.", "timerPickerMinuteLabelOne": "min.",
"@timerPickerMinuteLabelOne": {
"optional": true
},
"@timerPickerMinuteLabelTwo": {
"optional": true
},
"@timerPickerMinuteLabelFew": {
"optional": true
},
"@timerPickerMinuteLabelMany": {
"optional": true
},
"timerPickerMinuteLabelOther": "min.", "timerPickerMinuteLabelOther": "min.",
"@timerPickerMinuteLabel": { "@timerPickerMinuteLabel": {
"description": "The label adjacent to a minute integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.", "description": "The label adjacent to a minute integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.",
"plural": "minute" "plural": "minute"
}, },
"@timerPickerSecondLabelZero": {
"optional": true
},
"timerPickerSecondLabelOne": "sec.", "timerPickerSecondLabelOne": "sec.",
"@timerPickerSecondLabelOne": {
"optional": true
},
"@timerPickerSecondLabelTwo": {
"optional": true
},
"@timerPickerSecondLabelFew": {
"optional": true
},
"@timerPickerSecondLabelMany": {
"optional": true
},
"timerPickerSecondLabelOther": "sec.", "timerPickerSecondLabelOther": "sec.",
"@timerPickerSecondLabel": { "@timerPickerSecondLabel": {
"description": "The label adjacent to a second integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.", "description": "The label adjacent to a second integer number in a countdown timer. The reference abbreviation is what iOS does in the stock clock app's countdown timer.",

View File

@ -73,7 +73,22 @@
}, },
"licensesPackageDetailTextZero": "No licenses", "licensesPackageDetailTextZero": "No licenses",
"@licensesPackageDetailTextZero": {
"optional": true
},
"licensesPackageDetailTextOne": "1 license", "licensesPackageDetailTextOne": "1 license",
"@licensesPackageDetailTextOne": {
"optional": true
},
"@licensesPackageDetailTextTwo": {
"optional": true
},
"@licensesPackageDetailTextFew": {
"optional": true
},
"@licensesPackageDetailTextMany": {
"optional": true
},
"licensesPackageDetailTextOther": "$licenseCount licenses", "licensesPackageDetailTextOther": "$licenseCount licenses",
"@licensesPackageDetailText": { "@licensesPackageDetailText": {
"description": "The subtitle and detail text for a package displayed on the Flutter licenses page. The value of $licenseCount is an integer which indicates the number of licenses the package has.", "description": "The subtitle and detail text for a package displayed on the Flutter licenses page. The value of $licenseCount is an integer which indicates the number of licenses the package has.",
@ -104,7 +119,22 @@
}, },
"selectedRowCountTitleZero": "No items selected", "selectedRowCountTitleZero": "No items selected",
"@selectedRowCountTitleZero": {
"optional": true
},
"selectedRowCountTitleOne": "1 item selected", "selectedRowCountTitleOne": "1 item selected",
"@selectedRowCountTitleOne": {
"optional": true
},
"@selectedRowCountTitleTwo": {
"optional": true
},
"@selectedRowCountTitleFew": {
"optional": true
},
"@selectedRowCountTitleMany": {
"optional": true
},
"selectedRowCountTitleOther": "$selectedRowCount items selected", "selectedRowCountTitleOther": "$selectedRowCount items selected",
"@selectedRowCountTitle": { "@selectedRowCountTitle": {
"description": "The title for the header of a paginated data table when the user is selecting rows. The value of $selectedRowCount is an integer which indicates the number of data table row elements that have been selected.", "description": "The title for the header of a paginated data table when the user is selecting rows. The value of $selectedRowCount is an integer which indicates the number of data table row elements that have been selected.",
@ -389,7 +419,22 @@
}, },
"remainingTextFieldCharacterCountZero": "No characters remaining", "remainingTextFieldCharacterCountZero": "No characters remaining",
"@remainingTextFieldCharacterCountZero": {
"optional": true
},
"remainingTextFieldCharacterCountOne": "1 character remaining", "remainingTextFieldCharacterCountOne": "1 character remaining",
"@remainingTextFieldCharacterCountOne": {
"optional": true
},
"@remainingTextFieldCharacterCountTwo": {
"optional": true
},
"@remainingTextFieldCharacterCountFew": {
"optional": true
},
"@remainingTextFieldCharacterCountMany": {
"optional": true
},
"remainingTextFieldCharacterCountOther": "$remainingCount characters remaining", "remainingTextFieldCharacterCountOther": "$remainingCount characters remaining",
"@remainingTextFieldCharacterCount": { "@remainingTextFieldCharacterCount": {
"description": "The label for the TextField's character counter. remainingCharacters is a integer representing how many more characters the user can type into the text field before using up a given budget. All values are greater than or equal to zero.", "description": "The label for the TextField's character counter. remainingCharacters is a integer representing how many more characters the user can type into the text field before using up a given budget. All values are greater than or equal to zero.",

View File

@ -1,7 +1,9 @@
{ {
"scriptCategory": "tall", "scriptCategory": "tall",
"timeOfDayFormat": "HH:mm", "timeOfDayFormat": "HH:mm",
"anteMeridiemAbbreviation": "AM",
"@anteMeridiemAbbreviation": {"notUsed":"Pashto time format does not use a.m. indicator"}, "@anteMeridiemAbbreviation": {"notUsed":"Pashto time format does not use a.m. indicator"},
"postMeridiemAbbreviation": "PM",
"@postMeridiemAbbreviation": {"notUsed":"Pashto time format does not use p.m. indicator"}, "@postMeridiemAbbreviation": {"notUsed":"Pashto time format does not use p.m. indicator"},
"openAppDrawerTooltip": "د پرانیستی نیینګ مینو", "openAppDrawerTooltip": "د پرانیستی نیینګ مینو",
"backButtonTooltip": "شاته", "backButtonTooltip": "شاته",

View File

@ -87,16 +87,16 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// The [narrowWeekdays] and [firstDayOfWeekIndex] properties use the values /// The [narrowWeekdays] and [firstDayOfWeekIndex] properties use the values
/// from the [intl.DateFormat] used by [formatFullDate]. /// from the [intl.DateFormat] used by [formatFullDate].
const GlobalMaterialLocalizations({ const GlobalMaterialLocalizations({
@required String localeName, required String localeName,
@required intl.DateFormat fullYearFormat, required intl.DateFormat fullYearFormat,
@required intl.DateFormat compactDateFormat, required intl.DateFormat compactDateFormat,
@required intl.DateFormat shortDateFormat, required intl.DateFormat shortDateFormat,
@required intl.DateFormat mediumDateFormat, required intl.DateFormat mediumDateFormat,
@required intl.DateFormat longDateFormat, required intl.DateFormat longDateFormat,
@required intl.DateFormat yearMonthFormat, required intl.DateFormat yearMonthFormat,
@required intl.DateFormat shortMonthDayFormat, required intl.DateFormat shortMonthDayFormat,
@required intl.NumberFormat decimalFormat, required intl.NumberFormat decimalFormat,
@required intl.NumberFormat twoDigitZeroPaddedFormat, required intl.NumberFormat twoDigitZeroPaddedFormat,
}) : assert(localeName != null), }) : assert(localeName != null),
_localeName = localeName, _localeName = localeName,
assert(fullYearFormat != null), assert(fullYearFormat != null),
@ -140,7 +140,6 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
final int hour = timeOfDay.hourOfPeriod; final int hour = timeOfDay.hourOfPeriod;
return formatDecimal(hour == 0 ? 12 : hour); return formatDecimal(hour == 0 ? 12 : hour);
} }
return null;
} }
@override @override
@ -184,9 +183,9 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
} }
@override @override
DateTime parseCompactDate(String inputString) { DateTime? parseCompactDate(String? inputString) {
try { try {
return _compactDateFormat.parseStrict(inputString); return inputString != null ? _compactDateFormat.parseStrict(inputString) : null;
} on FormatException { } on FormatException {
return null; return null;
} }
@ -219,28 +218,26 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
final String minute = formatMinute(timeOfDay); final String minute = formatMinute(timeOfDay);
switch (timeOfDayFormat(alwaysUse24HourFormat: alwaysUse24HourFormat)) { switch (timeOfDayFormat(alwaysUse24HourFormat: alwaysUse24HourFormat)) {
case TimeOfDayFormat.h_colon_mm_space_a: case TimeOfDayFormat.h_colon_mm_space_a:
return '$hour:$minute ${_formatDayPeriod(timeOfDay)}'; return '$hour:$minute ${_formatDayPeriod(timeOfDay)!}';
case TimeOfDayFormat.H_colon_mm: case TimeOfDayFormat.H_colon_mm:
case TimeOfDayFormat.HH_colon_mm: case TimeOfDayFormat.HH_colon_mm:
return '$hour:$minute'; return '$hour:$minute';
case TimeOfDayFormat.HH_dot_mm: case TimeOfDayFormat.HH_dot_mm:
return '$hour.$minute'; return '$hour.$minute';
case TimeOfDayFormat.a_space_h_colon_mm: case TimeOfDayFormat.a_space_h_colon_mm:
return '${_formatDayPeriod(timeOfDay)} $hour:$minute'; return '${_formatDayPeriod(timeOfDay)!} $hour:$minute';
case TimeOfDayFormat.frenchCanadian: case TimeOfDayFormat.frenchCanadian:
return '$hour h $minute'; return '$hour h $minute';
} }
return null;
} }
String _formatDayPeriod(TimeOfDay timeOfDay) { String? _formatDayPeriod(TimeOfDay timeOfDay) {
switch (timeOfDay.period) { switch (timeOfDay.period) {
case DayPeriod.am: case DayPeriod.am:
return anteMeridiemAbbreviation; return anteMeridiemAbbreviation;
case DayPeriod.pm: case DayPeriod.pm:
return postMeridiemAbbreviation; return postMeridiemAbbreviation;
} }
return null;
} }
/// The raw version of [dateRangeStartDateSemanticLabel], with `$formattedDate` verbatim /// The raw version of [dateRangeStartDateSemanticLabel], with `$formattedDate` verbatim
@ -288,7 +285,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
@override @override
String pageRowsInfoTitle(int firstRow, int lastRow, int rowCount, bool rowCountIsApproximate) { String pageRowsInfoTitle(int firstRow, int lastRow, int rowCount, bool rowCountIsApproximate) {
String text = rowCountIsApproximate ? pageRowsInfoTitleApproximateRaw : null; String? text = rowCountIsApproximate ? pageRowsInfoTitleApproximateRaw : null;
text ??= pageRowsInfoTitleRaw; text ??= pageRowsInfoTitleRaw;
assert(text != null, 'A $_localeName localization was not found for pageRowsInfoTitle or pageRowsInfoTitleApproximate'); assert(text != null, 'A $_localeName localization was not found for pageRowsInfoTitle or pageRowsInfoTitleApproximate');
return text return text
@ -303,7 +300,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
String get tabLabelRaw; String get tabLabelRaw;
@override @override
String tabLabel({ int tabIndex, int tabCount }) { String tabLabel({ required int tabIndex, required int tabCount }) {
assert(tabIndex >= 1); assert(tabIndex >= 1);
assert(tabCount >= 1); assert(tabCount >= 1);
final String template = tabLabelRaw; final String template = tabLabelRaw;
@ -325,7 +322,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [selectedRowCountTitleMany], the "many" form /// * [selectedRowCountTitleMany], the "many" form
/// * [selectedRowCountTitleOther], the "other" form /// * [selectedRowCountTitleOther], the "other" form
@protected @protected
String get selectedRowCountTitleZero => null; String? get selectedRowCountTitleZero => null;
/// The "one" form of [selectedRowCountTitle]. /// The "one" form of [selectedRowCountTitle].
/// ///
@ -340,7 +337,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [selectedRowCountTitleMany], the "many" form /// * [selectedRowCountTitleMany], the "many" form
/// * [selectedRowCountTitleOther], the "other" form /// * [selectedRowCountTitleOther], the "other" form
@protected @protected
String get selectedRowCountTitleOne => null; String? get selectedRowCountTitleOne => null;
/// The "two" form of [selectedRowCountTitle]. /// The "two" form of [selectedRowCountTitle].
/// ///
@ -355,7 +352,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [selectedRowCountTitleMany], the "many" form /// * [selectedRowCountTitleMany], the "many" form
/// * [selectedRowCountTitleOther], the "other" form /// * [selectedRowCountTitleOther], the "other" form
@protected @protected
String get selectedRowCountTitleTwo => null; String? get selectedRowCountTitleTwo => null;
/// The "few" form of [selectedRowCountTitle]. /// The "few" form of [selectedRowCountTitle].
/// ///
@ -370,7 +367,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [selectedRowCountTitleMany], the "many" form /// * [selectedRowCountTitleMany], the "many" form
/// * [selectedRowCountTitleOther], the "other" form /// * [selectedRowCountTitleOther], the "other" form
@protected @protected
String get selectedRowCountTitleFew => null; String? get selectedRowCountTitleFew => null;
/// The "many" form of [selectedRowCountTitle]. /// The "many" form of [selectedRowCountTitle].
/// ///
@ -385,7 +382,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [selectedRowCountTitleFew], the "few" form /// * [selectedRowCountTitleFew], the "few" form
/// * [selectedRowCountTitleOther], the "other" form /// * [selectedRowCountTitleOther], the "other" form
@protected @protected
String get selectedRowCountTitleMany => null; String? get selectedRowCountTitleMany => null;
/// The "other" form of [selectedRowCountTitle]. /// The "other" form of [selectedRowCountTitle].
/// ///
@ -458,7 +455,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [licensesPackageDetailTextMany], the "many" form /// * [licensesPackageDetailTextMany], the "many" form
/// * [licensesPackageDetailTextOther], the "other" form /// * [licensesPackageDetailTextOther], the "other" form
@protected @protected
String get licensesPackageDetailTextZero => null; String? get licensesPackageDetailTextZero => null;
/// The "one" form of [licensesPackageDetailText]. /// The "one" form of [licensesPackageDetailText].
/// ///
@ -473,7 +470,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [licensesPackageDetailTextMany], the "many" form /// * [licensesPackageDetailTextMany], the "many" form
/// * [licensesPackageDetailTextOther], the "other" form /// * [licensesPackageDetailTextOther], the "other" form
@protected @protected
String get licensesPackageDetailTextOne => null; String? get licensesPackageDetailTextOne => null;
/// The "two" form of [licensesPackageDetailText]. /// The "two" form of [licensesPackageDetailText].
/// ///
@ -489,7 +486,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [licensesPackageDetailTextMany], the "many" form /// * [licensesPackageDetailTextMany], the "many" form
/// * [licensesPackageDetailTextOther], the "other" form /// * [licensesPackageDetailTextOther], the "other" form
@protected @protected
String get licensesPackageDetailTextTwo => null; String? get licensesPackageDetailTextTwo => null;
/// The "many" form of [licensesPackageDetailText]. /// The "many" form of [licensesPackageDetailText].
/// ///
@ -505,7 +502,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [licensesPackageDetailTextMany], the "many" form /// * [licensesPackageDetailTextMany], the "many" form
/// * [licensesPackageDetailTextOther], the "other" form /// * [licensesPackageDetailTextOther], the "other" form
@protected @protected
String get licensesPackageDetailTextMany => null; String? get licensesPackageDetailTextMany => null;
/// The "few" form of [licensesPackageDetailText]. /// The "few" form of [licensesPackageDetailText].
/// ///
@ -521,7 +518,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [licensesPackageDetailTextMany], the "many" form /// * [licensesPackageDetailTextMany], the "many" form
/// * [licensesPackageDetailTextOther], the "other" form /// * [licensesPackageDetailTextOther], the "other" form
@protected @protected
String get licensesPackageDetailTextFew => null; String? get licensesPackageDetailTextFew => null;
/// The "other" form of [licensesPackageDetailText]. /// The "other" form of [licensesPackageDetailText].
/// ///
@ -555,7 +552,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// The "zero" form of [remainingTextFieldCharacterCount]. /// The "zero" form of [remainingTextFieldCharacterCount].
/// ///
/// This form is required. /// This form is optional.
/// ///
/// See also: /// See also:
/// ///
@ -567,7 +564,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [remainingTextFieldCharacterCountMany], the "many" form /// * [remainingTextFieldCharacterCountMany], the "many" form
/// * [remainingTextFieldCharacterCountOther], the "other" form /// * [remainingTextFieldCharacterCountOther], the "other" form
@protected @protected
String get remainingTextFieldCharacterCountZero; String? get remainingTextFieldCharacterCountZero => null;
/// The "one" form of [remainingTextFieldCharacterCount]. /// The "one" form of [remainingTextFieldCharacterCount].
/// ///
@ -582,7 +579,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [remainingTextFieldCharacterCountMany], the "many" form /// * [remainingTextFieldCharacterCountMany], the "many" form
/// * [remainingTextFieldCharacterCountOther], the "other" form /// * [remainingTextFieldCharacterCountOther], the "other" form
@protected @protected
String get remainingTextFieldCharacterCountOne => null; String? get remainingTextFieldCharacterCountOne => null;
/// The "two" form of [remainingTextFieldCharacterCount]. /// The "two" form of [remainingTextFieldCharacterCount].
/// ///
@ -598,7 +595,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [remainingTextFieldCharacterCountMany], the "many" form /// * [remainingTextFieldCharacterCountMany], the "many" form
/// * [remainingTextFieldCharacterCountOther], the "other" form /// * [remainingTextFieldCharacterCountOther], the "other" form
@protected @protected
String get remainingTextFieldCharacterCountTwo => null; String? get remainingTextFieldCharacterCountTwo => null;
/// The "many" form of [remainingTextFieldCharacterCount]. /// The "many" form of [remainingTextFieldCharacterCount].
/// ///
@ -614,7 +611,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [remainingTextFieldCharacterCountMany], the "many" form /// * [remainingTextFieldCharacterCountMany], the "many" form
/// * [remainingTextFieldCharacterCountOther], the "other" form /// * [remainingTextFieldCharacterCountOther], the "other" form
@protected @protected
String get remainingTextFieldCharacterCountMany => null; String? get remainingTextFieldCharacterCountMany => null;
/// The "few" form of [remainingTextFieldCharacterCount]. /// The "few" form of [remainingTextFieldCharacterCount].
/// ///
@ -630,7 +627,7 @@ abstract class GlobalMaterialLocalizations implements MaterialLocalizations {
/// * [remainingTextFieldCharacterCountMany], the "many" form /// * [remainingTextFieldCharacterCountMany], the "many" form
/// * [remainingTextFieldCharacterCountOther], the "other" form /// * [remainingTextFieldCharacterCountOther], the "other" form
@protected @protected
String get remainingTextFieldCharacterCountFew => null; String? get remainingTextFieldCharacterCountFew => null;
/// The "other" form of [remainingTextFieldCharacterCount]. /// The "other" form of [remainingTextFieldCharacterCount].
/// ///
@ -714,7 +711,6 @@ TimeOfDayFormat _get24HourVersionOf(TimeOfDayFormat original) {
case TimeOfDayFormat.a_space_h_colon_mm: case TimeOfDayFormat.a_space_h_colon_mm:
return TimeOfDayFormat.HH_colon_mm; return TimeOfDayFormat.HH_colon_mm;
} }
return TimeOfDayFormat.HH_colon_mm;
} }
class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> { class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
@ -795,7 +791,7 @@ class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocal
shortMonthDayFormat, shortMonthDayFormat,
decimalFormat, decimalFormat,
twoDigitZeroPaddedFormat, twoDigitZeroPaddedFormat,
)); )!);
}); });
} }

View File

@ -28,7 +28,7 @@ void loadDateIntlDataIfNotLoaded() {
// Strip scriptCode from the locale, as we do not distinguish between scripts // Strip scriptCode from the locale, as we do not distinguish between scripts
// for dates. // for dates.
final List<String> codes = locale.split('_'); final List<String> codes = locale.split('_');
String countryCode; String? countryCode;
if (codes.length == 2) { if (codes.length == 2) {
countryCode = codes[1].length < 4 ? codes[1] : null; countryCode = codes[1].length < 4 ? codes[1] : null;
} else if (codes.length == 3) { } else if (codes.length == 3) {

View File

@ -43,7 +43,7 @@ class GlobalWidgetsLocalizations implements WidgetsLocalizations {
@override @override
TextDirection get textDirection => _textDirection; TextDirection get textDirection => _textDirection;
TextDirection _textDirection; late TextDirection _textDirection;
/// Creates an object that provides localized resource values for the /// Creates an object that provides localized resource values for the
/// lowest levels of the Flutter framework. /// lowest levels of the Flutter framework.

View File

@ -2,7 +2,7 @@ name: flutter_localizations
environment: environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite. # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.2.0 <3.0.0" sdk: ">=2.12.0-0 <3.0.0"
dependencies: dependencies:
# To update these, use "flutter update-packages --force-upgrade". # To update these, use "flutter update-packages --force-upgrade".

View File

@ -63,7 +63,7 @@ void main() {
) )
); );
await tester.binding.setLocale('zh', null); await tester.binding.setLocale('zh', '');
await tester.pump(); await tester.pump();
await tester.binding.setLocale('es', 'US'); await tester.binding.setLocale('es', 'US');
await tester.pump(); await tester.pump();
@ -87,18 +87,18 @@ class _DummyLocalizationsDelegate extends LocalizationsDelegate<DummyLocalizatio
class DummyLocalizations {} class DummyLocalizations {}
class LocalizationTracker extends StatefulWidget { class LocalizationTracker extends StatefulWidget {
const LocalizationTracker({Key key}) : super(key: key); const LocalizationTracker({Key? key}) : super(key: key);
@override @override
State<StatefulWidget> createState() => LocalizationTrackerState(); State<StatefulWidget> createState() => LocalizationTrackerState();
} }
class LocalizationTrackerState extends State<LocalizationTracker> { class LocalizationTrackerState extends State<LocalizationTracker> {
double captionFontSize; late double captionFontSize;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
captionFontSize = Theme.of(context).textTheme.caption.fontSize; captionFontSize = Theme.of(context).textTheme.caption!.fontSize!;
return Container(); return Container();
} }
} }

View File

@ -9,9 +9,9 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
DateTime firstDate; late DateTime firstDate;
DateTime lastDate; late DateTime lastDate;
DateTime initialDate; late DateTime initialDate;
setUp(() { setUp(() {
firstDate = DateTime(2001, DateTime.january, 1); firstDate = DateTime(2001, DateTime.january, 1);
@ -53,10 +53,10 @@ void main() {
for (final Locale locale in testLocales.keys) { for (final Locale locale in testLocales.keys) {
testWidgets('shows dates for $locale', (WidgetTester tester) async { testWidgets('shows dates for $locale', (WidgetTester tester) async {
final List<String> expectedDaysOfWeek = testLocales[locale]['expectedDaysOfWeek'] as List<String>; final List<String> expectedDaysOfWeek = testLocales[locale]!['expectedDaysOfWeek'] as List<String>;
final List<String> expectedDaysOfMonth = testLocales[locale]['expectedDaysOfMonth'] as List<String>; final List<String> expectedDaysOfMonth = testLocales[locale]!['expectedDaysOfMonth'] as List<String>;
final String expectedMonthYearHeader = testLocales[locale]['expectedMonthYearHeader'] as String; final String expectedMonthYearHeader = testLocales[locale]!['expectedMonthYearHeader'] as String;
final TextDirection textDirection = testLocales[locale]['textDirection'] as TextDirection; final TextDirection textDirection = testLocales[locale]!['textDirection'] as TextDirection;
final DateTime baseDate = DateTime(2017, 9, 27); final DateTime baseDate = DateTime(2017, 9, 27);
await _pumpBoilerplate(tester, CalendarDatePicker( await _pumpBoilerplate(tester, CalendarDatePicker(
@ -72,7 +72,7 @@ void main() {
expect(find.text(dayOfWeek), findsWidgets); expect(find.text(dayOfWeek), findsWidgets);
} }
Offset previousCellOffset; Offset? previousCellOffset;
for (final String dayOfMonth in expectedDaysOfMonth) { for (final String dayOfMonth in expectedDaysOfMonth) {
final Finder dayCell = find.descendant(of: find.byType(GridView), matching: find.text(dayOfMonth)); final Finder dayCell = find.descendant(of: find.byType(GridView), matching: find.text(dayOfMonth));
expect(dayCell, findsOneWidget); expect(dayCell, findsOneWidget);

View File

@ -163,7 +163,7 @@ void main() {
// Regression test for https://github.com/flutter/flutter/issues/67644. // 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 { testWidgets('en_US is initialized correctly by Flutter when DateFormat is used', (WidgetTester tester) async {
DateFormat dateFormat; late DateFormat dateFormat;
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
supportedLocales: const <Locale>[ supportedLocales: const <Locale>[
@ -180,7 +180,7 @@ void main() {
}), }),
)); ));
expect(dateFormat?.locale, 'en_US'); expect(dateFormat.locale, 'en_US');
}); });
} }

View File

@ -9,13 +9,13 @@ import 'package:flutter_test/flutter_test.dart';
class _TimePickerLauncher extends StatelessWidget { class _TimePickerLauncher extends StatelessWidget {
const _TimePickerLauncher({ const _TimePickerLauncher({
Key key, Key? key,
this.onChanged, this.onChanged,
this.locale, required this.locale,
this.entryMode = TimePickerEntryMode.dial, this.entryMode = TimePickerEntryMode.dial,
}) : super(key: key); }) : super(key: key);
final ValueChanged<TimeOfDay> onChanged; final ValueChanged<TimeOfDay?>? onChanged;
final Locale locale; final Locale locale;
final TimePickerEntryMode entryMode; final TimePickerEntryMode entryMode;
@ -32,7 +32,7 @@ class _TimePickerLauncher extends StatelessWidget {
return ElevatedButton( return ElevatedButton(
child: const Text('X'), child: const Text('X'),
onPressed: () async { onPressed: () async {
onChanged(await showTimePicker( onChanged?.call(await showTimePicker(
context: context, context: context,
initialEntryMode: entryMode, initialEntryMode: entryMode,
initialTime: const TimeOfDay(hour: 7, minute: 0), initialTime: const TimeOfDay(hour: 7, minute: 0),
@ -49,7 +49,7 @@ class _TimePickerLauncher extends StatelessWidget {
Future<Offset> startPicker( Future<Offset> startPicker(
WidgetTester tester, WidgetTester tester,
ValueChanged<TimeOfDay> onChanged, { ValueChanged<TimeOfDay?> onChanged, {
Locale locale = const Locale('en', 'US'), Locale locale = const Locale('en', 'US'),
}) async { }) async {
await tester.pumpWidget(_TimePickerLauncher(onChanged: onChanged, locale: locale,)); await tester.pumpWidget(_TimePickerLauncher(onChanged: onChanged, locale: locale,));
@ -89,7 +89,7 @@ void main() {
]; ];
for (final Locale locale in locales) { for (final Locale locale in locales) {
final Offset center = await startPicker(tester, (TimeOfDay time) { }, locale: locale); final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale);
final Text stringFragmentText = tester.widget(stringFragmentTextFinder); final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx; final double minuteLeftOffset = tester.getTopLeft(minuteControlFinder).dx;
@ -133,8 +133,8 @@ void main() {
await finishPicker(tester); await finishPicker(tester);
} }
tester.binding.window.physicalSizeTestValue = null; tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.devicePixelRatioTestValue = null; tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async { testWidgets('can localize the header in all known formats - landscape', (WidgetTester tester) async {
@ -161,7 +161,7 @@ void main() {
]; ];
for (final Locale locale in locales) { for (final Locale locale in locales) {
final Offset center = await startPicker(tester, (TimeOfDay time) { }, locale: locale); final Offset center = await startPicker(tester, (TimeOfDay? time) { }, locale: locale);
final Text stringFragmentText = tester.widget(stringFragmentTextFinder); final Text stringFragmentText = tester.widget(stringFragmentTextFinder);
final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx; final double hourLeftOffset = tester.getTopLeft(hourControlFinder).dx;
final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy; final double hourTopOffset = tester.getTopLeft(hourControlFinder).dy;
@ -210,8 +210,8 @@ void main() {
await finishPicker(tester); await finishPicker(tester);
} }
tester.binding.window.physicalSizeTestValue = null; tester.binding.window.clearPhysicalSizeTestValue();
tester.binding.window.devicePixelRatioTestValue = null; tester.binding.window.clearDevicePixelRatioTestValue();
}); });
testWidgets('can localize input mode in all known formats', (WidgetTester tester) async { testWidgets('can localize input mode in all known formats', (WidgetTester tester) async {
@ -234,7 +234,7 @@ void main() {
]; ];
for (final Locale locale in locales) { for (final Locale locale in locales) {
await tester.pumpWidget(_TimePickerLauncher(onChanged: (TimeOfDay time) { }, locale: locale, entryMode: TimePickerEntryMode.input)); await tester.pumpWidget(_TimePickerLauncher(onChanged: (TimeOfDay? time) { }, locale: locale, entryMode: TimePickerEntryMode.input));
await tester.tap(find.text('X')); await tester.tap(find.text('X'));
await tester.pumpAndSettle(const Duration(seconds: 1)); await tester.pumpAndSettle(const Duration(seconds: 1));
@ -292,8 +292,8 @@ void main() {
// 12:00 AM position. Because there's only one ring, no matter where you // 12:00 AM position. Because there's only one ring, no matter where you
// tap the time will be the same. // tap the time will be the same.
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
TimeOfDay result; TimeOfDay? result;
final Offset center = await startPicker(tester, (TimeOfDay time) { result = time; }, locale: locale); final Offset center = await startPicker(tester, (TimeOfDay? time) { result = time; }, locale: locale);
final Size size = tester.getSize(find.byKey(const Key('time-picker-dial'))); final Size size = tester.getSize(find.byKey(const Key('time-picker-dial')));
final double dy = (size.height / 2.0 / 10) * i; final double dy = (size.height / 2.0 / 10) * i;
await tester.tapAt(Offset(center.dx, center.dy - dy)); await tester.tapAt(Offset(center.dx, center.dy - dy));
@ -348,13 +348,13 @@ void main() {
final dynamic dialPainter = dialPaint.painter; final dynamic dialPainter = dialPaint.painter;
final List<dynamic> primaryLabels = dialPainter.primaryLabels as List<dynamic>; final List<dynamic> primaryLabels = dialPainter.primaryLabels as List<dynamic>;
expect( expect(
primaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text as TextSpan).text), primaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
labels12To11, labels12To11,
); );
final List<dynamic> secondaryLabels = dialPainter.secondaryLabels as List<dynamic>; final List<dynamic> secondaryLabels = dialPainter.secondaryLabels as List<dynamic>;
expect( expect(
secondaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text as TextSpan).text), secondaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
labels12To11, labels12To11,
); );
}); });
@ -366,13 +366,13 @@ void main() {
final dynamic dialPainter = dialPaint.painter; final dynamic dialPainter = dialPaint.painter;
final List<dynamic> primaryLabels = dialPainter.primaryLabels as List<dynamic>; final List<dynamic> primaryLabels = dialPainter.primaryLabels as List<dynamic>;
expect( expect(
primaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text as TextSpan).text), primaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
labels00To22TwoDigit, labels00To22TwoDigit,
); );
final List<dynamic> secondaryLabels = dialPainter.secondaryLabels as List<dynamic>; final List<dynamic> secondaryLabels = dialPainter.secondaryLabels as List<dynamic>;
expect( expect(
secondaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text as TextSpan).text), secondaryLabels.map<String>((dynamic tp) => ((tp.painter as TextPainter).text! as TextSpan).text!),
labels00To22TwoDigit, labels00To22TwoDigit,
); );
}); });

View File

@ -53,10 +53,10 @@ class FooMaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLoc
} }
Widget buildFrame({ Widget buildFrame({
Locale locale, Locale? locale,
Iterable<LocalizationsDelegate<dynamic>> delegates = GlobalMaterialLocalizations.delegates, Iterable<LocalizationsDelegate<dynamic>> delegates = GlobalMaterialLocalizations.delegates,
WidgetBuilder buildContent, required WidgetBuilder buildContent,
LocaleResolutionCallback localeResolutionCallback, LocaleResolutionCallback? localeResolutionCallback,
Iterable<Locale> supportedLocales = const <Locale>[ Iterable<Locale> supportedLocales = const <Locale>[
Locale('en', 'US'), Locale('en', 'US'),
Locale('es', 'ES'), Locale('es', 'ES'),
@ -210,7 +210,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
// Accept whatever locale we're given // Accept whatever locale we're given
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) => locale, localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
delegates: <FooMaterialLocalizationsDelegate>[ delegates: <FooMaterialLocalizationsDelegate>[
const FooMaterialLocalizationsDelegate(supportedLanguage: 'allLanguages'), const FooMaterialLocalizationsDelegate(supportedLanguage: 'allLanguages'),
], ],

View File

@ -92,7 +92,7 @@ void main() {
expect(topRight, const Offset(477.0, 347.5)); expect(topRight, const Offset(477.0, 347.5));
expect(bottomLeft, const Offset(392.0, 364.5)); expect(bottomLeft, const Offset(392.0, 364.5));
expect(bottomRight, const Offset(477.0, 364.5)); expect(bottomRight, const Offset(477.0, 364.5));
}, skip: !isLinux); });
testWidgets('Text baseline with EN locale', (WidgetTester tester) async { testWidgets('Text baseline with EN locale', (WidgetTester tester) async {
// This test in combination with 'Text baseline with CJK locale' verify the baselines // This test in combination with 'Text baseline with CJK locale' verify the baselines
@ -164,7 +164,6 @@ void main() {
Offset bottomLeft = tester.getBottomLeft(find.text('hello, world')); Offset bottomLeft = tester.getBottomLeft(find.text('hello, world'));
Offset bottomRight = tester.getBottomRight(find.text('hello, world')); Offset bottomRight = tester.getBottomRight(find.text('hello, world'));
expect(topLeft, const Offset(392.0, 300.0)); expect(topLeft, const Offset(392.0, 300.0));
expect(topRight, const Offset(584.0, 300.0)); expect(topRight, const Offset(584.0, 300.0));
expect(bottomLeft, const Offset(392.0, 316)); expect(bottomLeft, const Offset(392.0, 316));
@ -179,5 +178,5 @@ void main() {
expect(topRight, const Offset(472.0, 348.0)); expect(topRight, const Offset(472.0, 348.0));
expect(bottomLeft, const Offset(392.0, 364.0)); expect(bottomLeft, const Offset(392.0, 364.0));
expect(bottomRight, const Offset(472.0, 364.0)); expect(bottomRight, const Offset(472.0, 364.0));
}, skip: !isLinux); });
} }

View File

@ -13,19 +13,21 @@ class TestLocalizations {
TestLocalizations(this.locale, this.prefix); TestLocalizations(this.locale, this.prefix);
final Locale locale; final Locale locale;
final String prefix; final String? prefix;
static Future<TestLocalizations> loadSync(Locale locale, String prefix) { static Future<TestLocalizations> loadSync(Locale locale, String? prefix) {
return SynchronousFuture<TestLocalizations>(TestLocalizations(locale, prefix)); return SynchronousFuture<TestLocalizations>(TestLocalizations(locale, prefix));
} }
static Future<TestLocalizations> loadAsync(Locale locale, String prefix) { static Future<TestLocalizations> loadAsync(Locale locale, String? prefix) {
return Future<TestLocalizations>.delayed(const Duration(milliseconds: 100)) return Future<TestLocalizations>.delayed(
.then((_) => TestLocalizations(locale, prefix)); const Duration(milliseconds: 100),
() => TestLocalizations(locale, prefix)
);
} }
static TestLocalizations of(BuildContext context) { static TestLocalizations of(BuildContext context) {
return Localizations.of<TestLocalizations>(context, TestLocalizations); return Localizations.of<TestLocalizations>(context, TestLocalizations)!;
} }
String get message => '${prefix ?? ""}$locale'; String get message => '${prefix ?? ""}$locale';
@ -34,7 +36,7 @@ class TestLocalizations {
class SyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> { class SyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> {
SyncTestLocalizationsDelegate([this.prefix]); SyncTestLocalizationsDelegate([this.prefix]);
final String prefix; // Changing this value triggers a rebuild final String? prefix; // Changing this value triggers a rebuild
final List<bool> shouldReloadValues = <bool>[]; final List<bool> shouldReloadValues = <bool>[];
@override @override
@ -56,7 +58,7 @@ class SyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizati
class AsyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> { class AsyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> {
AsyncTestLocalizationsDelegate([this.prefix]); AsyncTestLocalizationsDelegate([this.prefix]);
final String prefix; // Changing this value triggers a rebuild final String? prefix; // Changing this value triggers a rebuild
final List<bool> shouldReloadValues = <bool>[]; final List<bool> shouldReloadValues = <bool>[];
@override @override
@ -85,12 +87,14 @@ class MoreLocalizations {
} }
static Future<MoreLocalizations> loadAsync(Locale locale) { static Future<MoreLocalizations> loadAsync(Locale locale) {
return Future<MoreLocalizations>.delayed(const Duration(milliseconds: 100)) return Future<MoreLocalizations>.delayed(
.then((_) => MoreLocalizations(locale)); const Duration(milliseconds: 100),
() => MoreLocalizations(locale)
);
} }
static MoreLocalizations of(BuildContext context) { static MoreLocalizations of(BuildContext context) {
return Localizations.of<MoreLocalizations>(context, MoreLocalizations); return Localizations.of<MoreLocalizations>(context, MoreLocalizations)!;
} }
String get message => '$locale'; String get message => '$locale';
@ -139,10 +143,10 @@ class OnlyRTLDefaultWidgetsLocalizationsDelegate extends LocalizationsDelegate<W
} }
Widget buildFrame({ Widget buildFrame({
Locale locale, Locale? locale,
Iterable<LocalizationsDelegate<dynamic>> delegates, Iterable<LocalizationsDelegate<dynamic>>? delegates,
WidgetBuilder buildContent, required WidgetBuilder buildContent,
LocaleResolutionCallback localeResolutionCallback, LocaleResolutionCallback? localeResolutionCallback,
List<Locale> supportedLocales = const <Locale>[ List<Locale> supportedLocales = const <Locale>[
Locale('en', 'US'), Locale('en', 'US'),
Locale('en', 'GB'), Locale('en', 'GB'),
@ -183,7 +187,7 @@ class SyncLoadTestState extends State<SyncLoadTest> {
void main() { void main() {
testWidgets('Localizations.localeFor in a WidgetsApp with system locale', (WidgetTester tester) async { testWidgets('Localizations.localeFor in a WidgetsApp with system locale', (WidgetTester tester) async {
BuildContext pageContext; late BuildContext pageContext;
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
@ -205,7 +209,7 @@ void main() {
testWidgets('Localizations.localeFor in a WidgetsApp with an explicit locale', (WidgetTester tester) async { testWidgets('Localizations.localeFor in a WidgetsApp with an explicit locale', (WidgetTester tester) async {
const Locale locale = Locale('en', 'US'); const Locale locale = Locale('en', 'US');
BuildContext pageContext; late BuildContext pageContext;
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
@ -477,7 +481,7 @@ void main() {
}); });
testWidgets('Directionality tracks system locale', (WidgetTester tester) async { testWidgets('Directionality tracks system locale', (WidgetTester tester) async {
BuildContext pageContext; late BuildContext pageContext;
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
@ -507,7 +511,7 @@ void main() {
testWidgets('localeResolutionCallback override', (WidgetTester tester) async { testWidgets('localeResolutionCallback override', (WidgetTester tester) async {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
localeResolutionCallback: (Locale newLocale, Iterable<Locale> supportedLocales) { localeResolutionCallback: (Locale? newLocale, Iterable<Locale> supportedLocales) {
return const Locale('foo', 'BAR'); return const Locale('foo', 'BAR');
}, },
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
@ -562,7 +566,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
// Accept whatever locale we're given // Accept whatever locale we're given
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) => locale, localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
delegates: const <LocalizationsDelegate<dynamic>>[ delegates: const <LocalizationsDelegate<dynamic>>[
GlobalWidgetsLocalizations.delegate, GlobalWidgetsLocalizations.delegate,
], ],
@ -571,7 +575,7 @@ void main() {
context: context, context: context,
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
final TextDirection direction = WidgetsLocalizations.of(context).textDirection; final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
return Text('$locale $direction'); return Text('$locale $direction');
}, },
@ -602,7 +606,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
// Accept whatever locale we're given // Accept whatever locale we're given
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) => locale, localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
return Localizations.override( return Localizations.override(
context: context, context: context,
@ -612,7 +616,7 @@ void main() {
], ],
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
final TextDirection direction = WidgetsLocalizations.of(context).textDirection; final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
return Text('$locale $direction'); return Text('$locale $direction');
}, },
@ -643,12 +647,12 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
// Accept whatever locale we're given // Accept whatever locale we're given
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) => locale, localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[ delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[
const OnlyRTLDefaultWidgetsLocalizationsDelegate(), const OnlyRTLDefaultWidgetsLocalizationsDelegate(),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
final TextDirection direction = WidgetsLocalizations.of(context).textDirection; final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
return Text('$locale $direction'); return Text('$locale $direction');
}, },
@ -680,13 +684,13 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
buildFrame( buildFrame(
// Accept whatever locale we're given // Accept whatever locale we're given
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) => locale, localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[ delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[
const OnlyRTLDefaultWidgetsLocalizationsDelegate(), const OnlyRTLDefaultWidgetsLocalizationsDelegate(),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale1 = ui.window.locales.first; final Locale locale1 = ui.window.locales!.first;
final Locale locale2 = ui.window.locales[1]; final Locale locale2 = ui.window.locales![1];
return Text('$locale1 $locale2'); return Text('$locale1 $locale2');
}, },
) )
@ -756,7 +760,7 @@ void main() {
Locale('ja'), Locale('ja'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -779,7 +783,7 @@ void main() {
Locale('zh', 'TW'), Locale('zh', 'TW'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -811,7 +815,7 @@ void main() {
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'), Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -952,7 +956,7 @@ void main() {
Locale.fromSubtags(languageCode: 'zh'), Locale.fromSubtags(languageCode: 'zh'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1092,7 +1096,7 @@ void main() {
Locale('it', 'IT'), Locale('it', 'IT'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1115,7 +1119,7 @@ void main() {
Locale('it', 'IT'), Locale('it', 'IT'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1148,7 +1152,7 @@ void main() {
Locale('pt', 'PT'), Locale('pt', 'PT'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1215,7 +1219,7 @@ void main() {
Locale('de', 'DE'), Locale('de', 'DE'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1279,7 +1283,7 @@ void main() {
Locale('vi'), Locale('vi'),
], ],
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1425,13 +1429,13 @@ void main() {
Locale('en', 'AU'), Locale('en', 'AU'),
Locale('de', 'DE'), Locale('de', 'DE'),
], ],
localeResolutionCallback: (Locale locale, Iterable<Locale> supportedLocales) { localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) {
if (locale == null) if (locale == null)
return const Locale('und', 'US'); return const Locale('und', 'US');
return const Locale('en', 'US'); return const Locale('en', 'US');
}, },
buildContent: (BuildContext context) { buildContent: (BuildContext context) {
final Locale locale = Localizations.localeOf(context); final Locale locale = Localizations.localeOf(context)!;
return Text('$locale'); return Text('$locale');
}, },
) )
@ -1443,10 +1447,6 @@ void main() {
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('en_US'), findsOneWidget); expect(find.text('en_US'), findsOneWidget);
await tester.binding.setLocales(null);
await tester.pumpAndSettle();
expect(find.text('und_US'), findsOneWidget);
await tester.binding.setLocales(const <Locale>[]); await tester.binding.setLocales(const <Locale>[]);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text('und_US'), findsOneWidget); expect(find.text('und_US'), findsOneWidget);