Introduction
A .po file is the text catalogue of GNU gettext:
it lists the messages of a program, each with its translation into one language. The
letters stand for Portable Object. A translator works on a PO file, and the build
compiles it to the binary .mo
catalogue that programs load at run time.
The usual life of a PO file starts with a template
(.pot) that xgettext extracts from the program’s source. The
translator copies it to LANG.po, by hand or with msginit, and
fills in the translations. When the program changes, msgmerge brings the
file up to date: new messages arrive empty, changed ones are marked
fuzzy, and messages the program no longer uses become
obsolete entries. The
language code in the file name takes the forms ll, ll_CC and
ll@variant, such as de, pt_BR or
sr@latin.
Many other tools read and write PO files: translation editors, web translation platforms and libraries in most programming languages. The file is text in the encoding that its own header entry names, usually UTF-8.
A file dropped on any page opens in the explorer. It shows the entries as a table (context, message, plural, translations, flags, references and comments), the header fields, and the errors it finds, each with its line number.
Structure
A PO file is a sequence of entries. Blank lines between entries are the custom, but
only the keywords and the quoted strings matter. Each entry is an optional group of
comment lines, then the keyword lines. The first entry of a file is the
header entry, whose
msgid is empty.
white-space
# translator-comments
#. extracted-comments
#: reference...
#, flag...
#| msgctxt previous-context
#| msgid previous-untranslated-string
#| msgid_plural previous-untranslated-string-plural
msgctxt context
msgid untranslated-string
msgid_plural untranslated-string-plural
msgstr translated-string
msgstr[0] translated-string-case-0
msgstr[1] translated-string-case-1
msgstr[N] translated-string-case-n
#Comments and flags translator comments, extracted comments, references, flags and previous strings; all optionallinesmsgctxtContext separates identical messages that mean different things; optional1 stringmsgidMessage the original text; empty only in the header entry1 stringmsgid_pluralPlural message the original text for other numbers; present only in plural entries1 stringmsgstrormsgstr[N]Translation one string, or one for each plural form1 or more strings
Reading rules in short
- Comment lines start with
#; the character after it says what the comment is (Comments and flags). A line whose first characters are#~belongs to an obsolete entry. - A string is written in double quotes with C escapes, and a message can be cut over several lines by closing the quote and opening it again on the next (Entries and strings).
- Two entries may not have the same context and message. The empty message belongs to the header entry, which comes first.
- Lines after the last entry that are not part of one are dropped by the tools.
Worked example
msgid ""
msgstr ""
"Project-Id-Version: demo 1.0\n"
"Language: fr\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#. Shown on the File menu
#: src/menu.c:41
msgctxt "menu"
msgid "Open"
msgstr "Ouvrir"
#: src/files.c:90
#, c-format
msgid "One file"
msgid_plural "%d files"
msgstr[0] "Un fichier"
msgstr[1] "%d fichiers"
#~ msgid "Gone"
#~ msgstr "Parti"
The compiled catalogue of an entry with a context stores the context, an EOT byte
(0x04) and the message as one string; see
the strings of an MO file.
Sources
This page and its sub-pages come from the GNU gettext manual’s chapters on PO files
(the texinfo source, gettext.texi, read in November 2026), and from the
reader that gettext itself uses, read-po-lex.c, for the points the manual
leaves open: the escape sequences and the comment prefixes. Where
msgfmt 1.0 was run on test files to see what it accepts, the page says
so.
Not described
Known, not yet covered
- Reference: the format strings that the
*-formatflags announce, and the checksmsgfmt --check-formatmakes on them. The flag names are listed, the syntax of each language’s format strings is not. - Viewer: the
domainkeyword of the reader’s grammar, which the manual does not document, is shown as an entry of its own with a note that it is not interpreted. - Viewer: the format strings of the entries are not checked
against their translations, and a plural entry whose number of translations differs
from
npluralsis only noted, sincemsgfmtdoes not check it. - Viewer: encodings other than those the browser’s text decoder knows are read as UTF-8, with a note.
Variants
- gettext PO message catalogue – the text catalogue a translator edits
- gettext POT template – the template a catalogue is made from, with every translation empty
- gettext MO binary catalogue – the compiled catalogue that programs load
Also used for
- Apple II disk image (ProDOS order) – The sectors of an Apple II floppy or the blocks of a ProDOS volume in ProDOS order.
Links
Software
- Poedit – translation editor for PO files (Windows, macOS, Linux)
- Lokalize – KDE’s translation editor (Linux, Windows)
- Gtranslator – GNOME’s PO editor (Linux)
- Weblate – web-based translation platform that keeps PO files in step with a repository
- GNU gettext – the tools that make and check PO files: xgettext, msginit, msgmerge, msgfmt and others (Linux, macOS, Windows)
Developers
- polib – reads and writes PO and MO files (Python)
- Babel – internationalisation library with a PO reader and writer (Python)
- gettext-parser – parses and compiles PO and MO files (JavaScript)
- Translate Toolkit – converts between PO and many other localisation formats (Python)
Reference
- The Format of PO Files – the GNU gettext manual’s description of entries, comments and flags
- Filling in the Header Entry – the manual’s description of the header fields
- Additional functions for plural forms – the manual on Plural-Forms and the plural rules of many languages
- gettext source code – the repository, including the PO reader
read-po-lex.c