Гид по технологиям

Локализация Python с gettext

5 min read Локализация Обновлено 18 Nov 2025
Локализация Python с gettext
Локализация Python с gettext

Этот практический гид показывает, как быстро сделать консольное Python‑приложение многоязычным с помощью встроенного модуля gettext. Мы пройдемся по пометке строк, созданию .po/.mo файлов, настройке каталогов локалей и добавим полезные методики, проверки и примеры для реального проекта.

Иллюстрация: локализация Python с gettext

Введение

Локализация (l10n) и интернационализация (i18n) часто пугают. В Python задача проще: модуль gettext разделяет логику приложения и тексты для пользователя. Это облегчает перевод и поддержку множества языков.

В этой статье вы найдете пошаговый пример на простом CLI‑приложении, а также практичные подсказки для расширения: работа с контекстом, множественным числом, тестированием переводов и стратегиями развертывания.

Короткая терминология

  • gettext — модуль Python для загрузки переводов.
  • .pot — шаблон (template) с исходными строками.
  • .po — человекочитаемый файл перевода (Portable Object).
  • .mo — скомпилированный двоичный файл для быстрого чтения (Machine Object).

Шаг 1: Одноязычное приложение (исходник)

Начнем с простого примера — приложение приветствует пользователя и спрашивает имя. Все строки сейчас захардкожены.

# app.py

def run_app():

    print("Welcome to the multilingual demo!")
    name = input("Please enter your name: ")
    print(f"Hello, {name}! How are you today?")

if __name__ == "__main__":
    run_app()

Это работает, но только на одном языке. Наша цель — отделить тексты от кода, чтобы добавлять новые языки без изменения логики.

Шаг 2: Помечаем строки для перевода

Обертка _() — устоявшаяся конвенция для gettext. Она делает код читаемым и удобным для инструментов извлечения строк.

# app.py

import gettext

# Set up a placeholder for the gettext function.
# This makes it easy to replace with a real translation
# function later, as you'll see.
_ = gettext.gettext

def run_app():

    print(_("Welcome to the multilingual demo!"))
    name = input(_("Please enter your name: "))
    print(_(f"Hello, {name}! How are you today?"))

if __name__ == "__main__":
    run_app()

Важно: не переводите внутри форматируемых строк до момента выполнения перевода. Лучше использовать f‑строки или .format с переменными, но помните о порядке аргументов и синтаксисе языков.

Шаг 3: Структура каталогов и создание шаблона

Стандартная структура локалей выглядит так:

└── my_app/
    ├── app.py
    └── locales/
        ├── en_US/
        │   └── LC_MESSAGES/
        │       └── base.po
        └── es_ES/
            └── LC_MESSAGES/
                └── base.po

Используйте инструменты вроде xgettext или pybabel для извлечения строк в .pot файл.

xgettext --language=Python --keyword=_ --output=locales/base.pot app.py

Этот шаг создаст locales/base.pot с набором строк, помеченных _().

Затем создайте .po для каждого языка:

msginit --locale=es_ES --input=locales/base.pot --output-file=locales/es_ES/LC_MESSAGES/base.po
msginit --locale=en_US --input=locales/base.pot --output-file=locales/en_US/LC_MESSAGES/base.po

Шаг 4: Заполнение .po файла переводом

Файл .po прост: msgid — оригинал, msgstr — перевод. Переводчики редактируют только msgstr.

# locales/es_ES/LC_MESSAGES/base.po

msgid ""
msgstr ""
"Project-Id-Version: Multilingual Demo\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: es_ES\n"

msgid "Welcome to the multilingual demo!"
msgstr "¡Bienvenido a la demostración multilingüe!"

msgid "Please enter your name: "
msgstr "Por favor, introduce tu nombre: "

msgid "Hello, {name}! How are you today?"
msgstr "¡Hola, {name}! ¿Cómo estás hoy?"

Советы переводчику:

  • Не изменяйте msgid.
  • Сохраняйте placeholder’ы {name} в переводе.
  • Учитывайте порядок слов и пунктуацию в целевом языке.

Шаг 5: Компиляция .po в .mo и загрузка в Python

Скомпилируйте .po в .mo:

msgfmt -o locales/es_ES/LC_MESSAGES/base.mo locales/es_ES/LC_MESSAGES/base.po

Затем настройте загрузку переводов в коде:

# app.py

import gettext
import os

# Define the root directory for our translation files

LOCALE_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'locales')

def setup_language(lang_code):
    try:
        # Load the translation from the locale directory
        translation = gettext.translation('base', localedir=LOCALE_DIR, languages=[lang_code])
        # Install the translation globally so gettext can find it
        translation.install()
    except FileNotFoundError:
        # Fallback to a default language (e.g., English) if translation isn't found
        print(f"Warning: Translation for '{lang_code}' not found. Using default language.")
        gettext.install('base', LOCALE_DIR, names=['ngettext']) 

if __name__ == "__main__":
    # Simulate setting the user's language environment.
    # On a real system, you might read this from a user setting or system locale.

    # Try running the app in Spanish
    setup_language('es_ES')
    print(_("Welcome to the multilingual demo!"))

    # Now, let's switch to English for the rest of the app's flow
    setup_language('en_US')
    name = input(_("Please enter your name: "))
    print(_(f"Hello, {name}! How are you today?"))

Запустите скрипт — вы увидите первую строку на испанском, остальное на английском, что демонстрирует динамическую смену переводов.

Расширенные возможности и лучшие практики

Контекст и множественное число

  • Для контекста используйте pgettext или msgctxt в .po. Контекст важен, когда одно слово имеет разные значения.
  • Для множественного числа используйте ngettext и заполните форму в .po для чисел.

