GNU gettext 快速上手

文章目录

  • 1.简介
  • 2.核心概念
    • 国际化 (i18n)
    • 本地化 (l10n)
    • POT 文件
    • PO 文件
    • MO 文件
    • 文本域
    • 翻译函数
  • 3.主要组件
  • 4.使用示例
  • 参考文献

1.简介

GNU gettext 是一套用于软件国际化(internationalization,i18n)和本地化(localization,l10n)的工具集,它帮助开发者创建多语言应用程序。

下面大致翻译自 GetText 主页的介绍 :

“通常,程序及其文档信息都是用英语语言写的,程序运行时同用户交 互的信息也是英语。这是一个事实,不仅仅 GNU 的软件是这样,其他大 部分私有软件或自由软件也是这样。一方面,对于来自所有国家的开 发者、维护者和用户来说,相互沟通中使用一种通用的语言非常的方便。另一方面,相对于母语来说大多数人并不适应使用英语,而且他 们的日常工作都是尽可能的使用他们自己的母语。多数人都会喜欢他 们的计算机屏幕显示的英语更少,显示的母语更多。"


GNU 的 ‘gettext’ 是 GNU 翻译项目的一个重要步骤,我们依赖于它 来作很多其他的步骤。该软件包为程序员、翻译人员甚至用户提供了一套集成良好的工具和文档。详细地说,GNU gettext 提供了一套工具, 能让其他 GNU 软件创建多语言信息。这些工具包括一组关于如何编写程序以支持消息目录的约定,消息目录本身的目录和文件命名组织,支持检索已翻译消息的运行时库,以及一些以各种方式处理可翻译字符串集或已翻译字符串集的独立程序。一个特殊的 GNU Emacs 模式也可以帮助有兴趣的各方准备这些集合,或者使它们更新。

gettext 的工作流程是这样的:比如我们写一个 C 程序,通常 printf 等输 出信息都是 English 的。如果我们在程序中加入 gettext 支持,在需要交互的字符串上用 gettext 函数,程序运行就可以先调用 gettext 函数处理字符串,替换当前的字符串。注意是运行时替换

2.核心概念

国际化 (i18n)

国际化(Internationalization)简写为 i18n,其中 i 和 n 分别代表单词的第一个和最后一个字母,中间的"18"代表省略的18个字母。

国际化是设计和开发软件应用的过程,使其架构能够支持多种语言和地区设置,而无需进行重大修改。

国际化的关键任务包括:

  • 将所有用户界面元素(如文本、图标)从代码中分离出来,使其可以独立于代码进行更改。
  • 使用通用的日期、时间和数字格式,可以根据用户的地区设置进行调整。
  • 支持多种字符编码,如 UTF-8,确保可以处理各种语言的输入和显示。
  • 设计灵活的布局,可以适应从右到左的阅读顺序等不同的文本方向。

本地化 (l10n)

本地化(Localization)简写为 l10n,其中 l 和 n 分别代表单词的第一个和最后一个字母,中间的"10"代表省略的10个字母。

本地化是将国际化的软件适配到特定地区或语言的过程,涉及翻译文本和调整功能以符合特定文化和语言的需求。

本地化的关键任务包括:

  • 翻译软件界面、帮助文档以及其他用户面向的文本。
  • 调整图形元素,使其符合地区文化的期望和标准。
  • 根据目标市场的习惯和法律要求调整软件功能,如货币、税率计算等。
  • 适应地区特有的日期、时间、地址和电话号码格式。

POT 文件

POT 文件(Portable Object Template)是 GNU gettext 工具链中的翻译模板文件,用于软件国际化和本地化(i18n/l10n)。

它作为翻译模板,存储源代码中提取的原始字符串(通常是英文),供后续生成多语言 PO(Portable Object)文件使用。

文件头:元数据(如语言、字符集、复数形式规则等)

