user5182503
user5182503

Reputation:

Combine internationalized string with noninternationalized in fxml

In my FXML file I have

<Label text="%label.total" />

And in properties file I have

label.total=Total

However, I want to have Total: on my screen. And not only for this label but for many labels which are in fxml file. I don't want to add : to properties file because it seems to be wrong because here we must keep only strings for different languages.

Is it possible to combine anyhow "%label.total" with ":"? Or another solutions are used this case?

Upvotes: 3

Views: 745

Answers (1)

James_D
James_D

Reputation: 209358

This seems like it should be easier than it is. The FXML loader has the resource bundle automatically in its namespace with the key resources. If the resource bundle were a java.util.Map, then

<Label text="${resources.labelText + ':'}$ />

would work (with the key in the properties file changed to labelText). However, the FXMLLoader doesn't treat a resource bundle the same way as it treats a map, so this just ends up looking for a getLabelText() method in the resource bundle. It may be worth a feature request to allow accessing resource bundle properties in the same way as map properties.

So one potential solution is to copy the resource values you need into a map. The following works with your original properties file:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.util.HashMap?>

<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>


<VBox xmlns:fx="http://javafx.com/fxml/1">

    <fx:define>
        <HashMap fx:id="resourceAccess"
            labelTotal="%label.total"
        />              
    </fx:define>

    <Label text="${resourceAccess.labelTotal + ':'}" />

</VBox>

Note that you can add as many properties into the same map as you need, just add additional attributes. This feels a bit artificial, but it works.

You could also do this in Java code when you load the FXML:

    ResourceBundle resourceBundle = ResourceBundle.getBundle(...);

    FXMLLoader loader = new FXMLLoader(getClass().getResource(...), resourceBundle);

    Map<String, Object> resourceAccess = new HashMap<>();
    for (String key : resourceBundle.keySet()) {
        resourceAccess.put(key, resourceBundle.getObject(key));
    }
    loader.getNamespace().put("resourceAccess", resourceAccess);

    Parent root = loader.load() ;

Then the FXML

<Label text="${resourceAccess.labelTotal + ':'}" />

will work without the <fx:define> block. Again, though, this solution prohibits using . in the resource keys (or at least you would have to translate them to something else in the Java code: resourceAccess.put(key.replaceAll("\\.","_"), resourceBundle.getObject(key)); or similar).

It is not immediately apparent that any of this is better than the (perhaps more obvious) workaround:

<HBox><Label text="%label.total"/><Label text=":"/></HBox>

Upvotes: 2

Related Questions