Интернационализация для
разработчиков плагинов и тем
Сергей Бирюков
WordCamp Moscow 2016
Сергей Бирюков
● WordPress-разработчик в Yoast
yoast.com
● Локализатор WordPress в России
ru.wordpress.org
sergeybiryukov.com
@SergeyBiryukov
Плагины и темы для всего мира
● Интернационализация (i18n) — возможность перевода
● Локализация (L10n) — перевод на конкретный язык
Плагины и темы для всего мира
● Более сотни языков
● Универсальный код
● Обратная связь
● Это просто
Локализованные каталоги тем
Локализованные каталоги плагинов
Введение в gettext
● Текстовый домен
– 'my-plugin'
● Подготовка строк
– <?php echo 'Title'; ?> →<?php _e( 'Title', 'my-plugin' ); ?>
● Файлы перевода
– .pot, .po, .mo
Текстовый домен
● Должен совпадать с именем папки плагина или темы:
– wp-content/plugins/my-plugin →'my-plugin'
– wp-content/themes/my-theme →'my-theme'
● Стоит добавить в заголовки плагина или темы:
– Plugin Name: My Plugin
– Version: 1.0
– Text Domain: my-plugin
Текстовый домен
● Подключение домена
– load_plugin_textdomain( 'my-plugin', false,
dirname( plugin_basename( __FILE__ ) ) . '/languages' );
– load_theme_textdomain( 'my-theme',
get_template_directory() . '/languages' );
Текстовый домен
● Подключение домена
– load_plugin_textdomain( 'my-plugin', false,
dirname( plugin_basename( __FILE__ ) ) . '/languages' );
– load_theme_textdomain( 'my-theme',
get_template_directory() . '/languages' );
● wp-content/languages (WordPress 4.6+)
Подготовка строк
● Обычные строки:
– __( 'Hello world!', 'my-plugin' );
– _e( 'Hello world!', 'my-plugin' );
● Строки с контекстом:
– _x( 'Hello world!', 'post title', 'my-plugin' );
– _ex( 'Hello world!', 'post title', 'my-plugin' );
Подготовка строк
● Множественные числа:
– _n( '%d item', '%d items', $count, 'my-plugin' );
– _nx( '%d item', '%d items', $count, 'comments', 'my-plugin' );
● Если число на момент вызова неизвестно:
– _n_noop( '%d item', '%d items', 'my-plugin' );
– _nx_noop('%d item', '%d items', 'comments', 'my-plugin' );
Подготовка строк
● Экранирование HTML-тегов:
– esc_html__( 'Hello <em>world</em>!', 'my-plugin' );
– esc_html_e( 'Hello <em>world</em>!', 'my-plugin' );
– esc_html_x( 'Hello <em>world</em>!', 'post title', 'my-plugin' );
● Экранирование HTML-атрибутов:
– esc_attr__( 'Hello "world"!', 'my-plugin' );
– esc_attr_e( 'Hello "world"!', 'my-plugin' );
– esc_attr_x( 'Hello "world"!', 'post title', 'my-plugin' );
Подготовка строк
● Экранирование HTML-тегов и атрибутов:
– <option value="<?php esc_attr_e( 'value', 'my-plugin' ); ?>">
<?php esc_html_e( 'Option label', 'my-plugin' ); ?>
</option>
● То же самое в более длинной записи:
– <option value="<?php echo esc_attr( __( 'value', 'my-plugin' ) ); ?>">
<?php echo esc_html( __( 'Option label', 'my-plugin' ) ); ?>
</option>
_e() ≠ echo()
● Не используйте переменные PHP, только простые строки:
– _e( $string ); — не надо так делать.
● Обеспечьте перевод целых фраз, а не отдельных слов:
– echo __( 'Hello' ) . ' ' . __( 'world!' ); — и так тоже.
● Не забывайте про текстовый домен:
– _e( 'Hello world!', 'my-plugin' );
● Не включайте в строки лишнюю HTML-разметку:
– _e( '<p>Hello world!</p>', 'my-plugin' );
Контекст и комментарии
● Контекст — разный перевод для одинаковых строк:
– _x( 'redirect', 'noun', 'my-plugin' );
– _x( 'redirect', 'verb', 'my-plugin' );
● Комментарии — пояснить значение переменной:
– /* translators: %s: file name */
__( '%s was deleted.', 'my-plugin' );
Множественные числа
● ???
– _e( "You have $count items.", 'my-plugin' );
– _e( 'You have ' . $count . ' items.', 'my-plugin' );
– printf( __( 'You have %d items.', 'my-plugin' ), $count );
– printf( _n( 'You have %d item.', 'You have %d items.', $count ),
$count );
Множественные числа
● Неправильно:
– _e( "You have $count items.", 'my-plugin' );
– _e( 'You have ' . $count . ' items.', 'my-plugin' );
– printf( __( 'You have %d items.', 'my-plugin' ), $count );
● Почти правильно:
– printf( _n( 'You have %d item.', 'You have %d items.', $count ),
$count );
Множественные числа
● Правильно:
– printf( _n( 'You have %d item.', 'You have %d items.', $count ),
number_format_i18n( $count ) );
● number_format_i18n() — для отображения чисел
● date_i18n() — для отображения даты
Множественные числа
● Если число неизвестно:
– $items_plural = _n_noop( 'You have %s item.', 'You have %s items',
'my-plugin' );
● ...
● А теперь известно:
– printf( translate_nooped_plural( $items_plural, $count ),
number_format_i18n( $count ) );
● translate_nooped_plural() — для отложенного перевода
множественных чисел
Множественные числа
● Первая форма не всегда используется для единственного числа:
– printf( _n( 'Theme deleted.', '%d themes deleted.', $count ),
number_format_i18n( $count ) );
● Лучше:
– if ( 1 === $count ) {
_e( 'Theme deleted.' );
– } else {
printf( _n( '%d theme deleted.', '%d themes deleted.', $count ),
number_format_i18n( $count ) );
– }
Файлы перевода
● .pot (Portable Object Template)
– Шаблон для перевода, содержит только английские строки.
● .po (Portable Object)
– Файл перевода в читаемом формате.
● .mo (Machine Object)
– Скомпилированный файл перевода в двоичном формате.
Файлы перевода
makepot.php→.pot→Poedit→.po/.mo→email
Список изменений
● Версия 1.5.6
– Добавлен перевод на шведский.
– Всё.
● Версия 1.5.6.1
– Исправлена опечатка в шведском переводе.
Файлы перевода
makepot.php→.pot→Poedit→.po/.mo→email
translate.wordpress.org
translate.wordpress.org
translate.wordpress.org
● GTE (General Translation Editor) — редакторы локали
– Могут проверять и одобрять все переводы.
● PTE (Project Translation Editor) — редакторы проектов
– Могут одобрять переводы конкретных проектов.
● Переводчики
– Могут предлагать переводы.
Если кто-то прислал перевод
● Попросите автора зарегистрироваться на WordPress.org
– Тогда его можно будет назначить редактором проекта.
– Он сам сможет импортировать свой файл .po.
– ...и в дальнейшем поддерживать перевод.
● Попросите редакторов локали импортировать файл
– Нет гарантии, что плагин будут продолжать активно переводить.
Если кто-то прислал перевод
● Когда автор зарегистрировался на WordPress.org
– Открываем блог сообщества переводчиков:
https://make.wordpress.org/polyglots/
– Находим ссылку на справочник переводчика:
https://make.wordpress.org/polyglots/handbook/
– На странице «Theme & Plugin Directories» находим шаблон
запроса для добавления редакторов проекта.
– Отправляем запрос в блог переводчиков и ждём ответа.
@SergeyBiryukov
Спасибо! Вопросы?

