Resourcebundle - Sprache zur Laufzeit aktualisieren?

Ja genau das ist jetzt mein Problem, ich finde kein Ansatz wie er die Änderungen nun übernehmen soll. Ich habe angenommen, dass er nun jegliche Platzhalter, welche vor zB mit den Englischen besetzt waren, durch die Deutschen ersetzt. Hat jemand vllt einen Ansatz wie man das umsetzen kann?
 
Hier mal mein Ansatz, mit dem bin ich eigentlich immer ganz gut gefahren.
Java:
package de.tutorials.forum.hilfe.badabum.resourcebundle.update;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class ComponentsUpdateSample extends JFrame {
	private static final String	COMPONENTS_BUTTONS_DEBUTTON	= "componentsupdatesample.components.buttons.debutton";
	private static final String	COMPONENTS_BUTTONS_ENBUTTON	= "componentsupdatesample.components.buttons.enbutton";
	private static final String	COMPONENTS_LABELS_TESTLABEL	= "componentsupdatesample.components.labels.testlabel";
	private static final String	LANG_BUNDLE_NAME			= "lang";
	private static final long	serialVersionUID			= 8049149370558375561L;

	private JButton				deButton;
	private JButton				enButton;
	private ResourceBundle		langBundle;
	private JLabel				testLabel;

	public static void main(String[] args) {
		new ComponentsUpdateSample();
	}

	public ComponentsUpdateSample() {
		initSettings();
		initComponents();
		initGui();
	}

	private JButton getDeButton() {
		if(deButton == null) {
			deButton = new JButton(
					langBundle.getString(COMPONENTS_BUTTONS_DEBUTTON));
			deButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					langBundle = getLangBundle(Locale.GERMAN);
					updateLangComponents();
				}
			});
		}

		return deButton;
	}

	private JButton getEnButton() {
		if(enButton == null) {
			enButton = new JButton(
					langBundle.getString(COMPONENTS_BUTTONS_ENBUTTON));
			enButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent e) {
					langBundle = getLangBundle(Locale.ENGLISH);
					updateLangComponents();
				}
			});
		}

		return enButton;
	}

	private ResourceBundle getLangBundle(Locale locale) {
		return ResourceBundle.getBundle(
				ResLoader.class.getPackage().getName() + "." + LANG_BUNDLE_NAME,
				locale);
	}

	private JLabel getTestLabel() {
		if(testLabel == null) {
			testLabel = new JLabel(
					langBundle.getString(COMPONENTS_LABELS_TESTLABEL));
		}

		return testLabel;
	}

	private void initComponents() {
		setLayout(new FlowLayout(FlowLayout.LEFT));
		add(getDeButton());
		add(getEnButton());
		add(getTestLabel());
	}

	private void initGui() {
		setSize(500, 500);
		setLocationRelativeTo(null);
		setVisible(true);
	}

	private void initSettings() {
		setTitle(getName());
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		langBundle = getLangBundle(Locale.getDefault());
	}

	private void updateButtons() {
		getDeButton().setText(langBundle.getString(COMPONENTS_BUTTONS_DEBUTTON));
		getEnButton().setText(langBundle.getString(COMPONENTS_BUTTONS_ENBUTTON));
	}

	private void updateLabels() {
		getTestLabel().setText(langBundle.getString(COMPONENTS_LABELS_TESTLABEL));
	}

	private void updateLangComponents() {
		updateButtons();
		updateLabels();
	}
}
Ist an sich nix besonderes und leicht zu verstehen, daher auch keine Kommentare.
Auf ResLoader brauchst du nicht achten. Das ist nur eine Klasse, die ich immer in das resource-Package kloppe, um somit zentral auf die Ressourcen zuzugreifen, da sich sonst je nach Klasse ein anderer Pfad ergibt und das Nachkorrigieren ziemlich nervig sein kann. Kurz gesagt: nicht drauf achten, is nix besonderes.

Und hier meine Property-Files:
lang_de.properties
componentsupdatesample.components.buttons.enbutton=Englisch
componentsupdatesample.components.buttons.debutton=Deutsch
componentsupdatesample.components.labels.testlabel=Das ist ein Test
lang_en.properties
componentsupdatesample.components.buttons.enbutton=English
componentsupdatesample.components.buttons.debutton=German
componentsupdatesample.components.labels.testlabel=This is a test
 
Hi Leute,

ich hab da was für euch, mag sein das es da auch was von Ratiopha*** gibt, aber von der Heuristik ist das ein skalierbarer Ansatz den man beliebig nach eigenen Wünschen verfeinern kann.
Die Idee.
Man hat eine Zentrale an der man Komponenten anmeldet die sich auf Sprachänderung anpassen sollen. Beobachter (Observer) Muster quasi. Ändert man in der Zentrale die Sprache so werden alle angemeldeten Komponenten benachrichtigt.
Java:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JFrame;

/**
 * kleine hilfsklasse könnte man auch wegoptimieren
 * aaaaber pro ResourceBundle kann man verschiedene
 * LocalizableComponent anmelden das müsste man sonst
 * mit maps mit sets oder maps von listen lösen...
 * 
 * ##OBSERVER-PATTERN## - BeobachtbaresObjekt
 */
class HelpBundle {
	private ResourceBundle rBundle;

	private Set<LocalizableComponent> lComponents;

	public HelpBundle(ResourceBundle rBundle) {
		this.rBundle = rBundle;
		this.lComponents = new HashSet<LocalizableComponent>();
	}

	public void addLocalizableComponent(LocalizableComponent lComponent) {
		lComponents.add(lComponent);
	}

	ResourceBundle getResourceBundle() {
		return rBundle;
	}

