iOS 支持多語(yǔ)言

簡(jiǎn)單嘗試

  • 首先先創(chuàng)建一個(gè)叫LociOS 空項(xiàng)目乱陡,創(chuàng)建好后目錄結(jié)構(gòu)如下:
  • 創(chuàng)建一個(gè)Language的文件夾在Loc目錄下溶弟, 然后在Language目錄下創(chuàng)建一個(gè)叫 LocalizableString File(Legacy)文件, 創(chuàng)建好后,我們show in finder可以看到Xcode 自動(dòng)幫我們創(chuàng)建了一個(gè)叫 en.lproj的文件夾


這是因?yàn)轫?xiàng)目默認(rèn)選擇的語(yǔ)言是英文蒲稳,可以在下圖中查看氮趋,如果你設(shè)置的是中文,生成的就是zh-Hans.lproj文件夾

  • 添加支持新的語(yǔ)言江耀, 比如我們這個(gè)項(xiàng)目要同時(shí)支持簡(jiǎn)體中文和英文剩胁,這時(shí)我們只需要在下圖點(diǎn)+按鈕選擇簡(jiǎn)體中文就好

完成后可以看到Language->Localizable中有兩個(gè)配置文件,分別對(duì)應(yīng)英文和簡(jiǎn)體中文祥国。 XcodeLocalizations 中也可以看到有英文和簡(jiǎn)體中文的配置了

  • 在配置文件中添加對(duì)應(yīng)字符串昵观,我們?cè)?code>Localizable(English)中添加 "personal_name" = "英文-san zhang"; ,在Localizable(Chinese, Simplified) 中添加"personal_name" = "簡(jiǎn)體中文-張三";
  • 現(xiàn)在我們可以使用了, 將ContentView中代碼改成如下:
struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(NSLocalizedString("personal_name", comment: ""))
        }
        .padding()
    }
}

那么運(yùn)行就會(huì)得到下圖結(jié)果,左邊英文舌稀,右邊中文

我們看到會(huì)根據(jù)不同的系統(tǒng)語(yǔ)言去相應(yīng)的配置中去取對(duì)應(yīng)的內(nèi)容啊犬,這里我們的項(xiàng)目就簡(jiǎn)單支持多語(yǔ)言了。


NSLocalizedString

  • 上面我們簡(jiǎn)單在配置文件中為不同語(yǔ)言配置了內(nèi)容壁查,然后NSLocalizedString會(huì)根據(jù)不同語(yǔ)言加載不同配置文件中的內(nèi)容觉至,那么NSLocalizedString做了什么呢?
 /// Returns the localized version of a string.
///
/// - parameter key: An identifying value used to reference a localized string.
///   Don't use the empty string as a key. Values keyed by the empty string will
///   not be localized.
/// - parameter tableName: The name of the table containing the localized string
///   identified by `key`. This is the prefix of the strings file—a file with
///   the `.strings` extension—containing the localized values. If `tableName`
///   is `nil` or the empty string, the `Localizable` table is used.
/// - parameter bundle: The bundle containing the table's strings file. The main
///   bundle is used by default.
/// - parameter value: A user-visible string to return when the localized string
///   for `key` cannot be found in the table. If `value` is the empty string,
///   `key` would be returned instead.
/// - parameter comment: A note to the translator describing the context where
///   the localized string is presented to the user.
///
/// - returns: A localized version of the string designated by `key` in the
///   table identified by `tableName`. If the localized string for `key` cannot
///   be found within the table, `value` is returned. However, `key` is returned
///   instead when `value` is the empty string.
....