Пример ngettext в коде:

from gettext import ngettext

count = 3
print(ngettext("{count} file deleted", "{count} files deleted", count).format(count=count))

.po файл должен содержать соответствующие формы plural‑rules.

Безопасность форматирования

Всегда валидируйте и экранируйте пользовательские данные. Перед вставкой в переводимые строки используйте именованные плейсхолдеры ({name}) вместо позиционных, это уменьшает ошибки при переводе.

Идём дальше: CI, тесты и рабочий процесс переводов

  • Автоматизируйте извлечение строк в CI (xgettext) при изменении кода.
  • Проверяйте, что .po файлы не содержат незаполненных msgstr.
  • Включите тесты на корректность placeholder’ов и на наличие перевода для основных языков.

Когда gettext не подходит или требует доработок

Важно понимать ограничения:

  • gettext хорош для классических приложений, но не покрывает динамическую генерацию UI‑текстов без дополнительной архитектуры.
  • Работа с богатым содержимым (HTML, Markdown внутри переводов) требует дополнительного контроля безопасности.
  • Для большого числа переводчиков и сложного рабочего процесса может быть удобнее использовать TMS (Translation Management System) и интегрировать экспорт/импорт .po.

Альтернативные подходы:

  • JSON/YAML‑файлы с ключами (популярно в веб‑приложениях).
  • ICU MessageFormat для сложных правил склонения и множественного числа.
  • Сторонние библиотеки (babel, polyglot, fluent). Выбор зависит от требований к форматированию и взаимодействию с переводчиками.

Контроль качества переводов — чеклист

Роль: разработчик

  • Пометил все пользовательские строки _().
  • Использует именованные placeholder’ы.
  • Настроил CI для обновления .pot.

Роль: локализатор (переводчик)

  • Проверил все msgstr.
  • Сохранил плейсхолдеры и их синтаксис.
  • Проверил пунктуацию и стиль.

Роль: тестировщик

  • Запуск тестов на наличие всех переводов.
  • Проверка UI на усечение или переполнение текста.
  • Проверка множественного числа в разных языках.

Критерии приёмки

  • Все пользовательские строки помечены и присутствуют в .pot.
  • Для целевых языков есть .mo в релизном артефакте.
  • Переводы не ломают форматирование и плейсхолдеры.
  • Тесты на placeholder/плюральность проходят в CI.

Мини‑методология внедрения локализации в проект

  1. Инвенторизация: найдите все тексты, видимые пользователю.
  2. Пометка: замените строки на _().
  3. Экстракция: автоматизированно создайте .pot.
  4. Перевод: интегрируйте .po в рабочий процесс переводчиков.
  5. Сборка: собирайте .mo и включайте их в сборки.
  6. Тестирование: автоматические и ручные проверки.
  7. Поддержка: процесс обновления переводов при изменениях UI.

Примеры проблем и как их решать

Проблема: плейсхолдер поменял порядок слов в другом языке. Решение: используйте именованные плейсхолдеры и объясните переводчику контекст.

Проблема: строка слишком длинная и ломает интерфейс. Решение: договоритесь о лимитах длины, добавьте проверку в QA, в UI оставьте место для расширения.

Проблема: вариант слова зависит от рода. Решение: разделяйте строку на более мелкие элементы с контекстом или используйте дополнительные msgctxt.

Тестовые случаи и приёмка

  • Запуск приложения с различными языковыми параметрами (es_ES, en_US, fr_FR).
  • Изменение системного локаля и проверка fallback.
  • Наличие .mo в каталоге локалей после сборки.
  • Проверка работы ngettext для нескольких чисел (0,1,2,5,21).

Глоссарий (1‑строчный)

  • Локализация: адаптация продукта к языку и региональным особенностям.
  • Интернационализация: проектирование продукта, чтобы его можно было легко локализовать.
  • .po/.mo/.pot: форматы gettext для переводов.

Резюме

Используя gettext, вы быстро отделите тексты от кода и упростите перевод приложения. Начните с пометки строк, настройте структуру локалей, автоматизируйте экспорт/импорт и добавьте проверки в CI. Для сложных случаев рассмотрите ICU или TMS.

Важно

  • Сохранение плейсхолдеров и контекста критично.
  • Автоматизация уменьшает количество ошибок при обновлении строк.

Дополнительно: краткая дорожная карта внедрения

  1. Пометить все строки в кодовой базе.
  2. Настроить xgettext в CI.
  3. Подготовить шаблон .pot и подключить переводчиков.
  4. Добавить проверку на корректность placeholder’ов в unit‑тесты.
  5. Включить .mo файлы в релиз и мониторить отзывы пользователей по локалям.

Авторская заметка: этот гид описывает практический, безопасный и расширяемый подход к локализации небольших и средних Python‑проектов с использованием стандартных инструментов. Он пригоден как для CLI, так и как основа для серверных приложений, где простота и совместимость важнее сложной логики форматирования.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

RDP: полный гид по настройке и безопасности
Инфраструктура

RDP: полный гид по настройке и безопасности

Android как клавиатура и трекпад для Windows
Гайды

Android как клавиатура и трекпад для Windows

Советы и приёмы для работы с PDF
Документы

Советы и приёмы для работы с PDF

Calibration в Lightroom Classic: как и когда использовать
Фото

Calibration в Lightroom Classic: как и когда использовать

Отключить Siri Suggestions на iPhone
iOS

Отключить Siri Suggestions на iPhone

Рисование таблиц в Microsoft Word — руководство
Office

Рисование таблиц в Microsoft Word — руководство