ruby way之国际化之二

本文介绍了如何在Ruby中处理国际化与本地化问题,包括Unicode字符串规范化、排序、编码转换等,并详细讲解了如何使用gettext库实现消息目录的创建与维护。
5规范化unicode字符串

这张没什么意思,它讲的是将一些拉丁文的音调和表示分开来表示,比如"é" 可以表示为e 和'.对我们来说,没有多大的用处,就不说了。

不过这张介绍了一个unicode的库,大家想看的话可以去看看

http://www.yoshidam.net/Ruby.html

6字符串的排序

这张也是没多少意思,对我们来说,这张讲的是对拉丁文,西班牙文之类的字符的排序,作者所作的是把那些字母的发音用上一小节所用到的Unicode库,单独那出来,然后再 进行排序.

这边要注意的是,对于array.sort他的排序,是通过解码后字节大小来进行排序的:

[code]eacute = [0x4E2D].pack('U')
acute = [0x56FD].pack('U')
puts array = ["人", "#{eacute}", "#{acute}"]
puts array.sort

puts array.map {|item| "#{item}: #{item.unpack('C*')[0,3].join(',')}" }[/code]

7编码之间的转换

ruby的标准库里面包含了一个iconv的库来将字符串在不同的编码之间转换

如果你想要转换UTF-8到 ISO-8859-15,你可以这么做:

[code]require 'iconv'
sword="asd"
converter = Iconv.new('GB2312', 'UTF-8')
puts sword_iso = converter.iconv(sword)[/code]

这里要注意的是,你所只支持的编码取决于你的操作系统,如果在linux你可以运行iconv -l来列出所有你支持的编码.

如果不能转换输入的字符串到输出的格式,这时iconv会抛出一个异常:

[code]broken_utf8_string = "hello\xfe"
converter = Iconv.new('ISO-8859-15', 'UTF-8')
begin
converter.iconv(broken_utf8_string) # raises
rescue Iconv::IllegalSequence
converter = Iconv.new('ISO-8859-15//IGNORE', 'UTF-8') #这里的//IGNORE的意思是跳过那些错误
puts converter.iconv(broken_utf8_string) # "hello"
end[/code]

这里还有一个标记,那就是//TRANSLIT,这个标记的意思是,尽可能近似的转码,以代替抛出异常

[code]sword = "épée"

converter = Iconv.new('ASCII//IGNORE', 'UTF-8')
puts converter.iconv(sword) # "pe"
converter = Iconv.new('ASCII//TRANSLIT', 'UTF-8')
puts converter.iconv(sword) # "?p?e"[/code]


下面来看这段代码,这个代码是将一个web网页,转成utf-8的编码:
[code]
require 'open-uri'

require 'iconv'


def get_web_page_as_utf8(url)

open(url) do |io|

source = io.read

type, *parameters = io.content_type_parse

# Don't transcode anything that isn't (X)HTML

unless type =~ %r!^(?:text/html|application/xhtml+xml)$!

return source

end

# Check server headers first:

if pair = parameters.assoc('charset')

encoding = pair.last

# Next, look in the HTML:

