Make an app's supported locales configurable (#11946)
* Make an app's supported locales configurable * Added an supportedLocales.isNotEmpty assert * WidgetsApp no longer const because supportedLocales.isNotEmpty * updated per review feedback * tweaked dartdoc to restart the build * updated per review feedback * Updated per review feedback
This commit is contained in:
parent
3bf3df33ea
commit
4262c1e9d3
@ -121,6 +121,10 @@ class StocksAppState extends State<StocksApp> {
|
|||||||
localizationsDelegates: <_StocksLocalizationsDelegate>[
|
localizationsDelegates: <_StocksLocalizationsDelegate>[
|
||||||
new _StocksLocalizationsDelegate(),
|
new _StocksLocalizationsDelegate(),
|
||||||
],
|
],
|
||||||
|
supportedLocales: const <Locale>[
|
||||||
|
const Locale('en', 'US'),
|
||||||
|
const Locale('es', 'ES'),
|
||||||
|
],
|
||||||
debugShowMaterialGrid: _configuration.debugShowGrid,
|
debugShowMaterialGrid: _configuration.debugShowGrid,
|
||||||
showPerformanceOverlay: _configuration.showPerformanceOverlay,
|
showPerformanceOverlay: _configuration.showPerformanceOverlay,
|
||||||
showSemanticsDebugger: _configuration.showSemanticsDebugger,
|
showSemanticsDebugger: _configuration.showSemanticsDebugger,
|
||||||
|
@ -94,6 +94,8 @@ class MaterialApp extends StatefulWidget {
|
|||||||
this.onUnknownRoute,
|
this.onUnknownRoute,
|
||||||
this.locale,
|
this.locale,
|
||||||
this.localizationsDelegates,
|
this.localizationsDelegates,
|
||||||
|
this.localeResolutionCallback,
|
||||||
|
this.supportedLocales: const <Locale>[const Locale('en', 'US')],
|
||||||
this.navigatorObservers: const <NavigatorObserver>[],
|
this.navigatorObservers: const <NavigatorObserver>[],
|
||||||
this.debugShowMaterialGrid: false,
|
this.debugShowMaterialGrid: false,
|
||||||
this.showPerformanceOverlay: false,
|
this.showPerformanceOverlay: false,
|
||||||
@ -233,6 +235,65 @@ class MaterialApp extends StatefulWidget {
|
|||||||
/// for this application's [Localizations] widget.
|
/// for this application's [Localizations] widget.
|
||||||
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
|
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
|
||||||
|
|
||||||
|
/// This callback is responsible for choosing the app's locale
|
||||||
|
/// when the app is started, and when the user changes the
|
||||||
|
/// device's locale.
|
||||||
|
///
|
||||||
|
/// The returned value becomes the locale of this app's [Localizations]
|
||||||
|
/// widget. The callback's `locale` parameter is the device's locale when
|
||||||
|
/// the app started, or the device locale the user selected after the app was
|
||||||
|
/// started. The callback's `supportedLocales` parameter is just the value
|
||||||
|
/// [supportedLocales].
|
||||||
|
///
|
||||||
|
/// An app could use this callback to substitute locales based on the app's
|
||||||
|
/// intended audience. If the device's OS provides a prioritized
|
||||||
|
/// list of locales, this callback could be used to defer to it.
|
||||||
|
///
|
||||||
|
/// If the callback is null then the resolved locale is:
|
||||||
|
/// - The callback's `locale` parameter if it's equal to a supported locale.
|
||||||
|
/// - The first supported locale with the same [Locale.languageCode] as the
|
||||||
|
/// callback's `locale` parameter.
|
||||||
|
/// - The first supported locale.
|
||||||
|
///
|
||||||
|
/// This callback is passed along to the [WidgetsApp] built by this widget.
|
||||||
|
final LocaleResolutionCallback localeResolutionCallback;
|
||||||
|
|
||||||
|
/// The list of locales that this app has been localized for.
|
||||||
|
///
|
||||||
|
/// By default only the American English locale is supported. Apps should
|
||||||
|
/// configure this list to match the locales they support.
|
||||||
|
///
|
||||||
|
/// This list must not null. It's default value is just
|
||||||
|
/// `[const Locale('en', 'US')]`. It is simply passed along to the
|
||||||
|
/// [WidgetsApp] built by this widget.
|
||||||
|
///
|
||||||
|
/// The order of the list matters. By default, if the device's locale doesn't
|
||||||
|
/// exactly match a locale in [supportedLocales] then the first locale in
|
||||||
|
/// [supportedLocales] with a matching [Locale.languageCode] is used. If that
|
||||||
|
/// fails then the first locale in [supportedLocales] is used. The default
|
||||||
|
/// locale resolution algorithm can be overridden with [localeResolutionCallback].
|
||||||
|
///
|
||||||
|
/// The material widgets include translations for locales with the following
|
||||||
|
/// language codes:
|
||||||
|
/// ```
|
||||||
|
/// ar - Arabic
|
||||||
|
/// de - German
|
||||||
|
/// en - English
|
||||||
|
/// es - Spanish
|
||||||
|
/// fa - Farsi (Persian)
|
||||||
|
/// fr - French
|
||||||
|
/// he - Hebrew
|
||||||
|
/// it - Italian
|
||||||
|
/// ja - Japanese
|
||||||
|
/// ps - Pashto
|
||||||
|
/// pt - Portugese
|
||||||
|
/// ru - Russian
|
||||||
|
/// sd - Sindhi
|
||||||
|
/// ur - Urdu
|
||||||
|
/// zh - Chinese (simplified)
|
||||||
|
/// ```
|
||||||
|
final Iterable<Locale> supportedLocales;
|
||||||
|
|
||||||
/// Turns on a performance overlay.
|
/// Turns on a performance overlay.
|
||||||
///
|
///
|
||||||
/// See also:
|
/// See also:
|
||||||
@ -399,6 +460,8 @@ class _MaterialAppState extends State<MaterialApp> {
|
|||||||
onUnknownRoute: _onUnknownRoute,
|
onUnknownRoute: _onUnknownRoute,
|
||||||
locale: widget.locale,
|
locale: widget.locale,
|
||||||
localizationsDelegates: _localizationsDelegates,
|
localizationsDelegates: _localizationsDelegates,
|
||||||
|
localeResolutionCallback: widget.localeResolutionCallback,
|
||||||
|
supportedLocales: widget.supportedLocales,
|
||||||
showPerformanceOverlay: widget.showPerformanceOverlay,
|
showPerformanceOverlay: widget.showPerformanceOverlay,
|
||||||
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
|
checkerboardRasterCacheImages: widget.checkerboardRasterCacheImages,
|
||||||
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
|
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers,
|
||||||
|
@ -23,6 +23,17 @@ import 'widget_inspector.dart';
|
|||||||
|
|
||||||
export 'dart:ui' show Locale;
|
export 'dart:ui' show Locale;
|
||||||
|
|
||||||
|
/// The signature of [WidgetsApp.localeResolutionCallback].
|
||||||
|
///
|
||||||
|
/// A `LocaleResolutionCallback` is responsible for computing the locale of the app's
|
||||||
|
/// [Localizations] object when the app starts and when user changes the default
|
||||||
|
/// locale for the device.
|
||||||
|
///
|
||||||
|
/// The `locale` is the device's locale when the app started, or the device
|
||||||
|
/// locale the user selected after the app was started. The `supportedLocales`
|
||||||
|
/// parameter is just the value of [WidgetApp.supportedLocales].
|
||||||
|
typedef Locale LocaleResolutionCallback(Locale locale, Iterable<Locale> supportedLocales);
|
||||||
|
|
||||||
// Delegate that fetches the default (English) strings.
|
// Delegate that fetches the default (English) strings.
|
||||||
class _WidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
|
class _WidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
|
||||||
const _WidgetsLocalizationsDelegate();
|
const _WidgetsLocalizationsDelegate();
|
||||||
@ -52,7 +63,10 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
/// The boolean arguments, [color], [navigatorObservers], and
|
/// The boolean arguments, [color], [navigatorObservers], and
|
||||||
/// [onGenerateRoute] must not be null.
|
/// [onGenerateRoute] must not be null.
|
||||||
const WidgetsApp({
|
///
|
||||||
|
/// The `supportedLocales` argument must be a list of one or more elements.
|
||||||
|
/// By default supportedLocales is `[const Locale('en', 'US')]`.
|
||||||
|
WidgetsApp({ // can't be const because the asserts use methods on Iterable :-(
|
||||||
Key key,
|
Key key,
|
||||||
@required this.onGenerateRoute,
|
@required this.onGenerateRoute,
|
||||||
this.onUnknownRoute,
|
this.onUnknownRoute,
|
||||||
@ -63,6 +77,8 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
this.initialRoute,
|
this.initialRoute,
|
||||||
this.locale,
|
this.locale,
|
||||||
this.localizationsDelegates,
|
this.localizationsDelegates,
|
||||||
|
this.localeResolutionCallback,
|
||||||
|
this.supportedLocales: const <Locale>[const Locale('en', 'US')],
|
||||||
this.showPerformanceOverlay: false,
|
this.showPerformanceOverlay: false,
|
||||||
this.checkerboardRasterCacheImages: false,
|
this.checkerboardRasterCacheImages: false,
|
||||||
this.checkerboardOffscreenLayers: false,
|
this.checkerboardOffscreenLayers: false,
|
||||||
@ -73,6 +89,7 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
}) : assert(onGenerateRoute != null),
|
}) : assert(onGenerateRoute != null),
|
||||||
assert(color != null),
|
assert(color != null),
|
||||||
assert(navigatorObservers != null),
|
assert(navigatorObservers != null),
|
||||||
|
assert(supportedLocales != null && supportedLocales.isNotEmpty),
|
||||||
assert(showPerformanceOverlay != null),
|
assert(showPerformanceOverlay != null),
|
||||||
assert(checkerboardRasterCacheImages != null),
|
assert(checkerboardRasterCacheImages != null),
|
||||||
assert(checkerboardOffscreenLayers != null),
|
assert(checkerboardOffscreenLayers != null),
|
||||||
@ -149,6 +166,55 @@ class WidgetsApp extends StatefulWidget {
|
|||||||
/// for this application's [Localizations] widget.
|
/// for this application's [Localizations] widget.
|
||||||
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
|
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
|
||||||
|
|
||||||
|
/// This callback is responsible for choosing the app's locale
|
||||||
|
/// when the app is started, and when the user changes the
|
||||||
|
/// device's locale.
|
||||||
|
///
|
||||||
|
/// The returned value becomes the locale of this app's [Localizations]
|
||||||
|
/// widget. The callback's `locale` parameter is the device's locale when
|
||||||
|
/// the app started, or the device locale the user selected after the app was
|
||||||
|
/// started. The callback's `supportedLocales` parameter is just the value
|
||||||
|
/// [supportedLocales].
|
||||||
|
///
|
||||||
|
/// If the callback is null or if it returns null then the resolved locale is:
|
||||||
|
///
|
||||||
|
/// - The callback's `locale` parameter if it's equal to a supported locale.
|
||||||
|
/// - The first supported locale with the same [Locale.langaugeCode] as the
|
||||||
|
/// callback's `locale` parameter.
|
||||||
|
/// - The first locale in [supportedLocales].
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [MaterialApp.localeResolutionCallback], which sets the callback of the
|
||||||
|
/// [WidgetsApp] it creates.
|
||||||
|
final LocaleResolutionCallback localeResolutionCallback;
|
||||||
|
|
||||||
|
/// The list of locales that this app has been localized for.
|
||||||
|
///
|
||||||
|
/// By default only the American English locale is supported. Apps should
|
||||||
|
/// configure this list to match the locales they support.
|
||||||
|
///
|
||||||
|
/// This list must not null. Its default value is just
|
||||||
|
/// `[const Locale('en', 'US')]`.
|
||||||
|
///
|
||||||
|
/// The order of the list matters. By default, if the device's locale doesn't
|
||||||
|
/// exactly match a locale in [supportedLocales] then the first locale in
|
||||||
|
/// [supportedLocales] with a matching [Locale.languageCode] is used. If that
|
||||||
|
/// fails then the first locale in [supportedLocales] is used. The default
|
||||||
|
/// locale resolution algorithm can be overridden with [localeResolutionCallback].
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
///
|
||||||
|
/// * [MaterialApp.supportedLocales], which sets the `supportedLocales`
|
||||||
|
/// of the [WidgetsApp] it creates.
|
||||||
|
///
|
||||||
|
/// * [localeResolutionCallback], an app callback that resolves the app's locale
|
||||||
|
/// when the device's locale changes.
|
||||||
|
///
|
||||||
|
/// * [localizationDelegates], which collectively define all of the localized
|
||||||
|
/// resources used by this app.
|
||||||
|
final Iterable<Locale> supportedLocales;
|
||||||
|
|
||||||
/// Turns on a performance overlay.
|
/// Turns on a performance overlay.
|
||||||
/// https://flutter.io/debugging/#performanceoverlay
|
/// https://flutter.io/debugging/#performanceoverlay
|
||||||
final bool showPerformanceOverlay;
|
final bool showPerformanceOverlay;
|
||||||
@ -231,11 +297,28 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
GlobalObjectKey<NavigatorState> _navigator;
|
GlobalObjectKey<NavigatorState> _navigator;
|
||||||
Locale _locale;
|
Locale _locale;
|
||||||
|
|
||||||
|
Locale _resolveLocale(Locale newLocale, Iterable<Locale> supportedLocales) {
|
||||||
|
if (widget.localeResolutionCallback != null) {
|
||||||
|
final Locale locale = widget.localeResolutionCallback(newLocale, widget.supportedLocales);
|
||||||
|
if (locale != null)
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
Locale matchesLanguageCode;
|
||||||
|
for (Locale locale in supportedLocales) {
|
||||||
|
if (locale == newLocale)
|
||||||
|
return newLocale;
|
||||||
|
if (locale.languageCode == newLocale.languageCode)
|
||||||
|
matchesLanguageCode ??= locale;
|
||||||
|
}
|
||||||
|
return matchesLanguageCode ?? supportedLocales.first;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_navigator = new GlobalObjectKey<NavigatorState>(this);
|
_navigator = new GlobalObjectKey<NavigatorState>(this);
|
||||||
_locale = ui.window.locale;
|
_locale = _resolveLocale(ui.window.locale, widget.supportedLocales);
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,9 +356,12 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeLocale(Locale locale) {
|
void didChangeLocale(Locale locale) {
|
||||||
if (locale != _locale) {
|
if (locale == _locale)
|
||||||
|
return;
|
||||||
|
final Locale newLocale = _resolveLocale(locale, widget.supportedLocales);
|
||||||
|
if (newLocale != _locale) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_locale = locale;
|
_locale = newLocale;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,10 @@ Widget buildFrame({
|
|||||||
return new MaterialApp(
|
return new MaterialApp(
|
||||||
color: const Color(0xFFFFFFFF),
|
color: const Color(0xFFFFFFFF),
|
||||||
locale: locale,
|
locale: locale,
|
||||||
|
supportedLocales: const <Locale>[
|
||||||
|
const Locale('en', 'US'),
|
||||||
|
const Locale('es', 'es'),
|
||||||
|
],
|
||||||
onGenerateRoute: (RouteSettings settings) {
|
onGenerateRoute: (RouteSettings settings) {
|
||||||
return new MaterialPageRoute<Null>(
|
return new MaterialPageRoute<Null>(
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -39,15 +43,16 @@ void main() {
|
|||||||
|
|
||||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
||||||
|
|
||||||
|
// Unrecognized locale falls back to 'en'
|
||||||
|
await tester.binding.setLocale('foo', 'bar');
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
||||||
|
|
||||||
// Spanish Bolivia locale, falls back to just 'es'
|
// Spanish Bolivia locale, falls back to just 'es'
|
||||||
await tester.binding.setLocale('es', 'bo');
|
await tester.binding.setLocale('es', 'bo');
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Espalda');
|
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Espalda');
|
||||||
|
|
||||||
// Unrecognized locale falls back to 'en'
|
|
||||||
await tester.binding.setLocale('foo', 'bar');
|
|
||||||
await tester.pump();
|
|
||||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('translations exist for all materia/i18n languages', (WidgetTester tester) async {
|
testWidgets('translations exist for all materia/i18n languages', (WidgetTester tester) async {
|
||||||
|
@ -107,11 +107,18 @@ Widget buildFrame({
|
|||||||
Locale locale,
|
Locale locale,
|
||||||
Iterable<LocalizationsDelegate<dynamic>> delegates,
|
Iterable<LocalizationsDelegate<dynamic>> delegates,
|
||||||
WidgetBuilder buildContent,
|
WidgetBuilder buildContent,
|
||||||
|
LocaleResolutionCallback localeResolutionCallback,
|
||||||
|
List<Locale> supportedLocales: const <Locale>[
|
||||||
|
const Locale('en', 'US'),
|
||||||
|
const Locale('en', 'GB'),
|
||||||
|
],
|
||||||
}) {
|
}) {
|
||||||
return new WidgetsApp(
|
return new WidgetsApp(
|
||||||
color: const Color(0xFFFFFFFF),
|
color: const Color(0xFFFFFFFF),
|
||||||
locale: locale,
|
locale: locale,
|
||||||
localizationsDelegates: delegates,
|
localizationsDelegates: delegates,
|
||||||
|
localeResolutionCallback: localeResolutionCallback,
|
||||||
|
supportedLocales: supportedLocales,
|
||||||
onGenerateRoute: (RouteSettings settings) {
|
onGenerateRoute: (RouteSettings settings) {
|
||||||
return new PageRouteBuilder<Null>(
|
return new PageRouteBuilder<Null>(
|
||||||
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
|
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
|
||||||
@ -182,7 +189,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(TestLocalizations.of(pageContext), isNotNull);
|
expect(TestLocalizations.of(pageContext), isNotNull);
|
||||||
expect(find.text('_'), findsOneWidget); // default test locale is '_'
|
expect(find.text('en_US'), findsOneWidget);
|
||||||
|
|
||||||
await tester.binding.setLocale('en', 'GB');
|
await tester.binding.setLocale('en', 'GB');
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
@ -205,25 +212,25 @@ void main() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() takes 100ms
|
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() takes 100ms
|
||||||
expect(find.text('_'), findsNothing); // TestLocalizations hasn't been loaded yet
|
expect(find.text('en_US'), findsNothing); // TestLocalizations hasn't been loaded yet
|
||||||
|
|
||||||
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() completes
|
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() completes
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('_'), findsOneWidget); // default test locale is '_'
|
expect(find.text('en_US'), findsOneWidget); // default test locale is US english
|
||||||
|
|
||||||
await tester.binding.setLocale('en', 'US');
|
|
||||||
await tester.pump(const Duration(milliseconds: 100));
|
|
||||||
await tester.pumpAndSettle();
|
|
||||||
expect(find.text('en_US'), findsOneWidget);
|
|
||||||
|
|
||||||
await tester.binding.setLocale('en', 'GB');
|
await tester.binding.setLocale('en', 'GB');
|
||||||
|
await tester.pump(const Duration(milliseconds: 100));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('en_GB'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.binding.setLocale('en', 'US');
|
||||||
await tester.pump(const Duration(milliseconds: 50));
|
await tester.pump(const Duration(milliseconds: 50));
|
||||||
// TestLocalizations.loadAsync() hasn't completed yet so the old text
|
// TestLocalizations.loadAsync() hasn't completed yet so the old text
|
||||||
// localization is still displayed
|
// localization is still displayed
|
||||||
expect(find.text('en_US'), findsOneWidget);
|
expect(find.text('en_GB'), findsOneWidget);
|
||||||
await tester.pump(const Duration(milliseconds: 50)); // finish the async load
|
await tester.pump(const Duration(milliseconds: 50)); // finish the async load
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.text('en_GB'), findsOneWidget);
|
expect(find.text('en_US'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Localizations with multiple sync delegates', (WidgetTester tester) async {
|
testWidgets('Localizations with multiple sync delegates', (WidgetTester tester) async {
|
||||||
@ -422,6 +429,10 @@ void main() {
|
|||||||
|
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
buildFrame(
|
buildFrame(
|
||||||
|
supportedLocales: const <Locale>[
|
||||||
|
const Locale('en', 'GB'),
|
||||||
|
const Locale('ar', 'EG'),
|
||||||
|
],
|
||||||
buildContent: (BuildContext context) {
|
buildContent: (BuildContext context) {
|
||||||
pageContext = context;
|
pageContext = context;
|
||||||
return const Text('Hello World');
|
return const Text('Hello World');
|
||||||
@ -437,6 +448,62 @@ void main() {
|
|||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(Directionality.of(pageContext), TextDirection.rtl);
|
expect(Directionality.of(pageContext), TextDirection.rtl);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('localeResolutionCallback override', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildFrame(
|
||||||
|
localeResolutionCallback: (Locale newLocale, Iterable<Locale> supportedLocales) {
|
||||||
|
return const Locale('foo', 'BAR');
|
||||||
|
},
|
||||||
|
buildContent: (BuildContext context) {
|
||||||
|
return new Text(Localizations.localeOf(context).toString());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('foo_BAR'), findsOneWidget);
|
||||||
|
|
||||||
|
await tester.binding.setLocale('en', 'GB');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('foo_BAR'), findsOneWidget);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
testWidgets('supportedLocales and defaultLocaleChangeHandler', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildFrame(
|
||||||
|
supportedLocales: const <Locale>[
|
||||||
|
const Locale('zh', 'CN'),
|
||||||
|
const Locale('en', 'GB'),
|
||||||
|
const Locale('en', 'CA'),
|
||||||
|
],
|
||||||
|
buildContent: (BuildContext context) {
|
||||||
|
return new Text(Localizations.localeOf(context).toString());
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Startup time. Default test locale is const Locale('', ''), so
|
||||||
|
// no supported matches. Use the first locale.
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('zh_CN'), findsOneWidget);
|
||||||
|
|
||||||
|
// defaultLocaleChangedHandler prefers exact supported locale match
|
||||||
|
await tester.binding.setLocale('en', 'CA');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('en_CA'), findsOneWidget);
|
||||||
|
|
||||||
|
// defaultLocaleChangedHandler chooses 1st matching supported locale.languageCode
|
||||||
|
await tester.binding.setLocale('en', 'US');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('en_GB'), findsOneWidget);
|
||||||
|
|
||||||
|
// defaultLocaleChangedHandler: no matching supported locale, so use the 1st one
|
||||||
|
await tester.binding.setLocale('da', 'DA');
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(find.text('zh_CN'), findsOneWidget);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as _WidgetsLocalizationsDelegate in widgets/app.dart
|
// Same as _WidgetsLocalizationsDelegate in widgets/app.dart
|
||||||
|
Loading…
x
Reference in New Issue
Block a user