## Djangoで[[gettext_lazy]]を[[JSON Key]]として使うと頭を抱える状況 {#sec-66ae94ff1145} > 結論を先に一言でまとめると:**[[JSON Key]]は必ず「本物の」文字列でなければならない**。しかし、Djangoの`gettext_lazy`が返すのは、実際には文字列ではなく`__proxy__`というオブジェクトです。 ## 1. 順調に動いていたコードがなぜ突然? {#sec-4a4b34e6a73c} Django開発において、多言語対応のために`gettext_lazy`を使うのは日常的なことです。ところが、普段通りに使っていたのに、ある日突然[[JSON]]レスポンス(JsonResponse)の過程で直列化(Serialization)エラーが発生することがあります。 通常、エラーログを見ても`__proxy__`といったような、意味不明なメッセージしか表示されないため、戸惑うものです。しかし、原因を紐解いてみると、意外にも単純なところに犯人がいます。 ![gettext_lazyとJSON Keyの問題に関するインフォグラフィック](/media/whitedec/blog_img/gettext_lazy_json_error.webp) ## 2. 犯人は「Key」にあった {#sec-361c46af305d} 結論から言うと、`gettext_lazy`オブジェクトは辞書の**Value**として使う場合は問題なく処理されますが、**Key**として使った瞬間に問題を引き起こします。 | 区分 | Valueで使った場合 | Keyで使った場合 | | :--- | :--- | :--- | | **動作可否** | 正常(自動でstrに変換される) | **エラー発生** | | **理由** | JSON直列化時に自動型変換をサポート | JSON Keyは必ず「本物の」文字列でなければならない | ## 3. なぜこのような違いが生じるのか? {#sec-80787e3802c2} `gettext_lazy`が返すのは、実際のStringではなく`__proxy__`というオブジェクトです。その名の通り、「後で必要になったら翻訳して渡すよ」と約束だけしている状態です。 Pythonの`json.dumps()`やDjangoの`JsonResponse`は、辞書内の値を走査しながら、この「約束」を自動的に文字列に展開(評価)してくれます。しかし、辞書の**Key**となると話は別です。[[JSON]]の標準ではKeyは必ず文字列でなければなりませんが、この過程で`__proxy__`オブジェクトが自動的に変換されず、そのまま衝突してしまうためエラーが発生するのです。 ```python # ✅ 問題なし: Valueは自動的にstrに変換されます。 json.dumps({'language': _('Korean')}) # ❌ エラー: Keyは自動的に変換されず、拒否されます。 json.dumps({_('Korean'): 'language'}) ``` ## 4. どのように解決するか? {#sec-87b95d49caed} ### 方法1: 単純に`gettext`を使う(最もシンプル) {#sec-d736d0465485} Lazy方式がどうしても必要な状況でなければ、呼び出しと同時に文字列を返す`gettext`を使うのが最も手軽です。 ```python from django.utils.translation import gettext as _ LANGUAGE_MAP = { "en": _("English"), "ko": _("Korean"), } ``` * **参考:** ただし、この方式はアプリがロードされる時点で翻訳が決定されるため、動的な翻訳環境が重要である場合は注意が必要です。 ### 方法2: 直列化直前に`str()`を挟む {#sec-fc5762a0f995} すでにLazyオブジェクトを広範囲で使っている場合は、[[JSON]]に渡す直前に強制的に文字列変換を行います。 ```python # Keyとして利用する前にstr()で一度囲み、「本物の文字列」にします。 lang_key = str(LANGUAGE_MAP.get(code)) ``` ### 方法3: 翻訳の主体をクライアントに任せる {#sec-f61be7ca95b2} もしフロントエンドでDjangoのテンプレートを使わず、別のフロントエンドクライアントを使用する方式であれば(最近ではこの方式がトレンドかもしれませんが)、Django(あるいはDRF)サーバーは`en`、`ko`のようなコード(Code)だけを返し、実際に画面に表示するテキストはフロントエンド(React、Vueなど)の[[i18n]]ライブラリで処理する方式です。サーバーロジックが軽量化されるという利点があります。 --- ## まとめ {#sec-0d2251a657d4} `json.dumps()`と`gettext_lazy()`を組み合わせて使用していて、「昨日は動いたのに、なぜ今日は動かないんだろう?」という状況に遭遇したなら、おそらく昨日は運良くValueにのみ使用し、今日はKeyに誤って使用した可能性が高いです。 `gettext_lazy`は便利ですが、結局のところ「本物の文字列」ではないという点を常に念頭に置いておく必要があります。特に[[JSON]]を扱う際にはなおさらです。同様のエラーで苦労されている方々の一助となれば幸いです。