Ruby on Rails网站语言国际化
涉及到在Git@OSC中的一些应用
Gem
Rails项目双语化的时候需要用到Rails-18n和http_accept_languageGem
- rails-i18n
根据对应的rails版本添加到Gemfile中gem 'rails-i18n', '~> 4.0.0' # For 4.0.x gem 'rails-i18n', '~> 3.0.0' # For 3.x gem 'rails-i18n', github: 'svenfuchs/rails-i18n', branch: 'master' # For 4.x gem 'rails-i18n', github: 'svenfuchs/rails-i18n', branch: 'rails-3-x' # For 3.x
- http_accept_language
这个Gem能够把用户请求发送过来的请求头中把Accept-Language
提取出来放在一个数组中。即就是能检测出用户浏览器中设置的语言偏好。gem 'http_accept_language'
configuration
在config/application.rb
文件中基本的设置如下
config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] #
config.i18n.default_locale = 'zh-CN'
config.i18n.available_locales = ['zh-CN', 'en', 'zh-TW']
config.i18n.fallbacks = true #当应用程序需要的语言文件缺失时,使用默认的语言文件default_locale
同时I18n.config.enforce_available_locales
默认是true
,要改变为true
ApplicationController
用户请求通过路由器发送到对应的action之前应在application_controller中设置好网站的语言种类:before_filter set_locale
def set_locale
if cookies[:user_locale] && I18n.available_locales.include?(cookies[:user_locale].to_sym)
l = cookies[:user_locale].to_sym
else
l = http_accept_language.compatible_language_from(I18n.available_locales)
cookies.permanent[:user_locale] = l
end
I18n.locale = l || I18n.locale
end
Git@OSC网站国际化的策略是:首先读取用户的浏览器中是否包含语言设置的cookie(下文会涉及到把语言设置的cookie写到用户浏览器中)并且判断网站是非提供该语言;如果不满足上诉判断,则通过http_accept_language
获取用户浏览器对语言设置的偏好,并且与网站中提供的语言匹配出来之后设置到用户浏览器的cookie中,以便下次读取用户的请求中判断是否包含已经设置的语言种类。
用户主动选择网站的语言
国际化的网站中都有语言列表供用户选择,这是用户主动根据自己的语言偏好设置对此网站进行访问。
Git@OSC对此的实现是这样的:
- 在view中
那么用户选择了语言之后经过路由= link_to change_locale_path(locale: "zh-CN"), class: "ui button text-left" do %i.china.flag 中文简体 = link_to change_locale_path(locale: "en"), class: "ui button text-left" do %i.us.flag English
- 在routes中
不言而明,经过路由分发之后由home_controller的language action处理用户请求。get '/language/:locale', to: 'home#language', as: :change_locale
- 在控制器中
可以看出还会把语言设置写入用户的浏览器cookie,以便下次用户访问的时候能记住其语言偏好。def language l = params[:locale].to_s.strip.to_sym l = I18n.default_locale unless I18n.available_locales.include?(l) cookies.permanent[:user_locale] = l if request.env["HTTP_REFERER"].present? redirect_to :back else redirect_to '/' end end
以上就是用户主动选择语言种类时的后端处理。
view、controller、model、xxx.js.coffee中对语言配置文件的读取
rails项目config/locals
目录下有各种语言以及Gem对应的语言版本配置文件,这些配置文件中rails项目各个模块中的引用不进相同。
- view controller
例如Git@OSC个人主页中的“加载更多”可以这样子写
#{t('dashboard.active.loading_more_none')}
例如Git@OSC新建项目成功时控制器返回的flash消息flash[:notice] ="#{t('flash.new_repo_success')}"
- model
在model中对语言文配置文件的读取与前面不同。
例如Git@OSC中“观察者”,“开发者”,“管理员”这些角色字眼写在model中,此时对于语言配置文件的读取应是这样I18n.t('reporter') => REPORTER
xxx.js.coffee 写rails项目时很多时候经常把js单独写在与coffeescript文件中,那么rails中的ruby实例变量(在这里指的是从语言配置文件读取文件是产生的实例变量)如何与coffee script使用呢?其实有个gon这样的Gem,他们的自定义是
Your Rails variables in your JS
明白了吧?下面我们来看看如何使用。
- = include_gon
这个推荐写在布局文件中,如果网站的header单独写在一个模版中,那么
= include_gon
写在这个模版中再好不过了。 - 在controller action中编写gon变量 视图渲染之前是一定是经过某个action(这里不包括nginx缓存前端模版啥的)那么在xxx.js.coffee想要使用rails项目中的变量就显得容易了,结合gon我们只在这对应的action中生成这个变量即可,举个例子。 Git@OSC项目主页中一键有克隆仓库地址的操作,然后有个popup提示用户“复制”或者“已复制”,这些都是写在coffscript文件中的。project_controller show action渲染项目主页,由此我们可以在此action中这样写:gon.cp = "#{t('gist.copy')}" gon.aready_cp = "#{t('gist.already_copy')}"
- xxx.js.coffee中需要国际化文字
结合上面写的举个例子比较明显
直接clip_holder.popup content: gon.aready_cp
gon.aready_cp
就可以了,方便吧。
- = include_gon
这个推荐写在布局文件中,如果网站的header单独写在一个模版中,那么
网站中时间的国际化
不推荐使用rails的time_ago_in_words
帮助方法。原因为这事后端渲染导致了一个问题。比如你打开一个网页,显示的是一分钟前,然而不关闭次网页,一段时间之后应比一分钟之前的“一分钟之前”还要长了,但是后端渲染无法做到动态改变此时间。那么timeago就应运而出现。
添加必要的jquery.timeago.js"
这里有各种国际语言供你选择jquery-timeago
首先封装一个帮助方法以便我们在视图中使用app/helpers/time_helper.rb
module TimeHelper
def timeago(time)
content_tag(:span, time.iso8601, title: time.iso8601, class: 'timeago')
end
end
然后在application.js中加入
$('.timeago').timeago()
最后就可以在视图中使用了
"posted #{timeago(post.created_at)} #{t('ago')}"
缓存相关
在rails项目中,国际化的网站有多少中语言就有多少套缓存文件,自然而然我们想到了用不同语言对应的键区分开来。
- 在ApplicationController中写个帮助方法获取当前用户设置的语言偏好
helper_method :getlocal
def getlocal I18n.locale.to_s end
- 生成缓存键的时候加上
getlocal
例如在视图中生成的建[@project.id, '@tree_readme@', @path, tree.readme.id, getlocal].join(':')