在PHP中使用语言文件最有效的方法?

时间:2009-09-12 02:32:15

标签: php multiple-languages

问题已更新而非提出新问题......

我真的想在我正在建立的社交网站上提供除英语之外的一些替代语言,这将是我第一次进行任何语言翻译,所以请耐心等待。
我正在研究,所以我很感兴趣并且对这些想法持开放态度,我已经有了很多问题。

1)
i18n是什么意思,我在研究SO上的语言翻译时经常看到它?

2)
大多数人都说使用gettext PHP有扩展或支持它,
好吧,我一直在研究它,我对它有一个基本的了解,据我所知,走这条路是很多额外的工作,
我的意思是编码我的网站以使用它的功能,即; _('你好世界我现在用英语')或者 gettext('你好世界我现在用英语')没有任何问题我会去要求。
但是你必须在你的服务器上安装gettext并使其正常工作 然后使用一些特殊的编辑器来创建特殊文件并编译它们?

听起来很痛苦,我知道这应该是最好的路线,好吧每个人似乎都这么说。
那么有人能告诉我为什么这是要走的路吗?

第3)
我非常喜欢这种方法的简单性,只需构建一个语言数组并在函数中调用您需要的短语,如下例所示  ,然后,您将只包含具有相应语言数组的文件。

我真正想知道的是,与使用gettext相比,这对于高流量和相当大的网站来说是不是更好的性能方法吗?如果可以的话,你能解释一下为什么会这样吗?

<?PHP
//Have seperate language files for each language I add, this would be english file
function lang($phrase){
    static $lang = array(
        'NO_PHOTO' => 'No photo\'s available',
        'NEW_MEMBER' => 'This user is new'
    );
    return $lang[$phrase];
}
//Then in application where there is text from the site and not from users I would do something like this
echo lang('NO_PHOTO');  // No photo's available would show here
?>

* brianreavis的答案中使用了一些代码

9 个答案:

答案 0 :(得分:21)

最好定义一个处理语言映射的函数。这样,如果您想要在以后更改它的工作方式,那么在使用$lang[...]并将其替换为其他内容的情况下,您不会被迫搜索数百个脚本。

这样的东西会起作用并且很好用快:

function lang($phrase){
    static $lang = array(
        'NO_PHOTO' => 'No photo\'s available',
        'NEW_MEMBER' => 'This user is new'
    );
    return $lang[$phrase];
}

使确定数组在函数内声明为static,因此每次调用函数时都不会重新分配数组。当$lang非常大时,这一点尤其重要。

使用它:

echo lang('NO_PHOTO');

要处理多种语言,只需在多个文件(如en.phpfr.php等)和require()中为用户定义此功能。

答案 1 :(得分:10)

这可能会更好:

function _L($phrase){
static $_L = array(
    'NO_PHOTO' => 'No photo\'s available',
    'NEW_MEMBER' => 'This user is new'
);

     return (!array_key_exists($phrase,$_L)) ? $phrase : $_L[$phrase];
}

这就是我现在用的东西。如果找不到该语言,它将返回短语,而不是错误。

您应该注意,一个数组可以包含不超过65500个项目。应该足够但是好,只是说。

以下是我用来检查用户语言的一些代码:

<?php
function setSessionLanguageToDefault() {
    $ip=$_SERVER['REMOTE_ADDR'];
    $url='http://api.hostip.info/get_html.php?ip='.$ip;
    $data=file_get_contents($url);
    $s=explode (':',$data);
    $s2=explode('(',$s[1]);

    $country=str_replace(')','',substr($s2[1], 0, 3));

    if ($country=='us') {
        $country='en';
    }

    $country=strtolower(ereg_replace("[^A-Za-z0-9]", "", $country ));
    $_SESSION["_LANGUAGE"]=$country;
}

if (!isset($_SESSION["_LANGUAGE"])) {
    setSessionLanguageToDefault();
}

if (file_exists(APP_DIR.'/language/'.$_SESSION["_LANGUAGE"].'.php')) {
    include(APP_DIR.'/language/'.$_SESSION["_LANGUAGE"].'.php');
} else {
    include(APP_DIR.'/language/'.DEFAULT_LANG.'.php');
}

?>

尚未完成,但我认为这可能会有很大帮助。

答案 2 :(得分:5)

不要编写自己的语言框架。使用gettext。 PHP具有您可以安装的标准bindings

答案 3 :(得分:4)

不要重新发明轮子。例如,使用gettextZend_Translate

答案 4 :(得分:1)

由于其他答案并没有真正回答所有问题,我会在答案中提出一个明智的选择。

1) I18n是国际化的缩写,与I-tenighte-n有一些相似之处。

