JAVAの国際化対応について

自分が国際化対応のプログラムをコーディングしているとき、情報があまりなかったので思い切って作ってみました。 ドキュメントに載っていることを、要点をかいつまんで誰にでもわかるように噛み砕いて説明しているだけです。 よかったら参考にどうぞ。

まじめな概要

JAVAの場合、いくつかの指標が提供されています。

私は国際化対応のリソースをきっと誰かが作っていてくれているかな、と贅沢なことを思ってたんですけど無いみたい。 普通、国際化の対応という部分は自分で作業していくしかないよねぇ。 そんなわけで、ここでは文脈レベルでの国際化対応にまとを絞っていきたいと思います。 でもいきなり文脈レベルと言われてもイメージしにくいと思うので、状況の実例を挙げて少し解説します。

まじめな状況の実例によるわずかばかりの解説

ファイルを開く処理の最中に指定されたファイルが存在しない等の処理の途中でファイルが存在しないという場合、JAVAではjava.io.FileNotFoundExceptionという例外オブジェクトがスローされることがあります。 必要なファイルが見つからなかったことをユーザーに通知する文は、どのように作成したらよいでしょうか。

ユーザーに表示する文をその場で定義する方法が、最もよく使われます。 この方法は開発者の負担が軽いため良いのですが、その分国際化対応は難しくなります (SOURCE-01参照)。 JAVAでの国際化対応の理念ではこの場合、ファイルが見つからなかったことを表す文字列をjava.util.ResourceBundleから取り出すことをすることでソフトウェアの文字列に層をかけ、前者の方法を一段抽象化します (SOURCE-02参照)。 この方法により国際化対応はできますが、開発者は負担を強いられます。 それでも今現在のソフトウェア技術ではこの方法しかない、と私は思います。

SOURCE-01

01:  FileReader  reader  = null;
02:  
03:  try
04:  {
05:    reader  = new FileReader("readme.txt");
06:  }
07:  catch(FileNotFoundException e){
08:    JOptionPane.showMessageDialog(
09:      null,
10:      "ファイルが見つかりません",
11:      "readme.txtファイルが見つかりませんでした。\n"  +
12:        "このままではシステムを続行できません。\n" +
13:         "システムを終了します。", 
14:      JOptionPane.ERROR_MESSAGE
15:    ); 
16:    System.exit(0);
17:  }
SOURCE-02

01:  ResourceBundle resource  = ResourceBundle.getBundle("hamtaro.resource.HamutaroDialogMessage");
02:
03:  try
04:  {
05:    reader  = new FileReader("readme.txt");
06:  }
07:  catch(FileNotFoundException e){
08:    JOptionPane.showMessageDialog(
09:      null,
10:      resource.getString("FileNotFoundException title"),
11:      resource.getString("FileNotFoundException message"),
12:      JOptionPane.ERROR_MESSAGE
13:    );
14:    System.exit(0);
15:  }

まじめな国際化対応のメカニズム

上記のSOURCE-02をただ眺めただけで、大方の予想はつくと思います。 マイクロソフト社のVisualC++でもこれと同じ事をその開発環境でサポートしていました。 JAVAでも、考え方は一緒です。 リソースを管理するクラスに、キーを与えて、そのキーに対応するオブジェクトを取得します。 ソースでは1011行でその処理を行っています。

リソースの定義方法は、複数あります。 Propertyファイルにキー(Key)と値(Value)との対応を記す方法と、ある特定のクラスを親とするクラスに記述する方法があります。 本来はPropertyファイルに記述するべきだと思います。 が、私はこれ以上開発環境のディレクトリ数を増やすことは良くないと考え、クラスに記述する方法を選びました。 そういうわけで、ここではクラスに記述する場合の方法を解説することにします。

java.util.ListResourceBundleというクラスがあります。 このクラスは、先のKeyValueの関係を定義するためのクラスです。 定義の条件は、getContents()というメソッドを満たすことです。 このメソッドの返す二次元のObject配列に、KeyValueの対応を含めればよいのです。 下記のSOURCE-03に、先ほどの例で使用するKeyValueの対応を記述します。

SOURCE-03

01:  package hamutaro.resource;
02:
03:
04:  public  class HamutaroDialogMessage_ja_JP extends java.util.ListResourceBundle
05:  {
06:    public  Object[][]  getContents(){ return HamutaroDialogMessage_ja_JP.contents; }
07:    
08:    private  static  Object[][]  contents  =
09:    {
10:      {"FileNotFoundException title", "ファイルが見つかりません"},
11:      {"FileNotFoundException message", "ハム太郎ファイルがないよ!\n起動できないよ〜。"}
12:    };
13:  }

リソースの定義は、これで完了です。 このcontentsに、リソースを付け足していく作業を行っていきます。

クラスの名前に注目してください。 HamutaroDialogMessage_ja_JPとなっていますね。 これは、先のSOURCE-02ResourceBundle.getBundle(String)の引数と微妙に異なっています。 それは、このリソース定義は地域対応のためのものだからです。 ja_JPで日本を表しています。 つまり、これをアメリカ英語で定義したリソースのクラス名は必ずHamutaroDialogMessage_en_USとならなければなりません。

さて、使用されている国を指示していないのに何故、JAVAはわかってくれるているのでしょうか。 それは、VMがプラットフォームの使用している国と言語を知っているからです。 日本で日本語を使用しているので、ja_JPとなります。 日本で英語を使用するならen_JPですけど。

リソースを取得する時、注意することがあります。 ResourceBundle.getBundle(String)で指定するリソースのクラスは、SOURCE-02にもあるように必ずフルパスで指定する必要があります。 パッケージの構成が変わっても、コンパイルエラーにはなりません。 実行時に確実に起こるランタイムエラーとなってしまいます。 注意しましょう。

国際化対応の機構についてまじめに考えた

ここに載せたソースは説明を分かりやすくするために作成されました。 実際の開発にはこの理解をベースとしてそれぞれの開発ターゲットに特化することが大切だと思います。

通常、国際対応するプログラムではそのリソースも大きなものになると想像されます。 この機構を使用することで、全てを一つのクラスで実装するのではなく分けることが可能です。 ある一定の約束事はありますが、それはリソースの実装を邪魔するものではないので、ある程度作業しやすいですよね。

実際には、ユーザーへのメッセージなどは今まで直感で作られてきました。 プログラムとは思考をコーディングする作業であり、ソフトウェアの設計はこのような仕上げにも属する部分は考慮されることがまず無いため、コーディング最中に見えてくるエラーメッセージなどは忙しいコーディング中に忙しく考えさせられて実装されるか、実装しないで終わってしまう。 そこでこの国際化の機構をうまく使用することで、リソースを後でソースとは別にじっくり考えることもできるわけです。 しかしそれは、この国際化対応の機能ではなく文字列処理の層を追加したための効果ですが、総合的には、開発速度の加速につながるのではないかと思います。


since 2001/10/07.
mail to nascent@mx11.freecom.ne.jp.
author nascent.
Level A conformance icon, W3C-WAI Web Content Accessibility Guidelines 1.0 Valid XHTML 1.0! Valid CSS! Make Width CSS