Локализация JavaScript/TypeScript

Введение

Подключение функции rk в компоненте

В первую очередь нужно подключить функцию для перевода с помощью RequireJS плагин i18n!. Зависимость должна содержать имя интерфейсного модуля, чей словарь вы хотите использовать.

  • JavaScript
define('SBIS3/Demo/NewButton', [ ..., 'i18n!SBIS3'], function(..., rk) {...});
  • TypeScript
import rk = require('i18n!SBIS3');
...

Локализация на сервере

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

caption: rk('Скачать') + '...'

Нужно, чтобы переводимая фраза целиком передавалась аргументом в функцию rk():

caption: rk('Скачать...')

Связано это с тем, что на сервере функция rk() возвращает не обычную строку, а объект, строковое значение которого вычисляется "лениво" при приведении к типу "Строка". Поэтому прототип класса должен хранить переводимые свойства в экземплярах подобных объектов, а не строк.

Локализация опций и переменных шаблона компонента

Значение опции компонента может быть локализовано в следующих случаях:

  1. В JS-модуле компонента для опции создан доклет с тегом @translatable и начальное значение обёрнуто в функциую rk(). Доклет должен начинаться с тега @cfg, чтобы описание было корректно интерпретировано (см. Документирование опции).
/**
 * @cfg {String} Устанавливает надпись на кнопке.
 * @translatable
 */
caption: rk('Скачать')
* Когда для локализации определён контекст перевода:
<pre class="brush: js">
/&#42;&#42;
 &#42; @cfg {String} Устанавливает надпись на кнопке.
 &#42; @translatable
 &#42;/
caption: rk('Скачать', 'Кнопка на главной странице')
</pre>
  1. В разметке компонента значение опции обёрнуто в конструкции вида {[ ... ]} (см. Локализация WML).
