Documentation

You are viewing the documentation for the 2.8.20 release in the 2.8.x series of releases. The latest stable release series is 3.0.x.

§Internationalization with Messages

§Specifying languages supported by your application

You specify languages for your application using language tags, specially formatted strings that identify a specific language. Language tags can specify simple languages, such as “en” for English, a specific regional dialect of a language (such as “en-AU” for English as used in Australia), a language and a script (such as “az-Latn” for Azerbaijani written in Latin script), or a combination of several of these (such as “zh-cmn-Hans-CN” for Chinese, Mandarin, Simplified script, as used in China).

To start you need to specify the languages supported by your application in the conf/application.conf file:

play.i18n.langs = [ "en", "en-US", "fr" ]

These language tags will be used to create play.i18n.Lang instances. To access the languages supported by your application, you can inject a play.i18n.Langs component into your class:

import play.i18n.Langs;
import play.i18n.Messages;
import play.i18n.MessagesApi;

import javax.inject.Inject;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;

public class MyService {
  private final Langs langs;

  @Inject
  public MyService(Langs langs) {
    this.langs = langs;
  }
}

An individual play.i18n.Lang can be converted to a java.util.Locale object by using lang.toLocale() method:

java.util.Locale locale = lang.toLocale();

§Externalizing messages

You can externalize messages in the conf/messages.xxx files.

The default conf/messages file matches all languages. You can specify additional language messages files, such as conf/messages.fr or conf/messages.en-US.

Messages are available through the MessagesApi instance, which can be added via injection. You can then retrieve messages using the play.i18n.Messages object:

class SomeService {
  private final play.i18n.MessagesApi messagesApi;

  @Inject
  SomeService(MessagesApi messagesApi) {
    this.messagesApi = messagesApi;
  }

  public void message() {
    Collection<Lang> candidates = Collections.singletonList(new Lang(Locale.US));
    Messages messages = messagesApi.preferred(candidates);
    String message = messages.at("home.title");
  }
}

If you don’t want to use preferred(...) to retrieve a Messages object you can directly get a message string by specifying a message’s language explicitly:

String title = messagesApi.get(Lang.forCode("fr"), "hello");

Note that you should inject the play.i18n.MessagesApi class, using dependency injection. For example, using Guice you would do the following:

public class MyClass {

  private final play.i18n.MessagesApi messagesApi;

  @Inject
  public MyClass(MessagesApi messagesApi) {
    this.messagesApi = messagesApi;
  }
}

§Use in Controllers

If you are in a Controller, you can get the Messages instance through the current Http.Request:

public Result index(Http.Request request) {
  Messages messages = this.messagesApi.preferred(request);
  String hello = messages.at("hello");
  return ok(hellotemplate.render(messages));
}

MessagesApi.preferred(request) determines the language by:

  1. Seeing if the Request has a transient lang set by checking its transientLang() method.
  2. Looking for a PLAY_LANG cookie in the request.
  3. Looking at the Accept-Language headers of the request.
  4. Using the application’s default language.

To use Messages as part of form processing, please see Handling form submission.

§Use in templates

Once you have the Messages object, you can pass it into the template:

@(messages: play.i18n.Messages)
@messages.at("hello")

There is also a shorter form that’s equivalent to messages.at which many people find useful.

@(messages: play.i18n.Messages)
@messages("hello")

Localized templates that use messages.at(...) or simply messages(...) are invoked like normal:

public Result index(Http.Request request) {
  Messages messages = this.messagesApi.preferred(request);
  return ok(hellotemplate.render(messages));
}

§Changing the language

If you want to change the language of the current request (but not for future requests) use Request.withTransientLang(lang), which sets the transient lang of the current request.
Like explained above, the transient language of the request will be taken into account when calling MessagesApi.preferred(request). This is useful to change the language of templates.

public Result index(Http.Request request) {
  Lang lang = Lang.forCode("en-US");
  Messages messages = this.messagesApi.preferred(request.withTransientLang(lang));
  return ok(hellotemplate.render(messages));
}

If you want to permanently change the language you can do so by calling withLang on the Result. This will set a PLAY_LANG cookie for future requests and will therefore be used when calling MessagesApi.preferred(request) in a subsequent request (like shown above).

public Result index(Http.Request request) {
  Lang lang = Lang.forCode("fr");
  Messages messages = this.messagesApi.preferred(request.withTransientLang(lang));
  return ok(hellotemplate.render(messages)).withLang(lang, messagesApi);
}

§Formatting messages

Messages are formatted using the java.text.MessageFormat library. For example, if you have defined a message like this:

files.summary=The disk {1} contains {0} file(s).

You can then specify parameters as:

Messages.get("files.summary", d.files.length, d.name)

§Notes on apostrophes

Since Messages uses java.text.MessageFormat, please be aware that single quotes are used as a meta-character for escaping parameter substitutions.

For example, if you have the following messages defined:

info.error=You aren''t logged in!
example.formatting=When using MessageFormat, '''{0}''' is replaced with the first parameter.

you should expect the following results:

String errorMessage = messages.at("info.error");
Boolean areEqual = errorMessage.equals("You aren't logged in!");
String errorMessage = messages.at("example.formatting");
Boolean areEqual =
    errorMessage.equals(
        "When using MessageFormat, '{0}' is replaced with the first parameter.");

§Retrieving supported languages from an HTTP request

You can retrieve a specific HTTP request’s supported languages:

public Result index(Http.Request request) {
  List<Lang> langs = request.acceptLanguages();
  String codes = langs.stream().map(Lang::code).collect(joining(","));
  return ok(codes);
}

§Using explicit MessagesApi

The default implementation of MessagesApi is backed by a DefaultMessagesApi instance which is a Scala API. But you can instantiate a DefaultMessagesApi and manually inject it into the MessagesApi like:

private MessagesApi explicitMessagesApi() {
  return new play.i18n.MessagesApi(
      new play.api.i18n.DefaultMessagesApi(
          Collections.singletonMap(
              Lang.defaultLang().code(), Collections.singletonMap("foo", "bar")),
          new play.api.i18n.DefaultLangs().asJava()));
}

If you need a MessagesApi instance for unit testing, you can also use play.test.Helpers.stubMessagesApi(). See Testing your application for more details.

Next: Dependency Injection