[gen_l10n] Add scriptCode handling (#53868)
* [gen_l10n] Add scriptCode handling
This commit is contained in:
parent
2396616e09
commit
6837b0e353
@ -248,26 +248,120 @@ String generateBaseClassMethod(Message message) {
|
||||
.replaceAll('@(name)', message.resourceId);
|
||||
}
|
||||
|
||||
String generateLookupBody(AppResourceBundleCollection allBundles, String className) {
|
||||
String _generateLookupByAllCodes(AppResourceBundleCollection allBundles, String className) {
|
||||
final Iterable<LocaleInfo> localesWithAllCodes = allBundles.locales.where((LocaleInfo locale) {
|
||||
return locale.scriptCode != null && locale.countryCode != null;
|
||||
});
|
||||
|
||||
if (localesWithAllCodes.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
final Iterable<String> switchClauses = localesWithAllCodes.map<String>((LocaleInfo locale) {
|
||||
return switchClauseTemplate
|
||||
.replaceAll('@(case)', locale.toString())
|
||||
.replaceAll('@(class)', '$className${locale.camelCase()}');
|
||||
});
|
||||
|
||||
return allCodesLookupTemplate.replaceAll(
|
||||
'@(allCodesSwitchClauses)',
|
||||
switchClauses.join('\n '),
|
||||
);
|
||||
}
|
||||
|
||||
String _generateLookupByScriptCode(AppResourceBundleCollection allBundles, String className) {
|
||||
final Iterable<String> switchClauses = allBundles.languages.map((String language) {
|
||||
final Iterable<LocaleInfo> locales = allBundles.localesForLanguage(language);
|
||||
if (locales.length == 1) {
|
||||
return switchClauseTemplate
|
||||
.replaceAll('@(case)', language)
|
||||
.replaceAll('@(class)', '$className${locales.first.camelCase()}');
|
||||
}
|
||||
final Iterable<LocaleInfo> localesWithScriptCodes = locales.where((LocaleInfo locale) {
|
||||
return locale.scriptCode != null && locale.countryCode == null;
|
||||
});
|
||||
|
||||
final Iterable<LocaleInfo> localesWithCountryCodes = locales.where((LocaleInfo locale) => locale.countryCode != null);
|
||||
return countryCodeSwitchTemplate
|
||||
if (localesWithScriptCodes.isEmpty)
|
||||
return null;
|
||||
|
||||
return nestedSwitchTemplate
|
||||
.replaceAll('@(languageCode)', language)
|
||||
.replaceAll('@(code)', 'scriptCode')
|
||||
.replaceAll('@(class)', '$className${LocaleInfo.fromString(language).camelCase()}')
|
||||
.replaceAll('@(switchClauses)', localesWithScriptCodes.map((LocaleInfo locale) {
|
||||
return switchClauseTemplate
|
||||
.replaceAll('@(case)', locale.scriptCode)
|
||||
.replaceAll('@(class)', '$className${locale.camelCase()}');
|
||||
}).join('\n '));
|
||||
}).where((String switchClause) => switchClause != null);
|
||||
|
||||
if (switchClauses.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return languageCodeSwitchTemplate
|
||||
.replaceAll('@(comment)', '// Lookup logic when language+script codes are specified.')
|
||||
.replaceAll('@(switchClauses)', switchClauses.join('\n '),
|
||||
);
|
||||
}
|
||||
|
||||
String _generateLookupByCountryCode(AppResourceBundleCollection allBundles, String className) {
|
||||
final Iterable<String> switchClauses = allBundles.languages.map((String language) {
|
||||
final Iterable<LocaleInfo> locales = allBundles.localesForLanguage(language);
|
||||
final Iterable<LocaleInfo> localesWithCountryCodes = locales.where((LocaleInfo locale) {
|
||||
return locale.countryCode != null && locale.scriptCode == null;
|
||||
});
|
||||
|
||||
if (localesWithCountryCodes.isEmpty)
|
||||
return null;
|
||||
|
||||
return nestedSwitchTemplate
|
||||
.replaceAll('@(languageCode)', language)
|
||||
.replaceAll('@(code)', 'countryCode')
|
||||
.replaceAll('@(class)', '$className${LocaleInfo.fromString(language).camelCase()}')
|
||||
.replaceAll('@(switchClauses)', localesWithCountryCodes.map((LocaleInfo locale) {
|
||||
return switchClauseTemplate
|
||||
.replaceAll('@(case)', locale.countryCode)
|
||||
.replaceAll('@(class)', '$className${locale.camelCase()}');
|
||||
}).join('\n '));
|
||||
});
|
||||
return switchClauses.join('\n ');
|
||||
}).where((String switchClause) => switchClause != null);
|
||||
|
||||
if (switchClauses.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return languageCodeSwitchTemplate
|
||||
.replaceAll('@(comment)', '// Lookup logic when language+country codes are specified.')
|
||||
.replaceAll('@(switchClauses)', switchClauses.join('\n '));
|
||||
}
|
||||
|
||||
String _generateLookupByLanguageCode(AppResourceBundleCollection allBundles, String className) {
|
||||
final Iterable<String> switchClauses = allBundles.languages.map((String language) {
|
||||
final Iterable<LocaleInfo> locales = allBundles.localesForLanguage(language);
|
||||
final Iterable<LocaleInfo> localesWithLanguageCode = locales.where((LocaleInfo locale) {
|
||||
return locale.countryCode == null && locale.scriptCode == null;
|
||||
});
|
||||
|
||||
if (localesWithLanguageCode.isEmpty)
|
||||
return null;
|
||||
|
||||
return localesWithLanguageCode.map((LocaleInfo locale) {
|
||||
return switchClauseTemplate
|
||||
.replaceAll('@(case)', locale.languageCode)
|
||||
.replaceAll('@(class)', '$className${locale.camelCase()}');
|
||||
}).join('\n ');
|
||||
}).where((String switchClause) => switchClause != null);
|
||||
|
||||
if (switchClauses.isEmpty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return languageCodeSwitchTemplate
|
||||
.replaceAll('@(comment)', '// Lookup logic when only language code is specified.')
|
||||
.replaceAll('@(switchClauses)', switchClauses.join('\n '));
|
||||
}
|
||||
|
||||
String _generateLookupBody(AppResourceBundleCollection allBundles, String className) {
|
||||
return lookupBodyTemplate
|
||||
.replaceAll('@(lookupAllCodesSpecified)', _generateLookupByAllCodes(allBundles, className))
|
||||
.replaceAll('@(lookupScriptCodeSpecified)', _generateLookupByScriptCode(allBundles, className))
|
||||
.replaceAll('@(lookupCountryCodeSpecified)', _generateLookupByCountryCode(allBundles, className))
|
||||
.replaceAll('@(lookupLanguageCodeSpecified)', _generateLookupByLanguageCode(allBundles, className));
|
||||
}
|
||||
|
||||
class LocalizationsGenerator {
|
||||
@ -466,7 +560,9 @@ class LocalizationsGenerator {
|
||||
if (localeString.runtimeType != String) {
|
||||
throw L10nException('Incorrect runtime type for $localeString');
|
||||
}
|
||||
return LocaleInfo.fromString(localeString.toString());
|
||||
return LocaleInfo.fromString(
|
||||
localeString.toString(),
|
||||
);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
@ -566,9 +662,19 @@ class LocalizationsGenerator {
|
||||
final String outputFileName = path.basename(outputFile.path);
|
||||
|
||||
final Iterable<String> supportedLocalesCode = supportedLocales.map((LocaleInfo locale) {
|
||||
final String country = locale.countryCode;
|
||||
final String countryArg = country == null ? '' : "', '$country";
|
||||
return 'Locale(\'${locale.languageCode}$countryArg\')';
|
||||
final String languageCode = locale.languageCode;
|
||||
final String countryCode = locale.countryCode;
|
||||
final String scriptCode = locale.scriptCode;
|
||||
|
||||
if (countryCode == null && scriptCode == null) {
|
||||
return 'Locale(\'$languageCode\')';
|
||||
} else if (countryCode != null && scriptCode == null) {
|
||||
return 'Locale(\'$languageCode\', \'$countryCode\')';
|
||||
} else if (countryCode != null && scriptCode != null) {
|
||||
return 'Locale.fromSubtags(languageCode: \'$languageCode\', countryCode: \'$countryCode\', scriptCode: \'$scriptCode\')';
|
||||
} else {
|
||||
return 'Locale.fromSubtags(languageCode: \'$languageCode\', scriptCode: \'$scriptCode\')';
|
||||
}
|
||||
});
|
||||
|
||||
final Set<String> supportedLanguageCodes = Set<String>.from(
|
||||
@ -618,7 +724,7 @@ class LocalizationsGenerator {
|
||||
return "import '${fileName}_${locale.toString()}.dart';";
|
||||
});
|
||||
|
||||
final String lookupBody = generateLookupBody(_allBundles, className);
|
||||
final String lookupBody = _generateLookupBody(_allBundles, className);
|
||||
|
||||
return fileTemplate
|
||||
.replaceAll('@(header)', header)
|
||||
|
@ -120,9 +120,7 @@ class _@(class)Delegate extends LocalizationsDelegate<@(class)> {
|
||||
}
|
||||
|
||||
@(class) @(lookupName)(Locale locale) {
|
||||
switch(locale.languageCode) {
|
||||
@(lookupBody)
|
||||
}
|
||||
@(lookupBody)
|
||||
assert(false, '@(class).delegate failed to load unsupported locale "\$locale"');
|
||||
return null;
|
||||
}
|
||||
@ -207,11 +205,30 @@ const String baseClassMethodTemplate = '''
|
||||
String @(name)(@(parameters));
|
||||
''';
|
||||
|
||||
// DELEGATE LOOKUP TEMPLATES
|
||||
|
||||
const String lookupBodyTemplate = '''@(lookupAllCodesSpecified)
|
||||
@(lookupScriptCodeSpecified)
|
||||
@(lookupCountryCodeSpecified)
|
||||
@(lookupLanguageCodeSpecified)''';
|
||||
|
||||
const String switchClauseTemplate = '''case '@(case)': return @(class)();''';
|
||||
|
||||
const String countryCodeSwitchTemplate = '''case '@(languageCode)': {
|
||||
switch (locale.countryCode) {
|
||||
const String nestedSwitchTemplate = '''case '@(languageCode)': {
|
||||
switch (locale.@(code)) {
|
||||
@(switchClauses)
|
||||
}
|
||||
return @(class)();
|
||||
break;
|
||||
}''';
|
||||
|
||||
const String languageCodeSwitchTemplate = '''@(comment)
|
||||
switch (locale.languageCode) {
|
||||
@(switchClauses)
|
||||
}
|
||||
''';
|
||||
|
||||
const String allCodesLookupTemplate = '''// Lookup logic when language+script+country codes are specified.
|
||||
switch (locale.toString()) {
|
||||
@(allCodesSwitchClauses)
|
||||
}
|
||||
''';
|
||||
|
@ -80,37 +80,49 @@ void main() {
|
||||
'#l10n 1 (supportedLocales[0]: languageCode: en, countryCode: null, scriptCode: null)\n'
|
||||
'#l10n 2 (supportedLocales[1]: languageCode: en, countryCode: CA, scriptCode: null)\n'
|
||||
'#l10n 3 (supportedLocales[2]: languageCode: en, countryCode: GB, scriptCode: null)\n'
|
||||
'#l10n 4 (--- countryCode (en_CA) tests ---)\n'
|
||||
'#l10n 5 (CA Hello World)\n'
|
||||
'#l10n 6 (Hello CA fallback World)\n'
|
||||
'#l10n 7 (--- countryCode (en_GB) tests ---)\n'
|
||||
'#l10n 8 (GB Hello World)\n'
|
||||
'#l10n 9 (Hello GB fallback World)\n'
|
||||
'#l10n 10 (--- General formatting tests ---)\n'
|
||||
'#l10n 11 (Hello World)\n'
|
||||
'#l10n 12 (Hello _NEWLINE_ World)\n'
|
||||
'#l10n 13 (Hello World)\n'
|
||||
'#l10n 14 (Hello World)\n'
|
||||
'#l10n 15 (Hello World on Friday, January 1, 1960)\n'
|
||||
'#l10n 16 (Hello world argument on 1/1/1960 at 00:00)\n'
|
||||
'#l10n 17 (Hello World from 1960 to 2020)\n'
|
||||
'#l10n 18 (Hello for 123)\n'
|
||||
'#l10n 19 (Hello for price USD123.00)\n'
|
||||
'#l10n 20 (Hello)\n'
|
||||
'#l10n 21 (Hello World)\n'
|
||||
'#l10n 22 (Hello two worlds)\n'
|
||||
'#l10n 23 (Hello)\n'
|
||||
'#l10n 24 (Hello new World)\n'
|
||||
'#l10n 25 (Hello two new worlds)\n'
|
||||
'#l10n 26 (Hello on Friday, January 1, 1960)\n'
|
||||
'#l10n 27 (Hello World, on Friday, January 1, 1960)\n'
|
||||
'#l10n 28 (Hello two worlds, on Friday, January 1, 1960)\n'
|
||||
'#l10n 29 (Hello other 0 worlds, with a total of 100 citizens)\n'
|
||||
'#l10n 30 (Hello World of 101 citizens)\n'
|
||||
'#l10n 31 (Hello two worlds with 102 total citizens)\n'
|
||||
'#l10n 32 ([Hello] -World- #123#)\n'
|
||||
'#l10n 33 (Flutter\'s amazing!)\n'
|
||||
'#l10n 34 (Flutter is "amazing"!)\n'
|
||||
'#l10n 4 (supportedLocales[3]: languageCode: zh, countryCode: null, scriptCode: null)\n'
|
||||
'#l10n 5 (supportedLocales[4]: languageCode: zh, countryCode: null, scriptCode: Hans)\n'
|
||||
'#l10n 6 (supportedLocales[5]: languageCode: zh, countryCode: null, scriptCode: Hant)\n'
|
||||
'#l10n 7 (supportedLocales[6]: languageCode: zh, countryCode: TW, scriptCode: Hant)\n'
|
||||
'#l10n 8 (--- countryCode (en_CA) tests ---)\n'
|
||||
'#l10n 9 (CA Hello World)\n'
|
||||
'#l10n 10 (Hello CA fallback World)\n'
|
||||
'#l10n 11 (--- countryCode (en_GB) tests ---)\n'
|
||||
'#l10n 12 (GB Hello World)\n'
|
||||
'#l10n 13 (Hello GB fallback World)\n'
|
||||
'#l10n 14 (--- zh ---)\n'
|
||||
'#l10n 15 (你好世界)\n'
|
||||
'#l10n 16 (--- scriptCode: zh_Hans ---)\n'
|
||||
'#l10n 17 (简体你好世界)\n'
|
||||
'#l10n 18 (--- scriptCode - zh_Hant ---)\n'
|
||||
'#l10n 19 (繁體你好世界)\n'
|
||||
'#l10n 20 (--- scriptCode - zh_Hant_TW ---)\n'
|
||||
'#l10n 21 (台灣繁體你好世界)\n'
|
||||
'#l10n 22 (--- General formatting tests ---)\n'
|
||||
'#l10n 23 (Hello World)\n'
|
||||
'#l10n 24 (Hello _NEWLINE_ World)\n'
|
||||
'#l10n 25 (Hello World)\n'
|
||||
'#l10n 26 (Hello World)\n'
|
||||
'#l10n 27 (Hello World on Friday, January 1, 1960)\n'
|
||||
'#l10n 28 (Hello world argument on 1/1/1960 at 00:00)\n'
|
||||
'#l10n 29 (Hello World from 1960 to 2020)\n'
|
||||
'#l10n 30 (Hello for 123)\n'
|
||||
'#l10n 31 (Hello for price USD123.00)\n'
|
||||
'#l10n 32 (Hello)\n'
|
||||
'#l10n 33 (Hello World)\n'
|
||||
'#l10n 34 (Hello two worlds)\n'
|
||||
'#l10n 35 (Hello)\n'
|
||||
'#l10n 36 (Hello new World)\n'
|
||||
'#l10n 37 (Hello two new worlds)\n'
|
||||
'#l10n 38 (Hello on Friday, January 1, 1960)\n'
|
||||
'#l10n 39 (Hello World, on Friday, January 1, 1960)\n'
|
||||
'#l10n 40 (Hello two worlds, on Friday, January 1, 1960)\n'
|
||||
'#l10n 41 (Hello other 0 worlds, with a total of 100 citizens)\n'
|
||||
'#l10n 42 (Hello World of 101 citizens)\n'
|
||||
'#l10n 43 (Hello two worlds with 102 total citizens)\n'
|
||||
'#l10n 44 ([Hello] -World- #123#)\n'
|
||||
'#l10n 45 (Flutter\'s amazing!)\n'
|
||||
'#l10n 46 (Flutter is "amazing"!)\n'
|
||||
'#l10n END\n'
|
||||
);
|
||||
});
|
||||
|
@ -18,6 +18,10 @@ class GenL10nProject extends Project {
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_en.arb'), appEn);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_en_CA.arb'), appEnCa);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_en_GB.arb'), appEnGb);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_zh.arb'), appZh);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_zh_Hant.arb'), appZhHant);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_zh_Hans.arb'), appZhHans);
|
||||
writeFile(globals.fs.path.join(dir.path, 'lib', 'l10n', 'app_zh_Hant_TW.arb'), appZhHantTw);
|
||||
return super.setUpIn(dir);
|
||||
}
|
||||
|
||||
@ -116,6 +120,38 @@ class Home extends StatelessWidget {
|
||||
results.add(AppLocalizations.of(context).hello("GB fallback World"));
|
||||
},
|
||||
),
|
||||
LocaleBuilder(
|
||||
locale: Locale('zh'),
|
||||
test: 'zh',
|
||||
callback: (BuildContext context) {
|
||||
results.add('--- zh ---');
|
||||
results.add(AppLocalizations.of(context).helloWorld);
|
||||
},
|
||||
),
|
||||
LocaleBuilder(
|
||||
locale: Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans'),
|
||||
test: 'zh',
|
||||
callback: (BuildContext context) {
|
||||
results.add('--- scriptCode: zh_Hans ---');
|
||||
results.add(AppLocalizations.of(context).helloWorld);
|
||||
},
|
||||
),
|
||||
LocaleBuilder(
|
||||
locale: Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),
|
||||
test: 'scriptCode - zh_Hant',
|
||||
callback: (BuildContext context) {
|
||||
results.add('--- scriptCode - zh_Hant ---');
|
||||
results.add(AppLocalizations.of(context).helloWorld);
|
||||
},
|
||||
),
|
||||
LocaleBuilder(
|
||||
locale: Locale.fromSubtags(languageCode: 'zh', countryCode: 'TW', scriptCode: 'Hant'),
|
||||
test: 'scriptCode - zh_TW_Hant',
|
||||
callback: (BuildContext context) {
|
||||
results.add('--- scriptCode - zh_Hant_TW ---');
|
||||
results.add(AppLocalizations.of(context).helloWorld);
|
||||
},
|
||||
),
|
||||
LocaleBuilder(
|
||||
locale: Locale('en'),
|
||||
test: 'General formatting',
|
||||
@ -364,5 +400,52 @@ void main() {
|
||||
"@@locale": "en_GB",
|
||||
"helloWorld": "GB Hello World"
|
||||
}
|
||||
''';
|
||||
|
||||
// Only tests `helloWorld`. The rest of the messages are added out of
|
||||
// necessity since every base class requires an override for every
|
||||
// message.
|
||||
final String appZh = r'''
|
||||
{
|
||||
"@@locale": "zh",
|
||||
"helloWorld": "你好世界",
|
||||
"helloNewlineWorld": "Hello \n World",
|
||||
"hello": "Hello {world}",
|
||||
"greeting": "{hello} {world}",
|
||||
"helloWorldOn": "Hello World on {date}",
|
||||
"helloWorldDuring": "Hello World from {startDate} to {endDate}",
|
||||
"helloOn": "Hello {world} on {date} at {time}",
|
||||
"helloFor": "Hello for {value}",
|
||||
"helloCost": "Hello for {price} {value}",
|
||||
"helloWorlds": "{count,plural, =0{Hello} =1{Hello World} =2{Hello two worlds} few{Hello {count} worlds} many{Hello all {count} worlds} other{Hello other {count} worlds}}",
|
||||
"helloAdjectiveWorlds": "{count,plural, =0{Hello} =1{Hello {adjective} World} =2{Hello two {adjective} worlds} other{Hello other {count} {adjective} worlds}}",
|
||||
"helloWorldsOn": "{count,plural, =0{Hello on {date}} =1{Hello World, on {date}} =2{Hello two worlds, on {date}} other{Hello other {count} worlds, on {date}}}",
|
||||
"helloWorldPopulation": "{count,plural, =1{Hello World of {population} citizens} =2{Hello two worlds with {population} total citizens} many{Hello all {count} worlds, with a total of {population} citizens} other{Hello other {count} worlds, with a total of {population} citizens}}",
|
||||
"helloWorldInterpolation": "[{hello}] #{world}#",
|
||||
"helloWorldsInterpolation": "{count,plural, other {[{hello}] -{world}- #{count}#}}",
|
||||
"singleQuote": "Flutter's amazing!",
|
||||
"doubleQuote": "Flutter is \"amazing\"!"
|
||||
}
|
||||
''';
|
||||
|
||||
final String appZhHans = r'''
|
||||
{
|
||||
"@@locale": "zh_Hans",
|
||||
"helloWorld": "简体你好世界"
|
||||
}
|
||||
''';
|
||||
|
||||
final String appZhHant = r'''
|
||||
{
|
||||
"@@locale": "zh_Hant",
|
||||
"helloWorld": "繁體你好世界"
|
||||
}
|
||||
''';
|
||||
|
||||
final String appZhHantTw = r'''
|
||||
{
|
||||
"@@locale": "zh_Hant_TW",
|
||||
"helloWorld": "台灣繁體你好世界"
|
||||
}
|
||||
''';
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user