Skip to content
The library `Lib-I18N` allows a developer to bind a key-value pair of a `.properties` file to a [StringBinding]. This makes it very easy to change the language during runtime in a [JavaFX] application.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
concept
docs/apidocs
release
src
.gitignore
.travis.yml
LICENSE
README.md
nb-configuration.xml
nbactions.xml
pom.xml

README.md

Lib-I18n

Build Status license: GPL v3 GitHub release

Intention

The library Lib-I18N allows a developer to bind a key-value pair of a .properties file to a StringBinding. This makes it very easy to change the language during runtime in a JavaFX application.
Lib-I18N is written in JavaFX, Maven and NetBeans.

Image: Example integration App-Yin-Yang
Integration_App-Yin-Yang_v0.7.0_2018-12-29_20-54.png

Content

Examples

How to use the builder I18NResourceBundleBuilder

With the builder I18NResourceBundleBuilder the developer can configure the ResourceBundle which contains the key - value terms which will then be bind to a Locale. That means switching the actual Locale update all binded textes with the specific value from the corresponding language .properties file.

Specification: Usage of I18NResourceBundleBuilder

/**
 * 1) Starts the configuration process.
 * 2) Defines the path and name from the .properties file.
 * 3) Sets all supported Locales with an [].
 * 4) Sets all supported Locales with an ObservableList.
 * 5) Sets the default Locale.
 * 6) Sets the actual Locale.
 * 7) Completes the configuration process.
 */
I18NResourceBundleBuilder.configure() // 1
        .baseBundleName(String)       // 2
        .supportedLocales(Locale...)  // 3
        .supportedLocales(ObservableList<Locale>) // 4
        .defaultLocale(Locale)        // 5
        .actualLocale(Locale)         // 6
        .build();                     // 7

Examples:

@Test
public void lastStepWithSupportedLocalesAsArray() {
    String resourcbundle = "com.github.naoghuman.lib.i18n.internal.resourcebundle";
    I18NResourceBundleBuilder.configure()
            .baseBundleName(resourcbundle)
            .supportedLocales(Locale.ITALIAN, Locale.JAPANESE)
            .defaultLocale(Locale.ITALIAN)
            .actualLocale(Locale.JAPANESE)
            .build();

    assertEquals(resourcbundle,   I18NFacade.getDefault().getBaseBundleName());
    assertEquals(Locale.ITALIAN,  I18NFacade.getDefault().getDefaultLocale());
    assertEquals(Locale.JAPANESE, I18NFacade.getDefault().getActualLocale());
    assertEquals(2,               I18NFacade.getDefault().getSupportedLocales().size());
}

@Test
public void lastStepWithSupportedLocalesAsObservableList() {
    String resourcbundle = "com.github.naoghuman.lib.i18n.internal.resourcebundle";
    final ObservableList<Locale> locales = FXCollections.observableArrayList();
    locales.addAll(Locale.ITALIAN, Locale.JAPANESE, Locale.FRENCH);
    I18NResourceBundleBuilder.configure()
            .baseBundleName(resourcbundle)
            .supportedLocales(locales)
            .defaultLocale(Locale.ITALIAN)
            .actualLocale(Locale.JAPANESE)
            .build();

    assertEquals(resourcbundle,  I18NFacade.getDefault().getBaseBundleName());
    assertEquals(Locale.ITALIAN, I18NFacade.getDefault().getDefaultLocale());
    assertEquals(Locale.JAPANESE,I18NFacade.getDefault().getActualLocale());
    assertEquals(3,              I18NFacade.getDefault().getSupportedLocales().size());
}

How to use the builder I18NBindingBuilder

The builder I18NBindingBuilder let the developer create a StringBinding. The StringBinding can created with a function from type Callable<String> or with a .properties key and optional arguments.

Specification: Usage of I18NBindingBuilder

/**
 * 1) Starts the binding process.
 * 2) Use the given function to create a StringBinding.
 * 3) Completes the binding process and returns the StringBinding.
 */
I18NBindingBuilder.bind()          // 1
       .callable(Callable<String>) // 2
       .build();                   // 3

/**
 * 1) Starts the binding process.
 * 2) Defines the key which value will be bind to the StringBinding.
 * 3) Optional arguments for the value from the given key.
 * 4) Completes the binding process and returns the StringBinding.
 */
I18NBindingBuilder.bind()         // 1
       .key(String)               // 2
       .arguments(Object... args) // 3
       .build();                  // 4

Examples:

@Test
public void lastStepCallable() {
    I18NResourceBundleBuilder.configure()
            .baseBundleName("com.github.naoghuman.lib.i18n.internal.resourcebundle")
            .supportedLocales(Locale.ENGLISH, Locale.GERMAN)
            .defaultLocale(Locale.ENGLISH)
            .actualLocale(Locale.GERMAN)
            .build();

    Optional<StringBinding> result = I18NBindingBuilder.bind()
            .callable(() -> I18NMessageBuilder.message()
                    .key("resourcebundle.title")
                    .build()
            )
            .build();
    assertTrue(result.isPresent());
    assertEquals("RB: Test Titel", result.get().get());

    I18NFacade.getDefault().setActualLocale(Locale.ENGLISH); // Here the magic happen :)
    assertEquals("RB: Test title", result.get().get());
}

@Test
public void lastStepKeyWithoutArguments() {
    I18NResourceBundleBuilder.configure()
            .baseBundleName("com.github.naoghuman.lib.i18n.internal.resourcebundle")
            .supportedLocales(Locale.ENGLISH, Locale.GERMAN)
            .defaultLocale(Locale.ENGLISH)
            .actualLocale(Locale.GERMAN)
            .build();

    Optional<StringBinding> result = I18NBindingBuilder.bind()
            .key("resourcebundle.title")
            .build();
    assertTrue(result.isPresent());
    assertEquals("RB: Test Titel", result.get().get());

    I18NFacade.getDefault().setActualLocale(Locale.ENGLISH); // Here the magic happen :)
    assertEquals("RB: Test title", result.get().get());
}

@Test
public void lastStepKeyWithArguments() {
    I18NResourceBundleBuilder.configure()
            .baseBundleName("com.github.naoghuman.lib.i18n.internal.resourcebundle")
            .supportedLocales(Locale.ENGLISH, Locale.GERMAN)
            .defaultLocale(Locale.ENGLISH)
            .actualLocale(Locale.GERMAN)
            .build();

    Optional<StringBinding> result = I18NBindingBuilder.bind()
            .key("resourcebundle.label.with.parameter")
            .arguments(123)
            .build();
    assertTrue(result.isPresent());
    assertEquals("RB: Text mit Parameter: 123", result.get().get());

    I18NFacade.getDefault().setActualLocale(Locale.ENGLISH); // Here the magic happen :)
    assertEquals("RB: Text with parameter: 123", result.get().get());
}

How to use the builder I18NMessageBuilder

To load a .properties key with optional arguments from the initialized ResourceBundle through the I18NResourceBundleBuilder the developer can use the builder I18NMessageBuilder.

Specification: Usage of I18NMessageBuilder

/**
 * 1) Starts the message process.
 * 2) Defines the key which value will be loaded.
 * 3) Optional arguments for the value from the given key.
 * 4) Completes the message process and returns a String.
 */
I18NMessageBuilder.message()  // 1
        .key(String)          // 2
        .arguments(Object...) // 3
        .build();             // 4

Examples:

@Test
public void lastStepWithoutArguments() {
    I18NResourceBundleBuilder.configure()
            .baseBundleName("com.github.naoghuman.lib.i18n.internal.resourcebundle")
            .supportedLocales(Locale.ENGLISH, Locale.GERMAN)
            .defaultLocale(Locale.ENGLISH)
            .actualLocale(Locale.GERMAN)
            .build();

    String result = I18NMessageBuilder.message()
            .key("resourcebundle.title")
            .build();
    assertEquals("RB: Test Titel", result);

    I18NFacade.getDefault().setActualLocale(Locale.ENGLISH); // Here the magic happen :)
    result = I18NMessageBuilder.message()
            .key("resourcebundle.title")
            .build();
    assertEquals("RB: Test title", result);
}
    
@Test
public void lastStepWithArguments() {
    I18NResourceBundleBuilder.configure()
            .baseBundleName("com.github.naoghuman.lib.i18n.internal.resourcebundle")
            .supportedLocales(Locale.ENGLISH, Locale.GERMAN)
            .defaultLocale(Locale.ENGLISH)
            .actualLocale(Locale.GERMAN)
            .build();

    String result = I18NMessageBuilder.message()
            .key("resourcebundle.label.with.parameter")
            .arguments(2)
            .build();
    assertEquals("RB: Text mit Parameter: 2", result);

    I18NFacade.getDefault().setActualLocale(Locale.ENGLISH); // Here the magic happen :)
    result = I18NMessageBuilder.message()
            .key("resourcebundle.label.with.parameter")
            .arguments(123)
            .build();
    assertEquals("RB: Text with parameter: 123", result);
}

Conventions

In this chapter, the interested developer can find out all about the conventions from the library Lib-I18N:

Convention: 'baseBundleName' from ResourceBundle

If a ResourceBundle with the defined 'baseBundleName' can't be found a spezific MissingResourceException will be thrown.

public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    private ResourceBundle getResourceBundle() {
        ResourceBundle bundle = null;
        try {
            bundle = ResourceBundle.getBundle(this.getBaseBundleName(), this.getActualLocale());
        } catch (MissingResourceException mre) {
            LoggerFacade.getDefault().error(this.getClass(), 
                    String.format("Can't access the ResourceBundle[path=%s, actual-locale=%s]", 
                            this.getBaseBundleName(), this.getActualLocale().getDisplayLanguage()), 
                    mre);
        }
        
        return bundle;
    }
    ...
}

Convention: 'Key not found' in ResourceBundle

If a key can't be found in the defined ResourceBundle then * the String pattern '<key>' will returned and * the following 'warning' message will be logged:
"Can't find key(%s) in resourcebundle. Return: %s"

public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    @Override
    public String getMessage(final String key, final Object... arguments) {
        DefaultI18NValidator.requireNonNullAndNotEmpty(key);
        DefaultI18NValidator.requireNonNullAndNotEmpty(arguments);
        DefaultI18NValidator.requireResourceBundleExist(this.getBaseBundleName(), this.getActualLocale());
        
        final ResourceBundle bundle = getResourceBundle();
        String value = MessageFormat.format(PATTERN_KEY_NAME, key);
        
        if (bundle != null) {
            try {
                value = MessageFormat.format(bundle.getString(key), arguments);
            } catch (MissingResourceException mre) {
                LoggerFacade.getDefault().warn(this.getClass(), 
                        String.format("Can't find key(%s) in resourcebundle. Return: %s", key, value), 
                        mre);
            }
        }
        
        return value;
    }
    ...
}

Convention: Defined supported Locales, default and actual Locale

Supported Locales

public final class I18NResourceBundleBuilder {
    ...
    private static final class I18NResourceBundleBuilderImpl implements
            FirstStep,  ForthStep, LastStep, SecondStep, ThirdStep
    {
        ...
        @Override
        public ThirdStep supportedLocales(final Locale... locales) {
            LoggerFacade.getDefault().debug(this.getClass(), "I18NResourceBundleBuilderImpl.supportedLocales(Locale...)"); // NOI18N
            
            final List<Locale> list = Arrays.asList(locales);
            DefaultI18NValidator.requireNonNullAndNotEmpty(list);
            
            final ObservableList<Locale> observableList = FXCollections.observableArrayList();
            observableList.addAll(list);
            properties.put(ATTR__SUPPORTED_LOCALES, new SimpleObjectProperty(observableList));
            
            return this;
        }

        @Override
        public ThirdStep supportedLocales(final ObservableList<Locale> locales) {
            LoggerFacade.getDefault().debug(this.getClass(), "I18NResourceBundleBuilderImpl.supportedLocales(ObservableList<Locale>)"); // NOI18N
            
            DefaultI18NValidator.requireNonNullAndNotEmpty(locales);
            properties.put(ATTR__SUPPORTED_LOCALES, new SimpleObjectProperty(locales));
            
            return this;
        }
        ...
    }
}
public final class I18NFacade implements I18NBinding, I18NResourceBundle {
    ...
    @Override
    public ObservableList<Locale> getSupportedLocales() {
        return i18NResourceBundle.getSupportedLocales();
    }

    @Override
    public void setSupportedLocales(final ObservableList<Locale> locales) {
        i18NResourceBundle.setSupportedLocales(locales);
    }

    @Override
    public void setSupportedLocales(final Locale... locales) {
        i18NResourceBundle.setSupportedLocales(locales);
    }
    ...
}
public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    @Override
    public ObservableList<Locale> getSupportedLocales() {
        DefaultI18NValidator.requireNonNull(supportedLocales);
        
        return supportedLocales;
    }

    @Override
    public void setSupportedLocales(final ObservableList<Locale> locales) {
        DefaultI18NValidator.requireNonNullAndNotEmpty(locales);
        
        supportedLocales.clear();
        supportedLocales.addAll(locales);
    }

    @Override
    public void setSupportedLocales(final Locale... locales) {
        final List<Locale> list = Arrays.asList(locales);
        DefaultI18NValidator.requireNonNullAndNotEmpty(list);
        
        supportedLocales.clear();
        supportedLocales.addAll(list);
    }
    ...
}

Default Locale

  • If the supported Locales doesn't contained the default Locale then the Locale#ENGLISH instead will be return.
public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    @Override
    public void setDefaultLocale(final Locale locale) {
        DefaultI18NValidator.requireNonNull(locale);
        
        defaultLocale = this.getSupportedLocales().contains(locale) ? locale : Locale.ENGLISH;
    }
    ...
}

Actual Locale

  • If the supported Locales doesn't contained the actual Locale then the default Locale instead will be return.
public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    @Override
    public void setActualLocale(final Locale locale) {
        DefaultI18NValidator.requireNonNull(locale);
        
        actualLocaleProperty.set(this.getSupportedLocales().contains(locale) ? locale : defaultLocale);
    }
    ...
}

Convention: Basic validation

public final class I18NResourceBundleBuilder {
    ...
    private static final class I18NResourceBundleBuilderImpl implements
            FirstStep,  ForthStep, LastStep, SecondStep, ThirdStep
    {
        ...
        @Override
        public SecondStep baseBundleName(final String baseBundleName) {
            LoggerFacade.getDefault().debug(this.getClass(), "I18NResourceBundleBuilderImpl.baseBundleName(String)"); // NOI18N

            DefaultI18NValidator.requireNonNullAndNotEmpty(baseBundleName);
            properties.put(ATTR__BASE_BUNDLE_NAME, new SimpleStringProperty(baseBundleName));

            return this;
        }
        ...
    }
}
public final class DefaultI18NResourceBundle implements I18NResourceBundle {
    ...
    @Override
    public String getBaseBundleName() {
        DefaultI18NValidator.requireNonNullAndNotEmpty(baseBundleName);
        
        return baseBundleName;
    }

    @Override
    public void setBaseBundleName(final String baseBundleName) {
        DefaultI18NValidator.requireNonNullAndNotEmpty(baseBundleName);
        
        this.baseBundleName = baseBundleName;
    }
    ...
}
public final class DefaultI18NBinding implements I18NBinding {
    ...
    @Override
    public StringBinding createStringBinding(final String key, Object... arguments) {
        DefaultI18NValidator.requireNonNullAndNotEmpty(key);
        DefaultI18NValidator.requireNonNullAndNotEmpty(arguments);
        
        return Bindings.createStringBinding(() -> I18NFacade.getDefault().getMessage(key, arguments), I18NFacade.getDefault().actualLocaleProperty());
    }
    ...
}

Features

Main library featureas

In this sub-section all main features from the library 'Lib-I18N' are listed:

  1. The library Lib-I18N allows a developer to bind a key with its associated value of a .properties file to a StringBinding.
  2. With the builder I18NResourceBundleBuilder the developer can configure the ResourceBundle which contains the key - value pairs which will then be bind to a actual Locale.
  3. The builder I18NBindingBuilder let the developer create a StringBinding. The StringBinding can created with a function from type Callable<String> or with a .properties key and optional arguments.
  4. To load a .properties key with optional arguments from the initialized ResourceBundle through the I18NResourceBundleBuilder the developer can use the builder I18NMessageBuilder.

General library features

This sub-section list all general features from the library 'Lib-I18N':

  1. The library Lib-I18N is open source and licensed under General Public License 3.0.
  2. The library is written in Java and JavaFX.
  3. The library is programmed with the IDE NetBeans as a Maven library.
  4. The library can easily integrated into a foreign project over Maven Central.
  5. Due to the connection of the project with Travis CI, a build is automatically executed at each commit.
  6. By integrating various "badges" from "img.shield.io", interested readers can easily find out about the "build" state, the current version and the license used for this library.
  7. All functionalities from the classes in the core and internal packages are tested with Unittests.
  8. Every parameter in all functionalities will be verified against minimal conditions with the internal validator DefaultI18NValidator. For example a String can't be NULL or EMPTY.
  9. The documentation from the library is available with an extended ReadMe and well-described JavaDoc comments.

JavaDoc

The JavaDoc from the library Lib-I18N can be explored here: JavaDoc Lib-I18N

Image: JavaDoc Lib-I18N v0.7.1
Lib-I18N_JavaDoc_v0.7.1_2019-02-10_19-19.png

Download

Current version is 0.7.1. Main points in this release are:

  • Update the section 'Conventions'. Add for every convention an example.
  • Restructure the section 'Features'. Split it into 'generall' and 'main' features.

Maven coordinates
In context from a
Maven project you can use following maven coordinates:

<dependencies>
    <dependency>
        <groupId>com.github.naoghuman</groupId>
        <artifactId>lib-i18n</artifactId>
        <version>0.7.1</version>
    </dependency>

    <!-- optional -->
    <dependency>
        <groupId>com.github.naoghuman</groupId>
        <artifactId>lib-logger</artifactId>
        <version>0.6.0</version>
    </dependency>
</dependencies>

Download:

An overview about all existings releases can be found here:

  • Overview from all releases in Lib-I18N.

Requirements

In the library are following libraries registered as dependencies:

Installation

Install the project in your preferred IDE

Contribution

License

The project Lib-I18n is licensed under General Public License 3.0.

Autor

The project Lib-I18n is maintained by me, Peter Rogge. See Contact.

Contact

You can reach me under peter.rogge@yahoo.de.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.