i18n for Plugin and Theme Developers, WordCamp Moscow 2016

  • 1.
  • 2.
    Сергей Бирюков ● WordPress-разработчикв Yoast yoast.com ● Локализатор WordPress в России ru.wordpress.org sergeybiryukov.com @SergeyBiryukov
  • 3.
    Плагины и темыдля всего мира ● Интернационализация (i18n) — возможность перевода ● Локализация (L10n) — перевод на конкретный язык
  • 4.
    Плагины и темыдля всего мира ● Более сотни языков ● Универсальный код ● Обратная связь ● Это просто
  • 5.
  • 6.
  • 7.
    Введение в gettext ●Текстовый домен – 'my-plugin' ● Подготовка строк – <?php echo 'Title'; ?> →<?php _e( 'Title', 'my-plugin' ); ?> ● Файлы перевода – .pot, .po, .mo
  • 8.
    Текстовый домен ● Долженсовпадать с именем папки плагина или темы: – wp-content/plugins/my-plugin →'my-plugin' – wp-content/themes/my-theme →'my-theme' ● Стоит добавить в заголовки плагина или темы: – Plugin Name: My Plugin – Version: 1.0 – Text Domain: my-plugin
  • 9.
    Текстовый домен ● Подключениедомена – load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); – load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
  • 10.
    Текстовый домен ● Подключениедомена – load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); – load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' ); ● wp-content/languages (WordPress 4.6+)
  • 11.
    Подготовка строк ● Обычныестроки: – __( 'Hello world!', 'my-plugin' ); – _e( 'Hello world!', 'my-plugin' ); ● Строки с контекстом: – _x( 'Hello world!', 'post title', 'my-plugin' ); – _ex( 'Hello world!', 'post title', 'my-plugin' );
  • 12.
    Подготовка строк ● Множественныечисла: – _n( '%d item', '%d items', $count, 'my-plugin' ); – _nx( '%d item', '%d items', $count, 'comments', 'my-plugin' ); ● Если число на момент вызова неизвестно: – _n_noop( '%d item', '%d items', 'my-plugin' ); – _nx_noop('%d item', '%d items', 'comments', 'my-plugin' );
  • 13.
    Подготовка строк ● ЭкранированиеHTML-тегов: – esc_html__( 'Hello <em>world</em>!', 'my-plugin' ); – esc_html_e( 'Hello <em>world</em>!', 'my-plugin' ); – esc_html_x( 'Hello <em>world</em>!', 'post title', 'my-plugin' ); ● Экранирование HTML-атрибутов: – esc_attr__( 'Hello "world"!', 'my-plugin' ); – esc_attr_e( 'Hello "world"!', 'my-plugin' ); – esc_attr_x( 'Hello "world"!', 'post title', 'my-plugin' );
  • 14.
    Подготовка строк ● ЭкранированиеHTML-тегов и атрибутов: – <option value="<?php esc_attr_e( 'value', 'my-plugin' ); ?>"> <?php esc_html_e( 'Option label', 'my-plugin' ); ?> </option> ● То же самое в более длинной записи: – <option value="<?php echo esc_attr( __( 'value', 'my-plugin' ) ); ?>"> <?php echo esc_html( __( 'Option label', 'my-plugin' ) ); ?> </option>
  • 15.
    _e() ≠ echo() ●Не используйте переменные PHP, только простые строки: – _e( $string ); — не надо так делать. ● Обеспечьте перевод целых фраз, а не отдельных слов: – echo __( 'Hello' ) . ' ' . __( 'world!' ); — и так тоже. ● Не забывайте про текстовый домен: – _e( 'Hello world!', 'my-plugin' ); ● Не включайте в строки лишнюю HTML-разметку: – _e( '<p>Hello world!</p>', 'my-plugin' );
  • 16.
    Контекст и комментарии ●Контекст — разный перевод для одинаковых строк: – _x( 'redirect', 'noun', 'my-plugin' ); – _x( 'redirect', 'verb', 'my-plugin' ); ● Комментарии — пояснить значение переменной: – /* translators: %s: file name */ __( '%s was deleted.', 'my-plugin' );
  • 17.
    Множественные числа ● ??? –_e( "You have $count items.", 'my-plugin' ); – _e( 'You have ' . $count . ' items.', 'my-plugin' ); – printf( __( 'You have %d items.', 'my-plugin' ), $count ); – printf( _n( 'You have %d item.', 'You have %d items.', $count ), $count );
  • 18.
    Множественные числа ● Неправильно: –_e( "You have $count items.", 'my-plugin' ); – _e( 'You have ' . $count . ' items.', 'my-plugin' ); – printf( __( 'You have %d items.', 'my-plugin' ), $count ); ● Почти правильно: – printf( _n( 'You have %d item.', 'You have %d items.', $count ), $count );
  • 19.
    Множественные числа ● Правильно: –printf( _n( 'You have %d item.', 'You have %d items.', $count ), number_format_i18n( $count ) ); ● number_format_i18n() — для отображения чисел ● date_i18n() — для отображения даты
  • 20.
    Множественные числа ● Есличисло неизвестно: – $items_plural = _n_noop( 'You have %s item.', 'You have %s items', 'my-plugin' ); ● ... ● А теперь известно: – printf( translate_nooped_plural( $items_plural, $count ), number_format_i18n( $count ) ); ● translate_nooped_plural() — для отложенного перевода множественных чисел
  • 21.
    Множественные числа ● Перваяформа не всегда используется для единственного числа: – printf( _n( 'Theme deleted.', '%d themes deleted.', $count ), number_format_i18n( $count ) ); ● Лучше: – if ( 1 === $count ) { _e( 'Theme deleted.' ); – } else { printf( _n( '%d theme deleted.', '%d themes deleted.', $count ), number_format_i18n( $count ) ); – }
  • 22.
    Файлы перевода ● .pot(Portable Object Template) – Шаблон для перевода, содержит только английские строки. ● .po (Portable Object) – Файл перевода в читаемом формате. ● .mo (Machine Object) – Скомпилированный файл перевода в двоичном формате.
  • 23.
  • 24.
    Список изменений ● Версия1.5.6 – Добавлен перевод на шведский. – Всё. ● Версия 1.5.6.1 – Исправлена опечатка в шведском переводе.
  • 25.
  • 26.
  • 27.
    translate.wordpress.org ● GTE (GeneralTranslation Editor) — редакторы локали – Могут проверять и одобрять все переводы. ● PTE (Project Translation Editor) — редакторы проектов – Могут одобрять переводы конкретных проектов. ● Переводчики – Могут предлагать переводы.
  • 28.
    Если кто-то прислалперевод ● Попросите автора зарегистрироваться на WordPress.org – Тогда его можно будет назначить редактором проекта. – Он сам сможет импортировать свой файл .po. – ...и в дальнейшем поддерживать перевод. ● Попросите редакторов локали импортировать файл – Нет гарантии, что плагин будут продолжать активно переводить.
  • 29.
    Если кто-то прислалперевод ● Когда автор зарегистрировался на WordPress.org – Открываем блог сообщества переводчиков: https://make.wordpress.org/polyglots/ – Находим ссылку на справочник переводчика: https://make.wordpress.org/polyglots/handbook/ – На странице «Theme & Plugin Directories» находим шаблон запроса для добавления редакторов проекта. – Отправляем запрос в блог переводчиков и ждём ответа.
  • 30.