mirror of
https://github.com/flutter/flutter
synced 2024-10-13 11:42:54 +00:00
Localizations for Material (#11832)
This commit is contained in:
parent
0323f2ddd2
commit
541afae45b
127
dev/tools/gen_localizations.dart
Normal file
127
dev/tools/gen_localizations.dart
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Given a directory that contains localized ".arb" (application resource
|
||||
// bundle) files, generates a Dart "localizations" Map definition that combines
|
||||
// the contents of the arb files. The map can be used to lookup a localized
|
||||
// string: localizations[localeString][resourceId].
|
||||
//
|
||||
// See *.arb and localizations.dart in packages/flutter/lib/src/material/i18n/.
|
||||
//
|
||||
// The arb (JSON) format files must contain a single map indexed by locale.
|
||||
// Each map value is itself a map with resource identifier keys and localized
|
||||
// resource string values.
|
||||
//
|
||||
// The arb filenames are assumed to end in "prefix_lc.arb" or "prefix_lc_cc.arb",
|
||||
// where prefix is the 2nd command line argument, lc is a language code and cc
|
||||
// is the country code. In most cases both codes are just two characters. A typical
|
||||
// filename would be "material_en.arb".
|
||||
//
|
||||
// This app is typically run by hand when a module's .arb files have been
|
||||
// updated.
|
||||
//
|
||||
// Usage: dart gen_localizations.dart directory prefix
|
||||
|
||||
import 'dart:convert' show JSON;
|
||||
import 'dart:io';
|
||||
|
||||
const String outputHeader = '''
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file has been automatically generated. Please do not edit it manually.
|
||||
// To regenerate the file, use:
|
||||
// @(regenerate)
|
||||
''';
|
||||
|
||||
final Map<String, Map<String, String>> localeToResources = <String, Map<String, String>>{};
|
||||
|
||||
// Return s as a Dart-parseable raw string in double quotes. Expand double quotes:
|
||||
// foo => r"foo"
|
||||
// foo "bar" => r"foo " '"' r"bar" '"'
|
||||
String generateString(String s) {
|
||||
if (!s.contains('"'))
|
||||
return 'r"$s"';
|
||||
|
||||
final StringBuffer output = new StringBuffer();
|
||||
bool started = false; // Have we started writing a raw string.
|
||||
for (int i = 0; i < s.length; i++) {
|
||||
if (s[i] == '"') {
|
||||
if (started)
|
||||
output.write('"');
|
||||
output.write(' \'"\' ');
|
||||
started = false;
|
||||
} else if (!started) {
|
||||
output.write('r"${s[i]}');
|
||||
started = true;
|
||||
} else {
|
||||
output.write(s[i]);
|
||||
}
|
||||
}
|
||||
if (started)
|
||||
output.write('"');
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
String generateLocalizationsMap() {
|
||||
final StringBuffer output = new StringBuffer();
|
||||
|
||||
output.writeln('const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {');
|
||||
|
||||
final String lastLocale = localeToResources.keys.last;
|
||||
for (String locale in localeToResources.keys) {
|
||||
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');
|
||||
}
|
||||
final String comma = locale == lastLocale ? "" : ",";
|
||||
output.writeln(' }$comma');
|
||||
}
|
||||
|
||||
output.writeln('};');
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
void processBundle(File file, String locale) {
|
||||
localeToResources[locale] ??= <String, String>{};
|
||||
final Map<String, String> resources = localeToResources[locale];
|
||||
final Map<String, dynamic> bundle = JSON.decode(file.readAsStringSync());
|
||||
for (String key in bundle.keys) {
|
||||
// The ARB file resource "attributes" for foo are called @foo.
|
||||
if (key.startsWith('@'))
|
||||
continue;
|
||||
resources[key] = bundle[key];
|
||||
}
|
||||
}
|
||||
|
||||
void main(List<String> args) {
|
||||
if (args.length != 2)
|
||||
stderr.writeln('Usage: dart gen_localizations.dart directory prefix');
|
||||
|
||||
// filenames are assumed to end in "prefix_lc.arb" or "prefix_lc_cc.arb", where prefix
|
||||
// is the 2nd command line argument, lc is a language code and cc is the country
|
||||
// code. In most cases both codes are just two characters.
|
||||
|
||||
final Directory directory = new Directory(args[0]);
|
||||
final String prefix = args[1];
|
||||
final RegExp filenameRE = new RegExp('${prefix}_(\\w+)\\.arb\$');
|
||||
|
||||
for (FileSystemEntity entity in directory.listSync()) {
|
||||
final String path = entity.path;
|
||||
if (FileSystemEntity.isFileSync(path) && filenameRE.hasMatch(path)) {
|
||||
final String locale = filenameRE.firstMatch(path)[1];
|
||||
processBundle(new File(path), locale);
|
||||
}
|
||||
}
|
||||
|
||||
final String regenerate = 'dart gen_localizations ${directory.path} ${args[1]}';
|
||||
print(outputHeader.replaceFirst('@(regenerate)', regenerate));
|
||||
print(generateLocalizationsMap());
|
||||
}
|
|
@ -26,19 +26,17 @@ const TextStyle _errorTextStyle = const TextStyle(
|
|||
decorationStyle: TextDecorationStyle.double
|
||||
);
|
||||
|
||||
// Delegate that fetches the default (English) strings.
|
||||
class _MaterialLocalizationsDelegate extends LocalizationsDelegate<MaterialLocalizations> {
|
||||
const _MaterialLocalizationsDelegate();
|
||||
|
||||
@override
|
||||
Future<MaterialLocalizations> load(Locale locale) {
|
||||
return new SynchronousFuture<MaterialLocalizations>(const MaterialLocalizations());
|
||||
}
|
||||
Future<MaterialLocalizations> load(Locale locale) => DefaultMaterialLocalizations.load(locale);
|
||||
|
||||
@override
|
||||
bool shouldReload(_MaterialLocalizationsDelegate old) => false;
|
||||
}
|
||||
|
||||
|
||||
/// An application that uses material design.
|
||||
///
|
||||
/// A convenience widget that wraps a number of widgets that are commonly
|
||||
|
|
80
packages/flutter/lib/src/material/i18n/localizations.dart
Normal file
80
packages/flutter/lib/src/material/i18n/localizations.dart
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file has been automatically generated. Please do not edit it manually.
|
||||
// To regenerate the file, use:
|
||||
// dart gen_localizations packages/flutter/lib/src/material/i18n material
|
||||
|
||||
const Map<String, Map<String, String>> localizations = const <String, Map<String, String>> {
|
||||
"ar": const <String, String>{
|
||||
"openAppDrawerTooltip": r"افتح قائمة التنقل",
|
||||
"backButtonTooltip": r"الى الخلف",
|
||||
"closeButtonTooltip": r"إغلا",
|
||||
"nextMonthTooltip": r"الشهر القادم",
|
||||
"previousMonthTooltip": r"الشهر الماضى"
|
||||
},
|
||||
"it": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Apri il menu di navigazione",
|
||||
"backButtonTooltip": r"Indietro",
|
||||
"closeButtonTooltip": r"Chiudi",
|
||||
"nextMonthTooltip": r"Il prossimo mese",
|
||||
"previousMonthTooltip": r"Il mese scorso"
|
||||
},
|
||||
"pt": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Abrir menu de navegação",
|
||||
"backButtonTooltip": r"Costas",
|
||||
"closeButtonTooltip": r"Fechar",
|
||||
"nextMonthTooltip": r"Próximo mês",
|
||||
"previousMonthTooltip": r"Mês anterior"
|
||||
},
|
||||
"es": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Abrir el menú de navegación",
|
||||
"backButtonTooltip": r"Espalda",
|
||||
"closeButtonTooltip": r"Cerrar",
|
||||
"nextMonthTooltip": r"Próximo mes",
|
||||
"previousMonthTooltip": r"mes anterior"
|
||||
},
|
||||
"fr": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Ouvrir le menu de navigation",
|
||||
"backButtonTooltip": r"Arrière",
|
||||
"closeButtonTooltip": r"Fermer",
|
||||
"nextMonthTooltip": r"Mois Suivant",
|
||||
"previousMonthTooltip": r"Le mois précédent"
|
||||
},
|
||||
"zh": const <String, String>{
|
||||
"openAppDrawerTooltip": r"打开导航菜单",
|
||||
"backButtonTooltip": r"背部",
|
||||
"closeButtonTooltip": r"关",
|
||||
"nextMonthTooltip": r"-下月就29了。",
|
||||
"previousMonthTooltip": r"前一个月"
|
||||
},
|
||||
"en": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Open navigation menu",
|
||||
"backButtonTooltip": r"Back",
|
||||
"closeButtonTooltip": r"Close",
|
||||
"nextMonthTooltip": r"Next month",
|
||||
"previousMonthTooltip": r"Previous month"
|
||||
},
|
||||
"de": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Navigationsmenü öffnen",
|
||||
"backButtonTooltip": r"Zurück",
|
||||
"closeButtonTooltip": r"Schließen ",
|
||||
"nextMonthTooltip": r"Nächster Monat",
|
||||
"previousMonthTooltip": r"Letzter Monat"
|
||||
},
|
||||
"ja": const <String, String>{
|
||||
"openAppDrawerTooltip": r"ナビゲーションメニューを開く",
|
||||
"backButtonTooltip": r"バック",
|
||||
"closeButtonTooltip": r"閉じる",
|
||||
"nextMonthTooltip": r"来月",
|
||||
"previousMonthTooltip": r"前の月"
|
||||
},
|
||||
"ru": const <String, String>{
|
||||
"openAppDrawerTooltip": r"Открыть меню навигации",
|
||||
"backButtonTooltip": r"назад",
|
||||
"closeButtonTooltip": r"Закрыть",
|
||||
"nextMonthTooltip": r"В следующем месяце",
|
||||
"previousMonthTooltip": r"Предыдущий месяц"
|
||||
}
|
||||
};
|
27
packages/flutter/lib/src/material/i18n/material_ar.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_ar.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "افتح قائمة التنقل",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "الى الخلف",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "إغلا",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "الشهر القادم",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "الشهر الماضى",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_de.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_de.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Navigationsmenü öffnen",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "Zurück",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Schließen ",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "Nächster Monat",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "Letzter Monat",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
31
packages/flutter/lib/src/material/i18n/material_en.arb
Normal file
31
packages/flutter/lib/src/material/i18n/material_en.arb
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Open navigation menu",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
|
||||
"backButtonTooltip": "Back",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
|
||||
"closeButtonTooltip": "Close",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
|
||||
"nextMonthTooltip": "Next month",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
|
||||
"previousMonthTooltip": "Previous month",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_es.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_es.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Abrir el menú de navegación",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "Espalda",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Cerrar",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "Próximo mes",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "mes anterior",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_fr.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_fr.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Ouvrir le menu de navigation",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "Arrière",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Fermer",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "Mois Suivant",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "Le mois précédent",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_it.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_it.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Apri il menu di navigazione",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "Indietro",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Chiudi",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "Il prossimo mese",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "Il mese scorso",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_ja.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_ja.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "ナビゲーションメニューを開く",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "バック",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "閉じる",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "来月",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "前の月",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_pt.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_pt.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Abrir menu de navegação",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "Costas",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Fechar",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "Próximo mês",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "Mês anterior",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_ru.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_ru.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "Открыть меню навигации",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "назад",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "Закрыть",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "В следующем месяце",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "Предыдущий месяц",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
27
packages/flutter/lib/src/material/i18n/material_zh.arb
Normal file
27
packages/flutter/lib/src/material/i18n/material_zh.arb
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"openAppDrawerTooltip": "打开导航菜单",
|
||||
"@openAppDrawerTooltip": {
|
||||
"description": "The tooltip for the leading AppBar menu (aka 'hamburger') button",
|
||||
"type": "text"
|
||||
},
|
||||
"backButtonTooltip": "背部",
|
||||
"@backButtonTooltip": {
|
||||
"description": "The BackButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"closeButtonTooltip": "关",
|
||||
"@closeButtonTooltip": {
|
||||
"description": "The CloseButton's tooltip",
|
||||
"type": "text"
|
||||
},
|
||||
"nextMonthTooltip": "-下月就29了。",
|
||||
"@nextMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'next month' button.",
|
||||
"type": "text"
|
||||
},
|
||||
"previousMonthTooltip": "前一个月",
|
||||
"@previousMonthTooltip": {
|
||||
"description": "The tooltip for the MonthPicker's 'previous month' button.",
|
||||
"type": "text"
|
||||
}
|
||||
}
|
|
@ -2,35 +2,34 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// Interface for localized resource values for the material widgets.
|
||||
import 'i18n/localizations.dart';
|
||||
|
||||
/// Defines the localized resource values used by the Material widgts.
|
||||
///
|
||||
/// This class provides a default placeholder implementation that returns
|
||||
/// hard-coded American English values.
|
||||
class MaterialLocalizations {
|
||||
/// Create a placeholder object for the localized resources of material widgets
|
||||
/// which only provides American English strings.
|
||||
const MaterialLocalizations();
|
||||
|
||||
/// The locale for which the values of this class's localized resources
|
||||
/// have been translated.
|
||||
Locale get locale => const Locale('en', 'US');
|
||||
|
||||
/// See also:
|
||||
///
|
||||
/// * [DefaultMaterialLocalizations], which implements this interface and
|
||||
/// and supports a variety of locales.
|
||||
abstract class MaterialLocalizations {
|
||||
/// The tooltip for the leading [AppBar] menu (aka 'hamburger') button
|
||||
String get openAppDrawerTooltip => 'Open navigation menu';
|
||||
String get openAppDrawerTooltip;
|
||||
|
||||
/// The [BackButton]'s tooltip.
|
||||
String get backButtonTooltip => 'Back';
|
||||
String get backButtonTooltip;
|
||||
|
||||
/// The [CloseButton]'s tooltip.
|
||||
String get closeButtonTooltip => 'Close';
|
||||
String get closeButtonTooltip;
|
||||
|
||||
/// The tooltip for the [MonthPicker]'s "next month" button.
|
||||
String get nextMonthTooltip => 'Next month';
|
||||
String get nextMonthTooltip;
|
||||
|
||||
/// The tooltip for the [MonthPicker]'s "previous month" button.
|
||||
String get previousMonthTooltip => 'Previous month';
|
||||
String get previousMonthTooltip;
|
||||
|
||||
/// The `MaterialLocalizations` from the closest [Localizations] instance
|
||||
/// that encloses the given context.
|
||||
|
@ -48,3 +47,46 @@ class MaterialLocalizations {
|
|||
return Localizations.of<MaterialLocalizations>(context, MaterialLocalizations);
|
||||
}
|
||||
}
|
||||
|
||||
/// Localized strings for the material widgets.
|
||||
class DefaultMaterialLocalizations implements MaterialLocalizations {
|
||||
/// Construct an object that defines the material widgets' localized strings
|
||||
/// for the given `locale`.
|
||||
DefaultMaterialLocalizations(this.locale) {
|
||||
assert(locale != null);
|
||||
_nameToValue = localizations[locale.toString()]
|
||||
?? localizations[locale.languageCode]
|
||||
?? localizations['en']
|
||||
?? <String, String>{};
|
||||
}
|
||||
|
||||
Map<String, String> _nameToValue;
|
||||
|
||||
/// The locale for which the values of this class's localized resources
|
||||
/// have been translated.
|
||||
final Locale locale;
|
||||
|
||||
@override
|
||||
String get openAppDrawerTooltip => _nameToValue["openAppDrawerTooltip"];
|
||||
|
||||
@override
|
||||
String get backButtonTooltip => _nameToValue["backButtonTooltip"];
|
||||
|
||||
@override
|
||||
String get closeButtonTooltip => _nameToValue["closeButtonTooltip"];
|
||||
|
||||
@override
|
||||
String get nextMonthTooltip => _nameToValue["nextMonthTooltip"];
|
||||
|
||||
@override
|
||||
String get previousMonthTooltip => _nameToValue["previousMonthTooltip"];
|
||||
|
||||
/// Creates an object that provides localized resource values for the
|
||||
/// for the widgets of the material library.
|
||||
///
|
||||
/// This method is typically used to create a [LocalizationsDelegate].
|
||||
/// The [MaterialApp] does so by default.
|
||||
static Future<MaterialLocalizations> load(Locale locale) {
|
||||
return new SynchronousFuture<MaterialLocalizations>(new DefaultMaterialLocalizations(locale));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,17 @@ import 'framework.dart';
|
|||
// class Intl { static String message(String s, { String name, String locale }) => ''; }
|
||||
// Future<Null> initializeMessages(String locale) => null;
|
||||
|
||||
// Used by loadAll() to record LocalizationsDelegate.load() futures we're
|
||||
// waiting for.
|
||||
class _Pending {
|
||||
_Pending(this.delegate, this.futureValue);
|
||||
final LocalizationsDelegate<dynamic> delegate;
|
||||
final Future<dynamic> futureValue;
|
||||
}
|
||||
|
||||
// A utility function used by Localizations to generate one future
|
||||
// that completes when all of the LocalizationsDelegate.load() futures
|
||||
// complete. The returned map is indexed by the type of each input
|
||||
// future's value.
|
||||
// complete. The returned map is indexed by each delegate's type.
|
||||
//
|
||||
// The input future values must have distinct types.
|
||||
//
|
||||
|
@ -31,38 +38,41 @@ import 'framework.dart';
|
|||
// 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(Iterable<Future<dynamic>> inputValues) {
|
||||
Future<Map<Type, dynamic>> _loadAll(Locale locale, Iterable<LocalizationsDelegate<dynamic>> delegates) {
|
||||
final Map<Type, dynamic> output = <Type, dynamic>{};
|
||||
List<Future<dynamic>> outputFutures;
|
||||
List<_Pending> pendingList;
|
||||
|
||||
for (Future<dynamic> inputValue in inputValues) {
|
||||
for (LocalizationsDelegate<dynamic> delegate in delegates) {
|
||||
final Future<dynamic> inputValue = delegate.load(locale);
|
||||
dynamic completedValue;
|
||||
final Future<dynamic> futureValue = inputValue.then<dynamic>((dynamic value) {
|
||||
return completedValue = value;
|
||||
});
|
||||
if (completedValue != null) { // inputValue was a SynchronousFuture
|
||||
final Type type = completedValue.runtimeType;
|
||||
final Type type = delegate.type;
|
||||
assert(!output.containsKey(type));
|
||||
output[type] = completedValue;
|
||||
} else {
|
||||
outputFutures ??= <Future<dynamic>>[];
|
||||
outputFutures.add(futureValue);
|
||||
pendingList ??= <_Pending>[];
|
||||
pendingList.add(new _Pending(delegate, futureValue));
|
||||
}
|
||||
}
|
||||
|
||||
// All of the input.values were synchronous futures, we're done.
|
||||
if (outputFutures == null)
|
||||
// All of the delegate.load() values were synchronous futures, we're done.
|
||||
if (pendingList == null)
|
||||
return new SynchronousFuture<Map<Type, dynamic>>(output);
|
||||
|
||||
// Some of input.values were asynchronous futures. Wait for them.
|
||||
return Future.wait<dynamic>(outputFutures).then<Map<Type, dynamic>>((List<dynamic> values) {
|
||||
for (dynamic value in values) {
|
||||
final Type type = value.runtimeType;
|
||||
assert(!output.containsKey(type));
|
||||
output[type] = value;
|
||||
}
|
||||
return output;
|
||||
});
|
||||
// Some of delegate.load() values were asynchronous futures. Wait for them.
|
||||
return Future.wait<dynamic>(pendingList.map((_Pending p) => p.futureValue))
|
||||
.then<Map<Type, dynamic>>((List<dynamic> values) {
|
||||
assert(values.length == pendingList.length);
|
||||
for (int i = 0; i < values.length; i += 1) {
|
||||
final Type type = pendingList[i].delegate.type;
|
||||
assert(!output.containsKey(type));
|
||||
output[type] = values[i];
|
||||
}
|
||||
return output;
|
||||
});
|
||||
}
|
||||
|
||||
/// A factory for a set of localized resources of type `T`, to be loaded by a
|
||||
|
@ -92,8 +102,10 @@ abstract class LocalizationsDelegate<T> {
|
|||
/// after [load] has completed.
|
||||
bool shouldReload(covariant LocalizationsDelegate<T> old);
|
||||
|
||||
Type get type => T;
|
||||
|
||||
@override
|
||||
String toString() => '$runtimeType';
|
||||
String toString() => '$runtimeType[$type]';
|
||||
}
|
||||
|
||||
/// Interface for localized resource values for the lowest levels of the Flutter
|
||||
|
@ -346,12 +358,8 @@ class _LocalizationsState extends State<Localizations> {
|
|||
return;
|
||||
}
|
||||
|
||||
final Iterable<Future<dynamic>> allResources = delegates.map((LocalizationsDelegate<dynamic> delegate) {
|
||||
return delegate.load(locale);
|
||||
});
|
||||
|
||||
Map<Type, dynamic> typeToResources;
|
||||
final Future<Map<Type, dynamic>> typeToResourcesFuture = _loadAll(allResources)
|
||||
final Future<Map<Type, dynamic>> typeToResourcesFuture = _loadAll(locale, delegates)
|
||||
.then((Map<Type, dynamic> value) {
|
||||
return typeToResources = value;
|
||||
});
|
||||
|
@ -383,7 +391,6 @@ class _LocalizationsState extends State<Localizations> {
|
|||
T resourcesFor<T>(Type type) {
|
||||
assert(type != null);
|
||||
final T resources = _typeToResources[type];
|
||||
assert(resources.runtimeType == type);
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
|
52
packages/flutter/test/material/localizations_test.dart
Normal file
52
packages/flutter/test/material/localizations_test.dart
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2016 The Chromium 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/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
Widget buildFrame({
|
||||
Locale locale,
|
||||
WidgetBuilder buildContent,
|
||||
}) {
|
||||
return new MaterialApp(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
locale: locale,
|
||||
onGenerateRoute: (RouteSettings settings) {
|
||||
return new MaterialPageRoute<Null>(
|
||||
builder: (BuildContext context) {
|
||||
return buildContent(context);
|
||||
}
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void main() {
|
||||
final Key textKey = new UniqueKey();
|
||||
|
||||
testWidgets('sanity check', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
buildFrame(
|
||||
buildContent: (BuildContext context) {
|
||||
return new Text(
|
||||
MaterialLocalizations.of(context).backButtonTooltip,
|
||||
key: textKey,
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
||||
|
||||
// Spanish Bolivia locale, falls back to just 'es'
|
||||
await tester.binding.setLocale('es', 'bo');
|
||||
await tester.pump();
|
||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Espalda');
|
||||
|
||||
// Unrecognized locale falls back to 'en'
|
||||
await tester.binding.setLocale('foo', 'bar');
|
||||
await tester.pump();
|
||||
expect(tester.widget<Text>(find.byKey(textKey)).data, 'Back');
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue