背景
國際化(internationalization)是設計和制造容易適應不同區域要求的產品的一種方式。它要求從產品中抽離所有地域語言,國家/地區和文化相關的元素。換言之,應用程序的功能和代碼設計考慮在不同地區運行的需要,其代碼簡化了不同本地版本的生產。開發這樣的程序的過程,就稱為國際化。-----引自百度百科
前言
最近因為周會輸出,整理了下iOS國際化這塊,發現這塊坑點還蠻多的,而且網上博客也比較雜,沒有一份比較系統的文章,所以想嘮叨兩句。主要是結合自己之前做國際化的經驗,分享下常見的一些坑點和解決方法。附帶我們之前的國際化方案。(類似Localization怎么配置、xib/storyboard國際化。。。就不講了,網上很容易就能找到)
流程
流程圖
時間國際化
時間在很多app里都有體現,有些涉及業務,有些只是為了顯示。但是在不同時區,時間應該是不一樣的,所以我們應該多一些處理,來讓應用根據不同的時區來顯示時間。
時間國際化是我們在開發中很容易忽視的地方,雖然東西很小,但是影響卻很大,因為時間在業務的體現更多是提醒的作用,重中之重。(令人難以置信的是我前后兩個公司都有這個問題)
異常場景描述:系統需要對報名課程的用戶進行開課提醒,但是因為沒有做國際化,所以用戶身處國外看到的卻是東八區的時間,可想而知是有多坑,熬到了半夜,明明到了上課時間,但是直播課確沒有。
what's the fuсk?
注意!
首先我們要和服務端同學規定,凡是系統中和時間相關的字段,都需要返回時間戳格式。時間戳!時間戳!時間戳!(有遇到服務端過于友好,特意轉成直接可用的字符串給客戶端,所以這個大家要小心,不管做沒做國際化。)
如何避免?
其實系統已經幫我們做了這件事,我們要做的是受它支配,乖乖的~不要不反抗~
具體是這樣的:眾所周知,我們需要通過NSDateFormatter對象將時間戳轉換成可用的字符串,NSDateFormatter對象里面有個TimeZone屬性,默認是取系統當前時區,那么我們要做的是不去setTimeZone。這樣獲取到的時間就是當前系統對應的時間,隨系統時區切換,時間也會跟著變化。
國際化分兩種情況
開發之初就考慮國際化,這種情況做國際化是很容易的,只要在開發過程中對字符串進行簡單的處理即可。
已經經歷過多個版本的開發,并且一開始就沒有做國際化的適配。此時面對項目中成千上萬的字符串,內心就崩潰了。我們主要針對這種情況展開討論。
字符串國際化
已開發多個版本,會面對如下問題
1. 大量字符串未加宏
2. Localizable.strings文件生成
3. storyboard/xib下的strings文件管理
1. 大量字符串未加宏
在已有工程上進行適配,首先要做的就是給需要進行國際化的字符串加上NSLocalizedString宏了。這種情況下一個個修改肯定不現實,工程里面可能有成千上萬個字符串。
可以用Replace模式進行替換
Command+Shift+F,進入全局搜索引擎
切換為Replace模式,并把匹配模式改為Regular Expression
在搜索條件里輸入正則?@"["]*[\u4E00-\u9FA5]+["\n]*?",該正則的作用是:匹配到所有符合OC字符串格式的包含有中文的字符串
在下面替換內容里輸入NSLocalizedString($1, nil)
然后進行查找,并Replace
步驟
但是過程并不一定那么順利
很有可能產生語法錯誤,這種報錯惡心的一匹,而且很難去排查。
iOS 國際化工具,讓你的國際化更簡單,包含了 iOS 中常用的一些腳本 。
2. Localizable.strings文件生成
跟NSLocalizedString配置一樣,對于已有工程我們不可能把項目中的字符串一處處挑出來再寫到Localizable.strings文件里的。
可以利用genstrings生成多語言文件
cd工程目錄
mkdir en.lproj
//.m
find ./ -name “*.m" -print0 | xargs -0 genstrings -o en.lproj
//.h 和.m
find . \( -name '*.m' -o -name '*.h' \)?-print0 | xargs -0 genstrings -o en.lproj
(去遍歷所有的.m子目錄文件,去生成Localizable.strings,其中包含key和value)
en.lproj會生成Localizable.strings文件
然后我們修改每個key所對應的value值就行(這其實是翻譯的事)
成功
或者也可以用github上的開源框架ReadChinese
使用起來非常方便,讀取某個目錄中的所有中文,并且將這些中文按照多語言(.string)格式寫入文件中,可以直接拿來實現國際化。
操作示例圖
3. storyboard/xib的國際化處理
storyboard的國際化非常簡單
將storyboard的inspector欄目的localization項勾上后,project的file navigator那里會多出幾個文件
示意圖
不足之處
storyboard/xib多語言文件中的配置并不會隨著控件的增減而變化,需要手動添加。
storyboard/xib需要多維護很多語言文件,增加不必要的成本
storyboard/xib少用/不用(在項目之初),如果考慮到國際化
也可以這樣做
通過python腳本來實現。
原理:假設原來我們就有翻譯文件A,添加控件后,我們再執行一次國際化指令,生成文件B,我們拿A和B對比,把B中多出來的鍵值對插入A文件的尾部,將A中有而B中沒有的鍵值對刪掉(即控件被刪除),這樣我們就算是更新了storyboard的翻譯文件了。然后每次installing的時候會運行腳本,去重新生成storyboard/xib中的多語言文件。
參考文章:https://www.cnblogs.com/levilinxi/p/4296712.html
參考git:https://github.com/linyu92/MyGitHub
網絡請求國際化
采用方案:(可參考)
在RequestHead中加個lang(en或cn)字段做語言區分
服務端獲取到lang,返回對應的數據,一般差異會體現在文案、圖片、requestErrorMessage
應用內語言切換
采用方案:(可參考)
默認跟隨系統語言:中文(中文簡|繁體)英文(非中文簡|繁體)
除了默認語言外,用戶可以切換語言,切換成功后就跟隨用戶設定的語言
設置語言方法[[NSUserDefaults standardUserDefaults] setObject:@"zh-Hans" forKey:currentLanguageKey]
應用內動態更新語言
常用的更新語言方式:
1. reloadRootViewController
2. 通知
3. 預留更新文字的方法
1. reloadRootViewController(成本低)
這個方法應該是編碼成本最低的方法了,只需要把原有的rootViewController移除并清空,然后重新設置一遍rootViewController就行了。但是這種實現方式會重新加載已經原來已經加載好的所有界面。
微信用的其實也是這種,在微信內切換語言的時候很明顯會感覺到有一個重新載入的過程。可能在項目之初也沒有考慮到國際化。
然后因為我們國際化是在之后提出的,所以考慮到成本風險,最后也選用了這種方式,雖然會重新加載,但是畢竟編碼成本最低,也不容易出錯。建議老項目,時間預留不多的可以用這個。(其實效果也不會那么差)
2. 通知
在用戶切換語言的時候,發送一個通知,然后在各個界面接收通知,更新所有需要更新的文本即可。這種方法適合新建的項目,在代碼編寫之初就預留好更新文本的方法,收到通知后調用此方法就行。如果已經是一個已上線項目,則改動成本比較高,需要改動的地方比較多。
3. 預留更新文字的方法(切換順暢)
在用戶切換語言的時候,遍歷所有已經加載的界面,調用更新文字的方法。這種實現也是比較適合新建的項目,在代碼編寫之初就預留好更新文本的方法。如果項目已上線,則改動成本較高。
支付寶切換過程就比較完美,實現了無縫切換,有可能是前期就預留了更新文本的方法,后期直接調用就可以。建議新項目試試,體驗會很好。
出處:http://www.lxweimin.com/p/1550f2835f4f