0

I'm trying to add localisation functionality to a JavaFX program using FXML. From what I understand, when you create a FXMLLoader object, you can pass a ResourceBundle into the FXMLLoader's constructor like so:

FXMLLoader loader = new FXMLLoader(Application.class.getResource("main-menu.fxml"),
        ResourceBundle.getBundle("com.example.myApp.MainMenu");

However, I want to be able to access the ResourceBundle inside one of my controllers, so that I can do something like this:

class MainMenuController {
    // ...
    @FXML
    protected void onButtonClick() {
        welcomeText.setText(localisationBundle.getString("greetMessage");
    }
    // ...
}

I have put the following initialize method inside my main menu controller...

@FXML
public void initialize(URL location, ResourceBundle bundle) {
    this.localisationBundle = bundle;
}

...but it does not get invoked when the program is run, and thus localisationBundle is null when my button is pressed. The initialize method only gets invoked when I change its signature to have no parameters. I have seen a suggestion on StackOverflow that my controller should implement Initializable, however the documentation says that this has been superceded.

My question is: Is there a way to get access to the ResourceBundle that is passed to the FXMLLoader's constructor? Is Initializable the only way I can do this or is there a better way?

Thanks in advance :)

  • 1
    That should work. If your `initialize()` method is not getting invoked something else is wrong in your setup: create and post a [mre]. Note you can also inject the resource bundle using `@FXML` on a field called `resources` (though this is undocumented behavior, as far as I can tell). – James_D Nov 10 '22 at 18:51
  • 2
    `@FXML private ResourceBundle resources;` it injects like other fxml annotated fields, no fx:id required. – jewelsea Nov 10 '22 at 19:01
  • In addition to the load method with the resources parameter, there are a couple of [alternate methods for specifying a resource bundle](https://stackoverflow.com/questions/46103533/specify-resourcebundle-within-fxml-file-in-javafx), they all achieve the same thing. – jewelsea Nov 10 '22 at 19:05
  • 2
    @James_D It's _sort of_ [documented behavior](https://openjfx.io/javadoc/19/javafx.fxml/javafx/fxml/Initializable.html), but the documentation is... poor. – Slaw Nov 10 '22 at 19:07
  • 2
    Ah, actually, yes. The `initialize()` method that takes parameters appears *not* to get invoked if you don't implement `Initializable`. If you don't want to implement the interface, use injection instead. – James_D Nov 10 '22 at 19:23

1 Answers1

4

The initialize() method taking the URL and ResourceBundle parameters only gets invoked if you implement Initializable. This interface has not been deprecated, so I think it is fine to use that approach; however it has been superseded by (to quote the documentation

automatic injection of location and resources properties into the controller.

To do this, you need:

public class MainMenuController {

    @FXML
    private ResourceBundle resources ;

    // if needed:
    @FXML
    private URL location ;

    // ...
    @FXML
    protected void onButtonClick() {
        welcomeText.setText(resources.getString("greetMessage");
    }
    // ...
}
James_D
  • 201,275
  • 16
  • 291
  • 322