[iOS] リアルタイムにローカライゼーション文字列を変更できるlocalizationKitを試してみました。

1 はじめに

localizationKitは、iOS用のリアルタイムなローカライゼーションの配信システムです。 再コンパイルや再デプロイをしなくても、サーバ上でテキストを編集する事で、アプリの表示を更新したり、新しく別の言語を追加したりする事ができます。

https://github.com/willpowell8/LocalizationKit_iOS

localizationKitは、MITライセンスで公開されており、CocoaPodで簡単にインストールが可能です。

pod "LocalizationKit"

なお、2017年1月現在、最新のバージョンは、1.1.1です。

ライブラリの導入後は、下記のインポートで利用可能になります。

import LocalizationKit

2 使用方法

(1) API Keyの作成

http://www.localizationkit.com/app/ に接続し、アプリケーション名(何でも可能)を入力してCREATE NEWボタンを押すことで新しいアプリが作成できます。

001

作成後に表示されるAPI Keyは、アプリ作成時に必要になりますので手元に保存しておきます。

002

(2) 言語の追加

続いて、Add Languageでサポートする言語を追加します。 003

言語は、いくつでも追加可能です。(後で追加することも可能です)

004

(3) アプリの初期化

アプリに初期化コードとして、下記のように追加します。([KEY] は、先程コピーしたAPI Keyです)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    Localization.start(appKey: "[KEY]", libe: true)
    return true
}

libe: true の設定は、リアルタイにテキストの変更をする設定です。

変更の方法(タイミング)は、live_localizationという名のバンドル設定で決定したり、

Localization.start(appKey: "[KEY]", useSettings: true)

アプリから動的に変更することも可能です。

Localization.liveEnabled = true

(4) storyboard

StoryboardUILabelUIButtonを配置し、アトリビュートでLocalization Keyに、キー(何でも可能)をセットします。

008 009

localizationKitでは、@IBInspectableでコントロールが拡張されており、アトリビュートでLocalization Keyとう文字列を設定することが出来るようになっています。

参考:UILabel+Localization.swift

extension UILabel{
/// Localization Key used to reference the unique translation and text required.
@IBInspectable
public var LocalizeKey: String? {
    get {
        return objc_getAssociatedObject(self, &localizationKey) as? String
    }
    set(newValue) {
        self.localizationClear()
        objc_setAssociatedObject(self, &localizationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        updateLocalisation()
        localizationSetup();
    }
}

なお、localizationKitで対応しているコントールは、下記のとおりです。

  • UILabel
  • UINavigatioNitem
  • String
  • UIBarItem
  • UIBarButtonItem
  • UITextField
  • UIButton

(6) テキストの変更

この状態で、アプリを実行すると、Storyboardで設定したキーが、サーバ上で確認できます。(キーの一覧がアプリからサーバに送られている)

005 006 サーバ上でテキストを変更すると、リアルタイムでアプリの文字列が変更されることを確認できます。

007

(7) 言語の変更

次のようなコードを書くと、以下の出力を得ることができます。

Localization.availableLanguages { (languages) in
        for language in languages {
        print("Key=\(language.key) localizedName=\(language.localizedName)")
    }
}
Key=ja localizedName=Japanese
Key=en localizedName=English

サーバ上で作成した「言語」(Japanese,English)が列挙され、「キー」(ja,en)を割り振られていることが分かります。

言語を変更すには、この「キー」を指定します。

Localization.setLanguage("ja")

指定した言語で設定したテキストが反映されている事を確認できます。

010

3 サーバとの通信

テキストがサーバ上で設定したものとリンクするための仕組みですが、例えば、先程の言語の一覧を取得するファンクションでは、内部で下記のようなAPIが呼ばれています。

https://www.localizationkit.com/api/app/[API-Key]/languages/"  

そして、結果はJSONで受け取っています。

{"languages":
  [
    {"key":"ja","name":{"en":"Japanese"}},
    {"key":"en","name":{"en":"English""}}
  ]
}

また、言語ごとのテキストも、次のようなAPIが準備されています。

https://www.localizationkit.com/api/app/[API-Key]/language/(言語key)"    

ただし、live=trueでリアルタイムのアップデートをONにした場合、アプリとサーバは、常にSocket接続されていることに注意が必要です。 そして、そのSocketを通じてサーバからの指示を受け、アプリ内に通知が送られています。アプリでは、この通知を受けて、上記のようなAPIをコールする仕組みになっています。

参考:LocalizationKit.swift

private static func startSocket(){
    let url = URL(string: server)
    socket = SocketIOClient(socketURL: url!)
    socket?.on("connect", callback: {(data,ack) in
        self.joinLanguageRoom()
        let appRoom = "\((self.appKey)!)_app"
        sendMessage(type: "join", data: ["room":appRoom])
        NotificationCenter.default.post(name: ALL_CHANGE, object: self)
    })
    socket?.on("languages", callback: {(data,ack) in
        //let dictionary = data[0] as! [AnyHashable : Any]
    })
    socket?.on("highlight", callback: {(data,ack) in
        let dictionary = data[0] as! [AnyHashable : Any]
        guard let meta = dictionary["meta"] as? String else {
            return;
        }
        NotificationCenter.default.post(name: self.highlightEvent(localizationKey: meta), object: self)
    })
    socket?.on("text", callback: {(data,ack) in
        let dictionary = data[0] as! [AnyHashable : Any]
        guard let meta = dictionary["meta"] as? String else {
            return;
        }
        let value = dictionary["value"] as! String
        self.loadedLanguageTranslations?[meta] = value
        NotificationCenter.default.post(name: self.localizationEvent(localizationKey: meta), object: self)
    })
    socket?.connect()
}

4 最後に

今回、ローカライゼーション文字列をサーバから変更することができる、localizationKitを試してみました。 仕組みは、シンプルですが、非常に良く作り込まれており、サーバでの操作も快適だと感じました。

5 参考資料


https://github.com/willpowell8/LocalizationKit_iOS