From: Mathieu Baudier Date: Tue, 13 Nov 2012 14:18:53 +0000 (+0000) Subject: Internationalization support X-Git-Tag: argeo-commons-2.1.30~757 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=00474cf92c05359177aba1768bd2ef95a310afaf;p=lgpl%2Fargeo-commons.git Internationalization support git-svn-id: https://svn.argeo.org/commons/trunk@5789 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/base/runtime/org.argeo.eclipse.ui.rap/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java b/base/runtime/org.argeo.eclipse.ui.rap/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java new file mode 100644 index 000000000..3bab4d999 --- /dev/null +++ b/base/runtime/org.argeo.eclipse.ui.rap/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java @@ -0,0 +1,33 @@ +package org.argeo.eclipse.ui.specific; + +import org.eclipse.osgi.util.NLS; +import org.eclipse.rwt.RWT; + +/** NLS attached to a given thread */ +public class ThreadNLS extends InheritableThreadLocal { + public final static String DEFAULT_BUNDLE_LOCATION = "/properties/plugin"; + + private final String bundleLocation; + + private Class type; + private Boolean utf8 = false; + + public ThreadNLS(String bundleLocation, Class type, Boolean utf8) { + this.bundleLocation = bundleLocation; + this.type = type; + this.utf8 = utf8; + } + + public ThreadNLS(Class type) { + this(DEFAULT_BUNDLE_LOCATION, type, false); + } + + @SuppressWarnings("unchecked") + @Override + protected T initialValue() { + if (utf8) + return (T) RWT.NLS.getUTF8Encoded(bundleLocation, type); + else + return (T) RWT.NLS.getISO8859_1Encoded(bundleLocation, type); + } +} diff --git a/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/DefaultNLS.java b/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/DefaultNLS.java new file mode 100644 index 000000000..e49ddb3e6 --- /dev/null +++ b/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/DefaultNLS.java @@ -0,0 +1,16 @@ +package org.argeo.eclipse.ui.specific; + +import org.eclipse.osgi.util.NLS; + +/** RCP specific {@link NLS} to be extended */ +public class DefaultNLS extends NLS { + public final static String DEFAULT_BUNDLE_LOCATION = "/properties/plugin"; + + public DefaultNLS() { + this(DEFAULT_BUNDLE_LOCATION); + } + + public DefaultNLS(String bundleName) { + NLS.initializeMessages(bundleName, getClass()); + } +} diff --git a/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java b/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java new file mode 100644 index 000000000..8fd1d7e39 --- /dev/null +++ b/base/runtime/org.argeo.eclipse.ui.rcp/src/main/java/org/argeo/eclipse/ui/specific/ThreadNLS.java @@ -0,0 +1,74 @@ +package org.argeo.eclipse.ui.specific; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.argeo.util.LocaleUtils; +import org.eclipse.osgi.util.NLS; + +/** NLS attached to a given thread */ +public class ThreadNLS extends InheritableThreadLocal { + public final static String DEFAULT_BUNDLE_LOCATION = "/properties/plugin"; + + private final String bundleLocation; + + private Class type; + private Boolean utf8 = false; + + public ThreadNLS(String bundleLocation, Class type, Boolean utf8) { + this.bundleLocation = bundleLocation; + this.type = type; + this.utf8 = utf8; + } + + public ThreadNLS(Class type) { + this(DEFAULT_BUNDLE_LOCATION, type, false); + } + + @Override + protected T initialValue() { + ResourceBundle bundle = ResourceBundle.getBundle(bundleLocation, + LocaleUtils.threadLocale.get(), type.getClassLoader()); + T result; + try { + NLS.initializeMessages(bundleLocation, type); + Constructor constructor = type.getConstructor(); + constructor.setAccessible(true); + result = constructor.newInstance(); + final Field[] fieldArray = type.getDeclaredFields(); + for (int i = 0; i < fieldArray.length; i++) { + int modifiers = fieldArray[i].getModifiers(); + if (String.class.isAssignableFrom(fieldArray[i].getType()) + && Modifier.isPublic(modifiers) + && !Modifier.isStatic(modifiers)) { + try { + String value = bundle + .getString(fieldArray[i].getName()); + byte[] bytes = value.getBytes(); + + String forcedValue; + if (utf8) + forcedValue = new String(bytes, "UTF8"); + else + forcedValue = value; + if (value != null) { + fieldArray[i].setAccessible(true); + fieldArray[i].set(result, forcedValue); + } + } catch (final MissingResourceException mre) { + fieldArray[i].setAccessible(true); + fieldArray[i].set(result, ""); + mre.printStackTrace(); + } + } + } + return result; + } catch (final Exception ex) { + throw new IllegalStateException(ex.getMessage()); + } + } + +} diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleCallback.java b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleCallback.java new file mode 100644 index 000000000..2d3d9fc1a --- /dev/null +++ b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleCallback.java @@ -0,0 +1,106 @@ +package org.argeo.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import javax.security.auth.callback.Callback; + +/** Choose in a list of locales */ +public class LocaleCallback implements Callback { + private List availableLocales = new ArrayList(); + + private Integer selectedIndex = null; + private Integer defaultIndex = null; + private String prompt = "Language"; + + public LocaleCallback(Integer defaultIndex, List availableLocales) { + this.availableLocales = Collections + .unmodifiableList(new ArrayList(availableLocales)); + this.defaultIndex = defaultIndex; + this.selectedIndex = defaultIndex; + } + + /** + * Convenience constructor based on a comma separated list of iso codes (en, + * en_US, fr_CA, etc.). Default selection is default locale. + */ + public LocaleCallback(String locales) { + if (locales == null || locales.trim().equals("")) + return; + String[] codes = locales.split(","); + for (int i = 0; i < codes.length; i++) { + String code = codes[i]; + // variant not supported + int indexUnd = code.indexOf("_"); + Locale locale; + if (indexUnd > 0) { + String language = code.substring(0, indexUnd); + String country = code.substring(indexUnd + 1); + locale = new Locale(language, country); + } else { + locale = new Locale(code); + } + availableLocales.add(locale); + if (locale.equals(Locale.getDefault())) + defaultIndex = i; + } + + if (defaultIndex == null) + defaultIndex = 0; + + this.selectedIndex = defaultIndex; + } + + public String[] getSupportedLocalesLabels() { + String[] labels = new String[availableLocales.size()]; + for (int i = 0; i < availableLocales.size(); i++) { + Locale locale = availableLocales.get(i); + if (locale.getCountry().equals("")) + labels[i] = locale.getDisplayLanguage(locale) + " [" + + locale.getLanguage() + "]"; + else + labels[i] = locale.getDisplayLanguage(locale) + " (" + + locale.getDisplayCountry(locale) + ") [" + + locale.getLanguage() + "_" + locale.getCountry() + + "]"; + + } + return labels; + } + + public Locale getSelectedLocale() { + return availableLocales.get(selectedIndex); + } + + public void setSelectedIndex(Integer selectedIndex) { + this.selectedIndex = selectedIndex; + } + + public Integer getDefaultIndex() { + return defaultIndex; + } + + public String getPrompt() { + // TODO localize it? + return prompt; + } + + public void setPrompt(String prompt) { + this.prompt = prompt; + } + + public List getAvailableLocales() { + return availableLocales; + } + + public static void main(String[] args) { + for (String isoL : Locale.getISOLanguages()) { + Locale locale = new Locale(isoL); + System.out.println(isoL + "\t" + locale.getDisplayLanguage() + "\t" + + locale.getDisplayLanguage(locale)); + } + } + +} diff --git a/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleUtils.java b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleUtils.java new file mode 100644 index 000000000..d23f85096 --- /dev/null +++ b/base/runtime/org.argeo.util/src/main/java/org/argeo/util/LocaleUtils.java @@ -0,0 +1,27 @@ +package org.argeo.util; + +import java.util.Locale; + +import org.argeo.ArgeoException; + +/** Utilities around internationalization. */ +public class LocaleUtils { + /** + * The locale of the current thread and its children. Allows to deal with + * internationalisation as a cross cutting aspect. Never null. + */ + public final static InheritableThreadLocal threadLocale = new InheritableThreadLocal() { + @Override + protected Locale initialValue() { + return Locale.getDefault(); + } + + @Override + public void set(Locale value) { + if (value == null) + throw new ArgeoException("Thread local cannot be null."); + super.set(value); + } + + }; +} diff --git a/demo/argeo_node_rcp.properties b/demo/argeo_node_rcp.properties index e240a9913..fdc3eb110 100644 --- a/demo/argeo_node_rcp.properties +++ b/demo/argeo_node_rcp.properties @@ -9,3 +9,5 @@ org.argeo.jackrabbit.webapp,\ log4j.configuration=file:../../log4j.properties org.argeo.security.ui.initialPerspective=org.argeo.jcr.ui.explorer.perspective eclipse.application=org.argeo.security.ui.rcp.secureUi + +user.language=fr diff --git a/demo/argeo_node_web.properties b/demo/argeo_node_web.properties index 69a4fddba..b922bcc14 100644 --- a/demo/argeo_node_web.properties +++ b/demo/argeo_node_web.properties @@ -19,6 +19,9 @@ org.argeo.security.ui.initialPerspective=org.argeo.jcr.ui.explorer.perspective log4j.configuration=file:../../log4j.properties +argeo.i18n.availableLocales=en,fr,de,ru,ar +eclipse.registry.MultiLanguage=true + # Tomcat #argeo.server.port.http=7070 #argeo.server.port.https=7443 diff --git a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml index ed0a78860..7a3e8025a 100644 --- a/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml +++ b/security/plugins/org.argeo.security.equinox/META-INF/spring/loginModules.xml @@ -15,6 +15,7 @@ +