1. Overview
1.概述
Exceptions in Java are used to signal that something has gone wrong in a program. In addition to throwing the exception, we can even add a message to provide additional information.
Java中的异常是用来提示程序中出了问题。除了抛出异常之外,我们甚至可以添加一个消息来提供额外的信息。
In this article, we’ll take advantage of the getLocalizedMessage method to provide exception messages in both English and French.
在这篇文章中,我们将利用getLocalizedMessage方法来提供英语和法语的异常信息。
2. Resource Bundle
2.资源捆绑
We need a way to lookup messages using a messageKey to identify the message and the Locale to identify which translation will provide the value for the messageKey. We’ll create a simple class to abstract access to our ResourceBundle for retrieving English and French message translations:
我们需要一种方法来查询消息,使用messageKey来识别消息,并使用Locale来识别哪个翻译将为messageKey提供值。我们将创建一个简单的类来抽象访问我们的ResourceBundle以检索英语和法语消息的翻译。
public class Messages {
public static String getMessageForLocale(String messageKey, Locale locale) {
return ResourceBundle.getBundle("messages", locale)
.getString(messageKey);
}
}
Our Messages class uses ResourceBundle to load the properties files into our bundle, which is at the root of our classpath. We have two files – one for our English messages and one for our French messages:
我们的Messages类使用ResourceBundle将属性文件加载到我们的bundle中,它位于我们classpath的根部。我们有两个文件–一个用于英语消息,一个用于法语消息。
# messages.properties
message.exception = I am an exception.
# messages_fr.properties
message.exception = Je suis une exception.
3. Localized Exception Class
3.本地化的异常类
Our Exception subclass will use the default Locale to determine which translation to use for our messages. We’ll get the default Locale using Locale#getDefault.
我们的Exception子类将使用默认的Locale来决定对我们的消息使用哪种翻译。我们将使用Locale#getDefault获得默认的Locale。
If our application were running on a server, we would use the HTTP request headers to identify the Locale to use instead of setting the default. For this purpose, we’ll create a constructor to accept a Locale.
如果我们的应用程序在服务器上运行,我们将使用HTTP请求头来确定要使用的Locale,而不是设置默认值。为此,我们将创建一个构造函数来接受一个Locale。
Let’s create our Exception subclass. For this, we could extend either RuntimeException or Exception. Let’s extend Exception and override getLocalizedMessage:
让我们来创建我们的Exception子类。为此,我们可以扩展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. Putting It All Together
4.归纳总结
Let’s create some unit tests to verify that everything works. We’ll create tests for English and French translations to verify passing a custom Locale to the exception during construction:
让我们创建一些单元测试来验证一切工作。我们将创建英语和法语翻译的测试,以验证在构建过程中向异常传递一个自定义的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.");
}
Our exception can use the default Locale as well. Let’s create two more tests to verify the default Locale functionality works:
我们的异常也可以使用默认的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. Caveats
5.注意事项
5.1. Logging Throwables
5.1.记录可抛物
We’ll need to keep in mind the logging framework we’re using to send Exception instances to the log.
我们需要牢记我们所使用的日志框架,将Exception实例发送到日志中。
Log4J, Log4J2, and Logback use getMessage to retrieve the message to write to the log appender. If we use java.util.logging, the content comes from getLocalizedMessage.
Log4J、Log4J2和Logback使用getMessage来检索要写入日志appender的消息。如果我们使用java.util.logging,内容来自getLocalizedMessage。
We might want to consider overriding getMessage to invoke getLocalizedMessage so we won’t have to worry about which logging implementation is used.
我们可能要考虑重写getMessage来调用getLocalizedMessage,这样我们就不必担心使用哪种日志实现了。
5.2. Server-Side Applications
5.2.服务器端应用
When we localize our exception messages for client applications, we only need to worry about one system’s current Locale. However, if we want to localize exception messages in a server-side application, we should keep in mind that switching the default Locale will affect all requests within our application server.
当我们为客户端应用程序本地化异常消息时,我们只需要担心一个系统的当前Locale。然而,如果我们想在服务器端应用程序中对异常消息进行本地化,我们应该记住,切换默认的Locale将影响我们应用程序服务器中的所有请求。
Should we decide to localize exception messages, we’ll create a constructor on our exception to accept the Locale. This will give us the ability to localize our messages without updating the default Locale.
如果我们决定对异常信息进行本地化,我们将在异常上创建一个构造函数来接受Locale。这将使我们有能力在不更新默认Locale的情况下对消息进行本地化。
6. Summary
6.归纳总结
Localizing exception messages is fairly straightforward. All we need to do is create a ResourceBundle for our messages, then implement getLocalizedMessage in our Exception subclasses.
异常消息的本地化是相当简单的。我们所要做的就是为我们的消息创建一个ResourceBundle,然后在我们的Exception子类中实现getLocalizedMessage。
As usual, the examples are available over on GitHub.
像往常一样,这些例子可以在GitHub上找到over。