Как инициализировать интернационализацию полимерного элемента перед его загрузкой на страницу

Я использую Dart для создания приложения Polymer. Поскольку я использую возможности интернационализации 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>

person Peter    schedule 02.12.2013    source источник


Ответы (2)


Я написал для этого образец, который вы можете найти по адресу 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();
}
person Alan Knight    schedule 02.12.2013
comment
Привет, Алан, я добавил свой код выше. У меня есть пара вопросов: 1) Intl.getCurrentLocale() ничего не печатает; нужна ли интернационализация дополнительная инициализация? 2) Как я могу напечатать интернационализированную строку myMsg в clickcounter.html? - person Peter; 04.12.2013
comment
Intl.getCurrentLocale() и Intl.defaultLocal возвращают для меня 'en_US', используя предоставленный вами код. В отладчике, а не в HTML, мне еще предстоит это попробовать. - person Günter Zöchbauer; 04.12.2013
comment
@Alan Knight Надеюсь, вы не возражаете, что я добавляю ссылку на ваш пример интернационализации/локализации здесь, которую вы предоставили в группе Dart: codereview.chromium.org/105073003 - person Günter Zöchbauer; 05.12.2013
comment
@Alan Knight Спасибо за код! Наконец-то я заработал! :) - person Peter; 05.12.2013
comment
Я не против. Я собирался подождать, пока не появится более постоянная ссылка, но ладно. - person Alan Knight; 05.12.2013
comment
Изменен ответ, чтобы он ссылался на пример кода, поэтому приведенные выше комментарии, вероятно, теперь менее актуальны. - person Alan Knight; 10.12.2013

У меня что-то работает:

добавить геттер в 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, чтобы работать, как вы можете видеть в коде.

person Günter Zöchbauer    schedule 04.12.2013