PO and POT files

Last updated on
9 August 2022

Drupal uses the .po (portable object) and .pot (portable object template) extensions for user interface text translation files. These use the GNU Gettext format. .pot files are templates that contain source text but no translations, while .po files also contain the translations to a particular language.

PO files

PO files are the files that contain the actual translations. Each language will have its own PO file; for example, for French there would be a fr.po file, for German there would be a de.po, for American English there might be en-US.po. You can even use po files to customize the displayed text without changing the code, by for example, creating an adapted file such as en-my_company.po.

The core of each PO file is made of pairs of the source text (that which is found in the code) and target text (the translated text). For example, in the French PO file you might have a translation of a string as follows:

msgid "Hello world"
msgstr "Bonjour le monde"

The msgid line contains the text actually in the code, and the msgstr line contains the translated text. If the msgstr is empty, then on the site the source text will be used instead.

PO files are plain text files and can thus be edited by any text editor, but there are also many tools available to make editing them easier.

A Drupal site will usually contain multiple PO files for a single language, which are distributed as a single package. Individual PO files can be imported into the database via http://[your_site]/admin/build/translate/import (Drupal 6) or http://[your_site]/admin/config/regional/translate/import (Drupal 7 and beyond):

This page imports the translated strings contained in an individual Gettext Portable Object (.po) file. Normally distributed as part of a translation package (each translation package may contain several .po files), a .po file may need to be imported after off-line editing in a Gettext translation editor. Importing an individual .po file may be a lengthy process.

Note that the .po files within a translation package are imported automatically (if available) when new modules or themes are enabled, or as new languages are added. Since this page only allows the import of one .po file at a time, it may be simpler to download and extract a translation package into your Drupal installation directory and add the language (which automatically imports all .po files within the package). Translation packages are available for download on the Drupal translation page.

POT files

POT files are the template files for PO files (Warning: Microsoft also uses POT as the extension for PowerPoint template files, but these are not the same). They have all the translation strings (the msgstr parts) left empty, for example:

msgid "Hello world"
msgstr ""

The French PO file (fr.po) is then a copy of the POT file but with the translations filled in.

If you need to generate a POT file, the Translation template extractor module will do this.

Syntax

The syntax follows the GNU Gettext format.

String delimiters (quote characters)

Drupal only supports single– (') and double– (") quoted strings in PO and POT files. It does not support the other GNU gettext quoting methods.

Context

To quote GNU Gettext format:

msgctxt context
msgid untranslated-string
msgstr translated-string

The context serves to disambiguate messages with the same untranslated-string. It is possible to have several entries with the same untranslated-string in a PO file, provided that they each have a different context. Note that an empty context string and an absent msgctxt line do not mean the same thing.

Plural forms

Plural forms have some additions to the syntax. See the gettext manual section on plurals for more information. Here is a sample:

msgid "One file removed"
msgid_plural "%d files removed"
msgstr[0] ""
msgstr[1] ""

In English, there are two pluralization forms of words: "singular" is used for 1 item, and "plural" is used for 0 or more than 1 item (example: 0 cats, 1 cat, 2 cats, ...). Many languages have different rules for plurals, which could have 1, 2, or more forms for pluralization. If your language does not follow the same pluralization scheme as English, your PO file will need to contain a line telling about the plural forms in the header, in this format:

Plural-Forms: nplurals=1; plural=0;

You can find the current plural header strings for your language by downloading a translation file for Drupal for your language from localize.drupal.org and looking in the top few lines.

Comments

Lines in PO and POT files that start with # are comments.

Variables

In the Drupal project, we have the ability to substitute variables into user interface text. Words starting with @, !, and %, as well as words inside {} and expressions like {text}.text are variables and should be left as-is in translation.

Custom module translation

A PO file can be added to a custom module by referring to it in the my_module.info.yml file.

name: My Module
type: module
description: My module provides my module functionallity.
package: Custom
core: 8.x
core_version_requirement: ^8 || ^9
'interface translation project': my_module
'interface translation server pattern': modules/custom/%project/translations/%project.%language.po

Some headers need to be added to the modules/custom/my_module/translations/my_module.nl.po file to make Drupal import the translations.

# Dutch translation of the My Module module.

msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"POT-Creation-Date: 2018-07-23 09:50+0200\n"
"PO-Revision-Date: 2018-07-23 09:50+0200\n"
"Last-Translator: NAME <EMAIL@ADDRESS>\n"
"Language-Team: Dutch <EMAIL@ADDRESS>\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"

msgid "example text"
msgstr "Voorbeeldtekst"

Examples

Here are examples of these files:

A POT file (i.e. the translation template):

#: modules/user/views_handler_filter_user_name.inc:29
msgid "Enter a comma separated list of user names."
msgstr ""

#: modules/user/views_handler_filter_user_name.inc:112
msgid "Unable to find user: @users"
msgid_plural "Unable to find users: @users"
msgstr[0] ""
msgstr[1] ""

A German PO file (i.e. the file containing the translations):

#: modules/user/views_handler_filter_user_name.inc:29
msgid "Enter a comma separated list of user names."
msgstr "Eine kommagetrennte Liste von Benutzernamen."

#: modules/user/views_handler_filter_user_name.inc:112
msgid "Unable to find user: @users"
msgid_plural "Unable to find users: @users"
msgstr[0] "Benutzer konnte nicht gefunden werden: @users"
msgstr[1] "Benutzer konnten nicht gefunden werden: @users"

Help improve this page

Page status: No known problems

You can: