Fallgropar¶
Den här webbplatsen är översatt till trettiofem språk, och varenda en av dem togs fram genom att köra det kretslopp som dokumentationen lär ut. Det är ett litet korpus med branschens mått mätt, och ändå räckte det för att träffa de flesta av de fällor som gör i18n svårare än det ser ut.
Varje avsnitt nedan är något som faktiskt gick fel här, hur det såg ut när det hände, och var gränsen går mellan vad biblioteket kontrollerar åt dig och vad som förblir din egen bedömning.
Att byta namn på en variabel översätter om en mening¶
Ett msgid är katalogens nyckel, och ett interpolerat namn ligger inuti det.
Att flytta en konstant till modulnivå och versalisera den så som Pythons stil
kräver — author till AUTHOR — förvandlade
Copyright © 2026 {author} · MIT License till ett meddelande som ingen katalog
någonsin hade sett. Varje översättning av den raden skulle ha gått tillbaka
genom fuzzy-cykeln, på varje språk, för ett namnbyte som inte ändrade något en
läsare kunde se.
Biblioteket hindrar dig inte: båda stavningarna är giltiga platshållarnamn. Vad det däremot gör är att göra namnet värt att skydda — en interpolation måste vara ett enkelt namn, så det som står i katalognyckeln är ett ord som en översättare kan läsa, inte ett uttryck.
Spegelfallet är säkert av konstruktion. Konverteringar och formatspecifikationer
ingår inte i msgid:t, så att strama åt {amount:,.2f} till {amount:,.0f}
ändrar ingen nyckel och ogiltigförklarar ingen översättning någonstans.
nplurals=2 betyder inte två olika strängar¶
Turkiska, ungerska, persiska och bengaliska deklarerar alla två pluralformer,
och i alla fyra är de två formerna av ett räknat meddelande med rätta samma
sträng — substantivet står kvar i singular efter ett räkneord, så {n} sayfa
är rätt både för en sida och för tio. En granskare som "rättar" dubbleringen
förstör översättningen.
Det motsatta misstaget är precis lika lätt. Lettiskans tredje form finns för
noll ensamt; slovenskans andra är ett dualis, för exakt två;
rumänskans sista form kräver ordet de som dess två första inte får ha. Att
fylla de platserna med en singular och en plural ger en katalog som bara är fel
för antal som ingen testar.
Värre är att ordningen mellan platserna inte är semantisk. Kymriskan
indexerar sina fem former så att msgstr[0] är det allmänna fallet och
msgstr[1] är singularen. Att fylla i dem i den självklara följden placerar
singularen där varje oräknat meddelande kommer att hitta den.
Biblioteket tar inget av detta på sig, och det är just poängen: målspråkets pluralregel bor i dess egen kataloghuvud, och unions-/snittregeln låter en översättning ha fler former, eller färre, än källan. Vad det kontrollerar är det enda det kan kontrollera utan att kunna språket — att varje form behåller de platshållare den behöver.
Två former kan vara identiska av en anledning¶
Iriskan har fem pluralformer, och i den här webbplatsens byggrapport stavas
flera av dem likadant. Det är inte ett klipp-och-klistra-slarv: leathanach
börjar på l, och ingen av de två initiala mutationer som iriska räkneord
utlöser skrivs ut på l. Formerna gör fortfarande verkligt arbete — stammen
växlar mellan leathanach och leathanaigh, och antal över tio återgår till
singularen — men inget substantiv med betydelsen "sida" skulle visa
kontrasten.
Varje kontroll som flaggar dubblerade former som misstänkta kommer att flagga korrekt iriska. En människa som kan språket är den enda granskaren för detta.
Ett meddelande kan bara kongruera med ett enda antal¶
Den här webbplatsens byggrapport berättar hur många sidor som renderades och
hur lång tid det tog. Att skriva det som "Rendered {n} pages in {seconds}
seconds" ser harmlöst ut och går inte att översätta: gettext väljer en form
utifrån ett antal, och det antalet är n. Ordet seconds skulle behöva
kongruera med ett tal som pluralmaskineriet aldrig får se.
Lösningen är att göra den andra storheten till en enhetssymbol i stället för
ett ord, och enhetssymboler är i sin tur lokaliserade: den här webbplatsens
kataloger bär s, с, ث, שנ׳ och mp, och fransk, spansk och svensk
typografi vill ha ett mellanslag före symbolen där engelskan inte vill det.
Inget av det är bibliotekets sak — men att lägga märke till att ett meddelande
behöver två kongruenser är det, och det enda verktyget för den saken är att
skriva meddelandet annorlunda.
Att redigera en engelsk mening redigerar främmande grammatik¶
Startsidan sa förut "all ten language editions". Att ta bort talet — en engelsk ändring på ett ord, gjord för att talet ständigt blev inaktuellt — gjorde ett plural-subjekt singulart. Spanska, italienska, portugisiska, ryska, ukrainska, grekiska, nederländska och hebreiska behövde alla kongruera om verbet; flera behövde ändra participet också.
En källändring som läses som trivial på engelska är inte trivial längre ned i
kedjan. Att markera den som fuzzy, vilket är vad pybabel update gör, är den
mekanism som ger varje översättare chansen att upptäcka den.
Osynliga skillnader överlever varje kopiering¶
Guiden citerar ett diagnostikmeddelande som innehåller (nаme) — en avsiktlig
escape-sekvens, eftersom tecknet den namnger är ett kyrilliskt а som ingen
läsare kan skilja från det latinska. Översättare av den här webbplatsen
förvandlade den escape-sekvensen till det faktiska tecknet fem separata
gånger, på fem olika språk, och producerade varje gång en sida som såg
korrekt ut och var fel.
Just den här fångar biblioteket, och det är skälet till att diagnostiken är formad som den är: en platshållare vars bokstäver blandar skriftsystem rapporteras två gånger, en gång läsbart och en gång escapat, eftersom den escapade formen är den enda stavning som skiljer dem åt. Ett hårt mellanslag inuti klamrar skrivs ut med kodpunkt av samma skäl. Katalogkontrollen avvisar meddelandet innan det hinner gå ut.
Icke-tom är inte översatt¶
En katalog som ställts i ordning med sina msgid:n kopierade in i msgstr:erna klarar varje naiv kontroll: inget är tomt, inget är fuzzy, meddelandemängden stämmer exakt. En utgåva av den här webbplatsen låg ute så i flera timmar. Det gjorde också åtta sidor i en annan utgåva som var byte-identiska kopior av den engelska källan — vilket klarar en kontroll som jämför kodblock mellan dem, eftersom de är samma fil.
Inget av det är något ett översättningsbibliotek kan se. Båda är billiga att
testa för, men inte genom att kräva att varje post skiljer sig från sin källa:
OK, produktnamn, personnamn, akronymer och kodidentifierare översätts alla
till sig själva, och en kontroll som förbjuder det ger falsklarm för all
framtid.
Mät andelen i stället, över en hel katalog eller en hel sida, och skicka avvikarna till en människa. Den här webbplatsens eget test gör precis det — det jämför prosaraderna i varje utgåva mot den engelska källan och fallerar över 25 % identiska. Den förfalskade utgåvan låg på 87 %; varje äkta översättning ligger mellan 4 % och 8 %, vilket är den lilla svansen av rader som med rätta sammanfaller, såsom URL:er och citerad programutdata. De två populationerna ligger tillräckligt långt isär för att tröskeln inte ska behöva vara exakt.
Katalogen är inte det enda som översätts¶
Två fel här hade ingenting med gettext att göra.
Att översätta en rubrik ändrar ankaret som genereras ur den, så varje korssidelänk in i det avsnittet går sönder — tyst, och bara på det språket. Den här webbplatsen spikar det engelska ankaret på varje rubrik, och ett test härleder den förväntade listan från den engelska sidan.
Och webbplatsgeneratorn levererar gränssnittsöversättningar för sextioåtta språk, vilket inte omfattar swahili eller iriska. Utan en sådan faller bygget inte tillbaka till engelska; mall-inkluderingen misslyckas och utgåvan går över huvud taget inte att bygga. Två av det här förrådets egna filer finns för att fylla den luckan.
Dina verktyg har också buggar¶
CI-steget som den här dokumentationen rekommenderar för att fånga inaktuella
kataloger, pybabel update --check, klarar inte det jobbet för något projekt
som använder pgettext eller npgettext. På Babel 2.18.0 rapporterar det
varje katalog med ett msgctxt som inaktuell, vid varje körning. Jämförelsen
går genom Catalog.is_identical, som slår upp varje meddelande under den
nyckel det lagras under — och för ett kontextbärande meddelande är den nyckeln
paret (id, context), som Catalog.get inte tar emot. Uppslagningen ger
ingenting, och katalogerna blir aldrig lika:
>>> from babel.messages.catalog import Catalog
>>> c = Catalog(locale="ja")
>>> c.add("Guide", "ガイド", context="navigation")
<Message 'Guide' (flags: [])>
>>> c.is_identical(c)
False
Den hittades här genom att någon försökte använda verktyget, rapporterades uppströms, och ersättningskontrollen finns på produktionssidan.
Den allmänna lärdomen är den obekväma: en grind som alltid lyser rött är sämre än ingen grind alls, eftersom ett team stänger av den. Kontrollera att din CI-kontroll faktiskt kan gå igenom innan du litar på att den kan fälla något.
Vad biblioteket är till för, på en rad¶
Det mesta på den här sidan är omdöme som inget verktyg kan ta över. Vad ett verktyg kan göra är att garantera att en översättning inte kan ändra strukturen i den mening den översätter — inte kan tappa ett värde, hitta på ett, formatera om ett eller sträcka sig in i dina objekt — och att säga det i en mening som den som ska rätta felet kan agera på. Det är hela vad det här biblioteket lovar, och resten av den här webbplatsen är hur det håller löftet.