88점
Django meertalige verwerking: "Polish" wordt "Polen" vermijden (Contextual Markers)
Wanneer je een app met meerdere talen ondersteunt, kom je soms op dit probleem.
- Een knop bevat “Polish” (verbeteren van de UI), maar de vertaling wordt “Polen”
- De maand “May” wordt in sommige talen als een persoonsnaam vertaald
- Het menu-item “Book” vertaalt alleen naar “boek” en niet naar “reserveren”
De oorzaak is simpel.
Computers kennen geen context. Als een string identiek is, behandelen ze deze als één en dezelfde.
In dit artikel leg ik uit hoe je met Django’s Contextual Markers dezelfde string in verschillende contexten kunt vertalen, zonder de broncode te veranderen.
Waarom gebeurt dit? De basiswerking van gettext
Django’s vertaal-systeem gebruikt intern GNU gettext. Gettext werkt met een heel eenvoudige regel:
- Originele string →
msgid - Vertaalde string →
msgstr - Als
msgidgelijk is, wordt altijd dezelfdemsgstrgebruikt
# django.po
msgid "Polish"
msgstr "Polen"
Zodra een .po-bestand een mapping heeft, wordt overal waar “Polish” voorkomt dezelfde vertaling gebruikt.
Daarom kunnen de volgende twee UI-elementen niet onderscheiden worden:
- “Polish” = werkwoord (UI verbeteren)
- “Polish” = taal/land
Om dit te voorkomen, kun je de broncode aanpassen, maar dat leidt vaak tot onduidelijke strings of moeilijk herbruikbare code.
We willen:
- De bronstring nog steeds
"Polish" - En een extra uitleg over de betekenis in de context
Hier komt de Contextual Marker (contextuele informatie) om de hoek kijken.
Oplossen in templates: {% translate %} + context
In Django-templates kun je het {% translate %} (of de oudere {% trans %}) tag gebruiken met een context-optie om dezelfde string in verschillende contexten te onderscheiden.
1) Originele code (conflict)
{% load i18n %}
<button>{% translate "Polish" %}</button>
<span>{% translate "Polish" %}</span>
In het .po-bestand zijn beide msgid "Polish", dus er is maar één vertaling.
2) Verbeterde code (met context)
{% load i18n %}
<button>
{% translate "Polish" context "verb: to refine UI" %}
</button>
<span>
{% translate "Polish" context "language name" %}
</span>
Belangrijk:
- De tekst na
contextis niet zichtbaar voor de gebruiker. - Het is alleen meta-informatie voor het vertaalsysteem en vertalers.
-
Houd het kort en duidelijk.
-
"verb: to refine UI" "language name""menu label""button text"
3) Ook in {% blocktranslate %}
Voor langere zinnen kun je {% blocktranslate %} gebruiken met een context.
{% load i18n %}
{% blocktranslate context "greeting message" with username=user.username %}
Hello {{ username }}
{% endblocktranslate %}
Op deze manier kun je dezelfde "Hello %(username)s" in verschillende contexten gebruiken.
Oplossen in Python-code: pgettext
In views, models, forms, enz. gebruik je in plaats van gettext de pgettext-familie.
Voorbeelden:
pgettext(context, message)pgettext_lazy(context, message)– voor lazy evaluation (model-velden, module-niveau)npgettext(context, singular, plural, number)– meervoud + context
1) Basisvoorbeeld
from django.utils.translation import pgettext
def my_view(request):
# 1. Maand "May"
month = pgettext("month name", "May")
# 2. Persoonsnaam "May"
person = pgettext("person name", "May")
# 3. Hulpwerkwoord "may" (~mogelijk)
verb = pgettext("auxiliary verb", "may")
Hier zijn alle msgid gelijk, maar dankzij verschillende context-waarden krijgen ze verschillende vertalingen.
2) pgettext_lazy in een model
from django.db import models
from django.utils.translation import pgettext_lazy
class Order(models.Model):
# "Order" = bestelling
type = models.CharField(
verbose_name=pgettext_lazy("order model field", "Order type"),
max_length=20,
)
STATUS_CHOICES = [
# "Open" = status
("open", pgettext_lazy("order status", "Open")),
# "Open" = actie (openen)
("opened", pgettext_lazy("log action", "Open")),
]
status = models.CharField(
max_length=20,
choices=STATUS_CHOICES,
)
3) Meervoud met npgettext
from django.utils.translation import npgettext
def get_notification(count):
return npgettext(
"user notification", # context
"You have %(count)d message", # singular
"You have %(count)d messages", # plural
count
) % {"count": count}
Hoe ziet het eruit in een .po-bestand?
Na het toevoegen van context:
python manage.py makemessages -l ko
Wordt in het .po-bestand een msgctxt-veld toegevoegd.
# django.po
# 1) "Polish" = UI verbeteren (werkwoord)
msgctxt "verb: to refine UI"
msgid "Polish"
msgstr "opp oetsen"
# 2) "Polish" = taal/land
msgctxt "language name"
msgid "Polish"
msgstr "Pools"
msgid blijft hetzelfde, maar msgctxt maakt het een aparte vertaling.
Tips voor goede context
Context-strings zijn niet zichtbaar voor de gebruiker, maar geven vertalers een unieke hint.
1) Beschrijf de rol
"button label""menu item""tooltip""error message""form field label"
2) Voeg een extra concept toe
-
"File" -
"file menu item" "uploaded file object"-
"Order" -
"e-commerce order" "sorting order"
3) Plaats geen vertaalde tekst in de context
Context moet altijd in de originele taal (meestal Engels) en beschrijvend zijn.
Wanneer gebruik je Contextual Markers?
Overweeg altijd een context/pgettext als:
- Korte strings (1–2 woorden) – knoppen, tabs, menu-items
- Herbruikbare strings met verschillende betekenissen –
"Open","Close","Book" - Vertalers werken zonder de UI te zien – externe vertaal-platforms,
.po-bestanden alleen
Samenvatting

- Django koppelt standaard één
msgidaan één vertaling. - Homoniemen zoals
"Polish","May","Book"veroorzaken vaak fouten. - Gebruik in templates
{% translate "…" context "…" %}en in Pythonpgettext/pgettext_lazy/npgettext. - Hierdoor krijgt het
.po-bestand eenmsgctxt-veld, waardoor dezelfde string verschillende vertalingen kan hebben.
Resultaat: leesbare code, betere vertaal-kwaliteit en onderhoudbaarheid.
Aanbevolen artikelen
댓글이 없습니다.