alestro
@alestro

Как локализовать проект при помощи mo файлов?

Интересует как локализуют php проекты при помощи mo файлов, к примеру, как в том же WP. Где можно почитать по этому поводу?
  • Вопрос задан
  • 1039 просмотров
Пригласить эксперта
Ответы на вопрос 3
AlekseyNemiro
@AlekseyNemiro
full-stack developer
Проводить локализацию проектов PHP, и тем более WordPress, силами gettext не приходилось, но на днях делал это с некоторыми bash-скриптами. Возможно мой опыт будет полезен.

1. Необходимо определить домен и область поиска файлов сообщений.
Домен задается функцией textdomain, а путь к ресурсам - bindtextdomain.
bindtextdomain('example', './local');
textdomain('example');

2. В коде, весь локализуемый текст следует выводить через функцию gettext. Например:
echo gettext("Hello world!");
echo gettext("Test123");

Можно использовать фразы, либо ключи.

Если использовать фразы, то не нужно будет создавать ресурсы для языка по умолчанию. Из минусов такого подхода, то что некоторые фразы могут иметь разное значение в зависимости от контекста использования, но эту проблему в принципе можно решить перефразированием.

Если использовать ключи (например, MSG_ABOUT_TEXT1), то придется создавать ресурсы для языка по умолчанию. При отсутствии ресурсов, или если что-то сломается, пользователю будут выводиться ключи, что не очень хорошо.

Какой подход выбрать, зависит от сложности проекта и предпочтений. Фразы проще и проблем с ними в небольших проектах точно не будет.

3. Необходимо извлечь строки из кода и создать файлы po. Делается это при помощи набора инструментов gettext. Если ранее этим заниматься не приходилось, то скорее всего придется выполнить установку необходимых компонентов.

Под Debian/Ubuntu установить пакет gettext можно следующей командой:

sudo apt-get install gettext

Под остальными разновидностями Linux систем в общем-то примерно также, только диспетчер пакетов будет другим.

Под Windows мне не доводилось этим заниматься. Думаю, можно что-нибудь найти. Например, sourceforge.net/projects/gettext

Я опишу только порядок действий под Linux (конкретно Debian).

Для создания po-файла необходимо выполнить следующую команду:

xgettext --extract-all --default-domain=example --from-code=utf-8 /путь к проекту/*.php


Параметры:

--default-domain - имя домена, должно соответствовать домену, который используется в коде PHP (textdomain). Не путать с доменом сайта, хотя обычно используется название проекта;
--from-code=имя кодировки текста. Например: utf-8;
--extract-all - указывает на необходимость извлечения всех строк.

Дополнительно можно указать параметры:

--output=имяФайла.po - по умолчанию строки будут извлечены в файл messages.po, этот параметр позволяет указать любое имя файла;
--no-wrap - запрет разбития длинных строк;
--join-existing - если есть предыдущие извлеченные строки, то эта опция указывает на необходимость склейки новых найденных строк с существующими (использовать, только если po-файл существует);
--copyright-holder="Вася Пупкаидзе" - кому принадлежат авторские права.

Параметр --help позволяет посмотреть список всех параметров :-)

Программа создаст po-файл примерно следующего содержания:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-01-15 14:55+0300\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

msgid "Hello world!"
msgstr ""

msgid "Test123"
msgstr ""


msgid - это идентификатор сообщения.
msgstr - перевод.

После указания перевода и сохранения изменений в файле po:
msgid "Hello world!"
msgstr "Привет, мир!"

msgid "Test123"
msgstr "Тест123"

Его необходимо компилировать в файл mo.
Делается это при помощи команды msgfmt:
msgfmt --output-file="/путь к файлу.mo" "/путь к файлу.po"

Для себя я написал следующий bash-скрипт, который компилирует все файлы po в каталоге (включая все подкаталоги), в котором был запущен скрипт:
#!/bin/bash

lang="$1"
path="$(cd "$(dirname "$0")" && pwd)"

if [[ -n "$lang" ]]; then
  path="$path/$lang"
  if [[ ! -d "$path" ]]; then
    mkdir "$path"
  fi
fi

cd "$path"

find "$path" -name "*.po" | while read -r f; do
  po_dir="$(dirname $f)"
  po_file="$(basename $f)"
  po_name="$(echo $po_file | cut -d'.' -f1)"
  msgfmt --output-file="$po_dir/$po_name.mo" "$f" && \
  printf "Created: $po_dir/$po_name.mo\n" || \
  printf "ERROR: Could not create mo-file from: $f\n"
done

Если все пройдет без эксцессов, файлы mo следует разместить по подпапкам LC_MESSAGES нужных культур, которые должны располагаться в папке указанной в коде PHP функцией bindtextdomain. Запутано вышло, проще показать :-)

Если:
bindtextdomain('example', './local');
textdomain('example');

, то структуру размещения файлов mo:
/local/ru/LC_MESSAGES/messages.mo
/local/en/LC_MESSAGES/messages.mo
/local/en_US/LC_MESSAGES/messages.mo
/local/ru_GB/LC_MESSAGES/messages.mo
/local/[Код культуры]/LC_MESSAGES/messages.mo

/local - часть пути, указанная в коде PHP: bindtextdomain('example', './local');
Код культуры - это стандартный (ISO 639) двузначный код языка, или код языка с указанием кода региона (ISO 639 + ISO 3166): ru (русский язык), ru_RU (русский язык, Россия), en (английский язык), en_US (американский английский) и т.п.

Честно говоря, я не вижу пока никаких особых преимуществ от использования gettext. Слишком сложный процесс генерирования всех этих po и mo. Проще и удобней текстовой файл с нужными ресурсами создать, или использовать базу. Хотя работу с gettext можно автоматизировать, но придется потратить на это время.
Ответ написан
Комментировать
@Wol_fi
php, js, mysql, highload
не вижу смысла в этих .po\.mo, тем более для php.
хранить в простом ассоциативном массиве - и проще (файл отредактировать в любом редакторе можно, без необходимости компиляции) и меньше ресурсов тратит.
вот например вордпресс 5MWYccj.pngMO::import_from_reader и не выкинуть, и процессорного времени жрёт.
Ответ написан
BuriK666
@BuriK666
Компьютерный псих
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы