为什么您的 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" 在中文中是“文件未找到”。
忽略其中任何一点都会让您的应用程序变得毫无用处。让我们逐一来看。
基础级别:标准 locale 和 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"。这是第一个痛点。通过 std::locale 进行的标准 C++ 本地化适用于简单任务,但对于严肃的项目,最好使用专门的库。
进阶级别:Boost.Locale —— 国际化者的最佳伙伴
如果您使用 C++ 并且希望正确地进行 C++ 国际化,请使用 Boost.Locale。这个库解决了所有三个问题:它可以处理 Unicode,格式化任何内容,并从 .po 和 .mo 文件(GNU gettext 格式)中提取已翻译的字符串。
安装和配置
Boost.Locale 是 Boost 库的一部分。在您的 CMakeLi