iOS語言國際化/本地化-實踐總結

Build Apps for the World

1 添加要支持的國際語言

  1. 添加語言後面的括號內容是該語言的國際標準縮寫名 html

  2. 如選擇添加日語後,會彈出以下對話框,選擇Finish便可 java

  3. 以下選擇添加日語,法語,簡體中文,繁體中文後,能夠發現相應的變化 python

2 本地化應用名

本地化應用名:App的名稱,根據設備語言的設置,顯示成對應名稱(~如微信App,在簡體中文語言下顯示成微信,在英文語言下顯示weChat~)git

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等github

每種語言都有本身的 語言代碼.lproj 文件夾,加載資源時只須要加載相應語言文件夾下的資源,這步能夠系統爲咱們完成,也能夠手動去作shell

2.10 先設置demo的display name爲:本地化測試Demo

  • info.plist 文件中會出現display name的key value展現 編程

  • 咱們知道display name 的名字就是App安裝後再設備上顯示的名稱 swift

  • 經過顯示info.plist中的raw key value來獲取修改display name對應的key:CFBundleDisplayName c#

看看官方解析咯 CFBundleDisplayName CFBundleName info.plist 的全部key查看 -Core Foundation Keys

CFBundleDisplayName

因此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 設置模擬器的語言環境

在iOS設備上設置語言

2.14 運行程序後各個語言本地化的效果展現

  1. 繁體環境下(模擬器當前語言: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
複製代碼

  1. 英語環境下(模擬器當前語言: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
複製代碼

  1. 日語環境下(模擬器當前語言: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
複製代碼

  1. 簡體中文環境下(模擬器當前語言: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
複製代碼

  1. 法語環境下(模擬器當前語言: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 影響經過AppleLanguageskey 從NSUserDefaults中獲取的支持語言的緣由

  1. 根據設備曾經添加過的語言返回結果
NSArray *languages = [[NSUserDefaults standardUserDefaults] valueForKey:@"AppleLanguages"];
複製代碼

上面得到的NSArray *languages內容是根據當前設備已經添加過哪些語言決定的,模擬器默認只有英文,因此你會看到2.14中打印的不一樣結果

  1. 受到 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)這個系統提供的宏,使用本地化文件中的內容

  1. 環境語言的切換能夠經過設備的語言設置Xcode中Scheme設置,這裏推薦經過 Xcode 進行快速設置,這樣省去等待模擬器的重啓時間
  2. 下面是設置運行效果
  • 簡體中文

  • 英文

  • 法語

  • 繁體中文

  1. NSLocalizedString宏定義解析

  2. localizedStringForKey:value:table: - NSBundle

3.8 NSLocalizedString 使用小技巧

  1. 使用NSLocalizedString按照給定的 key 查找對應 strings 文件時,若是找不到該 key 對應value 時,默認返回的值就是 key。
  • Localizable.strings(English)文件什麼都沒寫
  • NSLocalizedString使用的 key 爲 lala
  • 當查找不到時,就會將 key 返回,以下圖:
  1. 假設你使用的是英文的名稱做爲 key,那麼通常狀況下,Localizable.strings(English)文件中的鍵值對應該是這樣的"home" = "home";,即鍵值同樣,那就能夠利用上面的第一點,查找不到是返回 key 的特性,省去在Localizable.strings(English)文件中補上鍵值的狀況(~固然,這是不建議的😆~)

4 模塊化管理本地化

4.1 模塊化管理的緣由

  1. 從第3大點上能夠知道,經過構建一個系統默認的名稱的Localizable.strings文件,能夠將項目中全部須要本地化語言的代碼字符串統一放在Localizable.strings文件中。
  2. 可是都放在一個地方雖然能夠統一管理,但隨着項目的模塊的增多等狀況,該文件內容一定會存在內容臃腫狀況,雖然可經過註釋或者#pragma mark - <#desc#>來分層管理,但面向多人編程時,同時修改一個文件致使的問題更復雜

4.2 自定義.strings文件,實現模塊化管理

  1. 經過NSLocalizedStringFromTable宏,手動指定查找 strings 文件。
NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
複製代碼
  1. 自定義名稱·strings文件(Module1.strings)

  2. 使用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文件夾中~)

  1. 拖拽一張圖片至項目 bundle 中

  2. 本地化圖片

  3. 將其餘語言選上

  4. 在對應圖片的本地化文件夾內均可以看到有一張 icon 圖

  5. 將對應語言的.lproj文件夾內的 icon 圖替換成同名的其餘 icon 圖

    其餘語言同樣操做

  6. 完成第5步後回到項目,點擊對應的語言.strings文件看到對應的 icon

  7. 經過 icon 名稱langueIcon做爲 key,使用NSLocalizedString獲取應語言字符串

  • 運行效果如5.1

本地化圖片須要多張圖片相似的圖片,若是一次適配的語言較多狀況下,那麼包體積變大是不可避免的事情,這一點可考慮一下動態獲取圖片的方法。這樣按需獲取在多語言狀況下比較可行

6 本地化 Xib

6.1 本地化 Xib

  1. 建立 xib 的 vc

  2. Localize xib 文件,注意:直接選擇 Base,不要選其餘

  • 選其餘的話,會沒有生成對應的 key-value
  1. 勾選其餘的語言

相比於其餘的.strings文件,xib 或 sb 本地化以後,對應語言的.strings 文件是能夠變換成特定 xib 樣式的

你能夠選擇 讓其餘語言以 strings 文件形式來 基於Base 的 xib;或者每一個語言都成爲獨立的 xib 文件 可是不建議使用獨立 xib 的形式,固然若是不一樣語言不一樣佈局的話,也是可使這樣形式的

  1. 選擇 Base 的 String 自動生成strings 文件內容瀏覽 系統會根據當前 xib 中的子控件(~限文本控件,如:Label、Button等~),的 Object ID 生成內容鍵值

  2. 根據語言修改對應 value 值便可,系統會自動獲取xib 中控件 ID 而後匹配系統語言進行內容賦值

  3. 修改 Xcode 的語言設置,查看運行結果

  • 英文

  • 法語

6.2 在Interface Builder中預覽本地化

在Interface Builder中,您能夠在不運行應用程序的狀況下預覽用戶界面的本地化。

  1. 在項目導航器中,選擇要預覽的文件.storyboard或.xib文件

  2. 選擇視圖>輔助編輯器>顯示助手編輯器

  3. 在助手編輯器跳轉欄中,打開「助手」彈出菜單,滾動並選擇「預覽」項,而後從子菜單中選擇.storyboard或.xib文件(~若是應用程序用戶界面的預覽未顯示在助理編輯器中,請在圖標或大綱視圖中選擇要預覽的窗口或視圖~)

  4. 在助理編輯器中,從右下角的語言彈出菜單中選擇要預覽的本地化。(~本地化的預覽顯示在助理編輯器中。若是選擇實際語言,則不須要本地化或須要本地化但當前不是本地化的字符串將以大寫形式顯示~)

6.3 添加新控件至 XIB

  1. 不會聯動變化 咱們發現,添加新控件後,相應的 strings 文件沒有自動發生變化⁉️

注意:Xib相應語言的strings一旦生成後,Base Xib有任何編輯都不會影響到strings,即刪除或添加了一個Label,strings也不會同步作相應的改動

  1. 手動添加咯(~固然是能夠的~)
  • 獲取到對應 Label 的 ObjectID,而後參考以前生成 strings 以前已經添加到 xib 的 label 處理格式,分別修改對應語言的 strings 文件,以下:

  • 運行效果

6.3 自動化更新 strings 文件

  1. 方式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的尾部(~實在麻煩~)
  1. 方式2:使用腳原本實現自動追加新 key-value,刪除再也不存在的 key-value 腳本內仍是經過使用 ibtool
  • 邏輯是:假設原來咱們就有翻譯文件A,添加控件後,咱們再執行一次國際化指令,生成文件B,咱們拿A和B對比,把B中多出來的鍵值對插入A文件的尾部,將A中有而B中沒有的鍵值對刪掉(即控件被刪除),這樣咱們就算是更新了storyboard的翻譯文件了

  • 參照上述的邏輯,咱們能夠藉助腳本文件來實現,Xcode的Run Script也提供了腳本支持,可讓咱們在Build後執行腳本

2.1 新建 py 腳本

AutoGenStrings.py參考 demo 工程

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 將使用了NSLocalizedStringviewController.m文件,生成對應語言環境的 strings 文件

  • 當全部的.m文件都使用NSLocalizedString修改好以後,就能夠動用genstrings工具了
  1. 啓動終端,進入工程所在目錄。
  2. 新建須要支持的語言.lproj 文件夾,位置默認放在項目根目錄下 目錄名會做用到Localizable.strings文件對應的語言,因此目錄名稱不能寫錯了。
mkdir zh-Hans.lproj
mkdir en.lproj
複製代碼
  • 推薦經過 Xcode 幫咱們生成,參考文章 「第1點:添加要支持的國際語言」,這樣你還能夠省去語言簡寫目錄名的煩惱,直接從 Xcode 中選擇你想要支持的國際語言

  • 選擇語言

  • 生成的.lproj文件夾

  • 發現沒有 en.lproj 文件夾,不要緊,點選 main.storyboard,在文件的 localize 位置勾上 English 選項,同理 launch.storyboard 也一樣操做

  • 出現了 en.lproj

  1. 生成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,其餘同理
  1. 生成Localizable.strings文件都拖拽到工程中,Xcode會自動合併成一個,而且對應生成的內容是按照前面NSLocalizedString(@"home", @"這個是用來在生成 strings 文件時,在對應的 key-value 行上的註釋,用來提示翻譯員或者猿們的相關提示")生成的。

  2. 以後咱們將這些文件分發到翻譯員(~或者你本身手裏~)

注意:genstrings指令只能是該目錄下的文件遍歷,但不能實現遞歸遍歷,要實現遞歸變量,可使用下述命令 find ./ -name *.m | xargs genstrings -o en.lproj 這是shell組合指令find+xargsfind ./ -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:如非特別說明,全部文章均爲原創做品,著做權歸做者全部,轉載需聯繫做者得到受權,並註明出處,全部打賞均歸本人全部!

相關文章
相關標籤/搜索