FindGettext

查找 GNU gettext 工具并提供用于生成多语言消息的命令

find_package(Gettext [<version>] ...)

GNU gettext 是一个用于国际化 (i18n) 和本地化 (l10n) 的系统,由命令行工具和运行时库 (libintl) 组成。此模块查找 gettext 工具(例如 msgmergemsgfmt),而运行时库可以使用单独的 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_USfrde_DEzh_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)。