CakePHP 国际化与本地化
让您的应用程序能够覆盖更广泛的受众群体,最好的方法之一就是支持多种语言。这通常是一项艰巨的任务,但 CakePHP 中的国际化和本地化功能使它变得更加容易和更强大。CakePHP 的优势之一就是国际化和本地化,包括使用 gettext 样式的静态翻译,以及对模型数据的动态翻译。将公开内容以多种语言提供,并使用唯一的 URL 访问,这是一个好主意。这使得用户(和搜索引擎)更容易找到他们期望的语言内容。可以通过多种方法实现,例如使用语言特定的子域(en.example.com,fra.example.com 等)或在 URL 中使用前缀,就像此应用程序所做的那样。您还可以从浏览器的用户代理信息中获取相关信息,等等。
首先,了解一些术语很重要。国际化是指应用程序能够被本地化的能力。本地化是指将应用程序适配到特定语言(或文化)要求的过程(即“区域设置”)。
1-部分:首先,您需要将 config/core.php 文件中的 Security.salt 值更改为不同的值,然后创建文件 /app/config/config.php 用于插入您要显示的语言。在本篇文章中,我将使用英语和西班牙语,默认语言为英语。
PHP 代码片段
<?php
<?php
/* add language to the file*/
$config['LANGUAGE'] = array(‘supported’ => array(‘eng’, ‘spa’),
‘default’ => ‘eng’);
?>
国际化和本地化通常分别简称为 i18n 和 l10n,
为什么 CakePHP 使用 i18n 或 L10n?
因为这两个术语通常缩写为 i18n(其中 18 代表国际化(internationalization)中第一个 i 和最后一个 n 之间的字母数,这个用法在 20 世纪 70 年代或 80 年代的 DEC 出现)和 L10n,这是因为这两个词太长。L10n 中的大写 L 有助于将其与 i18n 中的小写 i 区分开来。
您需要了解自己的语言缩写。以下是语言及其缩写的列表
cake/libs/l10n.php
注意:三字母区域设置代码符合 ISO 639-2 标准,但如果您创建了区域性区域设置(en_US,en_GB 等),CakePHP 会在适当的时候使用它们。如果您使用的是三字母区域设置代码,它将作为备用区域设置,如果不存在,您可以像这样手动添加它:
$this->Session->write(‘Config.language’, ‘eng’);
为了在您的应用程序中加载配置,您需要在 config/core.php 文件末尾添加以下代码:
PHP 代码
PHP 代码片段
<?php
<?php
Configure::load(‘config’);?>
?>
2-部分:CakePHP 中的语言文件扩展名为 .po 或 .mo。在本教程中,我将使用 .po 文件。
要了解更多信息,您可以参考这篇文章:
Abouzekry 撰写的本地化 PHP 应用程序系列。 https://phpmaster.com/localizing-php-applications-1 注意:请记住,po 文件适用于简短信息,如果您发现要翻译长段落,甚至整个页面,您应该考虑实施其他解决方案,在本篇文章中我们将省略这些解决方案。
我们创建以下文件夹:
app/locale/eng app/locale/spa 对于本教程,我们将使用“消息”的翻译,因此在每个语言文件夹中,我们都有一个名为 LC_MESSAGES(大写)的子文件夹。
现在我们应该有以下文件:
app/locale/eng/LC_MESSAGES/default.po
app/locale/spa/LC_MESSAGES/default.po
完成这一步后,我们可以继续下一步。
3-部分:为了使用 CakePHP 的文本函数(例如:__() 等),首先我们需要描述它们。事实上,__() 函数将这些字符串标识为可翻译的文本,这些文本会根据语言区域设置而有所不同,并使用 __() 函数中的文本作为消息 ID。如果我们定义了某种语言的翻译,那么这些翻译将显示在这些函数的位置。如果我们没有定义该语言的翻译,默认情况下,__() 函数中的文本将直接显示。每个要翻译的词语或短语都由一个 id-string 对组成,id 是“msgid”值,字符串是“msgstr”值。
您的西班牙语 PO 文件应该如下所示:
代码
msgid “bienvenida”
msgstr ” En varios idiomas-tutorial por Alireza.”
msgid “congrat”
msgstr ” le da las gracias”
现在我们需要创建一个假的控制器来切换语言。它的作用是在用户想要切换语言时调用 AppController::beforeFilter() 方法。
使用以下代码在 app/controllers/switchto_controller.php 中创建控制器
PHP 代码片段
<?php
<?php
class SwitchtoController extends AppController {
var $uses = array();
var $name = ‘Switchto’;
function beforeFilter()
{
parent::beforeFilter();
}
}
The AppController needs some modifications; edit the controller so it looks like this:
<?php
class AppController extends Controller
{
function beforeFilter()
{
if($this->_checkLanguage())
$this->redirect($this->referer(), null, true);
}
function _checkLanguage()
{
if(!$this->Session->check(‘Config.language’) || $this->name == “Switchto”) {
$default_lang = Configure::read(‘LANGUAGE.default’);
$supported_lang = Configure::read(‘LANGUAGE.supported’);
$lang = null;
if($this->name == “Switchto”)
$lang = $this->action;
// we need the Cookie
App::Import(‘Component’, ‘Cookie’);
$cookie = & new CookieComponent;
$cookie->time = ‘+360 days’;
$cookie->name = ‘MYAPP’;
$cookie->domain = ”;
$cookie->key = ‘whatever-key-you-wish’;
$cookie->startup();
if(!class_exists(“L10n”))
uses(‘l10n’);
$l10n = & new L10n();
if(!$lang || !in_array($lang, $supported_lang))
{
if($cookie->read(‘tutolanguage.lang’) )
{
$lang = $cookie->read(‘tutolang/lang’);
if(!in_array($lang, $supported_lang))
$lang = null;
}
/* try to find a language spaom browser that we support */
if(!$lang)
{
$browserLang = split (‘[,;]‘, env(‘HTTP_ACCEPT_LANGUAGE’));
foreach($browserLang as $langKey )
{
if(isset($l10n->__l10nCatalog[$langKey]) &&
in_array($l10n->__l10nCatalog[$langKey]['locale'], $supported_lang) )
{
$lang = $l10n->__l10nCatalog[$langKey]['locale'];
break;
}
}
}
}
if(!$lang)
$lang = $language_default;
// set the language, and write in cookie
$l10n->__setLanguage($lang);
$cookie->write(array(‘tutolanguage.lang’ => $lang));
$this->Session->write(‘Config.language’,$lang);
if($this->name == “Switchto”)
return true;
}
return false;
}
}
?>
为了记住用户选择的语言,我们将使用 cookie,所以我已经导入了 Cookie 组件。我选择以这种方式集成 cookie,而不是在 $components 中声明它,以避免在每次调用时对组件造成开销。
_checkLanguage 方法的解释
此方法仅在两种情况下起作用:“当未设置会话语言时”和“当用户想要切换语言时”。这是由第一个条件语句处理的。我们从配置中获取支持的语言和默认语言。如果控制器是“SwitchTo”,则表示用户点击了更改语言的链接。然后,操作将是我们选择的语言(请参阅下面如何设置链接以处理语言切换)。我们假设所需语言是操作名称。接下来,我们导入 Cookie 组件。实际上,为了记住语言,我们使用 cookie。我采用这种方式集成 cookie,而不是在 $components 中声明它,以避免在每次调用时对组件造成开销(我已经测试过)。我们设置 cookie 参数,您可以将其更改为自己的设置。请注意,调用 $cookie->startup 对于正确初始化过期日期至关重要。我们将使用 L10n 类来设置我们的语言。我们实例化了该类的对象。我们验证我们所需的语言是否受支持(所需语言为空或由 SwitchTo 操作设置)。如果语言不受支持,我们将查看 cookie 中是否包含该语言。如果是,我们仍然需要验证是否支持该语言(这可能发生在删除某种语言的情况下)。如果没有任何语言,我们将验证浏览器支持的语言中是否有任何语言与我们支持的语言相匹配。如果是,我们将使用第一个匹配的语言。仍然没有定义语言,那么我们将使用我们的应用程序默认语言。我们使用 L10n _setLanguage 方法在整个应用程序中设置我们的语言,并设置我们的会话语言(缺少它会导致流程出错)。我们将语言写入 cookie。当用户返回时,他们将自动设置为他们上次使用的语言。如果用户有意切换语言,我们将返回 true,以使 beforeFilter 重定向到引用 URL。beforerFilter 不言自明,如果用户选择另一种语言,我们将重定向到引用 URL。
4-部分:示例主页
为了测试示例,我修改了 CakePHP 的默认主页(从 CakePHP 分发版中复制并放置在 app/views/pages/display.ctp 中)。
PHP 代码片段
<?php
<h2><?php __(” bienvenida”); ?></h2>
<br />
<ul>
<li><?php echo $html->link(‘English’, ‘/switchto/eng’);?></li>
<li><?php echo $html->link(‘Spanish’, ‘/switchto/spa’);?></li>
</ul>
<br />
<h3><?php echo __(“congrat”, true);?><h3>
?>
此文件演示了两种使用 __() 函数的方法。在任何情况下,第一个参数都是与 default.po 文件中的 msgid 相匹配的值。如果在 PO 文件中没有找到 msgid,则将返回该值本身。默认情况下,翻译消息(或不匹配的 msgid)将输出给用户。但 __() 还支持第二个可选的布尔参数,如果您想捕获输出而不是发送输出,可以使用此参数,例如,将其传递给另一个函数或您需要执行的其他任何操作。
值得注意的是,语言文件被缓存到 tmp/cache/persistent/cake_core_default_xxx 文件中(其中 xxx 是区域设置)。当使用 debug = 0 的 CakePHP 时,请确保删除缓存的语言文件,以便立即反映更改。
5-部分:总结 当您需要为您的 Web 应用程序进行国际化和本地化时,您可能有许多选择,但 CakePHP 将是最佳选择。实际上,与使用子域和其他方法相比,使用 cookie 以及使用 gettext 样式的翻译具有许多优势,我们将在本文中找到这些优势,CakePHP 使您能够快速而灵活地创建应用程序。