Unverified Commit c98500de authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

Update gen_l10n tool to require base locale; Stocks app refresh (#51602)

parent 6a337a76
...@@ -23,16 +23,10 @@ The `flutter run --release` command both builds and installs the Flutter app. ...@@ -23,16 +23,10 @@ The `flutter run --release` command both builds and installs the Flutter app.
## Internationalization ## Internationalization
This app has been internationalized (just enough to show how it's This app has been internationalized (just enough to show how it's
done). It's an example of how one can do so with the done). It's an example of how one can do so with the gen_l10n tool.
[Dart intl package](https://pub.dev/packages/intl).
The [Flutter Internationalization Tutorial](https://flutter.dev/tutorials/internationalization/) See [regenerate.md](lib/i18n/regenerate.md) for an explanation for how
covers Flutter app internationalization in general. the tool is used to generate localizations for this app.
See [regenerate.md](lib/i18n/regenerate.md) for an explanation
of how the Dart internationalization tools, like
`intl_translation:generate_from_arb`, were used to generate
localizations for this app.
## Icon ## Icon
......
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that looks up messages for specific locales by
// delegating to the appropriate library.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:implementation_imports, file_names, unnecessary_new
// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
// ignore_for_file:argument_type_not_assignable, invalid_assignment
// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
// ignore_for_file:comment_references
import 'dart:async';
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
import 'messages_en_US.dart' as messages_en_us;
import 'messages_es_ES.dart' as messages_es_es;
typedef Future<dynamic> LibraryLoader();
Map<String, LibraryLoader> _deferredLibraries = {
'en_US': () => new Future.value(null),
'es_ES': () => new Future.value(null),
};
MessageLookupByLibrary _findExact(String localeName) {
switch (localeName) {
case 'en_US':
return messages_en_us.messages;
case 'es_ES':
return messages_es_es.messages;
default:
return null;
}
}
/// User programs should call this before using [localeName] for messages.
Future<bool> initializeMessages(String localeName) async {
var availableLocale = Intl.verifiedLocale(
localeName,
(locale) => _deferredLibraries[locale] != null,
onFailure: (_) => null);
if (availableLocale == null) {
return new Future.value(false);
}
var lib = _deferredLibraries[availableLocale];
await (lib == null ? new Future.value(false) : lib());
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
return new Future.value(true);
}
bool _messagesExistFor(String locale) {
try {
return _findExact(locale) != null;
} catch (e) {
return false;
}
}
MessageLookupByLibrary _findGeneratedMessagesFor(String locale) {
var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
onFailure: (_) => null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
}
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a en_US locale. All the
// messages from the main program should be duplicated here with the same
// function name.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'en_US';
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"market" : MessageLookupByLibrary.simpleMessage("MARKET"),
"portfolio" : MessageLookupByLibrary.simpleMessage("PORTFOLIO"),
"title" : MessageLookupByLibrary.simpleMessage("Stocks")
};
}
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
// This is a library that provides messages for a es_ES locale. All the
// messages from the main program should be duplicated here with the same
// function name.
// Ignore issues from commonly used lints in this file.
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
// ignore_for_file:unused_import, file_names
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'es_ES';
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"market" : MessageLookupByLibrary.simpleMessage("MERCADO"),
"portfolio" : MessageLookupByLibrary.simpleMessage("CARTERA"),
"title" : MessageLookupByLibrary.simpleMessage("Acciones")
};
}
...@@ -6,8 +6,9 @@ stocks app uses the [Dart `intl` package](https://github.com/dart-lang/intl). ...@@ -6,8 +6,9 @@ stocks app uses the [Dart `intl` package](https://github.com/dart-lang/intl).
Rebuilding everything requires two steps. Rebuilding everything requires two steps.
1. Create or update the English and Spanish localizations, `stocks_en_US.arb` 1. Create or update the English and Spanish localizations,
and `stocks_es_ES.arb`. See the [ARB specification](https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification) `stocks_en_US.arb`, `stocks_en.arb`, and `stocks_es.arb`. See the
[ARB specification](https://github.com/google/app-resource-bundle/wiki/ApplicationResourceBundleSpecification)
for more info. for more info.
2. With `examples/stocks` as the current directory, generate a 2. With `examples/stocks` as the current directory, generate a
...@@ -20,7 +21,9 @@ dart ${FLUTTER_PATH}/dev/tools/localization/bin/gen_l10n.dart --arb-dir=lib/i18n ...@@ -20,7 +21,9 @@ dart ${FLUTTER_PATH}/dev/tools/localization/bin/gen_l10n.dart --arb-dir=lib/i18n
--output-class=StockStrings --output-class=StockStrings
``` ```
The `StockStrings` class uses the generated `initializeMessages()`function The `StockStrings` class creates a delegate that performs message lookups
(`messages_all.dart`) to load the localized messages and `Intl.message()` based on the locale of the device. In this case, the stocks app supports
to look them up. The generated class's API documentation explains how to add `en`, `en_US`, and `es`. Thus, the `StockStringsEn` and `StockStringsEs`
the new localizations delegate and supported locales to the Flutter application. classes extends `StockStrings`. `StockStringsEnUs` extends
`StockStringsEn`. This allows `StockStringsEnUs` to fall back on messages
in `StockStringsEn`.
\ No newline at end of file
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async'; import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart'; // ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'messages_all.dart'; // ignore_for_file: unnecessary_brace_in_string_interps
/// Callers can lookup localized strings with an instance of StockStrings returned /// Callers can lookup localized strings with an instance of StockStrings returned
/// by `StockStrings.of(context)`. /// by `StockStrings.of(context)`.
...@@ -58,16 +64,12 @@ import 'messages_all.dart'; ...@@ -58,16 +64,12 @@ import 'messages_all.dart';
/// you wish to add from the pop-up menu in the Value field. This list should /// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the StockStrings.supportedLocales /// be consistent with the languages listed in the StockStrings.supportedLocales
/// property. /// property.
class StockStrings { abstract class StockStrings {
StockStrings(Locale locale) : _localeName = Intl.canonicalizedLocale(locale.toString()); StockStrings(String locale) : assert(locale != null), _localeName = intl.Intl.canonicalizedLocale(locale.toString());
// ignore: unused_field
final String _localeName; final String _localeName;
static Future<StockStrings> load(Locale locale) {
return initializeMessages(locale.toString())
.then<StockStrings>((_) => StockStrings(locale));
}
static StockStrings of(BuildContext context) { static StockStrings of(BuildContext context) {
return Localizations.of<StockStrings>(context, StockStrings); return Localizations.of<StockStrings>(context, StockStrings);
} }
...@@ -80,6 +82,10 @@ class StockStrings { ...@@ -80,6 +82,10 @@ class StockStrings {
/// Returns a list of localizations delegates containing this delegate along with /// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate. /// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[ static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
delegate, delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
...@@ -89,44 +95,28 @@ class StockStrings { ...@@ -89,44 +95,28 @@ class StockStrings {
/// A list of this localizations delegate's supported locales. /// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[ static const List<Locale> supportedLocales = <Locale>[
Locale('en', 'US'), Locale('en'),
Locale('es', 'ES'), Locale('en, US'),
Locale('es')
]; ];
String get market { // Title for the Stocks application
return Intl.message( String get title;
r'MARKET',
locale: _localeName,
name: 'market',
desc: r'Label for the Market tab'
);
}
String get portfolio { // Label for the Market tab
return Intl.message( String get market;
r'PORTFOLIO',
locale: _localeName,
name: 'portfolio',
desc: r'Label for the Portfolio tab'
);
}
String get title {
return Intl.message(
r'Stocks',
locale: _localeName,
name: 'title',
desc: r'Title for the Stocks application'
);
}
// Label for the Portfolio tab
String get portfolio;
} }
class _StockStringsDelegate extends LocalizationsDelegate<StockStrings> { class _StockStringsDelegate extends LocalizationsDelegate<StockStrings> {
const _StockStringsDelegate(); const _StockStringsDelegate();
@override @override
Future<StockStrings> load(Locale locale) => StockStrings.load(locale); Future<StockStrings> load(Locale locale) {
return SynchronousFuture<StockStrings>(_lookupStockStrings(locale));
}
@override @override
bool isSupported(Locale locale) => <String>['en', 'es'].contains(locale.languageCode); bool isSupported(Locale locale) => <String>['en', 'es'].contains(locale.languageCode);
...@@ -134,3 +124,59 @@ class _StockStringsDelegate extends LocalizationsDelegate<StockStrings> { ...@@ -134,3 +124,59 @@ class _StockStringsDelegate extends LocalizationsDelegate<StockStrings> {
@override @override
bool shouldReload(_StockStringsDelegate old) => false; bool shouldReload(_StockStringsDelegate old) => false;
} }
/// The translations for English (`en`).
class StockStringsEn extends StockStrings {
StockStringsEn([String locale = 'en']) : super(locale);
@override
String get title => 'Stocks';
@override
String get market => 'MARKET';
@override
String get portfolio => 'PORTFOLIO';
}
/// The translations for English, as used in the United States (`en_US`).
class StockStringsEnUs extends StockStringsEn {
StockStringsEnUs([String locale = 'en_US']) : super(locale);
@override
String get title => 'Stocks';
@override
String get market => 'MARKET';
@override
String get portfolio => 'PORTFOLIO';
}
/// The translations for Spanish Castilian (`es`).
class StockStringsEs extends StockStrings {
StockStringsEs([String locale = 'es']) : super(locale);
@override
String get title => 'Acciones';
@override
String get market => 'MERCADO';
@override
String get portfolio => 'CARTERA';
}
StockStrings _lookupStockStrings(Locale locale) {
switch(locale.languageCode) {
case 'en': {
switch (locale.countryCode) {
case 'US': return StockStringsEnUs();
}
return StockStringsEn();
}
case 'es': return StockStringsEs();
}
assert(false, 'StockStrings.delegate failed to load unsupported locale "$locale"');
return null;
}
{
"title": "Stocks",
"market": "MARKET",
"portfolio": "PORTFOLIO"
}
...@@ -11,18 +11,10 @@ void main() { ...@@ -11,18 +11,10 @@ void main() {
testWidgets('Changing locale', (WidgetTester tester) async { testWidgets('Changing locale', (WidgetTester tester) async {
stocks.main(); stocks.main();
await tester.idle(); // see https://github.com/flutter/flutter/issues/1865
await tester.pump(); await tester.pump();
// The initial test app's locale is "_", so we're seeing the fallback translation here. // The initial test app's locale is "_", so we're seeing the fallback translation here.
expect(find.text('MARKET'), findsOneWidget); expect(find.text('MARKET'), findsOneWidget);
await tester.binding.setLocale('es', 'US'); await tester.binding.setLocale('es', '');
await tester.idle();
// The Localizations widget has been built with the new locale. The
// new locale's strings are loaded asynchronously, so we're still
// displaying the previous locale's strings.
await tester.pump();
expect(find.text('MARKET'), findsOneWidget);
// The localized strings have finished loading and dependent // The localized strings have finished loading and dependent
// widgets have been updated. // widgets have been updated.
......
...@@ -8,6 +8,7 @@ import 'dart:async'; ...@@ -8,6 +8,7 @@ import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart';
// ignore: unused_import
import 'package:intl/intl.dart' as intl; import 'package:intl/intl.dart' as intl;
// ignore_for_file: unnecessary_brace_in_string_interps // ignore_for_file: unnecessary_brace_in_string_interps
...@@ -67,6 +68,7 @@ import 'package:intl/intl.dart' as intl; ...@@ -67,6 +68,7 @@ import 'package:intl/intl.dart' as intl;
abstract class @(class) { abstract class @(class) {
@(class)(String locale) : assert(locale != null), _localeName = intl.Intl.canonicalizedLocale(locale.toString()); @(class)(String locale) : assert(locale != null), _localeName = intl.Intl.canonicalizedLocale(locale.toString());
// ignore: unused_field
final String _localeName; final String _localeName;
static @(class) of(BuildContext context) { static @(class) of(BuildContext context) {
......
...@@ -423,6 +423,23 @@ class AppResourceBundleCollection { ...@@ -423,6 +423,23 @@ class AppResourceBundleCollection {
languageToLocales[bundle.locale.languageCode].add(bundle.locale); languageToLocales[bundle.locale.languageCode].add(bundle.locale);
} }
} }
languageToLocales.forEach((String language, List<LocaleInfo> listOfCorrespondingLocales) {
final List<String> localeStrings = listOfCorrespondingLocales.map((LocaleInfo locale) {
return locale.toString();
}).toList();
if (!localeStrings.contains(language)) {
throw L10nException(
'Arb file for a fallback, $language, does not exist, even though \n'
'the following locale(s) exist: $listOfCorrespondingLocales. \n'
'When locales specify a script code or country code, a \n'
'base locale (without the script code or country code) should \n'
'exist as the fallback. Please create a {fileName}_$language.arb \n'
'file.'
);
}
});
return AppResourceBundleCollection._(directory, localeToBundle, languageToLocales); return AppResourceBundleCollection._(directory, localeToBundle, languageToLocales);
} }
......
...@@ -15,7 +15,7 @@ import '../../localization/localizations_utils.dart'; ...@@ -15,7 +15,7 @@ import '../../localization/localizations_utils.dart';
import '../common.dart'; import '../common.dart';
final String defaultArbPathString = path.join('lib', 'l10n'); final String defaultArbPathString = path.join('lib', 'l10n');
const String defaultTemplateArbFileName = 'app_en_US.arb'; const String defaultTemplateArbFileName = 'app_en.arb';
const String defaultOutputFileString = 'output-localization-file'; const String defaultOutputFileString = 'output-localization-file';
const String defaultClassNameString = 'AppLocalizations'; const String defaultClassNameString = 'AppLocalizations';
const String singleMessageArbFileString = ''' const String singleMessageArbFileString = '''
...@@ -251,7 +251,7 @@ void main() { ...@@ -251,7 +251,7 @@ void main() {
fail('Setting language and locales should not fail: \n$e'); fail('Setting language and locales should not fail: \n$e');
} }
expect(generator.supportedLocales.contains(LocaleInfo.fromString('en_US')), true); expect(generator.supportedLocales.contains(LocaleInfo.fromString('en')), true);
expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), true); expect(generator.supportedLocales.contains(LocaleInfo.fromString('es')), true);
}); });
...@@ -263,7 +263,7 @@ void main() { ...@@ -263,7 +263,7 @@ void main() {
.writeAsStringSync(singleZhMessageArbFileString); .writeAsStringSync(singleZhMessageArbFileString);
l10nDirectory.childFile('app_es.arb') l10nDirectory.childFile('app_es.arb')
.writeAsStringSync(singleEsMessageArbFileString); .writeAsStringSync(singleEsMessageArbFileString);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en.arb')
.writeAsStringSync(singleMessageArbFileString); .writeAsStringSync(singleMessageArbFileString);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -280,7 +280,7 @@ void main() { ...@@ -280,7 +280,7 @@ void main() {
fail('Setting language and locales should not fail: \n$e'); fail('Setting language and locales should not fail: \n$e');
} }
expect(generator.supportedLocales.first, LocaleInfo.fromString('en_US')); expect(generator.supportedLocales.first, LocaleInfo.fromString('en'));
expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es')); expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es'));
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('zh')); expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('zh'));
}); });
...@@ -288,7 +288,7 @@ void main() { ...@@ -288,7 +288,7 @@ void main() {
test('adds preferred locales to the top of supportedLocales and supportedLanguageCodes', () { test('adds preferred locales to the top of supportedLocales and supportedLanguageCodes', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en.arb')
.writeAsStringSync(singleMessageArbFileString); .writeAsStringSync(singleMessageArbFileString);
l10nDirectory.childFile('app_es.arb') l10nDirectory.childFile('app_es.arb')
.writeAsStringSync(singleEsMessageArbFileString); .writeAsStringSync(singleEsMessageArbFileString);
...@@ -313,7 +313,7 @@ void main() { ...@@ -313,7 +313,7 @@ void main() {
expect(generator.supportedLocales.first, LocaleInfo.fromString('zh')); expect(generator.supportedLocales.first, LocaleInfo.fromString('zh'));
expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es')); expect(generator.supportedLocales.elementAt(1), LocaleInfo.fromString('es'));
expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('en_US')); expect(generator.supportedLocales.elementAt(2), LocaleInfo.fromString('en'));
}); });
test( test(
...@@ -322,14 +322,14 @@ void main() { ...@@ -322,14 +322,14 @@ void main() {
() { () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en.arb')
.writeAsStringSync(singleMessageArbFileString); .writeAsStringSync(singleMessageArbFileString);
l10nDirectory.childFile('app_es.arb') l10nDirectory.childFile('app_es.arb')
.writeAsStringSync(singleEsMessageArbFileString); .writeAsStringSync(singleEsMessageArbFileString);
l10nDirectory.childFile('app_zh.arb') l10nDirectory.childFile('app_zh.arb')
.writeAsStringSync(singleZhMessageArbFileString); .writeAsStringSync(singleZhMessageArbFileString);
const String preferredSupportedLocaleString = '[44, "en_US"]'; const String preferredSupportedLocaleString = '[44, "en"]';
LocalizationsGenerator generator; LocalizationsGenerator generator;
try { try {
generator = LocalizationsGenerator(fs); generator = LocalizationsGenerator(fs);
...@@ -363,7 +363,7 @@ void main() { ...@@ -363,7 +363,7 @@ void main() {
() { () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true); ..createSync(recursive: true);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en.arb')
.writeAsStringSync(singleMessageArbFileString); .writeAsStringSync(singleMessageArbFileString);
l10nDirectory.childFile('app_es.arb') l10nDirectory.childFile('app_es.arb')
.writeAsStringSync(singleEsMessageArbFileString); .writeAsStringSync(singleEsMessageArbFileString);
...@@ -405,7 +405,7 @@ void main() { ...@@ -405,7 +405,7 @@ void main() {
.writeAsStringSync(singleZhMessageArbFileString); .writeAsStringSync(singleZhMessageArbFileString);
l10nDirectory.childFile('app_es.arb') l10nDirectory.childFile('app_es.arb')
.writeAsStringSync(singleEsMessageArbFileString); .writeAsStringSync(singleEsMessageArbFileString);
l10nDirectory.childFile('app_en_US.arb') l10nDirectory.childFile('app_en.arb')
.writeAsStringSync(singleMessageArbFileString); .writeAsStringSync(singleMessageArbFileString);
LocalizationsGenerator generator; LocalizationsGenerator generator;
...@@ -423,11 +423,11 @@ void main() { ...@@ -423,11 +423,11 @@ void main() {
} }
if (Platform.isWindows) { if (Platform.isWindows) {
expect(generator.arbPathStrings.first, r'lib\l10n\app_en_US.arb'); expect(generator.arbPathStrings.first, r'lib\l10n\app_en.arb');
expect(generator.arbPathStrings.elementAt(1), r'lib\l10n\app_es.arb'); expect(generator.arbPathStrings.elementAt(1), r'lib\l10n\app_es.arb');
expect(generator.arbPathStrings.elementAt(2), r'lib\l10n\app_zh.arb'); expect(generator.arbPathStrings.elementAt(2), r'lib\l10n\app_zh.arb');
} else { } else {
expect(generator.arbPathStrings.first, 'lib/l10n/app_en_US.arb'); expect(generator.arbPathStrings.first, 'lib/l10n/app_en.arb');
expect(generator.arbPathStrings.elementAt(1), 'lib/l10n/app_es.arb'); expect(generator.arbPathStrings.elementAt(1), 'lib/l10n/app_es.arb');
expect(generator.arbPathStrings.elementAt(2), 'lib/l10n/app_zh.arb'); expect(generator.arbPathStrings.elementAt(2), 'lib/l10n/app_zh.arb');
} }
...@@ -583,6 +583,32 @@ void main() { ...@@ -583,6 +583,32 @@ void main() {
'should fail' 'should fail'
); );
}); });
test('throws when the base locale does not exist', () {
final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
..createSync(recursive: true);
l10nDirectory.childFile('app_en_US.arb')
.writeAsStringSync(singleMessageArbFileString);
try {
final LocalizationsGenerator generator = LocalizationsGenerator(fs);
generator.initialize(
l10nDirectoryPath: defaultArbPathString,
templateArbFileName: 'app_en_US.arb',
outputFileString: defaultOutputFileString,
classNameString: defaultClassNameString,
);
generator.loadResources();
} on L10nException catch (e) {
expect(e.message, contains('Arb file for a fallback, en, does not exist'));
return;
}
fail(
'Since en_US.arb is specified, but en.arb is not, '
'the tool should throw an error.'
);
});
}); });
group('generateCode', () { group('generateCode', () {
......
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