LoginSignup
0

More than 5 years have passed since last update.

Interface Builderで行うローカライゼーション (DRY String Localization with Interface Builder)

Last updated at Posted at 2017-09-17

Original Link
by Victor Pavlychko
translated Korean by pilgwon

image1

格好いいアプリには格好いいローカライゼーションが必要であります。そしてユーザーは自分が好きなアプリが自分の言語で利用できるオプションがあるのに喜ぶでしょう。開発初期段階だとしてもインターフェースのローカライゼーションをサポートすることにおいて開発者は異論がないでしょう。特にそれがやりやすいのであれば最もやるべき作業ではないでしょうか。

私はデザインをInterface Builderでやることが好きです。この記事にはローカライゼーションをどのようにアクセスするかを共有するつもりです。

普通、XIBファイルかStoryBoardをローカライゼーションする時、 ファイルかStoryBoardをローカライゼーションする時、Xcodeは気持ちよくリソースをコピーするし、貴方は重複されたView Layoutに打つかるでしょう。orz..DRY方法論をやろうとするとそれはいい選択と言えないでしょう。 😕

そうする代わりにInterface Builderのローカライゼーション用語に “@”-prefixを付けておいて viewDidLoadawakeFromNibのようなメソッドで各自に合うローカライゼーションされた値で変更してあげることを提案します。以下がInterface Builderで見た時どう見られるのかのサンプルです:

image2

ローカライジェーションの対象に @ prefixを利用して必要であれば他の実際の値と混ぜ合わせるようにします。追加で、@@ prefixはローカライジェーションしなくてもいいのに@が含まれている場合に@の代わりに利用します。

Swiftによくあるように先にプロトコルから始めます:

//gist.github.com/victor-pavlychko/b6a1b37899485e5d24a8938509e018d3#file-better_localization_localizable-swift
public protocol Localizable {
    func localize()
}

次は文字列をローカライジェーションして属性にローカライジェーションされた値を適用するのに役に立つヘルパー達を含めているExtensionです:

//gist.github.com/victor-pavlychko/56da390872c9044b913e5c88f2ad401d#file-better_localization_localizableextension-swift
public extension Localizable {

    public func localize(_ string: String?) -> String? {
        guard let term = string, term.hasPrefix("@") else {
            return string
        }
        guard !term.hasPrefix("@@") else {
            return term.substring(from: term.index(after: term.startIndex))
        }
        return NSLocalizedString(term.substring(from: term.index(after: term.startIndex)), comment: "")
    }

    public func localize(_ string: String?, _ setter: (String?) -> Void) {
        setter(localize(string))
    }

    public func localize(_ getter: (UIControlState) -> String?, _ setter: (String?, UIControlState) -> Void) {
        setter(localize(getter(.normal)), .normal)
        setter(localize(getter(.selected)), .selected)
        setter(localize(getter(.highlighted)), .highlighted)
        setter(localize(getter(.disabled)), .disabled)
    }
}
参考: 2番目のローカライジェーションヘルパーはSwift 4では KeyPath Syntaxアップグレードが必要になります。

今まではいいです。これからいくつかのローカライジェーションを実装してみましょう。その過程自体はコンテナーがその子供に自分をローカライジェーションさせる作業のため明白的に再帰的です:

//gist.github.com/victor-pavlychko/7561f44595381a91c456b06097e30d65#file-better_localization_uiviewextensions-swift
extension UIView: Localizable {
    public func localize() {
        subviews.forEach { $0.localize() }
    }
}

この実現には大体のアプリで必要にする共通コントロールに関するローカライジェーションサポートを追加してみます。実装方法は簡単です:

//gist.github.com/victor-pavlychko/a92451e923a5c11e5a242d3fe4c8f131#file-better_localization_uiviewextensions2-swift
public extension UILabel {
    public override func localize() {
        super.localize()
        localize(text) { text = $0 }
    }
}

public extension UIButton {
    public override func localize() {
        super.localize()
        localize(title(for:), setTitle(_:for:))
    }
}

UIButtonのタイトルを設定することは可能な限り全てのコントロール状態に対するローカライジェーションを適用する他のヘルパーを利用することを覚えておきましょう。

ViewのみがInterface Builderで設定できるオブジェクトではありません。
次に出るオブジェクトも設定が可能なので覚えておきましょう:

  1. UIBarItemとそのサブクラス : UIBarButtonItem そして UITabBarItem
  2. UINavigationItem
  3. あなたのアプリで利用すると決めた全てのオブジェクト
//gist.github.com/victor-pavlychko/a0fc51221de4d287891ddcbf3b00f7b1#file-better_localization_uinavigationitemextensions-swift
extension UIBarItem: Localizable {
    public func localize() {
        localize(title) { title = $0 }
    }
}

public extension UIBarButtonItem {
    public override func localize() {
        super.localize()
        customView?.localize()
    }
}

extension UINavigationItem: Localizable {
    public func localize() {
        localize(title) { title = $0 }
        localize(prompt) { prompt = $0 }
        titleView?.localize()
        leftBarButtonItems?.forEach { $0.localize() }
        rightBarButtonItems?.forEach { $0.localize() }
    }
}

最後に、ローカライジェーションフローをどこかでは始めないといけません。そのためには主に次のイベントをよく使います:
1. UIViewControllerのサブクラス viewDidLoadメソッドの中でtitle,navigationItem,tabBarItemそしてviewをローカライジェーションします。
2. awakeFromNibメソッドの中でUITableViewCellのコンテンツとUICollectionViewCellのサブクラスをローカライジェーションします。

コンテンツ、ナビゲーションそしてタブバーをローカライジェーションする時に使うUIViewControllerのためのヘルパーは以下となります:

//gist.github.com/victor-pavlychko/25b8fbdaf02d9af90d5de7a9e391f90c#file-better_localization_uiviewcontrollerexensions-swift
extension UIViewController: Localizable {
    public func localize() {
        localize(title) { title = $0 }
        navigationItem.localize()
        tabBarItem?.localize()
        view.localize()
    }
}

最後まで読んでいただきましてありがとうございました。これからあなたのプロジェクトに適用してみましょう。 😉. 記事の内容が良かったり、直接プロジェクトに適用してみたとしたら 👏 の押下のこと宜しくお願い致しますね。(本文記事にあります。)

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0