Spring Boot API Lokalisierung
Typischerweise sind APIs zur Verarbeitung durch andere Systeme gedacht.
Wenn die Ausgaben jedoch für Menschen bestimmt sind, kann es sinnvoll sein, diese zu lokalisieren.
Das Spring Framework bringt dazu bereits Bausteine mit, ebenso Spring WebMVC für die Web bzw. API-Schicht.
Am Beispiel einer Spring Boot Anwendung wird der konkrete Einsatz illustriert.
Spring Boot bringt für Anwendungen automatische Konfigurationen mit.
Damit können viele Features von Spring und Spring WebMVC direkt verwendet werden, ohne dass diese als Teil des Anwendungscodes aktiviert oder konfiguriert werden müssen.
Dies gilt auch für die Features zur Lokalisierung von Texten.
Im Spring Framework wird dazu das MessageSource
Interface bereitgestellt, das durch die ResourceBundleMessageSource
implementiert wird.
Dabei werden standard Java Resource Bundles verwendet, um im Properties Format Texte für verschiedene Locales bereitzustellen.
Spring Boot Internationalization
Spring Boot aktiviert eine automatische Konfiguration durch die MessageSourceAutoConfiguration
.
Ohne weitere Konfiguration wird dann nach messages*.properties
Resource Bundles im Classpath gesucht.
Eine Anpassung ist durch das Spring Boot Property spring.messages.basename
möglich, bei dem eine Liste von zu verwendenden Positionen im Classpath angegeben werden kann.
Beispiele für entsprechende Dateien sind im folgenden Listing zu sehen.
message.properties
mit englischer Localewelcome.message=Hello {0}, welcome!
error.message=Sorry, the request could not be processed.
Um zwischen den verschiedenen Locales zu unterscheiden wird das Kürzel der jeweiligen Locale als Suffix hinter dem Basisnamen der Datei verwendet.
message_de.properties
mit deutscher Localewelcome.message=Willkommen, {0}.
error.message=Das hat nicht geklappt, wir bitten um Entschuldigung.
Je nach verwendeter IDE werden diese Resource Bundles auch gesondert angezeigt. In IntellIJ sieht das beispielsweise wie im folgenden Screenshot aus.
Verwendung von Internationalization in Spring Boot
Spring Boot stellt eine Bean vom Typ MessageSource
bereit, die dann ganz normal injected werden kann.
Alternativ kann auch das Interface MessageSourceAware
implementiert werden, dann wird die Methode setMessageSource(MessageSource messageSource)
durch das Interface vorgegeben und entsprechend durch die Spring Dependency Injection aufgerufen.
Im folgenden Beispiel ist eine Klasse zu sehen, die sich einer MessageSource
bedient, um lokalisierte Ausgaben zu ermitteln.
Es handelt sich dabei lediglich um ein Verwendungsbeispiel, das keinen eigenen Mehrwert bereitstellt.
Es spricht auch nichts dagegen, beispielsweise in der Controller-Schicht, direkt auf eine MessageSource
zuzugreifen.
MessageSource
@Service
public class MessageProvider implements MessageSourceAware
{
private MessageSource messageSource;
@Override
public void setMessageSource(MessageSource messageSource)
{
this.messageSource = messageSource;
}
public String resolve(String key, Locale locale, String ... args)
{
return messageSource.getMessage(key, args, locale);
}
}
Um nun die zu nutzende Ausgabe zu ermitteln wird die MessageSource
direkt oder indirekt aufgerufen.
Dabei können auch Parameter mitgegeben werden, um innerhalb der Ausgabe variable Daten abzubilden.
Eine Verwendung mit der oben gezeigten Beispielklasse in einem Controller könne wie folgt aussehen:
@GetMapping
public String welcome(String user, Locale locale)
{
return messageProvider.resolve("welcome.message", locale, user);
}
Die Locale
wird dabei automatisch von Spring WebMVC bereitgestellt und verwendet dazu die Default-Locale bzw. den Accept-Language
HTTP-Header.
Entsprechend sehen dann Beispielaufrufe der mit Spring Boot erstellten API aus.
$ http :8080/api user==thomas
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Hello thomas, welcome!
$ http :8080/api user==thomas Accept-Language:de
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Willkommen, thomas.
Analog zu Controller kann dies Verfahren genauso auch bei der Fehlerbehandlung verwendet werden.
Dazu werden typischerweise @ExceptionHandler
in den jeweiligen Controller-Klassen oder querschnittlich in @RestControllerAdvice
Klassen angegeben.
@RestControllerAdvice
@RestControllerAdvice
public class ErrorHandlingAdvice
{
private final MessageProvider messageProvider;
public ErrorHandlingAdvice(MessageProvider messageProvider)
{
this.messageProvider = messageProvider;
}
@ExceptionHandler
public String handleRuntime(RuntimeException ex, Locale locale)
{
return messageProvider.resolve("error.message", locale);
}
}
Der zugehörige Aufruf und die lokalisierte Ausgabe ist im folgenden Beispiel zu sehen.
$ http :8080/api/error Accept-Language:de
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Das hat nicht geklappt, wir bitten um Entschuldigung.
Speziell für die Entwicklung kann es sehr praktisch sein, wenn fehlende Angaben in den Messages-Dateien nicht zu einem Fehler führen, sondern stattdesssen der jeweillige Schlüssel ausgegeben wird.
Dies kann in Spring Boot durch das Property spring.messages.use-code-as-default-message
gesteuert werden.
Zu den Themen Spring und Spring Boot bieten wir zudem sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.