Migrate gen_localizations to null-safety (#86051)
This commit is contained in:
parent
a666925a02
commit
5456cad343
@ -2,8 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// @dart = 2.8
|
||||
|
||||
// This program generates a getMaterialTranslation() and a
|
||||
// getCupertinoTranslation() function that look up the translations provided by
|
||||
// the arb files. The returned value is a generated instance of a
|
||||
@ -44,7 +42,6 @@
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import '../gen_cupertino_localizations.dart';
|
||||
@ -55,17 +52,17 @@ import 'encode_kn_arb_files.dart';
|
||||
|
||||
/// This is the core of this script; it generates the code used for translations.
|
||||
String generateArbBasedLocalizationSubclasses({
|
||||
@required Map<LocaleInfo, Map<String, String>> localeToResources,
|
||||
@required Map<LocaleInfo, Map<String, dynamic>> localeToResourceAttributes,
|
||||
@required String generatedClassPrefix,
|
||||
@required String baseClass,
|
||||
@required HeaderGenerator generateHeader,
|
||||
@required ConstructorGenerator generateConstructor,
|
||||
@required String factoryName,
|
||||
@required String factoryDeclaration,
|
||||
@required String factoryArguments,
|
||||
@required String supportedLanguagesConstant,
|
||||
@required String supportedLanguagesDocMacro,
|
||||
required Map<LocaleInfo, Map<String, String>> localeToResources,
|
||||
required Map<LocaleInfo, Map<String, dynamic>> localeToResourceAttributes,
|
||||
required String generatedClassPrefix,
|
||||
required String baseClass,
|
||||
required HeaderGenerator generateHeader,
|
||||
required ConstructorGenerator generateConstructor,
|
||||
required String factoryName,
|
||||
required String factoryDeclaration,
|
||||
required String factoryArguments,
|
||||
required String supportedLanguagesConstant,
|
||||
required String supportedLanguagesDocMacro,
|
||||
}) {
|
||||
assert(localeToResources != null);
|
||||
assert(localeToResourceAttributes != null);
|
||||
@ -92,16 +89,16 @@ String generateArbBasedLocalizationSubclasses({
|
||||
for (final LocaleInfo locale in localeToResources.keys.toList()..sort()) {
|
||||
if (locale.scriptCode != null) {
|
||||
languageToScriptCodes[locale.languageCode] ??= <String>{};
|
||||
languageToScriptCodes[locale.languageCode].add(locale.scriptCode);
|
||||
languageToScriptCodes[locale.languageCode]!.add(locale.scriptCode!);
|
||||
}
|
||||
if (locale.countryCode != null && locale.scriptCode != null) {
|
||||
final LocaleInfo key = LocaleInfo.fromString('${locale.languageCode}_${locale.scriptCode}');
|
||||
languageAndScriptToCountryCodes[key] ??= <String>{};
|
||||
languageAndScriptToCountryCodes[key].add(locale.countryCode);
|
||||
languageAndScriptToCountryCodes[key]!.add(locale.countryCode!);
|
||||
}
|
||||
languageToLocales[locale.languageCode] ??= <LocaleInfo>[];
|
||||
languageToLocales[locale.languageCode].add(locale);
|
||||
allResourceIdentifiers.addAll(localeToResources[locale].keys.toList()..sort());
|
||||
languageToLocales[locale.languageCode]!.add(locale);
|
||||
allResourceIdentifiers.addAll(localeToResources[locale]!.keys.toList()..sort());
|
||||
}
|
||||
|
||||
// We generate one class per supported language (e.g.
|
||||
@ -137,19 +134,19 @@ String generateArbBasedLocalizationSubclasses({
|
||||
output.writeln(generateClassDeclaration(languageLocale, generatedClassPrefix, baseClass));
|
||||
output.writeln(generateConstructor(languageLocale));
|
||||
|
||||
final Map<String, String> languageResources = localeToResources[languageLocale];
|
||||
final Map<String, String> languageResources = localeToResources[languageLocale]!;
|
||||
for (final String key in allKeys) {
|
||||
final Map<String, dynamic> attributes = localeToResourceAttributes[canonicalLocale][key] as Map<String, dynamic>;
|
||||
final Map<String, dynamic>? attributes = localeToResourceAttributes[canonicalLocale]![key] as Map<String, dynamic>?;
|
||||
output.writeln(generateGetter(key, languageResources[key], attributes, languageLocale));
|
||||
}
|
||||
output.writeln('}');
|
||||
int countryCodeCount = 0;
|
||||
int scriptCodeCount = 0;
|
||||
if (languageToScriptCodes.containsKey(languageName)) {
|
||||
scriptCodeCount = languageToScriptCodes[languageName].length;
|
||||
scriptCodeCount = languageToScriptCodes[languageName]!.length;
|
||||
// Language has scriptCodes, so we need to properly fallback countries to corresponding
|
||||
// script default values before language default values.
|
||||
for (final String scriptCode in languageToScriptCodes[languageName]) {
|
||||
for (final String scriptCode in languageToScriptCodes[languageName]!) {
|
||||
final LocaleInfo scriptBaseLocale = LocaleInfo.fromString('${languageName}_$scriptCode');
|
||||
output.writeln(generateClassDeclaration(
|
||||
scriptBaseLocale,
|
||||
@ -157,16 +154,16 @@ String generateArbBasedLocalizationSubclasses({
|
||||
'$generatedClassPrefix${languageLocale.camelCase()}',
|
||||
));
|
||||
output.writeln(generateConstructor(scriptBaseLocale));
|
||||
final Map<String, String> scriptResources = localeToResources[scriptBaseLocale];
|
||||
final Map<String, String> scriptResources = localeToResources[scriptBaseLocale]!;
|
||||
for (final String key in scriptResources.keys.toList()..sort()) {
|
||||
if (languageResources[key] == scriptResources[key])
|
||||
continue;
|
||||
final Map<String, dynamic> attributes = localeToResourceAttributes[canonicalLocale][key] as Map<String, dynamic>;
|
||||
final Map<String, dynamic>? attributes = localeToResourceAttributes[canonicalLocale]![key] as Map<String, dynamic>?;
|
||||
output.writeln(generateGetter(key, scriptResources[key], attributes, languageLocale));
|
||||
}
|
||||
output.writeln('}');
|
||||
|
||||
final List<LocaleInfo> localeCodes = languageToLocales[languageName]..sort();
|
||||
final List<LocaleInfo> localeCodes = languageToLocales[languageName]!..sort();
|
||||
for (final LocaleInfo locale in localeCodes) {
|
||||
if (locale.originalString == languageName)
|
||||
continue;
|
||||
@ -181,12 +178,12 @@ String generateArbBasedLocalizationSubclasses({
|
||||
'$generatedClassPrefix${scriptBaseLocale.camelCase()}',
|
||||
));
|
||||
output.writeln(generateConstructor(locale));
|
||||
final Map<String, String> localeResources = localeToResources[locale];
|
||||
final Map<String, String> localeResources = localeToResources[locale]!;
|
||||
for (final String key in localeResources.keys) {
|
||||
// When script fallback contains the key, we compare to it instead of language fallback.
|
||||
if (scriptResources.containsKey(key) ? scriptResources[key] == localeResources[key] : languageResources[key] == localeResources[key])
|
||||
continue;
|
||||
final Map<String, dynamic> attributes = localeToResourceAttributes[canonicalLocale][key] as Map<String, dynamic>;
|
||||
final Map<String, dynamic>? attributes = localeToResourceAttributes[canonicalLocale]![key] as Map<String, dynamic>?;
|
||||
output.writeln(generateGetter(key, localeResources[key], attributes, languageLocale));
|
||||
}
|
||||
output.writeln('}');
|
||||
@ -195,12 +192,12 @@ String generateArbBasedLocalizationSubclasses({
|
||||
} else {
|
||||
// No scriptCode. Here, we do not compare against script default (because it
|
||||
// doesn't exist).
|
||||
final List<LocaleInfo> localeCodes = languageToLocales[languageName]..sort();
|
||||
final List<LocaleInfo> localeCodes = languageToLocales[languageName]!..sort();
|
||||
for (final LocaleInfo locale in localeCodes) {
|
||||
if (locale.originalString == languageName)
|
||||
continue;
|
||||
countryCodeCount += 1;
|
||||
final Map<String, String> localeResources = localeToResources[locale];
|
||||
final Map<String, String> localeResources = localeToResources[locale]!;
|
||||
output.writeln(generateClassDeclaration(
|
||||
locale,
|
||||
generatedClassPrefix,
|
||||
@ -210,7 +207,7 @@ String generateArbBasedLocalizationSubclasses({
|
||||
for (final String key in localeResources.keys) {
|
||||
if (languageResources[key] == localeResources[key])
|
||||
continue;
|
||||
final Map<String, dynamic> attributes = localeToResourceAttributes[canonicalLocale][key] as Map<String, dynamic>;
|
||||
final Map<String, dynamic>? attributes = localeToResourceAttributes[canonicalLocale]![key] as Map<String, dynamic>?;
|
||||
output.writeln(generateGetter(key, localeResources[key], attributes, languageLocale));
|
||||
}
|
||||
output.writeln('}');
|
||||
@ -268,19 +265,19 @@ $factoryDeclaration
|
||||
switch (locale.languageCode) {''');
|
||||
for (final String language in languageToLocales.keys) {
|
||||
// Only one instance of the language.
|
||||
if (languageToLocales[language].length == 1) {
|
||||
if (languageToLocales[language]!.length == 1) {
|
||||
output.writeln('''
|
||||
case '$language':
|
||||
return $generatedClassPrefix${languageToLocales[language][0].camelCase()}($factoryArguments);''');
|
||||
return $generatedClassPrefix${languageToLocales[language]![0].camelCase()}($factoryArguments);''');
|
||||
} else if (!languageToScriptCodes.containsKey(language)) { // Does not distinguish between scripts. Switch on countryCode directly.
|
||||
output.writeln('''
|
||||
case '$language': {
|
||||
switch (locale.countryCode) {''');
|
||||
for (final LocaleInfo locale in languageToLocales[language]) {
|
||||
for (final LocaleInfo locale in languageToLocales[language]!) {
|
||||
if (locale.originalString == language)
|
||||
continue;
|
||||
assert(locale.length > 1);
|
||||
final String countryCode = locale.countryCode;
|
||||
final String countryCode = locale.countryCode!;
|
||||
output.writeln('''
|
||||
case '$countryCode':
|
||||
return $generatedClassPrefix${locale.camelCase()}($factoryArguments);''');
|
||||
@ -294,14 +291,14 @@ $factoryDeclaration
|
||||
output.writeln('''
|
||||
case '$language': {
|
||||
switch (locale.scriptCode) {''');
|
||||
for (final String scriptCode in languageToScriptCodes[language]) {
|
||||
for (final String scriptCode in languageToScriptCodes[language]!) {
|
||||
final LocaleInfo scriptLocale = LocaleInfo.fromString('${language}_$scriptCode');
|
||||
output.writeln('''
|
||||
case '$scriptCode': {''');
|
||||
if (languageAndScriptToCountryCodes.containsKey(scriptLocale)) {
|
||||
output.writeln('''
|
||||
switch (locale.countryCode) {''');
|
||||
for (final LocaleInfo locale in languageToLocales[language]) {
|
||||
for (final LocaleInfo locale in languageToLocales[language]!) {
|
||||
if (locale.countryCode == null)
|
||||
continue;
|
||||
else
|
||||
@ -310,7 +307,7 @@ $factoryDeclaration
|
||||
continue;
|
||||
if (locale.scriptCode != scriptCode && locale.scriptCode != null)
|
||||
continue;
|
||||
final String countryCode = locale.countryCode;
|
||||
final String countryCode = locale.countryCode!;
|
||||
output.writeln('''
|
||||
case '$countryCode':
|
||||
return $generatedClassPrefix${locale.camelCase()}($factoryArguments);''');
|
||||
@ -319,7 +316,7 @@ $factoryDeclaration
|
||||
// Return a fallback locale that matches scriptCode, but not countryCode.
|
||||
//
|
||||
// Explicitly defined scriptCode fallback:
|
||||
if (languageToLocales[language].contains(scriptLocale)) {
|
||||
if (languageToLocales[language]!.contains(scriptLocale)) {
|
||||
if (languageAndScriptToCountryCodes.containsKey(scriptLocale)) {
|
||||
output.writeln('''
|
||||
}''');
|
||||
@ -330,7 +327,7 @@ $factoryDeclaration
|
||||
} else {
|
||||
// Not Explicitly defined, fallback to first locale with the same language and
|
||||
// script:
|
||||
for (final LocaleInfo locale in languageToLocales[language]) {
|
||||
for (final LocaleInfo locale in languageToLocales[language]!) {
|
||||
if (locale.scriptCode != scriptCode)
|
||||
continue;
|
||||
if (languageAndScriptToCountryCodes.containsKey(scriptLocale)) {
|
||||
@ -349,13 +346,13 @@ $factoryDeclaration
|
||||
if (hasCountryCode) {
|
||||
output.writeln('''
|
||||
switch (locale.countryCode) {''');
|
||||
for (final LocaleInfo locale in languageToLocales[language]) {
|
||||
for (final LocaleInfo locale in languageToLocales[language]!) {
|
||||
if (locale.originalString == language)
|
||||
continue;
|
||||
assert(locale.length > 1);
|
||||
if (locale.countryCode == null)
|
||||
continue;
|
||||
final String countryCode = locale.countryCode;
|
||||
final String countryCode = locale.countryCode!;
|
||||
output.writeln('''
|
||||
case '$countryCode':
|
||||
return $generatedClassPrefix${locale.camelCase()}($factoryArguments);''');
|
||||
@ -382,12 +379,12 @@ $factoryDeclaration
|
||||
/// Typically "String", but some (e.g. "timeOfDayFormat") return enums.
|
||||
///
|
||||
/// 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) {
|
||||
optional = attributes.containsKey('optional');
|
||||
switch (attributes['x-flutter-type'] as String) {
|
||||
switch (attributes['x-flutter-type'] as String?) {
|
||||
case 'icuShortTimePattern':
|
||||
type = 'TimeOfDayFormat';
|
||||
break;
|
||||
@ -406,11 +403,11 @@ String generateType(Map<String, dynamic> attributes) {
|
||||
/// those we have to therefore provide an alternate name.
|
||||
///
|
||||
/// Used by [generateGetter] below.
|
||||
String generateKey(String key, Map<String, dynamic> attributes) {
|
||||
String generateKey(String key, Map<String, dynamic>? attributes) {
|
||||
if (attributes != null) {
|
||||
if (attributes.containsKey('parameters'))
|
||||
return '${key}Raw';
|
||||
switch (attributes['x-flutter-type'] as String) {
|
||||
switch (attributes['x-flutter-type'] as String?) {
|
||||
case 'icuShortTimePattern':
|
||||
return '${key}Raw';
|
||||
}
|
||||
@ -447,12 +444,12 @@ const Map<String, String> _scriptCategoryToEnum = <String, String>{
|
||||
/// it.
|
||||
///
|
||||
/// Used by [generateGetter] below.
|
||||
String generateValue(String value, Map<String, dynamic> attributes, LocaleInfo locale) {
|
||||
String? generateValue(String? value, Map<String, dynamic>? attributes, LocaleInfo locale) {
|
||||
if (value == null)
|
||||
return null;
|
||||
// cupertino_en.arb doesn't use x-flutter-type.
|
||||
if (attributes != null) {
|
||||
switch (attributes['x-flutter-type'] as String) {
|
||||
switch (attributes['x-flutter-type'] as String?) {
|
||||
case 'icuShortTimePattern':
|
||||
if (!_icuTimeOfDayToEnum.containsKey(value)) {
|
||||
throw Exception(
|
||||
@ -479,14 +476,14 @@ String generateValue(String value, Map<String, dynamic> attributes, LocaleInfo l
|
||||
/// Combines [generateType], [generateKey], and [generateValue] to return
|
||||
/// the source of getters for the GlobalMaterialLocalizations subclass.
|
||||
/// The locale is the locale for which the getter is being generated.
|
||||
String generateGetter(String key, String value, Map<String, dynamic> attributes, LocaleInfo locale) {
|
||||
String generateGetter(String key, String? value, Map<String, dynamic>? attributes, LocaleInfo locale) {
|
||||
final String type = generateType(attributes);
|
||||
key = generateKey(key, attributes);
|
||||
value = generateValue(value, attributes, locale);
|
||||
final String? generatedValue = generateValue(value, attributes, locale);
|
||||
return '''
|
||||
|
||||
@override
|
||||
$type get $key => $value;''';
|
||||
$type get $key => $generatedValue;''';
|
||||
}
|
||||
|
||||
void main(List<String> rawArgs) {
|
||||
@ -551,7 +548,7 @@ void main(List<String> rawArgs) {
|
||||
exitWithError('$exception');
|
||||
}
|
||||
|
||||
final String materialLocalizations = options.writeToFile || !options.cupertinoOnly
|
||||
final String? materialLocalizations = options.writeToFile || !options.cupertinoOnly
|
||||
? generateArbBasedLocalizationSubclasses(
|
||||
localeToResources: materialLocaleToResources,
|
||||
localeToResourceAttributes: materialLocaleToResourceAttributes,
|
||||
@ -566,7 +563,7 @@ void main(List<String> rawArgs) {
|
||||
supportedLanguagesDocMacro: materialSupportedLanguagesDocMacro,
|
||||
)
|
||||
: null;
|
||||
final String cupertinoLocalizations = options.writeToFile || !options.materialOnly
|
||||
final String? cupertinoLocalizations = options.writeToFile || !options.materialOnly
|
||||
? generateArbBasedLocalizationSubclasses(
|
||||
localeToResources: cupertinoLocaleToResources,
|
||||
localeToResourceAttributes: cupertinoLocaleToResourceAttributes,
|
||||
@ -584,9 +581,9 @@ void main(List<String> rawArgs) {
|
||||
|
||||
if (options.writeToFile) {
|
||||
final File materialLocalizationsFile = File(path.join(directory.path, 'generated_material_localizations.dart'));
|
||||
materialLocalizationsFile.writeAsStringSync(materialLocalizations, flush: true);
|
||||
materialLocalizationsFile.writeAsStringSync(materialLocalizations!, flush: true);
|
||||
final File cupertinoLocalizationsFile = File(path.join(directory.path, 'generated_cupertino_localizations.dart'));
|
||||
cupertinoLocalizationsFile.writeAsStringSync(cupertinoLocalizations, flush: true);
|
||||
cupertinoLocalizationsFile.writeAsStringSync(cupertinoLocalizations!, flush: true);
|
||||
} else {
|
||||
if (!options.cupertinoOnly) {
|
||||
stdout.write(materialLocalizations);
|
||||
|
@ -68,11 +68,11 @@ void validateEnglishLocalizations(File file) {
|
||||
}
|
||||
|
||||
final bool optional = atResource.containsKey('optional');
|
||||
final String description = atResource['description'] as String;
|
||||
final String? description = atResource['description'] as String?;
|
||||
if (description == null && !optional)
|
||||
errorMessages.writeln('No description specified for $atResourceId');
|
||||
|
||||
final String plural = atResource['plural'] as String;
|
||||
final String? plural = atResource['plural'] as String?;
|
||||
final String resourceId = atResourceId.substring(1);
|
||||
if (plural != null) {
|
||||
final String resourceIdOther = '${resourceId}Other';
|
||||
|
Loading…
x
Reference in New Issue
Block a user