__(): Что делать, если нужно передать переменную?
В документации для функции перевода __( $text, $domain )
указано, что нужно помещать строку непосредственно вместо $text, и нельзя делать что-то хитрое вроде __( $my_text, 'text-domain' );
.
Однако я пишу метод, который принимает строку и должен как-то передать её в __(
... )
. Есть ли способ обойти это, например, с помощью printf
или sprintf
?
Что-то вроде...
function print_description( $text ) {
echo '<p>' . __( printf( '%s', $text ), 'text-domain' ) . '</p>';
}
Для перевода строк в WordPress, как и в большинстве CMS, использующих PHP, необходимо обернуть строку в функцию перевода GetText (например, __(), _e(), _n(), _x() и т.д.).
Строка также должна быть включена в PO-файл (GetText Portable Object files, стандарт индустрии для многоязычных сайтов на PHP — https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). Этот файл содержит пары строк: одна строка на исходном языке, а другая — её перевод на целевой язык.
Для создания этих PO-файлов для каждого языка (например, my-text-domain-es_ES.po для испанского, my-text-domain-fr_FR.po для французского и т.д.), в которые нужно перевести плагин или тему, переводчик использует POT-файл (PO-шаблон), содержащий все строки для перевода на исходном языке, и добавляет перевод для каждой из них. PO-файлы компилируются в двоичные MO-файлы, которые обрабатываются гораздо быстрее.
Во время выполнения строки для перевода извлекаются через MO-файлы и заменяются их переводом.
POT-файлы обычно генерируются с помощью специальных инструментов, которые анализируют исходные файлы кода и извлекают переводимые строки.
Если мы напишем код так:
$translated_text = __( $text, 'my_text_domain');
Когда код анализируется специальными инструментами, значение строки для перевода ($text) ещё не определено и поэтому отсутствует в коде. В результате автоматические инструменты поиска не включат эту строку в POT-файл, и она не попадёт в PO- и MO-файлы.
Во время выполнения, когда значение строки $text, предположительно, уже будет определено, не будет соответствия для этого значения в файлах перевода, и перевод будет невозможен.
Однако, если набор возможных значений для этой переменной ограничен и мы их знаем, у нас есть два варианта решения этой проблемы:
Вариант 1: Вручную отредактировать POT-файл, добавив записи с возможными значениями $text. Этот вариант прост и легко реализуем. Любой текстовый редактор и минимальные знания формата POT будут достаточны. Но у него есть один недостаток: каждый раз, когда мы используем автоматические инструменты поиска для обновления переводов после изменения нашего кода, внесённые нами правки будут потеряны, и нам придётся добавлять их снова вручную.
Вариант 2: Включить в наш код все возможные значения $text, обёрнутые функциями перевода. Рассмотрим пример. Предположим, что $text может принимать значения: apple, orange, banana, peach и pear. Нам нужно написать следующий код:
// эта переменная используется только для включения в качестве параметров в
// функции перевода всех возможных значений $text
$locale = __('apple', 'my_text_domain') .
__('orange', 'my_text_domain') .
__('banana', 'my_text_domain') .
__('peach', 'my_text_domain') .
__('pear', 'my_text_domain');
$translated_text = __( $text, 'my_text_domain');
Этот вариант также легко реализовать, и у него есть преимущество: он не будет потерян при использовании автоматических инструментов поиска для обновления переводов.
Если в нашей теме или плагине есть несколько переменных, которые мы хотим перевести, и у них ограниченный набор известных возможных значений, мы можем включить их все в отдельный файл, который должен находиться в корневой папке или подпапке (например, папки 'includes' или 'assets') темы или плагина, как показано ниже:
<?php
//значения переменных для перевода
$locale_var1 = __('text-of-var1_val1', 'my_text_domain') .
__('text-of-var1_val2', 'my_text_domain') .
__('text-of-var1_val3', 'my_text_domain') .
.......
__('text-of-var1_valn', 'my_text_domain');
$locale_var2 = __('text-of-var2_val1', 'my_text_domain') .
__('text-of-var2_val2', 'my_text_domain') .
.......
__('text-of-var2_valn', 'my_text_domain');
.............
$locale_varn = __('text-of-varn_val1', 'my_text_domain') .
__('text-of-varn_val2', 'my_text_domain') .
.......
__('text-of-varn_valn', 'my_text_domain');
Это чистый и удобный для поддержки подход, который сохраняет определение этих строк в отдельном файле, который можно изменять, не затрагивая другие файлы кода.

Нет
Инструменты, помогающие в генерации перевода, не могут проанализировать ваш код и определить, какие строки требуют перевода, когда строки, передаваемые в функции перевода, полностью динамические.
В вашем примере правильный способ написать эту функцию:
function print_description( $text ) {
echo '<p>' . $text . '</p>';
}
И вызывать её так:
print_description(__('конкретное описание','text_domain'));

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

По какой-то причине у меня работает передача переменных в _e():
$string = 'ciao';
_e($string, 'textdomain'); // укажите свой textdomain..
// выведет 'ciao' или 'hello', в зависимости от текущего языка
Очевидно, вам нужно сначала создать свой textdomain, желательно в yourtheme/functions.php:
add_action( 'after_setup_theme', 'theme_setup' );
function theme_setup() {
load_theme_textdomain( 'yourtextdomain', TEMPLATEPATH . '/languages' );
// [...] другой код инициализации
}
Если я переведу слово 'ciao' в .po файле, оно будет корректно переведено во фронтенде. Используйте Poedit или аналоги для компиляции .mo. Оба файла .po и .mo должны быть размещены в /wp-content/yourtheme/languages (согласно коду выше).
#. Тестовый en_EN.po
msgid "ciao"
msgstr "hello"
Не уверен, почему это работает, но это действительно так - выводит 'ciao' на итальянском и 'hello' на английском.

Это работает только потому, что вы вручную добавляете перевод. Если вы используете инструмент, который ищет строки для перевода в вашем коде, он не сможет найти правильную строку.

Да, конечно, но я думаю, что это не проблема исходного вопроса

Как я упомянул здесь http://www.westofwonder.com/2013/12/whats-with-all-the-double-underscores-everywhere/ (прошу прощения за тему, я внес улучшения, просто еще не опубликовал их), одним из возможных решений этой проблемы является создание функции для текста:
function yourtheme_thisisthetext() {
return __( 'Это текст.', 'yourthemetextdomain' );
}
Само по себе это некрасиво, но для длинной или часто используемой строки перевода компромисс может быть оправдан ради читаемости кода.
(Разрешено ли так делать? Ссылаться на свой блог в прямом ответе на вопрос? Если нет, приношу извинения и больше не буду.)
