编写国际化软件的一些提示
笔记,摘自 Internationalization Tips,基于国际化工具 GNU gettext
。
1. 不要分割整句
例如
String s = i18n("Press OK to delete ") + n + i18n(" files");
这样把一句话拆成几部分,在抽取字符串资源后,翻译人员在看到 " files"
这样的字符串时会莫名其妙,翻译到其他语言里很有可能意思不伦不类,表达不清。而且 像 " files"
这样短的词会整个程序中出现多次,并不能保证在每个语境下都是同一个 意思。
这种情况下应该使用占位符
printf(i18n("Press OK to delete %d files"), n);
这里还提到了一个C语言里的技巧:编译时于预处理器会将连续多行的字符串字面量 自动拼接,合并成一个,这样在写很长的字符串时,可以拆成多行来写。
2. 避免同时使用多个占位符
例如
printf("Press OK to %s %d file(s)", action, number);
像这样一条句子里使用了两个占位符,由于后面的参数位置写死在代码里,在翻译时,翻 译字符串中的占位符也必须依照参数的顺序,在某些语言习惯里,可能造成翻译困难或者 不够地道。比如
printf("You should say %s when %s comes.", hello, somebody);
当翻译成中文时
printf("当%s来的时候,你得说%s", somebody, hello);
后面的参数需要调整顺序。
由于C语言的 printf
族函数并不提供类似 C#、Python 那种 {0}
带序号的占位符用法,所以使用多个占位符不是明智之举。虽然标准库不支持,但是有一 些第三方库可以做到,例如 win32 下的 FormatMessage
和 java 的 MessageFormat
,还可以考虑 Qt。
其实个人觉得 Ruby 中的变量名占位符更好,翻译时候翻译人员可以根据有意义的变量名 来翻译,而不是数字。
当然,和作者再三强调的一样,最好的方法就是避免使用多个占位符。
3. 多复数处理
在某些语言中,单数和复数表达可能不一样。
例如
printf(i18n("You have won %d point(s)!"), n);
当 n == 1
时,输出 "1 points"
就欠妥当,最好修改成
if (n == 1)
printf(i18n("You have won one point!"));
else
printf(i18n("You have won %d points!"), n);
注意,这还没完,并不是所有语言就仅仅区分 n == 1
和 n != 1
这两种情况, 有些语言中,当 n == 101
时,也应当使用单数。
用硬编码来处理所有这些情行则会把代码弄得臃肿不堪,gettext 则提供了解决方法:ngettext
。
4. 翻译歧义
在编码时要注意多义词的处理。比如英文单词 right ,表示方向时是 右 的意思, 在表示对错时是 对 的意思。这个时候就需要给字符串加上前缀来以示区别。
作者给了个菜单项的例子,使用 |
来作为前缀
Menu|File
Menu|Printer
Menu|File|Open
Menu|File|New
Menu|Printer|Select
Menu|Printer|Open
然后使用一个新函数来查找翻译字符串
char * sgettext (const char *msgid)
{
char *msgval = gettext (msgid);
if (msgval == msgid)
msgval = strrchr (msgid, '|') + 1;
return msgval;
}
这个方法有几个缺点
* 包含了 `|` 字符的字符串不能这样来处理
* 翻译人员必须清楚只有 `|` 字符之后的字符串才是翻译的内容
* 开发者也许只用 `sgettext` 函数,并没有注意到字符串是否包含有 `|`
从这点上看,个人认为 MSVS 那套字符串也是有优势的。
推荐一篇文章
文章讲述C编程里的一些注意点,涉及命名、风格、数据结构。作者是 Rob Pike。
其中关于注释、复杂度、数据驱动以及函数指针这几小节特别值得一读。
简要笔记:
注释
作者倾向于少写注释,只写必要的
- 代码清晰,命名良好的代码应该是自解释的
- 编译器不会检查注释,不能保证注释是正确的,尤其是代码已经修改而注释没有更正
- 注释会打乱代码的排版
- 注释用于解释全局变量或类型的用法,介绍不寻常或者重要的子程序,将大量计算划分小节
- 避免花哨的注释
- 给数据写注释要比算法注释有用的多
- 如果代码需要注释来帮助理解,那么应该考虑重写以便于理解
复杂度
作者认为大部分程序写的过于复杂源于不好的设计,但是没有讲设计而是给了6条规则
- 避免过早优化
- 在没有测定程序运行效率前,不要进行优化
- 高级算法在数据规模小的时候会变慢,除非确信数据规模很大,不要使用高级算法。就算 数据规模很大,首先考虑规则2
- 高级算法比简单算法更难实现,更容易滋生bug,使用简单算法和简单的数据结构
- 数据主导。使用了正确的数据结构,那么算法就很清晰明了
- 没有规则 6
总结起来2点:杜绝过早优化,数据主导
包含文件
包含文件不应包含已经被包含的文件
避免编译依赖和物理耦合
PS:这里介绍两个技巧
碎碎
昨晚捣鼓下了 Debian 7.2 Xfce 的 CD,结果被坑了,安装选了中文进入系统是不带中文字体的, 都是方框和HEX数字。后来换了163的源安装字体后好了,大概用了用还是感觉没有 XUbuntu 开箱 即用来的方便。
今晚一直在 XUbuntu 下捣鼓代码,才意识到一个长久以来的问题:我总是很艰难地在 Bash 的输出 里找到从哪里开始是当前命令的输出结果。我想要是能把输入的命令或者提示符修改一个颜色,就容易 分辨了。
在我谷歌一番 change bash prompt color 后,果然找到了一篇文章讲方法。对着方法去修改 .bashrc
文件中的 PS1
环境变量时,发现里面已经有这个功能了:
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
取消注释,启用即可...
_(:з」∠)_
秋冷
长久没在线了,这次出差了一个半月,再加上十一在家的时间,基本上算是离线快两个月了。
这次出差不算累,但是压力感觉比较多,神经性皮炎有萌出的迹象。包括现在回来,依旧觉 得自己身体机能上,不是太健康。我自己不是个很能抗压的人,压力之下的思维和心境会很 影响创作和效率。
这么长的离线时间,我觉得对自己是个很好的心境历练,在出差的时候,呆在广州的那种烦躁 感少了很多。也有相当充裕的时间来思考一些问题。
近期列的计划
- 继续看《代码大全》
- 重读《Progamming in Lua》
但愿能抽得出空...
Windows 下修改 Inkscape 和 Gimp 字体
基于Gtk+的程序运行在Windows下默认字体是很简陋的,修改方法基本是一致的,可以参照这篇文章GTK+ 程序字体的设置(被墙)。
以 Gimp 2.8.6 为例,找到程序安装目录,然后进入 ..\etc\gtk-2.0\
目录,打开gtkrc.zh_CN
(根据系统语言环境后缀名可能不同,比如繁体对应 gtkrc.zh_TW
)文件,如果不存在则新建,修改内容为:
style "user-font" {
font_name = "Microsoft YaHei 10"
}
widget_class "*" style "user-font"
gtk-font-name="Microsoft YaHei 10"
这样就会使程序的字体变为微软雅黑。
如果不行则说明程序默认没有使用Native Window Syle,这时,打开目录下的 gtkrc
文件,将其内容修改为:
gtk-theme-name = "MS-Windows"
保存后重开程序即可。
PS: 在默认安装下,Gimp 只需前一步即可修改字体,而 Inkscape 则需要第二步才能完成字体修改。