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 {#sec-aff43a618865} Django’s vertaal-systeem gebruikt intern **GNU gettext**. Gettext werkt met een heel eenvoudige regel: * Originele string → `msgid` * Vertaalde string → `msgstr` * **Als `msgid` gelijk is, wordt altijd dezelfde `msgstr` gebruikt** ```po # 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` {#sec-e28151952ba2} 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) {#sec-40afc992a96b} ```html {% load i18n %} {% translate "Polish" %} ``` In het `.po`-bestand zijn beide `msgid "Polish"`, dus er is maar één vertaling. ### 2) Verbeterde code (met context) {#sec-4fa05f04b9d3} ```html {% load i18n %} {% translate "Polish" context "language name" %} ``` Belangrijk: * De tekst na `context` is **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 %}` {#sec-c2a9f27dea01} Voor langere zinnen kun je `{% blocktranslate %}` gebruiken met een `context`. ```html {% 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` {#sec-3a9a008d3f99} 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 {#sec-27f89a09cea2} ```python 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 {#sec-11832a96275e} ```python 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` {#sec-ed84f3cf8d15} ```python 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? {#sec-fb610023c81a} Na het toevoegen van context: ```bash python manage.py makemessages -l ko ``` Wordt in het `.po`-bestand een `msgctxt`-veld toegevoegd. ```po # 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 {#sec-df37b35ab408} Context-strings zijn niet zichtbaar voor de gebruiker, maar geven vertalers een unieke hint. ### 1) Beschrijf de *rol* {#sec-9dfe29490c86} * `"button label"` * `"menu item"` * `"tooltip"` * `"error message"` * `"form field label"` ### 2) Voeg een extra concept toe {#sec-135dce4b280b} * `"File"` * `"file menu item"` * `"uploaded file object"` * `"Order"` * `"e-commerce order"` * `"sorting order"` ### 3) Plaats geen vertaalde tekst in de context {#sec-9197b1a38f27} Context moet altijd in de originele taal (meestal Engels) en beschrijvend zijn. --- ## Wanneer gebruik je Contextual Markers? {#sec-58e84d2a2b4c} Overweeg altijd een `context`/`pgettext` als: 1. **Korte strings (1–2 woorden)** – knoppen, tabs, menu-items 2. **Herbruikbare strings met verschillende betekenissen** – `"Open"`, `"Close"`, `"Book"` 3. **Vertalers werken zonder de UI te zien** – externe vertaal-platforms, `.po`-bestanden alleen --- ## Samenvatting {#sec-8cc5759d0812} ![Ontroerde ontwikkelaar](/media/editor_temp/6/14112b82-d049-4b32-9275-02429e9305c0.png) * Django koppelt standaard één `msgid` aan één vertaling. * Homoniemen zoals `"Polish"`, `"May"`, `"Book"` veroorzaken vaak fouten. * Gebruik in templates `{% translate "…" context "…" %}` en in Python `pgettext`/`pgettext_lazy`/`npgettext`. * Hierdoor krijgt het `.po`-bestand een `msgctxt`-veld, waardoor dezelfde string verschillende vertalingen kan hebben. Resultaat: leesbare code, betere vertaal-kwaliteit en onderhoudbaarheid. --- **Aanbevolen artikelen** * [Django: gettext vs gettext_lazy verduidelijkt](/whitedec/2026/1/5/django-gettext-vs-gettext-lazy/) * [Problemen met gettext_lazy in JSON-sleutels](/whitedec/2025/4/26/gettext-lazy-json-key-problem-solution/)