Библиотека Globalize использует формат JSON как основной механизм хранения локализационных данных. Все переводы, правила форматирования чисел, валют, дат и сообщений подключаются в виде JSON-структур, совместимых со стандартом CLDR (Common Locale Data Repository).
JSON-файлы в Globalize выполняют несколько задач:
Структура JSON играет ключевую роль в корректной работе всей системы интернационализации.
Globalize не содержит встроенных локализаций. Вместо этого библиотека использует данные проекта Unicode CLDR.
Стандарт CLDR предоставляет:
Все эти данные поставляются в формате JSON.
Типичная схема подключения:
const Globalize = require("globalize");
Globalize.load(
require("cldr-data/main/ru/numbers.json"),
require("cldr-data/main/ru/ca-gregorian.json"),
require("cldr-data/main/ru/currencies.json"),
require("cldr-data/supplemental/likelySubtags.json"),
require("cldr-data/supplemental/numberingSystems.json")
);
Большинство JSON-файлов CLDR имеют вложенную структуру:
{
"main": {
"ru": {
"numbers": {
...
}
}
}
}
Компоненты структуры:
| Ключ | Назначение |
|---|---|
main |
Основной контейнер |
ru |
Код локали |
numbers |
Категория данных |
Globalize использует стандарт BCP 47.
Примеры:
| Локаль | Назначение |
|---|---|
en |
Английский |
en-US |
Английский США |
en-GB |
Английский Великобритании |
ru |
Русский |
ru-KZ |
Русский Казахстана |
kk |
Казахский |
fr-CA |
Французский Канады |
Файл numbers.json отвечает за:
Пример структуры:
{
"main": {
"ru": {
"numbers": {
"defaultNumberingSystem": "latn",
"symbols-numberSystem-latn": {
"decimal": ",",
"group": " ",
"percentSign": "%",
"plusSign": "+",
"minusSign": "-"
},
"decimalFormats-numberSystem-latn": {
"standard": "#,##0.###"
}
}
}
}
}
В разных странах используются разные символы.
{
"decimal": ",",
"group": " "
}
Формат:
1 234 567,89
{
"decimal": ".",
"group": ","
}
Формат:
1,234,567.89
Файл хранит:
Пример:
{
"main": {
"ru": {
"numbers": {
"currencies": {
"USD": {
"displayName": "доллар США",
"symbol": "$"
},
"EUR": {
"displayName": "евро",
"symbol": "€"
}
}
}
}
}
}
const Globalize = require("globalize");
Globalize.locale("ru");
const formatter = Globalize.currencyFormatter("USD");
console.log(formatter(1000));
Результат:
1 000,00 $
Файл отвечает за:
Пример структуры:
{
"main": {
"ru": {
"dates": {
"calendars": {
"gregorian": {
"months": {
"format": {
"wide": {
"1": "январь",
"2": "февраль"
}
}
}
}
}
}
}
}
}
CLDR использует собственную систему шаблонов.
| Символ | Значение |
|---|---|
y |
Год |
M |
Месяц |
d |
День |
E |
День недели |
H |
Часы |
m |
Минуты |
s |
Секунды |
Пример:
{
"dateFormats": {
"short": "dd.MM.y",
"medium": "d MMM y 'г'."
}
}
Globalize поддерживает собственные словари сообщений.
Пример JSON:
{
"hello": "Привет",
"bye": "До свидания",
"welcome": "Добро пожаловать"
}
Подключение:
Globalize.loadMessages({
ru: {
hello: "Привет"
}
});
Использование:
Globalize.locale("ru");
const translate = Globalize.messageFormatter("hello");
console.log(translate());
JSON позволяет создавать сложные словари.
Пример:
{
"auth": {
"login": {
"title": "Вход",
"button": "Авторизоваться"
}
}
}
Использование:
Globalize.messageFormatter("auth/login/title");
Globalize поддерживает ICU MessageFormat.
Пример:
{
"greeting": "Здравствуйте, {name}"
}
Использование:
const formatter = Globalize.messageFormatter("greeting");
console.log(formatter({
name: "Алексей"
}));
Для разных языков правила отличаются.
Пример JSON:
{
"items": "{count, plural, one {# товар} few {# товара} many {# товаров} other {# товара}}"
}
Использование:
const formatter = Globalize.messageFormatter("items");
formatter({ count: 1 });
formatter({ count: 3 });
formatter({ count: 10 });
CLDR использует категории:
| Категория | Назначение |
|---|---|
zero |
Ноль |
one |
Один |
two |
Два |
few |
Несколько |
many |
Много |
other |
Остальные |
Русский язык активно использует:
onefewmanyПомимо основных файлов используются supplemental-файлы.
Примеры:
| Файл | Назначение |
|---|---|
likelySubtags.json |
Расширение локалей |
timeData.json |
Форматы времени |
weekData.json |
Первый день недели |
currencyData.json |
Информация о валютах |
plurals.json |
Правила множественного числа |
Пример:
{
"supplemental": {
"likelySubtags": {
"ru": "ru-Cyrl-RU",
"en": "en-Latn-US"
}
}
}
Globalize может автоматически определить:
Файл содержит:
Пример:
{
"units": {
"length-kilometer": {
"displayName": "километры"
}
}
}
Крупные проекты обычно используют модульную структуру.
Пример:
locales/
ru/
auth.json
profile.json
cart.json
en/
auth.json
profile.json
cart.json
Пример:
const ruAuth = require("./ru/auth.json");
const ruCart = require("./ru/cart.json");
Globalize.loadMessages({
ru: {
...ruAuth,
...ruCart
}
});
Нежелательный пример:
{
"title": "Главная"
}
Во втором файле:
{
"title": "Профиль"
}
При объединении один ключ перезапишет другой.
Рекомендуется использовать namespaces.
Пример:
{
"home": {
"title": "Главная"
},
"profile": {
"title": "Профиль"
}
}
Полный набор CLDR очень большой.
Возможные проблемы:
Лучше подключать только нужные данные.
Плохой подход:
require("cldr-data");
Хороший подход:
require("cldr-data/main/ru/numbers.json");
Пример динамической загрузки:
async function loadLocale(locale) {
const messages = await import(`./locales/${locale}.json`);
Globalize.loadMessages({
[locale]: messages.default
});
}
JSON импортируется автоматически:
import messages from "./ru.json";
import messages from "./locales/ru.json";
const messages = require("./ru.json");
Ошибочный JSON:
{
"hello": "Привет",
}
Ошибка вызвана лишней запятой.
{
"hello": "Привет"
}
JSON не поддерживает:
undefined;Локализационные JSON-файлы рекомендуется хранить в UTF-8.
Проблемы неправильной кодировки:
Пример:
{
"quote": "Он сказал: \"Привет\""
}
{
"text": "Первая строка\nВторая строка"
}
Практика крупных приложений:
i18n/
ru/
common.json
errors.json
dashboard.json
settings.json
Рекомендуется:
function hasTranslation(messages, key) {
return key.split(".").reduce((obj, part) => {
return obj && obj[part];
}, messages);
}
Опасности:
{
"message": "<script>alert('XSS')</script>"
}
element.textContent = message;
{
"decimalFormats-numberSystem-latn": {
"standard": "#,##0.###"
}
}
Globalize интерпретирует шаблон и автоматически форматирует числа.
{
"percentFormats-numberSystem-latn": {
"standard": "#,##0%"
}
}
Использование:
const formatter = Globalize.percentFormatter();
formatter(0.25);
Результат:
25%
const formatter = Globalize.dateFormatter({
datetime: "medium"
});
formatter(new Date());
Все шаблоны берутся из JSON-файлов CLDR.
Иногда создаются собственные локализационные файлы:
{
"currency": "KZT",
"timezone": "Asia/Almaty",
"dateFormat": "dd.MM.yyyy"
}
Пример:
{
"network": {
"timeout": "Время ожидания истекло",
"offline": "Нет подключения к сети"
}
}
locales/
en/
ru/
kk/
de/
Хороший пример:
{
"auth.login.button": "Войти"
}
Или:
{
"auth": {
"login": {
"button": "Войти"
}
}
}
Плохой пример:
{
"Нажмите сюда": "Нажмите сюда"
}
Проблемы:
Локализации часто кэшируются браузером.
Пример:
fetch("/locales/ru.json");
При правильных HTTP-заголовках JSON может храниться в кэше длительное время.
JSON можно минифицировать:
{"hello":"Привет"}
Это уменьшает размер передаваемых данных.
При тысячах ключей используются:
Пример схемы:
{
"type": "object",
"properties": {
"hello": {
"type": "string"
}
}
}
Схемы позволяют автоматически проверять корректность локализаций.
Globalize полностью построен вокруг JSON-структур:
JSON в Globalize является не просто форматом хранения, а фундаментом всей системы интернационализации.