原文鏈接:http://www.cocoachina.com/ios/20170809/20190.html
按照原文操作,發(fā)現(xiàn)腳本有問題,各種Google+Baidu狂補Shell+sed知識,最終修復了shell腳本問題(正確腳本在下文中已更正)。

本文從提升效率和減少錯誤兩方面對傳統(tǒng)的多語言本地化方式進行了優(yōu)化。
- 傳統(tǒng)的方法
- 提升點效率
- 減少些錯誤
- 自動化萬歲
傳統(tǒng)的方法
在 Localizable.strings 中寫入多種語言的版本,然后使用 NSLocalizedString 進行本地化:
# en.lproj/Localizable.strings
"login" = "Login";
"logout" = "Logout";
# zh-Hans.lproj/Localizable.strings
"login" = "登錄";
"logout" = "退出";
# usage
loginButton.title = NSLocalizedString("login", comment: "login")
logoutButton.title = NSLocalizedString("logout", comment: "logout")
這有什么問題呢?
繁瑣!每次都要寫 NSLocalizedString(“xxx”, comment: “xxx”) ,雖然有代碼補全,但依然很費時。
提升點效率
直接上代碼:
extension String {
var localized: String {
return NSLocalizedString(self, comment: self)
}
}
于是現(xiàn)在的使用方式就變成了:
loginButton.title = "login".localized
logoutButton.title = "logout".localized
這樣代碼簡潔多了,也保留了代碼的自解釋。
但,依然還有問題,如果我不小心寫成了:
loginButton.title = "login".localized
logoutButton.title = "loguot".localized
編譯不會報錯,但logoutButton的title卻出不來(注意 “l(fā)oguot”.localized),寫錯一個字母,抓bug抓好長時間的經(jīng)歷相信很多人都遇到過吧。
這里涉及到編碼中的一個小技巧:不要徒手寫同一個需要多次使用的字符串,盡量定義成常量進行調(diào)用
減少些錯誤
還是直接上代碼:
extension String {
static var localized_login: String { return "login".localized }
static var localized_logout: String { return "logout".localized }
}
現(xiàn)在用起來就更爽了:
loginButton.title = .localized_login
logoutButton.title = .localized_logout
得益于Xcode代碼提示補全的功能,我只需輸入”.” “l(fā)ogin” 回車,基本就就可以完成輸入:

乍一看,已經(jīng)將寫字符串時出錯的概率降到最低了,但這樣又要多寫一堆代碼,豈不是把之前好不容易提升起來的效率又降低了,再加上萬一,我們在寫 localized_logout 時還是寫成了 “l(fā)oguot”.localized ,這不是”辛辛苦苦大半年,一朝回到解放前”的節(jié)奏?
自動化萬歲
思路:使用腳本讀取 Localizable.strings ,然后輸出成我們需要的常量格式。

Build Phases中新建一個 Run Script,填入以下腳本:
# Localizable.strings文件路徑
localizableFile="${SRCROOT}/${PROJECT_NAME}/Support/en.lproj/Localizable.strings"
# 生成的swift文件路徑(根據(jù)個人習慣修改)
localizedFile="${SRCROOT}/${PROJECT_NAME}/Source/Utils/LocalizedUtils.swift"
# 將localizable.strings中的文本轉為swift格式的常量,存入一個臨時文件
sed "s/^\"\([a-z]*\).*/static var localized_\1 : String { return \"\1\".localized }/g" "${localizableFile}" > "${localizedFile}.tmp"
# 先將localized作為計算屬性輸出到目標文件
echo -e "import Foundation\n\nextension String {\n var localized: String { return NSLocalizedString(self, comment: self) }" > "${localizedFile}"
# 再將臨時文件中的常量增量輸出到目標文件
cat "${localizedFile}.tmp" >> "${localizedFile}"
# 最后增量輸出一個"}"到目標文件,完成輸出
echo -e "\n}" >> "${localizedFile}"
# 刪除臨時文件
rm "${localizedFile}.tmp"
以上腳本的作用就是將localizable.strings中的內(nèi)容轉換成swift的常量形式,并作為String的extension存儲起來,具體步驟看注釋。
(原文中將文本轉為Swift格式常量中,錯誤的將值作為NSLocalizedString的key,原本shell腳本如下:)
sed "s/^\"/ static var localized_/g" "${localizableFile}" | sed "s/\" = \"/: String { return \"/g" | sed "s/;$/.localized }/g" > "${localizedFile}.tmp"
其中有幾點需要注意:
sed的用法中,^… 表示以…開頭,…$ 表示以…結尾 [參考鏈接]。
> 表示覆蓋輸出到文件,>> 表示增量輸出到文件。
echo -e 表示將\n作為換行符輸出(其他轉義字符同效)。
將 Run Script 放在 Compile Sources 的上面,這樣可以在編譯代碼前執(zhí)行,如果出現(xiàn)錯誤也很容易定位(例如Localizable.strings中行末忘記寫分號)。
腳本效果:
本地化文件:
# en.lproj/Localizable.strings
"login" = "Login";
"logout" = "Logout";
輸出文件:
# LocalizedUtils.swift
import Foundation
extension String {
var localized: String { return NSLocalizedString(self, comment: self) }
static var localized_login: String { return "login".localized }
static var localized_logout: String { return "logout".localized }
}
至此,我們只要在寫好Localizable.strings或有修改時 ?+B build一下,就能愉快的使用了。