Codeigniter の言語クラスで gettext を使えるようにする

最近、ちょっと訳あって Codeigniter をいじってます。
すでに PHP が分かっていれば、学習コストも低く、直感的に使えるんでなかなか良いっすよ。

Codeigniter で、国際化するために用意されてる言語クラスですが、通常は以下のようにして使います。

application/language ディレクトリに各言語のサブフォルダ(例:japanese)を用意する。

その中に _lang.php (例:error_lang.php) というファイルを作成して、連想配列 $lang にテキストをセットする。

$lang['language_key'] = "実際に表示されるメッセージ";

Controller で言語ファイルを読み込む。

$this->lang->load('filename');

lang オブジェクトの line メソッドか、lang() 関数で、キーを指定してテキストを取得する。

$message = $this->lang->line('language_key');
// または
echo lang('language_key');

ただ、これだとキーとの対比とか、メンテナンスがめんどくさいので、できれば .mo ファイル作って gettext() で処理したい所です。

幸い Codeigniter は、コアシステムクラスを簡単に拡張できます。
っつうわけで、言語クラス CI_Lang を拡張して gettext で言語リソースを扱えるようにしてみました。

まず、以下の内容で application/core/MY_Lang.php を作成します。

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * Code Igniter Gettext Extension library
 *
 * This Library overides the original CI's language class. Needs the  $config&#91;'language'&#93; variable set as ja_JP or en_EN or fr_FR ...
 *
 * @package       Gettext Extension
 * @author        wokamoto
 * @copyright     Copyright (c) 2012
 * @license       http://www.gnu.org/licenses/lgpl.txt
 * @link          
 * @version       Version 0.1
 * @since         2012 January, 27th
 */

// ------------------------------------------------------------------------

class MY_Lang extends CI_Lang {

	private $gettext_language;
	private $gettext_codeset;
	private $gettext_domain;
	private $gettext_path;

	/**
	 * The constructor initialize the library
	 *
	 * @return MY_Lang
	 */
	function __construct() {
		parent::__construct();
	}

	/**
	 * This method overides the original load method. Its duty is loading the domain files by config or by default internal settings.
	 *
	 * @access	public
	 * @param	string	$userlang	the language, set as ja_JP or it_IT or en_EN or fr_FR ...
	 * @param	string	$codeset	the codeset, set as UTF-8 or EUC ...
	 * @return	bool
	 */
	public function load_gettext( $textdomain = false, $userlang = false, $codeset = false, $path = false ) {
		$config =& get_config();

		$this->gettext_language = $userlang ? $userlang : $config['language'];
		$this->gettext_codeset  = $codeset ? $codeset : $config['charset'];
		$this->gettext_domain   = $textdomain ? $textdomain : $this->gettext_domain;
		$this->gettext_path     = $path ? $path : APPPATH.'language/locale';

		/* put env and set locale */
		putenv("LANG={$this->gettext_language}");
		setlocale(LC_ALL, $this->gettext_language);

		/* bind text domain */
		bindtextdomain($this->gettext_domain, $this->gettext_path);
		bind_textdomain_codeset($this->gettext_domain, $this->gettext_codeset);
		textdomain($this->gettext_domain);

		return  true;
	}

	/**
	 * Fetch a single line of text from the language array
	 *
	 * @access	public
	 * @param	string	$line the original string to translate
	 * @param	array	$params the plural parameters
	 * @return	string	translated
	 */
	public function line($line = '', $params = FALSE)
	{
		if ( $params !== FALSE || FALSE === ($value = parent::line($line)) )
			$value = $this->_trans( $line, $params );

		return $value ? $value : $line;
	}

	/**
	 *  Plural forms added by Tchinkatchuk
	 *  http://www.codeigniter.com/forums/viewthread/2168/
	 */

	/**
	 * The translator method
	 *
	 * @access	private
	 * @param	string	$original the original string to translate
	 * @param	array	$aParams the plural parameters
	 * @return	string	translated
	 */
	private function _trans( $original, $aParams = false ) {
		if ( !isset($this->gettext_domain) )
			return false;

		if ( $aParams && isset($aParams['plural']) && isset($aParams['count']) ) {
			$sTranslate = ngettext($original, $aParams['plural'], $aParams['count']);
			$sTranslate = $this->replaceDynamically($sTranslate, $aParams);
		} else {
			$sTranslate = gettext( $original );
			if ( is_array($aParams) && count($aParams) ) {
				$sTranslate = $this->replaceDynamically($sTranslate, $aParams);
			}
		}

		return $sTranslate;
	}

	/**
	 * Allow dynamic allocation in traduction
	 *
	 * @access	private
	 * @param	string	$sString
	 * @return	string
	 */
	private function replaceDynamically($sString) {
		$aTrad = array();
		for ( $i=1, $iMax = func_num_args(); $i<$iMax; $i++) {
			$arg = func_get_arg($i);
			if (is_array($arg)) {
				foreach ($arg as $key => $sValue) {
					$aTrad['%'.$key] = $sValue;
				}
			} else {
				$aTrad['%'.$key] = $arg;
			}
		}

		return strtr($sString, $aTrad);
	}
}

そんで、application/language ディレクトリに、以下のようにファイルを言語リソースを配置。
language
 + locale
  + ja_JP (ロケール: ja_JP or en_EN or fr_FR )
   + LC_MESSAGES
    – lang.mo
    – lang.po

これを、実際に使う時は以下のようにします。

Controller で言語ファイルを読み込む。

$this->lang->load_gettext('lang', 'ja_JP');

※第一引数は textdomain、第二引数はロケール。

後は、同じように使えます。

$message = $this->lang->line('Hello World!');
// または
echo lang('Hello World!');

WordPress で慣れてるんで gettext 使いたいすよね。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください