Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
9fb6fd81
Commit
9fb6fd81
authored
Sep 15, 2017
by
Hans Muller
Committed by
GitHub
Sep 15, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Localizations overrides (#12094)
parent
dc472386
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
424 additions
and
55 deletions
+424
-55
gen_localizations.dart
dev/tools/gen_localizations.dart
+2
-6
app.dart
packages/flutter/lib/src/material/app.dart
+60
-2
localizations.dart
packages/flutter/lib/src/material/i18n/localizations.dart
+23
-24
material_zh.arb
packages/flutter/lib/src/material/i18n/material_zh.arb
+0
-1
material_localizations.dart
...ages/flutter/lib/src/material/material_localizations.dart
+5
-9
app.dart
packages/flutter/lib/src/widgets/app.dart
+5
-2
localizations.dart
packages/flutter/lib/src/widgets/localizations.dart
+71
-3
localizations_test.dart
packages/flutter/test/material/localizations_test.dart
+119
-0
localizations_test.dart
packages/flutter/test/widgets/localizations_test.dart
+139
-8
No files found.
dev/tools/gen_localizations.dart
View file @
9fb6fd81
...
...
@@ -75,19 +75,15 @@ String generateLocalizationsMap() {
/// This variable is used by [MaterialLocalizations].
const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {'''
);
final
String
lastLocale
=
localeToResources
.
keys
.
last
;
for
(
String
locale
in
localeToResources
.
keys
.
toList
()..
sort
())
{
output
.
writeln
(
' "
$locale
": const <String, String>{'
);
final
Map
<
String
,
String
>
resources
=
localeToResources
[
locale
];
final
String
lastName
=
resources
.
keys
.
last
;
for
(
String
name
in
resources
.
keys
)
{
final
String
comma
=
name
==
lastName
?
""
:
","
;
final
String
value
=
generateString
(
resources
[
name
]);
output
.
writeln
(
' "
$name
":
$value
$comma
'
);
output
.
writeln
(
' "
$name
":
$value
,
'
);
}
final
String
comma
=
locale
==
lastLocale
?
""
:
","
;
output
.
writeln
(
' }
$comma
'
);
output
.
writeln
(
' },'
);
}
output
.
writeln
(
'};'
);
...
...
packages/flutter/lib/src/material/app.dart
View file @
9fb6fd81
...
...
@@ -234,6 +234,61 @@ class MaterialApp extends StatefulWidget {
///
/// The delegates collectively define all of the localized resources
/// for this application's [Localizations] widget.
///
/// Delegates that produce [WidgetsLocalizations] and [MaterialLocalizations]
/// are included automatically. Apps can provide their own versions of these
/// localizations by creating implementations of
/// [LocalizationsDelegate<WidgetLocalizations>] or
/// [LocalizationsDelegate<MaterialLocalizations>] whose load methods return
/// custom versions of [WidgetLocalizations] or [MaterialLocalizations].
///
/// For example: to add support to [MaterialLocalizations] for a
/// locale it doesn't already support, say `const Locale('foo', 'BR')`,
/// one could just extend [DefaultMaterialLocalizations]:
///
/// ```dart
/// class FooLocalizations extends DefaultMaterialLocalizations {
/// FooLocalizations(Locale locale) : super(locale);
/// @override
/// String get okButtonLabel {
/// if (locale == const Locale('foo', 'BR'))
/// return 'foo';
/// return super.okButtonLabel;
/// }
/// }
///
/// ```
///
/// A `FooLocalizationsDelegate` is essentially just a method that constructs
/// a `FooLocalizations` object. We return a [SynchronousFuture] here because
/// no asynchronous work takes place upon "loading" the localizations object.
///
/// ```dart
/// class FooLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
/// const FooLocalizationsDelegate();
/// @override
/// Future<FooLocalizations> load(Locale locale) {
/// return new SynchronousFuture(new FooLocalizations(locale));
/// }
/// @override
/// bool shouldReload(FooLocalizationsDelegate old) => false;
/// }
/// ```
///
/// Constructing a [MaterialApp] with a `FooLocalizationsDelegate` overrides
/// the automatically included delegate for [MaterialLocalizations] because
/// only the first delegate of each [LocalizationsDelegate.type] is used and
/// the automatically included delegates are added to the end of the app's
/// [localizationsDelegates] list.
///
/// ```dart
/// new MaterialApp(
/// localizationsDelegates: [
/// const FooLocalizationsDelegate(),
/// ],
/// // ...
/// )
/// ```
final
Iterable
<
LocalizationsDelegate
<
dynamic
>>
localizationsDelegates
;
/// This callback is responsible for choosing the app's locale
...
...
@@ -379,11 +434,14 @@ class _MaterialAppState extends State<MaterialApp> {
}
// Combine the Localizations for Material with the ones contributed
// by the localizationsDelegates parameter, if any.
// by the localizationsDelegates parameter, if any. Only the first delegate
// of a particular LocalizationsDelegate.type is loaded so the
// localizationsDelegate parameter can be used to override
// _MaterialLocalizationsDelegate.
Iterable
<
LocalizationsDelegate
<
dynamic
>>
get
_localizationsDelegates
sync
*
{
yield
const
_MaterialLocalizationsDelegate
();
// TODO(ianh): make this configurable
if
(
widget
.
localizationsDelegates
!=
null
)
yield
*
widget
.
localizationsDelegates
;
yield
const
_MaterialLocalizationsDelegate
();
}
RectTween
_createRectTween
(
Rect
begin
,
Rect
end
)
{
...
...
packages/flutter/lib/src/material/i18n/localizations.dart
View file @
9fb6fd81
...
...
@@ -4,7 +4,7 @@
// This file has been automatically generated. Please do not edit it manually.
// To regenerate the file, use:
// dart dev/tools/gen_localizations.dart lib/src/material/i18n material
// dart dev/tools/gen_localizations.dart
packages/flutter/
lib/src/material/i18n material
/// Maps from [Locale.languageCode] to a map that contains the localized strings
/// for that locale.
...
...
@@ -36,7 +36,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"selectAllButtonLabel"
:
r"اختر الكل"
,
"viewLicensesButtonLabel"
:
r"عرض التراخيص"
,
"anteMeridiemAbbreviation"
:
r"ص"
,
"postMeridiemAbbreviation"
:
r"م"
"postMeridiemAbbreviation"
:
r"م"
,
},
"de"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -63,7 +63,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"EINFÜGEN"
,
"selectAllButtonLabel"
:
r"ALLES AUSWÄHLEN"
,
"viewLicensesButtonLabel"
:
r"LIZENZEN ANZEIGEN"
"viewLicensesButtonLabel"
:
r"LIZENZEN ANZEIGEN"
,
},
"en"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"h:mm a"
,
...
...
@@ -92,16 +92,16 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"selectAllButtonLabel"
:
r"SELECT ALL"
,
"viewLicensesButtonLabel"
:
r"VIEW LICENSES"
,
"anteMeridiemAbbreviation"
:
r"AM"
,
"postMeridiemAbbreviation"
:
r"PM"
"postMeridiemAbbreviation"
:
r"PM"
,
},
"en_GB"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
"timeOfDayFormat"
:
r"HH:mm"
,
},
"en_IE"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
"timeOfDayFormat"
:
r"HH:mm"
,
},
"en_ZA"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
"timeOfDayFormat"
:
r"HH:mm"
,
},
"es"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"H:mm"
,
...
...
@@ -128,10 +128,10 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"PEGAR"
,
"selectAllButtonLabel"
:
r"SELECCIONAR TODO"
,
"viewLicensesButtonLabel"
:
r"VER LICENCIAS"
"viewLicensesButtonLabel"
:
r"VER LICENCIAS"
,
},
"es_US"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"h:mm a"
"timeOfDayFormat"
:
r"h:mm a"
,
},
"fa"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"H:mm"
,
...
...
@@ -156,7 +156,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"تایید"
,
"pasteButtonLabel"
:
r"چسباندن"
,
"selectAllButtonLabel"
:
r"انتخاب همه"
,
"viewLicensesButtonLabel"
:
r"مشاهده مجوز"
"viewLicensesButtonLabel"
:
r"مشاهده مجوز"
,
},
"fr"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -183,10 +183,10 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"COLLER"
,
"selectAllButtonLabel"
:
r"TOUT SÉLECTIONNER"
,
"viewLicensesButtonLabel"
:
r"AFFICHER LES LICENCES"
"viewLicensesButtonLabel"
:
r"AFFICHER LES LICENCES"
,
},
"fr_CA"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH 'h' mm"
"timeOfDayFormat"
:
r"HH 'h' mm"
,
},
"he"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"H:mm"
,
...
...
@@ -211,7 +211,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"בסדר"
,
"pasteButtonLabel"
:
r"הדבק"
,
"selectAllButtonLabel"
:
r"בחר הכל"
,
"viewLicensesButtonLabel"
:
r"ראה רישיונות"
"viewLicensesButtonLabel"
:
r"ראה רישיונות"
,
},
"it"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -236,7 +236,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"INCOLLA"
,
"selectAllButtonLabel"
:
r"SELEZIONA TUTTO"
,
"viewLicensesButtonLabel"
:
r"VEDI LE LICENZE"
"viewLicensesButtonLabel"
:
r"VEDI LE LICENZE"
,
},
"ja"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"H:mm"
,
...
...
@@ -261,7 +261,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"貼付け"
,
"selectAllButtonLabel"
:
r"全選択"
,
"viewLicensesButtonLabel"
:
r"ライセンス表記"
"viewLicensesButtonLabel"
:
r"ライセンス表記"
,
},
"ps"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -286,7 +286,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"سمه ده"
,
"pasteButtonLabel"
:
r"پیټ کړئ"
,
"selectAllButtonLabel"
:
r"غوره کړئ"
,
"viewLicensesButtonLabel"
:
r"لیدلس وګورئ"
"viewLicensesButtonLabel"
:
r"لیدلس وګورئ"
,
},
"pt"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -311,7 +311,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"OK"
,
"pasteButtonLabel"
:
r"COLAR"
,
"selectAllButtonLabel"
:
r"SELECIONAR TUDO"
,
"viewLicensesButtonLabel"
:
r"VER LICENÇAS"
"viewLicensesButtonLabel"
:
r"VER LICENÇAS"
,
},
"ru"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"H:mm"
,
...
...
@@ -336,7 +336,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"ОК"
,
"pasteButtonLabel"
:
r"Паст"
,
"selectAllButtonLabel"
:
r"Выбрать все"
,
"viewLicensesButtonLabel"
:
r"ПРОСМОТРЕТЬ ЛИЦЕНЗИИ"
"viewLicensesButtonLabel"
:
r"ПРОСМОТРЕТЬ ЛИЦЕНЗИИ"
,
},
"sd"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"HH:mm"
,
...
...
@@ -361,7 +361,7 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"okButtonLabel"
:
r"ٺيڪ آهي"
,
"pasteButtonLabel"
:
r"پيسٽ ڪريو"
,
"selectAllButtonLabel"
:
r"سڀ چونڊيو"
,
"viewLicensesButtonLabel"
:
r"لائسنس ڏسو"
"viewLicensesButtonLabel"
:
r"لائسنس ڏسو"
,
},
"ur"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"h:mm a"
,
...
...
@@ -388,12 +388,12 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"selectAllButtonLabel"
:
r"تکاپیمام منتخب کریں"
,
"viewLicensesButtonLabel"
:
r"لائسنس دیکھیں"
,
"anteMeridiemAbbreviation"
:
r"AM"
,
"postMeridiemAbbreviation"
:
r"PM"
"postMeridiemAbbreviation"
:
r"PM"
,
},
"zh"
:
const
<
String
,
String
>{
"timeOfDayFormat"
:
r"ah:mm"
,
"openAppDrawerTooltip"
:
r"打开导航菜单"
,
"backButtonTooltip"
:
r"
背部
"
,
"backButtonTooltip"
:
r"
返回
"
,
"closeButtonTooltip"
:
r"关"
,
"nextMonthTooltip"
:
r"-下月就29了。"
,
"previousMonthTooltip"
:
r"前一个月"
,
...
...
@@ -415,7 +415,6 @@ const Map<String, Map<String, String>> localizations = const <String, Map<String
"selectAllButtonLabel"
:
r"全选"
,
"viewLicensesButtonLabel"
:
r"查看许可证"
,
"anteMeridiemAbbreviation"
:
r"上午"
,
"postMeridiemAbbreviation"
:
r"下午"
}
"postMeridiemAbbreviation"
:
r"下午"
,
}
,
};
packages/flutter/lib/src/material/i18n/material_zh.arb
View file @
9fb6fd81
...
...
@@ -22,7 +22,6 @@
"pasteButtonLabel"
:
"粘贴"
,
"selectAllButtonLabel"
:
"全选"
,
"viewLicensesButtonLabel"
:
"查看许可证"
,
"backButtonTooltip"
:
"背部"
,
"closeButtonTooltip"
:
"关"
,
"nextMonthTooltip"
:
"-下月就29了。"
,
"previousMonthTooltip"
:
"前一个月"
,
...
...
packages/flutter/lib/src/material/material_localizations.dart
View file @
9fb6fd81
...
...
@@ -116,24 +116,20 @@ class DefaultMaterialLocalizations implements MaterialLocalizations {
///
/// [LocalizationsDelegate] implementations typically call the static [load]
/// function, rather than constructing this class directly.
factory
DefaultMaterialLocalizations
(
Locale
locale
)
{
DefaultMaterialLocalizations
(
this
.
locale
)
{
assert
(
locale
!=
null
);
final
Map
<
String
,
String
>
result
=
<
String
,
String
>{};
if
(
localizations
.
containsKey
(
locale
.
languageCode
))
result
.
addAll
(
localizations
[
locale
.
languageCode
]);
if
(
localizations
.
containsKey
(
locale
.
toString
()))
result
.
addAll
(
localizations
[
locale
.
toString
()]);
return
new
DefaultMaterialLocalizations
.
_
(
locale
,
result
);
_nameToValue
.
addAll
(
localizations
[
locale
.
languageCode
]);
if
(
localizations
.
containsKey
(
_localeName
))
_nameToValue
.
addAll
(
localizations
[
_localeName
]);
}
DefaultMaterialLocalizations
.
_
(
this
.
locale
,
this
.
_nameToValue
);
/// The locale for which the values of this class's localized resources
/// have been translated.
final
Locale
locale
;
final
Map
<
String
,
String
>
_nameToValue
;
final
Map
<
String
,
String
>
_nameToValue
=
<
String
,
String
>{}
;
String
get
_localeName
{
final
String
localeName
=
locale
.
countryCode
.
isEmpty
?
locale
.
languageCode
:
locale
.
toString
();
...
...
packages/flutter/lib/src/widgets/app.dart
View file @
9fb6fd81
...
...
@@ -383,11 +383,14 @@ class _WidgetsAppState extends State<WidgetsApp> implements WidgetsBindingObserv
}
// Combine the Localizations for Widgets with the ones contributed
// by the localizationsDelegates parameter, if any.
// by the localizationsDelegates parameter, if any. Only the first delegate
// of a particular LocalizationsDelegate.type is loaded so the
// localizationsDelegate parameter can be used to override
// _WidgetsLocalizationsDelegate.
Iterable
<
LocalizationsDelegate
<
dynamic
>>
get
_localizationsDelegates
sync
*
{
yield
const
_WidgetsLocalizationsDelegate
();
// TODO(ianh): make this configurable
if
(
widget
.
localizationsDelegates
!=
null
)
yield
*
widget
.
localizationsDelegates
;
yield
const
_WidgetsLocalizationsDelegate
();
}
@override
...
...
packages/flutter/lib/src/widgets/localizations.dart
View file @
9fb6fd81
...
...
@@ -38,10 +38,20 @@ class _Pending {
// This is more complicated than just applying Future.wait to input
// because some of the input.values may be SynchronousFutures. We don't want
// to Future.wait for the synchronous futures.
Future
<
Map
<
Type
,
dynamic
>>
_loadAll
(
Locale
locale
,
Iterable
<
LocalizationsDelegate
<
dynamic
>>
d
elegates
)
{
Future
<
Map
<
Type
,
dynamic
>>
_loadAll
(
Locale
locale
,
Iterable
<
LocalizationsDelegate
<
dynamic
>>
allD
elegates
)
{
final
Map
<
Type
,
dynamic
>
output
=
<
Type
,
dynamic
>{};
List
<
_Pending
>
pendingList
;
// Only load the first delegate for each delgate type.
final
Set
<
Type
>
types
=
new
Set
<
Type
>();
final
List
<
LocalizationsDelegate
<
dynamic
>>
delegates
=
<
LocalizationsDelegate
<
dynamic
>>[];
for
(
LocalizationsDelegate
<
dynamic
>
delegate
in
allDelegates
)
{
if
(!
types
.
contains
(
delegate
.
type
))
{
types
.
add
(
delegate
.
type
);
delegates
.
add
(
delegate
);
}
}
for
(
LocalizationsDelegate
<
dynamic
>
delegate
in
delegates
)
{
final
Future
<
dynamic
>
inputValue
=
delegate
.
load
(
locale
);
dynamic
completedValue
;
...
...
@@ -227,6 +237,9 @@ class _LocalizationsScope extends InheritedWidget {
/// class _MyDelegate extends LocalizationsDelegate<MyLocalizations> {
/// @override
/// Future<MyLocalizations> load(Locale locale) => MyLocalizations.load(locale);
///
/// @override
/// bool shouldReload(MyLocalizationsDelegate old) => false;
///}
/// ```
///
...
...
@@ -298,8 +311,7 @@ class _LocalizationsScope extends InheritedWidget {
/// One could choose another approach for loading localized resources and looking them up while
/// still conforming to the structure of this example.
class
Localizations
extends
StatefulWidget
{
/// Create a widget from which ambient localizations (translated strings)
/// can be obtained.
/// Create a widget from which localizations (like translated strings) can be obtained.
Localizations
({
Key
key
,
@required
this
.
locale
,
...
...
@@ -311,6 +323,51 @@ class Localizations extends StatefulWidget {
assert
(
delegates
.
any
((
LocalizationsDelegate
<
dynamic
>
delegate
)
=>
delegate
is
LocalizationsDelegate
<
WidgetsLocalizations
>));
}
/// Overrides the inherited [Locale] or [LocalizationsDelegate]s for `child`.
///
/// This factory constructor is used for the (usually rare) situtation where part
/// of an app should be localized for a different locale than the one defined
/// for the device, or if its localizations should come from a different list
/// of [LocalizationsDelegate]s than the list defined by
/// [WidgetsApp.localizationsDelegates].
///
/// For example you could specify that `myWidget` was only to be localized for
/// the US English locale:
///
/// ```dart
/// Widget build(BuildContext context) {
/// return new Localizations.override(
/// context: context,
/// locale: const Locale('en', 'US'),
/// child: myWidget,
/// );
/// }
/// ```
///
/// The `locale` and `delegates` parameters default to the [Localizations.locale]
/// and [Localizations.delegates] values from the nearest [Localizations] ancestor.
///
/// To override the [Localizations.locale] or [Localizations.delegates] for an
/// entire app, specify [WidgetsApp.locale] or [WidgetsApp.localizationsDelegates]
/// (or specify the same parameters for [MaterialApp]).
factory
Localizations
.
override
({
Key
key
,
@required
BuildContext
context
,
Locale
locale
,
List
<
LocalizationsDelegate
<
dynamic
>>
delegates
,
Widget
child
,
})
{
final
List
<
LocalizationsDelegate
<
dynamic
>>
mergedDelegates
=
Localizations
.
_delegatesOf
(
context
);
if
(
delegates
!=
null
)
mergedDelegates
.
insertAll
(
0
,
delegates
);
return
new
Localizations
(
key:
key
,
locale:
locale
??
Localizations
.
localeOf
(
context
),
delegates:
mergedDelegates
,
child:
child
,
);
}
/// The resources returned by [Localizations.of] will be specific to this locale.
final
Locale
locale
;
...
...
@@ -326,9 +383,19 @@ class Localizations extends StatefulWidget {
static
Locale
localeOf
(
BuildContext
context
)
{
assert
(
context
!=
null
);
final
_LocalizationsScope
scope
=
context
.
inheritFromWidgetOfExactType
(
_LocalizationsScope
);
assert
(
scope
!=
null
,
'a Localizations ancestor was not found'
);
return
scope
.
localizationsState
.
locale
;
}
// There doesn't appear to be a need to make this public. See the
// Localizations.override factory constructor.
static
List
<
LocalizationsDelegate
<
dynamic
>>
_delegatesOf
(
BuildContext
context
)
{
assert
(
context
!=
null
);
final
_LocalizationsScope
scope
=
context
.
inheritFromWidgetOfExactType
(
_LocalizationsScope
);
assert
(
scope
!=
null
,
'a Localizations ancestor was not found'
);
return
new
List
<
LocalizationsDelegate
<
dynamic
>>.
from
(
scope
.
localizationsState
.
widget
.
delegates
);
}
/// Returns the 'type' localized resources for the widget tree that
/// corresponds to [BuildContext] `context`.
///
...
...
@@ -345,6 +412,7 @@ class Localizations extends StatefulWidget {
assert
(
context
!=
null
);
assert
(
type
!=
null
);
final
_LocalizationsScope
scope
=
context
.
inheritFromWidgetOfExactType
(
_LocalizationsScope
);
assert
(
scope
!=
null
,
'a Localizations ancestor was not found'
);
return
scope
.
localizationsState
.
resourcesFor
<
T
>(
type
);
}
...
...
packages/flutter/test/material/localizations_test.dart
View file @
9fb6fd81
...
...
@@ -3,11 +3,33 @@
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
class
FooMaterialLocalizations
extends
DefaultMaterialLocalizations
{
FooMaterialLocalizations
(
Locale
locale
)
:
super
(
locale
);
@override
String
get
backButtonTooltip
=>
'foo'
;
}
class
FooMaterialLocalizationsDelegate
extends
LocalizationsDelegate
<
MaterialLocalizations
>
{
const
FooMaterialLocalizationsDelegate
();
@override
Future
<
FooMaterialLocalizations
>
load
(
Locale
locale
)
{
return
new
SynchronousFuture
<
FooMaterialLocalizations
>(
new
FooMaterialLocalizations
(
locale
));
}
@override
bool
shouldReload
(
FooMaterialLocalizationsDelegate
old
)
=>
false
;
}
Widget
buildFrame
(
{
Locale
locale
,
Iterable
<
LocalizationsDelegate
<
dynamic
>>
delegates
,
WidgetBuilder
buildContent
,
LocaleResolutionCallback
localeResolutionCallback
,
Iterable
<
Locale
>
supportedLocales:
const
<
Locale
>[
const
Locale
(
'en'
,
'US'
),
const
Locale
(
'es'
,
'es'
),
...
...
@@ -16,6 +38,8 @@ Widget buildFrame({
return
new
MaterialApp
(
color:
const
Color
(
0xFFFFFFFF
),
locale:
locale
,
localizationsDelegates:
delegates
,
localeResolutionCallback:
localeResolutionCallback
,
supportedLocales:
supportedLocales
,
onGenerateRoute:
(
RouteSettings
settings
)
{
return
new
MaterialPageRoute
<
Null
>(
...
...
@@ -133,6 +157,101 @@ void main() {
expect
(
localizations
.
selectedRowCountTitle
(
123456789
),
'123.456.789 artículos seleccionados'
);
});
testWidgets
(
'Localizations.override widget tracks parent
\'
s locale'
,
(
WidgetTester
tester
)
async
{
Widget
buildLocaleFrame
(
Locale
locale
)
{
return
buildFrame
(
locale:
locale
,
buildContent:
(
BuildContext
context
)
{
return
new
Localizations
.
override
(
context:
context
,
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
// No MaterialLocalizations are defined for the first Localizations
// ancestor, so we should get the values from the default one, i.e.
// the one created by WidgetsApp via the LocalizationsDelegate
// provided by MaterialApp.
return
new
Text
(
MaterialLocalizations
.
of
(
context
).
backButtonTooltip
);
},
),
);
}
);
}
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'en'
,
'US'
)));
expect
(
find
.
text
(
'Back'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'de'
,
'DE'
)));
expect
(
find
.
text
(
'Zurück'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'zh'
,
'CN'
)));
expect
(
find
.
text
(
'返回'
),
findsOneWidget
);
});
testWidgets
(
'Localizations.override widget with hardwired locale'
,
(
WidgetTester
tester
)
async
{
Widget
buildLocaleFrame
(
Locale
locale
)
{
return
buildFrame
(
locale:
locale
,
buildContent:
(
BuildContext
context
)
{
return
new
Localizations
.
override
(
context:
context
,
locale:
const
Locale
(
'en'
,
'US'
),
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
// No MaterialLocalizations are defined for the Localizations.override
// ancestor, so we should get all values from the default one, i.e.
// the one created by WidgetsApp via the LocalizationsDelegate
// provided by MaterialApp.
return
new
Text
(
MaterialLocalizations
.
of
(
context
).
backButtonTooltip
);
},
),
);
}
);
}
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'en'
,
'US'
)));
expect
(
find
.
text
(
'Back'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'de'
,
'DE'
)));
expect
(
find
.
text
(
'Back'
),
findsOneWidget
);
await
tester
.
pumpWidget
(
buildLocaleFrame
(
const
Locale
(
'zh'
,
'CN'
)));
expect
(
find
.
text
(
'Back'
),
findsOneWidget
);
});
testWidgets
(
'MaterialApp overrides MaterialLocalizations'
,
(
WidgetTester
tester
)
async
{
final
Key
textKey
=
new
UniqueKey
();
await
tester
.
pumpWidget
(
buildFrame
(
// Accept whatever locale we're given
localeResolutionCallback:
(
Locale
locale
,
Iterable
<
Locale
>
supportedLocales
)
=>
locale
,
delegates:
<
FooMaterialLocalizationsDelegate
>[
const
FooMaterialLocalizationsDelegate
(),
],
buildContent:
(
BuildContext
context
)
{
// Should always be 'foo', no matter what the locale is
return
new
Text
(
MaterialLocalizations
.
of
(
context
).
backButtonTooltip
,
key:
textKey
,
);
}
)
);
expect
(
tester
.
widget
<
Text
>(
find
.
byKey
(
textKey
)).
data
,
'foo'
);
await
tester
.
binding
.
setLocale
(
'zh'
,
'CN'
);
await
tester
.
pump
();
expect
(
find
.
text
(
'foo'
),
findsOneWidget
);
await
tester
.
binding
.
setLocale
(
'de'
,
'DE'
);
await
tester
.
pump
();
expect
(
find
.
text
(
'foo'
),
findsOneWidget
);
});
testWidgets
(
'deprecated Android/Java locales are modernized'
,
(
WidgetTester
tester
)
async
{
final
Key
textKey
=
new
UniqueKey
();
...
...
packages/flutter/test/widgets/localizations_test.dart
View file @
9fb6fd81
...
...
@@ -103,6 +103,36 @@ class AsyncMoreLocalizationsDelegate extends LocalizationsDelegate<MoreLocalizat
bool
shouldReload
(
AsyncMoreLocalizationsDelegate
old
)
=>
false
;
}
// Same as _WidgetsLocalizationsDelegate in widgets/app.dart
class
DefaultWidgetsLocalizationsDelegate
extends
LocalizationsDelegate
<
WidgetsLocalizations
>
{
const
DefaultWidgetsLocalizationsDelegate
();
@override
Future
<
WidgetsLocalizations
>
load
(
Locale
locale
)
=>
DefaultWidgetsLocalizations
.
load
(
locale
);
@override
bool
shouldReload
(
DefaultWidgetsLocalizationsDelegate
old
)
=>
false
;
}
class
OnlyRTLDefaultWidgetsLocalizations
extends
DefaultWidgetsLocalizations
{
OnlyRTLDefaultWidgetsLocalizations
(
Locale
locale
)
:
super
(
locale
);
@override
TextDirection
get
textDirection
=>
TextDirection
.
rtl
;
}
class
OnlyRTLDefaultWidgetsLocalizationsDelegate
extends
LocalizationsDelegate
<
WidgetsLocalizations
>
{
const
OnlyRTLDefaultWidgetsLocalizationsDelegate
();
@override
Future
<
WidgetsLocalizations
>
load
(
Locale
locale
)
{
return
new
SynchronousFuture
<
WidgetsLocalizations
>(
new
OnlyRTLDefaultWidgetsLocalizations
(
locale
));
}
@override
bool
shouldReload
(
OnlyRTLDefaultWidgetsLocalizationsDelegate
old
)
=>
false
;
}
Widget
buildFrame
(
{
Locale
locale
,
Iterable
<
LocalizationsDelegate
<
dynamic
>>
delegates
,
...
...
@@ -504,15 +534,116 @@ void main() {
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'zh_CN'
),
findsOneWidget
);
});
}
// Same as _WidgetsLocalizationsDelegate in widgets/app.dart
class
DefaultWidgetsLocalizationsDelegate
extends
LocalizationsDelegate
<
WidgetsLocalizations
>
{
const
DefaultWidgetsLocalizationsDelegate
();
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
,
buildContent:
(
BuildContext
context
)
{
return
new
Localizations
.
override
(
context:
context
,
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
final
Locale
locale
=
Localizations
.
localeOf
(
context
);
final
TextDirection
direction
=
WidgetsLocalizations
.
of
(
context
).
textDirection
;
return
new
Text
(
'
$locale
$direction
'
);
},
),
);
}
)
);
@override
Future
<
WidgetsLocalizations
>
load
(
Locale
locale
)
=>
DefaultWidgetsLocalizations
.
load
(
locale
);
// Initial WidgetTester locale is new Locale('', '')
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'_ 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
new
Localizations
.
override
(
context:
context
,
delegates:
<
OnlyRTLDefaultWidgetsLocalizationsDelegate
>[
// Override: no matter what the locale, textDirection is always RTL.
const
OnlyRTLDefaultWidgetsLocalizationsDelegate
(),
],
child:
new
Builder
(
builder:
(
BuildContext
context
)
{
final
Locale
locale
=
Localizations
.
localeOf
(
context
);
final
TextDirection
direction
=
WidgetsLocalizations
.
of
(
context
).
textDirection
;
return
new
Text
(
'
$locale
$direction
'
);
},
),
);
}
)
);
// Initial WidgetTester locale is new Locale('', '')
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'_ 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
new
Text
(
'
$locale
$direction
'
);
}
)
);
// Initial WidgetTester locale is new Locale('', '')
await
tester
.
pumpAndSettle
();
expect
(
find
.
text
(
'_ 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
);
});
@override
bool
shouldReload
(
DefaultWidgetsLocalizationsDelegate
old
)
=>
false
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment