显示修订历史自 #0 至 #1:
添加 | 移除
本文来自:http://pilipala.javaeye.com/blog/106389
Gibberish是基于rails框架下的一个语言本地化插件, beast项目使用它进行语言本地化。
Gibberish代码不多,也很容易理解,但是很好地实现了语言本地化的功能,读了以后感觉有些收获就写了这篇文档。
在rails项目下, 执行
ruby script/plugin install svn://errtheblog.com/svn/plugins/gibberish
在rails项目下,建立 lang 目录,并创建相应语言文件,例如:
en.yml 为英语文件,在其中输入: login: Login
zh.yml 为中文文件,在其中输入: login: 登录
这样即可,如果有新的需要本地化字符串,也按同样格式写入两个文件即可。
通过运行 ruby script/console , 查看一下Gibberish的使用方法。
#初始化加载 >> Gibberish.load_languages! => [:zh, :en] #显示 login >> "login"[:login] => "Login" #更改语言为zh >> Gibberish.current_language = :zh => :zh >> "login"[:login] => "登录"
稍微复杂的例子是可以写成如下格式
en.yml:
welcome: "Welcome {name}!"
zh:yml:
welcome: "{name},欢迎来访! "
执行:
"welcome"[:welcome,"Mike"]
在不同语言设置时,会显示:
Welcome Mike! Mike,欢迎来访!
1、初始化加载
def load_languages!
language_files.each do |file|
key = File.basename(file, '.*').to_sym
@@languages[key] = YAML.load_file(file).symbolize_keys
end
languages
end
def load_languages!
language_files.each do |file|
key = File.basename(file, '.*').to_sym
@@languages[key] = YAML.load_file(file).symbolize_keys
end
languages
end
简单地load 相应语言文件yml至 @@languages[key] 中。
2 翻译字符串:
首先, 执行:
String.send :include, Gibberish::StringExt
当Gibberish::String Ext被别的类include时会调用到函数:?
def self.included(base)
base.class_eval do
alias :brackets :[]
alias_method_chain :brackets, :translation
alias :[] :brackets
end
end
def self.included(base)
base.class_eval do
alias :brackets :[]
alias_method_chain :brackets, :translation
alias :[] :brackets
end
end
其中:alias_method_chain 大概实现如下:
def alias_method_chain(target, feature)
alias_method "#{target}without#{feature}", target
alias_method target, "#{target}with#{feature}"
end
def alias_method_chain(target, feature)
alias_method "#{target}without#{feature}", target
alias_method target, "#{target}with#{feature}"
end
所以,再执行String#[]时,会调用到函数 brackets_with_translation
def brackets_with_translation(*args)
args = [underscore.tr(' ', '_').to_sym] if args.empty?
return brackets_without_translation(*args) unless args.first.is_a? Symbol
Gibberish.translate(self, args.shift, *args)
end
def brackets_with_translation(*args)
args = [underscore.tr(' ', '_').to_sym] if args.empty?
return brackets_without_translation(*args) unless args.first.is_a? Symbol
Gibberish.translate(self, args.shift, *args)
end
当[]中第一个参数不是一个Symbol 还会执行以前的[],否则就执行Gibberish.translate
已经读过源码对一些使用细节有了更清楚的了解:
1、可以通过Gibberish::Localize#add_reserved_key添加保留字,如:
>>Gibberish.add_reserved_key(:aaa, :bbb) >> "bbb"[:bbb] => nil
2、对于“string”[:string] 如果未找到定义的,会返回”string”
3、“string”[] 相当于 “string”[:string]
4、 类似welcome: “Welcome {name}!” 这种功能是通过下面代码实现的
string.gsub(/\{\w+\}/) { args.shift }
所以,它只是把大括号里面的内容,按[]中的参数顺序替换而已。
比如,语言文件定义如下:
hello: hi,{name}! how are you, {name}? are you fine, {name}?
在调用时,应该是
“hello”[:hello, "Mike", "Mike", "Mike"]
而不是
“hello”[:hello, "Mike"]
另外,感觉每次更换语言,还需要set current_language 不太好。
因为,有时不同的用户会选用不同的语言,他们如果同时使用,就比较麻烦。
类似这样的调用似乎更好
"welcome"[:zh, "Mike"]
当然,实现上述功能也非常容易。
ruby的Mixin功能强大,可以很容易在一个Class中,加入另一个module的功能,简单这样即可:
class ClassA
include ModuleA
end
而ruby还有永不关闭的类的说法,我们可以在任何时候修改以往的类库来实现想要的功能。
在这时通常会需要重载以往已经实现的函数,而在Gibberish中就重载了String#[].
在这种情况下通常都有很固定的模式:
1、def self.included(base) 该函数会在module被别的类Mixin时候执行。
2、通过 base.class_eval 执行动态代码
3、使用 alias_method_chain :brackets, :translation
将原有函数命名为 brackets_without_translation
定义新函数 brackets_with_translation完成重载。