mirror of
https://github.com/flutter/flutter
synced 2024-09-17 23:31:55 +00:00
74cfc3db67
* Use `curly_braces_in_flow_control_structures` for `packages/flutter_driver` * Use `curly_braces_in_flow_control_structures` for `packages/flutter_goldens` * Use `curly_braces_in_flow_control_structures` for `packages/flutter_goldens_client` * Use `curly_braces_in_flow_control_structures` for `packages/flutter_localizations` * Use `curly_braces_in_flow_control_structures` for `packages/flutter_test` * Use `curly_braces_in_flow_control_structures` for `packages/flutter_web_plugins` * fix comments * Use `curly_braces_in_flow_control_structures` for `packages/integration_test` * fix indentation
1454 lines
50 KiB
Dart
1454 lines
50 KiB
Dart
// 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 'package:flutter/foundation.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
class TestLocalizations {
|
|
TestLocalizations(this.locale, this.prefix);
|
|
|
|
final Locale locale;
|
|
final String? prefix;
|
|
|
|
static Future<TestLocalizations> loadSync(Locale locale, String? prefix) {
|
|
return SynchronousFuture<TestLocalizations>(TestLocalizations(locale, prefix));
|
|
}
|
|
|
|
static Future<TestLocalizations> loadAsync(Locale locale, String? prefix) {
|
|
return Future<TestLocalizations>.delayed(
|
|
const Duration(milliseconds: 100),
|
|
() => TestLocalizations(locale, prefix)
|
|
);
|
|
}
|
|
|
|
static TestLocalizations of(BuildContext context) {
|
|
return Localizations.of<TestLocalizations>(context, TestLocalizations)!;
|
|
}
|
|
|
|
String get message => '${prefix ?? ""}$locale';
|
|
}
|
|
|
|
class SyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> {
|
|
SyncTestLocalizationsDelegate([this.prefix]);
|
|
|
|
final String? prefix; // Changing this value triggers a rebuild
|
|
final List<bool> shouldReloadValues = <bool>[];
|
|
|
|
@override
|
|
bool isSupported(Locale locale) => true;
|
|
|
|
@override
|
|
Future<TestLocalizations> load(Locale locale) => TestLocalizations.loadSync(locale, prefix);
|
|
|
|
@override
|
|
bool shouldReload(SyncTestLocalizationsDelegate old) {
|
|
shouldReloadValues.add(prefix != old.prefix);
|
|
return prefix != old.prefix;
|
|
}
|
|
|
|
@override
|
|
String toString() => '${objectRuntimeType(this, 'SyncTestLocalizationsDelegate')}($prefix)';
|
|
}
|
|
|
|
class AsyncTestLocalizationsDelegate extends LocalizationsDelegate<TestLocalizations> {
|
|
AsyncTestLocalizationsDelegate([this.prefix]);
|
|
|
|
final String? prefix; // Changing this value triggers a rebuild
|
|
final List<bool> shouldReloadValues = <bool>[];
|
|
|
|
@override
|
|
bool isSupported(Locale locale) => true;
|
|
|
|
@override
|
|
Future<TestLocalizations> load(Locale locale) => TestLocalizations.loadAsync(locale, prefix);
|
|
|
|
@override
|
|
bool shouldReload(AsyncTestLocalizationsDelegate old) {
|
|
shouldReloadValues.add(prefix != old.prefix);
|
|
return prefix != old.prefix;
|
|
}
|
|
|
|
@override
|
|
String toString() => '${objectRuntimeType(this, 'AsyncTestLocalizationsDelegate')}($prefix)';
|
|
}
|
|
|
|
class MoreLocalizations {
|
|
MoreLocalizations(this.locale);
|
|
|
|
final Locale locale;
|
|
|
|
static Future<MoreLocalizations> loadSync(Locale locale) {
|
|
return SynchronousFuture<MoreLocalizations>(MoreLocalizations(locale));
|
|
}
|
|
|
|
static Future<MoreLocalizations> loadAsync(Locale locale) {
|
|
return Future<MoreLocalizations>.delayed(
|
|
const Duration(milliseconds: 100),
|
|
() => MoreLocalizations(locale)
|
|
);
|
|
}
|
|
|
|
static MoreLocalizations of(BuildContext context) {
|
|
return Localizations.of<MoreLocalizations>(context, MoreLocalizations)!;
|
|
}
|
|
|
|
String get message => '$locale';
|
|
}
|
|
|
|
class SyncMoreLocalizationsDelegate extends LocalizationsDelegate<MoreLocalizations> {
|
|
@override
|
|
Future<MoreLocalizations> load(Locale locale) => MoreLocalizations.loadSync(locale);
|
|
|
|
@override
|
|
bool isSupported(Locale locale) => true;
|
|
|
|
@override
|
|
bool shouldReload(SyncMoreLocalizationsDelegate old) => false;
|
|
}
|
|
|
|
class AsyncMoreLocalizationsDelegate extends LocalizationsDelegate<MoreLocalizations> {
|
|
@override
|
|
Future<MoreLocalizations> load(Locale locale) => MoreLocalizations.loadAsync(locale);
|
|
|
|
@override
|
|
bool isSupported(Locale locale) => true;
|
|
|
|
@override
|
|
bool shouldReload(AsyncMoreLocalizationsDelegate old) => false;
|
|
}
|
|
|
|
class OnlyRTLDefaultWidgetsLocalizations extends DefaultWidgetsLocalizations {
|
|
@override
|
|
TextDirection get textDirection => TextDirection.rtl;
|
|
}
|
|
|
|
class OnlyRTLDefaultWidgetsLocalizationsDelegate extends LocalizationsDelegate<WidgetsLocalizations> {
|
|
const OnlyRTLDefaultWidgetsLocalizationsDelegate();
|
|
|
|
@override
|
|
bool isSupported(Locale locale) => true;
|
|
|
|
@override
|
|
Future<WidgetsLocalizations> load(Locale locale) {
|
|
return SynchronousFuture<WidgetsLocalizations>(OnlyRTLDefaultWidgetsLocalizations());
|
|
}
|
|
|
|
@override
|
|
bool shouldReload(OnlyRTLDefaultWidgetsLocalizationsDelegate old) => false;
|
|
}
|
|
|
|
Widget buildFrame({
|
|
Locale? locale,
|
|
Iterable<LocalizationsDelegate<dynamic>>? delegates,
|
|
required WidgetBuilder buildContent,
|
|
LocaleResolutionCallback? localeResolutionCallback,
|
|
List<Locale> supportedLocales = const <Locale>[
|
|
Locale('en', 'US'),
|
|
Locale('en', 'GB'),
|
|
],
|
|
}) {
|
|
return WidgetsApp(
|
|
color: const Color(0xFFFFFFFF),
|
|
locale: locale,
|
|
localizationsDelegates: delegates,
|
|
localeResolutionCallback: localeResolutionCallback,
|
|
supportedLocales: supportedLocales,
|
|
onGenerateRoute: (RouteSettings settings) {
|
|
return PageRouteBuilder<void>(
|
|
pageBuilder: (BuildContext context, Animation<double> _, Animation<double> __) {
|
|
return buildContent(context);
|
|
}
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
class SyncLoadTest extends StatefulWidget {
|
|
const SyncLoadTest({super.key});
|
|
|
|
@override
|
|
SyncLoadTestState createState() => SyncLoadTestState();
|
|
}
|
|
|
|
class SyncLoadTestState extends State<SyncLoadTest> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Text(
|
|
TestLocalizations.of(context).message,
|
|
textDirection: TextDirection.rtl,
|
|
);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
testWidgets('Localizations.localeFor in a WidgetsApp with system locale', (WidgetTester tester) async {
|
|
late BuildContext pageContext;
|
|
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
buildContent: (BuildContext context) {
|
|
pageContext = context;
|
|
return const Text('Hello World', textDirection: TextDirection.ltr);
|
|
}
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocale('en', 'GB');
|
|
await tester.pump();
|
|
expect(Localizations.localeOf(pageContext), const Locale('en', 'GB'));
|
|
|
|
await tester.binding.setLocale('en', 'US');
|
|
await tester.pump();
|
|
expect(Localizations.localeOf(pageContext), const Locale('en', 'US'));
|
|
});
|
|
|
|
testWidgets('Localizations.localeFor in a WidgetsApp with an explicit locale', (WidgetTester tester) async {
|
|
const Locale locale = Locale('en', 'US');
|
|
late BuildContext pageContext;
|
|
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
locale: locale,
|
|
buildContent: (BuildContext context) {
|
|
pageContext = context;
|
|
return const Text('Hello World');
|
|
},
|
|
)
|
|
);
|
|
|
|
expect(Localizations.localeOf(pageContext), locale);
|
|
|
|
await tester.binding.setLocale('en', 'GB');
|
|
await tester.pump();
|
|
|
|
// The WidgetApp's explicit locale overrides the system's locale.
|
|
expect(Localizations.localeOf(pageContext), locale);
|
|
});
|
|
|
|
testWidgets('Synchronously loaded localizations in a WidgetsApp', (WidgetTester tester) async {
|
|
final List<LocalizationsDelegate<dynamic>> delegates = <LocalizationsDelegate<dynamic>>[
|
|
SyncTestLocalizationsDelegate(),
|
|
DefaultWidgetsLocalizations.delegate,
|
|
];
|
|
|
|
Future<void> pumpTest(Locale locale) async {
|
|
await tester.pumpWidget(Localizations(
|
|
locale: locale,
|
|
delegates: delegates,
|
|
child: const SyncLoadTest(),
|
|
));
|
|
}
|
|
|
|
await pumpTest(const Locale('en', 'US'));
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await pumpTest(const Locale('en', 'GB'));
|
|
await tester.pump();
|
|
expect(find.text('en_GB'), findsOneWidget);
|
|
|
|
await pumpTest(const Locale('en', 'US'));
|
|
await tester.pump();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Asynchronously loaded localizations in a WidgetsApp', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
AsyncTestLocalizationsDelegate(),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
return Text(TestLocalizations.of(context).message);
|
|
},
|
|
)
|
|
);
|
|
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() takes 100ms
|
|
expect(find.text('en_US'), findsNothing); // TestLocalizations hasn't been loaded yet
|
|
|
|
await tester.pump(const Duration(milliseconds: 50)); // TestLocalizations.loadAsync() completes
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget); // default test locale is US english
|
|
|
|
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));
|
|
// TestLocalizations.loadAsync() hasn't completed yet so the old text
|
|
// localization is still displayed
|
|
expect(find.text('en_GB'), findsOneWidget);
|
|
await tester.pump(const Duration(milliseconds: 50)); // finish the async load
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Localizations with multiple sync delegates', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
SyncTestLocalizationsDelegate(),
|
|
SyncMoreLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
// All localizations were loaded synchronously
|
|
expect(find.text('A: en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Localizations with multiple delegates', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
SyncTestLocalizationsDelegate(),
|
|
AsyncMoreLocalizationsDelegate(), // No resources until this completes
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pump(const Duration(milliseconds: 50));
|
|
expect(find.text('A: en_US'), findsNothing); // MoreLocalizations.load() hasn't completed yet
|
|
expect(find.text('B: en_US'), findsNothing);
|
|
|
|
await tester.pump(const Duration(milliseconds: 50));
|
|
await tester.pumpAndSettle();
|
|
|
|
expect(find.text('A: en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('Multiple Localizations', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
SyncTestLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Localizations(
|
|
locale: const Locale('en', 'GB'),
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
SyncTestLocalizationsDelegate(),
|
|
DefaultWidgetsLocalizations.delegate,
|
|
],
|
|
// Create a new context within the en_GB Localization
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
return Text('B: ${TestLocalizations.of(context).message}');
|
|
},
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
expect(find.text('A: en_US'), findsOneWidget);
|
|
expect(find.text('B: en_GB'), findsOneWidget);
|
|
});
|
|
|
|
// If both the locale and the length and type of a Localizations delegate list
|
|
// stays the same BUT one of its delegate.shouldReload() methods returns true,
|
|
// then the dependent widgets should rebuild.
|
|
testWidgets('Localizations sync delegate shouldReload returns true', (WidgetTester tester) async {
|
|
final SyncTestLocalizationsDelegate originalDelegate = SyncTestLocalizationsDelegate();
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
originalDelegate,
|
|
SyncMoreLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('A: en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
expect(originalDelegate.shouldReloadValues, <bool>[]);
|
|
|
|
|
|
final SyncTestLocalizationsDelegate modifiedDelegate = SyncTestLocalizationsDelegate('---');
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
modifiedDelegate,
|
|
SyncMoreLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('A: ---en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
expect(modifiedDelegate.shouldReloadValues, <bool>[true]);
|
|
expect(originalDelegate.shouldReloadValues, <bool>[]);
|
|
});
|
|
|
|
testWidgets('Localizations async delegate shouldReload returns true', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
AsyncTestLocalizationsDelegate(),
|
|
AsyncMoreLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('A: en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
|
|
final AsyncTestLocalizationsDelegate modifiedDelegate = AsyncTestLocalizationsDelegate('---');
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: <LocalizationsDelegate<dynamic>>[
|
|
modifiedDelegate,
|
|
AsyncMoreLocalizationsDelegate(),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Column(
|
|
children: <Widget>[
|
|
Text('A: ${TestLocalizations.of(context).message}'),
|
|
Text('B: ${MoreLocalizations.of(context).message}'),
|
|
],
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('A: ---en_US'), findsOneWidget);
|
|
expect(find.text('B: en_US'), findsOneWidget);
|
|
expect(modifiedDelegate.shouldReloadValues, <bool>[true]);
|
|
});
|
|
|
|
testWidgets('Directionality tracks system locale', (WidgetTester tester) async {
|
|
late BuildContext pageContext;
|
|
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
delegates: const <LocalizationsDelegate<dynamic>>[
|
|
GlobalWidgetsLocalizations.delegate,
|
|
],
|
|
supportedLocales: const <Locale>[
|
|
Locale('en', 'GB'),
|
|
Locale('ar', 'EG'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
pageContext = context;
|
|
return const Text('Hello World');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocale('en', 'GB');
|
|
await tester.pump();
|
|
expect(Directionality.of(pageContext), TextDirection.ltr);
|
|
|
|
await tester.binding.setLocale('ar', 'EG');
|
|
await tester.pump();
|
|
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 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>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'GB'),
|
|
Locale('en', 'CA'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
return Text(Localizations.localeOf(context).toString());
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_GB'), 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);
|
|
});
|
|
|
|
testWidgets("Localizations.override widget tracks parent's locale and delegates", (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
// Accept whatever locale we're given
|
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
|
|
delegates: const <LocalizationsDelegate<dynamic>>[
|
|
GlobalWidgetsLocalizations.delegate,
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
return Localizations.override(
|
|
context: context,
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
|
|
return Text('$locale $direction');
|
|
},
|
|
),
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
// Initial WidgetTester locale is `en_US`.
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US TextDirection.ltr'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('en', 'CA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA TextDirection.ltr'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('ar', 'EG');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_EG TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('da', 'DA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('da_DA TextDirection.ltr'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets("Localizations.override widget overrides parent's DefaultWidgetLocalizations", (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
// Accept whatever locale we're given
|
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
|
|
buildContent: (BuildContext context) {
|
|
return Localizations.override(
|
|
context: context,
|
|
delegates: const <OnlyRTLDefaultWidgetsLocalizationsDelegate>[
|
|
// Override: no matter what the locale, textDirection is always RTL.
|
|
OnlyRTLDefaultWidgetsLocalizationsDelegate(),
|
|
],
|
|
child: Builder(
|
|
builder: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
|
|
return Text('$locale $direction');
|
|
},
|
|
),
|
|
);
|
|
},
|
|
)
|
|
);
|
|
|
|
// Initial WidgetTester locale is `en_US`.
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('en', 'CA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('ar', 'EG');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_EG TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('da', 'DA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('da_DA TextDirection.rtl'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('WidgetsApp overrides DefaultWidgetLocalizations', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
// Accept whatever locale we're given
|
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
|
|
delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[
|
|
const OnlyRTLDefaultWidgetsLocalizationsDelegate(),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
final TextDirection direction = WidgetsLocalizations.of(context).textDirection;
|
|
return Text('$locale $direction');
|
|
},
|
|
)
|
|
);
|
|
|
|
// Initial WidgetTester locale is `en_US`.
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('en', 'CA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('ar', 'EG');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_EG TextDirection.rtl'), findsOneWidget);
|
|
|
|
await tester.binding.setLocale('da', 'DA');
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('da_DA TextDirection.rtl'), findsOneWidget);
|
|
});
|
|
|
|
// We provide <Locale>[Locale('en', 'US'), Locale('zh', 'CN')] as ui.window.locales
|
|
// for flutter tester so that the behavior of tests match that of production
|
|
// environments. Here, we test the default locales.
|
|
testWidgets('WidgetsApp DefaultWidgetLocalizations', (WidgetTester tester) async {
|
|
await tester.pumpAndSettle();
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
// Accept whatever locale we're given
|
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) => locale,
|
|
delegates: <OnlyRTLDefaultWidgetsLocalizationsDelegate>[
|
|
const OnlyRTLDefaultWidgetsLocalizationsDelegate(),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale1 = WidgetsBinding.instance.platformDispatcher.locales.first;
|
|
final Locale locale2 = WidgetsBinding.instance.platformDispatcher.locales[1];
|
|
return Text('$locale1 $locale2');
|
|
},
|
|
)
|
|
);
|
|
// Initial WidgetTester default locales is `en_US` and `zh_CN`.
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US zh_CN'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('WidgetsApp.locale is resolved against supportedLocales', (WidgetTester tester) async {
|
|
// app locale matches a supportedLocale
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'US'),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Text(Localizations.localeOf(context).toString());
|
|
},
|
|
)
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
// app locale matches a supportedLocale's language
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'GB'),
|
|
],
|
|
locale: const Locale('en', 'US'),
|
|
buildContent: (BuildContext context) {
|
|
return Text(Localizations.localeOf(context).toString());
|
|
},
|
|
)
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_GB'), findsOneWidget);
|
|
|
|
// app locale matches no supportedLocale
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'US'),
|
|
],
|
|
locale: const Locale('ab', 'CD'),
|
|
buildContent: (BuildContext context) {
|
|
return Text(Localizations.localeOf(context).toString());
|
|
},
|
|
)
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_CN'), findsOneWidget);
|
|
});
|
|
|
|
// Example from http://unicode.org/reports/tr35/#LanguageMatching
|
|
testWidgets('WidgetsApp Unicode tr35 1', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('de'),
|
|
Locale('fr'),
|
|
Locale('ja'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'de', countryCode: 'AT'),
|
|
Locale.fromSubtags(languageCode: 'fr'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('de'), findsOneWidget);
|
|
});
|
|
|
|
// Examples from http://unicode.org/reports/tr35/#LanguageMatching
|
|
testWidgets('WidgetsApp Unicode tr35 2', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('ja', 'JP'),
|
|
Locale('de'),
|
|
Locale('zh', 'TW'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'de'),
|
|
Locale.fromSubtags(languageCode: 'fr'),
|
|
Locale.fromSubtags(languageCode: 'de', countryCode: 'SW'),
|
|
Locale.fromSubtags(languageCode: 'it'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('de'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('WidgetsApp EdgeCase Chinese', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'de'),
|
|
Locale.fromSubtags(languageCode: 'fr'),
|
|
Locale.fromSubtags(languageCode: 'de', countryCode: 'SW'),
|
|
Locale.fromSubtags(languageCode: 'zh'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh'), findsOneWidget);
|
|
|
|
// This behavior is up to the implementer to decide if a perfect scriptCode match
|
|
// is better than a countryCode match.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
|
|
// languageCode only match is not enough to prevent resolving a perfect match
|
|
// further down the preferredLocales list.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'JP'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
// When no language match, we try for country only, since it is likely users are
|
|
// at least familiar with their country's language. This is a possible case only
|
|
// on iOS, where countryCode can be selected independently from language and script.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', scriptCode: 'Hans', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
});
|
|
|
|
// Same as 'WidgetsApp EdgeCase Chinese' test except the supportedLocales order is
|
|
// reversed.
|
|
testWidgets('WidgetsApp EdgeCase ReverseChinese', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'de'),
|
|
Locale.fromSubtags(languageCode: 'fr'),
|
|
Locale.fromSubtags(languageCode: 'de', countryCode: 'SW'),
|
|
Locale.fromSubtags(languageCode: 'zh'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
// This behavior is up to the implementer to decide if a perfect scriptCode match
|
|
// is better than a countryCode match.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
|
|
// languageCode only match is not enough to prevent resolving a perfect match
|
|
// further down the preferredLocales list.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'JP'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'zh', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),
|
|
Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hans_CN'), findsOneWidget);
|
|
|
|
// When no language match, we try for country only, since it is likely users are
|
|
// at least familiar with their country's language. This is a possible case only
|
|
// on iOS, where countryCode can be selected independently from language and script.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', scriptCode: 'Hans', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'TW'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_TW'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'HK'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('zh_Hant_HK'), findsOneWidget);
|
|
});
|
|
|
|
// Examples from https://developer.android.com/guide/topics/resources/multilingual-support
|
|
testWidgets('WidgetsApp Android', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('en'),
|
|
Locale('de', 'DE'),
|
|
Locale('es', 'ES'),
|
|
Locale('fr', 'FR'),
|
|
Locale('it', 'IT'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'fr', countryCode: 'CH'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('fr_FR'), findsOneWidget);
|
|
});
|
|
|
|
// Examples from https://developer.android.com/guide/topics/resources/multilingual-support
|
|
testWidgets('WidgetsApp Android', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('en'),
|
|
Locale('de', 'DE'),
|
|
Locale('es', 'ES'),
|
|
Locale('it', 'IT'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'fr', countryCode: 'CH'),
|
|
Locale.fromSubtags(languageCode: 'it', countryCode: 'CH'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('it_IT'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('WidgetsApp Country-only fallback', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('en', 'US'),
|
|
Locale('de', 'DE'),
|
|
Locale('de', 'AU'),
|
|
Locale('de', 'LU'),
|
|
Locale('de', 'CH'),
|
|
Locale('es', 'ES'),
|
|
Locale('es', 'US'),
|
|
Locale('it', 'IT'),
|
|
Locale('zh', 'CN'),
|
|
Locale('zh', 'TW'),
|
|
Locale('fr', 'FR'),
|
|
Locale('br', 'FR'),
|
|
Locale('pt', 'BR'),
|
|
Locale('pt', 'PT'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'CH'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('de_CH'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'FR'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('fr_FR'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'es', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('es_US'), findsOneWidget);
|
|
|
|
// Strongly prefer matching first locale even if next one is perfect.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'pt'),
|
|
Locale.fromSubtags(languageCode: 'pt', countryCode: 'PT'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('pt_PT'), findsOneWidget);
|
|
|
|
// Don't country match with any other available match. This behavior is
|
|
// up for reconsideration.
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'BR'),
|
|
Locale.fromSubtags(languageCode: 'pt'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('pt_BR'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'BR'),
|
|
Locale.fromSubtags(languageCode: 'pt', countryCode: 'PT'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('pt_PT'), findsOneWidget);
|
|
});
|
|
|
|
// Simulates a Chinese-default app that supports english in Canada but not
|
|
// French. French-Canadian users should get 'en_CA' instead of Chinese.
|
|
testWidgets('WidgetsApp Multilingual country', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'CA'),
|
|
Locale('en', 'US'),
|
|
Locale('en', 'AU'),
|
|
Locale('de', 'DE'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'fr', countryCode: 'CA'),
|
|
Locale.fromSubtags(languageCode: 'fr'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA'), findsOneWidget);
|
|
});
|
|
|
|
|
|
testWidgets('WidgetsApp Common cases', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
// Decently well localized app.
|
|
supportedLocales: const <Locale>[
|
|
Locale('en', 'US'),
|
|
Locale('en', 'GB'),
|
|
Locale('en', 'AU'),
|
|
Locale('en', 'CA'),
|
|
Locale('zh', 'CN'),
|
|
Locale('zh', 'TW'),
|
|
Locale('de', 'DE'),
|
|
Locale('de', 'CH'),
|
|
Locale('es', 'MX'),
|
|
Locale('es', 'ES'),
|
|
Locale('es', 'AR'),
|
|
Locale('es', 'CO'),
|
|
Locale('ru', 'RU'),
|
|
Locale('fr', 'FR'),
|
|
Locale('fr', 'CA'),
|
|
Locale('ar', 'SA'),
|
|
Locale('ar', 'EG'),
|
|
Locale('ar', 'IQ'),
|
|
Locale('ar', 'MA'),
|
|
Locale('af'),
|
|
Locale('bg'),
|
|
Locale('nl', 'NL'),
|
|
Locale('pl'),
|
|
Locale('cs'),
|
|
Locale('fa'),
|
|
Locale('el'),
|
|
Locale('he'),
|
|
Locale('hi'),
|
|
Locale('pa'),
|
|
Locale('ta'),
|
|
Locale('id'),
|
|
Locale('it', 'IT'),
|
|
Locale('ja'),
|
|
Locale('ko'),
|
|
Locale('ms'),
|
|
Locale('mn'),
|
|
Locale('pt', 'BR'),
|
|
Locale('pt', 'PT'),
|
|
Locale('sv', 'SE'),
|
|
Locale('th'),
|
|
Locale('tr'),
|
|
Locale('vi'),
|
|
],
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'CA'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'AU'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_AU'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'CH'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_SA'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_SA'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ar', countryCode: 'IQ'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('ar_IQ'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'es', countryCode: 'ES'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('es_ES'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'es'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('es_MX'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'pa', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('pa'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'hi', countryCode: 'IN'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('hi'), findsOneWidget);
|
|
|
|
// Multiple preferred locales:
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'NZ'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'AU'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'GB'),
|
|
Locale.fromSubtags(languageCode: 'en'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_AU'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'ab'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'NZ'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'AU'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'GB'),
|
|
Locale.fromSubtags(languageCode: 'en'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_AU'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'NZ'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'PH'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'ZA'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'CB'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'CA'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'AU'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'GB'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'da'),
|
|
Locale.fromSubtags(languageCode: 'en'),
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'CA'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'da'),
|
|
Locale.fromSubtags(languageCode: 'fo'),
|
|
Locale.fromSubtags(languageCode: 'hr'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'da'),
|
|
Locale.fromSubtags(languageCode: 'fo'),
|
|
Locale.fromSubtags(languageCode: 'hr', countryCode: 'CA'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_CA'), findsOneWidget);
|
|
});
|
|
|
|
testWidgets('WidgetsApp invalid preferredLocales', (WidgetTester tester) async {
|
|
await tester.pumpWidget(
|
|
buildFrame(
|
|
supportedLocales: const <Locale>[
|
|
Locale('zh', 'CN'),
|
|
Locale('en', 'CA'),
|
|
Locale('en', 'US'),
|
|
Locale('en', 'AU'),
|
|
Locale('de', 'DE'),
|
|
],
|
|
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) {
|
|
if (locale == null) {
|
|
return const Locale('und', 'US');
|
|
}
|
|
return const Locale('en', 'US');
|
|
},
|
|
buildContent: (BuildContext context) {
|
|
final Locale locale = Localizations.localeOf(context);
|
|
return Text('$locale');
|
|
},
|
|
)
|
|
);
|
|
|
|
await tester.binding.setLocales(const <Locale>[
|
|
Locale.fromSubtags(languageCode: 'en', countryCode: 'US'),]
|
|
);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('en_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[]);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('und_US'), findsOneWidget);
|
|
});
|
|
}
|