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

3.3 版本中新增。

布尔值,指示是否找到了(请求版本)的 gettext。

Gettext_VERSION

版本 4.2 中添加。

找到的 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>...

要在构建阶段为指定的 <language> 编译成 .mo 文件的一个或多个 .po 翻译文件的列表。相对路径将相对于当前源目录(CMAKE_CURRENT_SOURCE_DIR)进行解释。

gettext_process_pot_file

创建一个构建规则,该规则将 gettext Portable Object Template(.pot)文件和相关的 .po 文件处理为编译后的 gettext Machine Object(.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 Portable Object Template 文件(.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 翻译文件处理为编译后的 Machine Object(.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 Portable Object Template 文件(.pot)的路径,作为翻译的来源。如果给出的是相对路径,则将相对于当前源目录(CMAKE_CURRENT_SOURCE_DIR)进行解释。

ALL

将生成的目录添加到默认 CMake 构建目录中,以便在构建时默认创建翻译。

<po-files>...

一个或多个 .po 格式的翻译源文件列表,其文件名必须遵循 <language>.po 的格式。相对路径将相对于当前源目录(CMAKE_CURRENT_SOURCE_DIR)进行解释。

注意

为了更好地控制构建和安装行为,请改用 gettext_process_po_files()

已弃用变量

以下变量提供用于向后兼容性

GETTEXT_FOUND

自 4.2 版本起已弃用: 使用 Gettext_FOUND,其值相同。

布尔值,指示是否找到了(请求版本)的 gettext。

GETTEXT_VERSION_STRING

自 4.2 版本起已弃用: Gettext_VERSION 替代。

找到的 gettext 的版本。

示例

示例:查找 gettext

查找 GNU gettext 工具

find_package(Gettext)

或者,查找 gettext 并指定最低必需版本

find_package(Gettext 0.21)

或者,查找 gettext 并将其设为必需(如果未找到,则处理将停止并显示错误消息)

find_package(Gettext REQUIRED)

示例:在 CMake 中使用 gettext

开始使用 gettext 时,.pot 文件被认为是手动创建的。例如,使用 xgettext 工具处理提供的 main.cxx 源文件

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() 命令会自动创建应用程序在运行时根据系统环境变量(如 LANG)加载所需的 .mo 文件。在以下示例中,还使用了 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)。