mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* Update project.pbxproj files to say Flutter rather than Chromium Also, the templates now have an empty organization so that we don't cause people to give their apps a Flutter copyright. * Update the copyright notice checker to require a standard notice on all files * Update copyrights on Dart files. (This was a mechanical commit.) * Fix weird license headers on Dart files that deviate from our conventions; relicense Shrine. Some were already marked "The Flutter Authors", not clear why. Their dates have been normalized. Some were missing the blank line after the license. Some were randomly different in trivial ways for no apparent reason (e.g. missing the trailing period). * Clean up the copyrights in non-Dart files. (Manual edits.) Also, make sure templates don't have copyrights. * Fix some more ORGANIZATIONNAMEs
1455 lines
50 KiB
Dart
1455 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 'dart:ui' as ui;
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_localizations/flutter_localizations.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))
|
|
.then((_) => 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() => '$runtimeType($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() => '$runtimeType($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))
|
|
.then((_) => 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,
|
|
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();
|
|
|
|
@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 {
|
|
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');
|
|
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 {
|
|
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 = ui.window.locales.first;
|
|
final Locale locale2 = ui.window.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(null);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('und_US'), findsOneWidget);
|
|
|
|
await tester.binding.setLocales(const <Locale>[]);
|
|
await tester.pumpAndSettle();
|
|
expect(find.text('und_US'), findsOneWidget);
|
|
});
|
|
}
|