Интернационализация C++ приложений: делаем софт мирового уровня

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему ваш C++ код должен заговорить на всех языках мира?

Представьте: вы написали идеальный парсер или высокопроизводительный сервер на C++. Он летает, жрет минимум памяти, но выводит сообщения только на русском. А завтра ваш продукт покупает японская корпорация. Что делать? Переписывать весь вывод? Вставлять сотни if (lang == "jp")? Это путь в ад.

Встречайте интернационализацию C++ (или просто i18n C++ — от слова "internationalization", где между i и n 18 букв). Это не просто "перевод кнопок", а целая философия проектирования, которая позволяет вашему приложению корректно работать с любым языком, культурой и кодировкой. Без интернационализации C++ проект обречен на локальную нишу. С ней — вы выходите на мировой рынок.

В этой статье мы разберем, как приручить локализацию C++ с помощью стандартных средств и мощных библиотек. Никакой воды — только рабочий код и реальные кейсы.

Три кита интернационализации: Locale, Encoding и Messages

Прежде чем писать код, давайте разберемся, из чего состоит интернационализация C++ на практике. Вам нужно решить три задачи:

  • Локаль (Locale): Как форматировать даты, числа и валюту. В США пишут 03/15/2024, в Германии — 15.03.2024.
  • Кодировка (Encoding): Как работать с Unicode. Кириллица, иероглифы, арабская вязь — все это должно храниться и выводиться без кракозябр.
  • Сообщения (Messages): Как хранить и подставлять переведенные строки. "File not found" по-русски — "Файл не найден".

Игнорирование хотя бы одного пункта превратит ваше приложение в тыкву. Поехали по порядку.

Базовый уровень: Стандартная локаль и std::locale

Стандартная библиотека C++ предоставляет класс std::locale. Это ваш первый инструмент для интернационализации C++. Он умеет менять разделители дробной части и формат вывода дат.

Пример: форматирование чисел и дат

#include <iostream>
#include <locale>
#include <ctime>
#include <iomanip>

void print_date(double value) {
    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "EN: " << value << std::endl;

    std::cout.imbue(std::locale("de_DE.UTF-8"));
    std::cout << "DE: " << value << std::endl;

    std::cout.imbue(std::locale("ru_RU.UTF-8"));
    std::cout << "RU: " << value << std::endl;
}

int main() {
    double pi = 3.14159;
    print_date(pi);

    // Работа с датами
    std::time_t t = std::time(nullptr);
    std::tm* tm = std::localtime(&t);

    std::cout.imbue(std::locale("en_US.UTF-8"));
    std::cout << "EN date: " << std::put_time(tm, "%x") << std::endl;

    std::cout.imbue(std::locale("ru_RU.UTF-8"));
    std::cout << "RU date: " << std::put_time(tm, "%x") << std::endl;

    return 0;
}

Важно: Названия локалей (например, "ru_RU.UTF-8") зависят от операционной системы. На Windows они могут называться "Russian_Russia.1251". Это первая боль. Стандартная локализация C++ через std::locale — это хорошо для простых задач, но для серьезных проектов лучше использовать специализированные библиотеки.

Продвинутый уровень: Boost.Locale — лучший друг интернационализатора

Если вы пишете на C++ и хотите делать интернационализацию C++ правильно — ставьте Boost.Locale. Эта библиотека решает все три проблемы: она умеет работать с Unicode, форматировать что угодно и вытаскивать переведенные строки из файлов .po и .mo (формат GNU gettext).

Установка и подключение

Boost.Locale входит в состав Boost. Подключите его в своем CMakeLists.txt:

find_package(Boost REQUIRED COMPONENTS locale)
target_link_libraries(your_project Boost::locale)

Пример 1: Правильная работа с UTF-8

Самая частая проблема — вывод Unicode в консоль. Boost.Locale решает ее за вас, генерируя правильные коды для терминала.

#include <boost/locale.hpp>
#include <iostream>

int main() {
    // Создаем глобальный генератор локалей
    boost::locale::generator gen;

    // Задаем локаль по умолчанию (UTF-8)
    std::locale loc = gen("ru_RU.UTF-8");
    std::locale::global(loc);

    // Теперь можем выводить любые символы
    std::cout << "Привет, мир! 🌍" << std::endl;
    std::cout << "Тест: こんにちは" << std::endl;

    // Форматируем число по-русски
    std::cout << 1234567.89 << std::endl; // Выведет: 1 234 567,89

    return 0;
}

Пример 2: Извлечение переведенных строк (локализация C++)

Это сердце любой локализации C++. Вы пишете код на английском, а переводы храните в отдельных файлах.

#include <boost/locale.hpp>
#include <iostream>

int main() {
    boost::locale::generator gen;

    // Загружаем переводы из папки "locales"
    // Файлы должны быть в формате: locales/ru/LC_MESSAGES/myapp.mo
    std::locale loc = gen("ru_RU.UTF-8");
    gen.add_messages_path("locales");
    gen.add_messages_domain("myapp");

    std::locale::global(loc);

    // Функция translate() автоматически подставит перевод
    std::cout << boost::locale::translate("Hello, World!") << std::endl;
    std::cout << boost::locale::translate("File not found") << std::endl;

    // Форматирование с подстановкой плюральных форм
    int count = 5;
    std::cout << boost::locale::format("You have {1} message(s)") % count << std::endl;

    return 0;
}

Как это работает: Вы запускаете утилиту xgettext из пакета GNU gettext, она собирает все строки из translate() в шаблон .pot. Переводи

Блоги

Рекомендаций по книгам