![]() |
Python Localization and Internationalization |
Python (Wikipedia) is a very popular programming language that is used to build all kinds of applications, including web pages and applications. Soluling Desktop and Soluling Cloud support Python.
The end of the document contains links to get the full source code of the samples. After reading this document, we recommend reading a tutorial about how to use Soluling.
The most common way to localize Python applications is to use gettext. When using gettext, you identify all the strings that need to be translated, and then you replace the strings with calls to gettext functions. On run time, the gettext function returns the string that matches the active language. The gettext module is included in the Python standard library, so you don't have to install anything.
Bind a text domain to the directory that contains the localized files, and use _ as a short name of the gettext function.
import gettext
from gettext import gettext as _
gettext.bindtextdomain('HelloWorld', 'locale')
gettext.textdomain('HelloWorld')
print(_("Hello World"))
If a string contains placeholders, pass the whole string to gettext and format it after the translation. Add a comment on the line before the string to give the translator more information.
# name: Name of the user
print(_("Hello {name}!").format(name='John'))
Do not build sentences by concatenating translated parts, and do not pass f-strings to gettext, because the value of an f-string is formed before gettext gets it. See the Composite sample.
Use gettext's xgettext tool to extract the strings into a PO file. The --add-comments option adds the comments of your code to the file.
xgettext --from-code=UTF-8 --add-comments -d HelloWorld HelloWorld.py
This creates HelloWorld.po. This file is the original file that you localize. Run xgettext again whenever you have modified the strings in your code.
Python's gettext looks for the compiled MO file in <localedir>/<language>/LC_MESSAGES/<domain>.mo, for example, locale/fi/LC_MESSAGES/HelloWorld.mo. Soluling creates the localized PO files in this structure and, by default, also compiles them into MO files. The language is selected from the environment variables LANGUAGE, LC_ALL, LC_MESSAGES, and LANG. To use a specific language, use gettext.translation.
fi = gettext.translation('HelloWorld', localedir='locale', languages=['fi'])
fi.install()
print(_("Hello World"))
Note! gettext requires an underscore in the directory names of country-specific languages, for example, de_AT or pt_BR. Soluling currently names these directories with a hyphen (e.g., de-AT). If you localize to country-specific languages, rename those directories after building. Language-only directories, such as fi and de, work as they are.
gettext has a plural enabled function: ngettext. Pass the singular and plural forms of the original language and the count. gettext returns the right plural form of the active language.
# count: Amount of files
print(gettext.ngettext("{count} file", "{count} files", value).format(count=value))
When Soluling creates the localized PO files, it writes the right number of plural forms for each language and the right Plural-Forms header. See the Plural sample that is localized to Finnish, Japanese, and Polish. Learn more about plurals in PO files.
Django (homepage) uses gettext and PO files too. Configure localization in settings.py.
MIDDLEWARE = [
...
'django.middleware.locale.LocaleMiddleware',
...
]
USE_I18N = True
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
LANGUAGES = (
('en-US', _('English')),
('de', _('German')),
('fi', _('Finnish')),
)
Mark the strings with gettext (usually imported as _) in Python code and with {% translate %} in templates. Then extract the strings and create the template file.
django-admin makemessages --keep-pot
This writes locale/django.pot. Create the Soluling project for django.pot. Soluling detects that the file comes from Django and creates the localized files into locale/<language>/LC_MESSAGES/django.po. Finally, compile the localized files.
django-admin compilemessages
LocaleMiddleware selects the language from the URL, session, cookie, or the Accept-Language header of the browser. See the note about country-specific directory names above.
Flask (homepage) does not have built-in localization. The most common extension is Flask-Babel, which uses gettext and PO files. Mark the strings with gettext or _ in code and templates, and use Babel's pybabel tool to extract the strings into a template file.
pybabel extract -F babel.cfg -o messages.pot .
Create the Soluling project for messages.pot, and build the localized files into translations/<language>/LC_MESSAGES/messages.po. Then compile them.
pybabel compile -d translations
HelloWorld.po or locale/django.pot) on Soluling or click the New from File or Files button and select the file.locale\fi\LC_MESSAGES\HelloWorld.po and HelloWorld.mo.When you change the strings, extract them again, open the Soluling project, and choose Home | Scan. Soluling keeps the existing translations, and you only translate the strings that were added or changed.
With Soluling Cloud, you localize the PO file in your browser: upload the file, translate it in Translate, and download the localized PO files. You need a Soluling account. See the available Cloud plans.
Click the project's green Translate button on the dashboard. Translate opens the project, and you can type the translations into the grid. Machine translation suggestions, translation memory, and spell checking are available there. You do not have to finish every language before moving on to the next step.
Plural messages are shown with a row for each plural form of the target language, and the comments of your code are shown to the translator.
locale/<language>/LC_MESSAGES/<domain>.po, for example, locale/fi/LC_MESSAGES/HelloWorld.po.Then compile the PO files into MO files, for example, with msgfmt -o HelloWorld.mo HelloWorld.po, django-admin compilemessages, or pybabel compile.
When you have extracted the strings again, upload the new file, translate what is new or changed, and download the localized files again. On the dashboard, click the project's Update file button (the upload arrow), select the new file or drop it onto the page, and click Update. Existing translations are kept, so you only translate the strings that were added or changed.
The dashboard is one of four ways to use Soluling Cloud. You can also use the SoluCLI command-line tool, Soluling Desktop, or SoluMake, which can run the update and build steps in your build pipeline. See the Cloud tutorial for all of them.
GitHub and <data-dir>\Samples\Python contain the following samples:
| Directory | Description | Notes |
|---|---|---|
| HelloWorld | A simple application that shows plain strings, placeholders, and translator comments. | Try this first! |
| Driving | Shows how to localize a Python application. | |
| Plural | Shows how to create grammatically correct singular and plural messages. Localized to Finnish, Japanese, and Polish. | |
| Composite | Shows the right and wrong ways to build messages that contain values, such as concatenation and f-strings versus formatted strings. | |
| Number | Shows how to localize messages that contain numbers. | No Soluling project |
| Django | A minimal Django application localized to German, Austrian German, Finnish, and Japanese. The Soluling project is Minimal\locale\django.ntp. | |
| Flask | A minimal Flask application. | Not localized yet |
| Formats | Shows locale-dependent date and time formatting. | No Soluling project |
Most samples contain Extract.bat that extracts the strings with xgettext and Run.bat that runs the sample. Python.sln is a Visual Studio solution that contains the samples. In addition, the PO and PHP samples show how to localize PO files.
You can configure how to localize your PO file by selecting the item in the project tree, right-clicking, and choosing the Options menu. A source dialog appears that lets you edit the options. This source uses the following option sheets.