## 在 Django 中將 gettext_lazy 用作 JSON 鍵時遇到的惱人狀況 {#sec-66ae94ff1145} > 結論簡而言之:**JSON 鍵必須是「真正的」字串**,但 Django 的 `gettext_lazy` 返回的實際上並非字串,而是一個 `__proxy__` 物件。 ## 1. 運作良好的程式碼為何突然出錯? {#sec-4a4b34e6a73c} 在 Django 開發中,為了處理多語言,使用 `gettext_lazy` 是家常便飯。然而,某天當我們像往常一樣使用它時,卻在 JSON 回應 (`JsonResponse`) 的序列化過程中突然爆出錯誤。 通常,錯誤日誌只會顯示諸如 `__proxy__` 之類的未知訊息,讓人摸不著頭緒。但深入探究原因,會發現問題的根源其實出乎意料地簡單。 ![關於 gettext_lazy 與 JSON 鍵問題的資訊圖表](/media/whitedec/blog_img/gettext_lazy_json_error.webp) ## 2. 禍根在於「鍵(Key)」 {#sec-361c46af305d} 開門見山地說,`gettext_lazy` 物件作為字典的 **值(Value)** 時,通常能順利通過,但一旦作為 **鍵(Key)**,就會引發問題。 | 分類 | 用作值(Value)時 | 用作鍵(Key)時 | | :--- | :--- | :--- | | **運作狀況** | 正常 (會自動轉換為字串) | **發生錯誤** | | **原因** | JSON 序列化時支援自動型別轉換 | JSON 鍵必須是「真正的」字串 | ## 3. 為何會產生這種差異? {#sec-80787a3802c2} `gettext_lazy` 返回的並非真正的字串,而是一個名為 `__proxy__` 的物件。顧名思義,它只是一個「稍後需要時再進行翻譯」的承諾。 Python 的 `json.dumps()` 或 Django 的 `JsonResponse` 在遍歷字典的值時,會自動將這個「承諾」解析為字串(Evaluation)。然而,對於 **字典的鍵(Key)** 來說,情況就不同了。根據 JSON 標準,鍵必須是字串,而在這個過程中,`__proxy__` 物件不會自動轉換,直接導致衝突並產生錯誤。 ```python # ✅ 沒有問題:值(Value)會自動轉換為字串。 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 時更是如此。希望這篇文章能幫助到那些正為類似錯誤而苦惱的朋友們。