如何使用GNU gettext本地化C++/CMake程序?附示例
C++程序使用GNU gettext本地化完整示例
一、代码修正(解决xgettext生成空文件问题)
xgettext是静态扫描源代码提取翻译条目,只能识别gettext("字符串字面量")的写法,原代码中传入变量name导致它无法解析,所以必须改用字符串字面量。同时需要补充gettext本地化环境的初始化代码,否则翻译不会生效:
#include <iostream> #include <string_view> #include <libintl.h> #include <locale.h> #define PACKAGE "myapp" // 程序标识,需与后续配置一致 #define LOCALEDIR "./lang" // 翻译文件存放目录 int main() { // 初始化本地化环境 setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); // 使用字符串字面量,让xgettext能提取翻译条目 std::string_view name = gettext("foo"); std::cout << name << "\n"; return 0; }
二、生成.pot翻译模板文件
在项目根目录执行以下命令,生成包含所有待翻译条目的模板文件到lang目录:
xgettext --keyword=gettext --language=C++ --output=lang/myapp.pot main.cpp
参数说明:
--keyword=gettext:指定要扫描的翻译函数为gettext--language=C++:按C++语法规则解析源代码--output=lang/myapp.pot:指定模板文件的输出路径
执行后lang目录下会生成myapp.pot,里面包含"foo"这个待翻译条目。
三、创建/更新.po翻译文件
1. 基于模板生成新语言的翻译文件
以德语(de_DE)为例,执行命令生成对应.po文件:
msginit --input=lang/myapp.pot --output=lang/de_DE.po --locale=de_DE.UTF-8
执行过程中会提示输入"foo"的德语翻译(比如"Hallo"),完成后lang/de_DE.po就创建好了。其他语言(如fr_FR、ru_RU)重复此步骤即可。
2. 更新已有翻译文件
当源代码新增翻译条目时,用以下命令更新现有.po文件,保留已有翻译的同时合并新条目:
msgmerge --update lang/de_DE.po lang/myapp.pot
四、编译.po为二进制.mo文件
gettext运行时加载的是二进制格式的.mo文件,需将每个.po编译为对应.mo,并放到指定目录结构下:
# 创建德语翻译的目录结构(其他语言同理) mkdir -p lang/de_DE/LC_MESSAGES # 编译po为mo msgfmt --output-file=lang/de_DE/LC_MESSAGES/myapp.mo lang/de_DE.po
五、CMake配置(自动化构建与翻译管理)
将本地化相关逻辑集成到CMakeLists.txt,方便一键构建和维护:
cmake_minimum_required(VERSION 3.10) project(myapp) # 查找系统中的gettext库 find_package(Gettext REQUIRED) # 编译主程序 add_executable(myapp main.cpp) target_link_libraries(myapp PRIVATE ${GETTEXT_LIBRARIES}) target_include_directories(myapp PRIVATE ${GETTEXT_INCLUDE_DIRS}) # 传递编译定义给代码 set(PACKAGE_NAME "myapp") set(LOCALEDIR "${CMAKE_SOURCE_DIR}/lang") target_compile_definitions(myapp PRIVATE PACKAGE="${PACKAGE_NAME}" LOCALEDIR="${LOCALEDIR}" ) # 生成pot模板的自定义目标 add_custom_target(update_pot COMMAND xgettext --keyword=gettext --language=C++ --output=lang/${PACKAGE_NAME}.pot main.cpp WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} ) # 批量编译所有语言的po为mo set(TRANSLATIONS de_DE fr_FR ru_RU) # 可添加更多语言 foreach(LANG ${TRANSLATIONS}) set(PO_FILE ${CMAKE_SOURCE_DIR}/lang/${LANG}.po) set(MO_DIR ${CMAKE_SOURCE_DIR}/lang/${LANG}/LC_MESSAGES) set(MO_FILE ${MO_DIR}/${PACKAGE_NAME}.mo) add_custom_command( OUTPUT ${MO_FILE} COMMAND mkdir -p ${MO_DIR} COMMAND msgfmt --output-file=${MO_FILE} ${PO_FILE} DEPENDS ${PO_FILE} ) list(APPEND MO_FILES ${MO_FILE}) endforeach() add_custom_target(translations ALL DEPENDS ${MO_FILES})
六、运行测试
通过设置环境变量指定运行时语言,验证翻译效果:
# 测试德语环境 export LANG=de_DE.UTF-8 ./myapp # 输出德语翻译内容 # 测试法语环境 export LANG=fr_FR.UTF-8 ./myapp # 输出法语翻译内容
内容的提问来源于stack exchange,提问作者yukkute
相关产品推荐
相关产品推荐

