xcmultilingualとは
作成したローカライズファイルのキーへのアクセスを簡単にします。
例えば、AnimalテーブルのDOGキーにある文言を出力したい場合、
[code lang=swift]
Multilingual.Animal.DOG.string()
[/code]
とすれば、出力されます。AnimalもDOGもそれぞれきちんと補完がでてきます。詳しくは、Youtube動画を御覧ください。
NSLocalizedStringの問題
普段、Xcodeでローカライゼーションファイルにアクセスする場合、このように書くと思います。
NSLocalizedString("DOG", comment: "")
さらに、テーブルを指定したりするとこのようになります。
NSLocalizedString("DOG", tableName: "Animal", bundle: NSBundle.mainBundle(), value: "", comment: "")
キーは文字列なので、そのキーが翻訳ファイルにあるのかどうかもわかりません。
このようにローカライゼーションファイルにアクセスするには以下のような問題がありました。
NSLocalizedString...
メソッドが長い。- どのキーの翻訳があって、どのキーの翻訳がないのかがパッとわからない。
- .stringsファイルを書くのが面倒くさい。
長いメソッドに関してはエイリアスを書けば良いかもしれないのですが、それだけではどのキーの翻訳があるかわかりません。
xcmultilingualは上記上から2つの問題を解決します。コマンドを実行すると、xcodeのプロジェクトファイルからローカライズファイルを探し出し、使いやすい形に成形したメソッドを生成します。
使い方
詳しくは、READMEを見ていただければと思いますが、簡単に解説します。
1. gemとしてインストールする
gem install xcmultilingual
、または、Gemfileにgem 'xcmultilingual'
と書いてインストールします。
2. Xcodeのファイルの一番上の階層に、結果を出力するための空の.swiftファイルを作成する
[code lang=bash]
.
├── DemoApp
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ ├── Images.xcassets
│ ├── Info.plist
│ ├── Loalizations
│ ├── Multilingual.swift
[/code]
3. 先ほどのファイルを指定してupdateコマンドを実行する
[code lang=bash]
$ xcmultingual update ./DemoApp/Multilingual.swift
[/code]
すると、Multiingual.swiftに下記のようなstructが生成されます。
例:
import Foundation struct Multilingual { enum Localizable: String { case HELLO = "HELLO" case GOODMORNING = "GOODMORNING" case GOODEVENING = "GOODEVENING" func string() -> String { return NSLocalizedString(rawValue, tableName: "Localizable", bundle: NSBundle.mainBundle(), value: "(rawValue)", comment: "") } static func keys() -> [String] { return ["HELLO", "GOODMORNING", "GOODEVENING"] } static func localizations() -> [String] { return Localizable.keys().map { Localizable(rawValue: $0)!.string() } } } enum Animal: String { case CAT = "CAT" case DOG = "DOG" case BEAR = "BEAR" case DEER = "DEER" func string() -> String { return NSLocalizedString(rawValue, tableName: "Animal", bundle: NSBundle.mainBundle(), value: "(rawValue)", comment: "") } static func keys() -> [String] { return ["CAT", "DOG", "BEAR", "DEER"] } static func localizations() -> [String] { return Animal.keys().map { Animal(rawValue: $0)!.string() } } } private static func bundle(relativePath: String) -> NSBundle { var components = (__FILE__ as String).pathComponents components.removeLast() let bundlePath = join("/", components) + "/" + relativePath return NSBundle(path: bundlePath) ?? NSBundle.mainBundle() } }
4. 気持ちいい補完とともに使う
これでローカライズファイルに簡単にアクセスできるようになります。Multilingualと打つとプロジェクト内の全てのテーブルが補完候補としてでてきます。
[code lang=swift]
Multilingual.Localizable
Multilingual.Animal
[/code]
ここで、Animalを選択すると、Animalテーブルの中のキーが補完候補としてでてきます。
[code lang=swift]
Multilingual.Animal.CAT
Multilingual.Animal.DOG
Multilingual.Animal.BEAR
Multilingual.Animal.DEER
[/code]
すごい!翻訳結果を出力するにはenumのstring()
コマンドを打ちます。
[code lang=swift]
Multilingual.Animal.DOG.string()
[/code]
簡単です!
RubyGemsで配布しています
そもそものローカライゼーションファイルを作るにはLinguanが便利かも
このライブラリのサンプルを作ってテストするときに、Linguanを使いました。ローカライゼーションが普通に書くよりは簡単に書けます。
後記
RubyのGemをはいふするのははじめての経験です。Rubyに慣れているわけでもなく、ファイルの探索など思うように進まず疲れました。開発中は、RubyとSwiftを半分づつ書いていました。やりたいことはわかっているのですが、うまく表現できずという感じでした。
ローカライズファイルに簡単にアクセスしたいなともう2年くらい前から思っていました。ただ、今回Swiftで強化されたenumを使うことで補完がスムーズにできることを感じ、xcmultilingualを形にしようと思いました。
2年間やりたいと思っていたことがとりあえずできてよかったです。
今の段階ではまだ、メインのプロジェクトのローカライズファイルしか対象にしないように限定していますが、バージョンアップでたのバンドルのローカライズファイルも扱えるようにしたいと思っています。
あと、慣れないRubyで書いたので、おかしな記述やバグなどもあると思いますので少しずつ直していきたいです。