Unverified Commit 4705e0cc authored by Abhishek Ghaskata's avatar Abhishek Ghaskata Committed by GitHub

migrate localization to null safety (#84064)

migrate localization to null safety
parent 4265acd6
...@@ -13,8 +13,6 @@ ...@@ -13,8 +13,6 @@
// This utility is run by `gen_localizations.dart` if --overwrite is passed // This utility is run by `gen_localizations.dart` if --overwrite is passed
// in as an option. // in as an option.
// @dart = 2.8
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
......
...@@ -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 extracts localized date symbols and patterns from the intl /// This program extracts localized date symbols and patterns from the intl
/// package for the subset of locales supported by the flutter_localizations /// package for the subset of locales supported by the flutter_localizations
/// package. /// package.
...@@ -42,7 +40,7 @@ const String _kCommandName = 'gen_date_localizations.dart'; ...@@ -42,7 +40,7 @@ const String _kCommandName = 'gen_date_localizations.dart';
// Date symbols for the Kannada locale ('kn') are handled specially because // Date symbols for the Kannada locale ('kn') are handled specially because
// some of the strings contain characters that can crash Emacs on Linux. // some of the strings contain characters that can crash Emacs on Linux.
// See packages/flutter_localizations/lib/src/l10n/README for more information. // See packages/flutter_localizations/lib/src/l10n/README for more information.
String currentLocale; String? currentLocale;
Future<void> main(List<String> rawArgs) async { Future<void> main(List<String> rawArgs) async {
checkCwdIsRepoRoot(_kCommandName); checkCwdIsRepoRoot(_kCommandName);
...@@ -66,7 +64,7 @@ Future<void> main(List<String> rawArgs) async { ...@@ -66,7 +64,7 @@ Future<void> main(List<String> rawArgs) async {
(String line) => line.startsWith('intl:'), (String line) => line.startsWith('intl:'),
orElse: () { orElse: () {
exitWithError('intl dependency not found in ${dotPackagesFile.path}'); exitWithError('intl dependency not found in ${dotPackagesFile.path}');
return null; // unreachable return ''; // unreachable
}, },
) )
.split(':') .split(':')
...@@ -143,7 +141,7 @@ String _jsonToMap(dynamic json) { ...@@ -143,7 +141,7 @@ String _jsonToMap(dynamic json) {
return '$json'; return '$json';
if (json is String) if (json is String)
return generateEncodedString(currentLocale, json); return generateEncodedString(currentLocale!, json);
if (json is Iterable) { if (json is Iterable) {
final StringBuffer buffer = StringBuffer('<dynamic>['); final StringBuffer buffer = StringBuffer('<dynamic>[');
...@@ -180,7 +178,7 @@ Set<String> _supportedLocales() { ...@@ -180,7 +178,7 @@ Set<String> _supportedLocales() {
for (final FileSystemEntity entity in supportedLocalesDirectory.listSync()) { for (final FileSystemEntity entity in supportedLocalesDirectory.listSync()) {
final String filePath = entity.path; final String filePath = entity.path;
if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath)) { if (FileSystemEntity.isFileSync(filePath) && filenameRE.hasMatch(filePath)) {
supportedLocales.add(filenameRE.firstMatch(filePath)[1]); supportedLocales.add(filenameRE.firstMatch(filePath)![1]!);
} }
} }
...@@ -200,5 +198,5 @@ Map<String, File> _listIntlData(Directory directory) { ...@@ -200,5 +198,5 @@ Map<String, File> _listIntlData(Directory directory) {
final List<String> locales = localeFiles.keys.toList(growable: false); final List<String> locales = localeFiles.keys.toList(growable: false);
locales.sort(); locales.sort();
return Map<String, File>.fromIterable(locales, value: (dynamic locale) => localeFiles[locale]); return Map<String, File>.fromIterable(locales, value: (dynamic locale) => localeFiles[locale]!);
} }
...@@ -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 updates the language locale arb files with any missing resource // This program updates the language locale arb files with any missing resource
// entries that are included in the English arb files. This is useful when // entries that are included in the English arb files. This is useful when
// adding new resources for localization. You can just add the appropriate // adding new resources for localization. You can just add the appropriate
...@@ -68,10 +66,10 @@ bool intentionallyOmitted(String key, Map<String, dynamic> bundle) { ...@@ -68,10 +66,10 @@ bool intentionallyOmitted(String key, Map<String, dynamic> bundle) {
/// Whether `key` corresponds to one of the plural variations of a key with /// Whether `key` corresponds to one of the plural variations of a key with
/// the same prefix and suffix "Other". /// the same prefix and suffix "Other".
bool isPluralVariation(String key, Map<String, dynamic> bundle) { bool isPluralVariation(String key, Map<String, dynamic> bundle) {
final Match pluralMatch = kPluralRegexp.firstMatch(key); final Match? pluralMatch = kPluralRegexp.firstMatch(key);
if (pluralMatch == null) if (pluralMatch == null)
return false; return false;
final String prefix = pluralMatch[1]; final String prefix = pluralMatch[1]!;
return bundle.containsKey('${prefix}Other'); return bundle.containsKey('${prefix}Other');
} }
...@@ -85,7 +83,7 @@ void updateMissingResources(String localizationPath, String groupPrefix) { ...@@ -85,7 +83,7 @@ void updateMissingResources(String localizationPath, String groupPrefix) {
for (final FileSystemEntity entity in localizationDir.listSync().toList()..sort(sortFilesByPath)) { for (final FileSystemEntity entity in localizationDir.listSync().toList()..sort(sortFilesByPath)) {
final String entityPath = entity.path; final String entityPath = entity.path;
if (FileSystemEntity.isFileSync(entityPath) && filenamePattern.hasMatch(entityPath)) { if (FileSystemEntity.isFileSync(entityPath) && filenamePattern.hasMatch(entityPath)) {
final String localeString = filenamePattern.firstMatch(entityPath)[1]; final String localeString = filenamePattern.firstMatch(entityPath)![1]!;
final LocaleInfo locale = LocaleInfo.fromString(localeString); final LocaleInfo locale = LocaleInfo.fromString(localeString);
// Only look at top-level language locales // Only look at top-level language locales
......
...@@ -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
import 'localizations_utils.dart'; import 'localizations_utils.dart';
String generateCupertinoHeader(String regenerateInstructions) { String generateCupertinoHeader(String regenerateInstructions) {
......
...@@ -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
import 'localizations_utils.dart'; import 'localizations_utils.dart';
String generateMaterialHeader(String regenerateInstructions) { String generateMaterialHeader(String regenerateInstructions) {
......
...@@ -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
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
...@@ -23,11 +21,11 @@ int sortFilesByPath (FileSystemEntity a, FileSystemEntity b) { ...@@ -23,11 +21,11 @@ int sortFilesByPath (FileSystemEntity a, FileSystemEntity b) {
@immutable @immutable
class LocaleInfo implements Comparable<LocaleInfo> { class LocaleInfo implements Comparable<LocaleInfo> {
const LocaleInfo({ const LocaleInfo({
this.languageCode, required this.languageCode,
this.scriptCode, this.scriptCode,
this.countryCode, this.countryCode,
this.length, required this.length,
this.originalString, required this.originalString,
}); });
/// Simple parser. Expects the locale string to be in the form of 'language_script_COUNTRY' /// Simple parser. Expects the locale string to be in the form of 'language_script_COUNTRY'
...@@ -42,8 +40,8 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -42,8 +40,8 @@ class LocaleInfo implements Comparable<LocaleInfo> {
final List<String> codes = locale.split('_'); // [language, script, country] final List<String> codes = locale.split('_'); // [language, script, country]
assert(codes.isNotEmpty && codes.length < 4); assert(codes.isNotEmpty && codes.length < 4);
final String languageCode = codes[0]; final String languageCode = codes[0];
String scriptCode; String? scriptCode;
String countryCode; String? countryCode;
int length = codes.length; int length = codes.length;
String originalString = locale; String originalString = locale;
if (codes.length == 2) { if (codes.length == 2) {
...@@ -111,8 +109,8 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -111,8 +109,8 @@ class LocaleInfo implements Comparable<LocaleInfo> {
} }
final String languageCode; final String languageCode;
final String scriptCode; final String? scriptCode;
final String countryCode; final String? countryCode;
final int length; // The number of fields. Ranges from 1-3. final int length; // The number of fields. Ranges from 1-3.
final String originalString; // Original un-parsed locale string. final String originalString; // Original un-parsed locale string.
...@@ -148,10 +146,10 @@ class LocaleInfo implements Comparable<LocaleInfo> { ...@@ -148,10 +146,10 @@ class LocaleInfo implements Comparable<LocaleInfo> {
/// Parse the data for a locale from a file, and store it in the [attributes] /// Parse the data for a locale from a file, and store it in the [attributes]
/// and [resources] keys. /// and [resources] keys.
void loadMatchingArbsIntoBundleMaps({ void loadMatchingArbsIntoBundleMaps({
@required Directory directory, required Directory directory,
@required RegExp filenamePattern, required RegExp filenamePattern,
@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,
}) { }) {
assert(directory != null); assert(directory != null);
assert(filenamePattern != null); assert(filenamePattern != null);
...@@ -169,13 +167,13 @@ void loadMatchingArbsIntoBundleMaps({ ...@@ -169,13 +167,13 @@ void loadMatchingArbsIntoBundleMaps({
for (final FileSystemEntity entity in directory.listSync().toList()..sort(sortFilesByPath)) { for (final FileSystemEntity entity in directory.listSync().toList()..sort(sortFilesByPath)) {
final String entityPath = entity.path; final String entityPath = entity.path;
if (FileSystemEntity.isFileSync(entityPath) && filenamePattern.hasMatch(entityPath)) { if (FileSystemEntity.isFileSync(entityPath) && filenamePattern.hasMatch(entityPath)) {
final String localeString = filenamePattern.firstMatch(entityPath)[1]; final String localeString = filenamePattern.firstMatch(entityPath)![1]!;
final File arbFile = File(entityPath); final File arbFile = File(entityPath);
// Helper method to fill the maps with the correct data from file. // Helper method to fill the maps with the correct data from file.
void populateResources(LocaleInfo locale, File file) { void populateResources(LocaleInfo locale, File file) {
final Map<String, String> resources = localeToResources[locale]; final Map<String, String> resources = localeToResources[locale]!;
final Map<String, dynamic> attributes = localeToResourceAttributes[locale]; final Map<String, dynamic> attributes = localeToResourceAttributes[locale]!;
final Map<String, dynamic> bundle = json.decode(file.readAsStringSync()) as Map<String, dynamic>; final Map<String, dynamic> bundle = json.decode(file.readAsStringSync()) as Map<String, dynamic>;
for (final String key in bundle.keys) { for (final String key in bundle.keys) {
// The ARB file resource "attributes" for foo are called @foo. // The ARB file resource "attributes" for foo are called @foo.
...@@ -258,9 +256,9 @@ GeneratorOptions parseArgs(List<String> rawArgs) { ...@@ -258,9 +256,9 @@ GeneratorOptions parseArgs(List<String> rawArgs) {
class GeneratorOptions { class GeneratorOptions {
GeneratorOptions({ GeneratorOptions({
@required this.writeToFile, required this.writeToFile,
@required this.materialOnly, required this.materialOnly,
@required this.cupertinoOnly, required this.cupertinoOnly,
}); });
final bool writeToFile; final bool writeToFile;
...@@ -271,7 +269,7 @@ class GeneratorOptions { ...@@ -271,7 +269,7 @@ class GeneratorOptions {
// See also //master/tools/gen_locale.dart in the engine repo. // See also //master/tools/gen_locale.dart in the engine repo.
Map<String, List<String>> _parseSection(String section) { Map<String, List<String>> _parseSection(String section) {
final Map<String, List<String>> result = <String, List<String>>{}; final Map<String, List<String>> result = <String, List<String>>{};
List<String> lastHeading; late List<String> lastHeading;
for (final String line in section.split('\n')) { for (final String line in section.split('\n')) {
if (line == '') if (line == '')
continue; continue;
...@@ -285,7 +283,7 @@ Map<String, List<String>> _parseSection(String section) { ...@@ -285,7 +283,7 @@ Map<String, List<String>> _parseSection(String section) {
final String name = line.substring(0, colon); final String name = line.substring(0, colon);
final String value = line.substring(colon + 2); final String value = line.substring(colon + 2);
lastHeading = result.putIfAbsent(name, () => <String>[]); lastHeading = result.putIfAbsent(name, () => <String>[]);
result[name].add(value); result[name]!.add(value);
} }
return result; return result;
} }
...@@ -304,11 +302,11 @@ void precacheLanguageAndRegionTags() { ...@@ -304,11 +302,11 @@ void precacheLanguageAndRegionTags() {
languageSubtagRegistry.split('%%').skip(1).map<Map<String, List<String>>>(_parseSection).toList(); languageSubtagRegistry.split('%%').skip(1).map<Map<String, List<String>>>(_parseSection).toList();
for (final Map<String, List<String>> section in sections) { for (final Map<String, List<String>> section in sections) {
assert(section.containsKey('Type'), section.toString()); assert(section.containsKey('Type'), section.toString());
final String type = section['Type'].single; final String type = section['Type']!.single;
if (type == 'language' || type == 'region' || type == 'script') { if (type == 'language' || type == 'region' || type == 'script') {
assert(section.containsKey('Subtag') && section.containsKey('Description'), section.toString()); assert(section.containsKey('Subtag') && section.containsKey('Description'), section.toString());
final String subtag = section['Subtag'].single; final String subtag = section['Subtag']!.single;
String description = section['Description'].join(' '); String description = section['Description']!.join(' ');
if (description.startsWith('United ')) if (description.startsWith('United '))
description = 'the $description'; description = 'the $description';
if (description.contains(kParentheticalPrefix)) if (description.contains(kParentheticalPrefix))
...@@ -336,10 +334,10 @@ String describeLocale(String tag) { ...@@ -336,10 +334,10 @@ String describeLocale(String tag) {
final List<String> subtags = tag.split('_'); final List<String> subtags = tag.split('_');
assert(subtags.isNotEmpty); assert(subtags.isNotEmpty);
assert(_languages.containsKey(subtags[0])); assert(_languages.containsKey(subtags[0]));
final String language = _languages[subtags[0]]; final String language = _languages[subtags[0]]!;
String output = language; String output = language;
String region; String? region;
String script; String? script;
if (subtags.length == 2) { if (subtags.length == 2) {
region = _regions[subtags[1]]; region = _regions[subtags[1]];
script = _scripts[subtags[1]]; script = _scripts[subtags[1]];
......
...@@ -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
import 'dart:convert' show json; import 'dart:convert' show json;
import 'dart:io'; import 'dart:io';
...@@ -62,7 +60,7 @@ void validateEnglishLocalizations(File file) { ...@@ -62,7 +60,7 @@ void validateEnglishLocalizations(File file) {
continue; continue;
final dynamic atResourceValue = bundle[atResourceId]; final dynamic atResourceValue = bundle[atResourceId];
final Map<String, dynamic> atResource = final Map<String, dynamic>? atResource =
atResourceValue is Map<String, dynamic> ? atResourceValue : null; atResourceValue is Map<String, dynamic> ? atResourceValue : null;
if (atResource == null) { if (atResource == null) {
errorMessages.writeln('A map value was not specified for $atResourceId'); errorMessages.writeln('A map value was not specified for $atResourceId');
...@@ -103,12 +101,12 @@ void validateLocalizations( ...@@ -103,12 +101,12 @@ void validateLocalizations(
Map<LocaleInfo, Map<String, String>> localeToResources, Map<LocaleInfo, Map<String, String>> localeToResources,
Map<LocaleInfo, Map<String, dynamic>> localeToAttributes, Map<LocaleInfo, Map<String, dynamic>> localeToAttributes,
) { ) {
final Map<String, String> canonicalLocalizations = localeToResources[LocaleInfo.fromString('en')]; final Map<String, String> canonicalLocalizations = localeToResources[LocaleInfo.fromString('en')]!;
final Set<String> canonicalKeys = Set<String>.from(canonicalLocalizations.keys); final Set<String> canonicalKeys = Set<String>.from(canonicalLocalizations.keys);
final StringBuffer errorMessages = StringBuffer(); final StringBuffer errorMessages = StringBuffer();
bool explainMissingKeys = false; bool explainMissingKeys = false;
for (final LocaleInfo locale in localeToResources.keys) { for (final LocaleInfo locale in localeToResources.keys) {
final Map<String, String> resources = localeToResources[locale]; final Map<String, String> resources = localeToResources[locale]!;
// Whether `key` corresponds to one of the plural variations of a key with // Whether `key` corresponds to one of the plural variations of a key with
// the same prefix and suffix "Other". // the same prefix and suffix "Other".
...@@ -116,10 +114,10 @@ void validateLocalizations( ...@@ -116,10 +114,10 @@ void validateLocalizations(
// Many languages require only a subset of these variations, so we do not // Many languages require only a subset of these variations, so we do not
// require them so long as the "Other" variation exists. // require them so long as the "Other" variation exists.
bool isPluralVariation(String key) { bool isPluralVariation(String key) {
final Match pluralMatch = kPluralRegexp.firstMatch(key); final Match? pluralMatch = kPluralRegexp.firstMatch(key);
if (pluralMatch == null) if (pluralMatch == null)
return false; return false;
final String prefix = pluralMatch[1]; final String? prefix = pluralMatch[1];
return resources.containsKey('${prefix}Other'); return resources.containsKey('${prefix}Other');
} }
...@@ -135,10 +133,10 @@ void validateLocalizations( ...@@ -135,10 +133,10 @@ void validateLocalizations(
// For language-level locales only, check that they have a complete list of // For language-level locales only, check that they have a complete list of
// keys, or opted out of using certain ones. // keys, or opted out of using certain ones.
if (locale.length == 1) { if (locale.length == 1) {
final Map<String, dynamic> attributes = localeToAttributes[locale]; final Map<String, dynamic>? attributes = localeToAttributes[locale];
final List<String> missingKeys = <String>[]; final List<String?> missingKeys = <String?>[];
for (final String missingKey in canonicalKeys.difference(keys)) { for (final String missingKey in canonicalKeys.difference(keys)) {
final dynamic attribute = attributes[missingKey]; final dynamic attribute = attributes?[missingKey];
final bool intentionallyOmitted = attribute is Map && attribute.containsKey('notUsed'); final bool intentionallyOmitted = attribute is Map && attribute.containsKey('notUsed');
if (!intentionallyOmitted && !isPluralVariation(missingKey)) if (!intentionallyOmitted && !isPluralVariation(missingKey))
missingKeys.add(missingKey); missingKeys.add(missingKey);
......
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