Skip to main content
gettext uses POT files as source message templates and PO files as locale catalogs. These catalogs can include message context and plural forms. Hyperlocalise reads both .po and .pot. Supported extensions: .po, .pot. Unreal Engine localization catalogs that export gettext .po files use the same parser.

Source file

Save this example as locales/en-US/messages.po.

Configure your files

Use this i18n.yml for the example, or add its file mapping to your existing bucket. See path templates for other layouts.

Translate

Install the CLI and set OPENAI_API_KEY in your project’s .env.local or shell. You can also configure another AI provider.
The dry run previews the work. The second command writes translations to the configured target path and updates the lockfile.

Unreal Engine rich text

Unreal Engine style tags close with nameless </>. Hyperlocalise treats each recognized tag as a placeholder so translators edit the surrounding words, not the markup. Writeback restores the original tags in the .po file, including tags that an existing target file moved or changed relative to the source. Save this source catalog as locales/en-US/messages.po:
In the Content Editor, each Unreal tag appears as a chip such as UE#0. Keep every chip. Translate only the visible words. {ItemName} stays a separate placeholder from the style tags around it. Attributes without double quotes, such as size='12' or size=12, are not Unreal tags. The following </> is still a tag. Converts at most 1000 Unreal tags in one entry. Further tags stay plain text and round-trip unchanged. Do not nest Unreal tags. The engine renders nested markup as literal text.

Keys, context, and comments

A singular entry’s key is its msgid. When msgctxt is set, the key is msgctxt||msgid, the same join Phrase Strings uses. Identical msgid values in different contexts stay separate entries.
Those two entries are nav||Open and forum||Open. Translator comments (#) and extracted comments (#.) are sent with the string as context. Reference comments (#:), flag comments (#,), and previous-string comments (#|) stay in the file. Obsolete entries (#~) are kept and are not translated. Replacing a translation removes a fuzzy flag and leaves other flags, such as c-format, in place. The header entry (msgid "") is metadata, not a string. Language and Plural-Forms in that header select plural categories. On writeback for a target locale, Hyperlocalise sets Language to that locale (hyphens become underscores) and writes the matching gettext Plural-Forms rule. It also clears a fuzzy flag on the header, replaces a template’s charset=CHARSET with UTF-8, and gives every plural entry the target’s number of forms, including entries with no translation yet.

Plural forms

A plural entry becomes one string per category, in gettext index order. English (nplurals=2) produces msgid||one and msgid||other. Polish produces one, few, many, and other. Arabic produces zero, one, two, few, many, and other. Russian uses one, few, and many. Croatian, Serbian, and Bosnian use one, few, and other for the same formula. With context, the key is msgctxt||msgid||one.
Writeback emits msgstr[0] through msgstr[n-1] for the target language and fills a category that has no translation from other. A lockfile entry that still uses the bare msgid fills the one slot. An empty msgstr falls back to msgid. An empty plural slot other than one falls back to msgid_plural. That is how .pot templates and Crowdin’s default source text are read. A source catalog that already stores the English text in msgstr keeps using msgstr. Add this header field when an empty msgstr must stay empty instead of falling back to msgid:

Behavior and limitations

  • Multiline quoted continuations are supported. Leading and trailing spaces in msgid are significant.
  • Map .pot templates directly, or keep a source-language .po whose msgstr values hold the source text.
  • Plural categories follow GNU gettext rules for the languages Hyperlocalise knows (English, French, German, Spanish, Polish, Russian, Czech, Arabic, Japanese, Chinese, and the usual neighbors). An unknown Plural-Forms formula with two slots is treated as one and other. Other unknown formulas use plural0, plural1, and so on.
  • Strings that gain translator comments, extracted comments, or msgctxt are new work on the next run. Plural keys change from a bare msgid to msgid||category, so existing plural lockfile entries are translated again once.
  • Unreal Engine rich-text tags in .po messages become placeholders during translation and return to the original markup on writeback. See Unreal Engine rich text.

Next steps