Localizing Your JavaFX Application
- Skill Level Intermediate
- Supported Versions JavaFX 1.3
- Key Features JavaFX Deployment
- Last Updated June 2010
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.
import java.util.Locale; import java.lang.String;
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.
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:
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.
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.
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.
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.
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
- Breaking Down Language Barriers in JavaFX Apps
- Internationalization Support in Java
- Class Locale
- Java Platform, Standard Edition 6, API Specification
Dmitry Kostovarov
Technical Writer, Sun Microsystems