近排為客戶製作一個網頁,因為客戶已經買下了虛擬主機空間,不能用 Java 去作 Server side language,只好使用 PHP + CodeIgniter。他要求有轉換語言的功能,但發覺 CodeIgniter 本身的 i18n 功能不太完善,只好自己製作一個。
這個 i18n 有點像 JSF 的i18n 功能,是根據用戶的瀏覽器語言來判定顯示那一種語言,並且對 Controller 控制語言的程式碼減少(可以 1 行程式碼也不用寫就能夠自動設換各種語言)。這可以減少重複的程式碼和減低 Controller 的複雜性。
我己經將這個 Library 放上 github 了,有興趣可以下載來試試 https://github.com/lawrence0819/php-ci-internationalization。
以下就是 I18n.php (Core),放到 application/libraries/I18n.php。
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
* I18n class
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author Lawrence Cheung
* @version 1.0
* @link https://github.com/lawrence0819
*/
class I18n{
protected $CI;
protected $auto = TRUE;
protected $loaded = FALSE;
protected $locale;
/**
* Constructor - get CI instance
*
*/
public function __construct(){
$this -> CI = get_instance();
}
/**
* Auto load language for CI HOOK
*
* @access public
* @return void
*/
public function auto_load_language(){
if ($this -> auto){
$this -> load_language();
}
}
/**
* Manual load language file
*
* @access public
* @return void
*/
public function load_language() {
$lang = $this -> get_current_locale();
$language = $this -> get_language_config();
if (!$this -> loaded) {
$files = $language['files'];
$locale = $language['locale'];
if (array_key_exists($lang, $locale)) {
$folder = $locale[$lang];
} else {
$shortLang = substr($lang, 0, 2);
if (array_key_exists($shortLang, $locale)) {
$folder = $locale[$shortLang];
} else {
$folder = $locale['default'];
}
}
foreach ($files as $file) {
$this -> CI -> lang -> load($file, $folder);
}
$this -> loaded = TRUE;
}
}
/**
* Prevent CI Hook to auto load language file
*
* @access public
* @return void
*/
public function prevent_auto(){
$this -> auto = FALSE;
}
/**
* Set current user locale and save locale to cookies
*
* @access public
* @Param string the locale string: en-US, en-UK, zh-TW, zh-CN
* @Param integer the cookies value expire time, default is 30 day
* @Param string cookies key
* @return void
*/
public function set_current_locale($locale, $expire = 259200, $cookie_key = 'locale') {
setcookie($cookie_key, $locale, time() + $expire);
$this -> locale = $locale;
}
/**
* Get current user locale
*
* @access public
* @Param string cookies key, if you changed the key at set_current_locale, please assign it
* @return string
*/
public function get_current_locale($cookie_key = 'locale') {
if (!$this -> locale){
if (isset($_COOKIE[$cookie_key])) {
$lang = $_COOKIE[$cookie_key];
} else {
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 5);
} else {
$language = $this -> get_language_config();
$lang = $language['default_locale'];
}
}
$this -> locale = $lang;
}
return $this -> locale;
}
/**
* Get configuration values
*
* @access default
* @return array
*/
function get_language_config(){
$this -> CI -> config -> load('i18n');
return $this -> CI -> config -> item('language');
}
}
/* End of file I18n.php */
/* Location: ./application/libraries/I18N.php */
以下的是所需要的設定檔案 i18n.php (Core),放到 application/config/i18n.php。
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* I18n library configuration file
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author Lawrence Cheung
* @version 1.0
* @link https://github.com/lawrence0819
*/
//Add file in this array, if you want I18n library auto load them
$config['language']['files'] = array('messages');
//If user locale not found, set this valus as a defaul user locale
$config['language']['default_locale'] = 'en';
//Default language folder, if locale folder not found
$config['language']['locale']['default'] = 'tchinese';
//zh-CN locale mapped to schinese folder
$config['language']['locale']['zh-CN'] = 'schinese';
//zh-TW locale mapped to tchinese folder
$config['language']['locale']['zh-TW'] = 'tchinese';
//en locale mapped to schinese folder
$config['language']['locale']['en'] = 'english';
/* End of file i18n.php */
/* Location: ./application/config/i18n.php */
英文語言檔 messages_lang.php,放到 application/language/english/messages_lang.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$lang['site_name'] = 'Example site';
$lang['message'] = 'Hello World!';
/* End of file messages_lang.php */
/* Location: ./application/language/english/messages_lang.php */
正體中文語言檔 messages_lang.php,放到 application/language/tchinese/messages_lang.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$lang['site_name'] = '範例網站';
$lang['message'] = '世界,你好!';
/* End of file messages_lang.php */
/* Location: ./application/language/tchinese/messages_lang.php */
簡體中文語言檔 messages_lang.php,放到 application/language/schinese/messages_lang.php
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$lang['site_name'] = '范例网站';
$lang['message'] = '世界,你好!';
/* End of file messages_lang.php */
/* Location: ./application/language/schinese/messages_lang.php */
設定就完成了,如果你有更多語言或不使用 english,tchinese,schinese 的名稱,請更改 application/config/i18n.php。
使用方法如下:
手動選擇語言的 Controller:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class I18nmanual extends CI_Controller{
public function __construct(){
parent::__construct();
$this -> load -> library('i18n');
}
public function index(){
$this -> i18n -> load_language();
$this -> load -> view('i18ntest');
}
}
/* End of file i18nmanual.php */
/* Location: ./application/controller/i18nmanual.php */
View:
<html>
<head>
<title><?php echo $this->lang->line('site_name'); ?></title>
</head>
<body>
<?php echo $this->lang->line('message'); ?>
</body>
</html>
將會見到和 Browser 相對應的語言。
如果覺得要在 __construct 內加上
$this -> load -> library('i18n');
太麻煩,可以在 application/config/autoload.php 自動載入 i18n library:
$autoload['libraries'] = array('i18n');
開啟全自動的功能要先在 application/config/config.php 更改以下程式碼:
$config['enable_hooks'] = TRUE;
再將 application/config/hooks.php 加入以下程式碼:
$hook['post_controller_constructor'][] = array(
'class' => 'I18n',
'function' => 'auto_load_language',
'filename' => 'I18n.php',
'filepath' => 'libraries'
);
Controller:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class I18nauto extends CI_Controller{
public function __construct(){
parent::__construct();
$this -> load -> library('i18n');
}
public function index(){
$this -> load -> view('i18ntest');
}
}
/* End of file i18nauto.php */
/* Location: ./application/controller/i18nauto.php */
如果有設定自動載入 i18n library,就連 __construct 也不需要。
如果開啟了全自動的功能,但有些 Controller 又不想自動選擇語言,可以在 __construct 加上:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class I18nmanual extends CI_Controller{
public function __construct(){
parent::__construct();
$this -> load -> library('i18n');
//prevent auto load language
$this -> i18n -> prevent_auto();
}
public function index(){
$this -> i18n -> set_current_locale('zh-TW');
$this -> i18n -> load_language();
$this -> load -> view('i18ntest');
}
}
/* End of file i18nmanual.php */
/* Location: ./application/controller/i18nmanual.php */
一經切換的語系,就會自動將此更改儲存到 Cookies,下一次就會以 Cookies 的語系來選擇語言檔。
說明完畢,有什麼問題可以留言給我。