-
Notifications
You must be signed in to change notification settings - Fork 0
Tutorial.Others II: Localization.zh_cn
- 本地化
在前面章节里,我们经常用到__()方法来处理字符串,这是一种类似语法糖的用法,用户可以方便地对需要翻译的字符串进行翻译。当然还需要去相应的文件里将需要翻译的最终结果写上,这一节将重点介绍如何进行本地化。
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里是这样设置的:
图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,用户注册
添加的内容里,每条翻译的待翻译字符串和翻译后的字符串用逗号隔开,前面为待翻译的字符串,后面为翻译后的字符串。由于翻译设置了缓存,因此需要到后台清除缓存,再进入登陆页将看到:
图9-4 全局默认文件翻译结果
**注意:**这里的字符不要用单引号括起,否则单引号会被当作字符串的一部分,从而匹配不了,用双引号将不影响翻译。
- 使用模块翻译
接下来我们在模块里添加翻译内容,在member目录下创建如下目录和文件,并添加翻译内容:
member
|- locale
|- en
|- main.csv
路径:usr/module/member/locale/en/main.csv
Code 9.2.2
Please enter,请输入用户信息
Register member,用户注册页面
清空缓存后进入登陆页将看到翻译结果被模块里的翻译文件覆盖了:
图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'));
}
重新刷新页面,我们看到主题的翻译已经应用了。
图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翻译文件。清空缓存后,进入注册页,会看到如下页面:
图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变量里:
图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,用户名已存在
需要注意的是,对于动态的变量,我们可以用%%的形式直接翻译过去。清空缓存后进入登陆页,可以看到错误提示已经被翻译:
图9-9 表单验证信息翻译结果