Thursday July 02, 2009 | Just my 2¢ Naoto Sato's Weblog |
|
All Languages |
English Only |
日本語のみ
JavaFX 1.2の機能と拡張(英語)の一つとして、インプットメソッドを扱うAPIが加わりました。JavaFX 1.2以前のリリースでは、シーングラフ中の
JavaFXでインプットメソッドがどのように動作するかという全体のデザインは、JavaのInput Method Frameworkとほぼ同様になっています。特に何もしない場合は(上に書いた通り)、
このサンプルは
以下は
もしお使いのOSにインプットメソッドがインストールされていない場合、Javaで書かれたインプットメソッドを使ってこのサンプルを試す事もできます。Javaインプットメソッドの使い方は 昔の記事を参照ください。
しかし、もしもあなたのアプリケーションでこの様な詳細な部分まで必要ない場合はどうすれば良いのでしょう?大丈夫。TextBox UIコントロールはこれらの仕組みを既に内部で実装しているので、 文字列リテラルのローカリゼーション記法がJavaFX Script言語リファレンスに。 JavaFX 1.0がリリースされてから既にしばらく経ちますが、ようやく"##"シンタックスについてのセクションをJavaFXランゲージリファレンスに追加できたのでblogでご紹介します。リファレンスの"String"タイプの章の"Localization of String Literal"の部分がそれです。基本的に以前紹介したプロポーザルのままです。 もし何かお気づきの点がありましたらコメントまで。 (2009-01-26 21:12:43.0) PermalinkJavaFX Scriptの「より簡単な」ローカリゼーション機能 前回のエントリーで、JavaFX Script言語の文字列リテラルの簡単なローカリゼーションの提案について説明しました。現時点でその実装が OpenJFXコンパイラリポジトリにコミットされたので、実際にどう動いているかをみてみることができます。例としてこのリポジトリにあるJavaFXBallsというデモを日本語にローカライズしてみました(このローカリゼーション自体もリポジトリに入っています)。
左下のボタンのテキスト、「ストップ」がソースコード上どうなっているかというと、ボタンのオブジェクトリテラルを作っているところのコードは:
text: bind if (not test._is_running) then ##"Start" else ##"Stop" で、それに対応するJavaFXプロパティファイルのエントリーは:
"Stop" = "ストップ" これだけ、です。 さて、今現在考えているのは、この機能をソースコードの文字列リテラルのローカリゼーションだけではなく、より一般的なローカリゼーション機能として使えないかということ。例えばJavaFXのランタイムライブラリとして、javafx.util.StringLocalizerというクラスを作り、その APIで、
package javafx.util;
public class StringLocalizer {
public attribute key: String;
public attribute locale: java.util.Locale;
public attribute packageName: String;
public attribute propertiesName: String;
public attribute defaultString: String;
// this is lazily bound to the above attributes.
public function localizedString(): String;
public static function associate(packageName: String,
scriptFileName: String,
properties: String): Void;
}
としたらどうでしょう。これらのAPIを使うことにより、次のようなことが可能になるはずです。
// ローカリゼーションオブジェクトの作成。
var localizer = StringLocalizer{ key: "Hello, World!" };
// "Hello, World!"のデフォルトロケール用の翻訳を出力。
System.out.println(localizer.localizedString());
// "Duke"のデフォルトロケール用の翻訳を出力。
localizer.key = "Duke";
System.out.println(localizer.localizedString());
// "Duke"のフランス語の翻訳を出力。
localizer.locale = Locale.FRENCH;
System.out.println(localizer.localizedString());
// "Duke"のフランス語の翻訳を、"foo/bar/MyBundle_fr.fxproperties"
// から探してきて出力。
localizer.packageName = "foo.bar";
localizer.propertiesName = "MyBundle";
System.out.println(localizer.localizedString());
また、"associate()"スタティック関数を使うことにより、JavaFX Scriptのソースファイル(またはJavaFXのパッケージごと)をJavaFXプロパティにマップすることができます。これにより文字列リテラルのローカリゼーションを探すプロパティファイルを指定できるようになります(デフォルトではソースのJavaFX Scriptファイルと同じ名前・場所のJavaFXプロパティファイルから探します)。このスタティック関数を使うことで、アプリケーションのプロパティファイルをどのようにパッケージするかを柔軟に指定できるようになるのです。一つのプロパティファイルで全アプリケーションのローカリゼーションを保持するか、ソースファイルごとにプロパティファイルを持つか、あるいはその中間か、など。 これはまだまだアイディアの段階で、実際にコミットするときにはもっと洗練されていると思いますが、この機能によって「より簡単に」JavaFX Scriptのローカリゼーションが可能になれば、と思っています。 (2008-02-12 12:53:41.0) Permalinkまたまたしばらく間が空いてしまいましたが、ここ最近はずっとJavaFX Scriptの国際化についての仕事をしています。JavaFX ScriptはJavaをベースにしたスクリプト言語なわけで、もちろんJavaに本来備わっている国際化に関する機能はすべて使えるわけですが、JavaFX ScriptからいちいちJavaの機能を呼び出して国際化関連のことを行うのはスクリプト言語らしくないし、さらにJava言語とJavaFX言語が混在してバグの元になりかねません。そこでJavaFX言語の仕様策定中ということもあり、その中に入れてしまいたいのがリテラル文字列を簡単にローカライズできる仕組みです。ある文字列をローカライズする場合、Javaでは普通、
import java.util.ResourceBundle;
static final String GREETINGS_KEY = "HELLO_WORLD";
String greetings;
try {
ResourceBundle rb = ResourceBundle.getBundle("foo.bar.resources.My_Resource");
greetings = rb.getString(GREETINGS_KEY);
} catch (MissingResourceException mre) {
greetings = "Hello, World!";
}
の様に書くと思いますが、いま模索中なのがGNUのgettext()関数のように、引数となる文字列がそのままデフォルトの翻訳になるような仕組みです。上のコードをそのシンタックスで表記すると、
var greetings = ##"Hello, World!";
たったの一行。シンプルでしょ?ここで"##"はリテラル文字列に働く単項演算子のような役割をします。この演算子がつくと実行時にこのリテラル文字列"Hello, World!"をキーとして適当な翻訳を探します。お気づきの方もいると思いますが、PropertyResourceBundleはホワイトスペース' 'をデリミタとして解釈するため、実は"Hello, World!"はキーとはなり得ないんです。そこで提案したいのがJavaFX Script用の新しいリソースバンドルのフォーマット。このフォーマットは単純に次のようなフォームを取ります。
<JavaFX string literal> = <JavaFX string literal>
e.g.,
"Hello, World!" = "こんにちは、世界!"
さらにボーナスとして考えているのは、このFX propertiesのデフォルトのエンコーディングを"UTF-8"にしようというもの。これで今まで頭を痛めてきた"ISO-8859-1" & native2asciiの呪縛から解放されるでしょう。他のエンコーディングを指定したい場合は、ファイルの頭にCSS形式のエンコーディング宣言(@charset "<IANA defined charset name>";)を入れてあげればそれに従うようにします。 ただこの方式には問題が一つあり、スクリプト内に同じリテラル文字列があり、それぞれ別の翻訳をさせたい場合(例えば2つの"File"というリテラル文字列をそれぞれ名詞、動詞として翻訳したい場合)に困ってしまいます。この問題を解決するためにオプションとしてキーを明示的に指定できるようにしました。#[FILE_NOUN]"File"のように、大括弧でくくって明示的なキーを指定します。 まあこんな所ですが、プロポーザル(英語です)とプロトタイプ実装をPlanet JFX wikiに置いてみたんで、どうぞおためしください。それとコメント、感想もよろしく! (2008-01-10 15:55:55.0) Permalink Comments [3]JDKのアプリケーションで通貨に関連したことを行おうとした場合、通常はjava.util.Currencyクラスを使います。このクラスを使うと、ある国で使われている通貨や、その通貨のローカライズされたシンボルがなんであるかを調べることが出来ます。このような情報を提供するためにJDKは内部にISO 4217標準に基づいた通貨のデータを持っています。ところがこのISO 4217のデータ、いろんな理由(たとえばデノミネーションとか)でしばしば管理機関によってアップデートがかかるんですが、JDKで持っている通貨のデータを常にこのISO 4217のデータに合わせておくことは通貨を扱うアプリケーションには非常に重要です。もし実際の通貨とJDKの通貨データに整合性がない場合、これらの金融アプリケーションのトランザクションに重大な問題が生じるからです。(前に書いたトルコのお菓子のエントリーが良い例(すいませんが英語です)かも) さて、現在のJDKの通貨サポートの問題点の一つに「通貨データが"lib/rt.jar"の中にクラスファイルとして存在している」というのがあります。なぜこれが問題か。というのもISO 4217のデータに変更があった場合(例えばスロベニアがユーロに移行したとか)、常にrt.jarをアップデートしなければなりません。この事実はたとえばお客さんが通貨データだけをアップデートしたい時でも、常にJDK全体をアップグレードしなければならない事を示しています。TimeZoneのデータも同様な位置づけにあるんですが、TimeZoneのデータは既に隔離されていて、個別にアップデート可能になっています。 で、このブログエントリー、何を言いたいかというとJDK7ではこの問題はもう起こらなくなります。というのも必要な変更のチェックインをつい最近完了したんで、もうしばらくするとOpenJDK経由でアクセスできるようになるはずです。変更後では通貨データは"<JAVA_HOME>/lib"の下に"currency.data"というバイナリファイルとして個別に置かれます。なのでJDKアップデートリリースとは別のサイクルでこの通貨データをアップデートすることが可能になるはずです。さらにボーナス機能として、ユーザーがプロパティファイルでこの通貨データの内容を上書きすることも出来ます。"<JAVA_HOME>/lib/currency.properties"というファイルを作って、その中に"key=value"というペア("key"はISO 3166国コード、"value"は3文字通貨コード、3桁数値コード、それにマイナー・ユニットをカンマで区切った物)を書いておけば、"key"で指定した国の通貨のデータを上書きできます。たとえば"JP=JPZ,999,2"というエントリーは、日本の通貨データを上書きします。 この通貨の拡張に加えて、いくつかのAPIも実装しました。まず初めはJDKで定義されているすべてのCurrencyインスタンスを列挙する機能: public static Set<Currency> getAvailableCurrencies() それからISO 4217の数値通貨コードを取得する機能: public int getNumericCode() 最後にCurrencyインスタンスのディスプレイ用の名称取得機能。例えば日本の通貨は、getSymbol()すると「¥」ですが、このAPIは「日本円」を返します(ロケールが日本の場合)。 public String getDisplayName() public String getDisplayName(Locale displayLocale) このAPIの最初の実装は英語、フランス語、ドイツ語、イタリア語、日本語、韓国語、中国語(簡体字)、スペイン語、スウェーデン語、それに中国語(繁体字)の10のロケール用にローカライズされた通貨のディスプレイ用名称を返すことが出来ます。 さらにこれに応じてjava.util.spi.CurrencyNameProviderにも新たなSPIを追加しました。上記10言語以外に対応したい場合に、このSPIを実装することでどんな言語にもローカライズ可能です。
以上が今回実装した拡張の概要です。これで開発者の皆さんの苦労が少しでも減ると良いんですけどね。今回実はデモも一緒に載せたかったんですが、さすがにまだ出回ってないビルド用のデモは載せられないんでパスです。あしからず。 (2007-06-28 15:55:11.0) PermalinkUbuntuの新しいリリース、7.04 「Feisty Fawn」にJava 6が入っていると聞いていたんで、国際化関係はどうなっているのか興味がありました。ということで早速手持ちのEdgy EftをFeisty Fawnにアップグレード。そして下のエントリーにもあるLocale Demoを走らせてみました。
お見事! 日中韓のフォントはそのまま表示されるようです! Ubuntu開発者の皆様ありがとうございます。ところでこのLocale Demoですがちょっと変更を加えてみました。来月開催されるJavaOneのデモ用にぱっと見でJDKに含まれているロケールか、あるいはCLDRロケールかがわかるように先頭に小さいアイコンを付けてみました。今年のJavaOneのパビリオンに設置するデモマシンにインストールする予定ですので、よかったらお立ちよりください。 (2007-04-22 21:16:19.0) Permalink今現在はテクニカル・ライターとして活躍しているJohn O'Conner、以前一緒にJavaの国際化チームで働いていたチーム・メイトでしたが、このたびJDK6での新しい国際化機能についての記事を書いてくれました。その記事はつい最近ここにアップロードされましたが、いろいろなサンプルとともに国際化の新機能を詳しく・わかりやすく紹介しています。 (2007-03-21 13:33:31.0) Permalink”百聞は一見にしかず”ということわざがありますが、前のエントリーで取り上げたロケール・デモをWebStartアプリケーションにして、実行可能にしてみました。 このデモはJava 6の機能を使うのでJava 6がマシンにインストールされていることが前提条件です。もしまだの場合はこの際ここからインストールしましょう。Java 6のインストールが完了したら下のボタンを押してみて下さい。 デモが立ち上がったでしょうか?この状態だとこのデモに表示されているロケールのデータはJava 6に同梱されているそのままです。"Locale Names"のタブへ移動すると実際にいくつのロケールがインストールされているかを見ることが出来ます。全部で"150"と表示されるはずです。 次に例のCLDRアダプターをインストールしてみましょう。CLDRアダプターはここにあるので、この"cldradapter.jar"ファイルをJavaランタイムの拡張ディレクトリに保存します。ウィンドウズですと通常、"C:\Program Files\Java\jre1.6.0\lib\ext"というディレクトリがあるはずですのでここに保存します。そして再び上の"Launch"ボタンを押してみましょう。どうですか?今度は少し立ち上がりに時間がかかったと思いますが、これはロケールデータをユニコード・コンソーシアムのウェブサイトから動的にダウンロードしているためです。先ほどのように"Locale Names"のタブに移動すると、"365"個のロケールが表示されていると思います。 このデモの面白いところは、ロケールデータを"オン・デマンド”で引っ張ってきてくれるところです。Javaランタイムにもともと組み込まれていなくても、必要になった時に初めてインストールすることによって、ダウンロードの最適化及び拡張性を同時に得ることが出来ます。次期Javaのリリース(えっと、Java 6の次の話をしています :-)のプランの一つにロケールデータを如何に効率よくデプロイするかというフィーチャーがありますが、このデモはそれに対する一つの方向性を示していると思います。 (2006-11-14 19:19:55.0) Permalink来週ワシントンD.C.で開催されるInternationalization and Unicode Conferenceで近々公開予定のJava 6の国際化機能についてプレゼンテーションをしに行ってきます。そこで使うデモを現在準備中なんですが、その中の一つに前のエントリーで紹介したLocale Sensitive Services SPI(長い名前だ)という機能の紹介をするデモがあり、ここでちょっと紹介したいと思います。 このデモは2つのコンポーネントから出来ていて、そのうちの一つは通常のSwingアプリケーションです。Locale.getAvailableLocales()で得られるロケールのリストを表示し、ユーザーがその中からロケールを選ぶと、そのロケールに従ってロケール依存のデータ(例えば日付・時刻、通貨、及びローカライズされた名前など)をフォーマットして表示します。 もう一つのコンポーネントは目には見えないですが、このデモの核心部分となる物です。Unicode Consortiumが公開しているCLDRというXMLで記述されたロケールデータがあるのですが、このコンポーネントはCLDRのデータをLocale Sensitive Services SPIを使ってJavaランタイムに組み込む働きをします。現時点ではJavaはISO 639-2で定められた3文字の言語コードをサポートしていないので、それらの言語コードを使っているロケールはプラグインすることはできませんが、それでも300以上のロケールがこのCLDRアダプターによってJavaのテキストプロセッシングクラスで利用可能になるんです! 下のイメージがこのデモのプレビューですが、ここではJavaランタイム単体では未だサポートされていないインドのタミール語ロケールでフォーマットされた日付・時刻が表示できています。 タミール語はJavaでは未サポートなので、表示に必要なフォントをどこかから持ってくる必要があります。このデモはWindowsXP上で動いているので、XPのタミール語フォントである"latha.ttf"をJava5.0でサポートされた"フォントフォールバック機能"を使ってJavaに組み込む(といってもコピーするだけ:-)だけで、まるで魔法のようCLDRのロケールデータが表示できてしまうんです。 下のスクリーンショットはアムハラ語(エチオピア)ロケールでのデモです。上と同じように日付・時刻がアムハラ語でフォーマットされて表示されています。 このデモではタミール語のようにWindows XPのフォントを持ってくることができない(Windows XPでも未サポートのため)ので、アムハラ語のオープンソースのTrueTypeフォントである"Jiret"というフォント(ここでダウンロード可能)を使いました。 もし来週開催のUnicode Conferenceに来られる方がいらっしゃいましたら是非声をかけてください。いろんな言語でのデモをお見せできると思います。 (2006-11-08 16:14:01.0) Permalink |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||