PHP 的多语言支持一般怎么做?

2014-11-19 13:47:25 +08:00
 lincanbin
前几天Github上不知道为什么跑过来个人,资料上写着加州,说想他很喜欢我的程序想让我做个多语言支持。(这点很奇怪,我的项目是全中文的,他是怎么跑过来的?)
我从来没做过多语言支持,想问问怎么做兼容性和性能最好?(因为是开源项目要在大部分机器上都能跑,例如IIS、Apache还有PHP5.3~5.6的各个版本的组合,所以靠外挂C拓展是不行了)

搞个language的dict,然后替换掉模板里的中文?这样怎么样?如果是这样,那么用dict好还是用一长串的常量好?
5486 次点击
所在节点    问与答
14 条回复
breestealth
2014-11-19 16:31:22 +08:00
这不就是最基本的语言包功能么?将所有的字符串提取出来当作语言包,然后挨个替换就可以了。
具体可以看看 Kohana 或者其他框架对多语言的实现也就是了。
kmvan
2014-11-19 16:41:59 +08:00
wp可参考
Showfom
2014-11-19 16:43:15 +08:00
现在的网站都很先进的根据浏览器第一第二语言来适配了
loserwn
2014-11-19 16:46:11 +08:00
可以考虑使用 gettext 和 po 来实现。
regmach
2014-11-19 16:55:14 +08:00
某框架使用数据库或者文本存储翻译信息
界面所有文字都使用方法调用
用户访问时根据设置自动调用即可
unidotnet
2014-11-19 16:58:09 +08:00
1.需要翻译的全部用英文,自定义函数输出。
2.创建一堆对应的模版,比如,locale.en locale.zh_cn
3.文件里写 hello=你好
lincanbin
2014-11-19 17:01:06 +08:00
@breestealth 我看他们都用的hashtable,常量有什么缺陷吗?
@regmach gettext不少虚拟主机不带的吧。
raincious
2014-11-19 17:25:56 +08:00
@lincanbin

常量你要一个个定义,会让程序变得很复杂。

另外如果你使用常量,就等于定义了一个全局量(无论const还是define),这样很明显会污染Scope。

联系到你之前论坛的实现方法,可能对Scope污染不敏感,但是减少全局量和Public Accessable量有助于降低非规范的调用,借此提高程序质量。(这就是有些东西需要封装的原因)

而Hashtable本身其实不慢,只是内存占用的问题比较突出。(所以要简化和最小化加载的数据)。

多语言还是用gettext这样成熟的方案然后产生语言包就好了。如果需要自己做,自己写个格式来读取语言表(比如$lang->get_my_text('this is a test')),然后放到模板里就行了。

(是的,我已经开始想实现方案了)

$lang = new Lang($request->get_client_language(), $setting);

<? echo $lang->get_text('this is a text %s', $value) ?>

// 哈哈,其实这就是框架的作用,打包好底层功能,然后愉快的使用就行了

=====================================================================

下面是我的实现方法,没用gettext,仅供参考:

// 加载方法,加载好存到LanguageMap里
https://github.com/raincious/facula/blob/master/src/Facula/Base/Prototype/Core/Template.php#L1264

// 编译模板的时候主动强制加载(如果未加载过)
https://github.com/raincious/facula/blob/master/src/Facula/Base/Prototype/Core/Template.php#L1165

// 后面的工作交给模板编译器自行决定如何处理,这是框架自带的标准模板编译器的处理方法
https://github.com/raincious/facula/blob/master/src/Facula/Unit/Paging/Compiler/Operator/Language.php#L131

// 按照上面那个模板引擎的Tag写的HTML模板,注意lang标签,比如“{lang TITLE_HOME_WELCOME /}”
https://github.com/raincious/facula/blob/master/examples/BasicStart/privated/Templates/template.home.htm

// 语言格式文件
https://github.com/raincious/facula/blob/master/examples/BasicStart/privated/Templates/language.zh%2Bhome.txt

语言文件仅在需要的时候(需要重新渲染或者需要读出用户消息)加载(并缓存),因此开销不算太大。我正在想着如何将其中“用户消息”的语言格式独立出来,这样开销会更低,但是一直苦于实现不太优雅。
lincanbin
2014-11-19 17:45:01 +08:00
@raincious 我做了一个循环50万次的测试,HashTable相比常量性能差距并不是太多,即使是循环50万次性能也相当接近。
而且我一个页面里的需要翻译的字符串也不多,最多就几十个,用HashTable应该也是比较划算的,一个页面多开销的时间应该不会超过50μs,内存开销也差不了几个Bytes,在可以接受的范围内。
cougar
2014-11-19 18:00:41 +08:00
joomla 和 Drupal里面的多语言支持做的很棒。可以下个看看
raincious
2014-11-19 18:02:59 +08:00
@lincanbin 我也说了,HashTale和const之前的区别在于管理性。常量定义这么大的数据很明显是不合适的。

而且常量是不能注销的(除非你用Runkit),因此如果你加载了一个用常量定义的语言文件,那么它就一直在那了。

所以综合各种迹象,你不应该纠结常量和HashTable的问题。直接用HashTable(Array)是最好的方案。

当然,如果你是自己的小项目,管理语言文件还是挺复杂的,考虑用gettext(_())实现好了,很多成熟的开源系统都有应用,有很多例子。自己去弄,每次项目变更都需要同步修改很多的语言文件,负担比较大。
learnshare
2014-11-19 18:09:28 +08:00
Gettext 是比较普遍的方案,网上也有一些提供翻译资源托管的地方,可以让不同国家的人来翻译,like https://www.transifex.com/
regmach
2014-11-19 19:37:37 +08:00
不是gettext, 就是PHP框架自带的适配方法而已.
breestealth
2014-11-20 08:50:13 +08:00
@lincanbin 常规做法是使用 array 而已,常量的用法没有做过。从程序逻辑来看是可以满足需求,但与 array 方法比没有什么明显优势。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/147718

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX