4

プログラムに国際化を追加する必要があります。ありがたいことに、まだ全体ではなく、ほんの一部ですが、プログラム全体をカバーできるようにスケールアップする方法が必要です. 問題は、私たちのプログラムはプラグインに基づいているため、すべての文字列が同じ場所にあるわけではないということです。

私が理解している限りでは、Java のResourceBundle動作はこのようなものです。ResourceBundleなどと呼ばれるを拡張するクラスと、などMyProgramStringsと呼ばれる言語固有のクラスを作成します。これらの各クラスは、キー (文字列) を値 (任意のオブジェクト) にマップします。データをどこから取得するかはこれらのクラスごとに異なりますが、共通の場所はプロパティ ファイルです。MyProgramStrings_frMyProgramStrings_es

値を 2 段階で検索します。最初に正しいバンドルを取得し、次に必要な文字列を照会します。

Locale locale = Locale.getDefault(); // or = new Locale("en", "GB");
ResourceBundle rb = ResourceBundle.getBundle("MyProgramStrings", locale);
String wotsitName = rb.getString("wotsit.name");

ただし、必要なのは、複数のロケールの結果を 1 つのリソース空間に結合することです。たとえば、プラグインは、既に定義されている文字列をオーバーライドし、コードが文字列を検索するたびにその新しい値を返すことができる必要があります。

私はこれらすべてに少し迷っています。誰でも助けることができますか?


更新: David Waters 氏は次のように尋ねました。

回答を最後に記載しましたが、この問題をどのように解決したかをお聞きしたいと思います。

まあ、まだそれほど進んでいません - 長期的なWIBNIは常に最新の危機の犠牲者になります - しかし、プラグインが実装するインターフェースに基づいており、リソースはインターフェースと同じ完全修飾名を持つという慣習があります.

そのため、インターフェイスUsersAPIにはさまざまな実装が含まれる場合があります。そのインターフェイスのメソッドgetBundle()は、デフォルトで と同等のものを返します ResourceBundle.get("...UsersAPI", locale)。そのファイルを置き換えるか、より複雑なものが必要な場合は、UsersAPI の実装でメソッドをオーバーライドできます。

これまでのところ、これで必要なことは完了していますが、プラグインに基づくより柔軟なソリューションを引き続き検討しています。

4

4 に答える 4

2

ロケールごとに 1 つのクラス (つまり、 、 という名前のクラス) を使用して、ResourceBundles を一連のクラスとして実装する必要はありませ。ResourceBundle クラスは、必要に応じてプロパティ ファイルを使用するようにフォールバックします。MyProgramStringsMyProgramStrings_frMyProgramStrings_de

public static void main(String[] args) {

    ResourceBundle bundle = ResourceBundle.getBundle("MyResources");
    System.out.println("got bundle: " + bundle);

    String valueInBundle = bundle.getString("someKey");
    System.out.println("Value in bundle is: " + valueInBundle);
}

MyResources.propertiesクラスパスに名前が付けられたファイルがある場合、このメソッドは次のようになります。

got bundle: java.util.PropertyResourceBundle@42e816  
Value in bundle is: someValue

バンドルの階層を設定する、またはそれらを「マージ」することに関しては、Spring には階層型のMessageSources ( API へのリンク) の概念が実装されていることを知っていることを除いて、私はあまり役に立たないことを恐れています。 java.util.ResourceBundle のトップなので、Spring の機能を使用して目的を達成できるのではないでしょうか?

ResourceBundle.getBundle()ところで、 「検索とインスタンス化の戦略」を説明するjavadocの関連部分は次のとおりです。

