WordPress как на ладони
Очень Удобный и Быстрый Хостинг для сайтов на WordPress. Пользуюсь сам и вам рекомендую!

Переводы в JS файлах

Локализация в PHP файлах давно уже обыденное дело для WordPress, однако перевод в JS файлах, который был реализован через функцию wp_localize_script() оставлял желать более динамичного и удобного подхода. С версии WordPress 5.0 такая возможность появилась, теперь можно также удобно как и в PHP использовать функции локализации: __(), _x() прямо в JS файлах.

Как это работает

Нужно «сказать» WP, что у вашего скрипта есть перевод, и какой текстовый домен (ID) нужно использовать для этого перевода. Делается это функцией wp_set_script_translations().

Таким образом регистрация вашего скрипта с переводом должна выглядеть так:

wp_register_script( 'my-handle', plugins_url( '/js/my-file.js', __FILE__ ) );
wp_set_script_translations( 'my-handle', 'my-domain' );

Функция wp_set_script_translations() добавляет зависимость основного скрипта от wp-i18n и подключает .json файл.

Обязательно ознакомьтесь с описанием функции wp_set_script_translations().

Теперь в JS коде нужно использовать объект wp-18n следующим образом:

const { __, _x, _n, _nx } = wp.i18n;

__( 'Hello', 'myl10n' );
_x( 'Hi', 'short word', 'myl10n' );
_n( '%s star', '%s stars', 5, 'myl10n' );
_nx( '%s star', '%s stars', 5, 'superstars', 'myl10n' );
sprintf( __( 'See Link: %s', 'myl10n' ), 'http://site.com' );

Используемые функции перевода полностью схожи с одноименными функциями PHP и используются точно так же. См. __(), _n(), _x(), _nx().

Настройка перевода для JS файлов готова!

Остается только создать .json файлы переводов из которых будут браться переводы строк. Как это делать читайте ниже.

Заметки:
  • Отсутствие функций esc_html(), esc_html__() и т.д. в JS объясняется тем, что они не нужны в JavaScript, потому что браузер сам умеет экранировать небезопасные символы.

  • Контент JSON файла перевода выводится прямо в HTML страницу в виде js кода, прямо перед скриптом для которого подключается перевод.

  • Хоть и не рекомендуется использовать HTML в переводимых строках, иногда это необходимо, например, для добавления ссылок: Check <a href="%s">my website</a>.. Сейчас это не так просто сделать не используя innerHTML (который может быть опасен). Эта ситуация обсуждается на GitHub.

  • Если регистрируются несколько скриптов для которых нужны переводы, то переводы нужно подключать для каждого скрипта отдельно (у каждого должен быть свой JSON файл перевода):

    wp_register_script( 'my-plugin-script', plugins_url( 'js/my-script.js', __FILE__ ), [ 'wp-i18n' ], '0.0.1' );
    wp_set_script_translations( 'my-plugin-script', 'my-plugin' );
    
    wp_register_script( 'my-awesome-block', plugins_url( 'js/my-block.js', __FILE__ ), [ 'wp-i18n' ], '0.0.1' );
    wp_set_script_translations( 'my-awesome-block', 'my-plugin' );

    Такой подход нужен для оптимизации: в HTML добавляются только строки перевода используемые в подключаемом скрипте - ничего лишнего.

Как создать JSON файл перевода

Вариант 1: Создание c помощью wp-cli (рекомендую)

Первое что нужно для этого способа - это иметь уже готовый PO файл, в котором кроме переводов для php файлов также есть переводы и для js файлов. Обычно, для того чтобы в базовый PO файл попали переводы из js файлов ничего отдельно делать не нужно, все делается как обычно, а в JS файлах используются функции __(), _x(), которые автоматически подхватываются программой Poedit или другим парсером, например, плагином Loco Translate.

Давайте представим, что в нашем плагине есть папка languages и в ней находятся несколько PO файлов с переводами для разных языков, в которых, среди прочих, есть строки из JS файлов.

Тогда, создать .json файлы из имеющихся .po файлов можно командой wp i18n make-json.

wp i18n make-json languages --no-purge
  • languages — это путь относительно вашей темы/плагина до папки в которой лежат .po файлы. .json файлы при этом появится в той же папке. Если нужно чтобы .json файлы создавались в другом месте, то укажите путь во втором параметре команды.
  • --no-purge — флаг, который просит не удалять строки перевода из PO файла. По умолчанию они удаляются (не понял зачем это нужно по умолчанию).
Как создается md5 хэш

При создании .json файла таким способом, он получит имя следующего формата: {domain}-{locale}-{md5}.json, где md5 хэш будет создан из пути к файлу взятого из PO файла.

Например, в PO файле строка перевода выглядит так:

#: scripts.js:9
msgid "Hello"
msgstr "Привет"

Тогда md5 будет создан из строки: md5('scripts.js'). Этот вариант создания хэша совпадает с тем, который используется стандартно в WP при использовании функции подключения json файла wp_set_script_translations().

Несколько json файлов: если в PO файле есть переводы для нескольких .js файлов, то будет создано несколько .json файлов для каждого из них.

Нет лишних строк: в создаваемый json файл попадут строки только относящиеся к конкретному js файлу.

Вариант 2: Конвертируем с помощью gulp

Шаг 1. Создаем .po файл

В нём будут находится строки из JS файла и их перевод. О том как создавать PO файлы я писал в статье про переводы. Тут делается все также, только для поиска строк перевода нужно указать наш js файл.

