Skip to content

Tutorial.Others II: Localization.zh_cn

linzongshu edited this page Jul 4, 2013 · 2 revisions

English

  1. 本地化

在前面章节里,我们经常用到__()方法来处理字符串,这是一种类似语法糖的用法,用户可以方便地对需要翻译的字符串进行翻译。当然还需要去相应的文件里将需要翻译的最终结果写上,这一节将重点介绍如何进行本地化。

2.1 翻译机制简介

目前在Pi Engine定义了三个位置的翻译,分别是全局、模块和主题。这些我们在目录里都能看到,就是locale目录。三种情况的locale位置分别为:

  • 全局:usr/locale
  • 模块:module/{module package}/locale
  • 主题:theme/{theme package}/locale

其中,默认情况下对于模块内内容的翻译,模块翻译文件的优先级高于全局翻译文件,而主题翻译文件需要通过Api指定后才能生效。

在locale目录下,我们会看到如en、zh-CN的文件夹,也就是哪种语言,相应的翻译文件都应该放在该文件下。而目前默认的翻译文件是CSV格式的,直接放在en或zh-CN等目录下。

Pi Engine的翻译实现都是由Pi\I18n\Translator\Translator类完成的,翻译在Pi Engine里也作为一种资源在系统初始化的时候被加载,此时会实例化Translator类并设置参数。参数的设置在var/config/application.{front/admin/feed}.php都已经写好了,如在application.front.php里是这样设置的:

fig9-3

图9-3 初始化Translator参数

因此,初始化时将使用全局和模块下的main.csv作为默认的翻译文件。在系统运行的时候,这些翻译文件里的数据将被写入到Translator类的相关变量里,因此翻译的时候,只需要到Translator类的变量里匹配即可。

2.2 本地化

2.2.1 使用翻译方法

前面我们都是使用__()方法来翻译,这种方法不会输出结果,若在模板里想输出翻译结果,有两种方式:

echo __('Hello');
_e('Hello');

这两种方式的效果一致。

2.2.2 添加翻译文件

现在我们以member模块为例介绍如何添加翻译文件,翻译文件存放的目录需要与Pi系统当前的语言环境一致,由于安装的时候安装的是en语言,因此我们暂时把中文翻译文件放在en目录下。

  • 使用全局翻译

打开usr/locale/en目录下的main.csv文件,并添加如下内容:

路径:usr/locale/en/main.csv

Code 9.2.1

Please enter,请输入
Register member,用户注册

添加的内容里,每条翻译的待翻译字符串和翻译后的字符串用逗号隔开,前面为待翻译的字符串,后面为翻译后的字符串。由于翻译设置了缓存,因此需要到后台清除缓存,再进入登陆页将看到:

fig9-4

图9-4 全局默认文件翻译结果

**注意:**这里的字符不要用单引号括起,否则单引号会被当作字符串的一部分,从而匹配不了,用双引号将不影响翻译。

  • 使用模块翻译

接下来我们在模块里添加翻译内容,在member目录下创建如下目录和文件,并添加翻译内容:

member
|- locale
   |- en
      |- main.csv

路径:usr/module/member/locale/en/main.csv

Code 9.2.2

Please enter,请输入用户信息
Register member,用户注册页面

清空缓存后进入登陆页将看到翻译结果被模块里的翻译文件覆盖了:

fig9-5

图9-5 模块的默认文件翻译结果

  • 使用主题翻译

现在我们尝试在主题里添加翻译,由于当前主题为course,我们course目录下创建同样的文件,为添加如下内容:

路径:usr/theme/course/locale/en/main.csv

Code 9.2.3

Please enter,用户信息
Register member,注册页面

但清空缓存后进入登陆页,发现页面没有变化,这是因为在模块里默认是使用模块翻译文件或全局翻译文件,若需要用主题翻译文件,需要额外指定,我们需要在引用翻译方法__()之前调用接口,引用主题的翻译文件,打开LoginController.php,在loginAction的最开头添加如下代码:

路径:usr/module/member/src/Controller/Front/LoginController.php

Code 9.2.4

public function loginAction()
{
    Pi::service('i18n')->loadTheme('main');
    ...
    $this->view()->assign('form', $form);
    $this->view()->assign('title', __('Please enter'));
}

重新刷新页面,我们看到主题的翻译已经应用了。

fig9-6

图9-6 在模块里应用主题的默认翻译文件

  • 自定义翻译文件

有时候我们希望将一些翻译归类,比如对于表单的翻译都放在form.csv里,这样方便维护,这时我们可采用自定义翻译文件。自定义翻译文件需要有相应的接口配合使用,这里先介绍下这些接口。

  • 在模板里可以用如下接口:

    • 指定模块翻译文件:$this->I18nModule('form');
    • 指定全局翻译文件:$this->I18n('form');
    • 指定主题翻译文件:$this->I18nTheme('form');
  • 在非模板里使用:

    • 指定模块翻译文件:Pi::service('i18n')->loadModule('form');
    • 指定全局翻译文件:Pi::service('i18n')->load('form');
    • 指定主题翻译文件:Pi::service('i18n')->loadTheme('form');

form就是要使用的翻译文件,即form.csv,关于这些接口的用法可以参考Pi的文档。现在我们为表单创建单独的翻译文件,在模块的en目录下创建form.csv并添加如下内容:

路径:usr/module/member/locale/en/form.csv

Code 9.2.5

Username,用户
Password,密码
Repeat Password,重复密码
Create,提交
Gender,性别
Male,男
Female,女
Country,国家
"Do you want to contact us?","是否与我们联系?"
Introduction,个人简介

接下来,我们还需要在表单文件里添加接口,载入该翻译文件,分别打开LoginForm.php和RegisterForm.php,并添加如下代码:

路径:usr/module/member/src/Form/LoginForm.php

Code 9.2.6

<?php
...
use Pi;

class LoginForm extends BaseForm
{
    public function init()
    {
        Pi::service('i18n')->loadModule('form');
        ...
    }
}

路径:usr/module/member/src/Form/RegisterForm.php

Code 9.2.7

<?php
...
use Pi;

class RegisterForm extends BaseForm
{
    public function init()
    {
        Pi::service('i18n')->loadModule('form');
        ...
    }
}

因为用到了Pi的接口,因此需要先引用Pi的命名空间,然后在表单使用翻译方法之前调用loadModule()接口载入form.csv翻译文件。清空缓存后,进入注册页,会看到如下页面:

fig9-7

图9-7 自定义翻译文件

2.2.3 为表单验证信息本地化

在前面介绍表单验证时,我们知道错误信息的提示都是在验证类里产生的,而验证类都封装在Zend或Pi的库里,因为我们就没法为其使用__()翻译方法。幸运的是,表单验证类早已经为我们想到了这一点,在AbstractValidator类里已经封装好了一个静态变量——$defaultTranslator用于保存处理翻译的实例,我们只需要在isValid()调用之前,将Pi系统的Translator实例赋给它即可。

因此我们同样可以在表单的初始化时,将这个变量赋上,同样打开LoginForm.php和RegisterForm.php,在init()函数的最开头添加如下代码:

路径:usr/module/member/src/Form/LoginForm.php

路径:usr/module/member/src/Form/RegisterForm.php

Code 9.2.8

<?php
...
    public function init()
    {
        $translator = Pi::service('i18n')->translator;
        \Zend\Validator\AbstractValidator::setDefaultTranslator($translator);
        Pi::service('i18n')->loadModule('form');
        ...
    }
}

代码里,Pi::service('i18n')->translator是获取Translator实例,然后调用AbstractorValicator的静态方法将实例赋给$defaultTranslator变量,setDefaultTranslator定义为静态方法方便开发者在任意位置都可以调用该方法,而不需要去考虑AbstractValidator类是否已经实例化。

最后我们还需要将翻译内容添加到翻译文件里,因为错误信息都是在Validator里产生的,所以我们要去相应的类里找待翻译的信息。比如登陆用户名的验证用到了StringLength类,所以要去Zend\Validator\StringLength类里找相应的错误信息提示,也就是$messageTemplates变量里:

fig9-8

图9-8 Vlidator类里的错误提示信息

然后我们将这些错误信息添加到翻译文件,并翻译:

路径:usr/module/member/locale/en/form.csv

Code 9.2.9

...
"The input is less than %min% characters long","用户名少于%min%个字符"
"The input is more than %max% characters long","用户名多于%max%个字符"
"The input does not match against pattern '%pattern%'","用户名不符合规范"
Username already exists,用户名已存在

需要注意的是,对于动态的变量,我们可以用%%的形式直接翻译过去。清空缓存后进入登陆页,可以看到错误提示已经被翻译:

fig9-9

图9-9 表单验证信息翻译结果

Clone this wiki locally