Internationalization (i18n) in C++: From Basics to Advanced Techniques
Internationalization (abbreviated as i18n — from the English word "internationalization", where 18 represents the number of letters between the first 'i' and the last 'n') is the process of designing software so that it can be adapted to various languages and regional differences without modifying the code. In C++, this task has its own specifics: the language does not provide built-in tools for working with translations, but there are several powerful libraries that solve this problem.
Why is i18n important for C++ projects?
Modern C++ applications are rarely limited to a single language. Desktop programs, games, server-side solutions — all of them require support for multiple locales. The main problems that i18n solves are:
- Working with encodings — transitioning from ASCII to UTF-8, UTF-16, and other multibyte encodings;
- Formatting numbers, dates, and currencies — different countries use different separators and formats;
- Word order in sentences — Russian requires declensions, while English requires articles;
- Pluralization — plural formation rules differ (Russian has 3 forms, English has 2).
Main libraries for i18n in C++
1. GNU gettext — the classic
GNU gettext is the most popular library for internationalization in C and C++. It uses separate translation files (.po/.mo) and allows isolating strings from the code.
Basic usage example:
#include <iostream>#include <libintl.h>#include <locale.h>
#define _(str) gettext(str)
int main() { setlocale(LC_ALL, ""); bindtextdomain("myapp", "./locale"); textdomain("myapp");
std::cout << _("Hello, world!") << std::endl; std::cout << _("File not found") << std::endl; return 0;}To extract strings, the xgettext utility is used, which scans the source code and creates a .pot file. Translators then work with .po files.
Advantages:
- Ease of integration;
- Huge community and many tools (Poedit, Lokalize);
- Support for pluralization via
ngettext(); - Works on any platform.
Disadvantages:
- Does not support contextual translations without additional workarounds;
- Requires a separate build step to generate .mo files.
2. Boost.Locale — a modern C++ approach
The Boost.Locale library provides a more modern and type-safe interface. It is built on top of ICU (International Components for Unicode) or system locales.
Example of working with translations:
#include <boost/locale.hpp>#include <iostream>
int main() { using namespace boost::locale; generator gen; std::locale loc = gen("ru_RU.UTF-8"); std::locale::global(loc); // Create a translator translator tr; std::cout << tr("Hello, world!") << std::endl; std::cout << tr("Today is {1}", "Monday") << std::endl; // Pluralization std::cout << tr("You have {1} message", "You have {1} messages", 5) << std::endl; return 0;}Advantages:
- Native UTF-8 support;
- Formatting of dates, numbers, and currencies;
- Support for contextual translations;
- Works with std::string and std::wstring.
Disadvantages:
- Dependency on Boost (a heavy library);
- Fewer tools for translators.
3. ICU — the industry standard
ICU (Intern