簡(jiǎn)單嘗試
- 首先先創(chuàng)建一個(gè)叫
Loc
的iOS
空項(xiàng)目乱陡,創(chuàng)建好后目錄結(jié)構(gòu)如下:
- 創(chuàng)建一個(gè)
Language
的文件夾在Loc
目錄下溶弟, 然后在Language
目錄下創(chuàng)建一個(gè)叫Localizable
的String 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)體中文祥国。 Xcode
的Localizations
中也可以看到有英文和簡(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):
- 如果找不到對(duì)應(yīng)
key
的value
峻贮, 就會(huì)從value
參數(shù)中取,如果value
參數(shù)中也去不到应闯,就會(huì)將key
作為value
來(lái)顯示 - 如果
tableName
沒(méi)有設(shè)置纤控,就會(huì)從Localizable
table里查找 - 默認(rèn)使用
main bundle
里的配置資源,如果在其它bundle
孽锥,這里bundle
不能省略嚼黔,需要設(shè)置對(duì)應(yīng)的bundle
,比如語(yǔ)言配置可以在一個(gè)package
里惜辑,這時(shí)就需要將bundle
設(shè)置為這個(gè)package
的bundle
了 - 不能使用空字符串作
key
-
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()
}
}
- 既然
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)求提示的配置伞芹。