msgctxt használata: Környezet hozzáadása a Gettext fordításokhoz

Lefordítod az angol „Book” szót németre, és a fordítód magabiztosan visszaküldi: „Buch”. Három héttel később hibajelentés érkezik: a „Book a table” gomb a foglalási űrlapodon most „Buch a table” feliratot mutat – a főnevet, nem az igét. A szó helyes volt. A kontextus hiányzott. Ez az egyik leggyakoribb csendes hiba a szoftverlokalizációban, és a javítás már évtizedek óta létezik a Gettextben: msgctxt.
Ha valaha is kiadtál olyan fordítást, ahol egyetlen angol szövegrészlet az egyik helyen helyes volt, a másikon viszont értelmetlen, akkor beleütköztél a kétértelműségi problémába. Ugyanaz a forrásszó különböző fordításokat kap attól függően, hogy hol jelenik meg. msgctxt nélkül a fordító (ember vagy mesterséges intelligencia) nem tudja megkülönböztetni ezeket az eseteket, mert mindössze a csupasz msgid "Book" szöveget látja. Ez az útmutató elmagyarázza, hogyan működik az msgctxt a Gettextben, hogyan jelöld meg a forráskódodat _x() és _ex() segítségével, hogyan jelenik meg a .po fájljaidban, és miért egy kontextus-érzékeny fordítási folyamat az egyetlen megbízható módja annak, hogy ezeket a szövegeket nagy léptékben is helyesen fordítsd.
A kétértelműségi probléma: Egy szó, sok jelentés
A természetes nyelv tele van olyan szavakkal, amelyek egyetlen angol kifejezésre egyszerűsödnek, de más nyelveken több szóra bomlanak. A fordító csak a forrásszöveget látja, így amikor két, egymással nem összefüggő UI elem ugyanazt az angol szót használja, ugyanazt az msgid-t osztják meg – és a Gettext egyetlen bejegyzésbe vonja össze őket.
Nyelvek között felosztódó szavak
Három klasszikus példa:
- „Book” – a főnév (tárgy a polcon) versus az ige („Book a flight”). Német: Buch versus buchen.
- „Post” – tartalom közzététele versus levélküldés. Francia: publier versus courrier.
- „Order” – sorrend/rendezés versus vásárlás. Spanyol: orden versus pedido.
Angolul a kódod ugyanazt a szöveges stringet használja mindkét helyen:
// Somewhere in a library catalog screen
echo __( 'Book', 'mytextdomain' );
// Somewhere in a reservation form button
echo __( 'Book', 'mytextdomain' );
Hogyan olvadnak össze az azonos szövegek egyetlen bejegyzéssé
Amikor futtatod a wp i18n make-pot vagy az xgettext parancsot, mindkét hívás egy .po bejegyzésbe olvad össze:
#: catalog.php:42 reservation-form.php:88
msgid "Book"
msgstr ""
Pontosan egy msgstr mező van, amit ki kell tölteni. Bármit is választ a fordító, a két képernyő közül az egyik rossz lesz. A fordító ezt akkor sem tudja kijavítani, ha megérti a problémát, mert maga a formátum nem teszi lehetővé, hogy két fordítást adjon meg egy msgid esetén. A kétértelműség bele van sütve az adatokba.
Mi az az msgctxt, és hogyan szünteti meg a kétértelműséget?
msgctxt egy kontextus-string, amely egy fordítási bejegyzéshez van csatolva. A rövid válasz: egy második kulcsot ad hozzá az msgid mellé, így a Gettext a (kontextus, msgid) párost egyedi párként kezeli. Két, azonos msgid-vel, de különböző msgctxt-vel rendelkező bejegyzés két különálló, egymástól függetlenül fordítható stringgé válik.
A Gettext keresési modelljében a fordítás kulcsa általában csak a forrásszöveg. msgctxt esetén a kulcs a kontextus és a forrás kombinációja lesz. Ez az egész mechanizmus, és ezért működik olyan tisztán: nem a megjelenített szöveget változtatod meg, hanem csak a belső keresési kulcsot.
Az msgctxt sor egy .po fájlban
Egy .po fájlban a kontextus a saját sorában, közvetlenül az msgid felett jelenik meg:
#: catalog.php:42
msgctxt "noun"
msgid "Book"
msgstr "Buch"
#: reservation-form.php:88
msgctxt "verb"
msgid "Book"
msgstr "Reservieren"
Most két bejegyzés van. Azonos msgid értékkel, de különböző msgctxt értékkel rendelkeznek, így mindegyik saját msgstr-t kap. A katalógus a Buch szót jeleníti meg; a foglalás gomb a Reservieren szót. A futásidejű környezet kiválasztja a megfelelőt, mert a kódod megmondta, melyik kontextust használja.
Hasonlítsd ezt össze a fentebb bemutatott hibás, egysoros verzióval. A különbség nem a fordítás minősége – hanem az, hogy az adatmodell egyáltalán lehetővé teszi-e a helyes válasz létezését.
Kódod megjelölése: _x() és _ex()
Az msgctxt beágyazásához a .po sablonodba egy kontextus-érzékeny fordítási függvényt hívsz meg a szokásos helyett. WordPressben ezek az _x() és a hozzá tartozó _ex() függvények; a nyers Gettextben pedig a pgettext()-nek felelnek meg.
Választás az _x() és _ex() között
Az egyszerű __() függvény a stringet és a szövegtartományt veszi fel. A kontextusos változat a kontextust második argumentumként szúrja be:
// Without context - ambiguous
__( 'Book', 'mytextdomain' );
// With context - the second argument is the msgctxt
_x( 'Book', 'noun', 'mytextdomain' ); // returns the translated string
_ex( 'Book', 'verb', 'mytextdomain' ); // echoes it directly
// Real-world disambiguation
_x( 'Post', 'verb: publish content', 'mytextdomain' );
_x( 'Post', 'noun: mail item', 'mytextdomain' );
_x( 'Order', 'sequence or sorting', 'mytextdomain' );
_x( 'Order', 'customer purchase', 'mytextdomain' );
A második argumentum a kontextuscímke. Soha nem jelenik meg a felhasználóidnak – kizárólag a kétértelműség feloldására szolgál, mind a Gettext keresés, mind pedig a fordítást végző személy (vagy dolog) számára. Írd a kontextusokat rövid, leíró tippként: 'főnév', 'ige', 'gomb felirat', 'admin menü'. Egy olyan homályos kontextus, mint az '1', technikailag érvényes, de használhatatlan egy fordító számára.
Amikor újragenerálod a sablont, az extraktor felismeri ezeket a hívásokat, és kiadja az msgctxt sort. Az olyan eszközök, mint a Poedit és más PO szerkesztők, ezután láthatóan csoportosítják a bejegyzéseket kontextus szerint, így egy emberi fordító azonnal látja, hogy a „Book (főnév)” és a „Book (ige)” két különböző feladat. Ha még mindig a kinyerési eszközláncodat állítod be, vagy azzal küzdesz, hogyan interakcióba lépnek a változók ezekkel a stringekkel, az PO fájlok fordítása a kódváltozók megsértése nélkül című útmutatónk részletesen tárgyalja a kapcsolódó munkafolyamatot.
Miért hibáznak a naiv fordítók – és sok mesterséges intelligencia eszköz – ebben
Itt van a kellemetlen rész. Az msgctxt hozzáadása a forráskódodhoz szükséges, de nem elegendő. A kontextus csak akkor segít, ha a fordítást végző entitás ténylegesen el is olvassa.
Az eldobott kontextus hibamódja
Egy naiv kötegelt fordítási szkript így működik: végigiterálja a bejegyzéseket, megragadja az összes msgid-t, elküldi egy fordítási API-nak, és az eredményt az msgstr-be írja. Soha nem nézi az msgctxt sort. Így annak ellenére, hogy gondosan megírtad az _x( 'Book', 'noun' ) és _x( 'Book', 'verb' ) kódokat, a szkript két azonos kérést küld – „Fordítsd le a Book szót” – és ugyanazt a választ illeszti be mindkettőbe. Minden megjelölési erőfeszítésed az utolsó lépésnél kárba vész.
Sok általános célú mesterséges intelligencia alapú fordítóeszköznek van hasonló vakfoltja. Ezeket szöveg fordítására építették, és az msgctxt metaadat, nem szöveg. Ha az eszköz .po fájlodat stringek listájává alakítja, mielőtt elküldi a modellnek, a kontextus soha nem jut el a modell promptjába. A modell, bármilyen jel hiányában, az adott szó statisztikailag leggyakoribb jelentésére – általában a „Book” esetében a főnévre, a „Post” esetében a közzétételre – alapoz, és csendben félrefordítja a kisebbik esetet. Nem fogsz hibát látni. Hónapokkal később egy német felhasználótól fogsz hibajelentést kapni.
A kontextus és a többesszámok ugyanazon gyökérproblémán osztoznak
Itt keresztezi egymást a többesszám-kezelés és a kontextus is, mivel mindkettő attól függ, hogy az eszköz megérti-e a Gettext struktúráját, ahelyett, hogy a fájlt lapos szövegként kezelné. Ha a stringjeid szám alapú alakokat is tartalmaznak, ugyanaz a strukturális tudatosság fontos – ezt részletezzük a Gettext többesszámok megértése című cikkünkben.
Hogyan használja egy kontextus-érzékeny pipeline az msgctxt-t
A msgctxt-t tiszteletben tartó fordítási pipeline az ellenkezőjét teszi, mint a naiv szkript. Strukturált adatként elemzi a .po fájlt, az egyes bejegyzések kontextusát csatolva tartja a forrásszövegéhez, és ezt a kontextust a prompt részeként átadja az AI-nak – így a modell tudja, hogy a „Book” szót kifejezetten igeként fordítja, nem pedig absztrakt értelemben.
A kontextus mint elsőrangú jel
Pontosan így közelíti meg a problémát a SimplePoTranslate. A kontextus-érzékeny mesterséges intelligenciája az msgctxt sort elsőrangú jelként olvassa: amikor két bejegyzés megosztja az msgid-t, de kontextusban eltér, akkor azokat a valójában különböző stringekként fordítja le, és a kontextus tipp tájékoztatja a modell szóválasztását. Az eredmény az, hogy a „Book (főnév)” Buch-ként, míg a „Book (ige)” buchen vagy reservieren-ként tér vissza – automatikusan, anélkül, hogy minden kétértelmű kifejezést manuálisan javítanod kellene.
Ugyanilyen fontos, hogy a pipeline megőrzi az msgctxt sort a kimenetben. Egy gyengébb eszköz eltávolíthatja a kontextust az oda-vissza fordítás során, csendben egybeolvasztva a két bejegyzésedet, és újra bevezetve a kétértelműséget a következő összevonáskor. A teljes Gettext támogatás azt jelenti, hogy a kontextus túléli a fordítást, az .mo fordítást és a későbbi újraimportálásokat is – így a kétértelműség feloldása tartós, nem pedig egyszeri manuális javítás. A sztringekben lévő helykitöltők Szintaxis zárolásával kombinálva olyan fordításokat kapsz, amelyek mind kontextuálisan helyesek, mind szerkezetileg érintetlenek.
A megjelölési döntés továbbra is a tiéd – csak te tudod, hogy egy adott „Book” ige. De amint megjelölted a forráskódodat _x() és _ex() segítségével, egy kontextus-érzékeny pipeline ezt a megjelölést helyes fordításokká alakítja minden célnyelven, stringenkénti felügyelet nélkül.
Összefoglalás
A kétértelműségi probléma – egy angol szó, sok jelentés – nem egy furcsaság, amelyet figyelmen kívül hagyhatsz; ez a Gettext által tárolt stringek szerkezeti jellemzője. A megoldás az msgctxt: jelöld meg a kétértelmű stringeket a forráskódodban _x() és _ex() segítségével, adj minden előfordulásnak egyértelmű kontextuscímkét, és hagyd, hogy a Gettext a fordítást a (kontextus, msgid) párosra kulcsolja. Ez a rész rajtad múlik, és percekbe telik.
A nehezebb rész az, hogy gondoskodj arról, hogy a fordítási lépésed ténylegesen tiszteletben tartja ezt a kontextust, ahelyett, hogy eldobná. A naiv szkriptek és csak szöveges AI eszközök figyelmen kívül hagyják az msgctxt-t, és újra bevezetik pontosan azt a hibát, amit meg akartál előzni. Egy kontextus-érzékeny pipeline elolvassa a kontextust, helyesen lefordítja az összes egyértelműsített bejegyzést, és megőrzi azt a fordítás és újraimportálás során is.
Kész vagy véget vetni a kontextus-vakságtól szenvedő félrefordításoknak? Próbáld ki a SimplePoTranslate-et ingyen — hitelkártya nélkül. Az ingyenes szint kezeli a valódi
.poés.potfájlokat teljes msgctxt kontextus támogatással, így az egyértelműsített stringjeid már elsőre helyesen fordítódnak.