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

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


{{tip|如果你使用KDE code repository管理代码,这些都是自动完成的。如果您没有使用KDE repository,您就要自己手动完成相关步骤,参见[[#handling i18n in third party applications]].}}
{{附注|如果你使用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]]。
The KDE translation teams translate the messages and commit them into a messages folder corresponding to the language, which is further broken down by module. For example, German translated messages for konqueror are committed to {{path|l10n/de/messages/kdebase/konqueror.po}}.


When the l10n module is built, the .po files are compiled into a binary format for fast lookup and installed as .mo files to {{path|$KDEDIR/share/locale/xx/LC_MESSAGES/}}, where xx is the two-letter ISO 639 code for the language. These are called the message catalogs.  
KDE翻译组会翻译这些信息将其并放在相应语言的文件夹中。这些文件夹会由模块细分。例如,德语翻译会被放置在{{path|l10n/de/messages/kdebase/konqueror.po}}.  


At runtime, the <tt>i18n(...)</tt> function, using the original string you coded, looks up the string in the message catalog of the user's desktop language and returns the translated string. If the message catalog is missing, or the specific string is not found, <tt>i18n(...)</tt> falls back to the original string in your code.
当l10n模块构建完成, 相应的.po文件会被编译成二进制形式的.mo文件以供更快的查询和显示。.mo files 在 {{path|$KDEDIR/share/locale/xx/LC_MESSAGES/}}中,其中 xx 是个两字符的 ISO 639 相对于该语言的编码。这被称为消息目录。


.desktop files in your project are handled separately. {{path|makemessages}} extracts strings, such as Name and Comment from the .desktop files and places them into a file named {{path|desktop_mmmm.pot}}, where mmmm is the module name, in the templates folder. Once translators have translated this file, makemessages inserts the translated strings back into the .desktop files. The list of strings extracted is in {{path|l10n/scripts/apply.cc}}. Here's the code that checks for them:
运行时 <tt>i18n(...)</tt> 函数会使用您代码中原有的字串,并查询用户桌面所使用的语言,从而查询消息目录并替换成用户相应的语言。 如果消息目录缺失,或者指定的字串没有找到,<tt>i18n(...)</tt> 会使用您程序中原有的字串。
 
您项目中的.desktop文档会被单独处理。{{path|makemessages}}提取字串,比如说将,desktop文件中的名字和注释放置在临时文件夹一个名为{{path|desktop_mmmm.pot}}的文件中,其中 mmmm 是模块的名字。翻译者完成翻译了文档,要将翻译的文本插入回到.desktop文件中。提取的字串列在{{path|l10n/scripts/apply.cc}}. Here's the code that checks for them:


<code cppqt n>if (checkTag("Name", in, argc, argv, newFile))
<code cppqt n>if (checkTag("Name", in, argc, argv, newFile))

Revision as of 07:43, 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库中程序的示例,或者,询问。

幕后的故事

Template:附注

每隔一段时间, 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;