原文: http://cpp.ezbty.org/content/science_doc/po_%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F
摘要:PO 是一种 GNU 定义的文件格式,通过这种格式的文件及一组实用工具使得用户维护一个程序多语言版本变得方便而科学。gettext 技术是如此通用,它可以用于普通的文档翻译工作中。
概述
PO 是可移植对象(Portable Object)的简写,它的目标就是实现一个可移植的用于技术文档翻译的技术与工具集。一个 PO 文件是一个纯文本文件,所以可以使用所有可能的文本编辑器打开并编辑,比如在GNU/Linux或其它任何系统里的 VIM,或是在 Windows 下的 notepad。
通常 PO 文件不是手工创建的,而由工具程序生成,这个工具可能有很多,最常见的就是 GNU gettextize,或者用户自己设计的程序。本文不准备介绍如何生成 PO 文体和为什么生成 PO 文件,我们只是说明一下一个普通的 PO 文件构成。
文件头
PO文件是面向工程的,在它的文件最初的数行存在一个对本文自身信息描述字段。这些字段用来指定本PO来自哪里,由哪个维护,文件创建日期,文件更新日期等。这些信息是固定的,只需要对号入座就可以了。
"Content-Transfer-Encoding" 是一个字段,这个字段指定当前文件的字符庥,但是在我的使用中没有发现需要特别指定它。所以我认为对一般意义上的使用 PO 文件不需要使用这个头。事实上这些头信息经常不被使用,而被直接忽略。但是GNU/Gettext工具里会提示,如果这个信息没有填写。
翻译项
翻译项就是一段一段需要翻译的字符文本,它可能是含有格式的文本。这些文本经常是从程序源码里通过gettextize抽取出来,或者其它工具生成,通常都会存在一些特殊的字符,最常见的特殊字符就是转义字符,在翻译的时候需要尤其关注。
结构化注释
每个翻译项都可能存在一些额外的信息,如一个翻译文本是从C程序里抽取出来的,可能就是需要说明这个从哪个源文件,哪个行抽取出来的。这些额外的信息通过结构注释来提供,用户可以定义自己的结构注释,当然GNU/Gettext工具集也定义了一组结构来表达相应信息。下面就针对这些GNU/Gettext定义的结构化注释结构进行讨论:
- #
- 正常意义下的注释是开始于 “#” ,它后面紧跟着注释的文本。
- #
- 翻译者留下的注释是开始于 “# ” ,也就是在“#”之后是一些空格。这样的注释是翻译者留下的,可能翻译都之间需要一个交流,或者需要告诉翻译者一些额外消息才它正确翻译。
- #.
- 给翻译者的注释开始于“#.”。这些注释往往是程序员给翻译者留下的,往往是工具从源码中直接抽取出来的,所以双叫做“抽取的注释”。
- #-
- 工具自动加入注释开始于“#-”。这些注释是工具为了保留额外信息的,这些信息将用于日后维护工作。
- #:
- 对源码的引用注释开始于“#:”。这些注释是工具保留相应翻译项的来源。
- #,
- 工具设置的一些标志注释开始于“#,”。这也提供额外信息的注释,往往用于表明程序文本是一个什么样的字符串,C语言的有转义的串,还是bash脚本里的串。
- #|
- 之前的 msgid 通过开始于 “#|” 来表明。翻译译文本自身可能也存在一个更新过程,这个更新过程可能通过这个注释来体现。它存在的目的往往是为了给翻译者一个提醒,因为更新的文本可能与现在的文本很相似。
msgid 和 msgstr
想象翻译根本上是一个很简单的事,就是把一个需要翻译的文本映射一到一个已经翻译的文本,建立这个映射过程就是一个翻译过程。需要翻译的文本在 PO 文件里叫做 msgid,而翻译所得的文本叫做 msgstr。这两个都字符串,而具体是什么字符串则由实际的文件本身决定,可是C风格的转义串,也可能是其它风格的转义串。串可以通过双引号包围起来,在工具解析的时候会自动去除双引号。
下面给出一个简单PO文件的示例:
# Chinese translations for PACKAGE package # PACKAGE 软件包的简体中文翻译 # Copyright (C) 2010 Free Software Foundation, Inc. # This file is distributed under the same license as the PACKAGE package. # Automatically generated, 2010. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION " "POT-Creation-Date: 2010-09-20 14:47+0800 " "PO-Revision-Date: 2010-09-20 12:07+0800 " "Last-Translator: Automatically generated " "Language-Team: none " "MIME-Version: 1.0 " "Content-Type: text/plain; charset=UTF-8 " "Content-Transfer-Encoding: 8bit " "Language: " #. type: TH #: source/CPU_SET.3:25 #, no-wrap msgid "CPU_SET" msgstr "" #. type: TH #: source/CPU_SET.3:25 #, fuzzy, no-wrap msgid "2010-02-21" msgstr "2010-02-25" #. type: TH #: source/CPU_SET.3:25 #, no-wrap msgid "Linux Programer's Manual" msgstr "Linux 程序员手册"
PO 文件使用
GNU/Gettext 工具集提供操作 PO 文件工具,这些工具的使用可以让翻译工具进行的十分顺利。下面是这些工具的简介。
- envsubst
- 替换 shell 格式化字符串中的环境变量。
- gettext
- 通过在消息列表中查找,来将一种自然语言的消息翻译成用户的本地语言。
- gettextize
- 拷贝所有的标准gettext文件到软件包的顶层目录下,以便于开始翻译。
- msgattrib
- 根据翻译目录中消息的属性过滤它们,并且操作这些属性。
- msgcat
- 将给定的.po文件合并到一起。
- msgcmp
- 比较两个.po,看它们是否包含相同的msgid字符串。
- msgcomm
- 找出不同.po文件中的相同信息。
- msgconv
- 把一个翻译列表转化成另一种字符编码。
- msgen
- 建立一个英文翻译目录。
- msgexec
- 对一个翻译列表中的所有翻译执行同一个命令。
- msgfilter
- 对一个翻译列表中的所有翻译使用同一个过滤器。
- msgfmt
- 从翻译列表生成一个二进制的消息列表。
- msggrep
- 将一个翻译列表中的所有符合给定格式或者属于给定源文件的消息展开。
- msginit
- 生成一个新的 .po 文件,并使用用户环境中的消息来对这个文件进行初始化。
- msgmerge
- 将两个翻译合并成一个。
- msgunfmt
- 将二进制翻译文件反编译成源文件。
- msguniq
- 将翻译目录中重复的翻译合并成一个。
- ngettext
- 显示依赖于数字格式的文本文件的本国语言翻译。
- xgettext
- 从源文件中展开消息行, 用来创建起始翻译模板。
- libgettextpo
- 用来写处理 PO 文件的程序。当 gettext 自带的标准程序(如msgcomm,msgcmp,msgattrib 和 msgen)不能满足要求时,可以使用这个库。