msgid ""
msgstr ""
"Project-Id-Version: MyApp 1.0\n"     # 项目名称和版本
"POT-Creation-Date: 2025-04-28 12:00\n"  # 创建时间
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"  # PO文件修订时间(模板中通常留空)
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"  # 最后译者(PO文件填充)
"Language-Team: LANGUAGE <LL@li.org>\n"       # 翻译团队(PO文件填充)
"Language: \n"                         # 语言代码(PO文件填充,POT中为空)
"MIME-Version: 1.0\n"                  # MIME版本
"Content-Type: text/plain; charset=UTF-8\n"  # 字符集(通常UTF-8)
"Content-Transfer-Encoding: 8bit\n"    # 编码方式
"Plural-Forms: nplurals=2; plural=(n != 1);\n"  # 复数规则(示例为英语)

不同语言的复数形式不同(如俄语有3种复数形式,阿拉伯语有6种),需根据语言调整 nplurals 和 plural 表达式。

PO 文件

PO(Portable Object)特定语言的翻译文件,基于 POT 文件生成,由翻译人员填充具体语言的译文。

示例:

msgid "Hello, world!"
msgstr "你好,世界!"

MO 文件

MO(Machine Object)文件,PO 文件的二进制编译版本,供程序运行时高效加载。

特点:

  • 二进制格式,不可直接编辑。
  • 文件扩展名:.mo。
  • 由 msgfmt 工具从 PO 文件编译生成。
  • 程序通过 gettext() 函数读取 MO 文件中的翻译。

文本域

文本域(Text Domain)是 gettext 中用来管理和隔离翻译资源的一个重要机制。

文本域允许程序将其翻译文件组织在不同的命名空间内,使同一程序可以同时加载多个独立的翻译文件(MO 文件)。

在代码中通过 textdomain() 函数设置当前文本域:

#include <libintl.h>
textdomain("myapp");  // 设置文本域为 "myapp"

在翻译文件中,MO 文件需放在特定路径:

./locale/<语言>/LC_MESSAGES/<文本域>.mo# 例如
./locale/zh_CN/LC_MESSAGES/myapp.mo

若程序需要同时使用多个文本域(如主程序和插件):

// 临时切换文本域(保存旧域)
char* old_domain = textdomain("plugin1");
printf("%s", gettext("Delete"));  // 使用 plugin1 的翻译
textdomain(old_domain);           // 恢复原文本域

注意,MO 文件必须与文本域同名:

文本域 "myapp"  -> MO 文件名为 myapp.mo
文本域 "gtk" -> MO 文件名为 gtk.mo

标准存放路径:

/usr/share/locale/zh_CN/LC_MESSAGES/myapp.mo  # 系统级
./locale/zh_CN/LC_MESSAGES/myapp.mo           # 项目内

翻译函数

函数作用示例
textdomain()设置/获取当前文本域textdomain(“myapp”);
bindtextdomain()指定文本域的 MO 文件搜索路径bindtextdomain(“myapp”, “./locale”);
gettext()根据当前文本域获取翻译gettext(“Hello”);
dgettext()显式指定文本域获取翻译dgettext(“plugin1”, “Save”);
ngettext()根据给定的数量(n)选择正确的单数或复数翻译字符串ngettext(“%d file”, “%d files”, n);

3.主要组件

  1. 开发库

libintl:提供 gettext() 等国际化函数

支持多种编程语言:C, C++, Python, Java, Perl, PHP 等。

  1. 工具集

xgettext:从源代码提取可翻译字符串,生成 POT 文件(翻译模板文件)。

msginit:根据 POT 文件创建新的 PO 文件(翻译文件)。

msgmerge:合并新旧 PO 文件。

msgfmt:将 PO 文件编译为 MO 文件。

  1. 运行时组件

gettext:在运行时根据当前 locale 加载适当的翻译。

4.使用示例

下面以 C 语言给出使用示例。

  1. 标记源代码。
