Archive:Development/Tutorials/Localization/i18n Build Systems (zh CN): Difference between revisions

From KDE TechBase
Line 70: Line 70:
=== 幕后的故事 ===
=== 幕后的故事 ===


{{附注|如果你使用KDE code repository管理代码,这些都是自动完成的。如果您没有使用KDE repository,您就要自己手动完成相关步骤,参见[[#handling i18n in third party applications]].}}
{{Tip|如果你使用KDE code repository管理代码,这些都是自动完成的。如果您没有使用KDE repository,您就要自己手动完成相关步骤,参见[[#handling i18n in third party applications]].}}


每隔一段时间, KDE 服务器会运行{{path|extract-messages.sh}} (又称为scripty) 脚本。这个脚本会使用适当的参数调用库中所有的Messages.sh。 提取所得的信息胡储存在一个l10n模块的一个临时文件夹的临时的 (.pot) 文件。参见 [[What Is Scripty]]。
每隔一段时间, KDE 服务器会运行{{path|extract-messages.sh}} (又称为scripty) 脚本。这个脚本会使用适当的参数调用库中所有的Messages.sh。 提取所得的信息胡储存在一个l10n模块的一个临时文件夹的临时的 (.pot) 文件。参见 [[What Is Scripty]]。

Revision as of 07:46, 21 June 2010

摘要

现在您的程序能够本地化了,我们接下来考虑怎样把这个重要的机能合并到您程序的Cmake系统中去。 首先我们“理论”上解释用于安装.po文件时解压缩信息字符串所需要的步骤。然后我们来看怎么实现这些步骤(#Theory: The xgettext toolchain)。如果您的程序书用KDE的subversion开发的,很多步骤是自动完成的(参见 #handling i18n in KDE's subversion repository)。 如果不是,请参见 #handling i18n in third party applications 部分。

理论: xgettext 工具

翻译需要以下步骤:

  1. 提取出要翻译的字符串
  2. 将新翻译的字串和已有的翻译合并在一起
  3. 将翻译编译进消息目录
  4. 安装消息目录
  5. 在程序中使用消息目录

提取字符串

本步骤中,所有您代码中标记为 i18n()/ki18n()/etc. 的字串需要被收集到一个临时翻译文件 (.pot) 文件中。 有些待翻译字串在.ui, .rc, or .kcfg 文件中. 此外也要把每日一帖搜集到.pot文件中.

这个步骤是由 xgettext, extractrc, 和 preparetips 这些程序分别完成的。有些情况下,您也会用到 extractattr.

合并翻译结果

一般来讲,某次只有少部分的可翻译字串需要更改:有些需要被移除,有些需要被添加,有些要被替换,有些要改变在代码中的位置。这些改变需要在翻译中得到体现,但显然每次(更新)都重做所有的翻译是一件耗力的工作。 把原有的翻译和那些改变的东西合并在一起会更好。这时需要 msgmerge 工具。

编译翻译结果

为了让信息查找更快,.po文件需要编译成所谓的 "消息目录" (.mo / .gmo)。这可由 msgfmt 工具完成.

安装消息目录

编译好的信息目录需和程序一起安装。KDE系统中,标准的消息目录的路径是 $KDEDIR/share/locale/xx/LC_MESSAGES/

使用消息目录

最后,但程序能够运行,程序需要载入消息目录来查找和显示翻译的字串。 对KDE程序而言,在大多数情形,这是由KLocale 类自动完成的。

一些特殊的情形,比如说插件,请参看 #Runtime Loading Of Catalogs.

在KDE的 subversion库中处理

如果您使用KDE subversion库做开发,上述大部分的步骤都是自动完成的。此时,您只需要提供一个Messages.sh脚本。我们下面会提到这个脚本。

此外,如果您的根目录和.pot文件重名,当您对代码打包时,svn2dist脚本会自动包含.po文件

当然,进行这一步骤所做的详细幕后信息会被提供。


编辑 Messages.sh 脚本

通常地,准备和安装一个KDE subversion 库程序的翻译只需要提供“信息”。包括了需要翻译的代码, ui文件和提示。就此而言,您只要写一小段 Messages.sh 代码,并把他放置到您的代码中就好了。下面是一个带注释的例子:

  1. !bin/sh
  1. invoke the extractrc script on all .ui, .rc, and .kcfg files in the sources
  2. the results are stored in a pseudo .cpp file to be picked up by xgettext.

$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp

  1. if your application contains tips-of-the-day, call preparetips as well.

$PREPARETIPS > tips.cpp

  1. call xgettext on all source files. If your sources have other filename
  2. extensions besides .cc, .cpp, and .h, just add them in the find call.

$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/APPNAME.pot

可以发现,这段脚本实际上只含有三行代码,而且这三段并不都是必要的。$XGETTEXT, $PREPARETIPS, $EXTRACTRC 和 $podir 环境变量是预先定义好的,不需要考虑。您只需要将 "APPNAME" 替换成您的程序的名字 (参见 #Naming .pot Files 描述了例外的情形)。

请确定您的Messages.sh 脚本概括了所有需要的信息。如有疑问,请查看其它KDE subversion库中程序的示例,或者,询问。

幕后的故事

Tip
如果你使用KDE code repository管理代码,这些都是自动完成的。如果您没有使用KDE repository,您就要自己手动完成相关步骤,参见#handling i18n in third party applications.


每隔一段时间, KDE 服务器会运行extract-messages.sh (又称为scripty) 脚本。这个脚本会使用适当的参数调用库中所有的Messages.sh。 提取所得的信息胡储存在一个l10n模块的一个临时文件夹的临时的 (.pot) 文件。参见 What Is Scripty

KDE翻译组会翻译这些信息将其并放在相应语言的文件夹中。这些文件夹会由模块细分。例如,德语翻译会被放置在l10n/de/messages/kdebase/konqueror.po中.

当l10n模块构建完成, 相应的.po文件会被编译成二进制形式的.mo文件以供更快的查询和显示。.mo files 在 $KDEDIR/share/locale/xx/LC_MESSAGES/中,其中 xx 是个两字符的 ISO 639 相对于该语言的编码。这被称为消息目录。

运行时 i18n(...) 函数会使用您代码中原有的字串,并查询用户桌面所使用的语言,从而查询消息目录并替换成用户相应的语言。 如果消息目录缺失,或者指定的字串没有找到,i18n(...) 会使用您程序中原有的字串。

您项目中的.desktop文档会被单独处理。makemessages提取字串,比如说将,desktop文件中的名字和注释放置在临时文件夹一个名为desktop_mmmm.pot的文件中,其中 mmmm 是模块的名字。翻译者完成翻译了文档,要将翻译的文本插入回到.desktop文件中。提取的字串列在l10n/scripts/apply.cc中. Here's the code that checks for them:

if (checkTag("Name", in, argc, argv, newFile))

   continue;

if (checkTag("Comment", in, argc, argv, newFile))

   continue;

if (checkTag("Language", in, argc, argv, newFile))

   continue;

if (checkTag("Keywords", in, argc, argv, newFile))

   continue;

if (checkTag("About", in, argc, argv, newFile))

   continue;

if (checkTag("Description", in, argc, argv, newFile))

   continue;

if (checkTag("GenericName", in, argc, argv, newFile))

   continue;

if (checkTag("Query", in, argc, argv, newFile))

   continue;

if (checkTag("ExtraNames", in, argc, argv, newFile))

   continue;