跳转到内容

FOSS 本地化/附录 B:技术方面

来自 Wikibooks,开放世界中的开放书籍

在本附录中,我们将讨论更多技术细节。 目的是为实施者提供开始本地化的必要信息。 但是,这并非旨在成为动手操作的食谱。

作为一种包含世界所有字符的通用字符集,Unicode 通过 16 位整数为其字符分配代码点,这意味着最多可以编码 65,536 个字符。 然而,由于 CJK 字符集庞大,这已变得不够用,Unicode 3.0 将索引扩展到 21 位,这将支持多达 1,114,112 个字符。

Unicode 代码点是介于 0 和 10FFFF 之间的数值,被划分为 64K 个字符的平面。 在 Unicode 4.0 中,已分配的平面是平面 0、1、2 和 14。

平面 0,范围从 0000 到 FFFF,称为基本多语言平面 (BMP),这是先前 16 位方案分配的字符集。

平面 1,范围从 10000 到 1FFFF,称为补充多语言平面 (SMP),专门用于使用较少的历史文字、专用发明文字和特殊符号。 这些包括哥特式、萧伯纳式和音乐符号。 未来,许多历史文字可能会在这个平面中编码。

平面 2,范围从 20000 到 2FFFF,称为补充表意文字平面 (SIP),是那些无法放入 BMP 中常用 CJK 字符块的 CJK 字符的溢出分配区域。

平面 14,范围从 E0000 到 EFFFF,称为补充专用平面 (SSP),用于一些无法放入 BMP 中分配的小区域的控制字符。

还有两个保留的平面:平面 15 和平面 16,供私人使用,其中没有分配代码点。

基本多语言平面

[编辑 | 编辑源代码]

基本多语言平面 (BMP) 或平面 0 最常见于通用文档。 代码点为当代文字中的常用字符分配,与 ISO/IEC 10646-1 的集合完全相同,如第 ý0 节中的图 2 所示。请注意,E000 到 F900 之间的代码点保留供供应商私人使用。 此区域中未分配任何字符。

字符编码

[编辑 | 编辑源代码]

有几种方法可以对 Unicode 字符串进行编码以进行信息交换。 一个人可以使用固定大小的整数(称为宽字符)简单地表示每个字符,这是由 ISO/IEC 10646 定义的 UCS-2 和 UCS-4,分别使用 2 字节和 4 字节整数 [1],其中 UCS-2 仅适用于 BMP。 但常见的做法是使用称为 UTF-8、UTF-16 和 UTF-32 的可变长度整数序列对字符进行编码,分别用于 8 位、16 位和 32 位整数。 [2] 还有 UTF-7 用于 7 位严格的电子邮件传输,但 UTF-8 在大多数情况下是安全的。

UTF-32 是最简单的 Unicode 编码形式。 每个 Unicode 代码点都由单个 32 位无符号整数直接表示。 因此,它是一种固定宽度字符编码形式。 这使得 UTF-32 成为传递单个字符值的 API 的理想形式。 但是,它在 Unicode 字符串的存储方面效率低下。

图 2:Unicode 基本多语言平面

UTF-16 将范围为 0000 到 FFFF(即 BMP)的代码点编码为单个 16 位无符号整数。

补充平面中的代码点则表示为一对 16 位无符号整数。 这些代码单元对称为代理对。 用于代理对的值在范围 D800 - DFFF 之内,它们未分配给任何字符。 因此,UTF-16 阅读器可以轻松区分单个代码单元和代理对。 Unicode 标准 [3] 提供了有关代理的更多详细信息。

UTF-16 是保存通用 Unicode 字符串的不错选择,因为它针对 BMP 中的字符进行了优化,BMP 用于 99% 的 Unicode 文本中。 它消耗的存储量约为 UTF-32 所需存储量的一半。

为了满足传统字节取向的基于 ASCII 的系统的需求,UTF-8 被定义为一种可变宽度编码形式,它保留了 ASCII 兼容性。它使用 1 到 4 个 8 位代码单元来表示一个 Unicode 字符,具体取决于代码点值。代码点在 0000 到 007F 之间用一个字节编码,使任何 ASCII 字符串成为有效的 UTF-8。超出 Unicode 的 ASCII 范围,一些非表意字符在 0080 到 07FF 之间用两个字节编码。然后,印度文字和 0800 到 FFFF 之间的 CJK 表意文字用三个字节编码。BMP 之外的补充字符需要四个字节。Unicode 标准 [4] 提供了有关 UTF-8 的更多详细信息。

UTF-8 通常是互联网首选的编码形式。ASCII 兼容性在从旧系统迁移中帮助很大。UTF-8 还具有字节序列化和对 C 或其他编程语言 API 友好的优点。例如,使用字节比较的传统字符串排序在 UTF-8 中有效。

简而言之,UTF-8 是 Unicode 最广泛采用的编码形式。

字符属性

[edit | edit source]

除了代码点之外,Unicode 还提供了一个称为 _Unicode 字符数据库 (UCD)_ 的字符属性数据库,[5] 它包含一组描述以下属性的文件

  • 名称。
  • 一般类别(分类为字母、数字、符号、标点符号等)。
  • 其他重要的一般特征(空格、连字符、表意文字、字母、非字符、已弃用等)。
  • 字符整形(双向类别、整形、镜像、宽度等)。
  • 大小写(大写、小写、标题、折叠;简单和完整)。
  • 数字值和类型(用于数字)。
  • 脚本和块。
  • 规范化属性(分解、分解类型、规范组合类、组合排除等)。
  • 年龄(标准中首次指定代码点的版本)。
  • 边界(音节簇、单词、行和句子)。
  • 标准化变体。

