ついにベールを脱いだJavaFX

第12回 国際化

この記事を読むのに必要な時間:およそ 5.5 分

今回はアプリケーションを作成する上で見過ごされがちではあるのですが,とても重要な要素について紹介します。

もう読者の皆さんにはおわかりのはずですね。そう,国際化です。

アプリケーションを動作させることを,特定の言語や地域だけに限定できるのであれば,国際化は必要ありません。しかし,ネットでつながれた世界では,アプリケーションをどの言語,どの地域で動作させるかを特定することがとても難しくなります。

そのため,できればはじめから国際化を考慮して,アプリケーションを作る必要があります。とはいうものの,アプリケーションを作りはじめてすぐの時には,なかなか国際化まで頭が回らないというのも本音だと思います。

Javaで国際化を行う場合,メニューなどの文字列はリソースバンドルによって切り替えます。最近では,EclipseやNetBeansなどのIDEの機能として,国際化が簡単にできるようになりました。しかし,IDEの力を借りないで既存のアプリケーションの国際化を行うのは,それなりに大変です。

これに対し,JavaFXではとても簡単に国際化を行うことができます。しかも,国際化は言語レベルで扱われるため,とてもスマートに国際化することができるのです。

そこで,今回は次の2つのトピックに関して解説を行っていきます。

  • ロケールによる文字列の切り替え
  • 埋め込み文字列のフォーマット

今回使用したサンプルのソースを含めたNetBeansのプロジェクトは下記のリンクよりダウンロードすることができます。

なお,2月12日にJavaFX 1.1がリリースされました。それと同時にNetBeansのJavaFXプラグインもJavaFX 1.1に対応したバージョンがリリースされています。本連載も今回からJavaFX 1.1を使用していきます。

ロケールによる文字列の切り替え

国際化を行うに当たって,その対象となるアプリケーションを用意しましょう。今回,作成したのは世界時計です。といっても,3つの都市の時間しか表示できませんが。

コンボボックスで都市を選択すると,その都市における時間を表示するというものです。ちょっと長いのですが,以下に世界時計のスクリプトを示します。

リスト1 世界時計スクリプト

// 都市名
var cities = ["New York", "Paris", "Tokyo"];
 
// タイムゾーン
var timezones = [
    TimeZone.getTimeZone("America/New_York"),
    TimeZone.getTimeZone("Europe/Paris"),
    TimeZone.getTimeZone("Asia/Tokyo")
];
 
// 選択項目が変更したら,デフォルトタイムゾーンを変更する
var selectedIndex: Integer = 0 on replace {
    TimeZone.setDefault(timezones[selectedIndex]);
}
 
// 時間を表す変数
var time = new Date();
 
// 1秒ごとに時間を更新するためのタイムライン
Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: [
        KeyFrame {
            time: 0s
            action: function() {
                time = new Date();
            }
        },
        KeyFrame {
            time: 1s
        }
    ]
}.play();
 
Stage {
    title: "World Clock"
    scene: Scene {
        width: 350 height: 100
        content: [
            SwingLabel {
                translateX: 20 translateY: 13
                text: "City:"
            },
            SwingComboBox {
                translateX: 70 translateY: 7
                width: 250
 
                // 選択項目はselectedIndexに双方向バインドさせる
                selectedIndex:
                    bind selectedIndex with inverse
                    
                items: for (city in cities) {
                    SwingComboBoxItem {
                        text: city
                    }
                }
            },
            Text {
                font: Font {
                    size: 20
                }
                x: 20 y: 70

                // 時間表示
                content: bind "{time}"
            }
        ]
    }
}

コンボボックスで都市名を選択すると,変数selectedIndexの値が変化します。変数selectedIndexには置換トリガが設定しておき,値が変更するとそれに応じたタイムゾーンをデフォルトタイムゾーンに設定します。

タイムゾーンにはJavaのjava.util.TimeZoneクラスを使用しています。デフォルトタイムゾーンを変更すると,Dateクラスの変数timeの表示が変化します。

図1に動作例を示します。Tokyoを選択しているので,時間がJSTで表されていることがわかります。

図1 世界時計の動作例

図1 世界時計の動作例

では,まず世界時計の文字列をロケールに応じて変更するようにしてみましょう。

JavaFXではロケールに応じた文字列の変更はとても簡単に行うことができます。たとえば,ラベルで表示しているCity:という文字列をロケールに応じて切り替えるようにするには,次のように表記します。

リスト2

        text: ##"City:"

文字列の前にシャープを2つ付け足すだけです。

Javaのリソースバンドルではキーに対応した文字列をロケールによって変更させますが,JavaFXでは##がついた文字列自体がデフォルトの文字列になり,しかもキーにもなります。

次に行うのが,リソースファイルの作成です。

リソースファイルはデフォルトではスクリプトのファイル名に言語を付け加え,拡張子をfxpropertiesとします。たとえば,世界時計のスクリプトファイルはworldClock.fxとしたので,日本語のリソースファイルはworldClock_ja.fxpropertiesになります。同じように,フランス語であればworldClock_fr.fxpropertiesとなります。

作成したリソースファイルはスクリプトファイルと同じディレクトリに配置します。したがって,NetBeansでは図2のように表示されます。

図2 worldClock_ja.fxpropertiesの配置

図2 worldClock_ja.fxpropertiesの配置

worldClock_ja.fxpropertiesの内容は次のようにします。

リスト3

@charset "Shift_JIS";

"City:" = "都市:"

先ほど##を付けた文字列をキーとし,イコールで結んで言語に応じた表記を記述します。ここでは,"City:"に対応する日本語の文字列として"都市:"としました。

また,リソースファイルの文字セットを指定することもできます。文字セットを指定する場合,リソースファイルの先頭に@charsetに続けて文字セット名を記述します。最後のセミコロンを忘れずに。ここでは,Shift_JISにしてみました。なお,リソースファイルのデフォルトの文字セットはUTF-8です。

著者プロフィール

櫻庭祐一(さくらばゆういち)

横河電機に勤務するかたわらJava in the Boxにて新しい技術を追い続けています。JavaOneは今年で11年目。名実共にJavaOneフリークと化しています。

コメント

コメントの記入