File formats

gettext PO

GNU gettext .po and .pot catalogs, with msgctxt, plural forms mapped from the Plural-Forms header, and Unreal Engine's PO variant.

FormatIdentifierExtensions
gettext POgettext_po.po, .pot (exports use .po)
Unreal POunreal_po.po

Both formats share the PO syntax but key their entries differently. gettext keys on the source text; Unreal keys on an identity it stores in msgctxt. transglot never guesses Unreal PO: choose unreal_po explicitly for files from Unreal's Localization Dashboard.

gettext PO

locale/fr.po
msgid ""
msgstr ""
"Language: fr\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#. Shown on the home screen
msgid "Welcome back"
msgstr "Bon retour"

msgctxt "menu"
msgid "Open"
msgstr "Ouvrir"

msgid "%d item"
msgid_plural "%d items"
msgstr[0] "%d article"
msgstr[1] "%d articles"

Keys

The msgid is the key, because gettext keys on the source text. An entry with a msgctxt is keyed context|msgid: the file above imports the keys Welcome back, menu|Open and %d item. On export, the key is split at the first unescaped | back into msgctxt and msgid. A literal | or \ in a context, or a | in a msgid without context, is escaped with a backslash in the key name, so every key maps back to exactly one entry.

What is imported

  • #. extracted comments become the key's description.
  • Entries flagged #, fuzzy are skipped with a warning, as gettext tools treat them as unreliable.
  • Entries with an empty msgstr are untranslated and are skipped. So are obsolete #~ entries.
  • #: references, #| previous strings and # translator comments are not imported.
  • The header's Language is checked against the locale you import; a mismatch is accepted with a warning.
  • Strings may span several quoted lines, and the C escape sequences (\n, \t, \", \\, octal and hex escapes) decode.
  • A duplicate entry, a second header, or a msgstr[N] without msgid_plural is an error that names the line.

Plurals

An entry with msgid_plural becomes a plural key. transglot reads the header's Plural-Forms expression to work out which CLDR category each msgstr[N] belongs to:

  • A standard two-form file maps msgstr[0] to one and msgstr[1] to other.
  • A three-form file for Russian, Ukrainian, Polish and similar languages maps to one, few and many, and also fills other from many.
  • A form that has no CLDR category for the locale is dropped with a warning. A Plural-Forms expression transglot does not recognize falls back to first form as one and last as other, with a warning saying exactly what was mapped.
  • A file without a Plural-Forms header is read with the locale's standard convention.
  • A msgstr[N] beyond the declared nplurals is an error.

On export, transglot writes the locale's standard Plural-Forms line and orders msgstr[N] to match it, so msgfmt --check accepts the file. msgid_plural is the source locale's plural text when there is one.

Export

Exports start with a header holding Language, MIME-Version, Content-Type (UTF-8), Content-Transfer-Encoding and Plural-Forms. There is no date in it, so pulling twice with no changes gives identical files. Each entry has its description as #. lines. A key whose name is empty cannot be exported, because it would collide with the header.

Exports keep translations that are not valid ICU, because PO is a format for reviewers as well as apps.

Unreal PO

The .po files Unreal Engine's Localization Dashboard exports and imports (Export Text and Import Text).

Content/Localization/Game/fr/Game.po
msgid ""
msgstr ""
"Language: fr\n"
"Content-Type: text/plain; charset=UTF-8\n"

#. Key:	MainMenu_Play
#. SourceLocation:	/Game/UI/MainMenu.MainMenu
msgctxt "MainMenu,MainMenu_Play"
msgid "Play"
msgstr "Jouer"

Keys

  • The key is the msgctxt (Namespace,Key), and msgid is the source text, not the key.
  • A file without msgctxt falls back to the #. Key: comment. Without either, the entry is keyed on its msgid, with a warning.
  • #. SourceLocation: and #. InfoMetaData: comments and #: references are Unreal's own scaffolding and are dropped. Any other #. line becomes the key's description.
  • Fuzzy entries are skipped with a warning; untranslated (empty msgstr) entries are skipped.
  • Escapes decoded: \\, \", \n, \t, \r. Any other escape is kept as written, with a warning.

Export

Each entry is written as msgctxt (the key), msgid (the source text) and msgstr (the translation), with the description as #. lines, after a date-free header.

Unreal handles plurals in the engine, not in PO files, so Unreal PO carries simple strings only and plural keys are left out of an export. If you need plural forms in a PO file, use gettext_po.

On this page