26

Is there any way to have message.properties records as follows

message.myMessage=This message is for ${name} in ${location}

as opposed to

message.myMessage = This message is for {0} in {1}

When I am creating the messages, I don't neccessarily know the order / how many parameters are needed, but I am able just pass in several properties by name, and just the correct ones would be used.

Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79
questioner
  • 775
  • 4
  • 9
  • 15
  • As provided in one of the answers below, the ICU (International Components for Unicode) library ICU4J is officially supported by the global Unicode Consortium, and is backwards compatible with the Java built-in `java.text.MessageFormat` (as in, it uses the same syntax, plus named variables, plus better support for pluralization in languages that were poorly supported before). http://site.icu-project.org/ – Erwin Bolwidt Oct 01 '19 at 03:59

6 Answers6

19

After facing the very same question and poking in source code I found a "loop-hole" that makes it possible in a very easy way:

message.myMessage = This message is for {0,,name} in {1,,location}

This approach doesn't eliminate usage of numbers. The reason to use it is to give hints to translation folks.

Yuriy Zubarev
  • 2,821
  • 18
  • 24
  • How can we pass `name` or `location` to `MessageSourceAccessor` as it takes array of objects to convert? – Saheb Jul 12 '17 at 11:32
13

I am afraid not, parameters are an Object array so there is no way to define names for them. If you always passes in the array of parameter in the same order though you could use them like this:

message.myMessage = This message is for {0} in {1}
message.myNameMessage = This message is for {0}
message.myLocationMessage = This message is for people in {1}
message.myAlternateMessage = The message params are location: {1}; name: {0}
krock
  • 28,904
  • 13
  • 79
  • 85
  • Marked correct bec we ended up going that route - passing in a list of all available parameters, and using the ones that are needed in the order needed. Not neat, but it works – questioner Apr 11 '11 at 16:42
  • It's possible with a little trick: http://stackoverflow.com/questions/5600055/how-can-i-used-named-parameters-in-a-messages-properties-file/9103148#9103148 – Yuriy Zubarev Feb 01 '12 at 20:59
11

Take a look at ICU4J

It allows for something like this:

message.myMessage=This message is for {name} in {location}.

And it is way more powerful than the simple replacements suggested, because can do locale aware formatting of the parameters (ie: "Subscription expires on: {expirationDate, date, long})

http://icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html

Mihai Nita
  • 5,547
  • 27
  • 27
7

Everything is possible for those who try... I never heard about something like that for Java, but you can write it by yourself.

Please take a look at this example:

public String format(String message, String... arguments) {
    for (String argument : arguments) {
        String[] keyValue = argument.split("=");
        if (keyValue.length != 2)
            throw new IllegalArgumentException("Incorrect argument: " + argument);
        String placeholder = "${" + keyValue[0] + "}";
        if (!message.contains(placeholder))
            throw new IllegalArgumentException(keyValue[0] + " does not exists.");
        while (message.contains(placeholder))
            message = message.replace(placeholder, keyValue[1]);
    }

    return message;
}

It is not ideal, as you actually would call it with hardcoded string (which is generally bad idea) and you would be forced to use Strings only, but it can be done. The only question is if it is practical.

Paweł Dyda
  • 18,366
  • 7
  • 57
  • 79
7

Unfortunately the MessageFormat API does not support named parameters, only argument-index:

Patterns and Their Interpretation

MessageFormat uses patterns of the following form:

MessageFormatPattern:
     String
     MessageFormatPattern FormatElement String

FormatElement:
     { ArgumentIndex }
     { ArgumentIndex , FormatType }
     { ArgumentIndex , FormatType , FormatStyle }
Community
  • 1
  • 1
matt b
  • 138,234
  • 66
  • 282
  • 345
3

It is possible using apache commons lang library.

https://commons.apache.org/proper/commons-lang/

    Properties messages = ...
    Map<String, String> m = new HashMap<>();
    m.put("name", "Mithu");
    m.put("location", "Dhaka");
    StrSubstitutor sub = new StrSubstitutor(m);
    String msg = sub.replace(messages.getProperty("message.myMessage"));
    // msg = This message is for Mithu in Dhaka