What Is a .PO File?
Portable Object (PO) for i18n
Gettext Portable Object (.po)
Overview
A .po file is a Portable Object translation catalogue used by GNU gettext, the internationalisation system behind a very large share of open-source software. It pairs each translatable string in a program with its translation into one target language, along with the source locations where the string appears and any translator notes.
PO files are plain text and designed to be edited by translators who are not programmers. Before use at runtime they are compiled into binary .mo (Machine Object) files, which the application loads.
Technical Specifications
Format Details
- MIME Type:
text/x-gettext-translation - File Extensions:
.po(editable catalogue),.pot(template),.mo(compiled binary) - Category: Data
- Encoding: UTF-8 (declared in the header)
- System: GNU gettext
- Naming convention:
de.po,fr_CA.po,pt_BR.po- language and optional region
Identification
PO files are recognisable from their entry structure - msgid and msgstr pairs, with # comments:
#: src/app.c:142
msgid "File not found"
msgstr "Datei nicht gefunden"
The first entry in every file is a special one with an empty msgid, carrying metadata as email-style headers.
File Structure
The header entry
# German translation of ExampleApp.
# Copyright (C) 2025 Example Project
# This file is distributed under the same licence as ExampleApp.
#
msgid ""
msgstr ""
"Project-Id-Version: ExampleApp 2.1\n"
"Report-Msgid-Bugs-To: bugs@example.com\n"
"POT-Creation-Date: 2025-03-04 10:12+0000\n"
"PO-Revision-Date: 2025-03-11 14:03+0100\n"
"Last-Translator: Jane Doe <jane@example.com>\n"
"Language-Team: German <de@example.com>\n"
"Language: de\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"
The Plural-Forms line is the important one: it is a C-style expression that selects which plural form to use for a given number, and it differs per language.
Comment types
Each prefix means something specific:
# translator-added note
#. comment extracted from the source code
#: src/main.c:88 src/ui.c:12 source references
#, fuzzy, c-format flags
#| msgid "previous original" the prior text of a fuzzy entry
The fuzzy flag marks an entry whose source string changed since it was translated. Fuzzy entries are not used at runtime: the original English shows instead - until a translator reviews and clears the flag.
Plural forms
Languages differ in how many plural categories they need. English has two, Polish has three, Arabic has six:
#: src/files.c:203
#, c-format
msgid "%d file deleted"
msgid_plural "%d files deleted"
msgstr[0] "%d Datei gelöscht"
msgstr[1] "%d Dateien gelöscht"
Contexts
When one English word needs different translations depending on where it appears, msgctxt disambiguates:
msgctxt "menu|File"
msgid "Open"
msgstr "Öffnen"
msgctxt "status|connection"
msgid "Open"
msgstr "Offen"
The Translation Workflow
source code
│ xgettext - scan for translatable strings
▼
messages.pot (template, no translations)
│ msginit - create a new language catalogue
▼
de.po (translator works here)
│ msgfmt - compile
▼
de.mo (binary, loaded at runtime)
When source strings change, msgmerge updates existing .po files against a regenerated .pot, preserving completed translations and marking changed ones fuzzy.
History and Development
GNU gettext was written by Ulrich Drepper in the mid-1990s, standardising an approach that Sun had pioneered. It solved the problem of separating user-visible text from code so that translation could happen independently of development.
The system spread far beyond C. PHP, Python, Ruby, Perl, JavaScript, and Rust all have gettext bindings, and the format underpins WordPress translations, Django's django.po catalogues, and the localisation of most Linux desktop software. Web platforms such as Weblate, Transifex, Crowdin, and Pootle use PO as their interchange format.
Common Use Cases
- Open-source application localisation: GNOME, KDE, and most GNU software.
- WordPress themes and plugins: the standard translation mechanism.
- Django and Flask projects: via
django.poand Flask-Babel. - Continuous localisation pipelines: PO as the exchange format between developers and translation platforms.
- Community translation: the format is simple enough for non-technical volunteers.
How to Open a PO File
Dedicated editors
- Poedit: the most widely used cross-platform PO editor, with translation memory and validation.
- Lokalize (KDE) and Gtranslator (GNOME) - desktop editors integrated with their environments.
- Weblate / Transifex / Crowdin: web platforms that import and export PO.
- Any text editor: the format is plain UTF-8 text and perfectly readable.
Command-line tooling
# Extract translatable strings from source into a template
xgettext -o messages.pot --from-code=UTF-8 src/*.c
# Start a new language catalogue from the template
msginit -i messages.pot -l de_DE -o de.po
# Merge new source strings into an existing translation
msgmerge --update de.po messages.pot
# Compile for runtime use
msgfmt -o locale/de/LC_MESSAGES/app.mo de.po
# Check for errors and format-string mismatches
msgfmt --check --statistics -o /dev/null de.po
# Show completion statistics
msgfmt --statistics -o /dev/null de.po
# → 412 translated messages, 18 fuzzy translations, 7 untranslated messages.
Useful maintenance commands
# List only untranslated entries
msgattrib --untranslated de.po
# Strip obsolete entries
msgattrib --no-obsolete -o de.po de.po
# Compare two catalogues
msgcmp de.po messages.pot
Advantages
- Human-readable and diffable: reviews well in version control.
- Translator-friendly: no programming knowledge required, with strong editor support.
- Rich context: source references, extracted comments, and translator notes travel with each string.
- Proper plural handling: a per-language plural rule expression, not an English-shaped assumption.
- Fuzzy tracking: changed strings are flagged rather than silently mistranslated.
- Mature ecosystem: decades of tooling and platform support.
Limitations
- Compilation step required:
.pomust become.mobefore runtime. - English-as-key fragility: using the source string as the key means fixing a typo in English invalidates every translation of that string.
- Merge conflicts: line-oriented diffs on frequently regenerated files can be noisy.
- Limited rich content: designed for short UI strings, not documents or markup-heavy content.
- Context is optional: without
msgctxt, ambiguous short strings get mistranslated.
Related Formats
File Information
Portable Object (PO) for i18n
Data
.po
text/x-gettext-translation
Related File Types
Other file types in the Data category you might also need:
Start Analyzing PO Files Now
Use our free AI-powered tool to detect and analyze Portable Object (PO) for i18n files instantly with Google's Magika technology.
⚡Try File Detection Tool