Если вы спрашиваете: «Что такое Yii?» Посмотрите мой предыдущий учебник: Введение в Yii Framework , который рассматривает преимущества Yii и включает обзор того, что нового в Yii 2.0, выпущенном 12 октября 2014 года.
В этой серии «Программирование с Yii2» я расскажу читателям, как использовать обновленную версию Yii2 Framework для PHP. В первой части мы настроили Yii2 локально, создали приложение Hello World, настроили удаленный сервер и использовали Github для развертывания нашего кода. Во второй части мы узнали о реализации Yii его архитектуры Model View Controller и о том, как создавать веб-страницы и формы, которые собирают и проверяют данные. В третьей части мы использовали базу данных Yii и возможности активной записи для автоматизации генерации кода для базового веб-приложения. И в четвертой части мы узнали, как интегрировать регистрацию пользователей.
В этом руководстве я собираюсь показать вам, как использовать встроенную поддержку Y18n интернационализации Yiin, чтобы подготовить ваше приложение к переводу на несколько языков.
Для этих примеров мы продолжим предполагать, что мы создаем структуру для публикации простых обновлений статуса, например, наш собственный мини-Twitter.
Что я
Согласно Википедии , I18n является нумеронимом интернационализации:
18 обозначает число букв между первым i и последним n в интернационализации , использование, придуманное в DEC в 1970-х или 80-х.
С I18n все текстовые строки, отображаемые пользователю из приложения, заменяются вызовами функций, которые могут динамически загружать переведенные строки для любого языка, выбранного пользователем.
Цели интернационализации
При создании веб-приложения полезно мыслить глобально с самого начала. Должно ли ваше приложение работать на других языках для пользователей из разных стран? Если это так, то внедрение I18n с самого начала сэкономит вам много времени и головной боли позже.
В нашем случае Yii Framework предоставляет встроенную поддержку I18n, поэтому относительно легко встроить поддержку I18n по мере продвижения.
Как работает I18n
I18n работает, заменяя все ссылки на текст, отображаемый пользователю вызовами функций, которые обеспечивают перевод при необходимости.
Например, вот как выглядят имена полей атрибутов в модели состояния до I18n:
1
2
3
4
5
6
7
8
9
|
public function attributeLabels()
{
return [
‘id’ => ‘ID’,
‘message’ => ‘Message’,
‘permissions’ => ‘Permissions’,
‘created_at’ => ‘Created At’,
‘updated_at’ => ‘Updated At’, ];
}
|
Предоставление переведенных версий кода станет очень сложным. Нетехнические переводчики должны будут переводить код на месте, вероятно, нарушая синтаксис.
Вот как выглядит тот же код с I18n:
1
2
3
4
5
6
7
8
9
|
public function attributeLabels()
{
return [
‘id’ => Yii::t(‘app’, ‘ID’),
‘message’ => Yii::t(‘app’, ‘Message’),
‘permissions’ => Yii::t(‘app’, ‘Permissions’),
‘created_at’ => Yii::t(‘app’, ‘Created At’),
‘updated_at’ => Yii::t(‘app’, ‘Updated At’), ];
}
|
Yii:t()
— это вызов функции, который проверяет, какой язык выбран в данный момент, и отображает соответствующую переведенную строку. Параметр 'app'
относится к разделу нашего приложения. При желании переводы могут быть организованы в соответствии с различными категориями. Но где эти переведенные строки появляются?
Язык по умолчанию, в данном случае английский, записывается в код, как показано выше. Файлы языковых ресурсов — это списки массивов строк, ключом которых является текст языка по умолчанию, например, 'Message'
или 'Permissions'
— и каждый файл предоставляет переведенные текстовые значения для соответствующего языка.
Вот пример нашего полного файла перевода на испанский язык с кодом «es». Функция Yii:t()
использует этот файл, чтобы найти соответствующий перевод для отображения:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
<?php
/**
* Message translations.
*
* This file is automatically generated by ‘yii translate’ command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of ‘@@’ marks.
*
* Message string can be used with plural forms format.
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
‘Get started with Yii’ => ‘Comience con Yii’,
‘Heading’ => ‘título’,
‘My Yii Application’ => ‘Mi aplicación Yii’,
‘Yii Documentation’ => ‘Yii Documentación’,
‘Yii Extensions’ => ‘Extensiones Yii’,
‘Yii Forum’ => ‘Yii Foro’,
‘Are you sure you want to delete this item?’
‘Congratulations!’
‘Create’ => ‘crear’,
‘Create {modelClass}’ => ‘crear {modelClass}’,
‘Created At’ => ‘Creado el’,
‘Delete’ => ‘borrar’,
‘ID’ => ‘identificación’,
‘Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
‘Message’ => ‘mensaje’,
‘Permissions’ => ‘Permisos’,
‘Reset’ => ‘reajustar’,
‘Search’ => ‘búsqueda’,
‘Statuses’ => ‘Los estados’,
‘Update’ => ‘actualización’,
‘Update {modelClass}: ‘ => ‘actualización {modelClass} :’,
‘Updated At’ => ‘Actualizado A’,
‘You have successfully created your Yii-powered application.’
];
|
Хотя это выглядит трудоемким, Yii предоставляет сценарии для автоматизации создания и организации этих шаблонов файлов.
Отделяя текст от кода, мы облегчаем для нетехнических многоязычных экспертов перевод наших приложений для нас — без нарушения кода.
I18n также предлагает специализированные функции для перевода времени, валюты, множественного числа и др. Я не буду вдаваться в детали этого в этом уроке.
Настройка поддержки I18n
К сожалению, документация по Yii2 для I18n еще не очень описательна, и было трудно найти рабочие, пошаговые примеры. К счастью для вас, я проведу вас через то, что я узнал, изучая документы и сеть. Я нашел пример Code Ninja I18n и Yii2 Definitive Guide on I18n полезным, и участник Yii Александр Макаров также предложил мне некоторую помощь.
Создание файла конфигурации I18n
Мы используем базовый шаблон приложения Yii2 для демонстрационного приложения. Это помещает нашу кодовую базу ниже корневого каталога /hello
. Конфигурационные файлы Yii в /hello/config/*
загружаются при каждом запросе страницы. Мы будем использовать сценарии сообщений Yiin I18n для создания файла конфигурации для I18n в common/config
пути common/config
.
Из нашего корня кодовой базы мы запустим скрипт Yii message/config
:
1
|
./yii message/config @app/config/i18n.php
|
Это создает следующий шаблон файла, который мы можем настроить:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
<?php
return [
// string, required, root directory of all source files
‘sourcePath’ => __DIR__,
// array, required, list of language codes that the extracted messages
// should be translated to.
‘languages’ => [‘de’],
// string, the name of the function for translating messages.
// Defaults to ‘Yii::t’.
// translated.
// multiple function names.
‘translator’ => ‘Yii::t’,
// boolean, whether to sort messages by keys when merging new messages
// with the existing ones.
// messages will be separated from the old (translated) ones.
‘sort’ => false,
// boolean, whether to remove messages that no longer appear in the source code.
// Defaults to false, which means each of these messages will be enclosed with a pair of ‘@@’ marks.
‘removeUnused’ => false,
// array, list of patterns that specify which files/directories should NOT be processed.
// If empty or not set, all files/directories will be processed.
// A path matches a pattern if it contains the pattern string at its end.
// ‘/a/b’ will match all files and directories ending with ‘/a/b’;
// the ‘*.svn’ will match all files and directories whose name ends with ‘.svn’.
// and the ‘.svn’ will match all files and directories named exactly ‘.svn’.
// Note, the ‘/’ characters in a pattern matches both ‘/’ and ‘\’.
// See helpers/FileHelper::findFiles() description for more details on pattern matching rules.
‘only’ => [‘*.php’],
// array, list of patterns that specify which files (not directories) should be processed.
// If empty or not set, all files will be processed.
// Please refer to «except» for details about the patterns.
// If a file/directory matches both a pattern in «only» and «except», it will NOT be processed.
‘except’ => [
‘.svn’,
‘.git’,
‘.gitignore’,
‘.gitkeep’,
‘.hgignore’,
‘.hgkeep’,
‘/messages’,
],
// ‘php’ output format is for saving messages to php files.
‘format’ => ‘php’,
// Root directory containing message translations.
‘messagePath’ => __DIR__ .
// boolean, whether the message file should be overwritten with the merged messages
‘overwrite’ => true,
/*
// ‘db’ output format is for saving messages to database.
‘format’ => ‘db’,
// Connection component to use.
‘db’ => ‘db’,
// Custom source message table.
// ‘sourceMessageTable’ => ‘{{%source_message}}’,
// Custom name for translation message table.
// ‘messageTable’ => ‘{{%message}}’,
*/
/*
// ‘po’ output format is for saving messages to gettext po files.
‘format’ => ‘po’,
// Root directory containing message translations.
‘messagePath’ => __DIR__ .
// Name of the file that will be used for translations.
‘catalog’ => ‘messages’,
// boolean, whether the message file should be overwritten with the merged messages
‘overwrite’ => true,
*/
];
|
Я настраиваю файл следующим образом. Я перемещаю messagePath
вверх и настраиваю sourcePath
и messagePath
. Я также указываю языки, которые я хочу, чтобы моя заявка поддерживала помимо английского, в данном случае это испанский (и), немецкий (де), итальянский (ит) и японский (я). Вот список всех кодов языка I18n .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<?php
return [
// string, required, root directory of all source files
‘sourcePath’ => __DIR__.
// Root directory containing message translations.
‘messagePath’ => __DIR__ .
// array, required, list of language codes that the extracted messages
// should be translated to.
‘languages’ => [‘de’,’es’,’it’,’ja’],
// string, the name of the function for translating messages.
// Defaults to ‘Yii::t’.
// translated.
// multiple function names.
‘translator’ => ‘Yii::t’,
|
На следующем шаге мы запустим скрипт извлечения Yii, который будет сканировать весь код в дереве sourcePath
чтобы сгенерировать строковые файлы по умолчанию для всех меток, используемых в нашем коде. Я настраиваю sourcePath
для сканирования всего дерева кода. Я настраиваю messagePath
для генерации результирующих файлов в common/messages
.
1
|
./yii message/extract @app/config/i18n.php
|
Вы увидите, как Yii сканирует все ваши файлы кода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Extracting messages from /Users/Jeff/Sites/hello/views/layouts/main.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/about.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/contact.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/error.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/index.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/login.php…
Extracting messages from /Users/Jeff/Sites/hello/views/site/say.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/_form.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/_search.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/create.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/index.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/update.php…
Extracting messages from /Users/Jeff/Sites/hello/views/status/view.php…
Extracting messages from /Users/Jeff/Sites/hello/web/index-test.php…
Extracting messages from /Users/Jeff/Sites/hello/web/index.php…
|
Когда он завершится, вы увидите что-то вроде этого в вашей кодовой базе:
Активация I18n и выбор языка
В общем файле конфигурации, /hello/config/web.php
, мы расскажем Yii о нашей новой языковой поддержке. Я сделаю испанский своим языком по умолчанию:
01
02
03
04
05
06
07
08
09
10
|
<?php
$params = require(__DIR__ . ‘/params.php’);
$config = [
‘id’ => ‘basic’,
‘basePath’ => dirname(__DIR__),
‘bootstrap’ => [‘log’],
‘language’=>’es’, // spanish
‘components’ => [
|
Но это еще не все. Мы должны сделать наш код I18n осведомленным.
Использование генератора кода Gii от Yii с I18n
В третьей части этой серии мы использовали базу данных Yii и возможности активной записи для автоматизации генерации кода. Но мы не активировали I18n, поэтому во весь наш код были встроены текстовые строки. Давайте переделаем это.
Мы возвращаемся к Gii, вероятно, http: // localhost: 8888 / hello / gii в вашем браузере, и перезапускаем модель и генераторы контроллера с активированным I18n.
Вот пример генерации кода модели Meeting с активированным I18n. Обратите внимание, что мы указываем «приложение» для нашей категории сообщений. Мы помещаем все наши текстовые строки в один файл категории приложения.
Давайте сделаем то же самое для генерации CRUD для контроллеров и представлений:
Если вы просматриваете сгенерированный код в моделях, контроллерах и представлениях, вы увидите текстовые строки, замененные функцией Yii:t('app',...)
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
<?php
use yii\helpers\Html;
use yii\grid\GridView;
/* @var $this yii\web\View */
/* @var $searchModel app\models\StatusSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */
$this->title = Yii::t(‘app’, ‘Statuses’);
$this->params[‘breadcrumbs’][] = $this->title;
?>
<div class=»status-index»>
<h1><?= Html::encode($this->title) ?></h1>
<?php // echo $this->render(‘_search’, [‘model’ => $searchModel]);
<p>
<?= Html::a(Yii::t(‘app’, ‘Create {modelClass}’, [
‘modelClass’ => ‘Status’,
]), [‘create’], [‘class’ => ‘btn btn-success’]) ?>
</p>
<?= GridView::widget([
‘dataProvider’ => $dataProvider,
‘filterModel’ => $searchModel,
‘columns’ => [
[‘class’ => ‘yii\grid\SerialColumn’],
‘id’,
‘message:ntext’,
‘permissions’,
‘created_at’,
‘updated_at’,
[‘class’ => ‘yii\grid\ActionColumn’],
],
]);
</div>
|
Создание статических видов I18n готов
Поскольку мы генерируем несколько представлений в нашем приложении вручную или в HTML, нам необходимо вручную преобразовать их для использования I18n. Например, нашу панель навигации в /views/layouts/main.php
и нашу домашнюю страницу в /views/site/index.php
необходимо редактировать вручную.
Вот панель навигации до I18n:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
NavBar::begin([
‘brandLabel’ => ‘My Company’,
‘brandUrl’ => Yii::$app->homeUrl,
‘options’ => [
‘class’ => ‘navbar-inverse navbar-fixed-top’,
],
]);
$navItems=[
[‘label’ => ‘Home’, ‘url’ => [‘/site/index’]],
[‘label’ => ‘Status’, ‘url’ => [‘/status/index’]],
[‘label’ => ‘About’, ‘url’ => [‘/site/about’]],
[‘label’ => ‘Contact’, ‘url’ => [‘/site/contact’]]
];
if (Yii::$app->user->isGuest) {
array_push($navItems,[‘label’ => ‘Sign In’, ‘url’ => [‘/user/login’]],[‘label’ => ‘Sign Up’, ‘url’ => [‘/user/register’]]);
} else {
array_push($navItems,[‘label’ => ‘Logout (‘ . Yii::$app->user->identity->username . ‘)’,
‘url’ => [‘/site/logout’],
‘linkOptions’ => [‘data-method’ => ‘post’]]
);
}
echo Nav::widget([
‘options’ => [‘class’ => ‘navbar-nav navbar-right’],
‘items’ => $navItems,
]);
NavBar::end();
|
Вот панель навигации после I18n:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
NavBar::begin([
‘brandLabel’ => Yii::t(‘app’, ‘My Company’),
‘brandUrl’ => Yii::$app->homeUrl,
‘options’ => [
‘class’ => ‘navbar-inverse navbar-fixed-top’,
],
]);
$navItems=[
[‘label’ => Yii::t(‘app’, ‘Home’), ‘url’ => [‘/site/index’]],
[‘label’ => Yii::t(‘app’,’Status’), ‘url’ => [‘/status/index’]],
[‘label’ => Yii::t(‘app’,’About’), ‘url’ => [‘/site/about’]],
[‘label’ => Yii::t(‘app’,’Contact’), ‘url’ => [‘/site/contact’]]
];
if (Yii::$app->user->isGuest) {
array_push($navItems,[‘label’ => Yii::t(‘app’,’Sign In’), ‘url’ => [‘/user/login’]],[‘label’ => Yii::t(‘app’,’Sign Up’), ‘url’ => [‘/user/register’]]);
} else {
array_push($navItems,[‘label’ => Yii::t(‘app’,’Logout’).’ (‘ . Yii::$app->user->identity->username . ‘)’,
‘url’ => [‘/site/logout’],
‘linkOptions’ => [‘data-method’ => ‘post’]]
);
}
echo Nav::widget([
‘options’ => [‘class’ => ‘navbar-nav navbar-right’],
‘items’ => $navItems,
]);
NavBar::end();
|
Вот фрагмент содержимого домашней страницы из index.php после I18n — большая часть HTML была заменена PHP-вызовами Yii::t()
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<div class=»jumbotron»>
<h1><?= Yii::t(‘app’,’Congratulations!’);
<p class=»lead»><?= Yii::t(‘app’,’You have successfully created your Yii-powered application.’);
<p><a class=»btn btn-lg btn-success» href=»http://www.yiiframework.com»><?= Yii::t(‘app’,’Get started with Yii’);
</div>
<div class=»body-content»>
<div class=»row»>
<div class=»col-lg-4″>
<h2><?= Yii::t(‘app’,’Heading’);
<p><?= Yii::t(‘app’,’Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.’);
<p><a class=»btn btn-default» href=»http://www.yiiframework.com/doc/»><?= Yii::t(‘app’,’Yii Documentation’) ?> »</a></p>
</div>
|
Перевод файлов сообщений
Взгляните на наш испанский файл сообщений, /common/messages/es/frontend.php
. Это длинный список значений пустого массива:
01
02
03
04
05
06
07
08
09
10
|
return [
‘About’ => »,
‘Contact’ => »,
‘Home’ => »,
‘Logout’ => »,
‘My Company’ => »,
‘Sign In’ => »,
‘Sign Up’ => »,
‘Status’ => »,
…
|
Для заполнения наших переводов на испанский язык для этого урока я буду использовать Google Translate . Хитрый, а?
Затем мы сделаем некоторые вставки с этими переводами обратно в файл сообщений.
1
2
3
4
5
6
7
8
9
|
return [
‘About’ => ‘Acerca de’,
‘Contact’ => ‘Contacto’,
‘Home’ => ‘Home’,
‘Logout’ => ‘Salir’,
‘My Company’ => ‘Mi Empresa’,
‘Sign In’ => ‘Entrar’,
‘Sign Up’ => ‘Registrarse’,
‘Status’ => ‘Estado’,
|
Когда мы посетим домашнюю страницу приложения, вы увидите испанскую версию — хорошо, а?
Вот форма создания статуса:
Если я хочу переключиться обратно на английский, я просто изменяю файл конфигурации, /config/web.php
, обратно на английский:
01
02
03
04
05
06
07
08
09
10
|
<?php
$params = require(__DIR__ . ‘/params.php’);
$config = [
‘id’ => ‘basic’,
‘basePath’ => dirname(__DIR__),
‘bootstrap’ => [‘log’],
‘language’=>’en’, // back to English
‘components’ => [
|
В процессе работы вы также заметите, что замена строк в JavaScript имеет свои сложности. Я не исследовал это сам, но расширение Yii 1.x JsTrans может предоставить полезную рекомендацию для поддержки этого.
Идем дальше с I18n
В конечном счете, мы можем захотеть перевести наше приложение на несколько языков. Я написал новый учебник под названием « Использование API Google Translate для локализации вашего приложения I18n» (Tuts +), который автоматически переводит ваше приложение на различные языки. Если он еще не опубликован, он будет опубликован в ближайшее время ( проверьте страницу моего инструктора ). Конечно, это просто обеспечивает базовые переводы. Вы можете нанять профессиональных переводчиков для настройки файлов впоследствии.
Некоторые приложения позволяют пользователям выбирать свой родной язык, чтобы при входе в систему пользовательский интерфейс автоматически переводил их. В Yii установка переменной $app->language
делает это:
\Yii::$app->language = 'es';
Другие приложения, такие как JScrambler.com ниже, используют URL-путь для переключения языков. Пользователь просто щелкает языковой префикс, который он хочет, например, «FR» , и приложение автоматически переводится:
Примечание: прочитайте мое недавнее введение в JScrambler, чтобы узнать больше — это довольно полезный сервис.
Менеджер URL-адресов Yii также может предоставить такую функциональность . Вероятно, я буду реализовывать эти функции в следующем уроке из этой серии статей Yii2, когда сосредоточусь на маршрутизации .
Что дальше?
Я надеюсь, что вы воодушевлены мощью I18n и преимуществами использования Yii Framework по сравнению с ванильным PHP. Следите за будущими уроками в нашей серии «Программирование с Yii2» .
Если вы хотите узнать, когда появится следующий учебник по Yii2, следуйте за мной @reifman в Твиттере или зайдите на страницу моего инструктора . Моя страница инструктора будет включать все статьи из этой серии, как только они будут опубликованы. Вы также можете написать мне на мой сайт Lookahead Consulting .