#include <stdio.h>
#include <locale.h>
#include <libintl.h> // gettext 头文件// 定义简化宏(约定俗成)
#define _(STRING) gettext(STRING)
#define LOCALEDIR "/usr/share/locale" // 翻译文件存放目录int main() {// 1.设置本地化环境采用系统默认设置。// 必须调用,否则 gettext 无法正确加载翻译。setlocale(LC_ALL, "");// 2.绑定文本域(指定翻译文件位置和名称)bindtextdomain("hello", LOCALEDIR);textdomain("hello"); // 设置当前文本域// 3.使用可翻译字符串printf(_("Hello, World!\n"));printf(_("This is a demo of gettext.\n"));// 4.带变量的翻译int count = 3;printf(_("You have %d new message.\n"), count);return 0;
}
  1. 提取字符串。

一旦您具有了使用 gettext 调用的代码,您可以使用 xgettext 从中提取消息,并将它们存储在 .pot 中

xgettext -d hello --keyword=_ -o hello.pot main.c

-d hello 指定生成的翻译模板文件(.pot)关联的文本域(text domain)为 “hello”。

文本域是 gettext 系统中用于区分不同模块或应用程序翻译的命名空间。

--keyword 查找被指定关键词包裹的字符串。

生成的翻译模板文件内容如下:

cat hello.pot# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-30 18:31+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"#: main.c:18
#, c-format
msgid "Hello, World!\n"
msgstr ""#: main.c:19
#, c-format
msgid "This is a demo of gettext.\n"
msgstr ""#: main.c:23
#, c-format
msgid "You have %d new message.\n"
msgstr ""
  1. 创建翻译文件。

这里创建中文简体的翻译文件 zh_CN.po。

msginit --input=hello.pot --locale=zh_CN -o hello.po

-i, --input 参数指定输入的模板文件,包含了所有待翻译的字符串。这个文件通常是通过 xgettext 命令从源代码中提取所有标记为翻译的字符串得到的。

-l, --locale参数指定了目标语言的语言代码,这里使用 zh_CN 表示简体中文。语言代码通常由两部分组成:语言(zh)和国家/地区(CN),这里 CN 代表中国。这个参数告诉 msginit 创建一个针对中文简体的 .po 文件。

  1. 编辑翻译文件进行翻译。
msgid "Hello, World!"
msgstr "你好,世界!"msgid "This is a demo of gettext."
msgstr "这是一个gettext的演示。"msgid "You have %d new message.\n"
msgstr "你有 %d 条新消息。\n"
  1. 编译翻译文件。

使用工具 msgfmt 将 PO 文件编译为程序使用的二进制 MO 文件。

msgfmt -o hello.mo hello.po

如果出现如下错误:

zh_CN.po:22:11: invalid multibyte sequence
zh_CN.po:22:16: invalid multibyte sequence
zh_CN.po:22:17: invalid multibyte sequence
...

说明生成的 PO 文件头中的元信息 Content-Type 不对,需要修改成正确的字符编码。

# 原来 GB2312
"Content-Type: text/plain; charset=UTF-8\n"# 改成 UTF-8
"Content-Type: text/plain; charset=UTF-8\n"

为什么使用 msginit 生成的 PO 文件字符编码为 GB2312 呢?

注意: MO 文件必须与文本域同名。

因为代码中使用的文本域为 hello,所以这里生成的 MO 文件需要命名为 hello.mo。

将生成的 MO 文件拷贝至代码中使用的文本域目录:

cp hello.mo /usr/share/locale/zh_CN/LC_MESSAGES/
  1. 验证多语言是否生效。

编译上面的示例程序。

gcc main.c -o hello.out

执行 hello.out 输出如下结果:

LANG=zh_CN.UTF-8 ./hello.out你好,世界!
是一个gettext的演示。
你有 3 条新消息。

注意,执行程序前需要临时设置环境变量 LANG 为 zh_CN.UTF-8,表明程序的语言环境和字符编码为简体中文和 UTF-8,这样程序就可以去 locale 目录找到特定语言的文本域对应的翻译文件(MO 文件),这里是 hello.mo 文件且字符编码为 UTF-8。这样程序就可以将 gettext 包裹的内容翻译成简体中文了。


参考文献

