Языки. Локаль
Кодовое обозначение локали
Чтобы различать локали, принято использовать следующие кодовые обозначения:
[язык]-[СТРАНА]
- [язык] — двухбуквенный код языка по стандарту ISO 639-1.
- [СТРАНА] — двухбуквенный код страны по стандарту ISO 3166-1.
Например, ru-RU
(Русский язык в России) или uk-UA
(Украинский язык в Украине).
Один язык в нескольких странах
Один язык может использоваться в нескольких странах. Например, для английского языка в Британии и США используют кодовые обозначения en-GB
и en-US
соответственно.
В контексте локализации различие языка заключается в написании одного и того же слова, а иногда — формата дат.
en-GB | en-US | ru-RU |
---|---|---|
Upload cancelled. | Upload canceled. | Загрузка отменена. |
Invitation to a dialogue. | Invitation to a dialog. | Приглашение к диалогу. |
Due date 31.01.20 | Due date 01.31.20 | Срок до 31 января 2020 |
Несколько языков внутри одной страны
Wasaby Framework позволяет поддерживать несколько языков внутри одной страны. Например, для России можно создать словарь как на русском, так и на татарском языке. Такой функционал даёт преимущество Wasaby Framework в том, что можно создавать продукт с возможностью выбора локализации web-приложения на негосударственный язык (язык меньшинства).
Язык ключей перевода
Не имеет значения какой язык используется в исходных файлах. Строки могут быть как на русском, так и на украинском или китайском языках. При локализации в Genie в окне назначения переводов будут отображены все строки, найденные в исходных файлах. Они будут соответствовать локали, установленной для web-приложения (при конвертации ресурсов проекта или развороте отладочного стенда) по умолчанию.
Изменение локали с помощью меню выбора языка
Для изменения текущего языка web-приложения, как правило, используют меню выбора языка. Для крупных web-приложений, например online.sbis.ru, оно уже создано. Такое меню выполняет, как правило, два действия:
- Устанавливает cookie с названием "lang" (см. Как устанавливается cookie с названием lang).
- Устанавливает язык в настройках профиля пользователя.
- Перезагружает web-страницу.
Ниже приведён пример кода, изменяющего локаль в cookie:
define(
...
[
... ,
'I18n/i18n'
],
function(... , i18n) {
...
this.getChildControlByName('УстановитьУкраинскийЯзык').subscribe('onClick', function() {
// Устанавливаем локализацию на украинский язык
i18n.controller.setLocale('uk-UA');
// Перезагружаем страницу
window.location = '/';
// альтернативный способ перезагрузки страницы
// window.location.reload();
});
}
);
Как устанавливается cookie с названием lang
Язык, на котором пользователь увидит интерфейс, определяется по содержимому cookie
с названием lang
. Значение lang
устанавливается по следующим правилам:
- В функции
init
прикладной разработчик устанавливает значениеlang
с помощью методаsave
статического класса Configuration, экспортируемого из библиотеки I18n/i18n. - Если в
init
этого не производилось, то механизм синглтона производит поиск параметраlang
в запросе к странице (адресная строка web-браузера). Если параметр найден, то его значение будет установлено в качествеcookie lang
. - Если параметр
lang
отсутствует, то вcookie lang
устанавливается кодовое обозначение языка web-браузера пользователя.
Механизм получения языка
В приложениях СБИС выбор языка основывается на настройках профиля авторизованного пользователя. В зависимости от типа приложения механизмы получения языка могут варьироваться.
Глобально можно выделить две стратегии получения языка:
- Из настроек профиля авторизованного пользователя.
- Из настроек системы, если нет доступа к профилю.
Приложения без аутентификации пользователей используют язык системы. Например, showcase, отправщик SMS.
Для web-приложений.
- Из настроек профиля авторизованного пользователя, через провайдер языка посредством транспорта cookie lang.
- Из настроек браузера, если нет доступа к профилю.
Для offline-приложений существует две базовых стратегии получения языка:
- Из настроек профиля авторизованного пользователя через провайдер языка.
- Из настроек ОС, если нет доступа к профилю.
Для приложения SBIS3 Plugin существует специфичный сценарий. В приложении одновременно может быть авторизовано несколько пользователей, которые принадлежат разным профилям. В таком случае настройки языка задаются настройками приложения.
Реализация провайдера языка
Для создания собственного провайдера языка необходимо реализовать интерфейс IAppLanguageProvider и зарегистрировать его в фабрике обработчиков.
- Создайте класс-наследник
IAppLanguageProvider
и переопределите у него методResolveCurrentLanguage()
.
Пример реализации провайдера, который возвращает русский язык:
class MyProvider : public IAppLanguageProvider
{
private:
String ResolveCurrentLanguage() const noexcept override
{
return L"ru-RU";
}
};
- Зарегистрируйте в фабрике обработчиков. Пример регистрации обработчика языка:
Factory::TemplateItem< IAppLanguageProvider, MyProvider > LANG ( GetLanguageProviderFactory() );
Определение языка по настройкам браузера без доступа к профилю пользователя
Предпочитаемый язык определяется по заголовку "Accept-Language". Если заголовок не задан, то языком страницы объявляется Английский — 'en'.
Формальное описание грамматики заголовка:
Accept-Language = "Accept-Language" ":"
1#( language-range [ ";" "q" "=" qvalue ] )
language-range = ( ( 1 * 8ALPHA *( "-" 1 * 8ALPHA ) ) | "*" )
qvalue = ( "0" [ "." 0 * 3DIGIT ] )
| ( "1" [ "." 0 * 3("0") ] )
Подробнее о заголовке читайте здесь:
Пример: Accept-Language: da, en-GB; q = 0.8, fr; q = 0.7
В данном примере указано, что пользователь предпочитает датский, но готов принять британский английский и любой тип французского.
Рассмотрим внимательно синтаксис этого выражения:
<Заголовок>: <предпочитаемый язык>, <альтернативный язык>; <коэффициент предпочтительности q>
Для предпочитаемого языка коэффициент не указывается — что q=1.
Алгоритм выбора языка
- Разделяем переданный заголовок по "весам".
- Сортируем полученные наборы в порядке уменьшения "весов".
- Обходим полученные наборы языков в порядке уменьшения "весов".
- Для каждого языка ищем соответсвующий ему словарь:
- Если словарь есть, то этот язык объявляем "текущим", завершаем цикл и возвращаем его.
- Если словаря нет, язык задан с уточнением региона и "наиболее подходящий" язык не определен.
- Ищем словарь без учета региона. Если нашли словарь, то сохраняем его как "наиболее подходящий".
- Иначе возвращаем 'en' — английский.
Пример реализации алгоритма для выбора предпочитаемого языка
langs = parse( headers['Accept-Language'] )
prefer = None
for lang in langs:
if dict_exists( lang ):
return lang # Ищем точное совпадение словаря и переданного языка.
delim = lang.find('-')
if delim != -1 and prefer is None and dict_exists( lang[ :delim ] ):
prefer = lang[ :delim ] # Наиболее подходящим языком объявляем язык с наибольшим весом без учета региона.
if prefer:
return prefer
else:
return 'en'
Получение текущей локали
// JavaScript
define('MyControl', ['UI/Base', 'I18n/i18n'], function(Base, i18n) {
var ModuleClass = Base.Control.extend({
_template: template,
_beforeMount: function() {
// Вернет строку в формате [язык]-[СТРАНА], где
// [язык] — двухбуквенный код языка по стандарту ISO 639-1.
// [СТРАНА] — двухбуквенный код страны по стандарту ISO 3166-1.
var locale = i18n.controller.currentLocale;
}
});
return ModuleClass;
});
# Python
from sbis import *
# Вернет строку в формате [язык]-[СТРАНА], где
# [язык] — двухбуквенный код языка по стандарту ISO 639-1.
# [СТРАНА] — двухбуквенный код страны по стандарту ISO 3166-1.
# Если параметры языка не заданы, то возвращает ru-RU.
lang_str = CurrentLanguageIsoCode()
// C++
#include <sbis-lib/forward/string.hpp>
#include <sbis-lib/utils/rk.hpp>
/**
* Вернет ISO code текущей локали в формате [язык]-[СТРАНА], где
* [язык] — двухбуквенный код языка по стандарту ISO 639-1.
* [СТРАНА] — двухбуквенный код страны по стандарту ISO 3166-1.
* Если не заданы параметры языка, то возвращает ru-RU.
*/
sbis::String lang = sbis::CurrentLanguageIsoCode();