在没有 i18n 或 TranslateBehaviour 的情况下将多语言功能添加到单语言网站 ==================
我目前正在开发一个需要多种语言的网站。因为我在项目开始时不知道这一点,所以我没有准备使用 CakePHP 集成的翻译功能。所以,我决定自己做点东西…
注意!
本教程适用于 CakePHP 2.x!
基本前提
在 CakePHP 中,你拥有 i18n、l10n 和 TranslateBehaviour 这样的优秀功能。问题是,只有当你从一开始就设计好你的应用程序来进行翻译时,这些功能才会真正有用。这假定你拥有为翻译内容创建单独的表格,等等。但是,如果你想将你的内容表用于所有语言的内容,你的新闻表用于所有语言的新闻等等,该怎么办呢?然后,你需要做的就是将 language_id 添加到所有你从中提取内容的表格中,并为你的语言建立一个 languages 表来将你的语言映射到名称,当然也包括添加新语言。
数据库/模型设置
首先,你应该创建你的内容表,其中包含一个 language_id 字段。当然,还要创建 languages 表。如下所示: ` CREATETABLE`contents`( id`int(11)NOTNULLAUTO_INCREMENT, `title`varchar(50)DEFAULTNULL, `body`varchar(250)DEFAULTNULL, `language_id`int(11)DEFAULTNULL, PRIMARYKEY(`id) )ENGINE=MyISAMDEFAULTCHARSET=utf8AUTO_INCREMENT=1;
CREATETABLE`languages`( id`int(11)NOTNULLAUTO_INCREMENT, `value`varchar(20)NOTNULL, PRIMARYKEY(`id), UNIQUEKEY`value`(value) )ENGINE=MyISAMAUTO_INCREMENT=5DEFAULTCHARSET=utf8AUTO_INCREMENT=5; ` 创建一个模型和关联关系,例如 Content > belongsTo > Language / Language > hasMany > Content。示例如下。
Content.php
` classContentextendsAppModel{
public$displayField=’title’; public$validate=array( ‘title’=>array( ‘notempty’=>array( ‘rule’=>array(‘notempty’), ), ), ‘body’=>array( ‘notempty’=>array( ‘rule’=>array(‘notempty’), ), ), );
public$belongsTo=array( ‘Language’=>array( ‘className’=>’Language’, ‘foreignKey’=>’language_id’, ‘conditions’=>’‘, ‘fields’=>’‘, ‘order’=>’’ ) ); } `
Language.php
` classLanguageextendsAppModel{
public$displayField=’value’;
public$hasMany=array( ‘Content’=>array( ‘className’=>’Content’, ‘foreignKey’=>’language_id’, ‘dependent’=>false) );
} <code> <p>这样就完成了数据库/模型部分,接下来我们来看控制器。</p>
<h2>控制器设置</h2>
<p>控制器设置非常简单,但取决于你的网站是如何配置的。我将所有前端内容放在 PagesController 中,并结合大量使用元素,当然还有路由到各种定义的动作。为了方便使用,我将把它建立在当你下载/解压缩 CakePHP 时获得的基本 PagesController 上。但我有点跑题了。在做任何操作之前,你需要配置一项设置。你必须配置你的应用程序来使用 Session 组件。这是至关重要的,因为这一切都依赖于一个简单的利用 session 的技巧:)
所以,我们开始吧…在 AppController 中,你只需要添加以下代码
<code> <?php classAppControllerextendsController{ public$components=array(‘Session’); } ` 没错,就这些。只需要这一段代码,而更多代码则包含在用于服务首页的控制器中,你将在该控制器中放置语言选择器。基本上,只是链接到控制器动作而已。我把链接放在 default.ctp 布局文件中,因为顶层菜单对于所有页面都是一样的。所以,让我们看一下如何配置 PagesController 来实现语言切换功能。 ` <?php classPagesControllerextendsAppController{ publicfunctiondisplay(){ $path=func_get_args(); $count=count($path); if(!$count){ $this->redirect(‘/’); } $page=$subpage=$title_for_layout=null;
if(!empty($path[0])){ $page=$path[0]; } if(!empty($path[1])){ $subpage=$path[1]; } if(!empty($path[$count-1])){ $title_for_layout=Inflector::humanize($path[$count-1]); } $this->set(compact(‘page’,’subpage’,’title_for_layout’)); $this->render(implode(‘/’,$path)); } publicfunctionsetLangEng(){ $this->Session->write(‘lang’,‘2’); $this->redirect(array(‘controller’=>’pages’,’action’=>’display’,’home’ )); } publicfunctionsetLangGer(){ $this->Session->write(‘lang’,‘1’); $this->redirect(array(‘controller’=>’pages’,’action’=>’display’,’home’ )); } } ` 这里唯一的自定义代码是 setLangEng() 和 setLangGer() 方法,它们只是写入一个用于存储所用语言的 session 变量。当然,你必须配置这些动作的路由以正确映射。这部分内容放在你的 routes.php 文件中,如下所示。 ` //routes.php 中的其他代码保持不变,只是在 //Router::connect(‘/eng’,array(‘controller’=>’pages’,’action’=>’displa y’,’home’));
Router::connect(‘/eng’,array(‘controller’=>’pages’,’action’=>’setLangE ng’)); Router::connect(‘/ger’,array(‘controller’=>’pages’,’action’=>’setLangG er’)); ` 最后,也是最重要的一点魔法发生在 ContentsController 中,你将在其中根据语言_id(PagesController.php 中设置的“lang” session 变量)设置要获取的每个语言的内容。所以,你打开 ContentsController.php,并添加一些自己的方法,如下所示… ` <?php classContentsControllerextendsAppController{ //基本的 index、add、view、edit… publicfunctiongetcont(){ if($this->Session->read(‘lang’)==1) { $this->paginate=array( ‘conditions’=>array(‘Content.language_id’=>1), ‘limit’=>3, ‘fields’=>array(‘News.body’) ); $content=$this->paginate(‘Content’); return$content; } if($this->Session->read(‘lang’)==2) { $this->paginate=array( ‘conditions’=>array(‘Content.language_id’=>2), ‘limit’=>3, ‘fields’=>array(‘News.body’) ); $content=$this->paginate(‘Content’); return$content; } } `
收尾工作
你现在需要做的就是设置语言选择链接,当然,还要获取内容。我在元素中做到了这一点。但首先是链接…打开你的 /app/View/Layouts/default.ctp 文件,并将以下内容放在你希望语言选择菜单出现的位置。 ` <ahref=”/ger”>Ger</a> <ahref=”/eng”>Eng</a> ` 如你所见,我使用了普通的 HTML 链接,但我更喜欢这种方式,因为前端的开发人员更容易理解。
最后一步是在视图中调用内容。由于它的设置方式,它将是所有语言的相同视图,只是内容(或你以这种方式设置的任何内容)会根据 session 变量“lang”而发生变化。所以,视图将看起来像这样(我将使用 requestAction,因为我是在一个不同的控制器中调用它)。 ` //视图中的其他代码 <divclass=”content-boxsix-cols”> <?php$contents=$this->requestAction(‘/contents/getcont’);?> <?phpforeach($contentsas$content):?> <h2><?phpecho$content[‘Content’][‘title’];?></h2> <p><?phpecho$content[‘Content’][‘body’];?></p> <?phpendforeach;?> </div> `