自从在PHP China上发布了我自己动手翻译的CSS 2规范中文版后,我体会到网络的力量。
几乎是在同时,两位热心的朋友就和我主动联系,要求转载,并完成了CHM文档的转化。并且友善的照顾到我个人私服的能力,给出了分流下载的地址。再此一并感谢他们!
他们的站点中关于CSS2的链接在此一并列出,作为纪念和对他们工作的感激。
同时,在此声明,目前我只授权了这两个站点的分流下载。
2002年6月,当我完成李维的《C++Builder 6 Soap/Web Service开发》一书的技术编辑工作后,应邀为这本书写了一个序,其中提到:
技术的发展永远是和现实需要相配套的。我们需要用一种新的概念和技术来解决当今极为分布的环境下,各应用之间互相集成的问题。幸运的是,这样的概念和技术已经出现了,它就是SOAP(Simple Object Access Protocol,暂译为“简化对象存取的协议 ”)和Web Service。
如今,创建一个Web Service已经是非常简单的工作了。在Visual Studio下,Web Service是一个现成的模板;几乎所有流行的脚本语言(PHP, Python, RoR, JavaScript)也都能支持对WS的调用。似乎所有的障碍和藩篱都已经撤除,我们可以顺利的进入WS的世界。
但是就在今天,当我和令狐兄就有关RPI系统的开发进行初步探索时,我的梦想却被无情的打破了。
令狐在他的BLOG里(链接:在此)写到:
查了一下资料说Encoded是SOAP规范里规定的编码方式,而另一种Literal则是使用SDL描述里定义的编码方式。但.NET默认的是后者。而很多客户端能识别的是前者(我查了,至少Python和Java的调用都需要修改这个编码方式)。不知道这是不是就是传说中的.NET的Web Service编码问题。但奇怪的是PHP的默认编码也是Literal,难道PHP和.NET关系这么好?
显然,对于一个“初级”开发者而言,牵涉到在VS中进行类似:[SoapDocumentService(Use= System.Web.Services.Description.SoapBindingUse.Encoded)]这样的设置确实有点太 “magic”了。
如此设置后,令狐用Python调用我在VS下开发的WS已经没有任何问题了。但是,我再次用PHP调用这个WS却出现了如令狐原来碰到的问题:当使用 Literal方式编码时,Python无法传递参数给WS的方法;而当使用Encoded方式编码时,PHP无法传递参数给WS的方法!
(你可以怀疑我的PHP功力,但是请你相信,我已经尝试了很多方法来修改我的PHP代码了。)
曾经我以为,有了WS,程序开发语言已经不是一个最大的问题。但是,我猜到了开头,却没有猜到结尾。
就如同HTML/CSS/XTHML一样,变种(mutant)的存在给原本简单的事情凭空增加了复杂度。而这一复杂化过程居然出现在Simple Object Access Protocol上,我只能怀疑Simple是不是用错了地方。
当然,在我们这个case中,我依然可以用Encoded方式编写WS,而让令狐兄用Python在另一端调用。而我,可以选择在当地用ASPX调试,或者干脆新学习一下Python。但这不是问题的关键,而且我也没有发言权。
打住。
地球人(包括火星人,前冥王星人,织女星系人)都知道,我的这个站点包含两个部分:一个是藏书/读书,一个是BLOG。由于BLOG是用的Word Press,没有什么可以让我多改动的地方,因此主要的改动出现在我的藏书页面。
今天完成了一个重要的功能,在书籍详细信息页面,我增加了一个加入用户自己的TAG的功能,用AJAX/XAJAX完成,也算是练兵。呵呵。
那为什么要加这个功能呢?一个当然是上面说的,练兵。
另一个原因是:这是WEB 2.0的要求。我自己在录入书籍时键入的TAG不一定是读者所认为的TAG,或者读者认为有更贴切、更适合他记忆的TAG存在。所以,有了这个功能,用户就可以自行添加。一来是补充我的不足,二来是方便用户日后搜索。
我现在还在考虑加入“自动补充”的功能。这样用户在增加一个“新”TAG的时候,可以清楚的知道,这个TAG是否已经存在于现有的数据库中了。
是日,上于股市继续保持受挫状态。终于出现红字。
下午与太子一起去邻里中心学习拼音,却带错了练习本无法练习写拼音。
回家后,上开始钻研两个问题:
就是这个看起来一般的问题,让我花费了差不多40分钟的之间去解决。开始我是怀疑OnKeyUp事件对中文输入不起作用,但是做了一个小的测试后发现不是这么回事。
输入的中文可以触发OnKeyUp事件。于是将注意力集中到数据库查询上。先是怀疑我构造的SQL语句无法搜索中文,但是在PHPMYADMIN中测试后发现SQL语句是正确的。 于是,这才将注意力集中到字符集上来了。
在搜索SQL之前插入如下两句SQL语句后,再次执行,果然该发生的终于发生了:
$dummy=set names utf8;
mysql_query($dummy, $conn);
这个问题说穿了还是MySQL返回字符串时使用的字符集的问题。这个问题我在之前的文章中已经描述过了,今天的解决方法还是完全一样。短短一个多月,我就忘记了这个问题,真是强烈的874自己。所以再次将这个问题写出来,再次的提醒自己。
PHP中如何实现i18n?如果你和我一样,最近也在集中精力解决一个多语种的站点的建设问题,那么也许你已经在考虑这个问题的解决方法了,或者已经有了自己的解决方案。那么就来看看我的吧。
PHP手册中,有一个关于gettext函数的说明,是这样说的:
The gettext functions implement an NLS (Native Language Support) API which can be used to internationalize your PHP applications. gettext函数实施了一个NLS(本地语言支持)API,可以用来国际化你的PHP应用。
我编程的一个原则是,如果有系统本身的函数,我是一定不会开发自己的函数的。所以我决定使用这个gettext函数来对我的站点进行i18n。 这是一个多语种的站点,因此根据用户的偏好(主要是语种设置)在界面上将显示相同内容但是不同语种的信息(缺省为英文)。例如:
//用户选择英文
Hello, today is July 29th, 2007.
//用户选择中文
你好,今天是2007年7月29日。
作为实施过程中最关键的一个环节,我们先集中在纯“静态”的内容之上。比如在英文语境下显示“Hello”而在中文语境下显示“你好”。
第一步,创建各语种对应的目录结构。 假定你的站点根目录为f:/temp(或/home/apple),那么先创建一个locale目录,然后对于你要支持的每个语种(除了缺省的“英语”)都要创建一个语种目录,并在该目录下创建一个LC_MESSAGES的目录。至于“语种”目录的命名,需要参考国际标准,例如:中文是zh-CN,加拿大英语是MARKDOWN_HASH22adf1e8cbf4b96513c1b5c3b5ef6e85MARKDOWNHASH等。**在Linux下,请将-替换为下划线()。**因此,如果我们要为中文、加拿大英文创建NLS内容,那么目录结构看起来应该差不多是这样的:
F:/temp/LOCALE
├─en_CA
│ └─LC_MESSAGES
└─zh_CN
└─LC_MESSAGES
第二步,编写一个所谓的PO文件,并将其编译为MO文件。你可以用专门的工具写PO文件并同时编译为MO文件,也可以用任何文本编辑器编辑PO文件,然后用专门的工具编译PO文件到MO文件。这个专门的工具我推荐poEdit。一般而言,一个PO文件的格式如下:
msgid
msgstr
Project-Id-Version: Apple
POT-Creation-Date:
PO-Revision-Date: 2007-07-29 17:01+0800
Last-Translator: Taylor Ren <taylor.ren@gmail.com>
Language-Team: 516' Studio
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Poedit-Language: English
X-Poedit-Country: UNITED STATES
X-Poedit-SourceCharset: utf-8
msgid Hello
msgstr 你好!
msgid Good
msgstr 好
我们可以很少关注最开始的几行代码。而我们真正要输入的是一个msgid-msgstr对,对于每个需要翻译的词组、短语,我们都应该给出对应的翻译。而且,这里的msgid-msgstr是可以嵌入参数的。例如:“今天是$y年$m月$日”。这样在真正输出时,就可以被当时赋值的变量替换。
如果我们在poEdit中编辑这些东西,那么在我们保存PO文件时,就会自动生成MO文件。只有MO文件可以被PHP使用。将这个MO文件保存到对应语种的LC_MESSAGES目录中去。
第三步,编写PHP脚本进行测试。
在测试前,我们必须保证在PHP中打开了gettext这个扩展。
在笔者的实践中,Windows和Linux的实现不同。假定这个index.php放在locale目录下。我们先看Windows的脚本:
putenv(LANG=en_CA);
setlocale(LC_ALL, '');
//setlocale(LC_ALL, 'en_CA'); //用这个在Windows下不起作用
// 指定翻译表的位置
bindtextdomain(default, ../locale);
// 选择域
textdomain(default);
// NLS的翻译会寻找../locale/en_CA/LC_MESSAGES/default.mo文件
// 打印一个测试消息
echo _(Hello); // _()是gettext()的快捷方式
echo _(Good).<br></br>;
// 来测试中文
putenv(LANG=zh_CN);
setlocale(LC_ALL, '');
bindtextdomain(default, ../locale);
textdomain(default);
//NLS的翻译会寻找../locale/zh_cn/LC_MESSAGES/default.mo文件
// 打印一个测试消息
echo _(Hello). ;
echo _(Good).<br></br>;
测试文件的地址在这里。(en_CA的翻译是随便乱写的,只是为了演示而已。)
Linux的脚本基本同上。但是要注意两点:
第一,Linux下推荐使用setlocale(LC_ALL, \'en_CA\');,此时不用putenv(LANG=en_CA.);setlocale(LC_ALL, \'\');
第二,Linux下的语种名必须是Linux支持的语种。支持的语种列表可以在/usr/lib/locale中找到,或者用locale -a命令列出。而且,必须使用utf8后缀。所以,完整的写法是setlocale(LC_ALL, zh_CN.utf8);
测试文件的地址就不列出来了。用户可以自己测试。 用这个方法进行i18n的工作,我个人觉得还是很直观、很快捷的。
装了个GNOME Commander,由于之前我曾经不自量力的想自己编译这个软件,所以可能是在系统中留了一些残渣,造成后来我用apt-get安装后无法运行的问题。
于是手工清除所有自己编译的残余,然后重新安装,一次成功。
界面和我在Windows下使用的Total Commander有的一拼,真的8错。
今天测试了一下从MySQL中获得中文数据,发现需要进行一些处理才能在网页中完美显示中文(在PHPMYADMIN中插入、显示是正常的):
首先,当然是你的MySQL数据库是基于UTF-8建立的。 然后是在PHP中的常规连接:
$hostname_test = localhost;
$database_test = test;
$username_test = root;
$password_test = xxxxxx;
$test = mysql_pconnect($hostname_test, $username_test, $password_test) or trigger_error(mysql_error(),E_USER_ERROR);
$query=select * from chinese; mysql_select_db($database_test, $test);
**$xx=set names utf8; mysql_query($xx);**
$rs=mysql_query($query, $test);
while($row=mysql_fetch_object($rs))
{
echo $row->id.<br/>;
echo $row->desc.<br/>;
echo =====================
<br/>;
}
注意上面的黑体部分,这两行很关键。
再然后是在PHP文件中要指定字符集:
<head> <meta http-equiv=Content-Type content=text/html; charset=utf-8> </head>
注意,这里要写utf-8,而set names时要写utf8。
因为有Netgear的SC101,所以很关心它的Vista驱动开发进展。
从3月份开始,官方网站的声明都是Will be available in the first half of 2007.
今天再次去同一个地方看有没有新消息,果然声明改为了Will be available in 2007 Q3.
跳票了……