注意,这篇文章中的内容有点过时,与中文化开发包中的实现方法不完全一样,这里仅供参考。
Bash也是可以支持gettext以实现l10n的。比如
这里还有一个辅助翻译的emacs脚本,很简单的东西,就是选定字符串中要翻译的部分以后按F4,emacs会在选定的部分开头和结尾分别加上
PuppyLinux 4.0自带的bash不支持自动翻译,需要用自己编译的。
很不幸,上述的方法已经deprecated了。另外更加不幸的是,我这一段已经写过一遍,结果没有保存,现在还要返工,郁闷。。。
这个方法被标记过时的原因是bash的$""语法有潜在的安全隐患,翻译者有可能自己加入代码到$""中间去执行。另外由于$""一直都是bash没有公开的特性,虽然可以这么用,但它从来没有出现在任何正式的文档中。所以出了这样的隐患,似乎大家都没有兴趣直接在bash里修理这个问题,而是用了eval_gettext来替代,方法如下:
生成.po的方法也有所不同,因为bash不认得eval_gettext语法,
由于用eval_gettext方法,字符串里的某些字符需要额外的escape处理,这就使得标记需翻译段落的emacs脚本复杂了很多。用法还是和前面的一样。另外,标记过的字符串中会产生一大堆\\\,看上去可读性下降了一些。
LANG=zh_CN.utf8 TEXTDOMAIN="test" TEXTDOMAINDIR="/usr/share/locale" echo $"Add"这里在显示Add的时候,会先去/usr/share/locale/zh_CN/~LC_MESSAGES/test.mo搜索,看看能否将Add翻译成汉语显示出来。根据这个脚本很容易可以生成相应的.po文件以供翻译者翻译,用法如下
bash --dump-op-strings <脚本名>这很类似于python的pygettext。这里有个小问题,dump出来的.po文件中不包含codeset等信息,放在poedit里会出现乱码,所以还要自己加一个头,形如
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR ORGANIZATION # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # msgid "" msgstr "" "Project-Id-Version: zh_CN\n" "POT-Creation-Date: 2008-05-22 00:15+EDT\n" "PO-Revision-Date: 2008-05-22 18:41-0500\n" "Last-Translator: laborer <laborer@126.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n"另外有资料说xgettext也可以用于从bash脚本生成.po文件。
这里还有一个辅助翻译的emacs脚本,很简单的东西,就是选定字符串中要翻译的部分以后按F4,emacs会在选定的部分开头和结尾分别加上
"$"
和""
,这样选定的这部分就从原来的字符串中独立出来,并且被标记为可翻译(add-hook 'sh-mode-hook (lambda () (local-set-key [f4] (lambda () (interactive) (insert-pair nil "\"$\"" "\"\"")))))
PuppyLinux 4.0自带的bash不支持自动翻译,需要用自己编译的。
很不幸,上述的方法已经deprecated了。另外更加不幸的是,我这一段已经写过一遍,结果没有保存,现在还要返工,郁闷。。。
这个方法被标记过时的原因是bash的$""语法有潜在的安全隐患,翻译者有可能自己加入代码到$""中间去执行。另外由于$""一直都是bash没有公开的特性,虽然可以这么用,但它从来没有出现在任何正式的文档中。所以出了这样的隐患,似乎大家都没有兴趣直接在bash里修理这个问题,而是用了eval_gettext来替代,方法如下:
LANG=zh_CN.utf8 TEXTDOMAIN="test" TEXTDOMAINDIR="/usr/share/locale" . /usr/bin/gettext.sh echo "`eval_gettext "Add"`"eval_gettext是在第四行的gettext.sh脚本中定义的,所以需要先载入这个脚本。后面eval_gettext部分看似也就比$""方法复杂了一点点,但在实际使用中要复杂了很多。因为字符串中的一些符号会在第一个双引号中被bash解析一遍,之后又被eval_gettext解释一遍,所以很多都需要加额外的escape character,比如,原来在字符串中使用的
\"
要写成\\\"
,$X
要写成\\\$X
。单引号似乎不需要做什么改变,至少我测试的结果是这样,虽然很多文档上说也要用\修饰。由于各个脚本解释器可能在解析字符串中的内容时有所差别。所以使用这个方法有可能降低程序的可移植性。生成.po的方法也有所不同,因为bash不认得eval_gettext语法,
--dump-po-strings
也就无法获得想要的结果。这里就需要前面提到的xgettext,方法如下xgettext -L Shell -o SCRIPT_NAME.po SCRIPT_NAME生成出的.po文件已经包含头了,不需要另外再加。不过还是需要自己填写一下头中的charset字段。用这个方法就不需要再另外编译bash了。
由于用eval_gettext方法,字符串里的某些字符需要额外的escape处理,这就使得标记需翻译段落的emacs脚本复杂了很多。用法还是和前面的一样。另外,标记过的字符串中会产生一大堆\\\,看上去可读性下降了一些。
(add-hook 'sh-mode-hook (lambda () (local-set-key [f4] (lambda (beg end) (interactive "r") (when mark-active (setq bound (max beg end)) (setq start (min beg end)) (goto-char start) (while (search-forward "\\\"" bound t) (setq pos (point)) (replace-match "\\\\\\\\\\\\\"") (setq bound (+ bound (- (point) pos)))) (goto-char start) (while (search-forward "$" bound t) (setq pos (point)) (replace-match "\\\\\\\\\\\\$") (setq bound (+ bound (- (point) pos)))) (goto-char start) (push-mark start) (goto-char bound) (insert-pair nil "\"\"`eval_gettext \"" "\"`\"\"") )))))下面这个emacs脚本是搜寻程序中形如
MSG="`Xdialog ...`"并替换为可以使用eval_gettext的形式
MSG="Xdialog ..." MSG="`$MSG`"
(global-set-key [f5] (lambda () (interactive) (let ((var nil) (start nil) (bound nil) (pos nil)) (transient-mark-mode nil) (search-forward "=\"`Xdialog") (search-backward "=") (setq start (point)) (beginning-of-line) (setq var (buffer-substring-no-properties (point) start)) (push-mark) (search-forward "`\"\n") (transient-mark-mode t) (when (y-or-n-p "fix this? ") (setq bound (- (point) 1)) (open-line 1) (insert var "=\"`$" (car (split-string var)) "`\"") (goto-char (- bound 2)) (delete-char 1) (goto-char (+ start 2)) (delete-char 1) (setq start (+ start 2)) (setq bound (- bound 3)) (goto-char start) (while (re-search-forward "[^\\]\"" bound t) (backward-char 1) (insert "\\") (setq bound (+ bound 1)) ) ) )))
- 12050 次点击
发表新评论