Skip to main content

i18n for Kivy

Project description

i18n

Kivyアプリの多言語化は面倒くさいです。 というのも只表示する文字列を切り替えればいいわけではないからです。 Kivyは文字列の描画に必要なフォントを自動で選んでくれはしないので、アプリ側がKivyに教えてあげなければいけません。 それを怠れば画面には文字に代わって豆腐が表示されてしまいます。

また多くのKivyアプリはフォントをアプリに詰め込むという方法を採っていますが、これも多言語化の際には問題となります。 フォントを幾つも詰め込んでアプリのサイズが数十MB膨れ上がればアプリの利用者は喜ばないでしょう。

そこでこのmoduleの出番です。 このmoduleは文字列を切り替える機能に加えて、OSにinstall済のフォントの中から各言語用の物を自動で選んでくれます。 なのでアプリにフォントを詰め込む必要はもうありません。

使い方

フォントの検索

表示する文字列の切り替えとフォントの切り替えは別々の機能であり、どちらか片方だけ使うこともできます。 また多言語化には興味無いもののOSにinstall済のフォントを利用して少しでもアプリの容量を減らしたいという人も居るでしょう。 そういった人には以下のような使い方がおすすめです。

# OSにinstall済の日本語フォントの内 最初に見つけた物を利用する例

from kivy_garden.i18n.fontfinder import enum_fonts_from_lang

font = next(enum_fonts_from_lang('ja'), None)
if font is None:
    print("日本語フォントが見つかりませんでした")
else:
    print("日本語フォントが見つかりました:", font.name)
    label.font_name = font.name
    textinput.font_name = font.name

フォントの切り替え

そして多言語化させたい場合は以下のようにします。

from kivy_garden.i18n.localizer import KXLocalizer

loc = KXLocalizer()
loc.lang = 'ja'
print(loc.font_name)  # => 何かの日本語フォント名が出力される
loc.lang = 'zh'
print(loc.font_name)  # => 何かの中文フォント名が出力される

重要なのがKXLocalizerEventDispatcherな事で

class KXLocalizer(EventDispatcher):
    lang = StringProperty(...)
    font_name = StringProperty(...)
    _ = ObjectProperty(...)

bindingを利かせればlangを切り替えた時にLabelfont_nameも自動で切り替えられます。

from kivy.app import App
from kivy.lang import Builder
from kivy_garden.i18n.localizer import KXLocalizer


KV_CODE = '''
Label:
    font_name: app.loc.font_name
'''


class SampleApp(App):
    def build(self):
        self.loc = KXLocalizer()
        return Builder.load_string(KV_CODE)

    def on_start(self):
        self.loc.lang = 'ja'  # bindingによりLabelには自動で日本語フォントが適用される
        self.loc.lang = 'ko'  # bindingによりLabelには自動で韓国語フォントが適用される

またKXLocalizer.install()を用いる事で#:import無しでKXLocalizerをKv言語内で直接参照できます。 ただしglobal変数を書き換える行為なので使用は自己責任で。

# 上のcodeど同等のcode
from kivy.app import App
from kivy.lang import Builder
from kivy_garden.i18n.localizer import KXLocalizer


KV_CODE = '''
Label:
    font_name: l.font_name  # import無しで参照 !!
'''

class SampleApp(App):
    def build(self):
        self.loc = KXLocalizer()
        self.loc.install(name='l')  # install
        return Builder.load_string(KV_CODE)

    def on_start(self):
        self.loc.lang = 'ja'

翻訳(文字列の切り替え)

そして肝心の翻訳ですが、これはKXLocalizerに翻訳者(Translator)を与える事で実現できます。 現在ある翻訳者は

  • gettextを利用するGettextTranslator
  • 辞書を用いた単純な仕組みのDictBasedTranslator

の二種で、ここではDictBasedTranslatorを用いた方法を解説します。 GettextTranslatorに関してはgettext_exampleを参照して下さい。

まず必要となるのは以下のような辞書型の翻訳表です。

翻訳表 = {
    'tiger': {
        'zh': '老虎',
        'ja': '虎',
        'en': 'tiger',
    },
    'apple': {
        'zh': '蘋果',
        'ja': 'りんご',
        'en': 'apple',
    },
}

pythonの辞書literalは書きづらいので実際にはYAML形式で翻訳表を作り、それをpythonの辞書に変換した方が良いかもしれません。

tiger:
  zh: 老虎
  ja: 
  en: tiger
apple:
  zh: 蘋果
  ja: りんご
  en: apple
# pip install pyyaml
import yaml
翻訳表 = yaml.safe_load(YAML文字列)

翻訳表ができたら後は以下のようにしてKXLocalizerに与えるだけです。

from kivy_garden.i18n.localizer import KXLocalizer, DictBasedTranslator
loc = KXLocalizer(translator=DictBasedTranslator(翻訳表))

これで既にloc.lang(現在の言語)に基づいて適切な翻訳結果が得られるようになっています。

loc.lang = 'ja'
print(loc._("tiger"))  # => 虎
print(loc._("apple"))  # => りんご
print(loc.font_name)   # => 何かの日本語フォント名
loc.lang = 'zh'
print(loc._("tiger"))  # => 老虎
print(loc._("apple"))  # => 蘋果
print(loc.font_name)   # => 何かの中文フォント名

そして当然bindingを利かせてあげればloc.lang(現在の言語)に連動してLabeltextfont_nameが自動で更新されます。

from kivy.app import App
from kivy.lang import Builder
from kivy_garden.i18n.localizer import KXLocalizer, DictBasedTranslator


KV_CODE = '''
Label:
    font_name: l.font_name
    text: l._("apple")
'''


class SampleApp(App):
    def build(self):
        self.loc = KXLocalizer(translator=DictBasedTranslator(翻訳表))
        self.loc.install(name='l')
        return Builder.load_string(KV_CODE)

    def on_start(self):
        # Labelのfont_nameに日本語フォントが、textには りんご が入る
        self.loc.lang = 'ja'

        # Labelのfont_nameに英文フォントが、textには apple が入る
        self.loc.lang = 'en'

このようにEventDispactherのbindingの仕組みを利用するとアプリの実行中に表示言語を自由に切り替えられるのがこのmoduleの強みとなります。 もちろん言語切替時にアプリの再起動を求めるつもりなのであれば無理にbindingを利かせる必要はありません。

以上がこのmoduleの基本的な使い方となります。

小道具

xgettextは翻訳の必要性のある文字列をpythonソース中から抜き出してくれる素晴らしい道具ですが、 文字列literalの中までは見てくれないという欠点があります。 すなわち以下のcodeにおいて

KV_CODE = '''
BoxLayout:
    Label:
        text: _("ABC")
    Label:
        text: _("DEF")
'''

_("123")

123は抜き出してくれてもABCDEFは抜き出してくれません。 というわけでそういったことをしてくれる物を作りました。

python -m kivy_gardem.i18n.extract_msgids_from_string_literals 上記のpythonファイル > ./output.py
# output.pyの中身
_("ABC")
_("DEF")

このように文字列literal内の翻訳対象文字列をその外に抜き出してくれるので、 それをxgettextに喰わせてあげれば取りこぼさずに済みます。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kivy_garden_i18n-0.1.0.tar.gz (6.5 kB view hashes)

Uploaded Source

Built Distribution

kivy_garden_i18n-0.1.0-py3-none-any.whl (7.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page