Skip to content

Language Manager is a JavaFX library that enables dynamic language switching at runtime, allowing you to update the application language without needing to refresh the scene.

License

Notifications You must be signed in to change notification settings

Snoopy137/language-manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

53 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

License

language-manager

Language Manager is a JavaFX library that enables dynamic language switching at runtime, allowing you to update the application language without needing to refresh the scene.

πŸ“‘ Table of Contents

  1. Features
  2. Installation
  3. File Structure
  4. Usage
  5. Language Properties
  6. Fallback Handling
  7. Demo
  8. License
  9. Contributing
  10. Issues
  11. Versioning

✨ Features

🌍 Support for multiple languages using standard .properties files.

πŸ”„ Change language dynamically at runtime β€” no need to reload the scene.

πŸ”— Automatic binding for JavaFX controls such as Label, Button, TextField, CheckBox, RadioButton, ChoiceBox, ComboBox, MenuItem, and more.

🧠 Programmatic binding for controls without @FXML IDs β€” perfect for dynamically created interfaces.

βš™οΈ Custom annotations to ignore or customize specific field bindings.

🧩 Support for TreeItem and Tab bindings as well.

πŸ“¦ Lightweight, non-intrusive, and easy to integrate into any JavaFX project.

πŸ“¦ Installation

Add the library to your project using Maven or Gradle

Maven

Add the following to your pom.xml:

<dependency>
    <groupId>io.github.snoopy137</groupId>
    <artifactId>language-manager</artifactId>
    <version>1.1.2</version>
</dependency>

Gradle

Add this to your build.gradle:

dependencies {
    implementation 'io.github.snoopy137:language-manager:1.1.2'
}

πŸ“ File Structure

Place your resource bundles in the src/main/resources folder:

src/
└── main/
    └── resources/
        β”œβ”€β”€ language.properties         # Default (English)
        β”œβ”€β”€ language_es.properties      # Spanish
        └── language_fr.properties      # French

For specific key patterns used by controls like ChoiceBox, ComboBox, etc., see the Key Structure section.

πŸš€ Usage

1. FXML-Based Auto Binding

If you're using FXML, simply annotate your controller fields and call Language.autoBind(this) to automatically bind controls based on their @FXML IDs.

@FXML
private Label greeting;

@FXML
private Button submitButton;

public void initialize() {
    Language.autoBind(this); // Binds all supported @FXML controls automatically
}

ℹ️ Supported controls include Label, Button, TextField, TextArea, CheckBox, MenuItem, Tab, Tooltip, and more.

🚫 To exclude a specific field from being auto-bound, use the @IgnoreBind annotation:

@FXML @IgnoreBind
private Label doNotTranslate;

2. Programmatic Binding (No FXML Required)

If you're not using FXML or want to create and bind controls dynamically, you can use the @Bind annotation without @FXML. Just make sure to initialize your controls before calling Language.autoBind(this).

@Bind
private Label dynamicLabel;

public void initialize() {
    dynamicLabel = new Label();
    rootPane.setCenter(dynamicLabel);

    Language.autoBind(this); // Binds to key "dynamicLabel"
}

3. Custom Binding Key (Optional)

Whether you're using FXML or not, you can override the default binding key (which is normally the field name) by providing a custom value to the @Bind annotation.

βœ… With FXML

@FXML
@Bind("custom.key")
private Label greeting; // Binds to the key "custom.key" instead of the field name.

βœ… Without FXML

@Bind("custom.key")
private Label dynamicLabel;

public void initialize() {
    dynamicLabel = new Label();
    Language.autoBind(this); // Binds to the key "custom.key" instead of the field name.
}

This is useful for mapping controls to translation keys that don’t match their field names or follow a naming convention.

4. Manual Binding Without Annotations

If you're creating controls programmatically (not declared as fields), you can bind them using Language.autoBindField(...). In this case, you must provide the translation key explicitly, as there's no field name to derive it from.

private void initialize() {
    Label dynamicLabel = new Label();
    Language.autoBindField(dynamicLabel, "dynamic.label");
}

This is ideal for dynamically created controls that aren't declared as fields or when you want precise manual control over the key used.

5. Change Language Dynamically

Switch the application's active language at runtime using:

Language.setLocale(Locale.forLanguageTag("es")); // Switch to Spanish

🌍 This will automatically update all bound controls with the translated values from the corresponding language_es.properties file.

You can switch to any language as long as a corresponding .properties file is available (e.g., language_fr.properties for French).

πŸ’‘ If a key is missing in the selected language file, the fallback mechanism (see next section) will handle it gracefully.

πŸ—‚οΈ Language Properties

1. Base Name Customization

By default, the Language Manager looks for a language.properties file. You can customize the base name using:

Language.setBaseName("mybundle"); // Looks for mybundle.properties, mybundle_es.properties, etc.

This lets you organize language files however you'd like.

2. Key Structure for Complex Controls

Some controls (like ChoiceBox, ComboBox, TabPane, etc.) require a specific key format in the .properties files for their child items or tooltips to be localized properly. Example structure:

# ChoiceBox
choiceBox=Choose an option
choiceBox.0=Option1
choiceBox.1=Option2

# ComboBox
comboBox=Select an item
comboBox.0=Option 1
comboBox.1=Option 2

# TabPane
tab1=Tab 1
tab2=Tab 2
tab1.tooltip=Tab tooltip 1
tab2.tooltip=Tab tooltip 2

# ListView
listView.0=First item
listView.1=Second item
listView.2=Third item

# TreeView
treeView.0=Parent Node
treeView.0.0=Child Node 1
treeView.0.1=Child Node 2

Controller Example:

@FXML private ChoiceBox<String> choiceBox;
@FXML private ComboBox<String> comboBox;
@FXML private ListView<String> listView;
@FXML private TreeView<String> treeView;
@FXML private TabPane tabPane;
@FXML private Tab tab1, tab2;

@FXML
private void initialize() {
    choiceBox.getItems().addAll("Choice 1", "Choice 2");
    comboBox.getItems().addAll("Combo 1", "Combo 2");

    listView.getItems().addAll("Item 1", "Item 2", "Item 3");

    TreeItem<String> root = new TreeItem<>("Root");
    root.getChildren().addAll(
        new TreeItem<>("Child 1"),
        new TreeItem<>("Child 2")
    );
    treeView.setRoot(root);
}

Fallback Handling

If a specific language file (e.g., language_es.properties) doesn't exist, the system automatically falls back to the default language.properties. Additionally, if a bound key is missing in the current resource bundle:

The original textProperty() (or equivalent property) of the control is preserved β€” it won't be overwritten with a blank or placeholder.

A warning will be logged to help you track missing translations:

Missing key 'submitButton' in resource bundle

πŸ“Έ Demo

Language Switching Demo

πŸ”§ Under the Hood

Language Manager leverages ResourceBundle, SimpleObjectProperty, and Bindings to keep text in sync with the selected locale β€” all while avoiding the need to reinitialize scenes.

πŸ“„ License

MIT License

πŸ“š View Javadocs

🀝 Contributing

We welcome contributions! Please fork the repository and submit a pull request with your changes.

🐞 Issues

If you encounter any bugs or have feature requests, please open an issue in the GitHub Issues section.

πŸ”– Versioning

We follow Semantic Versioning for our releases. You can check out the release notes for each version on the Releases Page.

About

Language Manager is a JavaFX library that enables dynamic language switching at runtime, allowing you to update the application language without needing to refresh the scene.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 2

  •  
  •  

Languages