该数据库对 Unicode 实现通常很有用。它可以在 Unicode.org 网站上找到。Unicode 标准 [6] 提供了有关该数据库的更多详细信息。

技术报告

[edit | edit source]

除了代码点、编码形式和字符属性之外,Unicode 还提供了一些技术报告,可作为实现指南。其中一些报告已作为附件包含在 Unicode 标准中,另一些则作为技术标准单独发布。

在 Unicode 4.0 中,标准附件是

UAX 9:双向算法
从右到左流动的字符(如阿拉伯语或希伯来语)的定位规范。
UAX 11:东亚宽度
与东亚传统字符集交互时有用的 Unicode 字符信息属性规范。
UAX 14:换行属性
Unicode 字符换行属性规范以及确定换行机会的模型算法。
UAX 15:Unicode 规范化形式
Unicode 文本四种规范化形式规范。使用这些形式,等效文本(规范或兼容)将具有相同的二进制表示。当实现将字符串保留在规范化形式时,可以确保等效字符串具有唯一的二进制表示。
UAX 24:脚本名称
将脚本名称分配给所有 Unicode 代码点。此信息在正则表达式等机制中很有用,因为它比简单地匹配块名称产生更好的结果。
UAX 29:文本边界
确定某些重要文本元素之间的默认边界的指南:音节簇(“用户字符”)、单词和句子。

各个技术标准是

UTS 6:Unicode 标准压缩方案
Unicode 压缩方案规范和示例实现。
UTS 10:Unicode 排序算法
在符合 Unicode 标准要求的情况下,如何比较两个 Unicode 字符串的规范。UCA 还提供了默认 Unicode 排序元素表 (DUCET) 作为数据,指定所有 Unicode 字符的默认排序顺序。
UTS 18:Unicode 正则表达式指南
关于如何调整正则表达式引擎以使用 Unicode 的指南。

所有 Unicode 技术报告都可以从 Unicode.org 网站访问。[7]

字体

[edit | edit source]

字体开发工具

[edit | edit source]

有一些用于开发字体的 FOSS 工具可用。虽然数量不如专有工具多,但它们足以完成工作,并且正在不断改进。以下是一些有趣的例子

