テキストを翻訳

説明

Python と TAL テンプレートのソースコードに含まれている文字列を、 gettext ライブラリと他の Plone の i18n (国際化)の仕組みを使用して翻訳を行います。

はじめに

国際化はあなたのコードを locale と言語に対応させるためのプロセスです。 国際化とは、コード中に使用される文字列を翻訳用のファイルに対応させることを意味しています。

Plone は国際化(i18n)ために UNIX 標準の gettext というツールを内部で使用しています。

Plone には2つの独立した gettext シスチムが存在します。 両方とも .po <http://www.gnu.org/software/hello/manual/gettext/PO-Files.html> ファイルフォーマットを翻訳に使用します。

この章ではコードレベルでの翻訳について述べています。 コンテンツの翻訳については Products.LinguaPlone アドオンプロダクトによる管理となります。

zope.i18n

  • 以下に gettext を使用する場合のベストプラクティスを記載します。
  • 翻訳ファイルをアプリケーションの locales フォルダに保存します。 例: locales/LC_MESSAGES/ja/your.app.po
  • zope.i18nmessageid パッケージは、テキスト中の文字列を簡単に翻訳可能にするための、強力な翻訳ドメインを保存できる文字列のようなクラスを持っています。
  • .po ファイルは翻訳文字列を更新するごとに、 .mo ファイルに変換されます。 詳しくは i18ndude を参照してください。

Plone (少なくとも 3.3)は翻訳ファイルの検索にファイルのパスとファイル名のみを使用します。 .po ファイルのヘッダーに記載してある情報は無視されます。

翻訳可能な文字列を作成する

それぞれのモジュールは翻訳ドメインによって呼び出し可能でマークされた文字列により MessageFactory を宣言します。 MessageFactory はパッケージのメイン __init__.py ファイルで宣言されます。

from zope.i18nmessageid import MessageFactory

# your.app.package は .po ファイルのドメイン宣言と同一である必要があります。
yourAppMessageFactory = MessageFactory('your.app.package')

以下のような ZCML エントリーの記述が必要です。

<configure
    xmlns:i18n="http://namespaces.zope.org/i18n">

    <i18n:registerTranslations directory="locales" />

</configure>

Generating a .pot template file for your package(s)

infrae.i18nextract can be used in your buildout, to create a script which searches particular packages for translation strings. This can be particularly useful for creating a single translations package which contains the translations for the set of packages which make up your application.

Add the following to your buildout.cfg:

[translation]
recipe = infrae.i18nextract
packages =
   myapplication.policy
   myapplication .theme
output = ${buildout:directory}/src/myapplication.translation/myapplication/translation/locales
output-package = myapplication.translations
domain = mypackage

Running the ./bin/translation-extract script will produce a .pot file in the specified output directory which can then be used to create the .po files for each translation:

msginit --locale=fr --input=locales/mypackage.pot --output=locales/fr/LC_MESSAGES/mypackage.po

The locales directory should contain a directory for each language, and a directory called LC_MESSAGES within each of these, followed by the corresponding .po files containing the translation strings:

./locales/en/LC_MESSAGES/mypackage.po
./locales/fi/LC_MESSAGES/mypackage.po
./locales/ga/LC_MESSAGES/mypackage.po

翻訳可能な文字列を作成する

上記の設定をした後、 MessageFactory で翻訳ドメインのマーク文字列を使用できるようになります。 i18ndude 翻訳ユーティリティーはアンダースコア(_)を使用して翻訳可能な文字列(gettext のメッセージid)にマークを付けます。 なお、メッセージid はユニコード文字列でなくてはなりません。

from your.app.package import yourAppMessageFactory as _

my_translatable_text = _(u"My text")

このオブジェクトは文字列のように見えます。

>>> my_translatable_text
u'My text'

しかし、実体は zope.i18nmessageid.message.Message オブジェクトです。

>>> my_translatable_text.__class__
<type 'zope.i18nmessageid.message.Message'>
>>> my_translatable_text.domain
'your.app.package'

翻訳された文字列を参照します。

>>> from zope.i18n import translate
>>> translate(my_translatable_text)
u"The text of the translation." # This is the corresponding msgstr from the .po file

より詳細な情報は以下を参照してください。

メッセージid による自動翻訳

Plone はページテンプレートを出力をするときにメッセージid による翻訳が自動的に行われます。

以下のコードによって現在のページで my_translateable_text を現在の言語にする翻訳が有効となります。

