使用静态和动态内容、路由和切换进行国际化 =========
很多时候,当我准备一个新的网站时,我总是思考如何更好地解决国际化问题。主要是如何解决在所选语言未翻译的情况下显示动态内容的问题,如何为数据库中的搜索友好链接(称为漂亮的 URL,即 slugs)创建友好链接,如何解决路由这些链接的问题,以及如何执行切换并保持语言。在最后一个网络项目中,我准备了不使用 Cookies 和 Session 的应用程序,但我只是通过地址(URL)中的切换参数来实现的。
为什么选择这些解决方案?
因为当我们没有通过 Gettext 的魔法函数 ( __(); ) 翻译链接时,Session 和 Cookies 可以完美地工作。
在许多教程中,语言设置是在控制器(主要是 AppController 或 Component)中完成的。当我们在路由器 ( Router::connect(); ) 中使用翻译内容时,这将不起作用。有时教程通过设置语言并刷新页面 ( 通过 $this->redirect(); ) 来解决问题。我不喜欢这样!
路由
我希望 URL 像这样
/ // home page for default language
/en // home page for english
/pl // home page for polish
/de // home page for germany
/register // register action (for e.g. UsersController) for default language
/pl/rejestracja // register action for polish
/de/anmeldung // register action for germans
我不希望链接像这样
/pl/register // polish language for translated action name
/en/anmeldung // like above
…
为什么?因为在我看来,没有必要混合链接(主要是为了 SEO)。
我的解决方案是在应用程序启动前设置语言(AppController),这是本文中最丑陋的部分,稍后我会解释原因。
让我们开始编码!
bootstap.php (app/Config)
define('DEFAULT_LANGUAGE', 'en').
Configure::write('Config.languages', array(
'en' => 'English version',
'pl' => 'Język polski',
'de' => 'Deutsch Version'));
在第一行,我们定义了一个常量,其中包含默认语言的 2 个字母代码,即英语。接下来,为自己的应用程序准备一个包含语言代码和描述的数组,并将其保存到配置中。
routes.php (app/Config)
$language = substr(Router::url(''), 0, 2); // check that it works properly (sometimes You must trip part of url, for e.g. folder names)
$languages = array_keys(Configure::read('Config.languages'));
if(!in_array($language, array_diff($languages, array(DEFAULT_LANGUAGE)))) {
$language = DEFAULT_LANGUAGE;
$schema = '';
} else {
$schema = '/:language';
}
Configure::write('Config.language', $language);
/* PagesController */
Router::connect('/', array(
'controller' => 'pages',
'action' => 'display',
'home'));
Router::connect('/:language', array(
'controller' => 'pages',
'action' => 'display',
'home'), array(
'language' => implode('|', $languages)));
/* UsersController */
Router::connect($schema .'/'. __('register', true), array(
'controller' => 'users',
'action' => 'register'), array(
'persist' => array(
'language')));
是的,第一行是最丑陋的代码。这将从 URL 中获取前两个字母,以检查它们在配置 ‘Config.languages’ 中代表哪种语言的代码。接下来,准备用于路由模式的模式,并将选定的语言写入 Config.language 中。在这段代码中,我为首页准备了三个路由模式,分别使用默认语言、选定语言和注册页面的模式。
注意:如何准备应用程序使用静态翻译内容,使用 Poedit 应用程序,在 Mariano Iglesias 编写的“CakePHP 1.3 应用程序开发食谱”一书中进行了详细描述(是的,这本书被翻译成了波兰语!)。
1.3 和 2.x 之间没有区别。
我使用魔法参数 ‘persist’ 进行路由。当模式使用 /:language 时,它将为 $this->Html->links(); 添加语言参数。有关更多信息,请查看 路由器 API。
AppHelper.php (app/Views/Helpers)
function url($url = null, $full = false) {
if($this->params['language'] == DEFAULT_LANGUAGE) {
unset($this->params['language']);
}
return parent::url($url, $full);
}
我必须重写 url() 方法,因为我想使用配置中的语言参数。当它是默认语言时,我会取消设置语言参数,因为我们有重复的内容(通过 2 个 URL:/register 和 /en/register)。
当我重写 url() 方法并在路由模式中使用 persist 时,这两件事可以完美地协同工作!
default.ctp (app/Views/Layouts/)
现在,我们使用以下代码测试自己的应用程序
foreach(Configure::read('Config.languages') as $code => $language) { // show links for translated version
echo $this->Html->link($language, array(
'controller' => 'pages',
'action' => 'display',
'home',
'language' => $code)) .' ';
}
echo $this->Html->link(__('register', true), array( // show link to registartion page
'controller' => 'users',
'action' => 'register'));
静态、路由和切换都完成了。
动态内容
对于动态内容,Cake 默认情况下会从配置 ( Config.language ) 中设置 $locale 变量。如何在手动设置此变量的步骤,在 保存到其他语言 中进行了描述。
但是,如果我们想要显示来自数据库的翻译文章,而这篇文章没有翻译,我希望查看原始版本。如何做到这一点?
AppController.php (app/Controller)
将以下代码放入 beforeFilter(); 中。
if(Configure::read('Config.language') !== DEFAULT_LANGUAGE) {
$this->{$this->modelClass}->locale = array(Configure::read('Config.language'), DEFAULT_LANGUAGE);
} else {
$this->{$this->modelClass}->locale = DEFAULT_LANGUAGE;
}
这将尝试获取翻译版本(第一个数组参数)或原始版本(第二个参数)。
如何添加、编辑和翻译内容?我认为最好的方法是在默认语言中添加内容,但如果想要翻译内容并保存,则必须切换语言并进入编辑页面。
这是魔法!当我们在编辑页面上并且 URL 中没有语言参数时,我们会将其保存到默认语言中,但当 URL 中有语言参数时,我们会将其保存到选定的语言中。
不要忘记为 i18n 数据库表和你的模型准备翻译字段。
就这样!我期待您的问题和评论!在 2.2.5 版本上测试。
对不起,我仍在学习英语。
kicaj blog.kdev.pl