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

Введение

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

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

  • JavaScript

    define('SBIS3/Demo/NewButton', [ ..., 'i18n!SBIS3'], function(..., rk) {...});

  • TypeScript

    import * as rk from 'i18n!SBIS3';
    ...

или:

import rk = require('i18n!SBIS3');
...

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

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

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

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

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

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

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

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

  1. В JS-модуле компонента для опции создан доклет с тегом @translatable и начальное значение обёрнуто в функциую rk(). Доклет должен начинаться с тега @cfg, чтобы описание было корректно интерпретировано (см. Документирование опции).
    /**
     * @cfg {String} Устанавливает надпись на кнопке.
     * @translatable
     */
    caption: rk('Скачать')
    • Когда для локализации определён контекст перевода:
      /**
       * @cfg {String} Устанавливает надпись на кнопке.
       * @translatable
       */
      caption: rk('Скачать', 'Кнопка на главной странице')
  2. В разметке компонента значение опции обёрнуто в конструкции вида {[ ... ]} (см. Локализация WML).
    <SBIS3.Demo.NewButton caption="{[Загрузить]}" />
    • Когда выполнено условие из пункта 1, оборачивать значение опции компонента необязательно (за исключением случая с опциями типа Content).
      <SBIS3.Demo.NewButton caption="Загрузить" />

Локализация @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 нельзя передавать переменные, для их локализации рекомендуется использовать функцию format:

define(..., [..., 'Core/helpers/String/format'], function(..., format) {
   ...
   var formatString = rk('Ошибка: "$message$s$" с кодом $code$s$'),
      object = {
         message: 'Текст ошибки',
         code: 'Код ошибки'
      };
   throw Error(format(object, formatString));
});

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

{
"Ошибка: \"$message$s$\" с кодом $code$s$ " : "Error message: \"$message$s$\" with status code $code$s$ "
}

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

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

  • TypeScript

    // 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)
             });
  2. В словарях перевода компонента: 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('Текст')
  2. Локализуемая строка не должна содержать символы перевода строки.
    // Неправильно
    rk('\nТекст')
    // Правильно
    '\n' + rk('Текст')

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