Как инициализировать интернационализацию для полимерного элемента до его загрузки на страницу
Я использую Dart для создания приложения Polymer. Поскольку я использую возможности интернационализации Дарта в элементах Polymer, я хочу инициализировать сообщения о интернационализации до создания элемента Polymer и отображения соответствующих сообщений для данного языка в пределах элемента Polymer.
Как это можно сделать? Кто-нибудь успешно использовал Полимер с интернационализацией?
пс. Я выполнил этот пример, чтобы настроить интернационализацию
Ниже приведенное по умолчанию приложение Polymer от Dart Editor плюс код, который я добавил.
messages_en.dart
library messages_en;
import 'package:intl/intl.dart';
import 'package:intl/message_lookup_by_library.dart';
final messages = new MessageLookup();
class MessageLookup extends MessageLookupByLibrary {
get localeName => 'en';
final messages = {
"myMsg" : () => Intl.message("MY MESSAGE")
};
}
messages_all.dart
library messages_all;
import'dart:async';
import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
import 'package:intl/intl.dart';
import 'messages_en.dart' as en;
MessageLookupByLibrary _findExact(localeName) {
switch (localeName) {
case 'en': return en.messages;
default: return null;
}
}
initializeMessages(localeName) {
initializeInternalMessageLookup(() => new CompositeMessageLookup());
messageLookup.addLocale(localeName, _findGeneratedMessagesFor);
return new Future.value();
}
MessageLookupByLibrary _findGeneratedMessagesFor(locale) {
var actualLocale = Intl.verifiedLocale(locale, (x) => _findExact(x) != null);
if (actualLocale == null) return null;
return _findExact(actualLocale);
}
clickcounter.dart
import 'package:polymer/polymer.dart';
import 'package:intl/intl.dart';
import 'dart:async';
import 'messages_all.dart';
import 'messages_en.dart' as en;
/**
* A Polymer click counter element.
*/
@CustomTag('click-counter')
class ClickCounter extends PolymerElement {
@published int count = 0;
@observable var messagesLoaded = false;
ClickCounter.created() : super.created() {
var enMessagesFuture = initializeMessages('en');
Future.wait([enMessagesFuture]).then((_) => messagesLoaded = true);
}
void increment() {
count++;
}
}
clickcounter.html
<polymer-element name="click-counter" attributes="count">
<template>
<style>
div {
font-size: 24pt;
text-align: center;
margin-top: 140px;
}
button {
font-size: 24pt;
margin-bottom: 20px;
}
</style>
<div>
<button on-click="{{increment}}">Click me</button><br>
<span>(click count: {{count}})</span>
<br>
<br>
<span>current locale: {{Intl.getCurrentLocale()}}</span>
<br>
<br>
<template if="{{messagesLoaded}}">
<span>intl message: {{How can I extract myMsg here?}}</span>
</template>
</div>
</template>
<script type="application/dart" src="clickcounter.dart"></script>
</polymer-element>
Ответы
Ответ 1
Я написал образец для этого, который вы можете найти в
https://github.com/dart-lang/sample-polymer-intl/blob/master/README.md
или см. https://www.dartlang.org/samples/ в разделе "Полимер и интернационализация"
Существенный бит выглядит следующим образом:
// Polymer should call this method automatically if the value of
// [selectedLocale] changes.
void selectedLocaleChanged() {
// We didn't provide en_US translations. We expect it to use the default
// text in the messages for en_US. But then we have to not try and
// initialize messages for the en_US locale. dartbug.com/15444
if (selectedLocale == 'en_US') {
updateLocale('en_US');
return;
}
// For the normal case we initialize the messages, wait for initialization
// to complete, then update all (all 1 of) our messages.
initializeMessages(selectedLocale).then(
(succeeded) => updateLocale(selectedLocale));
}
// When the user chooses a new locale, set the default locale for the
// whole program to that and update our messages. In a large program this
// could get to be a large method. Also, other components might want to
// observe the default locale and update accordingly.
void updateLocale(localeName) {
Intl.defaultLocale = selectedLocale;
helloWorld = helloFromDart();
}
Ответ 2
У меня есть что-то работающее:
добавить получателя в ClickCounter
String get locale => Intl.getCurrentLocale();
и измените HTML на
текущий язык: {{locale}}
создать трансформатор
library i18n_transformer;
import 'package:polymer_expressions/filter.dart' show Transformer;
import 'package:intl/intl.dart' show Intl;
class I18nTransformer extends Transformer<dynamic,String> {
Map<String,dynamic> _labels;
String language;
String missingIndicator;
I18nTransformer(this._labels, {this.language: 'en', this.missingIndicator: '#'});
String forward(params) {
String id;
if(params is String) {
id = params;
} else if(params is Map) {
if(!(params['0'] is String)) {
throw 'Error: The first list element must contain the label id as string.';
}
id = params['0'];
} else {
throw 'Error: The I18nTransformer expects either a label id as string or a list containing a label id and parameters.';
}
var msg = Intl.message('', name: id);
if(msg == null || msg.isEmpty) {
return '${missingIndicator}(${language}-${params})';
}
}
dynamic reverse(String label) {
return 'reverse not supported';
}
}
и добавьте следующее в свой ClickCounter
final I18nTransformer i18n = new I18nTransformer(null, language: 'en');
и в HTML
<p>{{ 'myMsg' | i18n }}</p>
<p>{{ 'myMsg2' | i18n }}</p> <!-- sample output for a not existing message -->
Комментарий:
Вы можете сделать более простой Transformer < String, String > но я предпочитаю использовать Transformer < dynamic, String >
чтобы иметь возможность предоставлять дополнительные параметры (еще не реализованные в трансформаторе) в форме
{{ {0: 'myMsg', 1:'x'} | i18n }}
Линейные листы еще не поддерживаются в PolymerExpressions, поэтому вам нужно добавить некоторые фиктивные ключи, такие как 0, 1,...
В моей реализации первый ключ должен быть 0, чтобы работать, как вы можете видеть в коде.