elsif source =~ /\]*?charset=([^\s'"]+)/i

encoding = $1

# Finally, use the HTTP default

else

encoding = 'ISO-8859-1'

end

converter = Iconv.new('UTF-8//IGNORE', encoding)

return converter.iconv(source)

end

end[/code]

假设ruby正在运行的操作系统的默认编码没有被设置成UTF-8,或者ruby不能使用utf-8在这个操作系统下时(win32的包).

例如windows提供unicode的文件名并且使用内置的unicode字符集,但是ruby是通过 legacy code page和windows进行联系的.在英语和一些西欧语言的版本的windows里面这个code page是1252.

你仍然能在你的程序里面使用utf-8.可是你必须转换 legacy code page到指定的文件名,这时就必须使用iconv.可是你要记住的是 legacy code page只能表示unicode字符集里面的一小部分子集.

这就说明ruby不能在windows系统下,打开文件名不能描述为 legacy code page的文件,而这种限制在 Mac OS X, Linux, or other systems using UTF-8 locales的操作系统是不存在的.

8使用消息目录

[quote]Lojban is culturally fully neutral. Its vocabulary was built algorithmically using today's six most widely spoken languages: Chinese, Hindi, English, Russian, Spanish, and Arabic.What is Lojban?, Nick Nicholas and John Cowan[/quote]

一个 message catalog是使用指定语言的消息集合.它是L10N的一部分.简而言之,它也就是能使我们得到不同语言的message的版本.比如出错提示之类的..

在ruby中最好的方法是使用库Ruby-GetText-Package.我们简单的用gettext这个名字来使用他.可是这边还有一个更高效的,那就是gettet/utils,稍后我们会介绍它.

gettext库所包含的库有好几个,基本的使用这个库就require 'gettex'就可以了,可是当我们要使用一些很有用的工具的时候,我们就要用 require 'gettext/utils'来使用它.

message catalogs也就是把message在不同语言之间翻译.

每一个库或者程序都有他们自己的 message catalog.这意味着catalogs是作为发行包的一部分而存在的.

环境变量比如LANG和GETTEXT_PATH都是很重要的,我们稍后会介绍他们.

这边有两个很基础的操作在你使用消息目录的时候可能会遇到.
1 提取消息,从你的ruby源代码到你所创建的最初目录
2 更新(合并)新的消息从ruby源码到一个存在的目录

9前置工作

如果你没有安装这个库的话,你需要gem install gettext来安装一下这个库.

对于开发者来说,你可能还需要一个GNU utilities,如果你是linux或者unix系统的话,你可能已经拥有这个工具包了.顺便说一下,这个工具包只是开发是用,而不是在运行时用.

如果你没有装rake,你现在可以gem install rake..

如果你已经安装好所有的东西了,你就可以开始消息目录了,在这之前,我们先理解几个概念:

#po-file 也就是 portable object file.他是消息目录的文本形式(也就是人可以直接看的格式).每个po-file对应于不同的local,都提供一个版本的文件.它也就是模板文件。

#mo-file也就是portable binary message catalog file,他是二进制的.他是从po-file里面创建而来的.我们的ruby库就是读这个文件.

#一个文本域,也就是一个mo-file的名字,一个文本域,是和一个应用程序帮定在一起的.

10 本地化一个简单的程序

[code]require 'rubygems'
require 'gettext'
class Person
include GetText

def initialize(name, age, children_num)
@name, @age, @children_num = name, age, children_num
bindtextdomain("myapp")
end

def show
puts _("Information")
puts _("Name: %{name}, Age: %{age}") % {:name => @name, :age => @age}
puts n_("%{name} has a child.", "%{name} has %{num} children.",
@children_num) % {:name => @name, :num => @children_num}
end
end

john = Person.new("John", 25, 1)
puts john.show
linda = Person.new("Linda", 30, 3)
puts linda.show[/code]

要注意这个文件的路径是myapp/person.rb. 在initialize方法里面使用bindtextdomain绑定了文本域myapp到person对象在运行时.

在show方法里面这里有3个gettext调用,我们稍后解释一个n_这个方法。

现在我们现建立一个Rakefile的文件,目录是myapp/Rakefile .

[quote]require 'rubygems'
require 'gettext/utils'

desc "Update pot/po files."
task :updatepo do
GetText.update_pofiles("myapp", ["person.rb"], "myapp 1.0.0")
end
desc "Create mo-files"
task :makemo do
GetText.create_mofiles
end[/quote]

update_pofiles方法帮助我们从person.rb源文件来创建myapp.pot文件,如果这个函数被调用两次(或者更多)的话,这个函数他将会自己对pot文件和po文件进行update或者合成.GetText.create_mofiles 创建一个 在data/locale/ 这个目录下的mo文件(从po文件).

现在我们运行rake updatepo,myapp/po下面将会生成myapp.pot文件.

现在我们复制myapp.pot到myapp/po/zh/myapp.po.然后我们编辑myapp.po(也就是翻译他).

[code]# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: myapp 1.0.0\n"
"POT-Creation-Date: 2007-12-16 01:44+0800\n"
"PO-Revision-Date: 2007-12-16 01:44+0800\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\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"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: person.rb:13
msgid "Information"
msgstr "信息"

#: person.rb:14
msgid "Name: %{name}, Age: %{age}"
msgstr "名字: %{name}, 年龄: %{age}"

#: person.rb:15
msgid "%{name} has a child."
msgid_plural "%{name} has %{num} children."
msgstr[0] "%{name} 有一个小孩"
msgstr[1] "%{name} 有%{num}个小孩"[/code]

我们现在来看这个文件:
msgid标记后面的字符串是原始的字符串,也就是是没有本地化的字符串.msgstr后面的字符串是我们所要翻译的字符串,也就是到时候本地浏览,所要看到的.

这边还有一个特殊的符号那就是msgid_plural,当看到这个的时候,我们就要通过上面所给的Plural-Forms来选择他所匹配的msgstr,这边的规则是n!=1,n也就是最上面n_函数里面最后一个参数,也就是孩子的个数不等于1时就选择匹配nsgstr[1].

在这里我们看到,这边的参数最重要的两个是Content-Type和Plural-Forms。

最终,修改完毕后,我们再次回到myapp/目录下,运行rake makemo,然后将会生成myapp.mo路径将会是:myapp/data/locale/zh/LC_MESSAGES/myapp.mo.所以整个工程的路径是下面的样子:

[quote]myapp/

Rakefile

person.rb

po/

myapp.pot

de/myapp.po

fr/myapp.po

ja/myapp.po

:

data/

locale/

de/LC_MESSAGES/myapp.mo

fr/LC_MESSAGES/myapp.mo

ja/LC_MESSAGES/myapp.mo

[/quote]

现在我们可以测试我们的本地化了,首先在命令行下执行export GETTEXT_PATH="data/locale"
,这边是指定mo文件的位置。而由于本身自己的操作系统就是zh_cn.utf-8的,因此export Lang就不用执行了.然后再执行ruby person.rb,可以看到,本地化成功..
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值