mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[gen_l10n] Update the arb filename parsing logic (#60185)
* Update the arb filename parsing to account for underscores * Generalize the locale searching algorithm * Update filename and @@locale behavior to require them to match
This commit is contained in:
parent
98d66de888
commit
1e6e7150f3
@ -5,6 +5,9 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:intl/locale.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'localizations_utils.dart';
|
||||
|
||||
// The set of date formats that can be automatically localized.
|
||||
@ -374,19 +377,53 @@ class AppResourceBundle {
|
||||
}
|
||||
|
||||
String localeString = resources['@@locale'] as String;
|
||||
if (localeString == null) {
|
||||
final RegExp filenameRE = RegExp(r'^[^_]*_(\w+)\.arb$');
|
||||
final RegExpMatch match = filenameRE.firstMatch(file.path);
|
||||
localeString = match == null ? null : match[1];
|
||||
|
||||
// Look for the first instance of an ISO 639-1 language code, matching exactly.
|
||||
final String fileName = path.basenameWithoutExtension(file.path);
|
||||
|
||||
for (int index = 0; index < fileName.length; index += 1) {
|
||||
// If an underscore was found, check if locale string follows.
|
||||
if (fileName[index] == '_' && fileName[index + 1] != null) {
|
||||
// If Locale.tryParse fails, it returns null.
|
||||
final Locale parserResult = Locale.tryParse(fileName.substring(index + 1));
|
||||
// If the parserResult is not an actual locale identifier, end the loop.
|
||||
if (parserResult != null && _iso639Languages.contains(parserResult.languageCode)) {
|
||||
// The parsed result uses dashes ('-'), but we want underscores ('_').
|
||||
final String parserLocaleString = parserResult.toString().replaceAll('-', '_');
|
||||
|
||||
|
||||
if (localeString == null) {
|
||||
// If @@locale was not defined, use the filename locale suffix.
|
||||
localeString = parserLocaleString;
|
||||
} else {
|
||||
// If the localeString was defined in @@locale and in the filename, verify to
|
||||
// see if the parsed locale matches, throw an error if it does not. This
|
||||
// prevents developers from confusing issues when both @@locale and
|
||||
// "_{locale}" is specified in the filename.
|
||||
if (localeString != parserLocaleString) {
|
||||
throw L10nException(
|
||||
'The locale specified in @@locale and the arb filename do not match. \n'
|
||||
'Please make sure that they match, since this prevents any confusion \n'
|
||||
'with which locale to use. Otherwise, specify the locale in either the \n'
|
||||
'filename of the @@locale key only.\n'
|
||||
'Current @@locale value: $localeString\n'
|
||||
'Current filename extension: $parserLocaleString'
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (localeString == null) {
|
||||
throw L10nException(
|
||||
"The following .arb file's locale could not be determined: \n"
|
||||
'${file.path} \n'
|
||||
"Make sure that the locale is specified in the file's '@@locale' "
|
||||
'property or as part of the filename (e.g. file_en.arb)'
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
final Iterable<String> ids = resources.keys.where((String key) => !key.startsWith('@'));
|
||||
return AppResourceBundle._(file, LocaleInfo.fromString(localeString), resources, ids);
|
||||
@ -469,3 +506,191 @@ class AppResourceBundleCollection {
|
||||
return 'AppResourceBundleCollection(${_directory.path}, ${locales.length} locales)';
|
||||
}
|
||||
}
|
||||
|
||||
// A set containing all the ISO630-1 languages. This list was pulled from https://datahub.io/core/language-codes.
|
||||
final Set<String> _iso639Languages = <String>{
|
||||
'aa',
|
||||
'ab',
|
||||
'ae',
|
||||
'af',
|
||||
'ak',
|
||||
'am',
|
||||
'an',
|
||||
'ar',
|
||||
'as',
|
||||
'av',
|
||||
'ay',
|
||||
'az',
|
||||
'ba',
|
||||
'be',
|
||||
'bg',
|
||||
'bh',
|
||||
'bi',
|
||||
'bm',
|
||||
'bn',
|
||||
'bo',
|
||||
'br',
|
||||
'bs',
|
||||
'ca',
|
||||
'ce',
|
||||
'ch',
|
||||
'co',
|
||||
'cr',
|
||||
'cs',
|
||||
'cu',
|
||||
'cv',
|
||||
'cy',
|
||||
'da',
|
||||
'de',
|
||||
'dv',
|
||||
'dz',
|
||||
'ee',
|
||||
'el',
|
||||
'en',
|
||||
'eo',
|
||||
'es',
|
||||
'et',
|
||||
'eu',
|
||||
'fa',
|
||||
'ff',
|
||||
'fi',
|
||||
'fj',
|
||||
'fo',
|
||||
'fr',
|
||||
'fy',
|
||||
'ga',
|
||||
'gd',
|
||||
'gl',
|
||||
'gn',
|
||||
'gu',
|
||||
'gv',
|
||||
'ha',
|
||||
'he',
|
||||
'hi',
|
||||
'ho',
|
||||
'hr',
|
||||
'ht',
|
||||
'hu',
|
||||
'hy',
|
||||
'hz',
|
||||
'ia',
|
||||
'id',
|
||||
'ie',
|
||||
'ig',
|
||||
'ii',
|
||||
'ik',
|
||||
'io',
|
||||
'is',
|
||||
'it',
|
||||
'iu',
|
||||
'ja',
|
||||
'jv',
|
||||
'ka',
|
||||
'kg',
|
||||
'ki',
|
||||
'kj',
|
||||
'kk',
|
||||
'kl',
|
||||
'km',
|
||||
'kn',
|
||||
'ko',
|
||||
'kr',
|
||||
'ks',
|
||||
'ku',
|
||||
'kv',
|
||||
'kw',
|
||||
'ky',
|
||||
'la',
|
||||
'lb',
|
||||
'lg',
|
||||
'li',
|
||||
'ln',
|
||||
'lo',
|
||||
'lt',
|
||||
'lu',
|
||||
'lv',
|
||||
'mg',
|
||||
'mh',
|
||||
'mi',
|
||||
'mk',
|
||||
'ml',
|
||||
'mn',
|
||||
'mr',
|
||||
'ms',
|
||||
'mt',
|
||||
'my',
|
||||
'na',
|
||||
'nb',
|
||||
'nd',
|
||||
'ne',
|
||||
'ng',
|
||||
'nl',
|
||||
'nn',
|
||||
'no',
|
||||
'nr',
|
||||
'nv',
|
||||
'ny',
|
||||
'oc',
|
||||
'oj',
|
||||
'om',
|
||||
'or',
|
||||
'os',
|
||||
'pa',
|
||||
'pi',
|
||||
'pl',
|
||||
'ps',
|
||||
'pt',
|
||||
'qu',
|
||||
'rm',
|
||||
'rn',
|
||||
'ro',
|
||||
'ru',
|
||||
'rw',
|
||||
'sa',
|
||||
'sc',
|
||||
'sd',
|
||||
'se',
|
||||
'sg',
|
||||
'si',
|
||||
'sk',
|
||||
'sl',
|
||||
'sm',
|
||||
'sn',
|
||||
'so',
|
||||
'sq',
|
||||
'sr',
|
||||
'ss',
|
||||
'st',
|
||||
'su',
|
||||
'sv',
|
||||
'sw',
|
||||
'ta',
|
||||
'te',
|
||||
'tg',
|
||||
'th',
|
||||
'ti',
|
||||
'tk',
|
||||
'tl',
|
||||
'tn',
|
||||
'to',
|
||||
'tr',
|
||||
'ts',
|
||||
'tt',
|
||||
'tw',
|
||||
'ty',
|
||||
'ug',
|
||||
'uk',
|
||||
'ur',
|
||||
'uz',
|
||||
've',
|
||||
'vi',
|
||||
'vo',
|
||||
'wa',
|
||||
'wo',
|
||||
'xh',
|
||||
'yi',
|
||||
'yo',
|
||||
'za',
|
||||
'zh',
|
||||
'zu',
|
||||
};
|
||||
|
@ -308,6 +308,61 @@ void main() {
|
||||
expect(generator.header, '/// Sample header in a text file');
|
||||
});
|
||||
|
||||
test('sets templateArbFileName with more than one underscore correctly', () {
|
||||
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
||||
..createSync(recursive: true);
|
||||
l10nDirectory.childFile('app_localizations_en.arb')
|
||||
.writeAsStringSync(singleMessageArbFileString);
|
||||
l10nDirectory.childFile('app_localizations_es.arb')
|
||||
.writeAsStringSync(singleEsMessageArbFileString);
|
||||
LocalizationsGenerator generator;
|
||||
try {
|
||||
generator = LocalizationsGenerator(fs);
|
||||
generator
|
||||
..initialize(
|
||||
inputPathString: defaultL10nPathString,
|
||||
templateArbFileName: 'app_localizations_en.arb',
|
||||
outputFileString: defaultOutputFileString,
|
||||
classNameString: defaultClassNameString,
|
||||
)
|
||||
..loadResources()
|
||||
..writeOutputFiles();
|
||||
} on L10nException catch (e) {
|
||||
fail('Generating output should not fail: \n${e.message}');
|
||||
}
|
||||
|
||||
final Directory outputDirectory = fs.directory('lib').childDirectory('l10n');
|
||||
expect(outputDirectory.childFile('output-localization-file.dart').existsSync(), isTrue);
|
||||
expect(outputDirectory.childFile('output-localization-file_en.dart').existsSync(), isTrue);
|
||||
expect(outputDirectory.childFile('output-localization-file_es.dart').existsSync(), isTrue);
|
||||
});
|
||||
|
||||
test('filenames with invalid locales should not be recognized', () {
|
||||
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
||||
..createSync(recursive: true);
|
||||
l10nDirectory.childFile('app_localizations_en.arb')
|
||||
.writeAsStringSync(singleMessageArbFileString);
|
||||
l10nDirectory.childFile('app_localizations_en_CA_foo.arb')
|
||||
.writeAsStringSync(singleMessageArbFileString);
|
||||
LocalizationsGenerator generator;
|
||||
try {
|
||||
generator = LocalizationsGenerator(fs);
|
||||
generator
|
||||
..initialize(
|
||||
inputPathString: defaultL10nPathString,
|
||||
templateArbFileName: 'app_localizations_en.arb',
|
||||
outputFileString: defaultOutputFileString,
|
||||
classNameString: defaultClassNameString,
|
||||
)
|
||||
..loadResources();
|
||||
} on L10nException catch (e) {
|
||||
expect(e.message, contains('The following .arb file\'s locale could not be determined'));
|
||||
return;
|
||||
}
|
||||
|
||||
fail('Using app_en_CA_foo.arb should fail as it is not a valid locale.');
|
||||
});
|
||||
|
||||
test('correctly creates an unimplemented messages file', () {
|
||||
fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
|
||||
..createSync(recursive: true)
|
||||
@ -799,7 +854,7 @@ void main() {
|
||||
expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true);
|
||||
});
|
||||
|
||||
test('correctly prioritizes @@locale property in arb file over filename', () {
|
||||
test('correctly requires @@locale property in arb file to match the filename locale suffix', () {
|
||||
const String arbFileWithEnLocale = '''
|
||||
{
|
||||
"@@locale": "en",
|
||||
@ -837,15 +892,14 @@ void main() {
|
||||
);
|
||||
generator.loadResources();
|
||||
} on L10nException catch (e) {
|
||||
fail('Setting language and locales should not fail: \n${e.message}');
|
||||
expect(e.message, contains('The locale specified in @@locale and the arb filename do not match.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// @@locale property should hold higher priority
|
||||
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
|
||||
expect(generator.supportedLocales.contains(LocaleInfo.fromString('zh')), true);
|
||||
// filename should not be used since @@locale is specified
|
||||
expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), false);
|
||||
expect(generator.supportedLocales.contains(LocaleInfo.fromString('am')), false);
|
||||
fail(
|
||||
'An exception should occur if the @@locale and the filename extensions are '
|
||||
'defined but not matching.'
|
||||
);
|
||||
});
|
||||
|
||||
test("throws when arb file's locale could not be determined", () {
|
||||
|
Loading…
Reference in New Issue
Block a user