deepseek.com
gettext - GNU Project - Free Software Foundation
使用GNU gettext 来翻译软件 - Weblate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903582.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享:VTK版本的选择 - WPF空域问题

在早期版本中&#xff0c;ActiViz 对 Windows Presentation Foundation (WPF) 框架的支持是通过 WindowsFormHost 组件实现的&#xff0c;这种方式依赖于 WindowsForm 和 WPF 的互操作性。然而&#xff0c;这种方法存在一个众所周知的“空域问题”&#xff08;airspace issue&a…

python数据分析(六):Pandas 多数据操作全面指南

Pandas 多数据操作全面指南&#xff1a;Merge, Join, Concatenate 与 Compare 1. 引言 在数据分析工作中&#xff0c;我们经常需要处理多个数据集并将它们以各种方式组合起来。Pandas 提供了多种强大的多数据操作方法&#xff0c;包括合并(merge)、连接(join)、连接(concaten…

spring 面试题

一、Spring 基础概念 什么是 Spring 框架&#xff1f; Spring 是一个开源的 Java 应用程序框架&#xff0c;它提供了一种轻量级的、非侵入式的方式来构建企业级应用。Spring 的核心功能包括依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;、面向切面编程…

OpenCV-Python (官方)中文教程(部分一)_Day20

22.直方图 22.1直方图的计算,绘制与分析 使用 OpenCV 或 Numpy 函数计算直方图 使用 Opencv 或者 Matplotlib 函数绘制直方图 将要学习的函数有&#xff1a;cv2.calcHist(),np.histogram() 什么是直方图呢&#xff1f;通过直方图你可以对整幅图像的灰度分布有一个整体的 了…

数电发票整理:免费实用工具如何高效解析 XML 发票数据

如今数字电子发票越来越普及&#xff0c;但是数电发票的整理还是颇有讲究~ 今天给大家介绍一个 XML 发票阅读器。使用它完全不收取任何费用&#xff0c;且无广告干扰&#xff0c;对财务人员而言十分实用。 01 软件介绍 这款软件就是XML格式&#xff08;数电票&#xff09;阅读…

深度学习正则化:原理、方法与应用深度解析

摘要 本文深入探讨深度学习中的正则化技术&#xff0c;介绍其避免过拟合的重要性&#xff0c;详细讲解常见的正则化方法&#xff0c;如 L 1 L_1 L1​和 L 2 L_2 L2​正则化、Dropout等&#xff0c;并通过线性回归案例和神经网络训练流程对其进行直观阐释。帮助读者理解正则化原…

【爬虫】deepseek谈爬虫工具

2025 年&#xff0c;随着 Web 技术的演进和反爬机制的升级&#xff0c;工具生态也会进一步优化。以下是 2025 年爬虫 & 自动化测试的前沿工具预测&#xff0c;结合行业趋势和现有技术发展方向&#xff1a; &#x1f680; 2025 年推荐组合&#xff08;预测版&#xff09; 1…

SQLMesh 测试自动化:提升数据工程效率

在现代数据工程中&#xff0c;确保数据模型的准确性和可靠性至关重要。SQLMesh 提供了一套强大的测试工具&#xff0c;用于验证数据模型的输出是否符合预期。本文将深入探讨 SQLMesh 的测试功能&#xff0c;包括如何创建测试、支持的数据格式以及如何运行和调试测试。 SQLMesh …

Java学习手册:Spring 中常用的注解

一、组件注解 Component &#xff1a;用于标记一个类为 Spring 管理的 Bean&#xff0c;是 Spring 的基本组件注解。Spring 会通过类路径扫描自动检测并注册标记了 Component 的类为 Bean。Service &#xff1a;是 Component 的派生注解&#xff0c;用于标记服务层类&#xff…

前端跨域问题详解:原因、解决方案与最佳实践

引言 在现代Web开发中&#xff0c;跨域问题是前端工程师几乎每天都会遇到的挑战。随着前后端分离架构的普及和微服务的发展&#xff0c;跨域请求变得愈发常见。本文将深入探讨跨域问题的本质、各种解决方案以及在实际开发中的最佳实践。 一、什么是跨域问题&#xff1f; 1.1…

