-
Notifications
You must be signed in to change notification settings - Fork 4
GSIP 75 Exception I18n
Adding ability to localize exception messages.
{info} This proposal is actually implemented as part of [GSIP 71 - New Security Subsystem]. {info}
Justin Deoliveira
2.2
Under Discussion, In Progress, Completed, Rejected, Deferred
Currently Geoserver supports i8n of the web admin interface, but lacks localized error messages from exceptions. The goal of this proposal is to provide a mechanism for localizing exception messages that translators are familiar with.
What is not the goal of this proposal is to do a comprehensive localization of every exception message emitted by GeoServer. This is meant to be built-up over time, the same way translations of the wicket ui are.
This proposal has two main parts. The first is a set of base classes that all localizable exceptions extend from. The second is a mechanism for adding properties files (resource bundles) containing exception message translations.
The idea here is to have two exception base classes, one for checked and one for non-checked exceptions, that all localizable exceptions in GeoServer extend from. These subclasses add two additional properties:
-
id
- An identifier for the exception -
args
- Arguments to pass to the localized exception message
The following is an excerpt from the GeoServerException
class:
public class GeoServerException extends Exception {
/** id for the exception, used to locate localized message for the exception */
String id;
/** arguments to pass into the localized exception message */
Object[] args;
@Override
public String getMessage() {
if (id == null) {
return super.getMessage();
}
String localized = GeoServerExceptions.localize(this);
return localized != null ? localized : super.getMessage();
}
}
The getMessage ()
method is overridden and a utility method,
GeoServerExceptions.localize
, is delegated to. The localize
method does two things.
- Locates the bundle containing translated messages for the exception class
- Looks up the message key based on exception id
Exception messages are stored in property files (known as bundles), named with a base name of “GeoServerException”. The naming convention is the same as that of the web ui message bundles, with the default bundle file being named “GeoServerException.properties”, and a two letter code appended onto the base name for each supported locale.
The location of the message bundles also mirrors of that of the web ui in that they are located in the root of a module. The contents of the message bundles are key value pairs in which the keys consist of an exception class name and exception id pair, and the values being the translated messages. For example consider the following entry.
XMLSecurityConfigException.FILENAME_CHANGE_INVALID=Cannot change file name from {0} to {1}
In the above “XMLSecurityConfigException” is the non-qualified exception class name, and “FILENAMECHANGEINVALID” is the exception identifier. This example also shows a translated message containing two parameters.
The exception class name can be specified as qualified or non-qualified. The qualified version is also looked up first, and if no matching key is found the non-qualified version is used.
The lookup order of exception message bundles depends on the server
locale. First the default locale of the server Locale.getDefault ()
is used to locate a message bundled using the two letter language code
of the locale. For instance a server a default local of german would
look for a file named “GeoServerException_de.properties”. If no such
bundle is found the language code is dropped and the default file
“GeoServerException.properties”, that contains the English translation,
is looked up.
In the event no file is found period, not even a default, the exception message is left un-localized and the exception message is simply the exception identifier.
Let us consider a full example of creating a localized exception. First the exception class itself:
public class FooException extends GeoServerException {
public static final String HELLO_$1 = "HELLO";
public FooException(String id, Object[] args) {
super(id);
setArgs(args);
}
}
We create public constants on the class for each of the exception identifiers to implement. Throwing this exception would look something like:
throw new FooException(HELLO_$1, new Object[]{"Bob"});
In the root of the module we would then create a default message bundle named “GeoServerException.properites” with the following contents:
FooException.HELLO=Hello {0}
And additional bundles for each supported language, for example GeoServerException_fr.properties
FooException.HELLO=Bounjour {0}
This section should contain feedback provided by PSC members who may have a problem with the proposal.
None.
Andrea Aime: Alessio Fabiani: Ben Caradoc Davies: Gabriel Roldan: Justin Deoliveira: Jody Garnett: Mark Leslie: Rob Atkinson: Simone Giannecchini:
JIRA Task Email Discussion Wiki Page