Unverified Commit 5456cad3 authored by Christopher Fujino's avatar Christopher Fujino Committed by GitHub

Migrate gen_localizations to null-safety (#86051)

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