[计算机网络]物理层

文章目录 物理层的概述与功能传输介质双绞线:分类:应用领域: 同轴电缆&#xff1a;分类: 光纤&#xff1a;分类: 无线传输介质&#xff1a;无线电波微波&#xff1a;红外线&#xff1a;激光&#xff1a; 物理层设备中继器&#xff1a;放大器&#xff1a;集线器(Hub)&#xff1a…

大连理工大学选修课——机器学习笔记(9):线性判别式与逻辑回归

线性判别式与逻辑回归 概述 判别式方法 产生式模型需要计算输入、输出的联合概率 需要知道样本的概率分布&#xff0c;定义似然密度的隐式参数也称为基于似然的分类 判别式模型直接构造判别式 g i ( x ∣ θ i ) g_i(x|\theta_i) gi​(x∣θi​)&#xff0c;显式定义判别式…

OpenCV 图像处理核心技术 (第二部分)

欢迎来到 OpenCV 图像处理的第二部分&#xff01;在第一部分&#xff0c;我们学习了如何加载、显示、保存图像以及访问像素等基础知识。现在&#xff0c;我们将深入探索如何利用 OpenCV 提供的强大工具来修改和分析图像。 图像处理是计算机视觉领域的基石。通过对图像进行各种…

【鸿蒙HarmonyOS】一文详解华为的服务卡片

7.服务卡片 1.什么是卡片 Form Kit&#xff08;卡片开发服务&#xff09;提供一种界面展示形式&#xff0c;可以将应用的重要信息或操作前置到服务卡片&#xff08;以下简称“卡片”&#xff09;&#xff0c;以达到服务直达、减少跳转层级的体验效果。卡片常用于嵌入到其他应…

探索目标检测:边界框与锚框的奥秘

笔者在2022年开始学习目标检测的时候&#xff0c;对各种框的概念那是相当混淆&#xff0c;比如&#xff1a; 中文名词&#xff1a;边界框、锚框、真实框、预测框等英文名词&#xff1a;BoundingBox、AnchorBox、Ground Truth等 同一个英文名词比如BoundingBox翻译成中文也有多个…

[原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何使用原生NSAlert消息框 (runModal模式)

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…

LangChain的向量RAG与MCP在意图识别的主要区别

LangChain的向量RAG与MCP在意图识别实现上的区别主要体现在技术路径、流程设计以及应用场景三个方面&#xff1a; 1. 技术路径差异 LangChain向量RAG 语义相似度驱动&#xff1a;通过用户输入的原始查询与向量化知识库的语义匹配实现意图识别。例如&#xff0c;用户提问"…

[特殊字符] Spring Cloud 微服务配置统一管理:基于 Nacos 的最佳实践详解

在微服务架构中&#xff0c;配置文件众多、管理复杂是常见问题。本文将手把手演示如何将配置集中托管到 Nacos&#xff0c;并在 Spring Cloud Alibaba 项目中实现统一配置管理 自动刷新机制。 一、为什么要使用 Nacos 统一配置&#xff1f; 传统方式下&#xff0c;每个服务都…

2025平航杯—团队赛

2025平航杯团队赛 计算机取证 分析起早王的计算机检材&#xff0c;起早王的计算机插入过USB序列号是什么(格式&#xff1a;1)分析起早王的计算机检材&#xff0c;起早王的便签里有几条待干(格式&#xff1a;1)分析起早王的计算机检材&#xff0c;起早王的计算机默认浏览器是什…

JSON-RPC 2.0 规范中文版——无状态轻量级远程过程调用协议

前言 JSON-RPC是一种简单、轻量且无状态的远程过程调用&#xff08;RPC&#xff09;协议&#xff0c;它允许不同系统通过标准化的数据格式进行通信。自2010年由JSON-RPC工作组发布以来&#xff0c;已成为众多应用中实现远程交互的基础协议之一。本规范主要表达了JSON-RPC 2.0版…