语言环境和多语言支持的最佳实践是什么?

What is the best practice for locales and multiple language support?

我想在我的程序中使用多种语言。 java Locale class 有一些语言环境,例如 Locale.GERMANLocale.ENGLISH 等。但我需要额外的语言环境,例如西班牙语等。

如何正确储存和使用它们?最佳做法是什么?

我是否应该创建某种 LanguageHandler 来将所有必需的语言环境存储在一个数组中?在该主题上有什么经验和做法吗?

编辑:该应用程序适用于桌面,使用 Java 编写。

获取所有受支持语言环境的列表:

您可以使用 Locale spanish = new Locale("es", "ES"); 在西班牙语言环境中使用西班牙语。

How can I store them and use them properly? What is the best practice?

据我了解,您不必存储受支持语言环境的主列表。您可以随时使用它们。通过如上所述定义语言环境将帮助您通过传递语言环境对象来加载 ResourceBundle,但是您需要为要在应用程序中使用的每个语言环境创建 ResourceBundle。

例如,对于一些不同语言的资源,您可能需要考虑翻译。

进一步阅读如何使用语言环境来初始化 resourceBundle。

http://tutorials.jenkov.com/java-internationalization/resourcebundle.html

https://mkyong.com/java/java-resourcebundle-example/

How to load a resource bundle from a file resource in Java?

您始终可以使用符合 ISO 3166 标准的国家/地区代码。西班牙语是

Locale spanish = new Locale("es", "ES");

是正确的,应该接受。他的评论提示了这个答案。

枚举

关于如何跟踪您的应用当前支持的语言环境,请定义一个枚举。枚举是处理 在编译时已知 并且 在执行期间不变 的项目列表的好方法。参见 Oracle tutorial

public enum L10n 
{
    fr_CA , es_ES ;  // Names of reference variables automatically set to point to objects automatically instantiated when this class loads.
}

使用构造函数传递由每个枚举元素表示的 Locale 对象。我们使用 L10n 作为枚举的 class 名称,其中“L10N”是单词“localization”的常见缩写。

public enum L10n 
{
    // Enum elements.
    fr_CA( Locale.CANADA_FRENCH ) , 
    es_ES( new Locale("es", "ES") ) ;

    final private Locale locale ;

    // Constructor
    L10n( Locale localeArg ) 
    {
        this.locale = Objects.requireNonNull( localeArg ) ;
    }

}

枚举元素是常量。所以在Java命名约定中,每个元素的名字都应该全部大写,比如FR_CA&ES_ES。我认为我们这里的案例是该约定的一个例外,因为 upper/lowercase 对于程序员识别每个名称的含义(语言和文化代码)很重要。

您可以使用此枚举中包含的 Locale 个对象来访问您的资源包。我们添加了一个 getResourceBundle 方法来提供此功能。

public enum L10n 
{
    // Enum elements.
    fr_CA( Locale.CANADA_FRENCH ) , 
    es_ES( new Locale("es", "ES") ) ;

    final private Locale locale ;  // Remember the `Locale` object behind each element in this enum.

    // Constructor
    L10n( Locale localeArg ) 
    {
        this.locale = Objects.requireNonNull( localeArg ) ;
    }

    // Access the ResourceBundle for a particular locale.
    public ResourceBundle getResourceBundle() 
    {
        …
    }

}

注意:考虑thread-safety。在您的应用中,每个枚举对象只有一个实例。因此,如果您可能跨线程调用,getResourceBundle 方法必须是线程安全的。如果仅从单个 UI 相关线程中调用,则线程安全不是问题。但请记住要考虑测试套件、日志记录或其他可能从主线程以外的线程调用的地方 UI。

使用 getResourceBundle 方法的示例。

L10n preferredLocalization = L10n.es_ES ;  // Perhaps taken from a dialog interaction with user.
ResourceBundle resourceBundle = preferredLocalization.getResourceBundle() ;

此枚举现在充当资源包处理前的外观。您可以重构该处理代码,而不会影响整个应用程序中您调用 L10n::getResourceBundle 的地方。

要显示您的应用支持的本地化列表,请添加获取显示名称的方法。此方法委托给包含的 Locale 对象的 Locale::getDisplayName 方法。您可能希望将该显示名称本地化为每个语言环境本身的语言和文化规范。

public enum L10n 
{
    // Enum elements.
    fr_CA( Locale.CANADA_FRENCH ) , 
    es_ES( new Locale("es", "ES") ) ;

    final private Locale locale ;  // Remember the `Locale` object behind each element in this enum.

    // Constructor
    L10n( Locale localeArg ) 
    {
        this.locale = Objects.requireNonNull( localeArg ) ;
    }

    // Access the ResourceBundle for a particular locale.
    public ResourceBundle getResourceBundle() 
    {
        …
    }

    // For presentation to the user.
    public String getDisplayName() 
    {
        String name = this.locale.getDisplayName( this.locale ) ;  // Pass a `Locale` to `Locale::getDisplayName` to have that locale's name automatically localized. 
        return name ;
    }

}

获取显示名称列表。

您可以获得枚举元素的集合。 Enum.values 方法是在 Java specs returning an array of all the objects defined as elements on that enum. Unfortunately this method is nearly omitted from the Enum Javadoc, with a mention buried in the valueOf 方法的描述中定义的一种特殊的“隐式”方法。

for ( L10n localization : L10n.values() )
{
    System.out.println( localization.getDisplayName() );
}

français (Canada)

español (España)

您可以通过将另一个成员字段添加到枚举 class 来获得代表该语言和文化的国旗图标,从而变得更加有趣。然后该标志可以出现在用户界面中以标识当前的本地化。将每个枚举元素的图标图像作为构造函数的第二个参数传递。或者在枚举 class 上编写代码来查找图标图像。当然,在我们的枚举 class 中添加一个 getFlag 方法到 return 表示标志图像。