	/**
	 * bescheid geben an alle angemeldeten beobachter
	 * ##OBSERVER-PATTERN## - Benachrichtigungen Abfeuern
	 */
	void notifyComponents(ResourceBundleHelper rbHelper) {
		for (LocalizableComponent component : lComponents)
			component.localeChanged(rbHelper, rBundle);
	}

	void setResourceBundle(ResourceBundle rBundle) {
		this.rBundle = rBundle;
	}
}

/**
 * Beobachter Interface
 * 
 * ##OBSERVER-PATTERN## - Beobachter
 */
interface LocalizableComponent {
	/**
	 * wird aufgerufen wenn sprache sich ändert
	 * ##OBSERVER-PATTERN## - Benachrichtigungs Methode
	 */
	public void localeChanged(ResourceBundleHelper rbHelper,
			ResourceBundle rBundle);
}

/**
 * kontroller klasse bei der mehrere ResourceBundles auf einmal geändert werden
 * können.
 * 
 * ##OBSERVER-PATTERN## - Beobachtbares Objekt
 * 
 */
class ResourceBundleHelper {

	private static Locale defaultLocale = Locale.getDefault();

	private Map<String, HelpBundle> bundles;
	private Locale locale;

	private static final ResourceBundleHelper instance;

	static {
		instance = new ResourceBundleHelper(defaultLocale);
	}

	public static ResourceBundleHelper getInstance() {
		return instance;
	}

	private ResourceBundleHelper(Locale locale) {
		bundles = new HashMap<String, HelpBundle>();
		this.locale = locale;
	}

	public void addLocalizableComponent(String bundleName,
			LocalizableComponent lComponent) {
		if (!bundles.containsKey(bundleName))
			addRes(bundleName, getLocale());
		HelpBundle hBundle = bundles.get(bundleName);
		hBundle.addLocalizableComponent(lComponent);
	}

	private void addRes(String baseName, Locale locale) {
		ResourceBundle rBundle = ResourceBundle.getBundle(baseName, locale);
		bundles.put(baseName, new HelpBundle(rBundle));
	}

	public Locale getLocale() {
		return locale;
	}

	public ResourceBundle getResourceBundle(String bundleName) {
		return bundles.get(bundleName).getResourceBundle();
	}

	private void notifyListeners() {
		for (String baseName : bundles.keySet()) {
			HelpBundle hBundle = bundles.get(baseName);
			hBundle.notifyComponents(this);
		}

	}

	public void setLocale(Locale locale) {
		if (!this.locale.equals(locale)) { // just a little performance tweak
			this.locale = locale;
			for (String bundleName : bundles.keySet()) {
				HelpBundle hBundle = bundles.get(bundleName);
				ResourceBundle rBundle = ResourceBundle.getBundle(bundleName,
						locale);
				hBundle.setResourceBundle(rBundle);
			}
			notifyListeners();
		}
	}
}
/**
 * TEST CLASS
 * 
 * ##OBSERVER-PATTERN## - Konkreter Beobachter
 *
 */
public class ResTest extends JFrame
		implements LocalizableComponent, ActionListener {
	private static final String LOCALIZED_FRAME_TITLE = "Frame.title";
	private static final String LOCALIZED_LANG_DE = "lang.de";
	private static final String LOCALIZED_LANG_EN = "lang.en";
	private static final String RESOURCE_BUNDLE_LANG = "lang";

	public static void main(String[] args) {
		new ResTest().setVisible(true);
	}

	private JButton deButton = new JButton();

	private JButton enButton = new JButton();

	public ResTest() {
		super();
		setLayout(new GridLayout());
		setDefaultCloseOperation(EXIT_ON_CLOSE);

		add(deButton);
		add(enButton);
		deButton.addActionListener(this);
		enButton.addActionListener(this);

		initLocalizedComponents();
	}

	public void actionPerformed(ActionEvent e) {
		ResourceBundleHelper rbh = ResourceBundleHelper.getInstance();
		Locale locale = rbh.getLocale();
		if (e.getSource().equals(enButton))
			locale = Locale.ENGLISH;
		if (e.getSource().equals(deButton))
			locale = Locale.GERMAN;
		rbh.setLocale(locale);
	}

	private void initLocalizedComponents() {
		ResourceBundleHelper rbh = ResourceBundleHelper.getInstance();
		/**
		 * ##OSERVER-PATTERN## - Konkreten Beobachter registrieren 
		 * in diesem Fall das Fenster nur einmal.
		 * Statt Fenster und je 2 Knöpfe.
		 */
		rbh.addLocalizableComponent(RESOURCE_BUNDLE_LANG, this);
		localeChanged(rbh, rbh.getResourceBundle(RESOURCE_BUNDLE_LANG));
	}

	/**
	 * ##OSERVER-PATTERN## - Konkrete Benachrichtigung
	 */
	public void localeChanged(ResourceBundleHelper rbHelper,
			ResourceBundle rBundle) {

		setTitle(rBundle.getString(LOCALIZED_FRAME_TITLE));
		deButton.setText(rBundle.getString(LOCALIZED_LANG_DE));
		enButton.setText(rBundle.getString(LOCALIZED_LANG_EN));
	}
}

Sollte lauffähig sein! Bei mir rennt das Moped zumindest.

Interessante Methoden sind ResTest::localeChanged() die vom ResourceBundleHelper automatisch aufgerufen wird wenn die Sprachen sich ändert & ResTest::initLocalizedComponents() mit der man sich am RescourceBundleHelper anmeldet.

Hoffe das hilft. ;)

Greez isaias
 
Zuletzt bearbeitet:
Zurück