【问题标题】:Best way to internationalize simple PHP website国际化简单 PHP 网站的最佳方式
【发布时间】:2011-10-20 16:16:41
【问题描述】:

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

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

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

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

hello: "Hello world!"

=> fr.yaml

hello: "Bonjour tout le monde !"

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

【问题讨论】:

  • 您不需要自己的函数。 _('my text')gettext('my text') 的别名函数。当您需要经常调用该函数时,该别名很方便,因为它的编写更少。
  • 不要使用框架,但如果使用 gettext,请务必使用 Zend_Translate 库和 gettext 适配器。 Zend 使 gettext 非常有用(否则它不是)。

标签: php internationalization multilingual


【解决方案1】:

尽管您不需要框架,但您可以使用框架。 Zend Framework 中的国际化功能非常好,您可以只使用它的一部分而不是使用所有部分(包括 MVC)

【讨论】:

  • 我可以将 i18n 模块从 zend 导入我的应用程序吗? (我已经有了自己的lightness MVC框架)
  • 如何只导入翻译部分?
  • 您可以只复制该部分,但您还需要依赖项。许多 Zend 框架模块大致依赖于以下内容:Zend_Exception、Zend_Locale...
  • 我要做的是包含我想要的模块,运行应用程序,它会抛出致命错误,说缺少某些模块。然后我也复制那个文件。但你也可以复制整个库。
【解决方案2】:

虽然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!');

【讨论】:

  • 是的,我刚刚用 i18n 结束了一个 Symfony2 支持的网站,所以选择它的组件是个好主意。但这个新项目是一个展示网站(最后不到 30 页......),有很多静态内容。其他非常有趣的答案谢谢。
  • 我只是实现了你的功能,只是为翻译文件添加了yaml支持而不是纯php数组!
  • @mowgli:您可能已经安装了ext/gettext_gettext 函数的别名。
  • 好的。受您的脚本启发,我做了一些事情:pastebin.com/XL3qSiRF 它也很简单并且效果很好(但可能需要改进/更多验证)
【解决方案3】:

Gettext 似乎是您所需要的。 有一个按语言划分的文件(原始文件除外),非常易于使用:

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

将打印你好,你好吗?用英语。

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

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

【讨论】:

    【解决方案4】:

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

    准备步骤 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 脚本中更改它。 重要提示:译者注释必须是注释的一部分紧接在 __() 函数之前,否则当我们扫描 PHP 文件以查找可翻译的字符串。

    // 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!
    

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

    #!/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
    

    要执行它,只需:

    cd /path/to/script && sh update.sh
    

    这将递归扫描该目录中的所有 PHP 文件并创建一个 .pot 文件(我称之为 i18n.pot,但您可以随意命名)并更新它找到的任何现有 .po 文件新的字符串。

    然后,我们需要创建将存储所有语言环境文件的目录,每个语言环境一个。它们的格式必须为./locale/{locale}/LC_MESSAGES。例如:

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

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

    define('TEXT_DOMAIN', 'yourdomain');
    bindtextdomain(TEXT_DOMAIN, __DIR__.'/locale');
    textdomain(TEXT_DOMAIN);
    bind_textdomain_codeset(TEXT_DOMAIN, 'UTF-8');
    

    然后要实际切换到另一个语言环境,请执行以下操作:

    $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));
    

    最初,您将上述脚本生成的.pot 文件发送给翻译人员。然后他们打开 Poedit 并点击File > New from POT/PO file。当他们保存它时,他们需要将它保存为{yourTextDomain}.po{yourTextDomain} 需要与您在 PHP 脚本中的文本域完全相同。当他们保存它时,它将自动创建.po 文件和.mo 文件。完成翻译后,这两个文件都需要保存在该语言的LC_MESSAGES 目录中。

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

    就是这样。设置起来可能有点困难,但是一旦设置并运行起来,就真的很容易了。

    【讨论】:

      猜你喜欢
      • 2010-12-21
      • 1970-01-01
      • 1970-01-01
      • 2010-09-10
      • 1970-01-01
      • 2010-12-09
      • 1970-01-01
      • 2020-11-27
      • 1970-01-01
      相关资源
      最近更新 更多