如何国际化PHP第三方库

Bol*_*wyn 11 php localization internationalization php-gettext

考虑编写一个PHP库,它将通过Packagist或Pear发布.它适用于在任意设置中使用它的同行开发人员.

该库将包含为客户端确定的一些状态消息.如何使此代码国际化,以便使用该库的开发人员可以尽可能自由地插入自己的本地化方法?我不想假设任何东西,特别是不强迫开发人员使用gettext.

要处理一个例子,让我们来看看这个类:

class Example {

    protected $message = "I'd like to be translated in your client's language.";

    public function callMe() {
        return $this->message;
    }

    public function callMeToo($user) {
        return sprintf('Hi %s, nice to meet you!', $user);
    }

}
Run Code Online (Sandbox Code Playgroud)

这里有两个问题:如何将private标记$message为翻译,以及如何允许开发人员在内部对字符串进行本地化callMeToo()

一个(非常不方便)选项是,在构造函数中要求一些i18n方法,如下所示:

public function __construct($i18n) {
    $this->i18n = $i18n;
    $this->message = $this->i18n($this->message);
}

public function callMeToo($user) {
    return sprintf($this->i18n('Hi %s, nice to meet you!'), $user);
}
Run Code Online (Sandbox Code Playgroud)

但我非常希望有一个更优雅的解决方案.

编辑1:除了简单的字符串替换外,i18n的字段很宽.前提是,我不想在我的库中打包任何i18n解决方案,或强迫用户专门选择一个以满足我的代码.

然后,我如何构建我的代码,以便为不同方面提供最佳和最灵活的本地化:字符串翻译,数字和货币格式,日期和时间,......?假设一个或另一个显示为我的库的输出.消费者可以在哪个位置或界面插入她的本地化解决方案?

ckr*_*use 7

最常用的解决方案是字符串文件.如下所示:

# library
class Foo {
  public function __construct($lang = 'en') {
    $this->strings = require('path/to/langfile.' . $lang . '.php');
    $this->message = $this->strings['callMeToo'];
  }

  public function callMeToo($user) {
    return sprintf($this->strings['callMeToo'], $user);
  }
}

# strings file
return Array(
  'callMeToo' => 'Hi %s, nice to meet you!'
);
Run Code Online (Sandbox Code Playgroud)

为了避免$this->message作业,你可以使用魔法吸气剂:

# library again
class Foo {
  # … code from above

  function __get($name) {
    if(!empty($this->strings[$name])) {
      return $this->strings[$name];
    }

    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以添加一个loadStrings方法,该方法从用户获取字符串数组并将其与内部字符串表合并.

编辑1:为了获得更大的灵活性,我会稍微改变上述方法.我会添加一个翻译函数作为对象属性,并在我想要本地化字符串时始终调用它.默认函数只查找字符串表中的字符串,如果找不到本地化字符串,则返回值本身,就像gettext一样.然后,使用您的库的开发人员可以将功能更改为他自己提供的功能,以执行完全不同的本地化方法.

日期本地化不是问题.设置区域设置取决于您的库使用的软件.格式本身是一个本地化的字符串,例如$this->translate('%Y-%m-%d')将返回日期格式字符串的本地化版本.

通过设置正确的区域设置和使用类似的功能来完成数字本地化sprintf().

但是,货币本地化是一个问题.我认为最好的方法是添加货币转换功能(并且,也许是为了更好的灵活性,另一个数字格式化功能),如果开发人员想要更改货币格式,可以覆盖该功能.或者,您也可以为货币实现格式字符串.例如%CUR %.02f- 在此示例中,您将替换%CUR为货币符号.货币符号本身也是本地化字符串.

编辑2:如果你不想使用setlocale你必须做很多工作......基本上你必须重写strftime()sprintf()实现本地化的日期和数字.当然可能,但很多工作.