Локализация текстовых сообщений

Задача
Необходимо отображать текстовые сообщения на языке, соответствующем установленной локали.

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

$messages = array ('en_US' =>
array(
'My favorite foods are' => 'My favorite foods are',
'french fries' => 'french fries',
'biscuit' => 'biscuit',
'candy' => 'candy',
'potato chips' => 'potato chips',
'cookie' => 'cookie',
'corn' => 'corn',
'eggplant' => 'eggplant'
),
'en_GB' =>
array(
'My favorite foods are' => 'My favourite foods are',
'french fries' => 'chips',
'biscuit' => 'scone',
'candy' => 'sweets',
'potato chips' => 'crisps',
'cookie' => 'biscuit',
'corn' => 'maize',
'eggplant' => 'aubergine'
)
);
function msg($s) {
global $LANG;
global $messages;
if (isset($messages[$LANG][$s])) {
return $messages[$LANG][$s];
} else {
error_log("l10n error: LANG: $lang, message: '$s'");
}
}

Обсуждение
В следующей короткой программе каталог сообщений нужен для распечатки списка продуктов питания:

$LANG = 'en_GB';
print msg('My favorite foods are').":\n";
print msg('french fries')."\n";
print msg('potato chips')."\n";
print msg('corn')."\n";
print msg('candy')."\n";
My favourite foods are:
chips
crisps
maize
sweets

Чтобы программа печатала не на британском английском, а на американском, просто присвойте переменной $LANG значение en_US.

Можно объединить функцию msg(), извлекающую сообщения, с функцией sprintf() и сохранять фразы, в которых требуется заменять значения.


Рассмотрим английскую фразу «I am 12 years old». Или в переводе на испанский: «Tengo 12 an ~ os». Испанская фраза не может быть построена соединением перевода слов «I am», числа 12 и слов «years old». Эти строки надо сохранить в каталоге сообщений как строки формата в стиле функции sprintf():

$messages = array ('en_US' => array('I am X years old.' =>
'I am %d years old.'),'es_US' => array('I am X years old.' => 'Tengo %d an~os.')
);

Затем можно передать результаты функции msg() функции sprintf() в качестве строки формата:

$LANG = 'es_US';
print sprintf(msg('I am X years old.'),12);
Tengo 12 an~os.

Для фраз, в которых заменяемые значения на другом языке надо вставить в другом порядке, функция sprintf() поддерживает изменение порядка аргументов:

$messages = array ('en_US' =>
array('I am X years and Y months old.' =>
'I am %d years and %d months old.'),
'es_US' =>
array('I am X years and Y months old.' =>
'Tengo %2$d meses y %1$d an~os.')
);

Для любого языка функция sprintf() вызывается с тем же самым порядком аргументов (т. е первый аргумент – это годы, а второй – месяцы):

$LANG = 'es_US';
print sprintf(msg('I am X years and Y months old.'),12,7);
Tengo 7 meses y 12 an~os.

В строке формата значение %2$ указывает функции sprintf() принять второй аргумент, а значение %1$ – первый аргумент.

Эти фразы можно также хранить как возвращаемое функцией значение, вместо того чтобы помещать их в массив в виде строки.


Хранение фраз как возвращаемое функцией значение устраняет необходимость в вызове функции sprintf(). Функции, возвращающие предложения, выглядят так:

// Английская версия
function i_am_X_years_old($age) {
return "I am $age years old.";
}
// Испанская версия
function i_am_X_years_old($age) {
return "Tengo $age an~os.";
}

Если какие-то части сообщения относятся к массиву, а какие-то - к функциям, то удобным контейнером для каталога языковых сообщений является объект. Ниже показано, как могут выглядеть базовый объект и два простых каталога сообщений:

class pc_MC_Base {
var $messages;var $lang;
function msg($s) {
if (isset($this->messages[$s])) {
return $this->messages[$s];
} else {
error_log("l10n error: LANG: $this->lang, message: '$s'");
}
}
}
class pc_MC_es_US extends pc_MC_Base {
function pc_MC_es_US() {
$this->lang = 'es_US';
$this->messages = array ('chicken' => 'pollo',
'cow' => 'vaca',
'horse' => 'caballo'
);
}
function i_am_X_years_old($age) {
return "Tengo $age an~os";
}
}
class pc_MC_en_US extends pc_MC_Base {
function pc_MC_en_US() {
$this->lang = 'en_US';
$this->messages = array ('chicken' => 'chicken',
'cow' => 'cow',
'horse' => 'horse'
);
}
function i_am_X_years_old($age) {
return "I am $age years old.";
}
}

Каждый объект каталога сообщений наследует класс pc_MC_Base, чтобы получить метод msg(), а затем определяет свои собственные сообщения (в своем конструкторе) и свои собственные функции, возвращающие фразы.


Покажем, как напечатать текст на испанском языке:

$MC = new pc_MC_es_US;
print $MC->msg('cow');
print $MC->i_am_X_years_old(15);

Чтобы напечатать тот же самый текст на английском языке, необходимо реализовать переменную $MC как объект pc_MC_en_US, вместо объекта pc_MC_es_US. Остальной код остается неизменным.

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела PHP на эту тему:
Использование определенной локали
Локализация включаемых файлов
Локализация дат и времени
Локализация денежных значений
Локализация изображений