Перейти к содержанию

Лучшие практики локализации

Обеспечение повторной оценки при рендеринге

Каждый раз, когда вызывается функция msg, она возвращает версию заданной строки или шаблона Lit в активной локали. Однако этот результат - обычная строка или шаблон; он не способен внутренне пересмотреть себя при смене локали.

По этой причине важно писать вызовы msg таким образом, чтобы обеспечить их переоценку при каждом запуске метода Lit render. Таким образом, при смене локали будет возвращена правильная строка или шаблон для последней локали.

Одна из ситуаций, в которой легко допустить ошибку, - это локализация значений свойств по умолчанию. Может показаться естественным написать так:

1
2
3
4
5
6
// Don't do this!
label = msg('Default label')

render() {
  return html`<button>${this.label}</button>`;
}

Однако вышеописанная схема не дает возможности обновлять метку по умолчанию при изменении локали. Значение по умолчанию будет застревать на версии локали, которая была активна в момент создания элемента.

Простым исправлением является перемещение возврата значения по умолчанию непосредственно в метод рендеринга:

1
2
3
render() {
  return html`<button>${this.label ?? msg('Default label')}</button>`;
}

Кроме того, для создания более естественного интерфейса можно использовать пользовательский геттер/сеттер:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private _label?: string;

@property()
get label() {
    return this._label ?? msg('Default label');
}

set label(label: string) {
    this._label = label;
}

render() {
    return html`<button>${this.label}</button>`;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
static properties = {
    label: {}
};

get label() {
    return this._label ?? msg('Default label');
}

set label(label) {
    this._label = label;
}

render() {
    return html`<button>${this.label}</button>`;
}

Избегайте ненужной HTML-разметки

Хотя @lit/localize полностью поддерживает встраивание HTML-разметки в локализованные шаблоны, лучше избегать этого, когда это возможно. Это связано с тем, что:

  1. Переводчикам проще работать с простыми строковыми фразами, а не с фразами со встроенной разметкой.
  2. Это позволяет избежать ненужной работы по повторному переводу при изменении разметки, например, при добавлении класса, который влияет на внешний вид, не меняя смысла.
  3. Смена локалей обычно происходит быстрее, поскольку обновлять нужно меньше частей DOM. Кроме того, в ваши пакеты будет включено меньше JavaScript, поскольку общую разметку не нужно будет дублировать в каждом переводе.

Не идеальный вариант:

1
2
3
4
5
render() {
  // Don't do this! There's no reason to include the <button> tag in this
  // localized template.
  return msg(html`<button>Launch rocket</button>`);
}

Идеально:

1
2
3
4
5
render() {
  // Much better! Now the phrase "Launch rocket" can be translated more easily
  // in isolation.
  return html`<button>${msg('Launch rocket')}</button>`;
}

Разбиение шаблонов на более мелкие части также может быть полезным:

1
2
3
4
5
6
7
render() {
  // Не делайте этого!
  return msg(html`
  <p>The red button makes the rocket go up.</p>
  <p>The green button makes the rocket do a flip.</p>
  `);
}

1
2
3
4
5
6
7
8
render() {
  // Лучше! Переводчикам не нужно обрабатывать разметку, и каждое предложение
  // может быть переведено независимо.
  return html`
  <p>${msg('The red button makes the rocket go up.')}</p>
  <p>${msg('The green button makes the rocket do a flip.')}</p>
  `;
}

При использовании режима трансформации шаблоны будут автоматически сплющиваться, чтобы сделать их как можно меньше и эффективнее. После трансформации в приведенном выше примере не будет никаких заполнителей, поскольку он знает, что строки можно напрямую объединять в HTML-шаблоны.

Есть случаи, когда HTML должен быть включен в локализованный шаблон. Например, когда в середине фразы требуется HTML-тег:

1
2
3
render() {
  return msg(html`Lift off in <b>T-${this.countdown}</b> seconds`);
}

Безопасный реэкспорт или переназначение API локализации

Статический анализ используется для определения того, когда вы вызываете функцию @lit/localize msg и другие API, а не другую функцию с тем же именем.

Можно реэкспортировать или переназначить функцию msg и другие API, и в большинстве случаев это будет работать.

Однако некоторые паттерны могут быть слишком динамичными, чтобы статический анализ мог их понять. Если сообщение не извлекается, а вы переназначили или реэкспортировали функцию msg, это может быть причиной.

Чтобы заставить функцию анализироваться как API @lit/localize, вы можете использовать комментарий JSDoc @type в JavaScript или приведение типа в TypeScript:

1
const myMsg = ... as typeof import('@lit/localize').msg;
1
2
/** @type import('@lit/localize').msg */
const myMsg = ...;

Комментарии