在Java中本地化异常消息

2023/05/30

1. 概述

Java中的异常用于表示程序中出现了错误。除了抛出异常,我们甚至可以添加一条消息来提供额外的信息。

在本文中,我们将利用getLocalizedMessage方法以英语和法语提供异常消息。

2. 资源包

我们需要一种方法来查找消息,使用messageKey来标识消息,并使用Locale来标识哪个翻译将为messageKey提供值。我们将创建一个简单的类来抽象对ResourceBundle的访问,以检索英语和法语消息翻译:

public class Messages {

    public static String getMessageForLocale(String messageKey, Locale locale) {
        return ResourceBundle.getBundle("messages", locale)
                .getString(messageKey);
    }
}

我们的Messages类使用ResourceBundle将属性文件加载到我们的包中,它位于我们类路径的根目录中。我们有两个文件-一个用于我们的英语消息,一个用于我们的法语消息:

# messages.properties
message.exception=I am an exception.
# messages_fr.properties
message.exception=Je suis une exception.

3. LocalizedException类

我们的Exception子类将使用默认的Locale来确定对我们的消息使用哪种翻译。我们将使用Locale#getDefault获取默认的Locale

如果我们的应用程序在服务器上运行,我们将使用HTTP请求标头来标识要使用的Locale,而不是设置默认值。为此,我们将创建一个构造函数来接收Locale。

让我们创建我们的异常子类。为此,我们可以扩展RuntimeException或Exception。让我们扩展Exception并覆盖getLocalizedMessage:

public class LocalizedException extends Exception {

    private final String messageKey;
    private final Locale locale;

    public LocalizedException(String messageKey) {
        this(messageKey, Locale.getDefault());
    }

    public LocalizedException(String messageKey, Locale locale) {
        this.messageKey = messageKey;
        this.locale = locale;
    }

    public String getLocalizedMessage() {
        return Messages.getMessageForLocale(messageKey, locale);
    }
}

4. 把它们放在一起

让我们创建一些单元测试来验证一切正常。我们将为英语和法语翻译创建测试,以验证在构造期间将自定义Locale传递给异常:

@Test
public void givenUsEnglishProvidedLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessage() {
    LocalizedException localizedException = new LocalizedException("message.exception", Locale.US);
    String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage();

    assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception.");
}

@Test
public void givenFranceFrenchProvidedLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() {
    LocalizedException localizedException = new LocalizedException("message.exception", Locale.FRANCE);
    String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage();

    assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception.");
}

我们的异常也可以使用默认的Locale。让我们再创建两个测试来验证默认的Locale功能是否有效:

@Test
public void givenUsEnglishDefaultLocale_whenLocalizingMessage_thenMessageComesFromDefaultMessages() {
    Locale.setDefault(Locale.US);

    LocalizedException localizedException = new LocalizedException("message.exception");
    String usEnglishLocalizedExceptionMessage = localizedException.getLocalizedMessage();

    assertThat(usEnglishLocalizedExceptionMessage).isEqualTo("I am an exception.");
}

@Test
public void givenFranceFrenchDefaultLocale_whenLocalizingMessage_thenMessageComesFromFrenchTranslationMessages() {
    Locale.setDefault(Locale.FRANCE);

    LocalizedException localizedException = new LocalizedException("message.exception");
    String franceFrenchLocalizedExceptionMessage = localizedException.getLocalizedMessage();

    assertThat(franceFrenchLocalizedExceptionMessage).isEqualTo("Je suis une exception.");
}

5. 注意事项

5.1 记录Throwable

我们需要记住用于将异常实例发送到日志的日志记录框架

Log4J、Log4J2和Logback使用getMessage检索消息以写入日志追加器。如果我们使用java.util.logging,则内容来自getLocalizedMessage。

我们可能要考虑重写getMessage以调用getLocalizedMessage,这样我们就不必担心使用哪个日志记录实现。

5.2 服务器端应用程序

当我们为客户端应用程序本地化我们的异常消息时,我们只需要担心一个系统的当前Locale。但是,如果我们想在服务器端应用程序中本地化异常消息,我们应该记住切换默认Locale将影响我们应用程序服务器中的所有请求

如果我们决定本地化异常消息,我们将在我们的异常上创建一个构造函数来接收Locale。这将使我们能够在不更新默认Locale的情况下本地化我们的消息。

6. 总结

本地化异常消息非常简单。我们需要做的就是为我们的消息创建一个ResourceBundle,然后在我们的Exception子类中实现getLocalizedMessage。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章