2) 在我看来,gettext是浪费时间。

3) 你的方法很好看。您应该寻找的是语言变量。 WoltLab Community Framework 2.0实现了双向语言系统。一旦存在保存在数据库中和模板内的语言变量,只使用变量的名称,然后将该变量的名称替换为当前语言中变量的内容(如果可用)。系统的第二部分提供了一种以多种语言保存用户生成内容的方法(需要多种语言输入)。

基本上,您拥有开发人员定义的界面文本以及用户定义的内容。内容的多语言文本保存在语言变量中,然后语言变量的名称将用作特定内容表中文本字段的值(因为单语言内容也是可能的)。

WCF的结构遗憾的是,在框架之外重用代码非常困难,但您可以将其用作灵感。系统的范围完全取决于您希望通过站点实现的目标。如果它比你大,你应该看看WCF系统。如果它很小的几个专用语言文件(de.php,en.php等),将包含当前语言的正确语言文件。

答案 5 :(得分:1)

不幸的是 gettext 无法正常工作,并且在各种情况下遇到问题,例如在不同的操作系统(Windows或Linux)上,并使其工作非常困难。

此外,它需要您设置很多环境变量和域,这没有任何意义。

如果开发人员想要简单地获取文本的翻译,他应该只设置.mo文件路径,并使用像translate这样的函数进行翻译(&#34; hello&#34;,&#34; en_EN&#34; );使用gettext这是不可能的。

答案 6 :(得分:1)

对上面值得给予赞扬的答案的扩展-我只是在发布,因为这可能对到此为止的其他人也很有用。

我个人更喜欢数组的键是母语(而不是英语)中的实际短语,而不是CONSTANT_VALUE,因为:

  • 我发现以文本为母语时更容易阅读代码,而不必记住CONSTANT_VALUE实际输出的内容
  • 这意味着无需查找即可返回同样使用我的母语(略微提高性能)的访问者的短语
  • 这是要维护的少一列值

缺点是,由于不再需要主列表,因此很难发现其他语言中的缺失值-我还记录了抽象方法的警告,以便发现任何缺失值。

我的实现方式是:

  • 具有用于输出文本值(使用后期静态绑定)的静态方法的抽象类
  • 每种语言的具体类:英语覆盖了不翻译而返回短语的方法,其他语言覆盖了短语列表,以便返回翻译后的短语
    <?php
    namespace Language;

    abstract class _Language
    {
        protected static $displayText = array();

        public static function output($phrase){
            return static::$displayText[$phrase] ?? $phrase;
        }
    }
    <?php
    namespace Language;

    class English extends _Language
    {
        public static function output($phrase){
            return $phrase;
        }
    }
    <?php
    namespace Language;

    class Spanish extends _Language
    {
        protected static $displayText = array(
            'Forename' => 'Nombre',
            'Registered Email' => 'Correo electrónico registrado',
            'Surname' => 'Apellido'
        );
    }

用法:

    $language = new \Language\Spanish();
    echo $language::output('Forename'); // Outputs: Nombre
    $language = new \Language\English();
    echo $language::output('Registered Email'); // Outputs: Registered Email

答案 7 :(得分:0)

为什么不把它作为多维数组......比如这个

<?php

$lang = array(
    'EN'=> array(
        'NO_PHOTO'=>'No photo\'s avaiable',
        'NEW_MEMBER'=>'This user is new',
    ),
    'MY'=> array(
        'NO_PHOTO'=>'Tiada gambar',
        'NEW_MEMBER'=>'Ini adalah pengguna baru',
    )
);

?>

答案 8 :(得分:0)

你可以这样做:

class T {
const language = "English";
const home = "Home";
const blog = "Blog";
const forum = "Forum";
const contact = "Support";
}

每种语言都有这样的文件。要使用文字:

There is no place like <?=T::home?>.

缺点是,如果添加新常量,则必须为每个langauge文件执行此操作。如果您忘记了一个,那么您的分页会破坏该语言。这有点令人讨厌,但它很有效,因为它不需要创建一个大的关联数组,并且可能值甚至内联。

也许可以改进访问,例如:

class T {
    const home = "home";

    public static function _ ($name) {
        $value = @constant("self::$name");
        return $value ? $value : $name;
    }

    // Or maybe through an instance:
    public function __get ($name) {
        $value = @constant("self::$name");
        return $value ? $value : $name;
    }
}
echo "There is no " . T::_("place") . " like " . T::_("home");
$T = new T();
echo "There is no " . $T->place . " like " . $T->home;

我们仍然避免使用数组并依赖constant进行查找,我认为这比直接使用常量更昂贵。上方是查找可以在找不到密钥时使用后备。