如何跨PHP、JS和模板文件向web应用程序添加多语言支持?

如何跨PHP、JS和模板文件向web应用程序添加多语言支持?,php,language-agnostic,localization,multilingual,Php,Language Agnostic,Localization,Multilingual,我正在建立一个网站,需要支持不同的语言翻译。我有PHP、JavaScript和Smarty模板文件中的字符串需要翻译 我想使用类似PHP的函数,并为每个语言环境创建一个语言文件 当可翻译字符串位于PHP文件中时,这很容易,但Smarty模板和JavaScript文件中也有需要翻译的文本 我真的想要一个单独的文件来保存所有可翻译的字符串 更新: 我想使用gettext(),但真正的问题是它只适用于PHP,而不适用于JavaScript,因为JavaScript是客户端的 我构建的所有web应用程

我正在建立一个网站,需要支持不同的语言翻译。我有PHP、JavaScript和Smarty模板文件中的字符串需要翻译

我想使用类似PHP的函数,并为每个语言环境创建一个语言文件

当可翻译字符串位于PHP文件中时,这很容易,但Smarty模板和JavaScript文件中也有需要翻译的文本

我真的想要一个单独的文件来保存所有可翻译的字符串


更新:


我想使用gettext(),但真正的问题是它只适用于PHP,而不适用于JavaScript,因为JavaScript是客户端的

我构建的所有web应用程序都支持3种语言,并且设计用于更多语言。我将所有文本存储在数据库中,并称之为常量

create table constants (
id integer not null,
fk_constant_group integer not null 
)

create table constants_group (
id integer not null,
name varchar(32)
)

create table languages (
id integer not null,
name varchar(32),
accronym varchar(3),
/*other fields if necessary*/
)

create table constants_value (
id integer not null,
fk_constant integer,
fk_language integer,
value text
)
常量组用于按模块/页面对它们进行分组。如果要显示一个页面,则需要所有常量,因此可以使用单个查询获取一个页面所需语言的所有数据。组名上的索引是合适的。 在PHP中,我写了如下内容:

public static function SetNames()
    {
        $info=debug_backtrace(true);
        $result=self::GetNames($info);
        Factory::getSmarty()->assign("names",$result);
        return $result;
    }

public static function GetNames($info=false) /*$info is the debug_backtrace result*/
    {
        if(!$info)
            $info=debug_backtrace(true);
        $class=$info[1]['class']; /*It's the page name basically*/
        if(isset(self::$m_names[$class]))
            return self::$m_names[$class]; /*Using a static member for caching*/
        global $application;
        $langId=$application->langId;
        $constants=AppFac::getAdo()->GetAll("SELECT 
    X.name as constant_name, 
    XV.value as constant_value 
FROM 
    constants X 
LEFT JOIN constants_values XV ON XV.fk_constant=X.id 
LEFT JOIN constants_groups XG ON X.fk_constant_group=XG.id
WHERE
    XG.name=?
    AND XV.fk_language=?",array($class,$langId)); /*Parametrized query*/
        $result=array();
        foreach($constants as $constant) /*Make constants easily accessible*/
            $result[$constant['constant_name']]=$constant['constant_value'];
        self::$m_names[$class]=$result;
        return $result;
    }
从PHP模块中,在获取或显示模板之前,调用
SetNames()
方法,该方法将自动确定从中调用的类的名称,并使用该名称查找常量组并在会话中以语言集的形式填充常量。然后,使用模板中的常量,如
{$names.label\u name}
,例如,如果您正在为页面查找
label\u name
常量

这种方式很好,因为: 1.您可以直接从为应用程序构建的Web界面添加多种语言。 2.当文本存储在数据库中时,您可以轻松地组织它们。 3.您可以从为应用程序构建的界面轻松添加和编辑文本

如果您希望翻译整个页面而不是常量,那么当您只在模板中包含一个资源时,可以使用Smarty资源,并在PHP中定义如何处理该资源。

您可以将字符串存储在CSV文件中,如下所示:

"Welcome","Welcome"
"Total Price","Total Price"
为每种语言制作一个文件。第一个值是用于获取字符串的键,第二个值是用于转换的键。然后,您可以使用加载适当文件、将变量存储在数组中以及根据请求翻译文本的函数构建一个类。例如:

protected function loadTranslation($locale) {
    $this->_data=array();
    $localeFilePath="locale/" . $locale . "/whatever.csv";
    if(file_exists($localeFilePath)){
        $localeFileHandle = fopen($localeFilePath, "r");
        while (($line = fgetcsv($localeFileHandle, 1000)) !== FALSE) {
            $this->_data[$line[0]]=$line[1];
        }
        fclose($localeFileHandle);
    }
    return $this;
}
用于加载值和

   public function __($label) {
        $output=$this->_data[$label];
        if(empty($output)) $output=$label;
        return $output;
    }
翻译。 例如,您可以使用以下方法获得正确的字符串:

echo $this->__('Total Price')
使用CSV的优点是,您不需要为数据库操心,当然,它们可以通过Excel进行编辑,当您需要告诉一些数据输入人员进行翻译时,Excel将非常有用

此外,您还可以编写一个小脚本,在代码中查找_u()函数使用的字符串,然后在CSV文件中写入相应的字符串,这样您就不必浪费时间为代码中使用的每个字符串在每个CSV文件中追加字符串


至于Smarty模板和Javascript文件,您还必须从PHP获取已翻译的字符串。Smarty值来自PHP,因此在为Smarty赋值之前,请使用转换器。至于javascript,它必须由PHP动态创建,以便您可以在适当的位置设置翻译后的字符串。

最大的障碍是获取javascript中的语言常量。我已经可以使用gettext()和.po文件完成上面的大部分工作了。这比gettext()更难使用。不调用gettext(),而是访问数组。与构建JS的方式相同。PHP甚至有一个将数组编码为JSON的函数,可以在JS中使用,因此它比gettext()更快更简单。