国际化简单PHP网站的最佳方式

时间:2011-08-05 08:34:56

标签: php internationalization multilingual

我必须开发一个非常简单的php网站,所以我不需要框架。 但它必须支持多语言(EN / FR / CHINESE)。 我已经找了php内置系统,我找到了两种方法:

我没有没有框架的i18n经验,所以有关支持多语言的最简单方法的建议吗?

最后我只需要一个搜索翻译到文件的功能(一个文件按语言)。 情商: trans('hello');

=> en.yaml(yaml与否,这是一个例子)

hello: "Hello world!"

=> fr.yaml

hello: "Bonjour tout le monde !"

如果可能的话,我更喜欢Pure PHP实现

4 个答案:

答案 0 :(得分:19)

虽然ext/gettextext/intl都与i18(国际化)相关,gettext处理翻译,而intl处理数字和日期显示等国际化,排序顺序和音译。所以你真的需要两个完整的i18解决方案。根据您的需求,您可以依靠上面提到的扩展或某些框架提供的使用组件来提出自制解决方案:

如果你只需要翻译并且网站足够简单,也许你的简单解决方案(将翻译配置文件读入PHP数组,使用简单的函数来检索令牌)可能是最简单的。

我能想到的最简单的解决方案是:

$translation = array(
    'Hello world!' => array(
        'fr' => 'Bonjour tout le monde!',
        'de' => 'Hallo Welt!'
    )
);

if (!function_exists('gettext')) {
    function _($token, $lang = null) {
        global $translation;
        if (   empty($lang)
            || !array_key_exists($token, $translation)
            || !array_key_exists($lang, $translation[$token])
        ) {
            return $token;
        } else {
            return $translation[$token][$lang];
        }
    }
}

echo _('Hello World!');

答案 1 :(得分:13)

我知道这是一个老问题,但我觉得答案从头到尾缺乏更实际的方法。这就是我在不使用Debian服务器上的任何其他PHP库时使用PHP's gettext libraryPoedit进行翻译的方法:

准备步骤1:在服务器上安装gettext和区域设置

我不确定如何使用其他操作系统,但对于Debian,您可以:

sudo apt-get install gettext
sudo dpkg-reconfigure locales

编辑:我认为Ubuntu与Debian相同,但显然它略有不同。有关在Ubuntu上安装区域设置的说明,请参阅this page

确保选择要使用的区域设置的全部。然后你应该看到类似的东西:

Generating locales (this might take a while)...
  en_US.UTF-8... done
  es_MX.UTF-8... done
  fr_FR.UTF-8... done
  zh_CN.UTF-8... done
Generation complete.

注意:确保为每种语言选择正确的变体字符编码(最有可能是UTF-8)。如果您安装es_MX.UTF-8并尝试使用es_ES.UTF-8es_MX.ISO-8859-1,那么它将无法正常使用。

准备步骤2:在翻译器上安装Poedit'计算机

Poedit可从大多数Linux操作系统的软件存储库中获得。对于基于Debian的,只需执行:

sudo apt-get install poedit

对于Windows和Mac,请转到:https://poedit.net/download

开始编码:

好的,现在您已准备好开始编码了。我编写了以下gettext()包装函数来翻译单数和复数:

function __($text, $plural=null, $number=null) {
    if (!isset($plural)) {
        return _($text);
    }
    return ngettext($text, $plural, $number);
}

使用示例:

// Singular
echo __('Hello world');

// Plural
$exp = 3;
printf(
    __(
        'Your account will expire in %d day',
        'Your account will expire in %d days',
        $exp
    ),
    $exp
);

这适用于所有语言,而不仅仅是复数为n != 1的语言 - 这包括多种复数类型的语言。

您还可以添加如下翻译说明:

/** NOTE: The name Coconut Hotel is a brand name and shouldn't be 
 translated.
*/
echo __('Welcome to Coconut Hotel');

您可以将文本从NOTE更改为您想要的任何内容,但您必须在下面的shell脚本中更改它。 重要:译员注意必须是紧接在<{1}}功能之前行的注释的一部分,否则我们扫描时不会被选中可翻译字符串的PHP文件。

__()

准备好将字符串发送给翻译人员后,将以下内容保存为应用程序根目录中的shell脚本(例如update.sh):

// Warning! THIS WILL NOT WORK!
/* NOTE: This translator's note will not be picked up because it is
not immediately preceding the __() function. */
printf(
    __(
        'Your account will expire in %d day',
        'Your account will expire in %d days',
        $exp
    ),
    $exp
);
// Warning! THIS WILL NOT WORK!

要执行它,只需执行:

#!/bin/sh
find . -iname "*.php" | xargs xgettext --add-comments=NOTE --keyword=__:1,2 --keyword=__ --from-code=UTF-8 -o i18n.pot
find . -name '*.po' | xargs -I{} msgmerge -U {} i18n.pot

这将递归扫描该目录中的所有PHP文件,并创建一个cd /path/to/script && sh update.sh 文件(我称之为.pot,但随时可以随意命名)并更新任何现有的{{1}它使用新字符串找到的文件。

然后,我们需要创建将存储所有区域设置文件的目录,每个区域设置一个。它们必须采用i18n.pot格式。例如:

.po

您需要决定要使用的文本域。这可以是您想要的任何内容,但脚本将在该语言的LC_MESSAGES文件夹中查找名为./locale/{locale}/LC_MESSAGES的文件。将以下内容放在PHP脚本中:

cd /path/to/your/project
mkdir -p ./locale/en_US.UTF-8/LC_MESSAGES
mkdir -p ./locale/es_MX.UTF-8/LC_MESSAGES
# ...etc.

然后要切换到另一个区域设置,请执行:

{yourTextDomain}.mo

最初,您将上述脚本生成的define('TEXT_DOMAIN', 'yourdomain'); bindtextdomain(TEXT_DOMAIN, __DIR__.'/locale'); textdomain(TEXT_DOMAIN); bind_textdomain_codeset(TEXT_DOMAIN, 'UTF-8'); 文件发送给翻译人员。然后他们打开Poedit并点击$lang = 'es_MX.UTF-8'; // Change this to the language you want to use if (setlocale(LC_ALL, $lang) === false) { throw new Exception("Server error: The $lang locale is not installed"); } putenv('LC_ALL='.$lang)); 。当他们保存时,他们需要将其保存为.potFile > New from POT/PO file需要与PHP脚本中的文本域完全相同。保存后,它会自动同时创建{yourTextDomain}.po文件和{yourTextDomain}文件。这些都需要在完成翻译时保存在该语言的.po目录中。

现在,当您更新PHP文件中的字符串时,只需重新执行shell脚本并将新更新的.mo文件发送给翻译人员。然后他们翻译字符串,LC_MESSAGES.po文件都需要重新上传。

那就是它。设置起来似乎有点困难,但是一旦你启动并运行,它就非常容易。

答案 2 :(得分:3)

Gettext似乎就是你所需要的。 langage有一个文件(原始文件除外),它很容易使用:

echo _('Bonjour, ça va ?');

会打印你好,你好吗?用英语讲。

some tools gettext可以扫描你的php文件并搜索可翻译的字符串(实际上是_()或gettext()中的所有字符串)。多亏了你,你不必担心不同的语言文件。您只需使用原始语言对网站进行编码,然后将自动创建langage文件。

尽管如此,gettext更像是一种翻译工具,而intl实际上是一种i18n(例如数字格式化)

答案 3 :(得分:1)

虽然你不需要一个可以使用框架的框架。 Zend Framework中的国际化功能相当不错,您只需使用它的一部分而不是使用所有部分(包括MVC)