wxGlade を日本語化しようとしたら既に gettext 使ってたけど機能が寝てた話

# 前提と切欠
今回も [szmCt](https://www.dlsite.com/home/work/=/product_id/RJ01387146.html) 開発のために触れる機会を持ったツールの話です。[wxGlade](https://wxglade.sourceforge.net/) 1.1.1, 2025-05-17現在。
# [wxGlade](https://wxglade.sourceforge.net/); [wxWidgets](https://wxwidgets.org/) 用の GUI 編集ツール
szmCt の元になった openMSX公式ランチャー [catapult](https://github.com/openMSX/catapult) には拡張子 .wxg のファイルがありまして、これが wxGlade で編集できるものになります。

wxWidgets の GUI リソースファイルは拡張子 .xrc を持ちます。
catapult では自前で .wxg を .xrc に変換していましたが、szmCt では wxGlade から .xrc ファイルを出力させて使っています。

なぜ catapult が自前変換していたのかは不明ですが、当時の wxGlade では使い物にならなかったからかもしれません。[取り消しと再実行がついたのが2年前の 1.1](https://github.com/wxGlade/wxGlade/blob/master/NEWS.txt) 、というくらいには成長中?のようですし。
# 日本語化はされてない、と思いきや
szmCt 開発中は既存のデータに手を加えるのが主体で、あまりガッツリとした使い方はしていませんでした。なので、szmCt が一通りできたら日本語化してみようかな、と思っていたんです。

で、その段階になってソースコードを見ると。

ちゃんとあるんです。`po/ja.po` と `locale/ja/LC_MESSAGES/wxglade.mo` 。
実行側でも `import gettext` ほか関係部分がちゃんとあリます。でも日本語化しないよね？ということで調査開始。

# Python の [gettext モジュール](https://docs.python.org/ja/3/library/gettext.html) はポンコツ?

ポンコツというかですね。言語を指定した場合はちゃんと動くんですが、自動検出で読み取る時の動作がちょっと足りないようです。

環境変数 LANGUAGE, LC_ALL, LC_MESSAGES, LANG を順に探して自動検出するのですが、 **Windows や Mac の場合「いずれも未定義」** ということがあってですね。それでせっかく用意してある翻訳ファイルを読み取らないということのようです。

# 対策はないこともない
簡単な対処法が見つからないので AI にこれどうすんの？って聞いたらだいたいこんな感じの対策ができました。**`locale.windows_locale` って何**。**[公式ドキュメント](https://docs.python.org/ja/3/library/locale.html)に説明がない**んですけど。

Python のソースコードリポジトリにある [locale.py](https://github.com/python/cpython/blob/main/Lib/locale.py) を見ると一応説明もついていて使って良さそうではあります。下記変更分は wxGlade に[プルリク](https://github.com/wxGlade/wxGlade/pull/579)しときました。

``` Python
# import とか必要なものは適宜。
def get_msw_locale_id():
    """Get UI language code string as locale.getlocale()

    @return locale ID like "ja_JP".
    On Windows, locale.getlocale() returns just "C" or None.
    This causes gettext.translation() returns
    gettext.NullTranslations object.

    Use this function to get locale ID.
    """
    try:
        locale_id = ctypes.windll.kernel32.GetUserDefaultUILanguage()
        return locale.windows_locale[locale_id]
    except:
        return None

t = gettext.translation(domain="wxglade", localedir='locale', fallback=True)
if t.__class__ == gettext.NullTranslations:
    if sys.platform == "win32":
        lang = get_msw_locale_id()
        t = gettext.translation(
            domain="wxglade", localedir='locale', languages=[lang,], fallback=True)
    if t.__class__ == gettext.NullTranslations:
        current_locale = locale.getlocale()
        if current_locale:
            t = gettext.translation(
                domain="wxglade", localedir='locale',
                languages=[current_locale[0],], fallback=True)
    if t.__class__ == gettext.NullTranslations:
        print("Are you trying to boot from IDLE?"
              " If so, after installing the necessary Python libraries,"
              " try 'python3 -m idlelib.idle.'")
t.install("wxglade")
```

# wxGlade 内でも扱いがよろしくない?
ソースコードを眺めていると、`_("...")` で括っていないところがあちこちにありますし、そもそも xgettext(.exe) で拾えないところに翻訳すべき文字があったりしますし、`po/*.po` は十言語分くらいあるのですが `locale/**/LC_MESSAGES/wxglade.mo` は `ja` 含む三つしかなかったりと、なんでしょう、このメンテナンスされてない感。

ということで、あちこち探って `_("...")` 付けて回りました。機械的に変換するのはちょっと難しいのが辛いところ。翻訳されては困るものも多々ありますし。

`_("...")` を付けて回りましたけれども、別の .wxg ファイルを作るか何かして多少は動作検証しないとまずいかしら、と思ったのでこちらはまだ公開やプルリクをしてません。

和訳(ja.po)をまる二日かけてやり抜いたので、死蔵はしないつもりです。それとは別に ja.po に書かれてた連絡先からの返事も多少は待とうかなと。

## 説明が古い…
wxGlade はかなり大量にツールチップテキストを仕込んであって偉いのですが、翻訳以前に原文があまりにも古い場合があるのは困りもの。Windows Vista, XP, 9x に GTK+, wxGTK1 といった文字がありました。修正確認が大変そうなのと、git 的に別の目的のものを混ぜる形になるので手をつけてません。

それと似た話で、流石に Python 2 系は切ってもいいんじゃないですかねぇ？

# 最後に
Python における gettext や gettext そのものについても書きたい気持ちがちょっとありますが、それはまた別の機会に。