Por que seu código C++ deve falar todos os idiomas do mundo?
\n\nImagine: você escreveu um parser perfeito ou um servidor de alto desempenho em C++. Ele voa, consome o mínimo de memória, mas exibe mensagens apenas em russo. E amanhã seu produto é comprado por uma corporação japonesa. O que fazer? Reescrever toda a saída? Inserir centenas de if (lang == "jp")? Esse é o caminho para o inferno.
Conheça a internacionalização C++ (ou simplesmente i18n C++ — da palavra "internationalization", onde entre i e n há 18 letras). Não é apenas "tradução de botões", mas toda uma filosofia de design que permite que sua aplicação funcione corretamente com qualquer idioma, cultura e codificação. Sem internacionalização, um projeto C++ está fadado a um nicho local. Com ela, você entra no mercado global.
\n\nNeste artigo, vamos analisar como dominar a localização C++ usando ferramentas padrão e bibliotecas poderosas. Sem enrolação — apenas código funcional e casos reais.
\n\nOs três pilares da internacionalização: Locale, Encoding e Messages
\n\nAntes de escrever código, vamos entender do que consiste a internacionalização C++ na prática. Você precisa resolver três tarefas:
\n\n- \n
- Localidade (Locale): Como formatar datas, números e moedas. Nos EUA escrevem 03/15/2024, na Alemanha — 15.03.2024. \n
- Codificação (Encoding): Como trabalhar com Unicode. Cirílico, ideogramas, escrita árabe — tudo isso deve ser armazenado e exibido sem caracteres ilegíveis. \n
- Mensagens (Messages): Como armazenar e substituir strings traduzidas. "File not found" em português — "Arquivo não encontrado". \n
Ignorar pelo menos um desses itens transformará sua aplicação em uma abóbora. Vamos em ordem.
\n\nNível básico: Localidade padrão e std::locale
\n\nA biblioteca padrão do C++ fornece a classe std::locale. Esta é sua primeira ferramenta para internacionalização C++. Ela pode alterar os separadores decimais e o formato de saída de datas.
Exemplo: formatação de números e datas
\n\n#include <iostream>\n#include <locale>\n#include <ctime>\n#include <iomanip>\n\nvoid print_date(double value) {\n std::cout.imbue(std::locale("en_US.UTF-8"));\n std::cout << "EN: " << value << std::endl;\n\n std::cout.imbue(std::locale("de_DE.UTF-8"));\n std::cout << "DE: " << value << std::endl;\n\n std::cout.imbue(std::locale("ru_RU.UTF-8"));\n std::cout << "RU: " << value << std::endl;\n}\n\nint main() {\n double pi = 3.14159;\n print_date(pi);\n\n // Trabalho com datas\n std::time_t t = std::time(nullptr);\n std::tm* tm = std::localtime(&t);\n\n std::cout.imbue(std::locale("en_US.UTF-8"));\n std::cout << "EN date: " << std::put_time(tm, "%x") << std::endl;\n\n std::cout.imbue(std::locale("ru_RU.UTF-8"));\n std::cout << "RU date: " << std::put_time(tm, "%x") << std::endl;\n\n return 0;\n}\n\nImportante: Os nomes das localidades (por exemplo, "ru_RU.UTF-8") dependem do sistema operacional. No Windows, podem ser chamados de "Russian_Russia.1251". Este é o primeiro problema. A localização C++ padrão via std::locale é boa para tarefas simples, mas para projetos sérios é melhor usar bibliotecas especializadas.
Nível avançado: Boost.Locale — o melhor amigo do internacionalizador
\n\nSe você programa em C++ e quer fazer internacionalização C++ corretamente — use Boost.Locale. Esta biblioteca resolve todos os três problemas: ela trabalha com Unicode, formata qualquer coisa e extrai strings traduzidas de arquivos .po e .mo (formato GNU gettext).
\n\nInstalação e configuração
\nBoost.Locale faz parte do Boost. Conecte-o no seu CMakeLi