对于那些感兴趣的人来说,PHP中有关本地化和国际化(i18n)的完全支持似乎终于开始实现了。详情请参考setlocale()函数。
$locale = Locale::acceptFromHttp(getenv('HTTP_ACCEPT_LANGUAGE'));
Locale::setDefault($locale);
setlocale(LC_ALL, $locale . '.UTF-8');
date_default_timezone_set('UTC');
iconv_set_encoding("internal_encoding", "UTF-8");
mb_internal_encoding('UTF-8');
有几个问题需要考虑,检测时区/语言环境并将其用于正确解析和显示输入/输出非常重要。最近发布了一个
PHP I18N库,其中包含大量此类信息的查找表,您可以使用它。
处理用户输入很重要,以确保应用程序从用户输入中获得干净、格式良好的UTF-8字符串。可以使用
iconv实现这一目标。
function encode($string, $to = 'UTF-8', $from = 'UTF-8')
{
if($to == 'UTF-8' AND is_ascii($string))
{
return $string;
}
return @iconv($from, $to . '//TRANSLIT//IGNORE', $string);
}
function is_ascii($string)
{
return ! preg_match('/[^\x00-\x7F]/S', $string);
}
那么只需将输入传递给这些函数即可。
$utf8_string = normalizer_normalize(encode($_POST['text']), Normalizer::FORM_C);
翻译
正如Andre所言,使用gettext似乎是编写可翻译应用程序的明智默认选择。
- Gettext使用一个相当快速的二进制协议。
- Gettext实现通常更简单,因为它只需要
_('Text to translate')
- 已经有了翻译者使用的工具,并且它们已被证明能很好地工作。
当你达到Facebook的规模时,可以开始实现RAM缓存和其他替代方法,比如我在问题中提到的方法。然而,对于大多数项目来说,没有什么能超过“简单、快速、有效”的做法。
然而,gettext还无法处理一些额外的内容,例如显示日期、货币和数字。对于这些内容,您需要使用INTL扩展。
function __date($locale = NULL, $datetype = IntlDateFormatter::MEDIUM, $timetype = IntlDateFormatter::SHORT, $timezone = NULL)
{
return new IntlDateFormatter($locale ?: setlocale(LC_ALL, 0), $datetype, $timetype, $timezone);
}
$now = new DateTime();
print __date()->format($now);
$time = __date()->parse($string);
此外,您可以使用
strftime来解析日期,考虑当前的语言环境。
有时您需要将数字和日期的值正确插入到本地化消息中。
function __($string, array $params = NULL)
{
return msgfmt_format_message(setlocale(LC_ALL, 0), $string, $params);
}
print __(_("{1,choice,0#no errors|1#single error|1<{1, number} errors}"), array(4));
print __(_("It is now {0,time,medium}), time());
请查看
ICU格式详细信息。
数据库
确保与数据库的连接使用正确的字符集,以便在存储过程中不会出现任何损坏。
字符串函数
您需要了解string, mb_string, 和 grapheme函数之间的区别。
// 'LATIN SMALL LETTER A WITH RING ABOVE' (U+00E5) normalization form "D"
$char_a_ring_nfd = "a\xCC\x8A";
var_dump(grapheme_strlen($char_a_ring_nfd));
var_dump(mb_strlen($char_a_ring_nfd));
var_dump(strlen($char_a_ring_nfd));
// 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5)
$char_A_ring = "\xC3\x85";
var_dump(grapheme_strlen($char_A_ring));
var_dump(mb_strlen($char_A_ring));
var_dump(strlen($char_A_ring));
域名顶级域名
INTL库中的IDN函数对处理非ASCII编码的域名有很大帮助。
_n()
函数,那么它只适用于一个单数/复数形式。有些语言不止两种形式。只有MessageFormatter
支持这些(如上面粗略示例所示)。 - Xeoncross_n()
只是一个示例,说明你如何使用工具。Gettext是一款成熟、强大、经过广泛测试和得到很好支持的工具。你来这里寻求建议,我推荐它。 - xmarcos