web-dev-qa-db-ja.com

多言語の最善のアプローチJava Enum

私が取っているアプローチで問題が発生しています。間違った道をたどり始めて、私のアプローチを再考する必要があるのではないかと考えています。これが私がしようとしていることです。

Enumを使用して、考えられるさまざまなアカウントステータスを表したいと思います(重複するアプローチを使用して設定する他の有限データセットがあります)。

  • A、アクティブ
  • I、非アクティブ
  • P、保留中

これらのアカウントステータスは、必要に応じてユーザーの言語で提示する必要があります。

例:アカウントのステータスがAの場合、英語を話す人は「アクティブ」、スペイン語は「アクティブ」と表示します。

また、適切なロケール設定で、考えられるすべてのアカウントステータスのドロップダウンリストを表示したい場合もあります。


現在のアプローチ

(A、I、P)の値を持つAccountStatusEnumクラスを使用します。

プライベート静的メンバー変数に、ローカライズされたアカウントステータスのEnumMapを、可能なロケールのEnumMap内に格納します。

例:

private static EnumMap<LocaleEnum, EnumMap<AccountStatusEnum, String>> localeAccountStatuses = new EnumMap<LocaleEnum, EnumMap<AccountStatusEnum, String>>(LocaleEnum.class);

これは、静的初期化ブロック内でロードされます。

次に、次のメソッドを使用して、ドロップダウンのすべての値を取得できます。

public static EnumMap<AccountStatusEnum, String> getAccountStatuses(LocaleEnum locale) {
        return localeAccountStatuses.get(locale);
    }

または、このメソッドを使用して、特定のEnumの単一の説明を取得することもできます。

public String getDescription(LocaleEnum locale){
            return getAccountStatuses(locale).get(this);
        }

使用例:AccountStatusEnum.A.getDescription(LocaleEnum.es_MX);

このアプローチに対するあなたの考えと、同じことを達成するための考えられるより良いアプローチに興味があります。

[〜#〜] edit [〜#〜] Enumsに入力する値を取得するロジックは、単一のヘルパークラス内に集中化されます。したがって、説明のソースが新しいソースからのものに変更された場合、コードの変更は最小限に抑えられます。

ありがとう

8
forevernewb123

ローカリゼーションの問題に取り組むのと同じように、この問題に取り組みます: ResourceBundle 。私は_I18n_というクラスを使用します。このクラスには、キーとオプションで引数のリストを受け取るgetMessageという静的メソッドがあります。キーは、デフォルトのResourceBundleを使用するように構成されたLocaleで検索されるか、または任意のものを使用します(ここでの詳細は重要ではありませんが、_I18n_の呼び出し元がLocaleが何であるかを知る必要があります)。

_I18n_クラスは次のとおりです。

_public final class I18n {
    private I18n() {
    }

    private static ResourceBundle bundle;

    public static String getMessage(String key) {
        if(bundle == null) {
            bundle = ResourceBundle.getBundle("path.to.i18n.messages");
        }
        return bundle.getString(key);
    }

    public static String getMessage(String key, Object ... arguments) {
        return MessageFormat.format(getMessage(key), arguments);
    }
}
_

プロジェクトでは、パッケージpath.to.i18n、messages.properties(デフォルト)、messages_en.properties(ロケールen)、messages_it.properties(ロケールit)などを含むファイルにあります。

Enum値を変換する必要がある場合、キーがenum用語であることを除いて、他のキーと異なる扱いをする必要はありません。

言い換えれば、あなたは持っています:

_public enum AccountStatusEnum {
  Active,
  Inactive,
  Pending
}
_

_I18n.getMessage_を呼び出すときは、AccountStatusEnum.Active.toString()を渡して、キーが「アクティブ」のプロパティファイルで変換を見つけます。私のようで、小文字のキーを使用したい場合は、文字列に対してtoLowerCase()を実行する必要があります。さらによいのは、キーではなくEnumを受け取る新しい_I18n.getMessage_を作成し、そのメソッドが列挙型の値を文字列に変換して小文字に変換した_I18n.getMessage_の文字列バージョンを呼び出すことです。

したがって、これを_I18n_クラスに追加します。

_    public static String getMessage(Enum<?> enumVal) {
        return getMessage(enumVal.toString().toLowerCase());
    }
_

デザインに影響を与えることなく、プログラムの同じ部分に同じ変換ロジックが組み込まれているため、私はこの方法を使用することを好みます。 enumキーを他のキーと区別することもできます。その場合は、各enumキーを「enum。」で始めることができるため、「enum」を付加します。 getMessageを呼び出すとき。プロパティファイルでキーに名前を付けることを忘れないでください。

お役に立てば幸いです。

15
Neil

ResourceBundleを使用する方法ですが、列挙型がオブジェクトであることを利用して、内部にi19nの詳細を非表示にします

public enum MyEnum {
  A,
  I,
  P;

  private String localeText = null;

  private MyEnum() {
    // Load resource bundle
    this.localeText = // get message;
  }

  public String getLocaleText() {
    return this.localeText();
  }
}

それはあなたがすることを可能にするでしょう:

MyEnum.A.getLocaleText();

直接、どこでも

最適化とは、静的イニシャライザでリソースバンドルを静的属性としてロードすることです。

JEEでは、リソースバンドルを注入可能にするためのボーナスポイント(ローカリゼーション文字列を簡単に変更できる場合があります)。

1
SJuan76

提案された回答の長所と短所を要約すると:

グローバルヘルパーファイルの問題は、柔軟性の欠如です。たとえば、アプリケーションに、特定の列挙型定数を持つさまざまな列挙型があり、一般的な形式に従っていない、非常に特定のキーが必要です。

列挙型でロジックを見つける際の問題はコードの複製であり、長期的には維持が難しくなります。

Java 8を使用すると、上記の問題の解決に非常に役立つ、デフォルトのメソッドという非常に役立つ機能を自由に利用できます。

私の提案は、キーを取得するための単一のメソッドを持つインターフェースを持つことです:

public interface I18nEnum {
   default String getMessageKey(Enum<?> e) {
      return e.getClass().getSimpleName() + '.' + e.name().toLowerCase();
   }
}

このように、列挙型は、実際に実装せずに、そのインターフェースを実装することを宣言するだけで済みます。コードを1か所に配置できるという利点がありますが、必要に応じてデフォルトのメソッドをオーバーライドすることで特定のケースを処理できる柔軟性があります。例えば:

public enum Sex implements I18nEnum {
    MALE,
    FEMALE,
    UNKNOWN {
        @Override
        public String getMessageKey(Enum<?> e) {
            return "Common.UNKNOWN";
        }
    }
}
1
magomar