<span tal:content="view/my_translateable_text">

my_translateable_text は gettext のドメイン情報を含んでいる zope.i18nmessageid.message.Message オブジェクトです。 ページテンプレートの中の i18n:domain 属性はメッセージファクトリーで定義されているメッセージid には影響を与えません。

メッセージid による手動翻訳

必要ならばページテンプレートの外で文字列の翻訳操作を行うことができますが、その場合は翻訳作業を手動で行う必要があります。

翻訳の実行には常にコンテクスト(例: 翻訳が行われるサイト情報)が必要であり、有効な言語と他の設定情報を HTTP リクエストのオブジェクトとサイトの設定から読み込みます。

翻訳は context.translate() メソッドを使用して行ないます。:

# ある文字列を翻訳します
msgid = _(u"My text") # my_text is zope.

# Use inherited translate() function to get the final text string
translated = self.context.translate(msgid)

# 日本語の "私の文字列" に翻訳されます

Python の外のメッセージid

Python ドメインの外にあるコードにも、メッセージidマーカーが存在します。

  • ZCML のエントリー
  • GenericSetup 用の XML
  • TAL ページテンプレート

翻訳文字列の置き換え

翻訳文字列の置き換えは翻訳後のメッセージが変数を含んでいる場合に必ず実行されます。

Plone のコンテンツクラスは変換後の文字列に対して実行可能な translate() 関数を所有しています。 その関数は現在の有効な言語に対して使用が可能です。 翻訳ドメインを文字列のような zope.i18nmesasgeid のインスタンスで実装されている msgid オブジェクトから取得されます。

メッセージidは変更不可(読み取り専用)のオブジェクトであり、異なった変数置き換えが必要となる場合には新しいメッセージidを作成しなければなりません。

Python コード:

from saariselka.app import appMessageFactory as _

class SomeView(BrowserView):


    def do_stuff(self):

        msgid = _(u"search_results_found_msg", default=u"Found ${results} results", mapping={ u"results" : len(self.contents)})

        # Use inherited translate() function to get the final text string
        translated = self.context.translate(msgid)

        # Show the final result count to the user as a portal status message
        messages = IStatusMessage(self.request)
        messages.addStatusMessage(translated, type="info")

上記のコードに対応する .po ファイルのエントリー:

#. Default: "Found ${results} results"
#: ./browser/accommondationsummaryview.py:429
msgid "search_results_found_msg"
msgstr "結果 ${results} を見つけました"

より詳細な情報は以下を参照してください。

PlacessTranslationService

  • 歴史的には、段階的に使用されなくなりつつあります。
  • .po ファイルをプロダクトの i18n フォルダに保存します。
  • “plone” 翻訳カタログに使用されています(Plone 3.3.xまで)。
  • Plone の再起動時に翻訳ファイルの処理が行われます。例: i18n/yourapp-fi.po

i18ndude

i18ndude は .po と .mo ファイルを管理するための開発用コマンドユーティリティーです。

通常は、プロダクトの .po ファイルと .mo ファイル を自動的に生成するためのシェルスクリプトを作成し、そのスクリプトの中で i18ndude を使用ます。

ノート

Plone 3.3 では手動での .po ファイルから .mo ファイルへの変換は不要で、 起動時に変換が行われます。 Plone 4 ではこの機能について特別な方法に変更されています。 Plone 4 has a special switch for this: in your buildout.cfg in the part using plone.recipe.zope2instance you can set an environment variable for this:

environment-vars =
    zope_i18n_compile_mo_files true

Note that the value does not matter: the code in zope.i18n simply looks for the existence of the variable and does not care what its value is.

参考

i18ndude をインストールする

おすすめは buildout 経由で i18ndude をインストールする方法です。

以下コードを buildout.cfg に追加します。:

parts =
        ...
        i18ndude

[i18ndude]
unzip = true
recipe = zc.recipe.egg
eggs = i18ndude

その後 i18ndude コマンドが buildout/bin フォルダーで使用できるようになります。

bin/i18ndude -h
Usage: i18ndude command [options] [path | file1 file2 ...]]

パッケージのソースフォルダーから以下のように相対パスで実行できます。

huiske-imac:twinapex moo$  cd src/mfabrik.plonezohointegration/
huiske-imac:mfabrik.plonezohointegration moo$ ../../bin/i18ndude

警告

easy_install で i18ndude をインストールしないでください。 i18ndude は様々な Zope パッケージに依存しています。 そして、システム全体の Python の設定により、Plone で使用される同一のパッケージが異なるバージョンの i18ndude を使用するというような衝突という危険な状態を引き起こす可能性があります。

