Index: /branches/version-2_12-multilang/html/install/sql/insert_data.sql
===================================================================
--- /branches/version-2_12-multilang/html/install/sql/insert_data.sql	(revision 21944)
+++ /branches/version-2_12-multilang/html/install/sql/insert_data.sql	(revision 22005)
@@ -1034,4 +1034,5 @@
 INSERT INTO mtb_constants (id, name, rank, remarks) VALUES ('MASTER_DATA_REALDIR', 'DATA_REALDIR . "cache/"', 27, 'マスターデータキャッシュディレクトリ');
 INSERT INTO mtb_constants (id, name, rank, remarks) VALUES ('UPDATE_HTTP', '"http://www.ec-cube.net/info/index.php"', 28, 'アップデート管理用ファイル格納場所');
+INSERT INTO mtb_constants (id, name, rank, remarks) VALUES ('LANG_CODE', '"ja"', 38, '言語コード');
 INSERT INTO mtb_constants (id, name, rank, remarks) VALUES ('CHAR_CODE', '"UTF-8"', 39, '文字コード');
 INSERT INTO mtb_constants (id, name, rank, remarks) VALUES ('LOCALE', '"ja_JP.UTF-8"', 40, 'ロケール設定');
Index: /branches/version-2_12-multilang/data/class_extends/SC_I18n_Ex.php
===================================================================
--- /branches/version-2_12-multilang/data/class_extends/SC_I18n_Ex.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/class_extends/SC_I18n_Ex.php	(revision 22005)
@@ -0,0 +1,27 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2012 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+require_once CLASS_REALDIR . 'SC_I18n.php';
+
+class SC_I18n_Ex extends SC_I18n {
+}
Index: /branches/version-2_12-multilang/data/class_extends/helper_extends/SC_Helper_Locale_Ex.php
===================================================================
--- /branches/version-2_12-multilang/data/class_extends/helper_extends/SC_Helper_Locale_Ex.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/class_extends/helper_extends/SC_Helper_Locale_Ex.php	(revision 22005)
@@ -0,0 +1,36 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+// {{{ requires
+require_once CLASS_REALDIR . 'helper/SC_Helper_Locale.php';
+
+/**
+ * Helper class for localization (extends).
+ * Edit this class to override SC_Helper_Locale.
+ *
+ * @package Helper
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class SC_Helper_Locale_Ex extends SC_Helper_Locale {
+}
Index: /branches/version-2_12-multilang/data/class/helper/SC_Helper_Locale.php
===================================================================
--- /branches/version-2_12-multilang/data/class/helper/SC_Helper_Locale.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/class/helper/SC_Helper_Locale.php	(revision 22005)
@@ -0,0 +1,171 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+require DATA_REALDIR . 'module/Locale/streams.php';
+require DATA_REALDIR . 'module/Locale/gettext.php';
+
+/**
+ * Helper class for localization.
+ * Library of static method.
+ *
+ * @package Helper
+ * @author LOCKON CO.,LTD.
+ * @version $Id$
+ */
+class SC_Helper_Locale {
+
+     public $_translations = array();
+
+     public $_plural_forms = array();
+
+     /**
+     * Return a string which corresponding with message alias.
+     *
+     * @param   string  $string             message alias
+     * @param   string  $lang_code          language code
+     * @param   integer $device_type_id     device type ID
+     * @return  string  a string corresponding with message alias
+     */
+    function get_locale($string, $lang_code = LANG_CODE, $device_type_id = DEVICE_TYPE_PC) {
+        // Get string list of specified language.
+        $translations = $this->get_translations($lang_code, $device_type_id);
+        // Whether a string which corresponding with alias is exist.
+        if (isset($translations[$string])) {
+            return $translations[$string];
+        }
+        else {
+            return $string;
+        }
+    }
+
+    /**
+     * Get the strings of specified language from locale files.
+     *
+     * @param   string  $lang_code      language code
+     * @param   integer $device_type_id device type ID
+     * @return  array   strings
+     */
+    function get_translations($lang_code = LANG_CODE, $device_type_id = DEVICE_TYPE_PC) {
+        // If the strings of specified language is not loaded
+        if (empty($this->_translations[$lang_code][$device_type_id])) {
+            $translations = array();
+
+            // Get a list of files to load.
+            $file_list = $this->get_locale_file_list($lang_code, $device_type_id);
+
+            // Get the strings from each locale file using php_gettext.
+            foreach ($file_list as $locale_file) {
+                $stream = new FileReader($locale_file);
+                $gettext = new gettext_reader($stream);
+
+                $gettext->load_tables();
+                $translations = array_merge($translations, $gettext->cache_translations);
+            }
+
+            $this->_translations[$lang_code][$device_type_id] = $translations;
+        }
+
+        return $this->_translations[$lang_code][$device_type_id];
+    }
+
+    /**
+     * Get a list of locale files.
+     *
+     * @param   string  $lang_code      language code
+     * @param   integer $device_type_id device type ID
+     * @return  array   file list
+     */
+    function get_locale_file_list($lang_code = LANG_CODE, $device_type_id = DEVICE_TYPE_PC) {
+        $file_list = array();
+
+        // Path to the EC-CUBE Core locale file.
+        $core_locale_path = DATA_REALDIR . "locales/{$lang_code}.mo";
+        // If a locale file of specified language is exist, add to the file list.
+        if (file_exists($core_locale_path)) {
+            $file_list[] = $core_locale_path;
+        }
+
+        // Get a list of enabled plugins.
+        $arrPluginDataList = SC_Plugin_Util_Ex::getEnablePlugin();
+        // Get the plugins directory.
+        $arrPluginDirectory = SC_Plugin_Util_Ex::getPluginDirectory();
+        foreach ($arrPluginDataList as $arrPluginData) {
+            // Check that the plugin filename is contained in the list of plugins directory.
+            if (array_search($arrPluginData['plugin_code'], $arrPluginDirectory) !== false) {
+                // Path to the plugin locale file.
+                $plugin_locale_path = PLUGIN_UPLOAD_REALDIR . $arrPluginData['plugin_code'] . "/locales/{$lang_code}.mo";
+                // If a locale file of specified language is exist, add to the file list.
+                if (file_exists($plugin_locale_path)) {
+                    $file_list[] = $plugin_locale_path;
+                }
+            }
+        }
+
+        // Path to the template locale file.
+        $template_locale_path = HTML_REALDIR . SC_Helper_PageLayout_Ex::getUserDir($device_type_id, true) . "locales/{$lang_code}.mo";
+        // If a locale file of specified language is exist, add to the file list.
+        if (file_exists($template_locale_path)) {
+            $file_list[] = $template_locale_path;
+        }
+
+        return $file_list;
+    }
+
+    /**
+     * Determine appropriate plural form.
+     *
+     * @param integer   $count      counter
+     * @param string    $lang_code  language code
+     * @return integer  index
+     */
+    function get_plural_index($count, $lang_code = LANG_CODE) {
+        // Get a formula
+        $string = $this->get_plural_forms($lang_code);
+        $string = str_replace('nplurals', "\$total", $string);
+        $string = str_replace("n", $count, $string);
+        $string = str_replace('plural', "\$plural", $string);
+
+        $total = 0;
+        $plural = 0;
+
+        eval("$string");
+        if ($plural >= $total) $plural = $total - 1;
+
+        return $plural;
+    }
+
+    /**
+     * Get a formula to determine appropriate plural form.
+     *
+     * @param   string  $lang_code  language code
+     * @return  string  formula
+     */
+    function get_plural_forms($lang_code = LANG_CODE) {
+        // If formula is empty, include the file.
+        if(empty($this->_plural_forms)){
+            $this->_plural_forms = @include_once DATA_REALDIR . "include/plural_forms.inc";
+        }
+
+        return $this->_plural_forms[$lang_code];
+    }
+}
Index: /branches/version-2_12-multilang/data/class/SC_I18n.php
===================================================================
--- /branches/version-2_12-multilang/data/class/SC_I18n.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/class/SC_I18n.php	(revision 22005)
@@ -0,0 +1,103 @@
+<?php
+/*
+ * This file is part of EC-CUBE
+ *
+ * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
+ *
+ * http://www.lockon.co.jp/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+class SC_I18n {
+
+    /**
+     * Store the instance of SC_Helper_Locale_Ex.
+     * @var object 
+     */
+    static $_instance = NULL;
+
+    /**
+     * Translate a message alias.
+     *
+     * @param   string  $string     message alias
+     * @param   array   $tokens     parameters for translation
+     * @param   array   $options    options
+     * @return  string  message to display
+     */
+    public static function t($string, $tokens = array(), $options = array()) {
+        is_null(SC_I18n_Ex::$_instance) and SC_I18n_Ex::$_instance = new SC_Helper_Locale_Ex();
+        $helper = SC_I18n_Ex::$_instance;
+
+        // If language code is not specified, use site default.
+        if (empty($options['lang_code'])) {
+            $options['lang_code'] = LANG_CODE;
+        }
+        // If device type ID is not specified, detect the viewing device.
+        if (empty($options['device_type_id'])) {
+            $options['device_type_id'] = SC_Display_Ex::detectDevice();
+        }
+
+        // Get a string of specified language which corresponds to the message alias.
+        $translated = $helper->get_locale($string, $options['lang_code'], $options['device_type_id']);
+
+        // If parameters are set, translate a message.
+        if (empty($tokens)) {
+          return $translated;
+        }
+        else {
+          return strtr($translated, $tokens);
+        }
+    }
+
+    /**
+     * Translate a message alias (plural).
+     *
+     * @param   integer $count      number for detecting format
+     * @param   string  $single     message alias (single)
+     * @param   string  $plural     message alias (plural)
+     * @param   array   $tokens     parameters for translation
+     * @param   array   $options    options
+     * @return  string  message to display
+     */
+    public static function t_plural($count, $single, $plural, $tokens = array(), $options = array()) {
+        is_null(SC_I18n_Ex::$_instance) and SC_I18n_Ex::$_instance = new SC_Helper_Locale_Ex();
+        $helper = SC_I18n_Ex::$_instance;
+
+        // Add a counter to translation parameters.
+        $tokens['T_COUNT'] = number_format($count);
+
+        // If language code is not specified, use site default.
+        if (empty($options['lang_code'])) {
+            $options['lang_code'] = LANG_CODE;
+        }
+        // If device type ID is not specified, detect the viewing device.
+        if (empty($options['device_type_id'])) {
+            $options['device_type_id'] = SC_Display_Ex::detectDevice();
+        }
+
+        // Determine appropriate plural form.
+        $index = $helper->get_plural_index($count, $options['lang_code']);
+
+        // Plural strings are coupled with a null character.
+        $key = $single . chr(0) . $plural;
+        // Get a string of specified language which corresponds to the message alias.
+        $translated = $helper->get_locale($key, $options['lang_code'], $options['device_type_id']);
+        // Divide with a null character.
+        $list = explode(chr(0), $translated);
+
+        return strtr($list[$index], $tokens);
+    }
+}
Index: /branches/version-2_12-multilang/data/smarty_extends/function.t_plural.php
===================================================================
--- /branches/version-2_12-multilang/data/smarty_extends/function.t_plural.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/smarty_extends/function.t_plural.php	(revision 22005)
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {t_plural} plugin
+ *
+ * Type:     function<br>
+ * Name:     t_plural<br>
+ * Purpose:  replace message alias to appropriate strings
+ * @author pineray 松田光貴 <matsudaterutaka at gmail dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_t_plural($params, &$smarty) {
+    // 書式判定用の数値が無ければエラーを出力
+    if (empty($params['counter'])) {
+        $smarty->_trigger_fatal_error("[plugin] parameter 'counter' cannot be empty");
+        return;
+    }
+    $counter = $params['counter'];
+    unset($params['counter']);
+    // 単数形のエイリアスが無ければエラーを出力
+    if (empty($params['single'])) {
+        $smarty->_trigger_fatal_error("[plugin] parameter 'single' cannot be empty");
+        return;
+    }
+    $single = $params['single'];
+    unset($params['single']);
+    // 複数形のエイリアスが無ければエラーを出力
+    if (empty($params['plural'])) {
+        $smarty->_trigger_fatal_error("[plugin] parameter 'plural' cannot be empty");
+        return;
+    }
+    $plural = $params['plural'];
+    unset($params['plural']);
+
+    // オプション用の配列
+    $options = array();
+    // 言語コードの指定があればオプションにセット
+    if (!empty($params['lang_code'])) {
+        $options['lang_code'] = $params['lang_code'];
+        unset($params['lang_code']);
+    }
+    // 機種の指定があればオプションにセット
+    if (!empty($params['device_type_id'])) {
+        $options['device_type_id'] = $params['device_type_id'];
+        unset($params['device_type_id']);
+    }
+
+    return SC_I18n_Ex::t_plural($counter, $single, $plural, $params, $options);
+}
Index: /branches/version-2_12-multilang/data/smarty_extends/function.t.php
===================================================================
--- /branches/version-2_12-multilang/data/smarty_extends/function.t.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/smarty_extends/function.t.php	(revision 22005)
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Smarty plugin
+ * @package Smarty
+ * @subpackage plugins
+ */
+
+
+/**
+ * Smarty {t} plugin
+ *
+ * Type:     function<br>
+ * Name:     t<br>
+ * Purpose:  replace message alias to appropriate strings
+ * @author pineray 松田光貴 <matsudaterutaka at gmail dot com>
+ * @param array
+ * @param Smarty
+ * @return string
+ */
+function smarty_function_t($params, &$smarty) {
+    // エイリアスが無ければエラーを出力
+    if (empty($params['string'])) {
+        $smarty->_trigger_fatal_error("[plugin] parameter 'string' cannot be empty");
+        return;
+    }
+    $string = $params['string'];
+    unset($params['string']);
+
+    // オプション用の配列
+    $options = array();
+    // 言語コードの指定があればオプションにセット
+    if (!empty($params['lang_code'])) {
+        $options['lang_code'] = $params['lang_code'];
+        unset($params['lang_code']);
+    }
+    // 機種の指定があればオプションにセット
+    if (!empty($params['device_type_id'])) {
+        $options['device_type_id'] = $params['device_type_id'];
+        unset($params['device_type_id']);
+    }
+
+    return SC_I18n_Ex::t($string, $params, $options);
+}
Index: /branches/version-2_12-multilang/data/locales/ja.po
===================================================================
--- /branches/version-2_12-multilang/data/locales/ja.po	(revision 22005)
+++ /branches/version-2_12-multilang/data/locales/ja.po	(revision 22005)
@@ -0,0 +1,179 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: EC-CUBE Core\n"
+"POT-Creation-Date: 2012-05-07 13T_39+0900\n"
+"PO-Revision-Date: 2012-08-21 16:44+0900\n"
+"Last-Translator: PineRay <matsuda@cyber-will.co.jp>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+
+msgid "SC_CHECKERROR_HTML_TAG_CHECK"
+msgstr "※ T_FIELDに許可されていないタグ T_TAG が含まれています。<br />"
+
+msgid "SC_CHECKERROR_EXIST_CHECK_INPUT"
+msgstr "※ T_FIELDが入力されていません。<br />"
+
+msgid "SC_CHECKERROR_EXIST_CHECK_SELECT"
+msgstr "※ T_FIELDが選択されていません。<br />"
+
+msgid "SC_CHECKERROR_EXIST_CHECK_REVERSE"
+msgstr "※ T_FIELDが入力されていません。<br />"
+
+msgid "SC_CHECKERROR_SPTAB_CHECK"
+msgstr "※ T_FIELDにスペース、タブ、改行のみの入力はできません。<br />"
+
+msgid "SC_CHECKERROR_NO_SPTAB"
+msgstr "※ T_FIELDにスペース、タブ、改行は含めないで下さい。<br />"
+
+msgid "SC_CHECKERROR_ZERO_START"
+msgstr "※ T_FIELDに0で始まる数値が入力されています。<br />"
+
+msgid "SC_CHECKERROR_SELECT_CHECK"
+msgstr "※ T_FIELDが選択されていません。<br />"
+
+msgid "SC_CHECKERROR_EQUAL_CHECK"
+msgstr "※ T_FIELD_1STとT_FIELD_2NDが一致しません。<br />"
+
+msgid "SC_CHECKERROR_DIFFERENT_CHECK"
+msgstr "※ T_FIELD_1STとT_FIELD_2NDは、同じ値を使用できません。<br />"
+
+msgid "SC_CHECKERROR_GREATER_CHECK"
+msgstr "※ T_FIELD_1STはT_FIELD_2NDより大きい値を入力できません。<br />"
+
+msgid "SC_CHECKERROR_MAX_LENGTH_CHECK"
+msgstr "※ T_FIELDはT_LENGTH字以下で入力してください。<br />"
+
+msgid "SC_CHECKERROR_MIN_LENGTH_CHECK_SINGLE"
+msgid_plural "SC_CHECKERROR_MIN_LENGTH_CHECK_PLURAL"
+msgstr[0] "※ T_FIELDはT_COUNT字以上で入力してください。<br />"
+msgstr[1] "※ T_FIELDはT_COUNT字以上で入力してください。<br />"
+
+msgid "SC_CHECKERROR_MAX_CHECK"
+msgstr "※ T_FIELDはT_LENGTH以下で入力してください。<br />"
+
+msgid "SC_CHECKERROR_MIN_CHECK_SINGLE"
+msgid_plural "SC_CHECKERROR_MIN_CHECK_PLURAL"
+msgstr[0] "※ T_FIELDはT_COUNT以上で入力してください。<br />"
+msgstr[1] "※ T_FIELDはT_COUNT以上で入力してください。<br />"
+
+msgid "SC_CHECKERROR_NUM_CHECK"
+msgstr "※ T_FIELDは数字で入力してください。<br />"
+
+msgid "SC_CHECKERROR_NUM_POINT_CHECK"
+msgstr "※ T_FIELDは数字で入力してください。<br />"
+
+msgid "SC_CHECKERROR_ALPHA_CHECK"
+msgstr "※ T_FIELDは半角英字で入力してください。<br />"
+
+msgid "SC_CHECKERROR_TEL_CHECK_EXIST"
+msgstr "※ T_FIELDはすべての項目を入力してください。<br />"
+
+msgid "SC_CHECKERROR_TEL_CHECK_MAX_LENGTH"
+msgstr "※ T_FIELDはT_LENGTH字以内で入力してください。<br />"
+
+msgid "SC_CHECKERROR_TEL_CHECK_NUM"
+msgstr "※ T_FIELDは数字で入力してください。<br />"
+
+msgid "SC_CHECKERROR_TEL_CHECK_SUM"
+msgstr "※ T_FIELDはT_LENGTH文字以内で入力してください。<br />"
+
+msgid "SC_CHECKERROR_FULL_EXIST_CHECK"
+msgstr "※ T_FIELDが入力されていません。<br />"
+
+msgid "SC_CHECKERROR_ALL_EXIST_CHECK"
+msgstr "※ T_FIELDはすべての項目を入力して下さい。<br />"
+
+msgid "SC_CHECKERROR_ONE_EXIST_CHECK"
+msgstr "※ T_FIELDが入力されていません。<br />"
+
+msgid "SC_CHECKERROR_TOP_EXIST_CHECK"
+msgstr "※ T_FIELDは先頭の項目から順番に入力して下さい。<br />"
+
+msgid "SC_CHECKERROR_KANA_CHECK"
+msgstr "※ T_FIELDはカタカナで入力してください。<br />"
+
+msgid "SC_CHECKERROR_KANABLANK_CHECK"
+msgstr "※ T_FIELDはカタカナで入力してください。<br />"
+
+msgid "SC_CHECKERROR_ALNUM_CHECK"
+msgstr "※ T_FIELDは英数字で入力してください。<br />"
+
+msgid "SC_CHECKERROR_GRAPH_CHECK"
+msgstr "※ T_FIELDは英数記号で入力してください。<br />"
+
+msgid "SC_CHECKERROR_ZERO_CHECK"
+msgstr "※ T_FIELDは1以上を入力してください。<br />"
+
+msgid "SC_CHECKERROR_NUM_RANGE_CHECK_SINGLE"
+msgid_plural "SC_CHECKERROR_NUM_RANGE_CHECK_PLURAL"
+msgstr[0] "※ T_FIELDはT_COUNT桁～T_DIGIT_MAX桁で入力して下さい。<br />"
+msgstr[1] "※ T_FIELDはT_COUNT桁～T_DIGIT_MAX桁で入力して下さい。<br />"
+
+msgid "SC_CHECKERROR_NUM_COUNT_CHECK_SINGLE"
+msgid_plural "SC_CHECKERROR_NUM_COUNT_CHECK_PLURAL"
+msgstr[0] "※ T_FIELDはT_COUNT桁で入力して下さい。<br />"
+msgstr[1] "※ T_FIELDはT_COUNT桁で入力して下さい。<br />"
+
+msgid "SC_CHECKERROR_EMAIL_CHECK"
+msgstr "※ T_FIELDの形式が不正です。<br />"
+
+msgid "SC_CHECKERROR_EMAIL_CHAR_CHECK"
+msgstr "※ T_FIELDに使用する文字を正しく入力してください。<br />"
+
+msgid "SC_CHECKERROR_URL_CHECK"
+msgstr "※ T_FIELDを正しく入力してください。<br />"
+
+msgid "SC_CHECKERROR_IP_CHECK"
+msgstr "※ T_FIELDに正しい形式のIPアドレスを入力してください。<br />"
+
+msgid "SC_CHECKERROR_FILE_EXT_CHECK"
+msgstr "※ T_FIELDで許可されている形式は、T_EXTです。<br />"
+
+msgid "SC_CHECKERROR_FIND_FILE"
+msgstr "※ T_PATHが見つかりません。<br />"
+
+msgid "SC_CHECKERROR_FILE_EXIST_CHECK"
+msgstr "※ T_FIELDをアップロードして下さい。<br />"
+
+msgid "SC_CHECKERROR_FILE_SIZE_CHECK"
+msgstr "※ T_FIELDのファイルサイズはT_SIZET_UNIT以下のものを使用してください。<br />"
+
+msgid "SC_CHECKERROR_FILE_NAME_CHECK"
+msgstr "※ T_FIELDのファイル名に日本語やスペースは使用しないで下さい。<br />"
+
+msgid "SC_CHECKERROR_CHECK_DATE_ALL_EXIST"
+msgstr "※ T_FIELDはすべての項目を入力して下さい。<br />"
+
+msgid "SC_CHECKERROR_CHECK_DATE_PROPER"
+msgstr "※ T_FIELDが正しくありません。<br />"
+
+msgid "SC_CHECKERROR_CHECK_SET_TERM_PROPER"
+msgstr "※ T_FIELDを正しく指定してください。<br />"
+
+msgid "SC_CHECKERROR_CHECK_SET_TERM_RANGE"
+msgstr "※ T_STARTとT_ENDの期間指定が不正です。<br />"
+
+msgid "SC_CHECKERROR_DIR_CHECK"
+msgstr "※ 指定したT_FIELDは存在しません。<br />"
+
+msgid "SC_CHECKERROR_DOMAIN_CHECK"
+msgstr "※ T_FIELDの形式が不正です。<br />"
+
+msgid "SC_CHECKERROR_MOBILE_EMAIL_CHECK"
+msgstr "※ T_FIELDは携帯電話のものではありません。<br />"
+
+msgid "SC_CHECKERROR_CHECK_REGIST_CUSTOMER_EMAIL_EXIST"
+msgstr "※ すでに会員登録で使用されているT_FIELDです。<br />"
+
+msgid "SC_CHECKERROR_CHECK_REGIST_CUSTOMER_EMAIL_INTERVAL"
+msgstr "※ 退会から一定期間の間は、同じT_FIELDを使用することはできません。<br />"
+
+msgid "SC_CHECKERROR_PROHIBITED_STR_CHECK"
+msgstr "※ T_FIELDは入力できません。<br />"
+
+msgid "SC_CHECKERROR_EVAL_CHECK"
+msgstr "※ T_FIELDの形式が不正です。<br />"
+
Index: /branches/version-2_12-multilang/data/include/plural_forms.inc
===================================================================
--- /branches/version-2_12-multilang/data/include/plural_forms.inc	(revision 22005)
+++ /branches/version-2_12-multilang/data/include/plural_forms.inc	(revision 22005)
@@ -0,0 +1,8 @@
+<?php
+/**
+ * 複数形書式判定用の計算式
+ */
+
+return array(
+    'ja' => "nplurals=2; plural=(n!=1);"
+);
Index: /branches/version-2_12-multilang/data/module/Locale/streams.php
===================================================================
--- /branches/version-2_12-multilang/data/module/Locale/streams.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/module/Locale/streams.php	(revision 22005)
@@ -0,0 +1,167 @@
+<?php
+/*
+   Copyright (c) 2003, 2005, 2006, 2009 Danilo Segan <danilo@kvota.net>.
+
+   This file is part of PHP-gettext.
+
+   PHP-gettext is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   PHP-gettext is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with PHP-gettext; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+
+  // Simple class to wrap file streams, string streams, etc.
+  // seek is essential, and it should be byte stream
+class StreamReader {
+  // should return a string [FIXME: perhaps return array of bytes?]
+  function read($bytes) {
+    return false;
+  }
+
+  // should return new position
+  function seekto($position) {
+    return false;
+  }
+
+  // returns current position
+  function currentpos() {
+    return false;
+  }
+
+  // returns length of entire stream (limit for seekto()s)
+  function length() {
+    return false;
+  }
+};
+
+class StringReader {
+  var $_pos;
+  var $_str;
+
+  function StringReader($str='') {
+    $this->_str = $str;
+    $this->_pos = 0;
+  }
+
+  function read($bytes) {
+    $data = substr($this->_str, $this->_pos, $bytes);
+    $this->_pos += $bytes;
+    if (strlen($this->_str)<$this->_pos)
+      $this->_pos = strlen($this->_str);
+
+    return $data;
+  }
+
+  function seekto($pos) {
+    $this->_pos = $pos;
+    if (strlen($this->_str)<$this->_pos)
+      $this->_pos = strlen($this->_str);
+    return $this->_pos;
+  }
+
+  function currentpos() {
+    return $this->_pos;
+  }
+
+  function length() {
+    return strlen($this->_str);
+  }
+
+};
+
+
+class FileReader {
+  var $_pos;
+  var $_fd;
+  var $_length;
+
+  function FileReader($filename) {
+    if (file_exists($filename)) {
+
+      $this->_length=filesize($filename);
+      $this->_pos = 0;
+      $this->_fd = fopen($filename,'rb');
+      if (!$this->_fd) {
+        $this->error = 3; // Cannot read file, probably permissions
+        return false;
+      }
+    } else {
+      $this->error = 2; // File doesn't exist
+      return false;
+    }
+  }
+
+  function read($bytes) {
+    if ($bytes) {
+      fseek($this->_fd, $this->_pos);
+
+      // PHP 5.1.1 does not read more than 8192 bytes in one fread()
+      // the discussions at PHP Bugs suggest it's the intended behaviour
+      $data = '';
+      while ($bytes > 0) {
+        $chunk  = fread($this->_fd, $bytes);
+        $data  .= $chunk;
+        $bytes -= strlen($chunk);
+      }
+      $this->_pos = ftell($this->_fd);
+
+      return $data;
+    } else return '';
+  }
+
+  function seekto($pos) {
+    fseek($this->_fd, $pos);
+    $this->_pos = ftell($this->_fd);
+    return $this->_pos;
+  }
+
+  function currentpos() {
+    return $this->_pos;
+  }
+
+  function length() {
+    return $this->_length;
+  }
+
+  function close() {
+    fclose($this->_fd);
+  }
+
+};
+
+// Preloads entire file in memory first, then creates a StringReader
+// over it (it assumes knowledge of StringReader internals)
+class CachedFileReader extends StringReader {
+  function CachedFileReader($filename) {
+    if (file_exists($filename)) {
+
+      $length=filesize($filename);
+      $fd = fopen($filename,'rb');
+
+      if (!$fd) {
+        $this->error = 3; // Cannot read file, probably permissions
+        return false;
+      }
+      $this->_str = fread($fd, $length);
+      fclose($fd);
+
+    } else {
+      $this->error = 2; // File doesn't exist
+      return false;
+    }
+  }
+};
+
+
+?>
Index: /branches/version-2_12-multilang/data/module/Locale/gettext.php
===================================================================
--- /branches/version-2_12-multilang/data/module/Locale/gettext.php	(revision 22005)
+++ /branches/version-2_12-multilang/data/module/Locale/gettext.php	(revision 22005)
@@ -0,0 +1,432 @@
+<?php
+/*
+   Copyright (c) 2003, 2009 Danilo Segan <danilo@kvota.net>.
+   Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
+
+   This file is part of PHP-gettext.
+
+   PHP-gettext is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   PHP-gettext is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with PHP-gettext; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/**
+ * Provides a simple gettext replacement that works independently from
+ * the system's gettext abilities.
+ * It can read MO files and use them for translating strings.
+ * The files are passed to gettext_reader as a Stream (see streams.php)
+ *
+ * This version has the ability to cache all strings and translations to
+ * speed up the string lookup.
+ * While the cache is enabled by default, it can be switched off with the
+ * second parameter in the constructor (e.g. whenusing very large MO files
+ * that you don't want to keep in memory)
+ */
+class gettext_reader {
+  //public:
+   var $error = 0; // public variable that holds error code (0 if no error)
+
+   //private:
+  var $BYTEORDER = 0;        // 0: low endian, 1: big endian
+  var $STREAM = NULL;
+  var $short_circuit = false;
+  var $enable_cache = false;
+  var $originals = NULL;      // offset of original table
+  var $translations = NULL;    // offset of translation table
+  var $pluralheader = NULL;    // cache header field for plural forms
+  var $total = 0;          // total string count
+  var $table_originals = NULL;  // table for original strings (offsets)
+  var $table_translations = NULL;  // table for translated strings (offsets)
+  var $cache_translations = NULL;  // original -> translation mapping
+
+
+  /* Methods */
+
+
+  /**
+   * Reads a 32bit Integer from the Stream
+   *
+   * @access private
+   * @return Integer from the Stream
+   */
+  function readint() {
+      if ($this->BYTEORDER == 0) {
+        // low endian
+        $input=unpack('V', $this->STREAM->read(4));
+        return array_shift($input);
+      } else {
+        // big endian
+        $input=unpack('N', $this->STREAM->read(4));
+        return array_shift($input);
+      }
+    }
+
+  function read($bytes) {
+    return $this->STREAM->read($bytes);
+  }
+
+  /**
+   * Reads an array of Integers from the Stream
+   *
+   * @param int count How many elements should be read
+   * @return Array of Integers
+   */
+  function readintarray($count) {
+    if ($this->BYTEORDER == 0) {
+        // low endian
+        return unpack('V'.$count, $this->STREAM->read(4 * $count));
+      } else {
+        // big endian
+        return unpack('N'.$count, $this->STREAM->read(4 * $count));
+      }
+  }
+
+  /**
+   * Constructor
+   *
+   * @param object Reader the StreamReader object
+   * @param boolean enable_cache Enable or disable caching of strings (default on)
+   */
+  function gettext_reader($Reader, $enable_cache = true) {
+    // If there isn't a StreamReader, turn on short circuit mode.
+    if (! $Reader || isset($Reader->error) ) {
+      $this->short_circuit = true;
+      return;
+    }
+
+    // Caching can be turned off
+    $this->enable_cache = $enable_cache;
+
+    $MAGIC1 = "\x95\x04\x12\xde";
+    $MAGIC2 = "\xde\x12\x04\x95";
+
+    $this->STREAM = $Reader;
+    $magic = $this->read(4);
+    if ($magic == $MAGIC1) {
+      $this->BYTEORDER = 1;
+    } elseif ($magic == $MAGIC2) {
+      $this->BYTEORDER = 0;
+    } else {
+      $this->error = 1; // not MO file
+      return false;
+    }
+
+    // FIXME: Do we care about revision? We should.
+    $revision = $this->readint();
+
+    $this->total = $this->readint();
+    $this->originals = $this->readint();
+    $this->translations = $this->readint();
+  }
+
+  /**
+   * Loads the translation tables from the MO file into the cache
+   * If caching is enabled, also loads all strings into a cache
+   * to speed up translation lookups
+   *
+   * @access private
+   */
+  function load_tables() {
+    if (is_array($this->cache_translations) &&
+      is_array($this->table_originals) &&
+      is_array($this->table_translations))
+      return;
+
+    /* get original and translations tables */
+    if (!is_array($this->table_originals)) {
+      $this->STREAM->seekto($this->originals);
+      $this->table_originals = $this->readintarray($this->total * 2);
+    }
+    if (!is_array($this->table_translations)) {
+      $this->STREAM->seekto($this->translations);
+      $this->table_translations = $this->readintarray($this->total * 2);
+    }
+
+    if ($this->enable_cache) {
+      $this->cache_translations = array ();
+      /* read all strings in the cache */
+      for ($i = 0; $i < $this->total; $i++) {
+        $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
+        $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
+        $this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
+        $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
+        $this->cache_translations[$original] = $translation;
+      }
+    }
+  }
+
+  /**
+   * Returns a string from the "originals" table
+   *
+   * @access private
+   * @param int num Offset number of original string
+   * @return string Requested string if found, otherwise ''
+   */
+  function get_original_string($num) {
+    $length = $this->table_originals[$num * 2 + 1];
+    $offset = $this->table_originals[$num * 2 + 2];
+    if (! $length)
+      return '';
+    $this->STREAM->seekto($offset);
+    $data = $this->STREAM->read($length);
+    return (string)$data;
+  }
+
+  /**
+   * Returns a string from the "translations" table
+   *
+   * @access private
+   * @param int num Offset number of original string
+   * @return string Requested string if found, otherwise ''
+   */
+  function get_translation_string($num) {
+    $length = $this->table_translations[$num * 2 + 1];
+    $offset = $this->table_translations[$num * 2 + 2];
+    if (! $length)
+      return '';
+    $this->STREAM->seekto($offset);
+    $data = $this->STREAM->read($length);
+    return (string)$data;
+  }
+
+  /**
+   * Binary search for string
+   *
+   * @access private
+   * @param string string
+   * @param int start (internally used in recursive function)
+   * @param int end (internally used in recursive function)
+   * @return int string number (offset in originals table)
+   */
+  function find_string($string, $start = -1, $end = -1) {
+    if (($start == -1) or ($end == -1)) {
+      // find_string is called with only one parameter, set start end end
+      $start = 0;
+      $end = $this->total;
+    }
+    if (abs($start - $end) <= 1) {
+      // We're done, now we either found the string, or it doesn't exist
+      $txt = $this->get_original_string($start);
+      if ($string == $txt)
+        return $start;
+      else
+        return -1;
+    } else if ($start > $end) {
+      // start > end -> turn around and start over
+      return $this->find_string($string, $end, $start);
+    } else {
+      // Divide table in two parts
+      $half = (int)(($start + $end) / 2);
+      $cmp = strcmp($string, $this->get_original_string($half));
+      if ($cmp == 0)
+        // string is exactly in the middle => return it
+        return $half;
+      else if ($cmp < 0)
+        // The string is in the upper half
+        return $this->find_string($string, $start, $half);
+      else
+        // The string is in the lower half
+        return $this->find_string($string, $half, $end);
+    }
+  }
+
+  /**
+   * Translates a string
+   *
+   * @access public
+   * @param string string to be translated
+   * @return string translated string (or original, if not found)
+   */
+  function translate($string) {
+    if ($this->short_circuit)
+      return $string;
+    $this->load_tables();
+
+    if ($this->enable_cache) {
+      // Caching enabled, get translated string from cache
+      if (array_key_exists($string, $this->cache_translations))
+        return $this->cache_translations[$string];
+      else
+        return $string;
+    } else {
+      // Caching not enabled, try to find string
+      $num = $this->find_string($string);
+      if ($num == -1)
+        return $string;
+      else
+        return $this->get_translation_string($num);
+    }
+  }
+
+  /**
+   * Sanitize plural form expression for use in PHP eval call.
+   *
+   * @access private
+   * @return string sanitized plural form expression
+   */
+  function sanitize_plural_expression($expr) {
+    // Get rid of disallowed characters.
+    $expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr);
+
+    // Add parenthesis for tertiary '?' operator.
+    $expr .= ';';
+    $res = '';
+    $p = 0;
+    for ($i = 0; $i < strlen($expr); $i++) {
+      $ch = $expr[$i];
+      switch ($ch) {
+      case '?':
+        $res .= ' ? (';
+        $p++;
+        break;
+      case ':':
+        $res .= ') : (';
+        break;
+      case ';':
+        $res .= str_repeat( ')', $p) . ';';
+        $p = 0;
+        break;
+      default:
+        $res .= $ch;
+      }
+    }
+    return $res;
+  }
+
+  /**
+   * Parse full PO header and extract only plural forms line.
+   *
+   * @access private
+   * @return string verbatim plural form header field
+   */
+  function extract_plural_forms_header_from_po_header($header) {
+    if (preg_match("/(^|\n)plural-forms: ([^\n]*)\n/i", $header, $regs))
+      $expr = $regs[2];
+    else
+      $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
+    return $expr;
+  }
+
+  /**
+   * Get possible plural forms from MO header
+   *
+   * @access private
+   * @return string plural form header
+   */
+  function get_plural_forms() {
+    // lets assume message number 0 is header
+    // this is true, right?
+    $this->load_tables();
+
+    // cache header field for plural forms
+    if (! is_string($this->pluralheader)) {
+      if ($this->enable_cache) {
+        $header = $this->cache_translations[""];
+      } else {
+        $header = $this->get_translation_string(0);
+      }
+      $expr = $this->extract_plural_forms_header_from_po_header($header);
+      $this->pluralheader = $this->sanitize_plural_expression($expr);
+    }
+    return $this->pluralheader;
+  }
+
+  /**
+   * Detects which plural form to take
+   *
+   * @access private
+   * @param n count
+   * @return int array index of the right plural form
+   */
+  function select_string($n) {
+    $string = $this->get_plural_forms();
+    $string = str_replace('nplurals',"\$total",$string);
+    $string = str_replace("n",$n,$string);
+    $string = str_replace('plural',"\$plural",$string);
+
+    $total = 0;
+    $plural = 0;
+
+    eval("$string");
+    if ($plural >= $total) $plural = $total - 1;
+    return $plural;
+  }
+
+  /**
+   * Plural version of gettext
+   *
+   * @access public
+   * @param string single
+   * @param string plural
+   * @param string number
+   * @return translated plural form
+   */
+  function ngettext($single, $plural, $number) {
+    if ($this->short_circuit) {
+      if ($number != 1)
+        return $plural;
+      else
+        return $single;
+    }
+
+    // find out the appropriate form
+    $select = $this->select_string($number);
+
+    // this should contains all strings separated by NULLs
+    $key = $single . chr(0) . $plural;
+
+
+    if ($this->enable_cache) {
+      if (! array_key_exists($key, $this->cache_translations)) {
+        return ($number != 1) ? $plural : $single;
+      } else {
+        $result = $this->cache_translations[$key];
+        $list = explode(chr(0), $result);
+        return $list[$select];
+      }
+    } else {
+      $num = $this->find_string($key);
+      if ($num == -1) {
+        return ($number != 1) ? $plural : $single;
+      } else {
+        $result = $this->get_translation_string($num);
+        $list = explode(chr(0), $result);
+        return $list[$select];
+      }
+    }
+  }
+
+  function pgettext($context, $msgid) {
+    $key = $context . chr(4) . $msgid;
+    $ret = $this->translate($key);
+    if (strpos($ret, "\004") !== FALSE) {
+      return $msgid;
+    } else {
+      return $ret;
+    }
+  }
+
+  function npgettext($context, $singular, $plural, $number) {
+    $key = $context . chr(4) . $singular;
+    $ret = $this->ngettext($key, $plural, $number);
+    if (strpos($ret, "\004") !== FALSE) {
+      return $singular;
+    } else {
+      return $ret;
+    }
+
+  }
+}
+
+?>
Index: /branches/version-2_12-multilang/data/mtb_constants_init.php
===================================================================
--- /branches/version-2_12-multilang/data/mtb_constants_init.php	(revision 21944)
+++ /branches/version-2_12-multilang/data/mtb_constants_init.php	(revision 22005)
@@ -30,4 +30,6 @@
 /** アップデート管理用ファイル格納場所 */
 define('UPDATE_HTTP', "http://www.ec-cube.net/info/index.php");
+/** 言語コード */
+define('LANG_CODE', "ja");
 /** 文字コード */
 define('CHAR_CODE', "UTF-8");
