Frustrerende situaties bij het gebruik van gettext_lazy als JSON-sleutel in Django
Samenvatting in één zin: Een JSON-sleutel moet altijd een 'echte' string zijn, maar
gettext_lazyvan Django retourneert eigenlijk geen string, maar een__proxy__object.
1. Waarom werkt code die altijd goed werkte ineens niet meer?
Tijdens de ontwikkeling met Django is het gebruik van gettext_lazy voor meertalige ondersteuning dagelijkse kost. Maar soms, terwijl je het normaal gebruikt, kan er plotseling een serialisatiefout optreden tijdens het JSON-antwoordproces (JsonResponse).
Meestal zie je dan vage foutmeldingen zoals __proxy__ iets, wat verwarrend kan zijn. Maar als je de oorzaak nader bekijkt, zit de boosdoener op een verrassend eenvoudige plek.

2. De boosdoener zat in de "Sleutel"
Om meteen met de deur in huis te vallen: een gettext_lazy-object wordt stilzwijgend geaccepteerd als waarde in een dictionary, maar zodra het als sleutel wordt gebruikt, veroorzaakt het problemen.
| Categorie | Gebruik als waarde | Gebruik als sleutel |
|---|---|---|
| Werking | Normaal (automatische str-conversie) |
Foutmelding |
| Reden | Automatische typeconversie wordt ondersteund bij JSON-serialisatie | Een JSON-sleutel moet altijd een 'echte' string zijn |
3. Waarom dit verschil?
Wat gettext_lazy retourneert, is geen echte string, maar een __proxy__-object. Zoals de naam al zegt, is het een belofte: "Ik geef je de vertaling wanneer die nodig is."
json.dumps() van Python of JsonResponse van Django doorloopt de waarden van een dictionary en lost deze 'belofte' automatisch op naar een string (evaluatie). Maar voor een sleutel van een dictionary ligt het anders. Volgens de JSON-standaard moet een sleutel altijd een string zijn. In dit proces wordt het __proxy__-object niet automatisch geconverteerd en botst het direct, wat resulteert in een foutmelding.
# ✅ Geen probleem: de waarde wordt automatisch naar str geconverteerd.
json.dumps({'language': _('Korean')})
# ❌ Foutmelding: de sleutel kan niet zelfstandig worden geconverteerd en wordt geweigerd.
json.dumps({_('Korean'): 'language'})
4. Hoe lossen we dit op?
Methode 1: Gebruik gewoon gettext (het meest elegant)
Als de 'lazy'-methode niet strikt noodzakelijk is, is het het meest praktisch om gettext te gebruiken, dat direct een string retourneert bij aanroep.
from django.utils.translation import gettext as _
LANGUAGE_MAP = {
"en": _("English"),
"ko": _("Korean"),
}
- Opmerking: Houd er rekening mee dat bij deze methode de vertaling wordt bepaald op het moment dat de app wordt geladen, dus voorzichtigheid is geboden als een dynamische vertaalomgeving belangrijk is.
Methode 2: Voeg str() toe vlak voor serialisatie
Als je al uitgebreid gebruikmaakt van 'lazy'-objecten, kun je een geforceerde stringconversie uitvoeren vlak voordat je ze doorgeeft aan JSON.
# Wikkel de sleutel in str() voordat je deze als sleutel gebruikt om er een 'echte string' van te maken.
lang_key = str(LANGUAGE_MAP.get(code))
Methode 3: Delegeer de vertaling naar de client
Als je geen Django-templates gebruikt voor de frontend, maar een aparte frontend-client (wat tegenwoordig misschien wel de trend is), dan kan de Django (of DRF) server alleen codes zoals en en ko doorgeven. De feitelijke tekst die op het scherm wordt weergegeven, wordt dan afgehandeld door de i18n-bibliotheek van de frontend (zoals React, Vue, etc.). Dit heeft als voordeel dat de serverlogica lichter wordt.
Conclusie
Als je tijdens het gebruik van json.dumps() in combinatie met gettext_lazy() de situatie tegenkomt van "gisteren werkte het wel, waarom vandaag niet meer?", dan is de kans groot dat je het gisteren gelukkig alleen als waarde gebruikte, en vandaag als sleutel.
gettext_lazy is handig, maar je moet er altijd rekening mee houden dat het uiteindelijk geen 'echte string' is. Vooral bij het omgaan met JSON is dit cruciaal. Ik hoop dat dit artikel nuttig is voor iedereen die met vergelijkbare fouten worstelt.
There are no comments.