Рассмотрим на примере. Пусть нам нужно создать .po файл для JS файла scripts.js, который лежит в корне темы.

Создаем в теме файл /languages/js/myl10n-ru_RU-my-script.po и добавляем в него следующий код (для понятности, название файла делаем аналогичное будущему файлу json):

msgid ""
msgstr ""
"Project-Id-Version: my-plugin-name\n"
"POT-Creation-Date: 2020-04-28 12:17+0500\n"
"PO-Revision-Date: \n"
"Last-Translator: Kama <foo@bk.ru>\n"
"Language-Team: WP Kama\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-KeywordsList: __;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;"
"_nx_noop:1,2,3c;esc_attr__;esc_attr_e;esc_html__;esc_html_e\n"
"X-Generator: Poedit 2.3\n"
"X-Poedit-Basepath: ../..\n"
"X-Poedit-SearchPath-0: scripts.js\n"
"X-Poedit-SearchPathExcluded-0: node_modules\n"

Обратите внимание на строки:

  • "X-Poedit-Basepath: ../..\n" — тут нужно указать путь от PO файла до папки темы. Так как у нас файл лежит в двух папках /languages/js поднимаемся на две папки.
  • "X-Poedit-SearchPath-0: scripts.js\n" — тут нужно указать путь до файла js, относительно папки темы (базового пути, Basepath). Так как у нас файл лежит прямо в теме, просто указываем тут имя файла.

Теперь открываем программу Poedit, закидываем туда наш PO файл, жмем кнопку «Обновить из кода», переводим полученные строки и жмем «сохранить».

PO файл готов!

Шаг 2. Конвертируем .po файл в .json

Обратите внимание, что в json файле появятся все строки из PO файла (не только js).

Для этого нам понадобятся библиотеки po2json и jed, потому что конвертировать нужно в jed формат. Устанавливаем их в проект командами:

npm install -D po2json
npm install -D jed

В gulpfile.js добавляем такой код:

let po2json = require('po2json'),
	Jed     = require('jed'),
	Write   = require('write');

gulp.task( 'po2json', async ()=>{

	// путь до PO файла
	let PO_file = 'languages/js/myl10n-ru_RU-my-script.po'

	po2json.parseFile( PO_file, { format:'jed' }, ( err, jsonData )=>{

		let i18n = new Jed( jsonData )
		let JSON_file = PO_file.replace( '.po', '.json' )

		Write.sync( JSON_file, JSON.stringify( i18n, null, 2 ), { newline: true } )
	})

} )

В этом коде вам нужно изменить название создаваемого json файла чтобы он подходил под ваш случай.

Теперь, создаем json файл такой командой:

gulp po2json

В результате рядом с .po файлом должен появится .json файл.

Процедуру создания JSON файла, можно повесить на watcher, чтобы при изменении PO файла, автоматически менялся JSON файл.

Вариант 3: Публикация плагина/темы в каталог WordPress

В этом случае все делается автоматически: все JS-файлы будут автоматически проанализированы так же, как это уже делается с PHP-файлами. Все обнаруженные переводы будут добавлены в translate.wordpress.org, чтобы позволить сообществу сделать переводы для них.

Таким образом .json файлы переводов создаются автоматом. Нужно только указать параметры Text Domain: и Domain Path: — домен перевода и путь до папки переводов в заголовках плагина, а затем перевести полученные строки на сайте GlotPress (translate.wordpress.org).

Для парсинга строк перевода для JS на GlotPress используются WP-CLI команды i18n. Этот вариант более стабильный по сравнению с makepot.php.

Имя JSON файла перевода

Рассмотрим какое имя должен иметь JSON файл перевода, чтобы функция wp_set_script_translations() нашла соотвествующий файл при попытке его подключить.

Тут есть два варианта, когда указан третий параметр функции $path и когда нет:

  • НЕ указан третий параметр $path:

    /wp-content/languages/themes/{domain}-{locale}-{md5}.json  // plugin-ru_RU-db8f629adc6c4c33f29613cfb71a6038.json
  • Указан третий параметр $path:
    УКАЗАННЫЙ_ПУТЬ/{domain}-{locale}-{handle}.json             // plugin-ru_RU-script.json
    УКАЗАННЫЙ_ПУТЬ/{domain}-{locale}-{md5}.json                // plugin-ru_RU-db8f629adc6c4c33f29613cfb71a6038.json
    /wp-content/languages/themes/{domain}-{locale}-{md5}.json  // plugin-ru_RU-db8f629adc6c4c33f29613cfb71a6038.json

MD5 хэш в имени формируется из пути к файлу относительно папки плагина/темы. Подробнее смотрите здесь.

Хуки

WordPress предоставляет фильтры, такие как load_textdomain и gettext, позволяющие переопределять путь к файлам перевода или отдельным переводам.

В WordPress 5.0.2 были добавлены следующие фильтры, позволяющие фильтровать поведение wp_set_script_translations(), чтобы можно было сделать то же самое для переводов JavaScript. Доступны следующие фильтры:

  • pre_load_script_translations — срабатывает в начале функции и позволяет полностью переопределить работу функции load_script_translations().
  • load_script_translation_file — позволяет изменить путь к файлу переводов для конкретного скрипта.
  • load_script_translations — позволяет изменить полученный код JSON файла.
4 комментария
    Войти