在 PHP 中处理语言文件的最有效方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1414079/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 02:27:57  来源:igfitidea点击:

Most efficient way to do language file in PHP?

phpmultiple-languages

提问by JasonDavis

Questions Updated instead of making a new question...

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

I really want to provide a few alternative languages other then English on my social network site I am building, this will be my first time doing any kind of language translation so please bear with me.
I am researching so I am al ear and open to ideas and I have a lot already here is are the questions.

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

1)
What does i18n mean, I see it often when researching language translation on SO?

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

2)
Most people say use gettextPHP has an extension or support for it,
well I have been researching it and I have a basic understanding of it, as far as I can tell it is a lot of extra work to go this route,
I mean coding my site to use it's functions ie; _('hello world i'm in English for now')or else gettext('hello world i'm in English for now')is no problem as any route I go will require that.
But then you have to install gettext on your server and get it working,
then use some special editors to create special files and compile them I think?

2)
大多数人说使用gettextPHP 有扩展或支持它,
我一直在研究它并且我对它有一个基本的了解,据我所知,走这条路需要很多额外的工作,
我意味着编码我的网站以使用它的功能,即; _('hello world i'm in English for now')或者gettext('hello world i'm in English for now')没有问题,因为我走的任何路线都需要这样做。
但是你必须在你的服务器上安装 gettext 并让它工作,
然后使用一些特殊的编辑器来创建特殊的文件并编译它们我认为?

Sounds like a pain, I understand this is supposed to be the best route to go though, well everyone seems to say it is.
So can someone tell me why this is the route to go?

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

3)
I really like the simplicity of this approach, just building a language array and calling the phrase you need in a function like the example below , you would then just include a file with the appropriate language array.

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

What I really want to know is, would this be the less better performance method on a high traffic and fairly large site compared to using gettext and if so can you explain why please?

我真正想知道的是,与使用 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
?>

* some code used from brianreavis's answer below

* 一些代码来自以下 brianreavis 的回答

采纳答案by raspi

Don't reinvent the wheel. Use for example gettextor Zend_Translate.

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

回答by brianreavis

It'd probably be best to define a function that handles your language mapping. That way, if you dowant to change how it works later, you're not forced to scour hundreds of scripts for cases where you used $lang[...]and replace them with something else.

最好定义一个处理语言映射的函数。这样,如果您以后确实想更改它的工作方式,您就不会被迫在数百个脚本中搜索您使用过的情况$lang[...]并用其他东西替换它们。

Something like this would work and would be nice & fast:

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

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

Make surethe array is declared staticinside the function so it doesn't get reallocated each time the function is called. This is especially important when $langis really large.

确保该数组声明static在函数内部,因此不会在每个函数被调用一次重新分配。这在$lang非常大时尤其重要。

To use it:

要使用它:

echo lang('NO_PHOTO');

For handling multiple languages, just have this function defined in multiple files (like en.php, fr.php, etc) and require()the appropriate one for the user.

为了处理多国语言,只是有在多个文件中定义该功能(如en.phpfr.php等)和require()相应的一个用户。

回答by Rob Quist

This might work better:

这可能会更好:

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];
}

Thats what i use for now. If the language is not found, it will return the phrase, instead of an error.

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

You should note that an array can contain no more than ~65500 items. Should be enough but well, just saying.

您应该注意,一个数组最多可以包含约 65500 个项目。应该足够了,但很好,只是说。

Here's some code that i use to check for the user's language:

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

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

?>

Its not done yet, but well i think this might help a lot.

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

回答by Fragsworth

Don't write your own language framework. Use gettext. PHP has standard bindingsthat you can install.

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

回答by Jim Martens

As the other answers don't really answer all the questions, I will go for that in my answer plus offering a sensible alternative.

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

1) I18n is short for Internationalization and has some similarities to I-eighteen-n.

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

2) In my honest opinion gettext is a waste of time.

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

3) Your approach looks good. What you should look for are language variables. The WoltLab Community Framework 2.0implements a two-way language system. For once there are language variables that are saved in database and inside a template one only uses the name of the variable which will then be replaced with the content of the variable in the current language (if available). The second part of the system provides a way to save user generated content in multiple languages (input in multiple languages required).

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

Basically you have the interface text that is defined by the developer and the content that is defined by the user. The multilingual text of the content is saved in language variables and the name of the language variable is then used as value for the text field in the specific content table (as single-language contents are also possible).

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

The structure of the WCF is sadly in a way that reusing code outside of the framework is very difficult but you can use it as inspiration. The scope of the system depends solely on what you want to achieve with your site. If it is going to be big than you should definitely take a look at the WCF system. If it's small a few dedicated language files (de.php, en.php, etc), from which the correct one for the current language is included, will do.

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

回答by user149513

why not you just make it as multi-dimesional array...such as this

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

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

?>

回答by Federico Schiocchet

Unfortunately gettextnot work good and have problems in various situation like on different OS (Windows or Linux) and make it work is very difficult.

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

In addition it require you set lot's of environment variables and domains and this not have any sense.

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

If a developer want simply get the translation of a text he should only set the .mo file path and get the translation with one function like translate("hello","en_EN"); With gettext this is not possible.

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

回答by NateS

You can do this:

你可以这样做:

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

You would have a file like this for each language. To use the text:

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

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

The downside is that if you add a new constant, you have to do it for every langauge file. If you forget one, your page breaks for that language. That is a bit nasty, but it is efficient since it doesn't need to create a large associative array and possibly the values even get inlined.

缺点是如果你添加一个新的常量,你必须为每个 langauge file做它。如果你忘记了,你的语言就会分页。这有点讨厌,但它很有效,因为它不需要创建一个大的关联数组,甚至可能会内联这些值。

Maybe access could be improved, eg:

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

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;

We still avoid the array and rely on constantto do the lookup, which I assume is more expensive than using the constants directly. The up side is the lookup can use a fallback when the key is not found.

我们仍然避免使用数组并依靠常量来进行查找,我认为这比直接使用常量更昂贵。好处是查找可以在找不到键时使用回退。

回答by Steve

An extension to the answers above whom deserve the credit - I'm just posting as maybe this will also be useful to someone else who ends up here.

对上述谁值得称赞的答案的扩展 - 我只是发布,因为这可能对最终来到这里的其他人也有用。

I personally prefer the key to the array to be the actual phrase in my mother tongue (in my case English) rather than a CONSTANT_VALUE because:

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

  • I find it easier to read the code when the text is in my native language rather than having to remember what a CONSTANT_VALUE actually outputs
  • It means no lookup is needed to return the phrase for visitors who also use my naitive language (giving marginally better performance)
  • It's one less list of values to maintain
  • 我发现当文本是我的母语时更容易阅读代码,而不必记住 CONSTANT_VALUE 实际输出的内容
  • 这意味着不需要查找来为也使用我的天真的语言的访问者返回短语(提供稍微更好的性能)
  • 少一份需要维护的价值清单

The downside is that it's harder to spot missing values in other languages as you don't necessarily have a master list anymore - I also log a warning from the abstract method so that I spot any missing values.

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

I implemented as:

我实现为:

  • An abstract class with static methods for outputting the text value (using late static binding)
  • A concrete class for each language: English overriding the method to return the phrase without translation, other languages overriding the list of phrases so that a translated phrase is returned
  • 具有用于输出文本值的静态方法的抽象类(使用后期静态绑定)
  • 每种语言的具体类:英语覆盖返回没有翻译的短语的方法,其他语言覆盖短语列表以便返回翻译的短语
    <?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'
        );
    }

Usage:

用法:

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