1. Help Center
  2. Supported formats

gettext PO files

A short introduction to GNU gettext and its standard PO files.

File Extensions .po
API Extension gettext
Import Yes
Export Yes
Pluralization supported? Yes
Descriptions supported? Yes

PO is the acronym for “portable object”. It is the standard file format for localization with GNU gettext, an open-source GNU library designed to simplify the localization process. With GNU gettext, you can extract localizable strings from your source code into a PO file for translation. A PO file is basically a series of key-value pairs. The key “msgid” is where the source string is put while the value “msgtr” is where the translation goes.

How GNU gettext works

First, gettext will extract strings from your source code into a POT (portable object template). Then, based on your defined locales, gettext converts the POT file into a couple of locale-specific PO files, the type you can upload to a CAT tool for translation. After the translation is done, you can use gettext again to convert the translated PO files into MO files (machine object files), the type that will eventually be used for localization.

Note: PO files are in fact identical with POT files except that POT files are mostly used by gettext to generate locale-specific PO files. It is perfectly fine if you translate a POT file directly and rename it according to the intended locale later. Phrase supports not only the translation of both PO and POT but also the machine-readable MO files.


msgid ""
msgstr ""
"Language: English\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: PhraseApp (phraseapp.com)\n"

msgid "boolean_key"
msgstr "--- true\n"

msgid "empty_string_translation"
msgstr ""

# This is the amazing description for this key!
msgid "key_with_description"
msgstr "Check it out! This key has a description! (At least in some formats)"

msgid "key_with_line-break"
msgstr "This translations contains\na line-break."

msgid "nested.deeply.key"
msgstr "Wow, this key is nested even deeper."

msgid "nested.key"
msgstr "This key is nested inside a namespace."

msgid "null_translation"
msgstr ""

msgid "pluralized_key"
msgid_plural ""
msgstr[0] "Only one pluralization found."
msgstr[1] "Wow, you have %s pluralizations!"

msgid "sample_collection"
msgstr "---\n- first item\n- second item\n- third item\n"

msgid "simple_key"
msgstr "simple key, simple message, so simple.2"

#, fuzzy
msgid "unverified_key"
msgstr "I need verification, please verify me! (In some formats we also export this status)"

A typical gettext entry looks something like this:

# description (Optional)
msgid "key-name"
msgstr "My Translation"

gettext Header

The header of a gettext file might contain a locale name and data for plural forms that Phrase will extract during import:

msgid ""
msgstr ""
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: PhraseApp (phraseapp.com)\n"


If you provide comments in your gettext file we will add them as key descriptions during import:

# This is my description
msgid "app_title"
msgstr "My Software Project"


Gettext uses the msgctxt notation to distinguish different contexts for the same msgid. In Phrase every key name must be unique thus we will add the msgctxt as the first part of the key name, separated by two pipe symbols (||):

msgctxt "menu"
msgid "Open"
msgstr "I'am a translation"

msgctxt "forum"
msgid "Open"
msgstr "I'am some other translation"

In order to add the msgctxt to a new key, simply prepend it to the key name:


This will result in the following gettext output:

msgctxt "my_context"
msgid "my_key_name"

Plural forms

Gettext supports plural forms for a translation:

msgid "new_messages"
msgid_plural ""
msgstr[0] "You have a new message"
msgstr[1] "You have %{count} new messages"


The fuzzy keyword is used for translators verification. Thus fuzzy will automatically invoke the unverification process within your app. If you’re unfamiliar with verifications please have a look at the documentation on verification.

#, fuzzy
msgid "app_title"
msgstr "My Software Project"

More Information