@available(macOS 10.10, iOS 8.0, watchOS 2.0, tvOS 9.0, *)
public func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String
  • 上面是NSLocalizedString的API, 注釋有很多睡腿,我這里只保留了參數(shù)的注釋语御。
    這里說(shuō)明以下幾點(diǎn):
  1. 如果找不到對(duì)應(yīng)keyvalue峻贮, 就會(huì)從value參數(shù)中取,如果 value參數(shù)中也去不到应闯,就會(huì)將key作為value來(lái)顯示
  2. 如果tableName沒(méi)有設(shè)置纤控,就會(huì)從Localizable table里查找
  3. 默認(rèn)使用main bundle里的配置資源,如果在其它bundle孽锥,這里bundle不能省略嚼黔,需要設(shè)置對(duì)應(yīng)的bundle,比如語(yǔ)言配置可以在一個(gè)package里惜辑,這時(shí)就需要將bundle設(shè)置為這個(gè)packagebundle
  4. 不能使用空字符串作key
  5. comment 是對(duì)應(yīng)說(shuō)明

優(yōu)化

  • 有了對(duì)NSLocalizedString的了解,我們就可以做一些優(yōu)化疫赎。比如我們可以String 加上一個(gè)分類盛撑,來(lái)優(yōu)化我們?nèi)≈担?具體做法: 首先我們新建一個(gè)String+Localizing的文件來(lái)給String添加一個(gè)fetch的方法:
import Foundation

public extension String {

    /// - Parameter localizedStringKey: Key for the localized string.
    /// - Returns: The localized string associated with the key.
    static func fetch(_ localizedStringKey: String) -> String {
        return NSLocalizedString(
            localizedStringKey,
            comment: ""
        )
    }
}

這樣我們就可以在ContentView使用了,使用String.fetch("personal_name")了和NSLocalizedString("personal_name", comment: "")效果是一樣的

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(NSLocalizedString("personal_name", comment: ""))
            Text(String.fetch("personal_name"))
        }
        .padding()
    }
}
  • 這樣直接使用key值我們很容易寫錯(cuò),所以我們可以定義一個(gè)枚舉捧搞,把這些key值定義成枚舉里的變量抵卫, 比如我們新建一個(gè)叫Localizable.swift的文件,在這個(gè)文件里我們定義一個(gè)Localizable的枚舉胎撇,然后定義一個(gè)叫personalName的靜態(tài)變量如下:
public enum Localizable {
    /// ...
    public static let personalName = "personal_name"
}

這樣我們就可以使用String.fetch(Localizable.personalName)取獲取文本了介粘,和上面兩種使用效果是一樣的

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(NSLocalizedString("personal_name", comment: ""))
            Text(String.fetch("personal_name"))
            Text(String.fetch(Localizable.personalName))
        }
        .padding()
    }
}
image.png
  • 既然public func NSLocalizedString(_ key: String, tableName: String? = nil, bundle: Bundle = Bundle.main, value: String = "", comment: String) -> String支持傳遞tableName,那么我們也可以制作多個(gè)table將我們的文本根據(jù)一定的規(guī)則進(jìn)行分類晚树,這樣可以將文本分散到不同的table中姻采,防止所有文本都存放到一個(gè)table里面導(dǎo)致table內(nèi)容過(guò)多.

比如,我們新建一個(gè)LocalizableGeneral.strings的文件

不過(guò)這次我們看到Xcode左側(cè)文件導(dǎo)航里并沒(méi)有像Localizable那樣幫我們分成Localizable(English)Localizable(Chinese, Simplified)兩個(gè)文件爵憎,我們show in finder中看到只在en.lproj目錄下多了一個(gè)LocalizableGeneral.strings文件慨亲,而zh-Hans.lproj中并沒(méi)有

查看Xcode的配置看到也是只在English下多了一個(gè)文件,而中文下還是1個(gè)

不過(guò)這沒(méi)關(guān)系宝鼓,我們可以把en.lproj目錄下的LocalizableGeneral.strings復(fù)制一份到zh-Hans.lproj目錄下刑棵,然后將LocalizableGeneral.strings拖動(dòng)到Xcode LocalizableGeneral文件下,這樣X(jué)code 自動(dòng)幫我們分成了LocalizableGeneral(English)LocalizableGeneral(Chinese,Simplified)

