1 新增要支援的國際語言
-
新增語言後面的括號內容是該語言的國際標準縮寫名
-
如選擇新增日語後,會彈出如下對話方塊,選擇Finish即可
-
如下選擇新增日語,法語,簡體中文,繁體中文後,可以發現相應的變化
2 本地化應用名
本地化應用名:App的名稱,根據裝置語言的設定,顯示成對應名稱(~如微信App,在簡體中文語言下顯示成微信,在英文語言下顯示weChat~)
2.1 選中info.plist檔案,右鍵選擇新建檔案
2.2 選擇建立檔案型別為Strings File
2.3 指定名稱為InfoPlist.strings(~名稱必須是InfoPlist~)
2.4 建立成功後
2.5 選中InfoPlist.strings,在Xcode的File inspection(Xcode右側檔案檢查器)中點選Localize,目的是選擇我們需要本地化的語言,如下圖:
注意:在點選Localize之前,一定要保證第1步已經新增了需要國際語言
2.6 彈出確認對話方塊,預設選擇English,你可展開優選選擇你需要本地化的語言,或者直接按預設,後續可以繼續新增你需要的國際語言
2.7 選擇本地化的語言後,可以看到InfoPlist.strings檔案在檔案檢查器欄的Locaization欄發生變化
2.8 將其他國際語言都勾上後,可以看到InfoPlist.strings檔案也出現了多個子項的變化
2.9 從專案資料夾方向看看發生了什麼
多語言本地化的核心思想 就是為每種語言單獨定義一份資源,iOS就是通過xxx.lproj目錄來定義每個語言的資源,這裡的資源可以是圖片,文字,Storyboard,Xib等
每種語言都有自己的
語言程式碼.lproj
資料夾,載入資源時只需要載入相應語言資料夾下的資源,這步可以系統為我們完成,也可以手動去做
2.10 先設定demo的display name為:本地化測試Demo
-
info.plist 檔案中會出現display name的key value展示
-
我們知道display name 的名字就是App安裝後再裝置上顯示的名稱
-
通過顯示info.plist中的raw key value來獲取修改display name對應的key:CFBundleDisplayName
看看官方解析咯 CFBundleDisplayName CFBundleName info.plist 的所有key檢視 -Core Foundation Keys
所以CFBundleDisplayName是可以用在infoPlist.strings上的。
2.11 分別在不同的語言所對應InfoPlist.strings上設定本地化的App名稱
// InfoPlist.strings(English) 檔案
CFBundleDisplayName = "EnglishDemo";
// InfoPlist.strings(Chinese(Simplified)) 檔案
CFBundleDisplayName = "簡體Demo";
// InfoPlist.strings(Chinese(Tradictional)) 檔案
CFBundleDisplayName = "繁體Demo";
// InfoPlist.strings(Japanese) 檔案
CFBundleDisplayName = "日語Demo";
// InfoPlist.strings(French) 檔案
CFBundleDisplayName = "法語Demo";
複製程式碼
備註:CFBundleDisplayName可以使用雙引號,也可以不使用雙引號!
2.12 獲取當前模擬器當前設定的語言
// ViewController.m
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
NSLog(@"AppleLanguages 語言有 %@", languages);
NSString *currentLanguage = languages.firstObject;
NSLog(@"模擬器當前語言:%@",currentLanguage);
}
複製程式碼
2.13 設定模擬器的語言環境
2.14 執行程式後各個語言本地化的效果展示
- 繁體環境下(模擬器當前語言:zh-Hant-HK)
// 執行結果
2018-09-04 16:49:40.056223+0800 LanguageLocalizationDemo[92506:3273624] AppleLanguages 語言有 (
"zh-Hant-HK",
"zh-Hans-US",
en
)
2018-09-04 16:49:40.056505+0800 LanguageLocalizationDemo[92506:3273624] 模擬器當前語言:zh-Hant-HK
複製程式碼
- 英語環境下(模擬器當前語言:en)
// 執行結果
2018-09-04 17:00:37.811874+0800 LanguageLocalizationDemo[92874:3283615] AppleLanguages 語言有 (
en
)
2018-09-04 17:00:37.812133+0800 LanguageLocalizationDemo[92874:3283615] 模擬器當前語言:en
複製程式碼
- 日語環境下(模擬器當前語言:ja-US)
// 執行結果
2018-09-05 10:33:16.423697+0800 LanguageLocalizationDemo[46412:14218145] AppleLanguages 語言有 (
"ja-US",
en
)
2018-09-05 10:33:16.423941+0800 LanguageLocalizationDemo[46412:14218145] 模擬器當前語言:ja-US
複製程式碼
- 簡體中文環境下(模擬器當前語言:zh-Hans-US)
// 執行結果
2018-09-05 10:36:18.376366+0800 LanguageLocalizationDemo[46510:14225868] AppleLanguages 語言有 (
"zh-Hans-US",
"zh-Hant-US",
"ja-US",
en
)
2018-09-05 10:36:18.376628+0800 LanguageLocalizationDemo[46510:14225868] 模擬器當前語言:zh-Hans-US
複製程式碼
- 法語環境下(模擬器當前語言:fr-US)
// 執行結果
2018-09-05 10:47:12.397641+0800 LanguageLocalizationDemo[46634:14239902] AppleLanguages 語言有 (
"fr-US",
"zh-Hans-US",
"zh-Hant-US",
"ja-US",
en
)
2018-09-05 10:47:12.398086+0800 LanguageLocalizationDemo[46634:14239902] 模擬器當前語言:fr-US
複製程式碼
當然,模擬器設定對應的語言之後,模擬器重啟完成時對應 App 的名稱就會隨系統語言而變更,不需要重新 run 這個專案,而上述結果每次都進行 run 操作的目的是觀察系統語言的變化及確定所設定的語言是否正確
2.15 影響通過AppleLanguages
key 從NSUserDefaults
中獲取的支援語言的原因
- 根據裝置曾經新增過的語言返回結果
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
複製程式碼
上面獲得的NSArray *languages
內容是根據當前裝置已經新增過哪些語言決定的,模擬器預設只有英文,所以你會看到2.14中列印的不同結果
- 受到 Xcode 的語言設定影響 假設裝置已經新增了簡體中文、繁體中文、英文、法語、日語。 2.1 裝置新增了對應語言
2.2 Xcode 中的原因按預設設定為跟隨系統
那麼此時執行下面程式碼獲得的陣列是:
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
複製程式碼
2018-09-05 10:47:12.397641+0800 LanguageLocalizationDemo[46634:14239902] AppleLanguages 語言有 (
"fr-US",
"zh-Hans-US",
"zh-Hant-US",
"ja-US",
en
)
2018-09-05 10:47:12.398086+0800 LanguageLocalizationDemo[46634:14239902] 模擬器當前語言:fr-US
複製程式碼
列印結果是裝置正常已新增的語言。
2.3 Xcode 中的語言設定為指定某一語言(~此處設為English~)時,結果是:
2018-09-05 10:58:06.445970+0800 LanguageLocalizationDemo[46726:14250118] AppleLanguages 語言有 (
en
)
2018-09-05 10:58:06.446199+0800 LanguageLocalizationDemo[46726:14250118] 模擬器當前語言:en
複製程式碼
AppleLanguages陣列中只有一個en 元素 但模擬器真實語言環境沒有變化,還是法語,且 App 名稱同樣還是根據裝置環境顯示成法語的名稱
這裡作出的對比,是希望以後再開發除錯時候,留意這些影響裝置語言獲取的因子
同時需要注意的是,App 的名稱不會隨 Xcode 的 application langue變化而變化,它僅僅跟隨裝置實際設定的語言而變
3 本地化 程式碼中的字串
本地化 程式碼中的字串
是指程式內的字串在不同的語言環境下顯示不同的內容,比如首頁
一詞,在簡體中文下顯示就是首頁
,而在英文下則會顯示Home
。
本地化 程式碼中的字串
流程與本地化 App 名稱
基本一致,同樣下面也會給出各個步驟的操作貼圖
3.1 選中要存放新建檔案位置的資料夾後,通過 command + n
快速建立檔案
3.2 選擇建立檔案型別為Strings File
3.3 指定 Strings File 檔名稱為 Localizable
使用這個名字原因它是系統預設載入本地化檔名稱,後面會提到通過自定義其他名稱來模組化處理本地化及解耦
3.4 Localize Localizable.strings檔案
3.5 勾選其他語言
到目前為止,上述步驟與本地化 App 名稱是一樣的,不同點是 strings 檔案的名稱
3.6 在對應語言檔案中按 key-value 的形式寫入需要本地化的字串
// Localizable.strings(English) 檔案
"home" = "home";
// Localizable.strings(Chinese(Simplified)) 檔案
"home" = "簡體主頁";
// Localizable.strings(Japanese) 檔案
"home" = "日語主頁";
// Localizable.strings(Chinese(Traditional)) 檔案
"home" = "繁體主頁";
// Localizable.strings(French) 檔案
"home" = "法語主頁";
複製程式碼
3.7 通過NSLocalizedString(key, comment)
這個系統提供的巨集,使用本地化檔案中的內容
- 環境語言的切換可以通過
裝置的語言設定
或Xcode中Scheme設定
,這裡推薦通過 Xcode 進行快速設定,這樣省去等待模擬器的重啟時間 - 下面是設定執行效果
- 簡體中文
- 英文
- 法語
- 繁體中文
3.8 NSLocalizedString 使用小技巧
- 使用NSLocalizedString按照給定的 key 查詢對應 strings 檔案時,如果找不到該 key 對應value 時,預設返回的值就是 key。
- Localizable.strings(English)檔案什麼都沒寫
- NSLocalizedString使用的 key 為
lala
- 當查詢不到時,就會將 key 返回,如下圖:
- 假設你使用的是英文的名稱作為 key,那麼一般情況下,Localizable.strings(English)檔案中的鍵值對應該是這樣的
"home" = "home";
,即鍵值一樣,那就可以利用上面的第一點,查詢不到是返回 key 的特性,省去在Localizable.strings(English)檔案中補上鍵值的情況(~當然,這是不建議的?~)
4 模組化管理本地化
4.1 模組化管理的原因
- 從第3大點上可以知道,通過構建一個系統預設的名稱的Localizable.strings檔案,可以將專案中所有需要本地化語言的程式碼字串統一放在Localizable.strings檔案中。
- 但是都放在一個地方雖然可以統一管理,但隨著專案的模組的增多等情況,該檔案內容必定會存在內容臃腫情況,雖然可通過
註釋
或者#pragma mark - <#desc#>
來分層管理,但面向多人程式設計時,同時修改一個檔案導致的問題更復雜
4.2 自定義.strings
檔案,實現模組化管理
- 通過NSLocalizedStringFromTable巨集,手動指定查詢 strings 檔案。
NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
複製程式碼
-
自定義名稱
·strings
檔案(Module1.strings
) -
使用
NSLocalizedStringFromTable
5 本地化圖片
5.1 方式1:類似本地化程式碼字串方式,通過NSLocalizedString
獲取語言的圖片名稱,從Assets.xcassets
中獲取相應圖片
-
使用程式碼示例
-
Assets.xcassets
圖片命名 -
對應 Localizable.strings 內容
// Localizable.strings(English) 檔案
"image-languge" = "english";
// Localizable.strings(Chinese(Simplified)) 檔案
"image-languge" = "simplify";
// Localizable.strings(Japanese) 檔案
"image-languge" = "japan";
// Localizable.strings(Chinese(Traditional)) 檔案
"image-languge" = "french";
// Localizable.strings(French) 檔案
"home" = "法語主頁";
複製程式碼
- 執行效果 其他請參考 demo
5.2 方式2:指定 bundle 的圖片,讓其具有本地化屬性(~即把圖片資源放到對應的語言lproj資料夾中~)
-
拖拽一張圖片至專案 bundle 中
-
本地化圖片
-
將其他語言選上
-
在對應圖片的本地化資料夾內都可以看到有一張 icon 圖
-
將對應語言的
其他語言一樣操作.lproj
資料夾內的 icon 圖替換成同名的其他 icon 圖 -
完成第5步後回到專案,點選對應的語言.strings檔案看到對應的 icon
-
通過 icon 名稱
langueIcon
作為 key,使用NSLocalizedString
獲取應語言字串
- 執行效果如5.1
本地化圖片需要多張圖片類似的圖片,如果一次適配的語言較多情況下,那麼包體積變大是不可避免的事情,這一點可考慮一下動態獲取圖片的方法。這樣按需獲取在多語言情況下比較可行
6 本地化 Xib
6.1 本地化 Xib
-
建立 xib 的 vc
-
Localize xib 檔案,注意:直接選擇 Base,不要選其他
- 選其他的話,會沒有生成對應的 key-value
- 勾選其他的語言
相比於其他的
你可以選擇 讓其他語言以 strings 檔案形式來 基於Base 的 xib;或者每個語言都成為獨立的 xib 檔案 但是不建議使用獨立 xib 的形式,當然如果不同語言不同佈局的話,也是可以使這樣形式的.strings
檔案,xib 或 sb 本地化之後,對應語言的.strings 檔案是可以變換成特定 xib 樣式的
-
選擇 Base 的 String 自動生成strings 檔案內容瀏覽 系統會根據當前 xib 中的子控制元件(~限文字控制元件,如:Label、Button等~),的 Object ID 生成內容鍵值
-
根據語言修改對應 value 值即可,系統會自動獲取xib 中控制元件 ID 然後匹配系統語言進行內容賦值
-
修改 Xcode 的語言設定,檢視執行結果
-
英文
-
法語
6.2 在Interface Builder中預覽本地化
在Interface Builder中,您可以在不執行應用程式的情況下預覽使用者介面的本地化。
-
在專案導航器中,選擇要預覽的檔案.storyboard或.xib檔案
-
選擇檢視>輔助編輯器>顯示助手編輯器
-
在助手編輯器跳轉欄中,開啟“助手”彈出選單,滾動並選擇“預覽”項,然後從子選單中選擇.storyboard或.xib檔案(~如果應用程式使用者介面的預覽未顯示在助理編輯器中,請在圖示或大綱檢視中選擇要預覽的視窗或檢視~)
-
在助理編輯器中,從右下角的語言彈出選單中選擇要預覽的本地化。(~本地化的預覽顯示在助理編輯器中。如果選擇實際語言,則不需要本地化或需要本地化但當前不是本地化的字串將以大寫形式顯示~)
6.3 新增新控制元件至 XIB
- 不會聯動變化 我們發現,新增新控制元件後,相應的 strings 檔案沒有自動發生變化⁉️
注意:Xib相應語言的strings一旦生成後,Base Xib有任何編輯都不會影響到strings,即刪除或新增了一個Label,strings也不會同步做相應的改動
- 手動新增咯(~當然是可以的~)
- 獲取到對應 Label 的 ObjectID,然後參考之前生成 strings 之前已經新增到 xib 的 label 處理格式,分別修改對應語言的 strings 檔案,如下:
- 執行效果
6.3 自動化更新 strings 檔案
- 方式1:使用
ibtool
生成新的.strings
檔案(~後續會分析這個的使用步驟~)
- Xcode 為我們提供了
ibtool
工具來生成 Xib 的 strings 檔案,命令如下ibtool XibController.xib --generate-strings-file ./XibController.strings
- 但是這個
ibtool
翻譯的鍵值對中的值是按照xib上控制元件上填寫的文字來顯示的,一般不是我們想要的,如果要實現更新,我們需要將XibController.strings和之前對應語言資料夾fr.lproj
等的XibController.strings比較,將XibController.string中多出來的key-value取出來,追加到Main.string的尾部(~實在麻煩~)
- 方式2:使用指令碼來實現自動追加新 key-value,刪除不再存在的 key-value
指令碼內還是通過使用
ibtool
-
邏輯是:假設原來我們就有翻譯檔案A,新增控制元件後,我們再執行一次國際化指令,生成檔案B,我們拿A和B對比,把B中多出來的鍵值對插入A檔案的尾部,將A中有而B中沒有的鍵值對刪掉(即控制元件被刪除),這樣我們就算是更新了storyboard的翻譯檔案了
-
參照上述的邏輯,我們可以藉助指令碼檔案來實現,Xcode的Run Script也提供了指令碼支援,可以讓我們在Build後執行指令碼
2.1 新建 py 指令碼
2.2 選擇:Target -> Build Phases -> New Run Script Phase,在shell裡面寫入下面指令
#!/bin/bash
python ${SRCROOT}/${TARGET_NAME}/RunScript/AutoGenStrings.py ${SRCROOT}/${TARGET_NAME}
複製程式碼
2.3 你也可以選擇Run script only when installing
,這樣在編譯是不會雲指令碼,只有install的時候才會執行指令碼
2.4 新新增控制元件之後,編譯一下,對應的 strings 檔案會增加新控制元件的 key-value 對,而刪除的控制元件的的 key-value 對會被註釋
之後有空會補上
AutoGenStrings.py
的解讀,參考的指令碼原先只有 storyboard 的處理,這裡擴充套件至 xib
7 本地化Storyboard
- 與 Xib 操作流程一致,請參考 Xib 的本地化流程
8 說說NSLocalizedString(key, comment)
中 comment 引數的使用
第一個引數是:key的名字 第二個引數是:對這個“鍵值對”的註釋,在用
genstrings
工具生成Localizable.strings檔案時會自動加上去
一般情況下,語言翻譯的操作並不是我們程式設計師源來做的(~當然,nb的猿都會nb地接手這些工作~),那麼怎樣才能夠將語言本地化strings檔案分發出去同時又能夠很好的按流程工作呢?
8.1 直接在程式碼中使用NSLocalizedString
進行臆想本地化實現
- 此時的情況是本地沒有任何 strings 檔案,利用
NSLocalizedString
的查詢邏輯,key 不存在時直接返回 key 值 - 所以開發過程時,介面顯示的就是 key 值,而推薦使用英文表示 key 的優點就是:當超出所支援語言時,預設使用英語。那使用英語翻譯的 key 正好滿足條件
8.2 通過 genstrings
將使用了NSLocalizedString
的viewController.m
檔案,生成對應語言環境的 strings 檔案
- 當所有的.m檔案都使用
NSLocalizedString
修改好之後,就可以動用genstrings
工具了
- 啟動終端,進入工程所在目錄。
- 新建需要支援的語言.lproj 資料夾,位置預設放在專案根目錄下 目錄名會作用到Localizable.strings檔案對應的語言,所以目錄名稱不能寫錯了。
mkdir zh-Hans.lproj
mkdir en.lproj
複製程式碼
-
推薦通過 Xcode 幫我們生成,參考文章 “第1點:新增要支援的國際語言”,這樣你還可以省去語言簡寫目錄名的煩惱,直接從 Xcode 中選擇你想要支援的國際語言
-
選擇語言
-
生成的
.lproj
資料夾 -
發現沒有
en.lproj
資料夾,沒關係,點選main.storyboard
,在檔案的 localize 位置勾上 English 選項,同理launch.storyboard
也同樣操作 -
出現了
en.lproj
- 生成
Localizable.strings
檔案
genstrings -o zh-Hans.lproj *.m
genstrings -o en.lproj *.m
genstrings -o ja.lproj *.m
複製程式碼
-o <資料夾>
,指定生成的Localizable.strings檔案放置的目錄。
*.m
,掃描所有的.m
檔案。這裡支援的檔案還包括.h
, .java
等。
- 執行完
genstrings -o zh-Hans.lproj *.m
命令之後,對應的zh-Hans.lproj
資料夾多了Localizable.strings
,其他同理
-
生成
Localizable.strings
檔案都拖拽到工程中,Xcode會自動合併成一個,並且對應生成的內容是按照前面NSLocalizedString(@"home", @"這個是用來在生成 strings 檔案時,在對應的 key-value 行上的註釋,用來提示翻譯員或者猿們的相關提示")
生成的。 -
之後我們將這些檔案分發到翻譯員(~或者你自己手裡~)
注意:
genstrings
指令只能是該目錄下的檔案遍歷,但不能實現遞迴遍歷,要實現遞迴變數,可以使用下述命令find ./ -name *.m | xargs genstrings -o en.lproj
這是shell組合指令find+xargs
,find ./ -name *.m
會遞迴所有.m
檔案並存在一個陣列中,這個陣列經由pipe
傳遞給了下一個指令,而xargs
會將收到的陣列一一分割,並交給genstrings執行。
9 應用內設定語言(~實踐後補上~)
10 指定語言 bundle 獲取本地化字串(~實踐後補上~)
- 巨集使用例子補充
#define NSLocalizedString(key, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
[NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
[bundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \
[bundle localizedStringForKey:(key) value:(val) table:(tbl)]
複製程式碼
11 啟動圖本地化(~實踐後補上~)
12 優化(~實踐後補上~)
Demo
LanguageLocalizationDemo - 第1-7點使用
LocalizationGenStringsDemo - 第8點使用
未完~
REF
文/Jacob_LJ(掘金作者)
PS:如非特別說明,所有文章均為原創作品,著作權歸作者所有,轉載需聯絡作者獲得授權,並註明出處,所有打賞均歸本人所有!