http://java.sun.com/j2se/1.5.0/docs/api/java/util/ResourceBundle.html#getBundle(java.lang.String , java.util.Locale, java.lang.ClassLoader)

  • 最初に、候補のバンドル名を使用してクラスをロードしようとします。そのようなクラスが、指定されたクラス ローダーを使用して検出およびロードでき、ResourceBundle と互換性のある割り当てがあり、ResourceBundle からアクセス可能であり、インスタンス化できる場合、getBundle はこのクラスの新しいインスタンスを作成し、それを結果のリソース バンドルとして使用します。
  • それ以外の場合、getBundle はプロパティ リソース ファイルを見つけようとします。すべての "." を置き換えることにより、候補のバンドル名からパス名を生成します。"/" を含む文字と文字列 ".properties" を追加します。ClassLoader.getResource を使用して、この名前の「リソース」を見つけようとします。(getResource の意味での「リソース」は、リソース バンドルの内容とは何の関係もないことに注意してください。これは、ファイルなどの単なるデータのコンテナーです。)「リソース」が見つかった場合は、そのコンテンツからの新しい PropertyResourceBundle インスタンス。成功した場合、このインスタンスが結果のリソース バンドルになります。
于 2008-11-12T03:21:33.263 に答える
1

getBundle は、指定されたロケール (存在する場合) とデフォルトのロケールを使用して生成された一連の候補バンドル ファイルをロードします。

通常、ロケール情報のないリソース ファイルには「デフォルト」値があり (たとえば、en_US値は MyResources.properties にあります)、別のロケール用にオーバーライド リソース値が作成されます (たとえばja、文字列は MyResources_ja.properties にあります)。より具体的なファイルは、より具体的でないファイル プロパティをオーバーライドします。

次に、各プラグインが独自のプロパティ ファイル セットを提供する機能を追加します。プラグインがメイン アプリまたは他のプラグインのリソースを変更できるかどうかは明らかではありませんが、各プラグインがそのベース リソース ファイル名を登録できるシングルトン クラスが必要なようです。 . プロパティ値に対するすべてのリクエストはそのシングルトンを経由し、各プラグインのリソース バンドルを調べて (ある順序で ...)、最後にアプリ自体でプロパティ値を調べます。

Netbeans NbBundle クラスは同様のことを行います。

于 2008-11-12T03:38:47.783 に答える
1

Struts と Spring にはそのための機能があることは知っています。しかし、Struts や Spring を使用できない場合は、ResourceBundle のサブクラスを作成し、この ResourceBundle に *.properties (プラグインごとに 1 つ) をロードします。次に、使用できます

ResourceBundle bundle = ResourceBundle.getBundle("MyResources");

通常、プロパティ ファイルで行うように。

もちろん、毎回各プロパティを検索する必要がないように、結果をキャッシュする必要があります。

于 2008-11-12T03:30:15.787 に答える
1

質問 653682を参照してください。私が見つけた解決策は、ResourceBundle を拡張するクラスを用意することでした。ファイルから生成された PropertyResourceBundle に委任しない場合は、値をオーバーライドしているかどうかを確認します。

したがって、UI のラベルを保存する場合は、クラス com.example.UILabels とプロパティ ファイル com.example.UILabelsFiles を作成します。

package com.example;

public class UILabels extends ResourceBundle{
    // plugins call this method to register there own resource bundles to override
    public static void addPluginResourceBundle(String bundleName){
        extensionBundles.add(bundleName);
    }

    // Find the base Resources via standard Resource loading
    private ResourceBundle getFileResources(){
        return ResourceBundle.getBundle("com.example.UILabelsFile", this.getLocale());
    }
    private ResourceBundle getExtensionResources(String bundleName){
        return ResourceBundle.getBundle(bundleName, this.getLocale());
    }

    ...
    protected Object handleGetObject(String key){
        // If there is an extension value use that
        Object extensionValue = getValueFromExtensionBundles(key);
        if(extensionValues != null)
            return extensionValues;
        // otherwise use the one defined in the property files
        return getFileResources().getObject(key);
    }

    //Returns the first extension value found for this key, 
    //will return null if not found    
    //will return the first added if there are multiple.
    private Object getValueFromExtensionBundles(String key){
        for(String bundleName : extensionBundles){
            ResourceBundle rb = getExtensionResources(bundleName);
            Object o = rb.getObject(key);
            if(o != null) return o;
        }
        return null;
    }    

}
于 2009-03-18T09:33:51.853 に答える