Stay hungry, Stay foolish

0%

ThinkPHP多语言的实现原理

环境

ThinkPHP 2.0

相关配置:

在tp的全局配置文件convention.php中:

1
2
3
4
'DEFAULT_LANG' => 'zh-cn',
'LANG_SWITCH_ON'=> false, // 默认关闭多语言包功能
'LANG_AUTO_DETECT' => true, // 自动侦测语言 开启多语言功能后有效
'VAR_LANGUAGE' => 'l', // 默认语言切换变量

App::checkLanguage()

1
$langSet = C('DEFAULT_LANG');

首先,通过”快捷”函数C获取这个默认设置

1
2
3
4
5
// 不开启语言包功能,仅仅加载框架语言文件直接返回
if (!C('LANG_SWITCH_ON')){
L(include THINK_PATH.'/Lang/'.$langSet.'.php');
return;
}

LANG_SWITCH_ON在关闭状态下,只会加载框架下面的语言文件。然后一个return结束这个方法的运行。如果想开启项目的多语言支持的话,务必在项目的配置文件中把这项重写为true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 启用了语言包功能
// 根据是否启用自动侦测设置获取语言选择
if (C('LANG_AUTO_DETECT')){
if(isset($_GET[C('VAR_LANGUAGE')])){// 检测浏览器支持语言
$langSet = $_GET[C('VAR_LANGUAGE')];// url中设置了语言变量
cookie('think_language',$langSet,3600);
}elseif(cookie('think_language'))// 获取上次用户的选择
$langSet = cookie('think_language');
elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言
preg_match('/^([a-z-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches);
$langSet = $matches[1];
cookie('think_language',$langSet,3600);
}
}

其次,通过三种方式来获取当前的语言($langSet)

  • 检查URL里是否有VAR_LANGUAGE(默认是l)——用户可以通过这个变量来改变项目的语言;

  • 检查cookie里有没有设置;

  • 在前两项都没有的情况下,检查$_SERVER[‘HTTP_ACCEPT_LANGUAGE’]

$_SERVER[‘HTTP_ACCEPT_LANGUAGE’]是用来获取HTTP请求头信息中的Accept Language。打开firebug,查看本博客的网络信息,会看到如下:

经过这三道程序的把关,想获取不到当前的语言设置都难。获取后,立马设了一个一小时的cookie。接下来的就是语言文件的加载:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 定义当前语言
define('LANG_SET',strtolower($langSet));
// 加载框架语言包
if(is_file(THINK_PATH.'/Lang/'.$langSet.'.php'))
L(include THINK_PATH.'/Lang/'.$langSet.'.php');
// 读取项目公共语言包
if (is_file(LANG_PATH.$langSet.'/common.php'))
L(include LANG_PATH.$langSet.'/common.php');
$group = '';
// 读取当前分组公共语言包
if (defined('GROUP_NAME')){
$group = GROUP_NAME.C('TMPL_FILE_DEPR');
if (is_file(LANG_PATH.$langSet.'/'.$group.'lang.php'))
L(include LANG_PATH.$langSet.'/'.$group.'lang.php');
}
// 读取当前模块语言包
if (is_file(LANG_PATH.$langSet.'/'.$group.strtolower(MODULE_NAME).'.php'))
L(include LANG_PATH.$langSet.'/'.$group.strtolower(MODULE_NAME).'.php');

同项目的配置文件一样,语言文件支持公共语言包、分组语言包、甚至到当前模块的语言包!从这段程序可以看出它们的命名规则:

公共语言包 common.php
分组语言包 分组名称.lang.php
模块语言包 分组名.模块名.php

设置与获取:快捷函数L

L是个全才,能吞能吐,设置和获取都靠它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function L($name=null,$value=null) {
static $_lang = array();
// 空参数返回所有定义
if(empty($name)) return $_lang;
// 判断语言获取(或设置)
// 若不存在,直接返回全大写$name
if (is_string($name) )
{
$name = strtoupper($name);
if (is_null($value))
return isset($_lang[$name]) ? $_lang[$name] : $name;
$_lang[$name] = $value;// 语言定义
return;
}
// 批量定义
if (is_array($name))
$_lang = array_merge($_lang,array_change_key_case($name,CASE_UPPER));
return;
}

它维护着一个叫$_lang的静态数组。如果有$name和$value,就添加到数组里(支持批量),如果只有$name,则查找数组,有则返回它对应的值,没有的话,就把这个$name给全部大写(strtoupper)返回。

使用

这一块直接看手册就行了

  • 在模块(Controller)里设置或使用
1
2
3
L('name', '名称'); //动态设置
$value = L('name'); //读取
$arr = L(); //读取所有
  • 在模型(Model)里使用
1
array('title', 'require','{\%name}', 1),
  • 在模板(View)里使用
1
{$Think.lang.name}
据说打赏我的人,代码没有BUG