その文字列にi18nを適用したいときは、おそらくgettext
フレームワーク関数に目を向けます。私はPHP/ Joomlaから来たので!私が以前使用した世界は、とJText::_
非常によく似ていgettext
ます。Pythonでは、Babelを使用しています。どちらも同じ問題を共有しており、おそらくより多くの言語も共有しています。ここで共有するすべてのコードは、Pythonで、より明確に、Makoテンプレートでそれを行う方法です。
もちろん、問題は次のとおりです。翻訳する文字列にHTMLが含まれています(さらに言えば、URLも含まれています)。これが私のオプションです。それぞれ後で説明します。
- 生の文字列をに渡す
gettext
- テキストを3ビットに分割する
- リンクされた単語を変数で囲む
- 個別にビルドされる1つの変数を使用する
生の文字列をに渡すgettext
これは、影響を認識していない場合、最初に採用する可能性のあるアプローチのようです。
アプローチ1:
_('Welcome to my site. Check out our cool <a href="/products">products</a> \
you should not miss.')
このためmsgid
に、HTMLをそのままにして、翻訳することができます。
利点:
- これはコードでは非常にきれいに見え、理解しやすいです
- 翻訳者がHTMLをそのまま保持している場合、これによって問題が発生することはありません。
短所:
- 翻訳者は少なくとも少しのHTMLを知っている必要があります
- 文字列は完全に柔軟性がありません。たとえば、URLが変更された場合は、すべての翻訳を調整する必要があります
- ルーターのようなものを使用してURLを動的に生成することはできません
結論として、これを使用している間、私はすぐに限界に達しました。私の次のアイデアは:
テキストを3ビットに分割する
アプローチ2:
_('Welcome to my site. Check out our cool ') + '<a href="/products">' +\
_('products') + '</a>' + _(' you should not miss.')
利点:
- URLは完全に柔軟になりました
- 翻訳者向けの実際のテキストのみ
短所:
- 文を3つの部分に分割します
- 翻訳者は、どの部分が相互に関連しているかを知る必要があります。そうしないと、意味のある文を生成できない可能性があります。
- コードではあまりきれいではありません
- は
msgid
単一の単語である可能性があり、問題を引き起こす可能性があります(コンテキストに注意してください)が、修正することができます。
printf
PHPのスタイル文字列(当時使用していた)について知らなかったため、この手法をしばらく使用しました。これはとても醜いように見えたので、私は別のアプローチを試しました:
リンクされた単語を変数で囲む
アプローチ3:
_('Welcome to my site. Check out our cool %sproducts%s you should not miss.' % \
('<a href="/products">', '</a>')
利点:
- 翻訳する単一の文字列、完全な文
- 翻訳者は文字列からコンテキストを正しく取得します
- コードはそれほど醜いものではありません
短所:
- 翻訳者は、
%s
行方不明にならないように注意する必要があります(次のように読むと混乱する可能性がありますsproducts
)
- すべてのURLに2つのフォーマット文字列変数を導入します。1つはのみです。
</a>
個別にビルドされる1つの変数を使用する
ここからいくつかの異なるアプローチがありましたが、最終的に現在使用しているアプローチを思いつきました(これはやり過ぎのように見えるかもしれませんが、今のところそれを実行します)。
アプローチ4:
_('Welcome to my site. Check out our cool %s \
you should not miss.') % ('<a href="%s">%s</a>' % ('/products', _('products')))
この(一見狂ったように見える)アプローチを推論するために少し時間を割いてみましょう。まず、実際の翻訳文字列は次のようになります。
_('Welcome to my site. Checkout our cool ${product_url} \
you should not miss.')
これにより、翻訳者はそこに挿入されている情報を残すことができます(これがtranslationstringバージョンです)。次に、HTMLに挿入されたすべての部分を手動でエスケープできるようにします。Makoは自動エスケープを提供しますが、これは次のようなステートメントでは意味がありません。
${'This is a <a href="/">url</a>'}
それはURLを破壊するので|n
、エスケープを削除するためにフィルターを適用する必要があります。ただし、その引数のいずれかがユーザー指定である場合は、防止したいXSSも開きます。リスクを冒さずに、入力をエスケープして(優れたテンプレートエンジンがdefualtで行うのと同じ方法で)、この1つの文字列に対するMakoのエスケープを削除できます。それで
'<a href="%s">%s</a>' % ('/products', _('products'))
実際には次のように見えます
'<a href="%s">%s</a>' % (escape('/products'), _('products'))
どこescape
からインポートされますかmarkupsafe
(Markupsafeを参照)。
最後の部分は、ルーターを介した動的URLです。request.route_url('products_view')
これらの可能性のそれぞれを組み合わせるには、非常に醜いものを作成する必要があります(これは、(translationstring.TranslationStringmapping
)のキーワード引数を使用しますが、翻訳から必要なすべての利点を組み合わせています。translationstring
最終結果:
_('Welcome to my site. Checkout our cool ${product_url} \
you should not miss.', mapping={'product_url': '<a href="%s">%s</a>' %\
(escape(request.route_url('products_view')), _('products'))})
利点:
- 完全なHTMLエスケープ
- 完全に動的
msgid
翻訳に非常に良い
短所:
- テンプレート(またはとにかくプログラム)の非常に醜い構成
- lingua抽出機能がキャッチされない
_('products')
ため、手動で抽出する必要があります
以上で、この問題への私のアプローチは終わりです。たぶん私は何か複雑な方法をやっていて、あなたはもっと良いアイデアを持っているか、あるいはこれは特定のタイプの翻訳可能なテキストに依存する問題です(そして正しいアプローチを選択する必要があります)。
私のアプローチを改善する解決策や何かを逃しましたか?