Reland "[dart][l10n] Ermine shell localization example."
This reverts commit 7eeb110ed7dca46f2ca5f686e10db298e9cc9eba.
Reason for revert: 2nd try, correcting the original error. Added a
regression test for the issue that caused the revert. The new attempt
is updated with the new strings from the battery management status.
TESTED=
fx set workstation.chromebook-x64 --with=//src/ermine:tests
fx run-host-tests ermine_internationalization_unittests
Original change's description:
> Revert "[dart][l10n] Ermine shell localization example."
>
> This reverts commit 3af5f54564a3a6cc1993f5fb74d1420fa04464c1.
>
> Reason for revert: <INSERT REASONING HERE>
>
> Original change's description:
> > [dart][l10n] Ermine shell localization example.
> >
> > This change adds scaffolding that allows Ermine shell
> > to display some system messages in a language
> > other than English.
> >
> > At the moment there is no way to select the locale of
> > the shell. This will be added in followup
> > changes. The resources are also not translated
> > since currently there is no infrastructure to do so.
> >
> > Added the basic documentation that explains how the localization is
> > used and maintained.
> >
> > Bug: 37241
> > Change-Id: I6414acf26f894564575fa4222cc386ebb93cd2a8
>
> TBR=anwilson@google.com,sanjayc@google.com,maxbittker@google.com,kpozin@google.com,wleshner@google.com,fmil@google.com,cwhitten@google.com
>
> Change-Id: Ieadbf77e37c057780fd1527e7c98ef232bfb2d62
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 37241
TBR=anwilson@google.com,sanjayc@google.com,maxbittker@google.com,kpozin@google.com,wleshner@google.com,fmil@google.com,cwhitten@google.com
Change-Id: I0602a5a25d34cdb76c6293daafbc432c0233d565
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 37241
diff --git a/session_shells/BUILD.gn b/session_shells/BUILD.gn
index 20f1d2d..227e5c0 100644
--- a/session_shells/BUILD.gn
+++ b/session_shells/BUILD.gn
@@ -14,6 +14,7 @@
deps = [
"ermine/settings:ermine_settings_unittests($host_toolchain)",
"ermine/shell:ermine_unittests($host_toolchain)",
+ "ermine/internationalization:ermine_internationalization_unittests($host_toolchain)",
"//src/experiences/lib/quickui:quickui_unittests($host_toolchain)",
]
}
diff --git a/session_shells/ermine/internationalization/BUILD.gn b/session_shells/ermine/internationalization/BUILD.gn
new file mode 100644
index 0000000..a3c0464
--- /dev/null
+++ b/session_shells/ermine/internationalization/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2019 The Fuchsia 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("//src/modular/build/modular_config/modular_config.gni")
+import("//build/dart/dart_library.gni")
+import("//topaz/runtime/dart/flutter_test.gni")
+import("//topaz/runtime/flutter_runner/flutter_app.gni")
+
+dart_library("internationalization") {
+ package_name = "internationalization"
+ # Disabling analysis for the time being, this is mostly generated code to begin
+ # with, and there are issues like this one that make things harder than necessary:
+ # https://github.com/dart-lang/sdk/issues/38598.
+ disable_analysis = true
+
+ sources = [
+ "current_locale.dart",
+ "localization/messages_all.dart",
+ "localization/messages_messages.dart",
+ "localization/messages_nl.dart",
+ "localization/messages_sr.dart",
+ "localizations_delegate.dart",
+ "profile_provider.dart",
+ "strings.dart",
+ "supported_locales.dart",
+ ]
+
+ deps = [
+ "//third_party/dart-pkg/git/flutter/packages/flutter",
+ "//third_party/dart-pkg/git/flutter/packages/flutter_localizations",
+ "//third_party/dart/third_party/pkg/intl",
+ "//topaz/public/dart/widgets:lib.widgets",
+ ]
+}
+
+flutter_test("ermine_internationalization_unittests") {
+ sources = [
+ "current_locale_test.dart",
+ ]
+
+ deps = [
+ ":internationalization",
+ "//third_party/dart-pkg/git/flutter/packages/flutter_test",
+ "//third_party/dart-pkg/pub/mockito",
+ "//third_party/dart-pkg/pub/test",
+ ]
+}
diff --git a/session_shells/ermine/internationalization/README.md b/session_shells/ermine/internationalization/README.md
new file mode 100644
index 0000000..49ae79a
--- /dev/null
+++ b/session_shells/ermine/internationalization/README.md
@@ -0,0 +1,78 @@
+# Ermine internationalization and localization
+
+This Dart package contains the support for Ermine Shell localization and
+internationalization.
+
+At its current state the support is in its very early phase. There is a lot of
+manual scaffolding that could be replaced by auto-generating the code of
+interest. Doing so will be the topic of followup work.
+
+# How to use this package
+
+This package is purpose-built for the Ermine Shell. The central part is the
+file `lib/strings.dart` which by design contains all the strings that the Ermine
+Shell needs to vary based on the system locale.
+
+Add a function to this file whenever you need to introduce a new text message.
+
+# Adding a dependency
+
+To make the library available to other Ermine Shell packages, add a dependency:
+
+```
+"//src/experiences/session_shells/ermine/internationalization"
+```
+
+to the dependencies in the appropriate `BUILD.gn` rule of your package.
+
+# Importing the new dependency
+
+To import the new dependency, add the import:
+
+```dart
+import 'packages:internationalization/strings.dart' as strings;
+```
+
+to the import section of any Dart file that needs strings.
+
+# Referring to localized strings
+
+You can now refer to the messages defined in [strings.dart][lib/strings.dart].
+For example, you can refer to the string `Ask` by calling `strings.ask()`.
+This is done so that the localization system can substitute the word `Ask` for
+the appropriate word in the language defined by the current locale. The approach
+extends in similar ways for most strings; with slight variations depending on
+whether number or date, or plural or gender formatting is needed.
+
+# Generating localizable libraries
+
+Two scripts are provided in the `./scripts` directory. One is
+`./scripts/run_extract_to_arb.sh`, which produces a "translation interchange
+form" in the form of [ARB][arb] files. The ARB files can be translated
+independently of the source code, and should be checked into the code base for
+now.
+
+## Translating
+
+The translation process amounts to making ARB files for each of the supported
+locales of interest and providing the translations for the messages and
+strings. The basic tool for doing so would be a simple text editor. While
+there also exists a wealth of tools that help software translators, it is out
+of scope of this file to go into specific details. So the choice of the
+translation environment is left to the developer and translator.
+
+## Generating Dart runtime format for the translations
+
+Once translated you can use the file `./scripts/run_generate_from_arb.sh` to
+generate the Dart code that wires up the translation. You will need to rebuild
+the entire project to take the new translations in.
+
+# Further reading
+
+Internationalization and localization are topic unto themselves, and it is out
+of scope of this file to go into all the details. Please see the section
+on [Internationalizing Flutter apps][1] for many more details that are directly
+relevant to Dart and Flutter app localization.
+
+[1]: https://flutter.dev/docs/development/accessibility-and-localization/internationalization
+[arb]: https://github.com/google/app-resource-bundle
diff --git a/session_shells/ermine/internationalization/analysis_options.yaml b/session_shells/ermine/internationalization/analysis_options.yaml
new file mode 100644
index 0000000..86fb3da
--- /dev/null
+++ b/session_shells/ermine/internationalization/analysis_options.yaml
@@ -0,0 +1,6 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+include: ../../../analysis_options.yaml
+
diff --git a/session_shells/ermine/internationalization/lib/current_locale.dart b/session_shells/ermine/internationalization/lib/current_locale.dart
new file mode 100644
index 0000000..d5a2688
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/current_locale.dart
@@ -0,0 +1,19 @@
+// Copyright 2019 The Fuchsia 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' show Locale;
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+
+/// Holds the current [Locale] and notifies any listeners of value changes.
+class CurrentLocale extends ValueNotifier<Locale> {
+ CurrentLocale(Locale value) : super(value);
+
+ /// Returns the Unicode locale of the current locale as a string. E.g.
+ /// "en_US".
+ String unicode() =>
+ // Locale.toString() is for debugging purposes only, but it's the
+ // correct form.
+ Intl.canonicalizedLocale(super.value.toString());
+}
diff --git a/session_shells/ermine/internationalization/lib/localization/messages_all.dart b/session_shells/ermine/internationalization/lib/localization/messages_all.dart
new file mode 100644
index 0000000..2836a52
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/localization/messages_all.dart
@@ -0,0 +1,71 @@
+// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
+// This is a library that looks up messages for specific locales by
+// delegating to the appropriate library.
+
+// Ignore issues from commonly used lints in this file.
+// ignore_for_file:implementation_imports, file_names, unnecessary_new
+// ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering
+// ignore_for_file:argument_type_not_assignable, invalid_assignment
+// ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases
+// ignore_for_file:comment_references
+
+import 'dart:async';
+
+import 'package:intl/intl.dart';
+import 'package:intl/message_lookup_by_library.dart';
+import 'package:intl/src/intl_helpers.dart';
+
+import 'messages_messages.dart' deferred as messages_messages;
+import 'messages_nl.dart' deferred as messages_nl;
+import 'messages_sr.dart' deferred as messages_sr;
+
+typedef Future<dynamic> LibraryLoader();
+Map<String, LibraryLoader> _deferredLibraries = {
+ 'messages': messages_messages.loadLibrary,
+ 'nl': messages_nl.loadLibrary,
+ 'sr': messages_sr.loadLibrary,
+};
+
+MessageLookupByLibrary _findExact(String localeName) {
+ switch (localeName) {
+ case 'messages':
+ return messages_messages.messages;
+ case 'nl':
+ return messages_nl.messages;
+ case 'sr':
+ return messages_sr.messages;
+ default:
+ return null;
+ }
+}
+
+/// User programs should call this before using [localeName] for messages.
+Future<bool> initializeMessages(String localeName) async {
+ var availableLocale = Intl.verifiedLocale(
+ localeName,
+ (locale) => _deferredLibraries[locale] != null,
+ onFailure: (_) => null);
+ if (availableLocale == null) {
+ return new Future.value(false);
+ }
+ var lib = _deferredLibraries[availableLocale];
+ await (lib == null ? new Future.value(false) : lib());
+ initializeInternalMessageLookup(() => new CompositeMessageLookup());
+ messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor);
+ return new Future.value(true);
+}
+
+bool _messagesExistFor(String locale) {
+ try {
+ return _findExact(locale) != null;
+ } catch (e) {
+ return false;
+ }
+}
+
+MessageLookupByLibrary _findGeneratedMessagesFor(String locale) {
+ var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor,
+ onFailure: (_) => null);
+ if (actualLocale == null) return null;
+ return _findExact(actualLocale);
+}
diff --git a/session_shells/ermine/internationalization/lib/localization/messages_messages.dart b/session_shells/ermine/internationalization/lib/localization/messages_messages.dart
new file mode 100644
index 0000000..5c72e12
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/localization/messages_messages.dart
@@ -0,0 +1,75 @@
+// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
+// This is a library that provides messages for a messages locale. All the
+// messages from the main program should be duplicated here with the same
+// function name.
+
+// Ignore issues from commonly used lints in this file.
+// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
+// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
+// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
+// ignore_for_file:unused_import, file_names
+
+import 'package:intl/intl.dart';
+import 'package:intl/message_lookup_by_library.dart';
+
+final messages = new MessageLookup();
+
+typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
+
+class MessageLookup extends MessageLookupByLibrary {
+ String get localeName => 'messages';
+
+ static m0(numThreads) => "${Intl.plural(numThreads, zero: '${numThreads} THR', one: '${numThreads} THR', other: '${numThreads} THR')}";
+
+ static m1(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks} RUNNING', one: '${numTasks} RUNNING', other: '${numTasks} RUNNING')}";
+
+ static m2(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks}', one: '${numTasks}', other: '${numTasks}')}";
+
+ final messages = _notInlinedMessages(_notInlinedMessages);
+ static _notInlinedMessages(_) => <String, Function> {
+ "ask" : MessageLookupByLibrary.simpleMessage("ASK"),
+ "auto" : MessageLookupByLibrary.simpleMessage("Auto"),
+ "back" : MessageLookupByLibrary.simpleMessage("Back"),
+ "batt" : MessageLookupByLibrary.simpleMessage("Batt"),
+ "battery" : MessageLookupByLibrary.simpleMessage("Battery"),
+ "brightness" : MessageLookupByLibrary.simpleMessage("Brightness"),
+ "browser" : MessageLookupByLibrary.simpleMessage("Browser"),
+ "cancel" : MessageLookupByLibrary.simpleMessage("Cancel"),
+ "chrome" : MessageLookupByLibrary.simpleMessage("Chrome"),
+ "cpu" : MessageLookupByLibrary.simpleMessage("CPU"),
+ "date" : MessageLookupByLibrary.simpleMessage("Date"),
+ "done" : MessageLookupByLibrary.simpleMessage("Done"),
+ "fps" : MessageLookupByLibrary.simpleMessage("FPS"),
+ "ide" : MessageLookupByLibrary.simpleMessage("IDE"),
+ "max" : MessageLookupByLibrary.simpleMessage("Max"),
+ "mem" : MessageLookupByLibrary.simpleMessage("MEM"),
+ "memory" : MessageLookupByLibrary.simpleMessage("Memory"),
+ "min" : MessageLookupByLibrary.simpleMessage("Min"),
+ "mockWirelessNetwork" : MessageLookupByLibrary.simpleMessage("Wireless_Network"),
+ "music" : MessageLookupByLibrary.simpleMessage("Music"),
+ "name" : MessageLookupByLibrary.simpleMessage("Name"),
+ "nameThisStory" : MessageLookupByLibrary.simpleMessage("Name this story"),
+ "network" : MessageLookupByLibrary.simpleMessage("Network"),
+ "numThreads" : m0,
+ "overview" : MessageLookupByLibrary.simpleMessage("Overview"),
+ "pause" : MessageLookupByLibrary.simpleMessage("Pause"),
+ "pid" : MessageLookupByLibrary.simpleMessage("PID"),
+ "powerOff" : MessageLookupByLibrary.simpleMessage("Power Off"),
+ "recents" : MessageLookupByLibrary.simpleMessage("Recents"),
+ "restart" : MessageLookupByLibrary.simpleMessage("Restart"),
+ "runningTasks" : m1,
+ "settings" : MessageLookupByLibrary.simpleMessage("Settings"),
+ "shutdown" : MessageLookupByLibrary.simpleMessage("Shutdown"),
+ "signalStrong" : MessageLookupByLibrary.simpleMessage("Strong Signal"),
+ "skip" : MessageLookupByLibrary.simpleMessage("Skip"),
+ "sleep" : MessageLookupByLibrary.simpleMessage("Sleep"),
+ "sunny" : MessageLookupByLibrary.simpleMessage("Sunny"),
+ "tasks" : MessageLookupByLibrary.simpleMessage("TASKS"),
+ "topProcesses" : MessageLookupByLibrary.simpleMessage("Top Processes"),
+ "totalTasks" : m2,
+ "typeToAsk" : MessageLookupByLibrary.simpleMessage("TYPE TO ASK"),
+ "volume" : MessageLookupByLibrary.simpleMessage("Volume"),
+ "weather" : MessageLookupByLibrary.simpleMessage("Weather"),
+ "wireless" : MessageLookupByLibrary.simpleMessage("Wireless")
+ };
+}
diff --git a/session_shells/ermine/internationalization/lib/localization/messages_nl.dart b/session_shells/ermine/internationalization/lib/localization/messages_nl.dart
new file mode 100644
index 0000000..1d4fe32
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/localization/messages_nl.dart
@@ -0,0 +1,65 @@
+// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
+// This is a library that provides messages for a nl locale. All the
+// messages from the main program should be duplicated here with the same
+// function name.
+
+// Ignore issues from commonly used lints in this file.
+// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
+// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
+// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
+// ignore_for_file:unused_import, file_names
+
+import 'package:intl/intl.dart';
+import 'package:intl/message_lookup_by_library.dart';
+
+final messages = new MessageLookup();
+
+typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
+
+class MessageLookup extends MessageLookupByLibrary {
+ String get localeName => 'nl';
+
+ static m0(numThreads) => "${Intl.plural(numThreads, zero: '${numThreads} DRAA', one: '${numThreads} DRAA', other: '${numThreads} DRAA')}";
+
+ static m1(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks} LOPENDE', one: '${numTasks} LOPEND', other: '${numTasks} LOPENDE')}";
+
+ static m2(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks}', one: '${numTasks}', other: '${numTasks}')}";
+
+ final messages = _notInlinedMessages(_notInlinedMessages);
+ static _notInlinedMessages(_) => <String, Function> {
+ "ask" : MessageLookupByLibrary.simpleMessage("ZOEKT"),
+ "back" : MessageLookupByLibrary.simpleMessage("TERUG"),
+ "batt" : MessageLookupByLibrary.simpleMessage("BATT"),
+ "battery" : MessageLookupByLibrary.simpleMessage("Batterij"),
+ "brightness" : MessageLookupByLibrary.simpleMessage("HELDERHEID"),
+ "cancel" : MessageLookupByLibrary.simpleMessage("Annuleren"),
+ "cpu" : MessageLookupByLibrary.simpleMessage("CPU"),
+ "date" : MessageLookupByLibrary.simpleMessage("DATUM"),
+ "done" : MessageLookupByLibrary.simpleMessage("Klaar"),
+ "fps" : MessageLookupByLibrary.simpleMessage("FPS"),
+ "max" : MessageLookupByLibrary.simpleMessage("MAX"),
+ "memory" : MessageLookupByLibrary.simpleMessage("GEHEUGEN"),
+ "min" : MessageLookupByLibrary.simpleMessage("MIN"),
+ "music" : MessageLookupByLibrary.simpleMessage("MUZIEK"),
+ "name" : MessageLookupByLibrary.simpleMessage("Naam"),
+ "nameThisStory" : MessageLookupByLibrary.simpleMessage("Noem dit verhaal"),
+ "network" : MessageLookupByLibrary.simpleMessage("NETWERK"),
+ "numThreads" : m0,
+ "pause" : MessageLookupByLibrary.simpleMessage("PAUZE"),
+ "powerOff" : MessageLookupByLibrary.simpleMessage("UITSCHAKELEN"),
+ "restart" : MessageLookupByLibrary.simpleMessage("HERSTARTEN"),
+ "runningTasks" : m1,
+ "settings" : MessageLookupByLibrary.simpleMessage("INSTELLINGEN"),
+ "signalStrong" : MessageLookupByLibrary.simpleMessage("STERK SIGNAAL"),
+ "skip" : MessageLookupByLibrary.simpleMessage("OVERSLAAN"),
+ "sleep" : MessageLookupByLibrary.simpleMessage("SLAAP"),
+ "sunny" : MessageLookupByLibrary.simpleMessage("ZONNIG"),
+ "tasks" : MessageLookupByLibrary.simpleMessage("TAKEN"),
+ "topProcesses" : MessageLookupByLibrary.simpleMessage("TOP PROCESSEN"),
+ "totalTasks" : m2,
+ "typeToAsk" : MessageLookupByLibrary.simpleMessage("ZOEKT EN GIJ ZAL SPINAZIE ETEN"),
+ "volume" : MessageLookupByLibrary.simpleMessage("GELUID"),
+ "weather" : MessageLookupByLibrary.simpleMessage("WEER"),
+ "wireless" : MessageLookupByLibrary.simpleMessage("DRAADLOZE")
+ };
+}
diff --git a/session_shells/ermine/internationalization/lib/localization/messages_sr.dart b/session_shells/ermine/internationalization/lib/localization/messages_sr.dart
new file mode 100644
index 0000000..6706563
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/localization/messages_sr.dart
@@ -0,0 +1,65 @@
+// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
+// This is a library that provides messages for a sr locale. All the
+// messages from the main program should be duplicated here with the same
+// function name.
+
+// Ignore issues from commonly used lints in this file.
+// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
+// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
+// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
+// ignore_for_file:unused_import, file_names
+
+import 'package:intl/intl.dart';
+import 'package:intl/message_lookup_by_library.dart';
+
+final messages = new MessageLookup();
+
+typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
+
+class MessageLookup extends MessageLookupByLibrary {
+ String get localeName => 'sr';
+
+ static m0(numThreads) => "${Intl.plural(numThreads, zero: '${numThreads} НИТИ', one: '${numThreads} НИТ', other: '${numThreads} НИТИ')}";
+
+ static m1(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks} ЗАДАТАКА', one: '${numTasks} ЗАДАТАК', other: '${numTasks} ЗАДАТАКА')}";
+
+ static m2(numTasks) => "${Intl.plural(numTasks, zero: '${numTasks}', one: '${numTasks}', other: '${numTasks}')}";
+
+ final messages = _notInlinedMessages(_notInlinedMessages);
+ static _notInlinedMessages(_) => <String, Function> {
+ "ask" : MessageLookupByLibrary.simpleMessage("УПИТ"),
+ "back" : MessageLookupByLibrary.simpleMessage("НАЗАД"),
+ "batt" : MessageLookupByLibrary.simpleMessage("БАТ"),
+ "battery" : MessageLookupByLibrary.simpleMessage("Батерија"),
+ "brightness" : MessageLookupByLibrary.simpleMessage("ОСВЕТЉАЈ"),
+ "cancel" : MessageLookupByLibrary.simpleMessage("Откажи"),
+ "cpu" : MessageLookupByLibrary.simpleMessage("ПРОЦ"),
+ "date" : MessageLookupByLibrary.simpleMessage("ДАТУМ"),
+ "done" : MessageLookupByLibrary.simpleMessage("Готово"),
+ "fps" : MessageLookupByLibrary.simpleMessage("СЛ/СЕК"),
+ "max" : MessageLookupByLibrary.simpleMessage("МАКС"),
+ "memory" : MessageLookupByLibrary.simpleMessage("МЕМОРИЈА"),
+ "min" : MessageLookupByLibrary.simpleMessage("МИН"),
+ "music" : MessageLookupByLibrary.simpleMessage("МУЗИКА"),
+ "name" : MessageLookupByLibrary.simpleMessage("ИМЕ"),
+ "nameThisStory" : MessageLookupByLibrary.simpleMessage("Именуј ову причу"),
+ "network" : MessageLookupByLibrary.simpleMessage("МРЕЖА"),
+ "numThreads" : m0,
+ "pause" : MessageLookupByLibrary.simpleMessage("ПАУЗА"),
+ "powerOff" : MessageLookupByLibrary.simpleMessage("ИСКЉУЧИ"),
+ "restart" : MessageLookupByLibrary.simpleMessage("РЕСТАРТ"),
+ "runningTasks" : m1,
+ "settings" : MessageLookupByLibrary.simpleMessage("ПОДЕШАВАЊА"),
+ "signalStrong" : MessageLookupByLibrary.simpleMessage("ЈАК СИГНАЛ"),
+ "skip" : MessageLookupByLibrary.simpleMessage("ПРЕСКОЧИ"),
+ "sleep" : MessageLookupByLibrary.simpleMessage("СПАВАЊЕ"),
+ "sunny" : MessageLookupByLibrary.simpleMessage("СУНЧАНО"),
+ "tasks" : MessageLookupByLibrary.simpleMessage("ЗАДАЦИ"),
+ "topProcesses" : MessageLookupByLibrary.simpleMessage("ВРШНИ ПРОЦЕСИ"),
+ "totalTasks" : m2,
+ "typeToAsk" : MessageLookupByLibrary.simpleMessage("УНЕСИТЕ УПИТ"),
+ "volume" : MessageLookupByLibrary.simpleMessage("ЈАЧИНА"),
+ "weather" : MessageLookupByLibrary.simpleMessage("ВРЕМЕ"),
+ "wireless" : MessageLookupByLibrary.simpleMessage("БЕЖИЧНА")
+ };
+}
diff --git a/session_shells/ermine/internationalization/lib/localizations_delegate.dart b/session_shells/ermine/internationalization/lib/localizations_delegate.dart
new file mode 100644
index 0000000..f8d782d
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/localizations_delegate.dart
@@ -0,0 +1,47 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Should the localizations delegate be generated instead?
+
+import 'dart:async';
+import 'dart:ui' show Locale;
+
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+import 'package:fuchsia_logger/logger.dart';
+
+import 'localization/messages_all.dart' as messages_all;
+import 'supported_locales.dart' as supported_locales;
+
+LocalizationsDelegate<void> delegate() => _LocalizationsDelegate();
+
+class _LocalizationsDelegate extends LocalizationsDelegate<void> {
+ static Future<void> loadLocale(Locale locale) async {
+ final String name =
+ (locale.countryCode == null || locale.countryCode.isEmpty)
+ ? locale.languageCode
+ : locale.toString();
+ final String localeName = Intl.canonicalizedLocale(name);
+ await messages_all.initializeMessages(localeName);
+ log.info(
+ '_LocalizationsDelegate: current default locale: ${Intl.defaultLocale}');
+ }
+
+ const _LocalizationsDelegate();
+
+ @override
+ Future<void> load(Locale locale) => loadLocale(locale);
+
+ // For the time being, never reload.
+ @override
+ bool shouldReload(_LocalizationsDelegate __) => false;
+
+ @override
+ bool isSupported(Locale locale) {
+ bool supported = supported_locales.locales.contains(locale);
+ log.finer(
+ '_LocalizationsDelegate: locale: ${locale.toString()}; isSupported: ${supported.toString()}');
+ return supported;
+ }
+}
diff --git a/session_shells/ermine/internationalization/lib/strings.dart b/session_shells/ermine/internationalization/lib/strings.dart
new file mode 100644
index 0000000..6ce95c5
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/strings.dart
@@ -0,0 +1,298 @@
+// Copyright 2019 The Fuchsia 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 is an L10N developer experience study fragment.
+// Let's see how it works when you offload all strings to a file.
+
+// The Intl.message texts have been offloaded to a separate file so as to
+// minimize the amount of code needed to be exported for localization.
+// While the individual string messages have been left in their original form,
+// the case-ness of the text is part of the presentation so should probably be
+// handled in the view code.
+
+import 'package:intl/intl.dart';
+
+String brightness() => Intl.message(
+ 'Brightness',
+ name: 'brightness',
+ desc: 'The label for the screen brightness settings widget',
+ );
+
+String cancel() => Intl.message(
+ 'Cancel',
+ name: 'cancel',
+ desc: 'The label for canceling an offered command',
+ );
+
+String done() => Intl.message(
+ 'Done',
+ name: 'done',
+ desc: 'The label for saying we are done with a command',
+ );
+
+
+String sleep() => Intl.message(
+ 'Sleep',
+ name: 'sleep',
+ desc: 'The label for the sleep settings widget',
+ );
+
+String restart() => Intl.message(
+ 'Restart',
+ name: 'restart',
+ desc: 'The label for the restart button',
+ );
+
+String powerOff() => Intl.message(
+ 'Power Off',
+ name: 'powerOff',
+ desc: 'The label for the restart button',
+ );
+
+String settings() => Intl.message(
+ 'Settings',
+ name: 'settings',
+ desc: 'The label for the settings button',
+ );
+
+String volume() => Intl.message(
+ 'Volume',
+ name: 'volume',
+ desc: 'The label for the settings button',
+ );
+
+String min() => Intl.message(
+ 'Min',
+ name: 'min',
+ desc:
+ 'The short label for "minimal" label for the volume button',
+ );
+
+String max() => Intl.message(
+ 'Max',
+ name: 'max',
+ desc:
+ 'The shortened label for "maximal" label for the volume button',
+ );
+
+String music() => Intl.message(
+ 'Music',
+ name: 'music',
+ desc: 'The label used for the music button',
+ );
+
+String back() => Intl.message(
+ 'Back',
+ name: 'back',
+ desc: 'The label for the "Back" button',
+ );
+
+String pause() => Intl.message(
+ 'Pause',
+ name: 'pause',
+ desc: 'The label for the "Pause" button',
+ );
+
+String skip() => Intl.message(
+ 'Skip',
+ name: 'skip',
+ desc: 'The label for the "Skip" button',
+ );
+
+String topProcesses() => Intl.message(
+ 'Top Processes',
+ name: 'topProcesses',
+ desc: 'The label for the "Top processes" label',
+ );
+
+String shutdown() => Intl.message(
+ 'Shutdown',
+ name: 'shutdown',
+ desc: 'The label for the "System shutdown" label',
+ );
+
+String memory() => Intl.message(
+ 'Memory',
+ name: 'memory',
+ desc: 'The label for the "memory" label',
+ );
+
+String cpu() => Intl.message(
+ 'CPU',
+ name: 'cpu',
+ desc: 'The short name for the "Central Processing Unit" label',
+ );
+
+String mem() => Intl.message(
+ 'MEM',
+ name: 'mem',
+ desc: 'The short name for the "Memory" label',
+ );
+
+String ide() => Intl.message(
+ 'IDE',
+ name: 'ide',
+ desc: 'The short name for the "Integrated Development Environment" label',
+ );
+
+String chrome() => Intl.message(
+ 'Chrome',
+ name: 'chrome',
+ desc: 'The short name for the "Google Chrome" browser',
+ );
+
+
+String pid() => Intl.message(
+ 'PID',
+ name: 'pid',
+ desc: 'The short name for the "Process identifier" label',
+ );
+
+
+String tasks() => Intl.message(
+ 'TASKS',
+ name: 'tasks',
+ desc: 'The short name for the "Tasks" label',
+ );
+
+String weather() => Intl.message(
+ 'Weather',
+ name: 'weather',
+ desc: 'The short name for the "Weather" label',
+ );
+
+String date() => Intl.message(
+ 'Date',
+ name: 'date',
+ desc: 'The short name for the "date" label',
+ );
+
+String network() => Intl.message(
+ 'Network',
+ name: 'network',
+ desc: 'The short name for the "network" label',
+ );
+
+String fps() => Intl.message(
+ 'FPS',
+ name: 'fps',
+ desc: 'The short name for the "Frames per Second" label',
+ );
+
+String batt() => Intl.message(
+ 'Batt',
+ name: 'batt',
+ desc: 'The short name for the "Battery level" label',
+ );
+
+String battery() => Intl.message(
+ 'Battery',
+ name: 'battery',
+ desc: 'The long name for the "Battery level" label',
+ );
+
+String wireless() => Intl.message(
+ 'Wireless',
+ name: 'wireless',
+ desc: 'The short name for the "Wireless network" label',
+ );
+
+String signalStrong() => Intl.message(
+ 'Strong Signal',
+ name: 'signalStrong',
+ desc: 'The short name for the "Strong signal" label',
+ );
+
+String sunny() => Intl.message(
+ 'Sunny',
+ name: 'sunny',
+ desc: 'The short name for the "Weather is sunny" label',
+ );
+
+String runningTasks(int numTasks) => Intl.plural(
+ numTasks,
+ zero: '$numTasks RUNNING',
+ one: '$numTasks RUNNING',
+ other: '$numTasks RUNNING',
+ name: 'runningTasks',
+ args: [numTasks],
+ desc: 'How many tasks are currently running',
+ examples: const {'numTasks': 42},
+ );
+
+String totalTasks(int numTasks) => Intl.plural(
+ numTasks,
+ zero: '$numTasks',
+ one: '$numTasks',
+ other: '$numTasks',
+ name: 'totalTasks',
+ args: [numTasks],
+ desc: 'How many tasks are currently running',
+ examples: const {'numTasks': 42},
+ );
+
+String numThreads(int numThreads) => Intl.plural(
+ numThreads,
+ zero: '$numThreads THR',
+ one: '$numThreads THR',
+ other: '$numThreads THR',
+ name: 'numThreads',
+ args: [numThreads],
+ desc: 'How many threads are currently there, short label',
+ examples: const {'numThreads': 42},
+ );
+
+String name() => Intl.message(
+ 'Name',
+ name: 'name',
+ desc: 'A generic label for a name, sentence case.',
+ );
+
+String ask() => Intl.message(
+ 'ASK',
+ name: 'ask',
+ desc: 'A generic short label for "query", sentence case.',
+ );
+
+String typeToAsk() => Intl.message(
+ 'TYPE TO ASK',
+ name: 'typeToAsk',
+ desc: 'Shown in the ask text entry box in Ermine shell',
+ );
+
+String overview() => Intl.message(
+ 'Overview',
+ name: 'overview',
+ desc: 'Shown in top bar on the Ermine shell',
+ );
+
+String recents() => Intl.message(
+ 'Recents',
+ name: 'recents',
+ desc: 'A list of recent apps',
+ );
+
+String browser() => Intl.message(
+ 'Browser',
+ name: 'browser',
+ desc: 'A button to invoke a browser with',
+ );
+
+String auto() => Intl.message(
+ 'Auto',
+ name: 'auto',
+ desc: 'A shorthand for "automatic" setting.',
+ );
+
+String mockWirelessNetwork() => Intl.message(
+ 'Wireless_Network',
+ name: 'mockWirelessNetwork',
+ desc: 'A mock label for a wireless network name that the device is connected to',
+ );
+
+String nameThisStory() => Intl.message(
+ 'Name this story',
+ name: 'nameThisStory',
+ desc: 'A hint appearing in a window for naming a story. This text should not include padding, but now it does.',
+ );
diff --git a/session_shells/ermine/internationalization/lib/supported_locales.dart b/session_shells/ermine/internationalization/lib/supported_locales.dart
new file mode 100644
index 0000000..84d978f
--- /dev/null
+++ b/session_shells/ermine/internationalization/lib/supported_locales.dart
@@ -0,0 +1,10 @@
+// Copyright 2019 The Fuchsia 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' show Locale;
+
+List<Locale> locales = [
+ const Locale.fromSubtags(languageCode: 'sr'),
+ const Locale.fromSubtags(languageCode: 'nl'),
+];
diff --git a/session_shells/ermine/internationalization/pubspec.yaml b/session_shells/ermine/internationalization/pubspec.yaml
new file mode 100644
index 0000000..4c61966
--- /dev/null
+++ b/session_shells/ermine/internationalization/pubspec.yaml
@@ -0,0 +1,12 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+name: internationalization
+description: The internationalization library for Ermine.
+
+flutter:
+
+dependencies:
+ # Needed for the ARB extraction scripts until this is fully automated.
+ intl_translation: ^0.17.2
+
diff --git a/session_shells/ermine/internationalization/resources/intl_messages.arb b/session_shells/ermine/internationalization/resources/intl_messages.arb
new file mode 100644
index 0000000..9dc62d8
--- /dev/null
+++ b/session_shells/ermine/internationalization/resources/intl_messages.arb
@@ -0,0 +1,279 @@
+{
+ "@@last_modified": "2019-10-04T10:36:29.147518",
+ "brightness": "Brightness",
+ "@brightness": {
+ "description": "The label for the screen brightness settings widget",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cancel": "Cancel",
+ "@cancel": {
+ "description": "The label for canceling an offered command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "done": "Done",
+ "@done": {
+ "description": "The label for saying we are done with a command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sleep": "Sleep",
+ "@sleep": {
+ "description": "The label for the sleep settings widget",
+ "type": "text",
+ "placeholders": {}
+ },
+ "restart": "Restart",
+ "@restart": {
+ "description": "The label for the restart button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "powerOff": "Power Off",
+ "@powerOff": {
+ "description": "The label for the restart button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "settings": "Settings",
+ "@settings": {
+ "description": "The label for the settings button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "volume": "Volume",
+ "@volume": {
+ "description": "The label for the settings button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "min": "Min",
+ "@min": {
+ "description": "The short label for \"minimal\" label for the volume button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "max": "Max",
+ "@max": {
+ "description": "The shortened label for \"maximal\" label for the volume button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "music": "Music",
+ "@music": {
+ "description": "The label used for the music button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "back": "Back",
+ "@back": {
+ "description": "The label for the \"Back\" button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "pause": "Pause",
+ "@pause": {
+ "description": "The label for the \"Pause\" button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "skip": "Skip",
+ "@skip": {
+ "description": "The label for the \"Skip\" button",
+ "type": "text",
+ "placeholders": {}
+ },
+ "topProcesses": "Top Processes",
+ "@topProcesses": {
+ "description": "The label for the \"Top processes\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "shutdown": "Shutdown",
+ "@shutdown": {
+ "description": "The label for the \"System shutdown\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "memory": "Memory",
+ "@memory": {
+ "description": "The label for the \"memory\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cpu": "CPU",
+ "@cpu": {
+ "description": "The short name for the \"Central Processing Unit\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "mem": "MEM",
+ "@mem": {
+ "description": "The short name for the \"Memory\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "ide": "IDE",
+ "@ide": {
+ "description": "The short name for the \"Integrated Development Environment\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "chrome": "Chrome",
+ "@chrome": {
+ "description": "The short name for the \"Google Chrome\" browser",
+ "type": "text",
+ "placeholders": {}
+ },
+ "pid": "PID",
+ "@pid": {
+ "description": "The short name for the \"Process identifier\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "tasks": "TASKS",
+ "@tasks": {
+ "description": "The short name for the \"Tasks\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "weather": "Weather",
+ "@weather": {
+ "description": "The short name for the \"Weather\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "date": "Date",
+ "@date": {
+ "description": "The short name for the \"date\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "network": "Network",
+ "@network": {
+ "description": "The short name for the \"network\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "fps": "FPS",
+ "@fps": {
+ "description": "The short name for the \"Frames per Second\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "batt": "Batt",
+ "@batt": {
+ "description": "The short name for the \"Battery level\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "battery": "Battery",
+ "@battery": {
+ "description": "The long name for the \"Battery level\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "wireless": "Wireless",
+ "@wireless": {
+ "description": "The short name for the \"Wireless network\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "signalStrong": "Strong Signal",
+ "@signalStrong": {
+ "description": "The short name for the \"Strong signal\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sunny": "Sunny",
+ "@sunny": {
+ "description": "The short name for the \"Weather is sunny\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "runningTasks": "{numTasks,plural, =0{{numTasks} RUNNING}=1{{numTasks} RUNNING}other{{numTasks} RUNNING}}",
+ "@runningTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": 42
+ }
+ }
+ },
+ "totalTasks": "{numTasks,plural, =0{{numTasks}}=1{{numTasks}}other{{numTasks}}}",
+ "@totalTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": 42
+ }
+ }
+ },
+ "numThreads": "{numThreads,plural, =0{{numThreads} THR}=1{{numThreads} THR}other{{numThreads} THR}}",
+ "@numThreads": {
+ "description": "How many threads are currently there, short label",
+ "type": "text",
+ "placeholders": {
+ "numThreads": {
+ "example": 42
+ }
+ }
+ },
+ "name": "Name",
+ "@name": {
+ "description": "A generic label for a name, sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "ask": "ASK",
+ "@ask": {
+ "description": "A generic short label for \"query\", sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "typeToAsk": "TYPE TO ASK",
+ "@typeToAsk": {
+ "description": "Shown in the ask text entry box in Ermine shell",
+ "type": "text",
+ "placeholders": {}
+ },
+ "overview": "Overview",
+ "@overview": {
+ "description": "Shown in top bar on the Ermine shell",
+ "type": "text",
+ "placeholders": {}
+ },
+ "recents": "Recents",
+ "@recents": {
+ "description": "A list of recent apps",
+ "type": "text",
+ "placeholders": {}
+ },
+ "browser": "Browser",
+ "@browser": {
+ "description": "A button to invoke a browser with",
+ "type": "text",
+ "placeholders": {}
+ },
+ "auto": "Auto",
+ "@auto": {
+ "description": "A shorthand for \"automatic\" setting.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "mockWirelessNetwork": "Wireless_Network",
+ "@mockWirelessNetwork": {
+ "description": "A mock label for a wireless network name that the device is connected to",
+ "type": "text",
+ "placeholders": {}
+ },
+ "nameThisStory": "Name this story",
+ "@nameThisStory": {
+ "description": "A hint appearing in a window for naming a story. This text should not include padding, but now it does.",
+ "type": "text",
+ "placeholders": {}
+ }
+}
\ No newline at end of file
diff --git a/session_shells/ermine/internationalization/resources/intl_nl.arb b/session_shells/ermine/internationalization/resources/intl_nl.arb
new file mode 100644
index 0000000..bb63915
--- /dev/null
+++ b/session_shells/ermine/internationalization/resources/intl_nl.arb
@@ -0,0 +1,218 @@
+{
+ "brightness": "HELDERHEID",
+ "@brightness": {
+ "description": "The label for the screen brightness settings widget (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cancel": "Annuleren",
+ "@cancel": {
+ "description": "The label for canceling an offered command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "done": "Klaar",
+ "@done": {
+ "description": "The label for saying we are done with a command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sleep": "SLAAP",
+ "@sleep": {
+ "description": "The label for the sleep settings widget (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "restart": "HERSTARTEN",
+ "@restart": {
+ "description": "The label for the restart button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "powerOff": "UITSCHAKELEN",
+ "@powerOff": {
+ "description": "The label for the restart button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "settings": "INSTELLINGEN",
+ "@settings": {
+ "description": "The label for the settings button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "volume": "GELUID",
+ "@volume": {
+ "description": "The label for the settings button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "min": "MIN",
+ "@min": {
+ "description": "The short label for \"minimal\" label for the volume button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "max": "MAX",
+ "@max": {
+ "description": "The shortened label for \"maximal\" label for the volume button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "music": "MUZIEK",
+ "@music": {
+ "description": "The label used for the music button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "back": "TERUG",
+ "@back": {
+ "description": "The label for the \"Back\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "pause": "PAUZE",
+ "@pause": {
+ "description": "The label for the \"Pause\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "skip": "OVERSLAAN",
+ "@skip": {
+ "description": "The label for the \"Skip\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "topProcesses": "TOP PROCESSEN",
+ "@topProcesses": {
+ "description": "The label for the \"Top processes\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "memory": "GEHEUGEN",
+ "@memory": {
+ "description": "The label for the \"memory\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cpu": "CPU",
+ "@cpu": {
+ "description": "The short name for the \"Central Processing Unit\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "tasks": "TAKEN",
+ "@tasks": {
+ "description": "The short name for the \"Tasks\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "weather": "WEER",
+ "@weather": {
+ "description": "The short name for the \"Weather\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "date": "DATUM",
+ "@date": {
+ "description": "The short name for the \"date\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "network": "NETWERK",
+ "@network": {
+ "description": "The short name for the \"network\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "fps": "FPS",
+ "@fps": {
+ "description": "The short name for the \"Frames per Second\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "batt": "BATT",
+ "@batt": {
+ "description": "The short name for the \"Battery level\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "battery": "Batterij",
+ "@battery": {
+ "description": "The long name for the \"Battery level\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "wireless": "DRAADLOZE",
+ "@wireless": {
+ "description": "The short name for the \"Wireless network\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "signalStrong": "STERK SIGNAAL",
+ "@signalStrong": {
+ "description": "The short name for the \"Strong signal\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sunny": "ZONNIG",
+ "@sunny": {
+ "description": "The short name for the \"Weather is sunny\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "runningTasks": "{numTasks, plural, =0 {{numTasks} LOPENDE} =1 {{numTasks} LOPEND} other {{numTasks} LOPENDE}}",
+ "@runningTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": "42"
+ }
+ }
+ },
+ "totalTasks": "{numTasks, plural, =0 {{numTasks}} =1 {{numTasks}} other {{numTasks}}}",
+ "@totalTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": "42"
+ }
+ }
+ },
+ "numThreads": "{numThreads, plural, =0 {{numThreads} DRAA} =1 {{numThreads} DRAA} other {{numThreads} DRAA}}",
+ "@numThreads": {
+ "description": "How many threads are currently there, short label",
+ "type": "text",
+ "placeholders": {
+ "numThreads": {
+ "example": "42"
+ }
+ }
+ },
+ "name": "Naam",
+ "@name": {
+ "description": "A generic label for a name, sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "ask": "ZOEKT",
+ "@ask": {
+ "description": "A generic short label for \"query\", sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "typeToAsk": "ZOEKT EN GIJ ZAL SPINAZIE ETEN",
+ "@typeToAsk": {
+ "description": "Shown in the ask text entry box in Ermine shell",
+ "type": "text",
+ "placeholders": {}
+ },
+ "nameThisStory": "Noem dit verhaal",
+ "@nameThisStory": {
+ "description": "A hint appearing in a window for naming a story. This text should not include padding, but now it does.",
+ "type": "text",
+ "placeholders": {}
+ }
+}
diff --git a/session_shells/ermine/internationalization/resources/intl_sr.arb b/session_shells/ermine/internationalization/resources/intl_sr.arb
new file mode 100644
index 0000000..88feb87
--- /dev/null
+++ b/session_shells/ermine/internationalization/resources/intl_sr.arb
@@ -0,0 +1,218 @@
+{
+ "brightness": "ОСВЕТЉАЈ",
+ "@brightness": {
+ "description": "The label for the screen brightness settings widget (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cancel": "Откажи",
+ "@cancel": {
+ "description": "The label for canceling an offered command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "done": "Готово",
+ "@done": {
+ "description": "The label for saying we are done with a command",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sleep": "СПАВАЊЕ",
+ "@sleep": {
+ "description": "The label for the sleep settings widget (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "restart": "РЕСТАРТ",
+ "@restart": {
+ "description": "The label for the restart button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "powerOff": "ИСКЉУЧИ",
+ "@powerOff": {
+ "description": "The label for the restart button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "settings": "ПОДЕШАВАЊА",
+ "@settings": {
+ "description": "The label for the settings button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "volume": "ЈАЧИНА",
+ "@volume": {
+ "description": "The label for the settings button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "min": "МИН",
+ "@min": {
+ "description": "The short label for \"minimal\" label for the volume button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "max": "МАКС",
+ "@max": {
+ "description": "The shortened label for \"maximal\" label for the volume button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "music": "МУЗИКА",
+ "@music": {
+ "description": "The label used for the music button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "back": "НАЗАД",
+ "@back": {
+ "description": "The label for the \"Back\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "pause": "ПАУЗА",
+ "@pause": {
+ "description": "The label for the \"Pause\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "skip": "ПРЕСКОЧИ",
+ "@skip": {
+ "description": "The label for the \"Skip\" button (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "topProcesses": "ВРШНИ ПРОЦЕСИ",
+ "@topProcesses": {
+ "description": "The label for the \"Top processes\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "memory": "МЕМОРИЈА",
+ "@memory": {
+ "description": "The label for the \"memory\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "cpu": "ПРОЦ",
+ "@cpu": {
+ "description": "The short name for the \"Central Processing Unit\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "tasks": "ЗАДАЦИ",
+ "@tasks": {
+ "description": "The short name for the \"Tasks\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "weather": "ВРЕМЕ",
+ "@weather": {
+ "description": "The short name for the \"Weather\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "date": "ДАТУМ",
+ "@date": {
+ "description": "The short name for the \"date\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "network": "МРЕЖА",
+ "@network": {
+ "description": "The short name for the \"network\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "fps": "СЛ/СЕК",
+ "@fps": {
+ "description": "The short name for the \"Frames per Second\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "batt": "БАТ",
+ "@batt": {
+ "description": "The short name for the \"Battery level\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "battery": "Батерија",
+ "@battery": {
+ "description": "The long name for the \"Battery level\" label",
+ "type": "text",
+ "placeholders": {}
+ },
+ "wireless": "БЕЖИЧНА",
+ "@wireless": {
+ "description": "The short name for the \"Wireless network\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "signalStrong": "ЈАК СИГНАЛ",
+ "@signalStrong": {
+ "description": "The short name for the \"Strong signal\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "sunny": "СУНЧАНО",
+ "@sunny": {
+ "description": "The short name for the \"Weather is sunny\" label (ALL CAPS)",
+ "type": "text",
+ "placeholders": {}
+ },
+ "runningTasks": "{numTasks, plural, =0 {{numTasks} ЗАДАТАКА} =1 {{numTasks} ЗАДАТАК} other {{numTasks} ЗАДАТАКА}}",
+ "@runningTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": "42"
+ }
+ }
+ },
+ "totalTasks": "{numTasks, plural, =0 {{numTasks}} =1 {{numTasks}} other {{numTasks}}}",
+ "@totalTasks": {
+ "description": "How many tasks are currently running",
+ "type": "text",
+ "placeholders": {
+ "numTasks": {
+ "example": "42"
+ }
+ }
+ },
+ "numThreads": "{numThreads, plural, =0 {{numThreads} НИТИ} =1 {{numThreads} НИТ} other {{numThreads} НИТИ}}",
+ "@numThreads": {
+ "description": "How many threads are currently there, short label",
+ "type": "text",
+ "placeholders": {
+ "numThreads": {
+ "example": "42"
+ }
+ }
+ },
+ "name": "ИМЕ",
+ "@name": {
+ "description": "A generic label for a name, sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "ask": "УПИТ",
+ "@ask": {
+ "description": "A generic short label for \"query\", sentence case.",
+ "type": "text",
+ "placeholders": {}
+ },
+ "typeToAsk": "УНЕСИТЕ УПИТ",
+ "@typeToAsk": {
+ "description": "Shown in the ask text entry box in Ermine shell",
+ "type": "text",
+ "placeholders": {}
+ },
+ "nameThisStory": "Именуј ову причу",
+ "@nameThisStory": {
+ "description": "A hint appearing in a window for naming a story. This text should not include padding, but now it does.",
+ "type": "text",
+ "placeholders": {}
+ }
+}
diff --git a/session_shells/ermine/internationalization/scripts/run_extract_to_arb.sh b/session_shells/ermine/internationalization/scripts/run_extract_to_arb.sh
new file mode 100755
index 0000000..d847f84
--- /dev/null
+++ b/session_shells/ermine/internationalization/scripts/run_extract_to_arb.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+set -x
+
+$FUCHSIA_DIR/third_party/dart-pkg/git/flutter/bin/flutter \
+ packages pub get intl_translation:extract_to_arb
+
+$FUCHSIA_DIR/third_party/dart-pkg/git/flutter/bin/flutter \
+ packages pub run intl_translation:extract_to_arb \
+ --output-dir=resources lib/*strings.dart
+
+rm .packages pubspec.lock
+rm -fr .dart_tool
diff --git a/session_shells/ermine/internationalization/scripts/run_generate_from_arb.sh b/session_shells/ermine/internationalization/scripts/run_generate_from_arb.sh
new file mode 100755
index 0000000..93f7b81
--- /dev/null
+++ b/session_shells/ermine/internationalization/scripts/run_generate_from_arb.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+set -x
+
+$FUCHSIA_DIR/third_party/dart-pkg/git/flutter/bin/flutter \
+ packages pub get intl_translation:generate_from_arb
+
+$FUCHSIA_DIR/third_party/dart-pkg/git/flutter/bin/flutter \
+ packages pub run intl_translation:generate_from_arb \
+ --output-dir=lib/localization \
+ lib/*strings.dart \
+ resources/*.arb
+
+rm .packages pubspec.lock
+rm -fr .dart_tool
diff --git a/session_shells/ermine/internationalization/test/current_locale_test.dart b/session_shells/ermine/internationalization/test/current_locale_test.dart
new file mode 100644
index 0000000..69c96b7
--- /dev/null
+++ b/session_shells/ermine/internationalization/test/current_locale_test.dart
@@ -0,0 +1,34 @@
+// Copyright 2019 The Fuchsia 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';
+
+// ignore_for_file: implementation_imports
+import 'package:internationalization/current_locale.dart';
+
+void main() {
+ testWidgets('Check en_US from subtags', (tester) async {
+ final CurrentLocale current = CurrentLocale(
+ Locale.fromSubtags(languageCode: 'en', countryCode: 'US'));
+ expect(current.unicode(), 'en_US');
+ expect(current.value.toString(), 'en_US');
+ });
+ testWidgets('Check sr_RS from subtags', (tester) async {
+ final CurrentLocale current = CurrentLocale(
+ Locale.fromSubtags(languageCode: 'sr', countryCode: 'RS'));
+ expect(current.unicode(), 'sr_RS');
+ expect(current.value.toString(), 'sr_RS');
+ });
+ testWidgets('Check sr from constructor', (tester) async {
+ final CurrentLocale current = CurrentLocale(Locale('sr'));
+ expect(current.unicode(), 'sr');
+ expect(current.value.toString(), 'sr');
+ });
+ testWidgets('Check sr_RS from constructor', (tester) async {
+ final CurrentLocale current = CurrentLocale(Locale('sr_RS'));
+ expect(current.unicode(), 'sr_RS');
+ expect(current.value.toString(), 'sr_RS');
+ });
+}
diff --git a/session_shells/ermine/settings/BUILD.gn b/session_shells/ermine/settings/BUILD.gn
index b2e3462..1d0b709 100644
--- a/session_shells/ermine/settings/BUILD.gn
+++ b/session_shells/ermine/settings/BUILD.gn
@@ -20,6 +20,7 @@
"//sdk/fidl/fuchsia.power",
"//sdk/fidl/fuchsia.ui.brightness",
"//src/experiences/lib/quickui",
+ "//src/experiences/session_shells/ermine/internationalization",
"//third_party/dart-pkg/git/flutter/packages/flutter",
"//topaz/public/dart/fuchsia_services",
]
diff --git a/session_shells/ermine/settings/lib/src/battery.dart b/session_shells/ermine/settings/lib/src/battery.dart
index 2c81f49..2b9acf9 100644
--- a/session_shells/ermine/settings/lib/src/battery.dart
+++ b/session_shells/ermine/settings/lib/src/battery.dart
@@ -9,11 +9,14 @@
import 'package:fidl_fuchsia_power/fidl_async.dart';
import 'package:fidl_fuchsia_ui_remotewidgets/fidl_async.dart';
import 'package:fuchsia_services/services.dart' show StartupContext;
+import 'package:internationalization/strings.dart' as strings;
import 'package:quickui/quickui.dart';
/// Defines a [UiSpec] for visualizing battery.
class Battery extends UiSpec {
- static const _title = 'Battery';
+ // Localized strings.
+ static String get _title => strings.battery();
+
static const _checkBatteryDuration = Duration(seconds: 1);
BatteryModel model;
diff --git a/session_shells/ermine/settings/lib/src/brightness.dart b/session_shells/ermine/settings/lib/src/brightness.dart
index cbc99b2..c086b5a 100644
--- a/session_shells/ermine/settings/lib/src/brightness.dart
+++ b/session_shells/ermine/settings/lib/src/brightness.dart
@@ -9,6 +9,7 @@
import 'package:fidl_fuchsia_ui_brightness/fidl_async.dart';
import 'package:fidl_fuchsia_ui_remotewidgets/fidl_async.dart';
import 'package:fuchsia_services/services.dart' show StartupContext;
+import 'package:internationalization/strings.dart' as strings;
import 'package:quickui/quickui.dart';
/// Defines a [UiSpec] for controlling screen brightness.
@@ -25,11 +26,13 @@
/// ----------------------
/// * {A} - Auto icon, {b} Brightness min icon, {B} Brightness max icon.
class Brightness extends UiSpec {
- static const _title = 'Brightness';
- static const _buttonLabel = 'Auto';
static const progressAction = 1;
static const autoAction = 2;
+ // Localized strings.
+ static String get _title => strings.brightness();
+ static String get _auto => strings.auto();
+
_BrightnessModel _model;
Brightness(ControlProxy control) {
@@ -69,7 +72,7 @@
Group(title: _title, values: [
Value.withIcon(IconValue(codePoint: Icons.brightness_auto.codePoint)),
Value.withProgress(ProgressValue(value: value, action: progressAction)),
- Value.withText(TextValue(text: _buttonLabel)),
+ Value.withText(TextValue(text: _auto)),
]),
]);
}
@@ -80,7 +83,7 @@
Value.withIcon(IconValue(codePoint: Icons.brightness_low.codePoint)),
Value.withProgress(ProgressValue(value: value, action: progressAction)),
Value.withIcon(IconValue(codePoint: Icons.brightness_high.codePoint)),
- Value.withButton(ButtonValue(label: _buttonLabel, action: autoAction)),
+ Value.withButton(ButtonValue(label: _auto, action: autoAction)),
]),
]);
}
diff --git a/session_shells/ermine/settings/lib/src/memory.dart b/session_shells/ermine/settings/lib/src/memory.dart
index 58d904d..7292b73 100644
--- a/session_shells/ermine/settings/lib/src/memory.dart
+++ b/session_shells/ermine/settings/lib/src/memory.dart
@@ -10,11 +10,14 @@
import 'package:fidl_fuchsia_memory/fidl_async.dart';
import 'package:fidl_fuchsia_ui_remotewidgets/fidl_async.dart';
import 'package:fuchsia_services/services.dart' show StartupContext;
+import 'package:internationalization/strings.dart' as strings;
import 'package:quickui/quickui.dart';
/// Defines a [UiSpec] for visualizing memory.
class Memory extends UiSpec {
- static const _title = 'Memory';
+
+ // Localized strings.
+ static String get _memory => strings.memory();
MemoryModel model;
@@ -48,7 +51,7 @@
String usedString = (used).toStringAsPrecision(3);
String totalString = (total).toStringAsPrecision(3);
return Spec(groups: [
- Group(title: _title, values: [
+ Group(title: _memory, values: [
Value.withProgress(ProgressValue(value: value)),
Value.withText(TextValue(text: '${usedString}GB / ${totalString}GB')),
]),
diff --git a/session_shells/ermine/shell/BUILD.gn b/session_shells/ermine/shell/BUILD.gn
index 693d0b2..e9211ef 100644
--- a/session_shells/ermine/shell/BUILD.gn
+++ b/session_shells/ermine/shell/BUILD.gn
@@ -109,9 +109,12 @@
"//sdk/fidl/fuchsia.ui.views",
"//src/experiences/lib/quickui",
"//src/experiences/session_shells/ermine/settings",
+ "//src/experiences/session_shells/ermine/internationalization",
"//third_party/dart-pkg/git/flutter/packages/flutter",
+ "//third_party/dart-pkg/git/flutter/packages/flutter_localizations",
"//third_party/dart-pkg/pub/flutter_svg",
"//third_party/dart-pkg/pub/uuid",
+ "//third_party/dart/third_party/pkg/intl",
"//topaz/lib/tiler",
"//topaz/public/dart/fuchsia_inspect",
"//topaz/public/dart/fuchsia_logger",
diff --git a/session_shells/ermine/shell/lib/main.dart b/session_shells/ermine/shell/lib/main.dart
index 44c61d1..88e7df6 100644
--- a/session_shells/ermine/shell/lib/main.dart
+++ b/session_shells/ermine/shell/lib/main.dart
@@ -3,19 +3,60 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:lib.widgets/model.dart';
import 'package:fuchsia_logger/logger.dart';
+import 'package:internationalization/localizations_delegate.dart'
+ as localizations;
+import 'package:internationalization/current_locale.dart';
+import 'package:internationalization/supported_locales.dart'
+ as supported_locales;
+import 'package:intl/intl.dart';
import 'src/models/app_model.dart' show AppModel;
import 'src/widgets/app.dart' show App;
Future<void> main() async {
+ // TODO(fmil): Add a dynamically changing value of the locale, based on system
+ // preferences.
+ final providers = Providers()
+ ..provideValue(CurrentLocale(Locale.fromSubtags(languageCode: 'en')));
+
setupLogger(name: 'ermine');
final model = AppModel();
- final app = App(model: model);
+ final app = _Localized(model);
- runApp(app);
+ runApp(ProviderNode(providers: providers, child: app));
await model.onStarted();
}
+
+/// This is a localized version of the Ermine shell localized app. It is the
+/// same as the original App, but it also has the current locale injected.
+class _Localized extends StatelessWidget {
+ final AppModel _model;
+ const _Localized(this._model);
+
+ @override
+ Widget build(BuildContext context) {
+ return Provide<CurrentLocale>(
+ builder: (BuildContext context, Widget child, currentLocale) {
+ // Changing the default locale here ensures that any non-Flutter
+ // code sees the locale change as well.
+ Intl.defaultLocale = currentLocale.unicode();
+ return MaterialApp(
+ home: App(model: _model),
+ debugShowCheckedModeBanner: false,
+ locale: currentLocale.value,
+ localizationsDelegates: [
+ localizations.delegate(),
+ GlobalMaterialLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ ],
+ supportedLocales: supported_locales.locales,
+ );
+ });
+ }
+}
diff --git a/session_shells/ermine/shell/lib/src/widgets/ask/ask_text_field.dart b/session_shells/ermine/shell/lib/src/widgets/ask/ask_text_field.dart
index 6541e4c..ffef0dd 100644
--- a/session_shells/ermine/shell/lib/src/widgets/ask/ask_text_field.dart
+++ b/session_shells/ermine/shell/lib/src/widgets/ask/ask_text_field.dart
@@ -3,6 +3,9 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
+// Includes the strings used for the button labels. Please only use the labels
+// defined there, and add new ones if you need them.
+import 'package:internationalization/strings.dart' as strings;
import '../../models/ask_model.dart';
import '../../utils/styles.dart';
@@ -59,7 +62,7 @@
child: Padding(
padding: EdgeInsets.only(right: 20),
child: Text(
- 'TYPE TO ASK',
+ strings.typeToAsk().toUpperCase(),
style: Theme.of(context).textTheme.body1.copyWith(
color: Colors.white,
backgroundColor: Colors.black,
diff --git a/session_shells/ermine/shell/lib/src/widgets/status/status.dart b/session_shells/ermine/shell/lib/src/widgets/status/status.dart
index 95306d9..53696e8 100644
--- a/session_shells/ermine/shell/lib/src/widgets/status/status.dart
+++ b/session_shells/ermine/shell/lib/src/widgets/status/status.dart
@@ -2,8 +2,9 @@
// 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:fidl_fuchsia_ui_remotewidgets/fidl_async.dart';
+import 'package:flutter/material.dart';
+import 'package:internationalization/strings.dart' as strings;
import 'package:quickui/uistream.dart';
import '../../models/status_model.dart';
@@ -218,11 +219,11 @@
height: kRowHeight,
child: Row(
children: <Widget>[
- _buildButton('Restart', null),
+ _buildButton(strings.restart(), null),
Padding(padding: EdgeInsets.only(right: kPadding)),
- _buildButton('Shutdown', null),
+ _buildButton(strings.shutdown(), null),
Spacer(),
- _buildButton('Settings', model.launchSettings),
+ _buildButton(strings.settings(), model.launchSettings),
],
),
);
diff --git a/session_shells/ermine/shell/lib/src/widgets/story/tile_chrome.dart b/session_shells/ermine/shell/lib/src/widgets/story/tile_chrome.dart
index 82801e8..6be7856 100644
--- a/session_shells/ermine/shell/lib/src/widgets/story/tile_chrome.dart
+++ b/session_shells/ermine/shell/lib/src/widgets/story/tile_chrome.dart
@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter/material.dart';
+import 'package:internationalization/strings.dart' as strings;
import '../../utils/styles.dart';
@@ -116,7 +117,7 @@
// Cancel edit button.
if (editing)
- _buildTitleBarTextButton(context, 'Cancel', onTapCancel),
+ _buildTitleBarTextButton(context, strings.cancel(), onTapCancel),
// Story name.
Expanded(
@@ -131,7 +132,8 @@
textAlign: TextAlign.center,
decoration: InputDecoration(
contentPadding: EdgeInsets.zero,
- hintText: ' NAME THIS STORY',
+ // TODO(fmil): I18N There should be no hard-coded paddings in the text.
+ hintText: ' ${strings.nameThisStory().toUpperCase()}',
border: InputBorder.none,
isDense: true,
),
@@ -148,7 +150,7 @@
// Done edit button.
if (editing)
- _buildTitleBarTextButton(context, 'Done', onTapDone),
+ _buildTitleBarTextButton(context, strings.done(), onTapDone),
if (editing)
Padding(
diff --git a/session_shells/ermine/shell/lib/src/widgets/topbar/topbar.dart b/session_shells/ermine/shell/lib/src/widgets/topbar/topbar.dart
index e4c3d3c..db0a5eb 100644
--- a/session_shells/ermine/shell/lib/src/widgets/topbar/topbar.dart
+++ b/session_shells/ermine/shell/lib/src/widgets/topbar/topbar.dart
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:intl/intl.dart';
import 'package:flutter/material.dart';
+import 'package:internationalization/strings.dart' as strings;
+import 'package:intl/intl.dart';
import '../../models/topbar_model.dart';
import '../../utils/styles.dart';
@@ -36,7 +37,7 @@
children: <Widget>[
// Overview.
Button(
- child: Text('OVERVIEW'),
+ child: Text(strings.overview().toUpperCase()),
decoration: BoxDecoration(
border: Border(
right: BorderSide(
@@ -49,7 +50,7 @@
),
// Recents.
Button(
- child: Text('RECENTS'),
+ child: Text(strings.recents().toUpperCase()),
decoration: BoxDecoration(
border: Border(
right: BorderSide(
@@ -87,7 +88,7 @@
// Ask.
Button(
key: model.askButtonKey,
- child: Text('ASK'),
+ child: Text(strings.ask().toUpperCase()),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
@@ -120,7 +121,7 @@
),
// Story title.
// Center(
- // child: Text('BROWSER', textAlign: TextAlign.center),
+ // child: Text(strings.browser().toUpperCase(), textAlign: TextAlign.center),
// ),
],
),