FindGettext¶
查找 GNU gettext 工具并提供用于生成多语言消息的命令
find_package(Gettext [<version>] ...)
GNU gettext 是一个用于国际化 (i18n) 和本地化 (l10n) 的系统,由命令行工具和运行时库 (libintl) 组成。此模块查找 gettext 工具(例如 msgmerge 和 msgfmt),而运行时库可以使用单独的 FindIntl 模块查找,该模块抽象了各种实现中的 libintl 处理。
gettext 中常用的文件类型
- POT 文件
- Portable Object Template ( - .pot) 文件用作翻译的源模板。
- PO 文件
- Portable Object ( - .po) 文件包含人类可读的翻译。
- MO 文件
- Machine Object ( - .mo) 文件由- .po文件编译而来,用于运行时使用。
结果变量¶
此模块定义了以下变量
- Gettext_FOUND
- 布尔值,指示是否找到 gettext(以及请求的版本)。为了向后兼容, - GETTEXT_FOUND变量也设置为相同的值。
- GETTEXT_VERSION_STRING
- 找到的 gettext 版本。 
缓存变量¶
以下缓存变量也可以设置
- GETTEXT_MSGMERGE_EXECUTABLE
- msgmerge工具的完整路径,用于合并消息目录和模板。
- GETTEXT_MSGFMT_EXECUTABLE
- msgfmt工具的完整路径,用于将消息目录编译为二进制格式。
命令¶
如果找到 gettext,此模块提供以下命令以在 CMake 中使用 gettext
- gettext_process_po_files¶
- 创建构建规则,将一个或多个 - .po翻译文件处理为指定可翻译语言区域的二进制- .mo文件- gettext_process_po_files( <language> [ALL] [INSTALL_DESTINATION <destdir>] PO_FILES <po-files>... ) - 此命令定义了一个自定义目标,用于将给定的 - <po-files>编译成指定- <language>的- .mo文件。首次调用时,它还会创建一个名为- pofiles的全局自定义目标,所有后续调用都会向其贡献。此目标可用于集体构建所有翻译文件或在其他 CMake 命令中引用。- 应为每个语言区域单独调用此命令,以生成每个区域相应的 - .mo文件。- 参数为 - <language>
- PO 文件的目标可翻译语言区域。 - 此字符串通常格式为区域标识符(例如,用于德国德语的 - de_DE,或用于奥地利德语的- de_AT等)。下划线前的一部分指定语言,下划线后的一部分指定国家或地区变体。在某些情况下,也可以使用仅包含语言代码的较短形式(例如,- de)。
- ALL
- 此选项将生成的任务添加到默认的 CMake 构建任务,以便默认构建翻译。 
- INSTALL_DESTINATION <destdir>
- 指定在安装阶段生成 - .mo文件的安装目录。如果指定,文件将安装到:- <destdir>/<language>/LC_MESSAGES/*.mo。如果未指定,则不安装文件。
- PO_FILES <po-files>...
- 一个或多个 - .po翻译文件的列表,将在构建阶段为指定的- <language>编译成- .mo文件。相对路径将相对于当前源目录 (- CMAKE_CURRENT_SOURCE_DIR) 进行解释。
 
- gettext_process_pot_file¶
- 创建构建规则,处理 gettext 可移植对象模板 ( - .pot) 文件和相关的- .po文件,生成已编译的 gettext 机器对象 (- .mo) 文件- gettext_process_pot_file( <pot-file> [ALL] [INSTALL_DESTINATION <destdir>] LANGUAGES <languages>... ) - 此命令定义了一个名为 - potfiles的自定义目标,它将给定的- <pot-file>和特定语言的- .po文件编译成每个指定语言的二进制- .mo文件。在调用此命令之前,相应的- <language>.po文件必须存在于当前二进制目录 (- CMAKE_CURRENT_BINARY_DIR) 中。- 参数为 - <pot-file>
- gettext 可移植对象模板文件 ( - .pot) 的路径,作为翻译的来源。如果给定相对路径,则将相对于当前源目录 (- CMAKE_CURRENT_SOURCE_DIR) 进行解释。
- ALL
- 将生成的任务添加到默认的 CMake 构建任务,以便默认构建文件。 
- INSTALL_DESTINATION <destdir>
- 指定在安装阶段生成 - .mo文件的安装目录。如果指定,文件将安装到:- <destdir>/<language>/LC_MESSAGES/<pot-base-filename>.mo。如果未指定,则不安装文件。
- LANGUAGES <languages>...
- 一个或多个可翻译语言区域的列表(例如, - en_US、- fr、- de_DE、- zh_CN等)。
 
- gettext_create_translations¶
- 创建构建规则,处理给定的 - .pot模板文件和相关的- .po翻译文件,生成已编译的机器对象 (- .mo) 文件- gettext_create_translations(<pot-file> [ALL] <po-files>...) - 此命令定义了一个名为 - translations的自定义目标,它将指定的- <pot-file>和- <po-files>编译成二进制- .mo文件。它还会自动为生成的- .mo文件添加安装规则,在安装阶段将其安装到默认的- share/locale/<language>/LC_MESSAGES/<pot-base-filename>.mo路径。- 参数为 - <pot-file>
- gettext 可移植对象模板文件 ( - .pot) 的路径,作为翻译的来源。如果给定相对路径,则将相对于当前源目录 (- CMAKE_CURRENT_SOURCE_DIR) 进行解释。
- ALL
- 将生成的任务添加到默认的 CMake 构建任务,以便在构建过程中默认创建翻译。 
- <po-files>...
- 一个或多个 - .po格式的翻译源文件列表,其文件名必须遵循- <language>.po格式。相对路径将相对于当前源目录 (- CMAKE_CURRENT_SOURCE_DIR) 进行解释。
 - 注意 - 为了更好地控制构建和安装行为,请改用 - gettext_process_po_files()。
示例¶
示例:查找 gettext¶
查找 GNU gettext 工具
find_package(Gettext)
或者,查找 gettext 并指定最小所需版本
find_package(Gettext 0.21)
或者,查找 gettext 并使其成为必需(如果未找到,则停止处理并显示错误消息)
find_package(Gettext REQUIRED)
示例:在 CMake 中使用 gettext¶
从 gettext 开始时,.pot 文件被认为是手动创建的。例如,在提供的 main.cxx 源代码文件上使用 xgettext 工具
main.cxx¶#include <iostream>
#include <libintl.h>
#include <locale.h>
int main()
{
  // Set locale from environment
  setlocale(LC_ALL, "");
  // Bind the text domain
  const char* dir = std::getenv("TEXTDOMAINDIR");
  if (!dir) {
    dir = "/usr/local/share/locale";
  }
  bindtextdomain("MyApp", dir);
  textdomain("MyApp");
  std::cout << gettext("Hello, World") << std::endl;
  return 0;
}
xgettext 工具从提供的源代码中的 gettext() 调用中提取所有字符串并创建可翻译字符串
$ xgettext -o MyApp.pot main.cxx
项目可以使用 msginit 工具手动初始化可翻译文件
$ mkdir -p locale/de_DE
$ msginit -l de_DE.UTF8 -o locale/de_DE/MyApp.po -i MyApp.pot --no-translator
它会创建一个人类可读的文件,可以翻译成所需的语言(根据需要调整)
locale/de_DE/MyApp.po¶msgid ""
msgstr ""
"Language: de\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgid "Hello, World"
msgstr "Hallo, Welt"
在 CMake 中,此模块提供的 gettext_process_po_files() 命令会自动创建所需的 .mo 文件,应用程序在运行时根据系统环境变量(例如 LANG)加载这些文件。在以下示例中,还使用了 GNUInstallDirs 模块来提供 CMAKE_INSTALL_LOCALEDIR 变量
CMakeLists.txt¶cmake_minimum_required(VERSION 3.24)
project(GettextExample)
include(GNUInstallDirs)
find_package(Gettext)
if(Gettext_FOUND)
  foreach(language IN ITEMS de_DE)
    gettext_process_po_files(
      ${language}
      ALL
      PO_FILES locale/${language}/MyApp.po
      INSTALL_DESTINATION ${CMAKE_INSTALL_LOCALEDIR}
    )
  endforeach()
endif()
add_executable(example main.cxx)
# Find and link Intl library to use gettext() from libintl.h
find_package(Intl)
target_link_libraries(example PRIVATE Intl::Intl)
install(TARGETS example)
$ cmake -B build
$ cmake --build build
$ DESTDIR=$(pwd)/stage cmake --install build
要利用翻译,需要在系统上启用 de_DE 区域设置(参见 locale -a)。然后可以运行本地化输出
$ LANG=de_DE.UTF-8 TEXTDOMAINDIR=./stage/usr/local/share/locale \
  ./stage/usr/local/bin/example
示例:处理 POT 文件¶
gettext_process_pot_file() 命令将当前二进制目录中的 .po 翻译文件处理为 .mo 文件
CMakeLists.txt¶find_package(Gettext)
if(Gettext_FOUND)
  set(languages de_DE fr zh_CN)
  foreach(language IN LISTS languages)
    configure_file(locale/${language}.po ${language}.po COPYONLY)
  endforeach()
  gettext_process_pot_file(
    MyApp.pot
    ALL
    INSTALL_DESTINATION ${CMAKE_INSTALL_LOCALEDIR}
    LANGUAGES ${languages}
  )
endif()
示例:创建翻译¶
使用简化的 gettext_create_translations() 命令创建 .mo 文件
CMakeLists.txt¶find_package(Gettext)
if(Gettext_FOUND)
  gettext_create_translations(
    MyApp.pot
    ALL
    locale/de_DE.po
    locale/fr.po
    locale/zh_CN.po
  )
endif()
另请参阅¶
- FindIntl模块用于查找 Gettext 运行时库 (libintl)。
