【问题标题】:Most efficient way to do language file in PHP?在 PHP 中处理语言文件的最有效方法是什么?
【发布时间】:2010-11-27 16:43:31
【问题描述】:

问题已更新,而不是提出新问题...

我真的想在我正在构建的社交网站上提供除英语以外的其他语言,这将是我第一次进行任何语言翻译,所以请多多包涵。
我正在研究,所以我耳熟能详,对想法持开放态度,我已经有很多问题了。

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

2)
大部分人都说用gettextPHP有扩展或者支持,
嗯,我一直在研究它,我对它有一个基本的了解,据我所知,走这条路需要做很多额外的工作,
我的意思是对我的网站进行编码以使用它的功能,即; _('hello world i'm in English for now') 或者 gettext('hello world i'm in English for now') 任何路线都没有问题我去会需要那个。
但是你必须在你的服务器上安装 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 回答中使用的一些代码

【问题讨论】:

  • 您知道不必在数组中使用 _,但是是的,您可能应该使用 php 扩展而不是自己滚动。

标签: php multiple-languages


【解决方案1】:

最好定义一个处理您的语言映射的函数。这样一来,如果您确实想在以后更改它的工作方式,就不必为使用 $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() 中为用户定义一个合适的函数即可。

【讨论】:

  • 仅供参考,此解决方案不如 Fragsworth 的建议:gettext。 Gettext 绝对是这类事情的更好途径。但是,如果您要推出自己的基本系统,您会这样做。
  • 嗨,我喜欢这个解决方案!我来自 C#,我怀疑静态变量在 PHP 中的工作方式。当你在 C# 中声明一个静态变量时,例如一个数组,它保存在内存中,你只需要加载一次,它的值在不同的用户线程之间保持不变。但据我所知,在 PHP 中,它在每次执行中都会失去价值,如果你想把东西保存在内存中,你必须使用 APC 之类的替代方案。那么为什么@brianreavis 你建议将其设为静态而不是每次都“重新分配”?谢谢!
  • @RobertoZamora 是的——我的意思是不需要为每次调用重新分配它。 PHP 执行随着每个请求而生死。要持久保存任何东西,您必须研究 APC(或类似的)。
  • 当我使用这个 $day1Txt = Day_1_Offer('EMAIL_OFFER'); 时出现错误;
【解决方案2】:

这可能会更好:

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');
}

?>

它还没有完成,但我认为这可能会有很大帮助。

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 今天发布之前我只是浏览了gettext页面,我无法真正弄清楚它是如何工作的,你能解释一下吗?
    • jasondavis:它完全符合您的要求,甚至更多。当你安装它时,你选择一个地方来放置你的语言翻译文件(“.po”)。您可以翻译此文件中的所有字符串。然后在您的源代码中,您使用 gettext()(或通常是别名,'_()')包装所有多语言字符串,它将为您提取该字符串的当前翻译。它还提供了复数短语和其他一些您认为必要的重要功能。
    • @future 读者,我会说,如果您的网站或应用程序不使用数百到数千个单词,那么采用关联数组方式比 gettext 更好。 Gettext 在其实现中非常过时,调试起来可能是一场噩梦。我只花了三天时间试图让它在我的服务器上工作。它有很多问题,而且维护得不好。相信我,你会遇到它的一些问题。最好使用 php-gettext(gettext 模拟器)、其他一些实现或编写自己的库。
    • @EmmanuelNK 我同意。 gettext 坏了。另外,它需要一些特殊文件。另外,重新编译 .po 文件有时需要重新启动服务。
    【解决方案4】:

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

    【讨论】:

    • Zend_Translate 链接已过时,v1 框架使用this link,v2 框架使用this one
    • 至少对于windows来说,gettext还是那么糟糕。
    【解决方案5】:

    由于其他答案并不能真正回答所有问题,我将在我的答案中继续这样做,并提供一个明智的选择。

    1) I18n 是 Internationalization 的缩写,与 I-eighteen-n 有一些相似之处。

    2) 老实说,gettext 是浪费时间。

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

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

    遗憾的是,WCF 的结构在某种程度上重用框架之外的代码非常困难,但您可以将其用作灵感。系统的范围完全取决于您希望通过您的网站实现的目标。如果它比你要大,你绝对应该看看 WCF 系统。如果它是一些专用语言文件(de.php、en.php 等),其中包含当前语言的正确文件,就可以了。

    【讨论】:

    • 2) 老实说,gettext 是浪费时间。 - 确实!
    【解决方案6】:

    你为什么不把它做成多维数组……比如这个

    <?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',
        )
    );
    
    ?>
    

    【讨论】:

    • 这会使用比必要更多的内存---因为这会为 every 请求加载 every 语言。最好将其分解为多个文件并加载单个适当的文件。
    【解决方案7】:

    你可以这样做:

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

    对于每种语言,您都会有一个这样的文件。使用文本:

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

    不利的一面是,如果您添加一个新常量,您必须为每个语言文件执行此操作。如果您忘记了其中一个,您的分页会因该语言而中断。这有点讨厌,但它很有效,因为它不需要创建一个大的关联数组,甚至可能值会被内联。

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

    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 进行查找,我认为这比直接使用常量更昂贵。好处是查找可以在找不到键时使用回退。

    【讨论】:

      【解决方案8】:

      对以上值得称赞的答案的扩展 - 我只是发布,因为也许这对最终在这里的其他人也有用。

      我个人更喜欢数组的键是我母语(在我的情况下是英语)中的实际短语,而不是 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
      

      【讨论】:

        【解决方案9】:

        不幸的是,gettext 不能很好地工作,并且在不同的操作系统(Windows 或 Linux)上等各种情况下都会出现问题,使其工作非常困难。

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

        如果开发人员只想获取文本的翻译,他应该只设置 .mo 文件路径并使用 translate("hello","en_EN"); 之类的一个函数来获取翻译。使用 gettext 这是不可能的。

        【讨论】:

          猜你喜欢
          • 2015-02-14
          • 2014-01-27
          • 2014-04-11
          • 2011-09-30
          • 1970-01-01
          • 1970-01-01
          • 2023-03-23
          相关资源
          最近更新 更多