Skip to content

Интернационализация (i18n)

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

Конфигурация

Переводы настраиваются в секции translations файла config.json:

json
{
    "translations": [
        {
            "domain": "identity",
            "path": "backend/identity/locale"
        },
        {
            "domain": "shop",
            "path": "backend/shop/locale"
        }
    ]
}

domain строка

Имя домена переводов. Используется для обращения к конкретному набору переводов в коде.

path строка

Путь до директории с файлами локализации.

Структура файлов переводов

Файлы переводов должны располагаться по следующему пути:

<path>/<lang>/LC_MESSAGES/<domain>.mo

Например, для домена identity и языка ru:

backend/identity/locale/ru/LC_MESSAGES/identity.mo
backend/identity/locale/en/LC_MESSAGES/identity.mo

Создание файлов переводов

1. Создание PO-файла

Создайте файл identity.po для каждого языка:

po
# Russian translations for identity module
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Language: ru\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

msgid "Welcome"
msgstr "Добро пожаловать"

msgid "Invalid credentials"
msgstr "Неверные учетные данные"

# Plural forms
msgid "error"
msgid_plural "errors"
msgstr[0] "ошибка"
msgstr[1] "ошибки"
msgstr[2] "ошибок"

2. Компиляция в MO-файл

bash
msgfmt -o identity.mo identity.po

Использование в коде

Подключите заголовочный файл:

c
#include "translation.h"

Простой перевод

Функция tr возвращает перевод по идентификатору сообщения:

c
const char* message = tr(ctx, "identity", "Welcome");
// Результат: "Добро пожаловать" (для ru) или "Welcome" (для en)

Внимание

Не освобождайте память, возвращаемую функцией tr. Строка управляется системой переводов.

Перевод с подстановкой

Функция trf заменяет плейсхолдеры {key} на переданные значения:

c
// PO-файл: msgid "Hello, {name}!" msgstr "Привет, {name}!"

char* message = trf(ctx, "identity", "Hello, {name}!", "name", username, NULL);
// Результат: "Привет, Иван!"

free(message); // Необходимо освободить память

Список аргументов

Аргументы передаются парами "ключ", "значение" и завершаются NULL.

Множественные формы

Функция trn выбирает правильную форму в зависимости от числа:

c
const char* message = trn(ctx, "identity", "error", "errors", error_count);
// 1 -> "ошибка"
// 2 -> "ошибки"
// 5 -> "ошибок"

Множественные формы с подстановкой

Функция trnf комбинирует множественные формы и подстановку:

c
char count_str[16];
snprintf(count_str, sizeof(count_str), "%d", count);

char* message = trnf(ctx, "identity", "{n} error found", "{n} errors found",
                     count, "n", count_str, NULL);
// 1 -> "1 ошибка найдена"
// 3 -> "3 ошибки найдено"

free(message);

Определение языка

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

  1. Query-параметр lang?lang=ru
  2. Заголовок Accept-Language — парсится для получения предпочтительного языка
  3. Язык по умолчаниюen

Пример

GET /api/users?lang=ru
Accept-Language: en-US,en;q=0.9

В этом случае будет использован русский язык (ru), так как query-параметр имеет наивысший приоритет.

API-справочник

tr

c
const char* tr(httpctx_t* ctx, const char* domain, const char* msgid);
ПараметрОписание
ctxHTTP-контекст для определения языка
domainДомен переводов
msgidИдентификатор сообщения
ВозвратПереведенная строка (не освобождать)

trf

c
char* trf(httpctx_t* ctx, const char* domain, const char* msgid, ...);
ПараметрОписание
ctxHTTP-контекст для определения языка
domainДомен переводов
msgidИдентификатор сообщения с плейсхолдерами
...Пары "ключ", "значение", завершенные NULL
ВозвратПереведенная строка (вызывающий должен освободить)

trn

c
const char* trn(httpctx_t* ctx, const char* domain, const char* singular,
                const char* plural, unsigned long n);
ПараметрОписание
ctxHTTP-контекст для определения языка
domainДомен переводов
singularФорма единственного числа
pluralФорма множественного числа
nЧисло для выбора формы
ВозвратПереведенная строка (не освобождать)

trnf

c
char* trnf(httpctx_t* ctx, const char* domain, const char* singular,
           const char* plural, unsigned long n, ...);
ПараметрОписание
ctxHTTP-контекст для определения языка
domainДомен переводов
singularФорма единственного числа с плейсхолдерами
pluralФорма множественного числа с плейсхолдерами
nЧисло для выбора формы
...Пары "ключ", "значение", завершенные NULL
ВозвратПереведенная строка (вызывающий должен освободить)

Пример использования

c
#include "http.h"
#include "translation.h"

void get_profile(httpctx_t* ctx) {
    // Простой перевод
    const char* title = tr(ctx, "identity", "Profile");

    // Перевод с подстановкой
    char* greeting = trf(ctx, "identity", "Welcome back, {name}!",
                         "name", user->name, NULL);

    // Множественное число
    char count_str[16];
    snprintf(count_str, sizeof(count_str), "%d", notification_count);
    char* notifications = trnf(ctx, "identity",
        "You have {n} new notification",
        "You have {n} new notifications",
        notification_count, "n", count_str, NULL);

    // ... формирование ответа ...

    free(greeting);
    free(notifications);
}

Выпущено под лицензией MIT.