<SBIS3.Demo.NewButton caption="{[Загрузить]}" />
* Когда выполнено условие из пункта 1, оборачивать значение опции компонента необязательно (за исключением случая с [опциями типа Content](/doc/platform/developmentapl/interface-development/internalization/javascript-localization/#localization-of-component-options-content)).
<pre class="brush: html">
&lt;SBIS3.Demo.NewButton caption="Загрузить" /&gt;
</pre>

Локализация @typedef

Чтобы локализовать опции собственных типов данных, которые определены в @typedef, их перечисляют через одинарный пробел в теге @translatable.

/**
 * @typedef {Object} Columns
 * @property {String} title
 * @property {String} field
 * @property {String|Boolean} extendedTooltip
 * @translatable title extendedTooltip
 */

Локализация строковых констант

Для локализации строковых констант используйте функцию rk().

console.log(rk('Аналитик', 'ИмяРоли'));

где "Аналитик" — локализуемая строка, а "ИмяРоли" — контекст перевода.

Конкатенация строк

В исходном JavaScript коде можно встретить склеенные строки следующим образом:

throw Error(rk('Ошибка: "') + message + rk('" с кодом ') + code);

Из-за того, что строки формируются динамически, и в rk нельзя передавать переменные, для их локализации рекомендуется использовать функцию template:

import {template} from 'Types/formatter';
 
const errorString = rk('Задача №${id} уже находится в статусе "${status}".');
throw new Error(template(errorString, {
   id: 42,
   status: rk('Выполнение')
}));

При локализации, например, на английский язык, в словаре переводов en-US.json ключи локализации и его перевод будут такими:

{
"Задача №${id} уже находится в статусе \"${status}\"." : "The task with id ${id} has \"${status}\" state already",
"Выполнение": "In progress"
}

Локализация дат

Используйте Types/formatter:date.

// My/SampleControl.ts
import {Control, TemplateFunction} from 'UI/Base';
import {date as format} from 'Types/formatter';
import template = require('wml!My/SampleTemplate');
 
export default class SampleControl extends Control {
   protected _template: TemplateFunction = template;
   protected _format: Function = format;
   protected _article: object = {};
   protected _beforeMount(): void {
      this._article.created= new Date();
   }
}
<!-- WML -->
This article was created at {{ _format(_article.created, _format.FULL_DATETIME) }}.

Склонение слова в зависимости от числа

Ранее задачу изменения формы слова Вы могли решать с использованием функции wordCaseByNumber. Однако использование этой функции признано устаревшим способом, в скором времени она будет удалена из веб-фреймворка WS.

require(['Core/helpers/i18n/wordCaseByNumber'], function(wordCaseByNumber) {
   console.log(wordCaseByNumber(10, 'рублей', 'рубль', 'рубля')); // 'рублей'
});

В функции rk() доступен необязательный числовой параметр, от значения которого можно установить соответствующую форму слова для текущей локализации.

// новый формат вызова функции
rk(stringToLocalization, contextString, number)
 
// второй вариант вызова функции, где второй аргумент number — число
rk(stringToLocalization, number)

При склонении слова в зависимости от числа предполагается, что исходная строка stringToLocalization будет следующего вида: запись(-и, -ей) . К исходной строке добавляются скобки с вариантами окончания слова. Такой вид строки нужен только для того, чтобы выделить её среди остальных в словаре переводов. Добавленные в скобках окончания никак не повлияют на перевод или форму слова при локализации. Если на сервисе отключена локализация, то строка будет выводиться в исходном виде.

Чтобы через функцию rk() добавить склонение слова в зависимости от числа, Вам нужно:

  1. В исходном коде обернуть строку функцией rk().
// число, которое соответствует форме склоняемого слова
var numberOfRecords;
...
tooltip: format(rk('В таблице БД хранится $n$s$ $row$s$'),
         object = {
            n: numberOfRecords ,
            row: rk("запись(-и,-ей)", numberOfRecords)
         });
  1. В словарях перевода компонента: ru-RU.json (для локализации на русском языке), en-US.json (для локализации на английском языке) и других — добавить "ключ:значение" (см. Правила):
/* ru-RU.json */
{
   "plural#запись(-и,-ей)": "запись|записи|записей|записи"
}
 
/* en-US.json */
{
   "plural#запись(-и,-ей)": "record|records"
}

В этом случае вызов функции rk('запись(-и,-ей)', 21) вернет для локализации:

  • на русском языке — "запись";
  • на английском языке — "records";
  • на стенде без локализации — "запись(-и,-ей)".

Правила добавления строки в словарь переводов для назначения разных форм слова и их локализации

В словарь переводов локализуемую строку добавляют с префиксом plural, которые разделяются символом # (решётка). В качестве перевода устанавливают строку, которая содержит слова в нужных склонениях, разделенные через | (pipe, вертикальная линия).

/* ru-RU.json */
"plural#запись(-и,-ей)": "запись|записи|записей|записи"

/* en-US.json */
"plural#запись(-и,-ей)": "record|records"

Для локализации на русском языке используются 4 слова, располагающиеся в следующем порядке:

  1. для единицы. Например одна "запись" или один "день".
  2. для диапазона от 2 до 4. Например две "записи" или два "дня".
  3. для диапазона от 5 до 9. Например пять "записей" или пять "дней".
  4. для дроби. Например полторы "записи" или полтора "дня".

Для локализации на английском языке используется 2 слова, располагающиеся в следующем порядке:

  • Первое слово — для единицы. Например one "record".
  • Второе слово — для нескольких. Например two "records".

Правила для остальных языков Вы можете найти здесь. Сейчас для локализации поддерживаются только русский и английский языки.

Если в функции rk мы указываем контекст и количество для склонения, то в словаре должно быть записано:

"Контекст@@plural#запись(-и,-ей)": "record|records"

Пробелы и управляющие символы в начале и в конце локализуемых строк

Для строковых констант, которые планируется локализовать, устанавливается особое требование в использовании пробелов и управляющих символов ("\t" — горизонтальная табуляция; "\n" — перевод строки; "\r" — возврат каретки.) в начале и в конце таких строк:

  1. Локализуемая строка не должна содержать символы пробелов в начале или в конце:
// Неправильно
rk('  Текст  ')
// Правильно
rk('Текст')
  1. Локализуемая строка не должна содержать символы перевода строки.
// Неправильно
rk('\nТекст')
// Правильно
'\n' + rk('Текст')

Ключи с невидимыми символами на концах строки сильно затруднят перевод. Например, строки "Сохранить", "\nСохранить" и " Сохранить" придётся переводить отдельно.