Better i18n with gettext: use class-based API
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 初心者へのやさしさ
- 35/100
- issue の種類
- 機能追加
- 明瞭さ
- おおむね明確
- 活発さ
- 停滞
- 技術スタック
- python
調査の方向性
まず、Click における from gettext import _ の現在の使用箇所と、command/group の初期化パスを特定します。次に、Python の classic gettext API と class-based gettext API を確認し、古い API と提案されている click.i18n 統合について互換性の対象範囲を定義します。Click が import 時に gettext のグローバル domain を変更せず、consumer が翻訳 domain を分離できるようになれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Hi lovely Click maintainers,
Currently, Click implements gettext using the classic GNU gettext API. That looks like this:
from gettext import _
print(_("Hello, world!"))
This API depends on a global state in the gettext module. By calling gettext.textdomain(), the active translation domain is changed for all Python modules that use the classic GNU gettext API.
This side effect is usually desirable, except when your module is imported by another module as a library. So you usually don't want to call gettext.textdomain() without putting it behind some sort of function call. With argparse, this is easy: put it in your main function before you even create the ArgumentParser object. With Click, I'm not sure this is possible:
- Your main group/command is decorated with all manner of Click magic and its contents may not actually be run (e.g.
--help). - There is no way to pre-hook a group/command with a function call that I am aware of.
So you end up having to call gettext.textdomain() on import of your module containing your Click groups/commands.
We can fix that by switching to the class-based API. Because Click will still need to support the old API as well for backwards compatibility, my proposal looks a little as follows. Create a module click.i18n with the following contents (simplified):
import gettext as _gettext_module
TRANSLATIONS = None
def gettext(message):
if TRANSLATIONS is None:
return _gettext_module.gettext(message)
return TRANSLATIONS.gettext(message)
# alias
_ = gettext
Now, elsewhere in Click, you replace all from gettext import _ with from .i18n import _.
Subsequently, we can create a function install_translations(translations) in i18n.py that replaces the TRANSLATIONS global constant with an instantiated GNUTranslations object. This function would still need to be called before the consumer's main function, but it wouldn't change the gettext global state—it would only change Click's. Which, as far perfectionism goes, is probably tolerable. It would be better still if there was a pre-hook, but this is fine.
Furthermore, the consumer could use different domains for Click's TRANSLATIONS object and their own, allowing them to separate their own translations from Click's, and hypothetically reuse the Click translations in other projects.
In fact, having done this plumbing, Click could even ship its own translation strings, getting rid of duplication efforts of translating the same Click strings. Click's own translations could then be activated using e.g. install_click_translations() without any arguments.
In summary, the problems solved by this:
- Importing the Click consumer's module no longer changes the global state of the gettext module.
- Users can separate their own module's translations from Click's.
- Click would be enabled to provide its own translations to reduce duplication of efforts.
I am not aware of other ways to achieve the above that do not require changes to Click. Adding a pre-hook to groups/commands might partially address the problem.
I am willing to make a PR if this issue is validated.
I wrote a blog post here that provides more context on how I use gettext + Click (+ some other components). It has more context than is necessary to understand this issue.
- 主要言語
- Python
- スター
- 17.8k
- フォーク
- 3.3k
- 平均マージ
- 3日 3時間
- マージ済み PR(30日)
- 13
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
pallets/click のほかの issue
-
`show_envvar=True` Drops Environment Variable from Error Messages When Using `auto_envvar_prefix`オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
メンテナーはふだん 1 日以内に返信
-
More private utilities that need to be marked and public api deprecated再び着手できるかも このイシューのプルリクエストはマージされずにクローズされました。 オープンtyping
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
pallets/click#3847 · コメント 9 件 ·
メンテナーはふだん 1 日以内に返信
-
Automatically append ellipsis (`...`) to metavars when `multiple=True` in options対応中かも @SparshGarg999 が 89 日前に担当しました。 オープンhelp output
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
pallets/click#3652 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
`HelpFormatter.write_usage` breaks options at a hyphen対応中かも @kdeldycke が 9 日前に担当しました。 オープンhelp output
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
pallets/click#3362 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
Add glossary of terms to click reference docs対応中かも @rohitbarhate111-commits が 55 日前に担当しました。 オープンdocs
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
pallets/click#3077 · コメント 5 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
needs-triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
gke-labs/kube-agents#5671 ·
メンテナーはふだん 1 日以内に返信
-
docs(auth): Method B step 4 should tell users to tick "Use this client for an AI-powered agent"オープンdocumentation next-release v0.9.6
難易度 1/5 1時間未満 初心者へのやさしさ 88/100
khuisman/mcp-gee-sweet#1446 ·
メンテナーはふだん 1 日以内に返信
-
model:sonnet runtime:claude security size:S
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
FootprintAI/Containarium#3671 ·
メンテナーはふだん 1 日以内に返信
-
HolidayBase: reassigning `language` does not re-initialize translations or re-populate holidays対応中かも @shikhabhadoria が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
vacanza/holidays#4116 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
bug CLI exec
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
メンテナーはふだん 1 日以内に返信