より詳細な情報は以下を参照してください。

日本語と英語のためのフォルダ構造を作成する

Example:

mkdir locales
mkdir locales/fi
mkdir locales/en
mkdir locales/fi/LC_MESSAGES
mkdir locales/en/LC_MESSAGES

例:

mkdir locales mkdir locales/ja mkdir locales/en mkdir locales/ja/LC_MESSAGES mkdir locales/en/LC_MESSAGES

.pot ファイルを生成する

Example:

i18ndude rebuild-pot --pot locales/mydomain.pot --create your.app.package .

例:

i18ndude rebuild-pot --pot locales/mydomain.pot --create your.app.package .

Manual po entries

i18ndude scans source .py and .pt files for translatable text strings. On some occassions this is not enough - for example if you dynamically generate message ids in your code. Entries which cannot be detected by automatic code scan are called manual po entries. They are managed in locales/manual.pot which is merged to generated locales/yournamespace.app.pot file.

Here is a sample manual.pot file:

msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
"Preferred-Encodings: utf-8 latin1\n"
"Domain: mfabrik.app\n"

# This entry is used in gomobiletheme.mfabrik  templates for the campaign page header
# It is not automatically picked, since it is referred from external package
#. Default: "Watch video"
msgid "watch_video"
msgstr ""

.po ファイルの管理

i18n ファイルを管理するシェルスクリプトの例です。 CATALOGNAME を実際のプロダクトのパッケージ名に変更して使用してください。

The script will

  • Pick up all changes to i18n strings in code and reflect them back to the translation catalog of each language
  • Pick up changes in manual.pot file and reflect them back to the translation catalog of each language
#!/bin/sh
#
# Shell script to manage .po files.
#
# Run this file in the folder main __init__.py of product
#
# E.g. if your product is yourproduct.name
# you run this file in yourproduct.name/yourproduct/name
#
#
# Copyright 2010 mFabrik http://mfabrik.com
#
# http://plone.org/documentation/manual/plone-community-developer-documentation/i18n/localization
#

# Assume the product name is the current folder name
CURRENT_PATH=`pwd`
CATALOGNAME="yourproduct.app"

# List of languages
LANGUAGES="en fi de"

# Create locales folder structure for languages
install -d locales
for lang in $LANGUAGES; do
    install -d locales/$lang/LC_MESSAGES
done

# Assume i18ndude is installed with buildout
# and this script is run under src/ folder with two nested namespaces in the package name (like mfabrik.plonezohointegration)
I18NDUDE=../../../../bin/i18ndude

if test ! -e $I18NDUDE; then
        echo "You must install i18ndude with buildout"
        echo "See http://svn.plone.org/svn/collective/collective.developermanual/trunk/source/i18n/localization.txt"
        exit
fi

#
# Do we need to merge manual PO entries from a file called manual.pot.
# this option is later passed to i18ndude
#
if test -e locales/manual.pot; then
        echo "Manual PO entries detected"
        MERGE="--merge locales/manual.pot"
else
        echo "No manual PO entries detected"
        MERGE=""
fi

# Rebuild .pot
$I18NDUDE rebuild-pot --pot locales/$CATALOGNAME.pot $MERGE --create $CATALOGNAME .


# Compile po files
for lang in $(find locales -mindepth 1 -maxdepth 1 -type d); do

    if test -d $lang/LC_MESSAGES; then

        PO=$lang/LC_MESSAGES/${CATALOGNAME}.po

        # Create po file if not exists
        touch $PO

        # Sync po file
        echo "Syncing $PO"
        $I18NDUDE sync --pot locales/$CATALOGNAME.pot $PO


        # Plone 3.3 and onwards do not need manual .po -> .mo compilation,
        # but it will happen on start up if you have
        # registered the locales directory in ZCML
        # For more info see http://vincentfretin.ecreall.com/articles/my-translation-doesnt-show-up-in-plone-4

        # Compile .po to .mo
        # MO=$lang/LC_MESSAGES/${CATALOGNAME}.mo
        # echo "Compiling $MO"
        # msgfmt -o $MO $lang/LC_MESSAGES/${CATALOGNAME}.po
    fi
done

ノート

自動で .mo ファイルのコンパイルを実行するために configure.zcml に locales ディレクトリの登録をすることを忘れないで下さい。

詳細な情報を以下を参照してください。