_XmBDFEd_。[8]
XmBDFEd 由 Mark Leisher 开发,是一款基于 Motif 的 BDF 字体开发工具。它允许编辑字体的位图字形,对字形进行一些简单的变换,在不同的字体之间传输信息等。
FontForge(以前称为 PfaEdit [9].
FontForge 由 George Williams 开发,是一款用于开发轮廓字体的工具,包括 Postscript Type1、TrueType 和 OpenType。可以导入字母的扫描图像并自动跟踪它们的轮廓矢量。可以编辑样条线,并且可以应用诸如倾斜、缩放、旋转、加厚等变换,以及更多操作。它提供了足够的编辑 Type1 和 TrueType 字体属性的功能。在最近的版本中,还可以编辑 OpenType 表格。但是,一个弱点是提示。它保证了 Type1 提示的质量,但不保证 TrueType 的质量。
_TTX/FontTools_ [10]
Just van Rossum 的 TTX/FontTools 是一种将 OpenType 和 TrueType 字体转换为 XML 的工具,反之亦然。FontTools 是一个用于操作字体的库,用 Python 编写。它支持 TrueType、OpenType、AFM,并在一定程度上支持 Type 1 和某些 Mac 特定的格式。它允许转储 OpenType 表格,使用 XML 或纯文本编辑器检查和编辑它们,并将它们合并回字体。

字体配置

[edit | edit source]

GNU/Linux 桌面中已有多个字体配置系统可用。最基本的是 X 窗口字体系统本身。但是,由于最近的一些发展,另一个名为 fontconfig 的字体配置已经开发出来,以满足现代桌面的某些特定要求。这两个字体配置将简要讨论。

首先,让我们简要讨论一下 X 窗口架构,以了解字体系统。X 窗口 [11] 是一个客户端-服务器系统。_X 服务器_ 是提供服务的代理,以控制硬件设备,例如视频卡、显示器、键盘、鼠标或触控板,以及将用户输入事件从设备传递给客户端。_X 客户端_ 是 GUI 应用程序,它们请求 X 服务器在屏幕上绘制图形对象,并通过 X 服务器馈送的事件接受用户输入。请注意,使用这种架构,X 客户端和服务器可以在网络中的不同机器上。在这种情况下,X 服务器是用户操作的机器,而 X 客户端可以是运行在同一机器或网络中的远程机器上的进程。

在这种客户端-服务器架构中,字体在服务器端提供。因此,安装字体意味着通过安装字体并将它们注册到其字体路径来配置 X 服务器。

然而,由于 X 服务器有时用于在某些部署中提供瘦客户端访问,其中 X 服务器可能在由软盘引导或通过网络引导的廉价 PC 上运行,甚至从 ROM 中运行,因此并非总是适合在每个 X 服务器上安装字体。因此,字体服务已被委托给一个名为 _X 字体服务器 (XFS)_ 的单独服务。网络中的另一台机器可以专门用于字体服务,以便所有 X 服务器都可以请求字体信息。因此,使用这种结构,X 服务器可以配置为自行管理字体或使用字体服务器中的字体,或两者兼而有之。

但是,XFree86 中的最新更改已经解决了一些在客户端管理字体的需求。Xft 扩展通过 X 客户端提供的字体信息提供了抗锯齿字形图像。为此,Xft 扩展还在其第一个版本中为 X 客户端提供了字体管理功能。这后来从 Xft2 中拆分出来,成为一个名为 fontconfig 的单独库。_fontconfig_ 是一个独立于 X 的字体管理系统,这意味着它也可以应用于非 GUI 应用程序,例如打印服务。现代桌面,包括 KDE 3 和 GNOME 2,已将 fontconfig 作为其字体管理系统,并且得益于更紧密的集成,提供了简单的字体安装流程。此外,客户端字体还允许应用程序进行所有字形操作,例如制作特殊效果,同时在屏幕和打印输出中享受一致的外观。

X 客户端-服务器架构的拆分不是独立桌面上的标准做法。但是,重要的是要始终记住拆分,以启用特定功能。

输出方法

[edit | edit source]

由于 XOM 的实用性仍在讨论中,我们将只讨论在两个主要工具包中已实现的输出方法:Pango of GTK+Qt

Pango 文本布局引擎

[edit | edit source]

Pango ['Pan' 在英语中意为“所有”,而 'go' 在日语中意为“语言”] [12] 是一个为高质量文本排版而设计的多种语言文本布局引擎。虽然它是 GTK+ 的文本绘制引擎,但它也可以在 GTK+ 之外用于其他目的,例如打印。[13] 本节将为本地化人员提供对 Pango 的概览。有关更多详细信息,请参考 Pango 参考手册。[14]

PangoLayout

[edit | edit source]

从较高层次上讲,Pango 提供了 PangoLayout 类,它负责在给定宽度的一列中排版文本,以及其他编辑所需的信息,例如光标位置。其功能可概括如下

段落属性

  • 缩进
  • 间距
  • 对齐
  • 对齐方式
  • 字词/字符换行模式
  • 制表符

文本元素

  • 获取行及其范围
  • 获取运行及其范围
  • 在 (x, y) 位置进行字符搜索
  • 字符逻辑属性(是否换行,是否光标位置等)
  • 光标移动

文本内容

  • 纯文本
  • 标记文本

中级处理

[edit | edit source]

Pango 还提供了一些中级文本处理函数的访问权限,尽管大多数客户端通常不会直接使用它们。为了简要了解 Pango 内部机制,这里将讨论一些重点内容。

Pango 中,文本处理主要包括三个步骤:[15]

  • 项目化。 将输入文本分解成方向和整形引擎一致的块(项目)。这通常意味着相同语言、使用相同字体的文本块。相应的整形和语言引擎也与这些项目相关联。
  • 断行。 在给定文本项目中确定可能的行、字词和字符断点。它会调用项目中的语言引擎(或基于 Unicode 数据的默认引擎,如果不存在语言引擎)来分析字符的逻辑属性(是否换行,是否字符断点等)。
  • 整形。 将文本项目转换为字形,并进行适当的定位。它会调用项目中的整形引擎(或当前适合欧洲语言的默认整形引擎)来获取字形字符串,该字符串提供渲染字形所需的信息(代码点、宽度、偏移量等)。

Pango 引擎

[edit | edit source]

Pango 引擎是在可加载模块中实现的,这些模块提供用于查询和创建所需引擎的入口函数。在初始化期间,Pango 会查询内存中所有已安装引擎的列表。然后,当它对输入文本进行项目化时,它也会搜索列表中针对每个项目脚本可用的语言和整形引擎,并创建它们以与相关的文本项目关联。

Pango 语言引擎

[edit | edit source]

如上所述,Pango 语言引擎被调用以确定特定语言文本项目中可能的断点位置。它提供了一种方法来分析文本中每个字符的逻辑属性,如表 3 所列。

表 3 Pango 逻辑属性
标志 描述
is_line_break 可以在字符前面断行
is_mandatory_break 必须 在字符前面断行
is_char_break 在进行字符换行时可以在这里断行
is_white 是空格字符
is_cursor_position 光标可以出现在字符前面
is_word_start 是单词中的第一个字符
is_word_end 是单词后第一个非单词字符
is_sentence_boundary 是句子间空格
is_sentence_start 是句子中的第一个字符
is_sentence_end 是句子后第一个非句子字符
backspace_deletes_character 退格键会删除一个字符,而不是整个字簇(Pango 1.3.x 中的新功能)

Pango 整形引擎

[edit | edit source]

如上所述,Pango 整形引擎会将特定语言文本项目中的字符转换为字形,并根据脚本约束对其进行定位。它提供了一种方法,将给定的文本字符串转换为一系列字形信息(字形代码、宽度和定位)以及逻辑映射,该映射将字形映射回原始文本中的字符位置。有了所有提供的信息,文本就可以在输出设备上正确渲染,并且光标也可以访问它,尽管某些脚本(如印度语、希伯来语和阿拉伯语)中逻辑顺序和渲染顺序有所不同。

Qt 文本布局

[edit | edit source]

Qt 3 的文本渲染与 GTK+/Pango 的文本渲染不同。它不是进行模块化,而是在一个名为 QComplexText 的类中处理所有复杂的文本渲染,该类主要基于 Unicode 字符数据库。这等效于 Pango 提供的默认例程。由于 Unicode 数据库的不完整性,此类有时需要额外的变通方法来覆盖某些值。如果脚本渲染不正确,开发人员应该检查此类。

虽然依赖 Unicode 数据库似乎是一种渲染 Unicode 文本的直接方法,但这使得该类变得僵化且容易出错。建议定期检查 Qt 网站以查看最新版本中是否存在错误。但是,Qt 4 计划进行一项重大更改,即 Scribe 文本布局引擎,类似于 GTK+ 的 Pango。

输入法

[edit | edit source]

第 37 页讨论了键盘映射和输入法的需求。本节将进一步讨论如何实现它们,从键盘布局开始。第 37-38 页还提到,XIM 是当前 X Window 的基本输入法框架。只有 Qt 3 依赖它,而 GTK+ 2 定义了自己的输入法框架。XIM 和 GTK+ IM 都将在本文中讨论。

键盘布局

[edit | edit source]

为特定语言提供文本输入的第一步是准备键盘映射。X Window 使用 X 键盘 (XKB) 扩展来处理键盘映射。当您在 GNU/Linux 上启动 X 服务器时,一个虚拟终端会以原始模式连接到它,这样键盘事件就会从内核发送,没有任何转换。

然后,按键的 原始扫描码 会根据键盘型号转换为 键码。对于 PC 上的 XFree86,键码映射通常为 "xfree86",如 /etc/X11/xkb/keycodes 目录中所保存的那样。键码只是以符号形式表示键的位置,用于进一步引用。

然后,根据指定的布局(例如 qwerty、dvorak 或特定语言的布局),从 /etc/X11/xkb/symbols 目录下的数据中选择,将keycode 转换为键盘符号(keysym)。Keysym 尚未表示字符。它需要一个输入法来将一系列键事件转换为字符,这将在后面介绍。对于 XFree86,所有上述设置都是通过setxkbmap 命令完成的。(在/etc/X11/XF86Config 中设置值意味着在 X 服务器启动时为setxkbmap 设置参数。)有很多方法可以描述配置,如 Ivan Pascal 的 XKB 说明中所述。[16] XFree86 4.x 的默认方法是 "xfree86" 规则(XKB 规则保存在/etc/X11/xkb/rules 下),并带有其他参数

  • model - pc104、pc105、microsoft、microsoftplus、...
  • mlayout - us、dk、ja、lo、th、...
    (对于 XFree86 4.0+,最多可以提供 64 个组作为布局定义的一部分)
  • variant - (主要用于拉丁语)nodeadkeys
  • option- 组切换键、交换大小写、LED 指示灯等。
    (请参阅/etc/X11/xkb/rules/xfree86 以了解所有可用选项。)

例如

$ setxkbmap us,th -option grp:alt_shift_toggle,grp_led:scroll

使用 US 符号作为第一个组,泰语符号作为第二个组来设置布局。Alt-Shift 组合用于在两个组之间切换。滚动锁定 LED 将作为组指示器,当当前组不是第一个组时,它将处于打开状态,即对于泰语,打开,对于 US,关闭。

你甚至可以混合两种以上的语言

$ setxkbmap us,th,lo -option grp:alt_shift_toggle,grp_led:scroll

这将加载三语种布局。Alt-Shift 用于在三个组之间循环;也就是说,Alt-RightShift 选择下一个组,而 Alt-LeftShift 选择上一个组。滚动锁定 LED 将在泰语或老挝语组处于活动状态时亮起。

可以通过在/etc/X11/XF86Config 中指定setxkbmap 的参数来在 X 服务器启动时进行初始化,方法是描述键盘的 "InputDevice" 部分,例如

Section "InputDevice"
    Identifier "Generic Keyboard"
    Driver "keyboard"
    Option "CoreKeyboard"
    Option "XkbRules" "xfree86"
    Option "XkbModel" "microsoftplus"
    Option "XkbLayout" "us,th_tis"
    Option "XkbOptions grp:alt_shift_toggle,lv3:switch,grp_led:scroll"
EndSection

注意最后四行选项。它们告诉setxkbmap 使用 "xfree86" 规则,使用 "microsoftplus" 模型(带有互联网键),混合了 US 和泰语 TIS-820.2538 的布局,以及一些用于组切换键和 LED 指示灯的更多选项。"lv3:switch" 选项仅适用于需要第三级换档(即比普通换档键多一级)的键盘布局。在本例中,对于 XFree86 4.4.0 中的 "th_tis",此选项将RightCtrl 设置为第三级换档。

提供键盘映射

[edit | edit source]

如果一种语言的键盘映射不可用,则需要准备一个新的键盘映射。在 XKB 术语中,需要准备一个symbols 映射,将keysyms 与可用的 keycode 关联起来。

最快的入门方法是阅读/etc/X11/xkb/symbols 目录下可用的 symbols 文件。特别是,XFree86 4.3.0 默认规则使用的文件位于pc/ 子目录下。这里,每个文件只定义一个组,这与父目录下的旧文件不同,旧文件中的组是预先组合的。这是因为 XFree86 4.3.0 提供了一种灵活的方法来混合键盘布局。

因此,除非你需要支持旧版本的 XFree86,否则你只需要在pc/ 子目录下准备一个单组符号文件。

以下是th_tis 符号文件的摘录

partial default alphanumeric_keys
xkb_symbols "basic" {
    name[Group1]= "Thai (TIS-820.2538)";
    // The Thai layout defines a second keyboard group and changes
    // the behavior of a few modifier keys.
    key <TLDE> { [ 0x1000e4f, 0x1000e5b ] };
    key <AE01> { [ Thai_baht, Thai_lakkhangyao] };
    key <AE02> { [ slash, Thai_leknung ] };
    key <AE03> { [ minus, Thai_leksong ] };
    key <AE04> { [ Thai_phosamphao, Thai_leksam ] };
    ...
};

xkb_symbols 数据中的每个元素(第一个元素除外)都是 keysyms 与 keycode 的关联,分别对应于未按 shift 和按 shift 版本。这里,一些 keysyms 在 Xlib 中是预定义的。你可以在 <X11/keysymdef.h> 中找到完整的列表。如果一种语言的 keysyms 在那里没有定义,可以使用 Unicode keysyms,如<TLDE> 键条目所示。(事实上,这可能是添加新 keysyms 的一种更有效的方法。)Unicode 值必须以 "0x100" 为前缀来描述单个字符的 keysym。

有关文件格式的更多详细信息,请参阅 Ivan Pascal 的 XKB 说明。[17] 完成后,应重新生成 symbols.dir 文件,以便列出 symbols 文件

# cd /etc/X11/xkb/symbols
# xkbcomp -lhlpR '*' -o ../symbols.dir

然后,可以按照上一节中描述的方法测试新的布局。

此外,还可以向/etc/X11/xkbcomp/rules/xfree86.lst 添加条目,以便某些 GUI 键盘配置工具可以查看布局。

完成新的键盘映射后,还可以将其包含在 XFree86 源代码中,其中 XKB 的数据保存在xc/programs/xkbcomp 子目录下。

XIM - X 输入法

[edit | edit source]

对于某些语言,文本输入与从 keysyms 到字符的一对一映射一样简单,例如英语。对于欧洲语言来说,这稍微复杂一些,因为有重音符号。但对于中文、日文和韩文(CJK),一对一映射是不可能的。它们需要一系列击键解释才能获得每个字符。

X 输入法(XIM) 是一个基于区域设置的框架,旨在满足任何语言的文本输入需求。它是一个独立的服务,用于处理 X 客户端请求的输入事件。X 客户端中的所有文本输入都由X 输入上下文(XIC)表示。所有键盘事件都将传播到 XIM,XIM 根据 XIC 的当前状态确定对事件的适当操作,并将生成的字符传回。

在内部,每个 XIM 的通用过程是通过调用 XKB 将键盘扫描代码转换为 keycode,然后转换为 keysym,其过程细节已在前面的章节中介绍。将 keysyms 转换为字符的后续过程因不同的区域设置而异。

在一般情况下,XIM 通常使用客户端-服务器模型实现。XIM 实现的更详细讨论超出了本文档的范围。有关更多信息,请参阅 Xlib 文档[18] 的第 13.5 节和 XIM 协议[19]

通常情况下,用户可以通过设置系统环境变量 XMODIFIERS 来选择他们喜欢的 XIM 服务器,如下所示

$ export LANG=th_TH.TIS-620
$ export XMODIFIERS="@im=Strict"

这指定了泰语区域设置的Strict 输入法。

GTK+ IM

[edit | edit source]

作为跨平台工具包,GTK+ 2 定义了自己的框架,使用纯 GTK+ API,而不是依赖于每个操作系统的输入法。这提供了高级抽象,使输入法开发比编写 XIM 服务器更容易。无论如何,GTK+ 仍然可以通过imxim 桥接模块使用现有的几个 XIM 服务器。此外,开发的输入法会立即在它支持的所有平台上对 GTK+ 可用,包括 XFree86、Windows 和 GNU/Linux 帧缓冲控制台。唯一的缺点是输入法无法与非 GTK+ 应用程序共享。

客户端

[edit | edit source]

一个普通的基于 GTK+ 的文本输入小部件将提供一个 "输入法" 上下文菜单,可以通过在文本区域内右键单击来打开。此菜单提供了所有已安装的 GTK+ IM 模块的列表,用户可以从中选择。菜单通过查询所有已安装的模块来初始化它们提供的引擎。

从客户端的角度来看,每个文本输入都由一个IM 上下文表示,它在每次按键事件后通过调用模块提供的键过滤器函数与 IM 模块进行通信。这允许 IM 拦截按键并将它们转换为字符。非字符键(例如功能键或控制键)通常不会被拦截。这允许客户端处理特殊键,例如快捷键。

还有一些用于其他方向的接口。IM 还可以通过发出 GLib 信号来调用客户端执行某些操作,客户端可以通过将回调连接到这些信号来提供处理程序

"preedit_changed"
未提交的(预编辑)字符串已更改。客户端可以更新显示,但不更新输入缓冲区,以便让用户看到按键。
"commit"
一些字符已从 IM 提交。提交的字符串也被传递,以便客户端可以将其包含到其输入缓冲区中。
"retrieve_surrounding"
IM 希望检索光标周围的一些文本。
"delete_surrounding"
IM 希望删除光标周围的文本。客户端应该按要求删除光标周围的文本部分。

IM 模块

[edit | edit source]

GTK+ 输入法是使用可加载模块实现的,这些模块提供用于查询和创建所需 IM 上下文的入口函数。这些用作文本输入区域中 "输入法" 上下文菜单的接口。

IM 模块定义了一个或多个新的 IM 上下文类,并提供过滤器函数,供客户端在按键事件发生时调用。它可以确定对键的适当操作,并在拦截事件时返回 TRUE,或在将事件传回客户端时返回 FALSE。

某些 IM(例如 CJK 和欧洲)可能执行状态转换,该转换会将输入字符串与预定义的模式进行增量匹配,直到每个唯一的模式都匹配,然后才提交转换后的字符串。在部分匹配期间,IM 为每次更改向客户端发出 "preedit_changed" 信号,以便它可以将预编辑字符串更新到显示。最后,要提交字符,IM 向 IM 上下文发出 "commit" 信号,并将转换后的字符串作为参数传递。某些 IM(例如泰语)是上下文敏感的。它需要检索光标周围的文本以确定适当的操作。这可以通过 "retrieve_surrounding" 信号来实现。

此外,IM 可能会根据泰国高级 IM 的要求请求删除客户端输入缓冲区中的部分文本。这也用于更正非法序列。可以通过“delete_surrounding”信号完成此操作。

语言环境

[编辑 | 编辑源代码]

如前所述,GNU C 库 根据 POSIX 和 ISO/IEC 14652 国际化。本节将讨论这两个语言环境

语言环境命名

[编辑 | 编辑源代码]

一个语言环境 由其语言、国家和字符集描述。OpenI18N 指南[20] 中给出的命名约定为

lang_territory.codeset[@modifiers]

其中

  • lang 是 ISO 639:1988 中定义的两位字母语言代码。在没有两位字母版本的情况下,ISO 639-2 中的三位字母代码也被允许。美国国会图书馆的 ISO 639-2 注册机构[21] 有一个完整的语言代码列表。
  • territory 是 ISO 3166-1:1997 中定义的两位字母国家代码。两位字母国家代码列表可从 ISO 3166 维护机构网站在线获取。[22]
  • codeset 描述了语言环境中使用的字符集。
  • modifiers 通过设置选项(打开标志或使用等号设置值)为语言环境添加更多信息。选项用逗号分隔。这部分是可选的,并且依赖于实现。不同的 I18N 框架提供不同的选项。

例如

  • fr_CA.ISO-8859-1= 使用 ISO-8859-1 字符集的加拿大法语
  • th_TH.TIS-620 = 使用 TIS-620 编码的泰国泰语

如果省略territorycodeset,通常通过语言环境别名解析默认值。

请注意,对于GNU/Linux 桌面,目前不支持modifiers 部分。X Window 的语言环境修改器需要通过 XMODIFIERS 环境设置。

字符集

[编辑 | 编辑源代码]

字符集是语言环境定义的一部分。它定义了字符集中的所有字符以及它们如何在信息交换中进行编码。在 GNU C 库 (glibc) 中,语言环境是用 Unicode 描述的。

新的字符集被描述为 Unicode 子集,其中每个元素通过一个字节字符串与目标字符集中要编码的字节字符串相关联。例如,UTF-8 编码的描述如下

...
<U0041> /x41         LATIN CAPITAL LETTER A
<U0042> /x42         LATIN CAPITAL LETTER B
<U0043> /x43         LATIN CAPITAL LETTER C
...
<U0E01> /xe0/xb8/x81 THAI CHARACTER KO KAI
<U0E02> /xe0/xb8/x82 THAI CHARACTER KHO KHAI
<U0E03> /xe0/xb8/x83 THAI CHARACTER KHO KHUAT
...

第一列是 Unicode 值。第二列是编码的字节字符串。其余的是注释。

另一个例子是泰语的 TIS-620 编码,它是一个简单的 8 位单字节编码。代码表的前半部分与 ASCII 相同,后半部分从 0xA1 开始编码第一个字符。因此,字符映射看起来像

...
<U0041> /x41         LATIN CAPITAL LETTER A
<U0042> /x42         LATIN CAPITAL LETTER B
<U0043> /x43         LATIN CAPITAL LETTER C
...
<U0E01> /xa1         THAI CHARACTER KO KAI
<U0E02> /xa2         THAI CHARACTER KHO KHAI
<U0E03> /xa3         THAI CHARACTER KHO KHUAT
...

POSIX 语言环境

[编辑 | 编辑源代码]

根据POSIX,标准 C 库函数根据以下类别进行国际化

类别 描述
LC_CTYPE 字符分类
LC_COLLATE 字符串排序
LC_TIME 日期和时间格式
LC_NUMERIC 数字格式
LC_MONETARY 货币格式
LC_MESSAGES 语言环境语言的消息

设置语言环境

[编辑 | 编辑源代码]

C 应用程序可以使用setlocale() 函数(在<locale.h>中声明)设置当前语言环境。第一个参数表示要设置的类别;或者,LC_ALL 用于设置所有类别。第二个参数是要选择的语言环境名称,或者使用空字符串("")来依赖系统环境设置。

因此,典型的国际化 C 程序的程序初始化可能如下所示

#include <locale.h>
...
const char *prev_locale;
prev_locale = setlocale (LC_ALL, "");

系统环境将被查找以确定相应的语言环境,如下所示

  1. 如果定义了 LC_ALL,则将其用作语言环境名称。
  2. 否则,如果定义了 LC_CTYPE、LC_COLLATE、LC_MESSAGES 的对应值,则将其用作对应类别的语言环境名称。
  3. 对于上面检查尚未定义的类别,如果定义了 LANG,则将其用作语言环境名称。
  4. 对于上面检查尚未定义的类别,将使用“C”(或“POSIX”)语言环境。

“C”或“POSIX”语言环境是一个虚拟语言环境,其中所有行为都是 C 默认值(例如,LC_COLLATE 的 ASCII 排序)。

LC_CTYPE 为在 <ctype.h> 中声明的函数定义字符分类

  • iscntl()
  • isspace()
  • isalpha()
  • islower()
  • toupper()
  • isgraph()
  • ispunct()
  • isdigit()
  • isupper()
  • isprint()
  • isalnum()
  • isxdigit()
  • tolower()

由于 glibc 基于 Unicode,并且所有字符集都被定义为 Unicode 子集,因此在每个语言环境中重新定义字符属性毫无意义。通常,大多数语言环境定义中的 LC_CTYPE 类别引用默认定义(称为“i18n”)。

LC_COLLATE

[编辑 | 编辑源代码]

受 LC_COLLATE 影响的 C 函数是strcoll()strxfrm()

  • strcoll() 以类似于strcmp() 的方式比较两个字符串,但在语言环境相关的方式下。请注意,strcmp() 的行为在不同的语言环境下绝不会改变。
  • strxfrm() 将字符串转换为可以使用普通的strcmp() 进行比较的形式,以获得与直接使用strcoll() 进行比较时相同的结果。

LC_COLLATE 规范是所有语言环境类别中最复杂的。有一个用于对 Unicode 字符串进行排序的单独标准,称为ISO/IEC 14651 国际字符串排序[23] glibc 默认语言环境定义基于此标准。语言环境开发人员在开始创建自己的语言环境定义之前,可以考虑调查其中定义的通用可定制模板 (CTT)

在 CTT 中,排序通过多个步骤完成。字符权重在多个级别(ISO/IEC 14651 有四个级别)中定义。一些字符可以在最初的步骤中被忽略(通过使用“IGNORE”作为权重),并在后面的步骤中被纳入考虑以进行更精细的调整。有关详细信息,请参阅 ISO/IEC 14651 文档。

LC_TIME 允许对由 strftime() 函数格式化的日期/时间字符串进行本地化。星期几和月份可以翻译成语言环境语言,并使用适当的日期。

LC_NUMERIC & LC_MONETARY

[编辑 | 编辑源代码]

每个文化都使用不同的约定来编写数字,即小数点、千位分隔符和分组。这是由 LC_NUMERIC 涵盖的。

LC_MONETARY 根据 ISO 4217 定义了语言环境中使用的货币符号,以及货币金额的书写格式。<locale.h> 中定义了一个单一函数localeconv() 用于从两个语言环境类别中检索信息。Glibc 在<monetary.h> 中提供了一个额外的函数strfmon() 用于根据 LC_MONETARY 格式化货币金额,但这不是标准 C 函数。

LC_MESSAGES

[编辑 | 编辑源代码]

LC_MESSAGES 主要用于消息翻译。POSIX 本地化中唯一的使用是在本地化中描述是/否答案。

ISO/IEC 14652

[编辑 | 编辑源代码]

ISO/IEC 14652 文化约定规范方法 基本上是 POSIX 本地化规范的扩展。除了六个类别中的详细信息外,它还引入了六个新的类别

类别 描述
LC_PAPER 纸张尺寸
LC_NAME 个人姓名格式
LC_ADDRESS 地址格式
LC_TELEPHONE 电话号码
LC_MEASUREMENT 计量单位
LC_VERSION 本地化版本

所有上述类别都已得到 glibc 的支持。C 应用程序可以使用 nl_langinfo() 函数检索所有本地化信息。

构建本地化

[编辑 | 编辑源代码]

要构建本地化,必须准备一个 本地化定义 文件,用于描述 ISO/IEC 14652 本地化类别的数据。(有关文件格式,请参阅标准文档。)此外,在定义新的字符集时,必须为其创建一个 charmap 文件;这会为每个字符提供一个符号名称并描述编码的字节字符串。

通常,glibc 在本地化定义中使用 UCS 符号名称(<Uxxxx>),方便为任何 charmap 生成本地化数据。C 程序使用的实际本地化数据采用二进制形式。本地化定义必须使用 localedef 命令进行编译,该命令接受类似以下参数

localedef [-f <charmap>] [-i <input>] <name>

例如,要使用 TIS-620 charmap 从本地化定义文件 th_TH 构建 th_TH 本地化

# localedef -f TIS-620 -i th_TH th_TH

charmap 文件可以安装在 /usr/share/i18n/charmaps 目录中,本地化定义文件可以安装在 /usr/share/i18n/locales 目录中,以便进一步参考。

locale 命令可以使用 “-a” 选项来检查所有已安装的本地化,并使用 “-m” 选项来列出支持的 charmap。不带参数执行该命令将显示环境设置选择的本地化类别。

FOSS 中最常用的翻译框架是 GNU gettext,尽管一些跨平台 FOSS,例如 AbiWordMozillaOpenOffice.org 由于跨平台抽象的原因使用了自己的框架。在本节中,我们将简要讨论 GNU gettext,它涵盖了超过 90% 的 GNU/Linux 桌面。但是,此处讨论的概念也适用于其他框架。

程序源代码中的消息被放置在一个简短的宏中,该宏调用 gettext 函数来检索翻译后的版本。在程序初始化时,将加载与 LC_MESSAGES 本地化类别对应的哈希消息数据库。然后,在程序执行期间,通过快速查找来翻译宏涵盖的所有消息。因此,翻译的任务是为特定语言构建消息翻译数据库,并将其安装在本地化的适当位置。有了这种准备,gettext 程序将根据本地化设置自动翻译,无需修改源代码。

GNU gettext 还提供用于创建消息数据库的工具。此过程中涉及两种文件

PO(可移植对象)文件。
这是一个人类可读的格式文件,供翻译人员使用。它之所以命名为“可移植对象”,是因为它具有纯文本性质,使其可以移植到其他平台。
MO(机器对象)文件。
这是一个供机器读取的哈希数据库。它是最终格式,将由 gettext 程序加载。商业 Unices 中有许多翻译框架,这些 MO 文件不兼容。您还可能会发现一些 GMO 文件作为 GNU gettext 工具的直接输出。它们是包含一些 GNU gettext 增强功能的 MO 文件。

我们将通过描述从头开始翻译的汇总步骤来讨论重要的 GNU gettext 工具(参见图 3)

图 3:GNU gettext 工作流程
  1. 使用 xgettext 实用程序提取消息。您将获得“package.pot”文件作为 PO 文件的模板。
  2. 从模板创建您语言的 PO 文件,方法是将其复制到 “xx.po”(其中 xx 是您的本地化语言)并使用您的信息填写其标头信息,或者使用 msginit 实用程序。
  3. 通过使用您喜欢的文本编辑器编辑 PO 文件来翻译消息。还可以使用一些专用于 PO 文件的编辑器,例如 kbabel 和 gtranslator。
  4. 使用 msgfmt 实用程序将 PO 文件转换为 MO 文件。
  5. 将 MO 文件安装到本地化的 LC_MESSAGES 目录下。
  6. 当程序开发时,会引入新的字符串。您不必从头开始。相反,您像往常一样使用 xgettext 实用程序提取新的 PO 模板,然后使用 msgmerge 实用程序将模板与当前的 PO 合并。然后,您可以继续翻译新消息。

GNOME intltool

[编辑 | 编辑源代码]

GNU/Linux 桌面需要翻译的东西比 C/C++ 源代码中的消息更多。例如,系统菜单项、事件的声音列表也包含消息,这些消息大多采用 XML 格式,GNU gettext 不支持这些格式。您可以深入研究这些单个文件来翻译消息,但这在维护上非常不方便,而且容易出错。

KDE 拥有严格的翻译策略。所有 KDE 核心应用程序的 PO 文件都被提取到每个语言的单个目录中,以便翻译人员可以在一个地方翻译桌面,而无需源代码副本。但实际上,您有时需要查看源代码以验证某些消息的确切含义,尤其是错误消息。这已经包含了上述 C++ 源代码之外的所有消息。

GNOME 采用了一种不同的方法。PO 文件仍然像往常一样放置在源代码的“po”子目录下。但是,GNOME 项目并没有直接使用 xgettext 从源代码中提取消息,而是开发了一个名为 intltool 的自动化工具。该工具将从 XML 文件中提取消息到 PO 模板中,以及 xgettext 通常执行的操作,并将翻译合并回去。因此,尽管翻译系统异构,但翻译人员仍然只需要为特定语言编辑单个 PO 文件。

intltool 的使用很简单。要生成 PO 模板,请将目录更改为“po”子目录并运行

$ intltool-update—pot

要生成新的 PO 文件并与现有翻译合并

$ intltool-update xx

其中 xx 是语言代码。这就是所需的一切。然后可以像往常一样编辑 PO 文件。

完成 PO 编辑后,典型的 GNOME 源代码的常规安装过程将自动调用适当的 intltool 命令,在安装之前将翻译合并回这些 XML 文件中。请注意,在这个自动化系统中,您不应该再直接调用 xgettext 和 msgmerge 命令。

以下网站和文档提供了有关 KDE 和 GNOME 翻译的更多信息

PO 编辑器

[编辑 | 编辑源代码]

PO 文件是纯文本文件。可以使用您喜欢的文本编辑器对其进行编辑。但是,如前所述,翻译是一项劳动密集型任务。值得考虑使用一些便捷的工具来加快工作速度。

通常,需要编辑器才能编辑UTF-8,因为KDEGNOME现在都将其用作标准文本编码。但是,以下工具具有许多其他功能。

KBabel是KDE软件开发工具包的一部分,它是一个高级且易于使用的PO文件编辑器,具有完整的导航和编辑功能、语法检查和统计信息。该编辑器将已翻译、未翻译和模糊的消息分开,以便于查找和编辑未完成的部分。

KBabel还提供CatalogManager,它允许同时跟踪多个PO文件,以及KBabelDict用于维护词汇表,这对于翻译一致性非常重要,尤其是在来自不同背景的团队成员之间。

Gtranslator

[编辑 | 编辑源代码]

Gtranslator是GNOME桌面环境的PO文件编辑器。它在核心功能上与Kbabel非常相似。

Gtranslator还支持自动翻译,它可以学习并保存翻译,并可以使用热键将其应用于以后的翻译中。

  1. UCS是通用多八位字节编码字符集的缩写
  2. UTF是Unicode(UCS)转换格式的缩写
  3. Unicode联盟。Unicode标准,版本4.0。,第76-77页。
  4. Unicode联盟。Unicode标准,版本4.0。,第77-78页。
  5. 同上,第95-104页。
  6. Unicode.org,'Unicode技术报告';可从http://www.unicode.org/reports/index.html获取。
  7. Unicode.org,'Unicode技术报告';可从http://www.unicode.org/reports/index.html获取。
  8. Leisher,M.,'XmBDFEd字体编辑器';可从crl.nmsu.edu/~mleisher/xmbdfed.html获取。
  9. Williams,G.,'PfaEdit';可从http://pfaedit.sourceforge.net获取。
  10. Just van Rossum,J.,S 'TTX/FontTools';可从http://fonttools.sourceforge.net/获取。
  11. 请注意与微软的“Windows”商标的区别。X Window 没有's'。
  12. Taylor,O.,'Pango';可从http://www.pango.org获取。
  13. Taylor,O.,'Pango - 设计';可从http://www.pango.org/design.shtml获取。
  14. GNOME开发网站,'Pango参考手册';可从http://developer.gnome.org/doc/API/2.0/pango/获取。
  15. 这是一个非常粗略的分类。显然,还有进一步的步骤,例如断行、对齐和对齐。这里不需要讨论它们,因为它们超出了本地化范围。
  16. Pascal,I.,X键盘扩展;可从http://pascal.tsu.ru/en/xkb/获取。
  17. Pascal,I.,X键盘扩展;可从http://pascal.tsu.ru/en/xkb/获取。
  18. Gettys,J.,Scheifler,R.W.,Xlib-C语言X接口,X联盟标准,X版本11发行版6.4。
  19. Narita,M.,Hiura,H.,输入法协议版本1.0。X联盟标准,X版本11发行版6.4
  20. OpenI18N.org。OpenI18N语言环境名称指南,版本1.1 - 2003-03-11;可从http://www.openi18n.org/docs/text/LocNameGuide-V11.txt获取。
  21. 国会图书馆,ISO 639-2注册机构;可从http://lcweb.loc.gov/standards/iso639-2获取。
  22. ISO,ISO 3166维护机构(ISO 3166/MA) - ISO的国家代码联络点;可从http://www.iso.org/iso/en/prodsservices/iso3166ma/index.html获取。
  23. ISO/IEC 14651 国际字符串排序。ISO/IEC,ISO/IEC JTC1/SC22/WG20 - 国际化;可从http://anubis.dkuug.dk/jtc1/sc22/wg20获取。
华夏公益教科书