Localizing Your JavaFX Application

In this article you will learn how to localize a JavaFX application. The Carousel application in this article enables viewers to see the names of animals in the selected language when they point to pictures.

Note: Some characters might not display correctly depending on your locale and installed language support.

To localize the Carousel application, you import the localization class, add property files to the project, add tooltips, and add the code that will call the necessary classes and substitute English text with the text of the selected language in the tooltips.

java.util.Locale Class

The Locale class represents a specific geographical, political, or cultural region. By importing the Locale class to your JavaFX application, you enable the localization features.

You also need to import other classes that help you to create text tooltips and HBox containers.

Main.fx
import java.util.Locale;

import java.lang.String;
Carousel.fx
import javafx.scene.text.Text;
import javafx.scene.paint.Color; 
import javafx.scene.text.Font; 
import javafx.scene.layout.HBox; 
import javafx.geometry.HPos;

Localizing the Tooltip Text

For each language translation of your product, create a new .fxproperties file. Your .fxproperties file names must begin with the main class file name. If you previously created a properties file with the default locale, use the same name and add the locale name to it. For example, if you created MyMainClass.fxproperties to store all English text, create a MyMainClass_fr.fxproperties file for the French text.

In the Carousel application, the English text is specified by the caption array directly in the Main.fx file. English is the default locale in this application.

English Text in the Main.fx File
var caption: String[];
var locale = Locale.getDefault() on replace {
Locale.setDefault(locale);
caption = [
##"fish",
##"lion",
##"koala",
##"bird",
##"frog",
##"giraffe"
]
}

Each string literal in the caption array is prefixed with a double hash sign ##. If JavaFX finds appropriate localization in JavaFX properties files, it substitutes the string literal with a localized one at run-time. A JavaFX properties file contains localized strings for a locale as "key" = "value" pairs. Localized strings are searched using the original string literals as keys. If no localized string is found, the original string literal is used as a default.

For the Carousel application, the following .fxproperties files were created for the Chinese, French, and Russian languages:

  • Main_zh.fxproperties
  • Main_fr.fxproperties
  • Main_ru.fxproperties

Each file contains text mappings such as the following for French:

Main_fr.fxproperties File Contents
"fish" = "poisson"
"lion" = "lion"
"koala" = "koala"
"bird" = "oiseau"
"frog" = "grenouille"
"giraffe" = "girafe"

You also create a new class to match the selected language with corresponding locale.

MyToggleGroup Class
  class MyToggleGroup extends ToggleGroup {

   override var selectedToggle on replace {
               var value = selectedToggle.value;
               if (selectedToggle != null)
                   if (value == "Chinese") {
                       locale = Locale.CHINESE
                   } else if (value == "French") {
                       locale = Locale.FRENCH
                   } else if (value == "English") {
                       locale = Locale.ENGLISH
                   } else if (value == "Russian") {
                       locale = new Locale("ru", "RU")

                   }
           }
}

Creating Language Option Buttons With Flags

When a user selects a language, the text array is filled with text read from the corresponding .fxproperties file. You create a MyControl class and a box container with option buttons for each language and flags of the countries of origin.

Create a MyControl class as follows:

Source Code
  class MyControl extends CustomNode {

   var button: Node[];
   var flagImage: Image;

   override function create() {
       HBox {
           spacing: 5
           nodeVPos: VPos.CENTER
           content: bind [button, ImageView {image: flagImage fitHeight: 10 preserveRatio: true}
           ]
       }
   }
}

The following code creates a box container with language buttons and flags. This code is placed in the scene element of the Main.fx file.

Source Code
        HBox {
translateY: 330
translateX: 10
spacing: 15
content: [
MyControl {
button: RadioButton {toggleGroup: toggleGroup value: "Chinese"}
flagImage: Image {url: "{__DIR__}china.jpg"}
},
MyControl {
button: RadioButton {toggleGroup: toggleGroup value: "French"}
flagImage: Image {url: "{__DIR__}french.jpg"}
},
MyControl {
button: RadioButton {toggleGroup: toggleGroup value: "English"}
flagImage: Image {url: "{__DIR__}eng.jpg"}
},
MyControl {
button: RadioButton {toggleGroup: toggleGroup value: "Russian"}
flagImage: Image {url: "{__DIR__}rus.jpg"}
}
]
}

Adding a Tooltip

In the Carousel.fx file, add a tooltip that appears when the mouse is pointed to an image.

Source Code
def tooltip: Text = Text{
        opacity: 0.0
        content: bind text 
        fill: Color.rgb(148, 176, 255)
        font: Font{size: 18}
       }

   def appear = Timeline {
         keyFrames: [
           at(0s) {tooltip.opacity => 0.0},
           at(0.5s) {tooltip.opacity => 1.0}
         ]
  }

The tooltip is then put in the HBox container in the Node to ensure that the text is centered.

Source Code
   public override function create(): Node {
       if (__PROFILE__ == "tv") {
           xcenter = 100;
           ycenter = 170;
           zcenter = 120;
           radius_x = 500;
           radius_y = 220;
       }
       return Group {
                   content: [
                       ImageView {
                           x: bind X
                           y: bind Y
                           scaleX: bind scale
                           scaleY: bind scale
                           opacity: bind local_opacity
                           image: bind image
                           cursor: Cursor.DEFAULT
                           blocksMouse: true
                           onMouseEntered: function (event) {
                               appear.rate = 1;
                               appear.play();
                           }
                           onMouseExited: function (event) {
                               appear.rate = -1;
                               appear.play();
                           }
                       },
                       //Adding a box for the text
                       HBox {
                           layoutX: 30
                           layoutY: 250
                           layoutInfo: LayoutInfo {width: 170}
                           hpos: HPos.CENTER
                           content: tooltip
                       }
                   ]
               };
   }

Binding Tooltip Text to Images

Using data binding, you can change the content of the tooltip without creating a separate code for it.

Source Code
for (i in [0..5]) {
insert Carousel {
X: Math.cos(Carousel.angle + i * Carousel.image_gap + Carousel.shift) * Carousel.radius_x + Carousel.xcenter;
Y: -Math.sin(Carousel.angle + i * Carousel.image_gap + Carousel.shift) * Carousel.radius_y + Carousel.ycenter;
Z: Math.sin(Carousel.angle + i * Carousel.image_gap + Carousel.shift) * Carousel.radius + Carousel.zcenter
local_opacity: Carousel.fl / (Carousel.fl + Math.sin(Carousel.angle + i * Carousel.image_gap + Carousel.shift) * Carousel.radius
+ Carousel.zcenter)
scale: Carousel.fl / (Carousel.fl + Math.sin(Carousel.angle + i * Carousel.image_gap + Carousel.shift) * Carousel.radius
+ Carousel.zcenter)
image: bind Image {
url: im[i]
}
text: bind caption[i]
} into carousel;
}

Note: To use localization features, your application must be signed. For more information, see Create a Secure JavaFX Application.

Related Links