前回、Groovy の Config ファイルからリソース・バンドルを生成するスクリプトを書きました。 でも、アプリケーションのビルドとは別にスクリプトを実行しないといけないので、このままではちょっと面倒。 ってことで、今回はアプリケーションのビルド時にリソース・バンドルの生成も行われるようにしてみます。 もちろん、リソース・バンドルの生成だけを行うこともできるようにしておきましょう(一覧)。
まずはリファクタリング
ビルド・プロセスにリソース・バンドルの生成を織り込む前に、まずは前回作成したスクリプトをリファクタリングしておきます。 このリファクタリングによって、「ビルド・プロセス中で実行」する場合と「スクリプト単独で実行」する場合に共通する処理を抜き出して再利用します(参考 Griffon Guide 「4.2 Re-using Griffon scripts」)。
- _Internationalize.groovy ・・・共通する処理
- GenerateResourceBundles.groovy ・・・単独で実行する場合の処理(引数の処理)
_Internationalize.groovy
まずは共通する処理。 Griffon では使い回すスクリプトは '_' で始める習わしだそうです。
- FunctionPlotter/scripts/_Internationalize.groovy
コードはこんな感じ:
includeTargets << griffonScript("Init") encoding = System.getProperty('file.encoding') target(generateResourceBundles: "Generate Resource Bundles") { def slurper = new ConfigSlurper() fileset(dir:'griffon-app/i18n', includes:'*.groovy').each{ antFile -> def file = antFile.file def props = slurper.parse(file.getText(encoding)).toProperties() def filename = file.name.replace('.groovy', '.properties') new File("griffon-app/i18n/$filename").withOutputStream{ out -> props.store(out, null) } } }
変更点は
- 引数の処理(argsMap など)は除去。
- ターゲット名を 'main' ではなく 'generateResourceBundles' に変更。 たのスクリプトからこのターゲットの処理を呼び出したい場合は、このターゲット名を参照する。
- defaultTarget の指定を除去。
GenerateResourceBundles.groovy
このスクリプトは単独で実行する場合に引数を処理するスクリプト。 引数を処理したら上記の _Internationalize.groovy に定義してあるターゲットを呼び出します。
- FunctionPlotter/scripts/GenerateResourceBundles.groovy
内容は下記の通り:
includeTargets << new File("$basedir/scripts/_Internationalize.groovy") // 上記の _Internationalize.groovy を読み込む target(main: "Generate Resource Bundles") { def params = argsMap['params'] if(!params.isEmpty()) encoding = params[0] generateResourceBundles() // _Internationalize.groovy の generateResourceBundles ターゲットを呼び出す。 } setDefaultTarget(main)
Gant スクリプトに特有っぽいコードがいくつかあるので解説:
- includeTargets << ・・・_Internationalize.groovy スクリプトを読み込む。
- encoding = params[0]・・・encoding プロパティ(これは _Internationalize.groovy で使う)に値をセットする。
- generateResourceBundles()・・・_Internationalize.groovy に定義したターゲットを呼び出す。
さて、これでリファクタリング完了。 リファクタリングなので、スクリプトの実行の仕方は前回と同じです:
griffon gRB
コンパイル時にリソース・バンドルを生成するようにする
ではビルド・プロセス中にリソース・バンドルを生成する処理を織り込みましょう(参考 Griffon Guide 「4.3 Hooking into Events」)。 ビルド・プロセス中で発生するイベントは上記参考先にまとめられてますが、ここでは CompileStart イベントがいいでしょう。 このイベントに関するイベント・ハンドラを
- FunctionPlotter/scripts/_Events.groovy
に記述します。 記述の仕方は eventCompileStart プロパティに処理を実行したいクロージャをセットします:
includeTargets << new File("$basedir/scripts/_Internationalize.groovy") def alreadyGenerated = false eventCompileStart = { kind -> if(!alreadyGenerated){ generateResourceBundles() alreadyGenerated = true } }
alreadyGenerated フィールド以外は GenerateResourceBundles.groovy の内容と同様(引数の処理がない分、むしろ簡単)です。 alreadyGenerated フィールドは、リソース・バンドルの生成を一度だけ行うために使用しています。 CompileStart イベントは「ソース・コードのコンパイル」と「テスト・コードのコンパイル」の2度呼ばれるのでこんな実装にしてます*1。
これらのスクリプトができたら
griffon compile
などとすればコンパイル開始時にリソース・バンドルの生成も行ってくれます。 エンコーディングの指定はできませんが。
これで国際化も結構簡単にできるようになったかと。
追記
上記のスクリプトでも動きますが、もう少し改善を。 改善点は
- Config オブジェクトの設定ファイルが変更されていない場合は、リソース・バンドルの生成を行わない
- AntBuilder によるファイルのイテレーションは fileScanner で行う
です。 1つ目は File#lastModified() メソッドを使えば問題なし。 2つ目は Ant API のファイルオブジェクトから java.io.File へ変更する手間が省けます。
includeTargets << griffonScript("Init") encoding = System.getProperty('file.encoding') target(generateResourceBundles: "Generate Resource Bundles") { def slurper = new ConfigSlurper() fileScanner{ fileset(dir:'griffon-app/i18n', includes:'*.groovy') }.each{ configFile -> def filename = configFile.name.replace('.groovy', '.properties') def propFile = new File("griffon-app/i18n/$filename") if(configFile.lastModified() > propFile.lastModified()){ def props = slurper.parse(configFile.getText(encoding)).toProperties() propFile.withOutputStream{ out -> props.store(out, null) echo("Genereate resource bundle : $filename") } } } }
- 作者: Steve Holzner,長瀬嘉秀(監訳),株式会社テクノロジックアート
- 出版社/メーカー: オライリージャパン
- 発売日: 2005/11/18
- メディア: 大型本
- 購入: 2人 クリック: 20回
- この商品を含むブログ (18件) を見る
*1:本当は eventCompile クロージャに渡される引数「kind」によって「ソース・コードのコンパイル」か「テスト・コードのコンパイル」かを判定できるんだと思いますが、ちょっとどうやったらいいのか分かりませんでした。