Unverified Commit 1c7e34bb authored by Darren Austin's avatar Darren Austin Committed by GitHub

Migrate flutter_localizations to null safety. (#68645)

Migrate flutter_localizations to null safety.
parent 2a5aa294
...@@ -704,7 +704,7 @@ Future<void> _runFrameworkTests() async { ...@@ -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);
......
...@@ -382,15 +382,20 @@ $factoryDeclaration ...@@ -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.
......
...@@ -16,7 +16,6 @@ HeaderGenerator generateCupertinoHeader = (String regenerateInstructions) { ...@@ -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) { ...@@ -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) { ...@@ -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,
......
...@@ -16,7 +16,6 @@ HeaderGenerator generateMaterialHeader = (String regenerateInstructions) { ...@@ -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) { ...@@ -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) { ...@@ -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,
......
...@@ -67,8 +67,9 @@ void validateEnglishLocalizations(File 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) { ...@@ -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');
} }
} }
......
...@@ -1763,9 +1763,10 @@ class _CupertinoTimerPickerState extends State<CupertinoTimerPicker> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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,
), ),
], ],
......
...@@ -108,7 +108,7 @@ abstract class CupertinoLocalizations { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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]
......
# 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.
{ {
"@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 @@ ...@@ -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.",
......
...@@ -73,7 +73,22 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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.",
......
{ {
"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": "شاته",
......
...@@ -28,7 +28,7 @@ void loadDateIntlDataIfNotLoaded() { ...@@ -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) {
......
...@@ -43,7 +43,7 @@ class GlobalWidgetsLocalizations implements WidgetsLocalizations { ...@@ -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.
......
...@@ -2,7 +2,7 @@ name: flutter_localizations ...@@ -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".
......
...@@ -63,7 +63,7 @@ void main() { ...@@ -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 ...@@ -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();
} }
} }
...@@ -9,9 +9,9 @@ import 'package:flutter_localizations/flutter_localizations.dart'; ...@@ -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() { ...@@ -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() { ...@@ -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);
......
...@@ -163,7 +163,7 @@ void main() { ...@@ -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() { ...@@ -180,7 +180,7 @@ void main() {
}), }),
)); ));
expect(dateFormat?.locale, 'en_US'); expect(dateFormat.locale, 'en_US');
}); });
} }
......
...@@ -9,13 +9,13 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -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 { ...@@ -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 { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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() { ...@@ -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,
); );
}); });
......
...@@ -53,10 +53,10 @@ class FooMaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLoc ...@@ -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() { ...@@ -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'),
], ],
......
...@@ -92,7 +92,7 @@ void main() { ...@@ -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() { ...@@ -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() { ...@@ -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); });
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment