Implementation of functionality "language-selection" in applications using GSI-Frames

Implementation of internationalization for (GUI-)applications is done with the assistance of the LanguageTranslator. The LanguageTranslator is a Localization-Framework for applications of GSI. The texts are defined as key/value-pairs in special Java classes. All applications using multilanguage texts have to create a Java-class containing the key definitions and the key/value-mapping for the default language. The name of this java class is build as follows:

Default texts: "Ap" + ​applicationterm + "ResourceBundle" (e.g. ApCommonResourceBundle.java). Other Java-files have to be generated for the texts in corresponding languages (i.e. currently in English). The name corresponds to that of the default texts plus the language suffix (e.g. ApCommonResourceBundle_en.java).

A Java class with key/value mappings for texts in default language looks like this:
package de.gsi.cs.co.ap.common.languagetranslator;

public class ApCommonResourceBundle extends AbstractApResourceBundle {

public static final String LANG_TEXT_CONTEXT_TITLE = "contextTitle";

{ addEntry(LANG_TEXT_CONTEXT_TITLE, "Kontext:"); } }

The Java-class has to extend the abstract class "AbstractApResourceBundle" which provides the RESOURCE_MAP for key/value-mapping.

Java classes with key/value mappings for texts in another language have to look like this:

package de.gsi.cs.co.ap.common.languagetranslator;

public class ApDevCtrlResourceBundle _en extends ApDevCtrlResourceBundle { { addEntry(LANG_TEXT_CONTEXT_TITLE, "Context:"); } }

The name of the Java class is built form the basename plus the language code. These Java-files have to be registered by the LanguageTranslator. The LanguageTranslator supports the following language-dependent output of the following formats:
  • getText(String) simple text
  • getText(String, Object...) parametrized texts
  • getObject(String) other formats (i.e. Date. Casting is necessary here)
And also language-independend output of the following formats (should be used for Logstash outputs with Locale.ENGLISH):
  • getText(Locale, String) simple text for the given locale
  • getText(Locale, String, Object...) parametrized texts for the given locale
  • getObject(Locale, String) other formats (i.e. Date. Casting is necessary here) for the given locale

Using LanguageTranslator -API in GUI-applications

  • Always: Load ResourceBundles very early - e.g. in the main method or (for Fx applications) in a main Controller class, e.g.
public static void main(String[] args) { // other stuff in main method like loading default properties

// note: it's not necessary to load each locale, just the default locale

LanguageTranslator.loadResourceBundle(ApDevCtrlResourceBundle.class);

// other stuff in main method }

Swing applications

  • The Swing-specific GSI-Frame provides a drop-down box for selecting a language to present the GUI elements texts and formats correspondingly. Include it in your frame:
GuiManager.initLanguageSelector(frame, true);
  • Implement the viewer as LanguageChangedListener:
public class DevCtrlHeaderPanel extends JPanel implements LanguageChangedListener {
  • Register the viewer in the constructor as listener of LanguageTranslator:
GuiManager.getInstance().addLanguageSelectionListener(this);
  • Language-dependent texts in GUI-frames have to be called like this:
final JLabel lblSelectContext = new JLabel( LanguageTranslator.getText(ApDevCtrlResourceBundle.LANG_TEXT_CONTEXT_TITLE));
  • Language-dependent texts and objects are updated in this method:
@Override public void selectedLanguageChanged(String selectedLanguage) { this.lblSelectContext.setText(LanguageTranslator.getText(ApDevCtrlResourceBundle.LANG_TEXT_CONTEXT_TITLE)); }

JavaFx applications

  • As of 2018/10, there is not yet a common language selector control provided by AP. You can create a temporary one for your applications like this:
ComboBox<Locale> tempLanguageSelector = new ComboBox<Locale>();
tempLanguageSelector.getItems().addAll(LanguageTranslator.LOCALES); 
// update LanguageSelectorImpl from control and vice-versa 
tempLanguageSelector.valueProperty()
                .addListener(obs -> LanguageSelectorImpl.getInstance().setLanguage(tempLanguageSelector.getValue()));
final LanguageChangedListener listener = newLocale -> tempLanguageSelector.setValue(newLocale);
tempLanguageSelector.getProperties().put(listener, null);
LanguageSelectorImpl.getInstance().addLanguageSelectionListener(listener);
  • Bind the texts in your GUI using "LanguageDependentBindings":
someControl.textProperty().bind(LanguageDependentBindings.createLanguageBinding(YourResourceBundle.LANG_TEXT_LANGUAGE_KEY));

Usage for external applications:

The LanguageTranslator -framework can be used by external applications (i.e. no GSI applications) as long as cscoap-common-language-translator is registered as a dependency.

References to registerend LanguageChangedListener

The LanguageTranslator keeps weak references to the registered listeners. That means that a listener that is reference nowhere else except for the LanguageTranslator will be garbage collected. That behaviour prevents memory leaks from UI components that registerend a listener for themselves, but did not remove the listener when the UI component is not used anymore.

However, this also means that the programmer is responsible for making sure that their listeners are not garbage collected while they are still needed. If you use the strategies described above, you should never have problems with listeners being garbage collected to early. If you use different strategies and register listeners, make sure that you keep a strong reference to them that keeps them alive - e.g. by storing them in a field of a long-lived view/controller class, or (in Fx) in the Properties of a node that lives as long as the listener should live with, e.g.:

// use a proper key and store the listener as the value if you ever want to retrieve it

node.getProperties().put(someKey, yourLanguageChangeListener);

// alternatively, just use the listener as the key if you just want to store but never retrieve it

node.getProperties().put(yourLanguageChangeListener, null); 
Topic revision: r18 - 13 Apr 2020, JuttaFitzek
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback