Planet JFX

This proposal intends to provide a convenient way to translate string literals in the JavaFX source for easier localization. It consists of an additional optional syntax to string literals, and a new properties file format that provides the translations of the strings for each language.


Chris Oliver prototyped translatable string literals support with the interpreter version of JavaFX. The prototype uses prefix ## followed by a string literal indicating that the given string literal may be translated. This mechanism enables internationalization of JavaFX applications. The following is an example of ## usage.

var x = ##"This needs translation.";

Unlike java.util.ResourceBundle, this supports the gettext() style interface for retrieving translated strings. That is, an entire string literal is the key to get its translation at the same time the key itself is the default string. With the example above, "This needs translation." is the key to get its translation. If the runtime can't find its translation, the key "This needs translation." is used as the default string.

To localize a JavaFX application, you need to provide a properties file with translations. For example, the properties file for French locale would look like this.

This needs translation.=Cela exige la traduction.

If the runtime finds the properties file for French locale, the string literal "This needs translation." is substituted with "Cela exige la traduction.".

In case that a string literal includes embedded expressions, the ## prototype converts those embedded expressions to java.text.MessageFormat specifies for creating a key. For example, with the following code:

var result = 123;
var y = ##"The result is {result}";

the key for retrieving its translation is "The result is {0,number,integer}" and the properties entry would be:

The result is {0,number,integer}=Le résultat est {0,number,integer}

The support of the gettext() style message catalog and embedded expressions raises unique issues.

Key/Value Delimiter

White space is a key/value delimiter in the traditional Java properties. (##"Hello, World" needs quoting in a properties file as "Hello,\ World".)

Character Encoding

The character encoding for the traditional Java properties is ISO-8859-1. Many developers say it's annoying to deal with \uxxxx.

Context aware translations

Different translations are sometimes required for the same words, especially short words for GUI, like menu items. ## may need the context support that is found in the GNU gettext context support.

Language syntax

String literals that may be localized are JavaFX string literals that are prefixed by "##". For example, ##"Hello" is a valid translatable string literal. JavaFX then looks in the FX properties file (described below) for the localized string for the original string literal "Hello". If it finds the localized string, then the localized literal is used as the string literal. The original string literal (in this case, "Hello") works both as a key to the localized literal and the default translation.

This syntax can optionally take an explicit key for looking up the translation. This explicit key can disambiguate the meaning of short words in order for the context aware translations. The explicit key is a JavaFX string, and needs to be surrounded by a pair of square brackets instead of double quotes/single quotes, and placed in between "##" and the string literal, e.g., ##[FILE_VERB]"File". In this example, JavaFX runtime looks for the translation in the FX properties file by using "FILE_VERB" as the key, instead of "File" itself.

FX properties file

In order to address the issues with the existing properties file that are described in the "Background" section, we are proposing a new properties file format for JavaFX Script as follows.

File encoding

The default file encoding of the FX properties file is "UTF-8", unless the first line contains the CSS style character encoding declaration, e.g.,

@charset "ISO-8859-1";

File contents

Except the above file encoding definition, the contents of an FX properties file are either a comment line(s) or a property that consists of a key/value pair of two string literals that are separated by an equal ('=') character. Both comments and string literals should follow the standard JavaFX conventions except the string expression described below. For example, for a source .fx file:

var a = ##"Hello World!";
var b = ##"Today is {new Date()}";
var bday = new GregorianCalendar(1995, Calendar.MAY, 23);
var c = ##"Duke's birthday: {%1$tm bday} {%2$te bday}, {%3$tY bday}.";

Then, a Japanese FX properties file would look like:

// this is a comment line
 * Multiple comment lines
"Hello World" = "こんにちは、世界"
"Today is %s" = "今日は%sです"
'single quote property' = 'シングルクォートプロパティ'
"Duke's birthday: %1$tm %2$te, %3$tY." = "デュークの誕生日は%3$tY年%1$tm月%2$te日です。"

Embedded expressions in the source ".fx" files are replaced with format specifiers of java.util.Formatter and they default to "%s", unless explicitly specified in the source fx file (cf. "Duke's birthday" example). Note that those single-quotes or double-quotes are mandatory to be able to include leading and trailing white spaces. Multi line property is allowed, as in the source JavaFX file, like:

"This is
a multi line property" = "これは

A backslash ('\') is used to escape special characters, such as ='"'=, '{', and '\' itself. It also allows to include control characters, '\n', '\t', '\r', '\f', and the Unicode escapes '\uXXXX', where XXXX is the Unicode code point of the character.

An explicit key can be used for the context aware translation. In the FX script:

var to_file = ##[FILE_VERB]"File";

In the FX properties file, the explicit key needs to be quoted:

"FILE_VERB" = "ファイルする"