然后我們分別在LocalizableGeneral(English)LocalizableGeneral(Chinese,Simplified)定義好"personal_name_general"對(duì)應(yīng)的文本

然后我們?cè)賱?chuàng)建一個(gè)LocalizableGeneral.swift的文件,內(nèi)容如下:

public enum LocalizableGeneral {
    /// ...
    public static let personalNameGeneral = "personal_name_general"
}

然后在String 的分類中再添加一個(gè)fetchGeneral的方法愚铡,在文件中添加localizableGeneralTableName變量名,注意這個(gè)變量對(duì)應(yīng)內(nèi)容要和創(chuàng)建的LocalizableGeneral文件名一致蛉签, static func fetch(_ localizedStringKey: String) -> String 中的實(shí)現(xiàn)沒(méi)有添加tableName的原因是,如果不添加默認(rèn)會(huì)到Localizable中查找

import Foundation

private let localizableTableName = "Localizable"
private let localizableGeneralTableName = "LocalizableGeneral"

public extension String {

    /// - Parameter localizedStringKey: Key for the localized string.
    /// - Returns: The localized string associated with the key.
    static func fetch(_ localizedStringKey: String) -> String {
        return NSLocalizedString(
            localizedStringKey,
            comment: ""
        )
    }

    static func fetchGeneral(_ localizedStringKey: String) -> String {
        return NSLocalizedString(
            localizedStringKey,
            tableName: localizableGeneralTableName,
            comment: ""
        )
    }
}

這樣我們就可以在ContentView中使用了

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(NSLocalizedString("personal_name", comment: ""))
            Text(String.fetch("personal_name"))
            Text(String.fetch(Localizable.personalName))
            Text(String.fetchGeneral(LocalizableGeneral.personalNameGeneral))
        }
        .padding()
    }
}

運(yùn)行得到如下結(jié)果:

  • 除了上面這種沥寥,我門還可以把文本分散到Localizable的分類中碍舍。比如,我們創(chuàng)建一個(gè)LocalizableError.strings的配置文件营曼,方式同上面LocalizableGeneral.strings文件一樣乒验, 然后再創(chuàng)建一個(gè)LocalizableError.swift文件,對(duì)應(yīng)文件內(nèi)容如下:

不過(guò)這次我們要修改一下fetch方法蒂阱,因?yàn)槟壳?code>fetch方法只會(huì)去Localizable配置文件中去找锻全,但我們配置在LocalizableError中狂塘,這樣就會(huì)導(dǎo)致照不到,fetch方法具體修改如下:

/// 首先去Localizable配置文件中根據(jù)localizedStringKey 查找鳄厌,如果找不到就會(huì)使用value的值荞胡,而value的值就會(huì)去LocalizableError這個(gè)配置文件中去找
    static func fetch(_ localizedStringKey: String) -> String {
        return NSLocalizedString(
            localizedStringKey,
            value: NSLocalizedString(
                localizedStringKey,
                tableName: localizableErrorTableName,
                comment: ""),
            comment: ""
        )
    }

這樣我們可以在ContentView中使用了

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text(NSLocalizedString("personal_name", comment: ""))
            Text(String.fetch("personal_name"))
            Text(String.fetch(Localizable.personalName))
            Text(String.fetchGeneral(LocalizableGeneral.personalNameGeneral))
            Text(String.fetch(Localizable.personalNameError))
        }
        .padding()
    }
}

運(yùn)行得到下面結(jié)果:



app 名 和 申請(qǐng)權(quán)限提示的配置

  • 除了上面文本的顯示,多語(yǔ)言還涉及到不同語(yǔ)言環(huán)境顯示的app 名稱也不一樣了嚎,另外還有訪問(wèn)權(quán)限的提示也不一樣泪漂。這兩個(gè)問(wèn)題都是在Info.plist文件中設(shè)置的,解決這兩個(gè)問(wèn)題就需要我們創(chuàng)建一個(gè)名為InfoPlist.strings的文件歪泳,注意:名字一定要是InfoPlist,別的名字Xcode不認(rèn)萝勤。
    名字的話我們?cè)诓煌Z(yǔ)言配置文件中設(shè)置CFBundleDisplayName key的value就好,權(quán)限的話也是一樣,根據(jù)不同的語(yǔ)言環(huán)境給相應(yīng)權(quán)限的key設(shè)置value。 下面我們?cè)O(shè)置的是簡(jiǎn)體中文和英文環(huán)境下仆百,app 名字 和 網(wǎng)絡(luò)請(qǐng)求提示的配置伞芹。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖蜗巧,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蕾盯,居然都是意外死亡幕屹,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門刑枝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)香嗓,“玉大人,你說(shuō)我怎么就攤上這事装畅】坑椋” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵掠兄,是天一觀的道長(zhǎng)像云。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蚂夕,這世上最難降的妖魔是什么迅诬? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮婿牍,結(jié)果婚禮上侈贷,老公的妹妹穿的比我還像新娘。我一直安慰自己等脂,他們只是感情好俏蛮,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布撑蚌。 她就那樣靜靜地躺著,像睡著了一般搏屑。 火紅的嫁衣襯著肌膚如雪争涌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天辣恋,我揣著相機(jī)與錄音亮垫,去河邊找鬼。 笑死伟骨,一個(gè)胖子當(dāng)著我的面吹牛饮潦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播携狭,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼害晦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了暑中?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鲫剿,失蹤者是張志新(化名)和其女友劉穎鳄逾,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灵莲,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雕凹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了政冻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枚抵。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖明场,靈堂內(nèi)的尸體忽然破棺而出汽摹,到底是詐尸還是另有隱情,我是刑警寧澤苦锨,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布逼泣,位于F島的核電站,受9級(jí)特大地震影響舟舒,放射性物質(zhì)發(fā)生泄漏拉庶。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一秃励、第九天 我趴在偏房一處隱蔽的房頂上張望氏仗。 院中可真熱鬧,春花似錦夺鲜、人聲如沸皆尔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)床佳。三九已至滋早,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間砌们,已是汗流浹背杆麸。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浪感,地道東北人昔头。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像影兽,于是被迫代替她去往敵國(guó)和親揭斧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

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

  • APP語(yǔ)言本地化峻堰,即語(yǔ)言國(guó)際化讹开。指的是根據(jù)用戶操作系統(tǒng)的語(yǔ)言設(shè)置,自動(dòng)將APP的語(yǔ)言設(shè)置為和操作系統(tǒng)一致的語(yǔ)言環(huán)境...
    喔牛慢慢爬閱讀 5,579評(píng)論 0 11
  • 歡迎訪問(wèn)我的博客muhlenXi捐名,該文章出自我的博客旦万。 版權(quán)聲明:本文為muhlenXi原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處镶蹋,...
    賣碼維生閱讀 3,280評(píng)論 0 12
  • ** 原文發(fā)表在:https://www.xiaolei0808.com/2016/04/24/Localized...
    金小白先生閱讀 17,569評(píng)論 16 90
  • 根據(jù)當(dāng)前設(shè)備語(yǔ)言自動(dòng)切換顯示成艘。 幾個(gè)涉及到多語(yǔ)言本地化設(shè)置的: 1.應(yīng)用名稱 2.文字 3.圖片、素材 4.Sto...
    齊玉婷閱讀 3,519評(píng)論 2 3
  • 相關(guān)問(wèn)題 國(guó)際化官網(wǎng)鏈接 Infoplist.strings為什么可以替換info.plist的名稱贺归?什么時(shí)機(jī)替換...
    wxkkkkk閱讀 2,579評(píng)論 0 1