為 Rails 項目添加動態(tài) I18n 內(nèi)容

場景:對于一個已經(jīng)做好靜態(tài) I18n 的 Rails 項目,需要對動態(tài)數(shù)據(jù)內(nèi)容也適配國際化儿子。

首先澎粟,動態(tài)內(nèi)容的數(shù)據(jù)肯定是存在數(shù)據(jù)庫中的奇昙,并且字段名也采用統(tǒng)一的 fieldname_#{I18n.locale} 期丰,方便統(tǒng)一管理群叶。

問題的核心是如何在盡量不修改現(xiàn)有代碼的情況下動態(tài)讀取模型某些字段的當前 locale 的值。

比如:原來的 user.name #=> Marry 咐汞,現(xiàn)在需要根據(jù)當前 locale (比如 cn)變成 user.name # => 翠花

首先接口肯定不能改儒鹿,view 層中有很多很多的 user.name 的調(diào)用化撕,就算用批量修改的方式改為類似 user.name_#{I18n.locale} 的寫法,
也很不優(yōu)雅约炎,何況不只是 name 屬性需要國際化植阴,以后每增加一個字段或模型的國際化都將成為很大的負擔。

說到如何在原有類的基礎(chǔ)上增加功能圾浅,那自然會想到使用裝飾器模式了掠手。

關(guān)于裝飾器模式的實現(xiàn),一種方式是使用 delegate :

require 'delegate'

class User < ApplicationRecord
  # attribute name
end

class InternationalUserDecorator < SimpleDelegator
  def name
    __getobj__.send("name_#{I18n.locale}")
  end
end

user = InternationalUserDecorator.new(User.find(12345))

I18n.locale = :en
user.name # => 'Marry'

I18n.locale = :cn
user.name # => '翠花'

但是這顯然是不行的狸捕,因為這需要修改每一個 User 實例的生成喷鸽,使用 Decorator 去顯式地包裝它。

類似的灸拍,還有一種通過繼承 module 的方式做祝,同樣需要顯示的修改每一個模型的實例,這樣的改動對原代碼改變很大鸡岗,也不能使用混槐。

module EnglishUser
  def name
    "Marry"
  end
end

module ChineseUser
  def name
   "翠花"
  end
end

user = User.find(123)
user.extend(EnglishUser) #=> name "Marry"
user.extend(ChineseUser) #=> name "翠花"

可見,需要在獲取模型實例時進行修改的思路是行不通轩性,如果項目一開始就使用倉儲模式的話声登,修改起來會容易很多,不過這超出了本文的范圍揣苏。

想要盡可能小的修改原代碼悯嗓,那只能使用元編程了,我們需要一個 Module卸察,來動態(tài)生成 locale 對應(yīng)的 field 供模型調(diào)用绅作。

localecn 的時候, user.name => user.name_cn
localeen 的時候蛾派, user.name => user.name_en

當然俄认,不是模型所有的 field 都需要做國際化个少,必須可以指定需要國際化的字段

client 端的代碼應(yīng)該是這樣的:

class User < ApplicationRecord
  # attributes :name, :position, :age
  include I18nDecorator.new(:name, :position)
end

這里的難點在于,需要傳參數(shù)給這個 Module眯杏,可 include 的時候是不能傳參的夜焦。
在這里,我們把 I18nDecorator 定義為 Module 的一個子類岂贩,這樣就可以通過 new 的時候的 initialize 方法中茫经,
對父類進行元編程,動態(tài)定義 Module 的方法萎津,這樣就能在模型中進行調(diào)用了卸伞。

class I18nDecorator < Module
  def initialize(*attrs)
    super() do
      attrs.each do |attr|
        define_method attr do
          send("#{attr}_#{I18n.locale}")
        end
      end
    end
  end
end

現(xiàn)在,當任何 User 類的實例調(diào)用 name 或者 position 的方法時锉屈,就會被 I18nDecorator 動態(tài)轉(zhuǎn)發(fā)給 name_cn 或者 position_en 的屬性上了荤傲。

就這樣,一共十幾行代碼颈渊,我們完成了一個 Rails 項目簡單的動態(tài) I18n 的功能遂黍,以后需要增加模型或?qū)傩缘臅r候,都只需要 include 這一行代碼就可以了俊嗽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雾家,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子绍豁,更是在濱河造成了極大的恐慌芯咧,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竹揍,死亡現(xiàn)場離奇詭異唬党,居然都是意外死亡,警方通過查閱死者的電腦和手機鬼佣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門驶拱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晶衷,你說我怎么就攤上這事蓝纲。” “怎么了晌纫?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵税迷,是天一觀的道長。 經(jīng)常有香客問我锹漱,道長箭养,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任哥牍,我火速辦了婚禮毕泌,結(jié)果婚禮上喝检,老公的妹妹穿的比我還像新娘。我一直安慰自己撼泛,他們只是感情好挠说,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著愿题,像睡著了一般损俭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上潘酗,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天杆兵,我揣著相機與錄音,去河邊找鬼仔夺。 笑死琐脏,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的囚灼。 我是一名探鬼主播骆膝,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼祭衩,長吁一口氣:“原來是場噩夢啊……” “哼灶体!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起掐暮,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝎抽,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后路克,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體樟结,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年精算,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓢宦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡灰羽,死狀恐怖驮履,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情廉嚼,我是刑警寧澤玫镐,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站怠噪,受9級特大地震影響恐似,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜傍念,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一矫夷、第九天 我趴在偏房一處隱蔽的房頂上張望葛闷。 院中可真熱鬧,春花似錦口四、人聲如沸孵运。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽治笨。三九已至,卻和暖如春赤嚼,著一層夾襖步出監(jiān)牢的瞬間旷赖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工更卒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留等孵,地道東北人。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓蹂空,卻偏偏與公主長得像俯萌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子上枕,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理咐熙,服務(wù)發(fā)現(xiàn),斷路器辨萍,智...
    卡卡羅2017閱讀 134,696評論 18 139
  • 9.2 添加國際化和本地化 Django提供了完整的國際化和本地化支持棋恼。它允許你把應(yīng)用翻譯為多種語言,它會處理特定...
    lakerszhy閱讀 1,141評論 0 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法锈玉,類相關(guān)的語法爪飘,內(nèi)部類的語法,繼承相關(guān)的語法拉背,異常的語法师崎,線程的語...
    子非魚_t_閱讀 31,662評論 18 399
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,280評論 25 707
  • 剛參加工作的年輕人犁罩,不少仍是為了滿足“馬斯諾五大條理理論”中的最低需求,就是保留必要而工作土陪,工作后贏利養(yǎng)活本身就意...
    智盛心法閱讀 285評論 0 0