Author: jverhaeg(a)redhat.com
Date: 2008-04-23 20:45:28 -0400 (Wed, 23 Apr 2008)
New Revision: 105
Added:
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/CommonI18nTest.java
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_en.properties
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_fr.properties
Removed:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n.properties
Modified:
trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
Log:
DNA-27: Re-designed I18n to store text and instance-specific problems within instances.
Corrected some synchronization- and exception-related bugs. Changed terminology related
to localization. Supplied many more tests, including for other locales.
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-04-22
20:42:49 UTC (rev 104)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/CommonI18n.java 2008-04-24
00:45:28 UTC (rev 105)
@@ -21,6 +21,8 @@
*/
package org.jboss.dna.common;
+import java.util.Locale;
+import java.util.Set;
import org.jboss.dna.common.i18n.I18n;
/**
@@ -29,17 +31,18 @@
*/
public final class CommonI18n {
- static {
- try {
- I18n.initialize(CommonI18n.class);
- } catch (final Exception err) {
- System.err.println(err);
- }
- }
-
// Make sure the following I18n.java-related fields are defined before all other
fields to ensure a valid error message is
// produced in the event of a missing/duplicate/unused property
+ /**
+ * Parameters:
+ * <ol>
+ * <li>{@link I18n#id() ID}</li>
+ * <li>Number of supplied arguments</li>
+ * <li>Localized text before parameter substitution</li>
+ * <li>Localized text after parameter substitution</li>
+ * </ol>
+ */
public static I18n i18nArgumentsMismatchedParameter;
public static I18n i18nArgumentMismatchedParameters;
public static I18n i18nArgumentsMismatchedParameters;
@@ -52,7 +55,16 @@
public static I18n i18nFieldInvalidType;
public static I18n i18nFieldNotPublic;
public static I18n i18nFieldNotStatic;
- public static I18n i18nPropertiesFileNotFound;
+ public static I18n i18nLocalizationFileNotFound;
+ public static I18n i18nLocalizationProblems;
+
+ /**
+ * Parameters:
+ * <ol>
+ * <li>{@link I18n#id() Property}</li>
+ * <li>Localization file URL</li>
+ * </ol>
+ */
public static I18n i18nPropertyDuplicate;
public static I18n i18nPropertyMissing;
public static I18n i18nPropertyUnused;
@@ -90,4 +102,24 @@
public static I18n pathIsNotAbsolute;
public static I18n pathIsNotRelative;
public static I18n pathCannotBeNormalized;
+
+ static {
+ try {
+ I18n.initialize(CommonI18n.class);
+ } catch (final Exception err) {
+ System.err.println(err);
+ }
+ }
+
+ public static Set<Locale> getLocalizationProblemLocales() {
+ return I18n.getLocalizationProblemLocales(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems() {
+ return I18n.getLocalizationProblems(CommonI18n.class);
+ }
+
+ public static Set<String> getLocalizationProblems( Locale locale ) {
+ return I18n.getLocalizationProblems(CommonI18n.class, locale);
+ }
}
Modified: trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java
===================================================================
--- trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-22 20:42:49
UTC (rev 104)
+++ trunk/dna-common/src/main/java/org/jboss/dna/common/i18n/I18n.java 2008-04-24 00:45:28
UTC (rev 105)
@@ -27,21 +27,22 @@
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
+import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;
import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.jboss.dna.common.util.ArgCheck;
import org.jboss.dna.common.util.ClassUtil;
-import org.jboss.dna.common.util.HashCode;
/**
* Manages the initialization of internationalization (i18n) files, substitution of
values within i18n message placeholders, and
@@ -56,37 +57,68 @@
private static final Pattern PARAMETER_COUNT_PATTERN =
Pattern.compile("\\{(\\d+)\\}");
private static final Object[] EMPTY_ARGUMENTS = new Object[] {};
private static final LocalizationRepository DEFAULT_LOCALIZATION_REPOSITORY = new
ClasspathLocalizationRepository();
- private static final ConcurrentMap<Localization, Map<String, String>>
LOCALIZATION_2_ID_2_ERROR_MAP = new ConcurrentHashMap<Localization, Map<String,
String>>();
- private static final ConcurrentMap<Localization, Map<String, String>>
LOCALIZATION_2_ID_2_TEXT_MAP = new ConcurrentHashMap<Localization, Map<String,
String>>();
+ /**
+ * The first level of this map indicates whether an i18n class has been localized to a
particular locale. The second level
+ * contains any problems encountered during localization.
+ */
+ static final ConcurrentMap<Locale, Map<Class, Set<String>>>
LOCALE_TO_CLASS_TO_PROBLEMS_MAP = new ConcurrentHashMap<Locale, Map<Class,
Set<String>>>();
+
private static LocalizationRepository localizationRepository =
DEFAULT_LOCALIZATION_REPOSITORY;
/**
- * @param i18nClass An internalization class for which errors should be returned.
- * @return The errors encountered while initializing the specified internationalization
class for the default locale mapped to
- * the applicable internalization IDs; never <code>null</code>.
+ * Note, calling this method will <em>not</em> trigger localization of the
supplied internationalization class.
+ *
+ * @param i18nClass The internalization class for which localization problem locales
should be returned.
+ * @return The locales for which localization problems were encountered while localizing
the supplied internationalization
+ * class; never <code>null</code>.
*/
- public static Map<String, String> getErrorsForDefaultLocale( Class i18nClass ) {
- return getErrorsForLocale(i18nClass, null);
+ public static Set<Locale> getLocalizationProblemLocales( Class i18nClass ) {
+ ArgCheck.isNotNull(i18nClass, "i18nClass");
+ Set<Locale> locales = new
HashSet<Locale>(LOCALE_TO_CLASS_TO_PROBLEMS_MAP.size());
+ for (Entry<Locale, Map<Class, Set<String>>> localeEntry :
LOCALE_TO_CLASS_TO_PROBLEMS_MAP.entrySet()) {
+ for (Entry<Class, Set<String>> classEntry :
localeEntry.getValue().entrySet()) {
+ if (!classEntry.getValue().isEmpty()) {
+ locales.add(localeEntry.getKey());
+ break;
+ }
+ }
+ }
+ return locales;
}
/**
- * @param i18nClass An internalization class for which errors should be returned.
- * @param locale The locale for which errors should be returned. If
<code>null</code>, errors for the the default locale
- * will be returned.
- * @return The errors encountered while initializing the specified internationalization
class for the specified locale mapped
- * to the applicable internalization IDs; never <code>null</code>.
+ * Note, calling this method will <em>not</em> trigger localization of the
supplied internationalization class.
+ *
+ * @param i18nClass The internalization class for which localization problems should be
returned.
+ * @return The localization problems encountered while localizing the supplied
internationalization class to the default
+ * locale; never <code>null</code>.
*/
- public static Map<String, String> getErrorsForLocale( Class i18nClass,
- Locale locale ) {
+ public static Set<String> getLocalizationProblems( Class i18nClass ) {
+ return getLocalizationProblems(i18nClass, null);
+ }
+
+ /**
+ * Note, calling this method will <em>not</em> trigger localization of the
supplied internationalization class.
+ *
+ * @param i18nClass The internalization class for which localization problems should be
returned.
+ * @param locale The locale for which localization problems should be returned. If
<code>null</code>, the default locale
+ * will be used.
+ * @return The localization problems encountered while localizing the supplied
internationalization class to the supplied
+ * locale; never <code>null</code>.
+ */
+ public static Set<String> getLocalizationProblems( Class i18nClass,
+ Locale locale ) {
ArgCheck.isNotNull(i18nClass, "i18nClass");
- Map<String, String> errors = LOCALIZATION_2_ID_2_ERROR_MAP.get(new Localization(
- locale
== null ? Locale.getDefault() : locale,
-
i18nClass));
- if (errors == null) {
- errors = Collections.emptyMap();
+ Map<Class, Set<String>> classToProblemsMap =
LOCALE_TO_CLASS_TO_PROBLEMS_MAP.get(locale == null ? Locale.getDefault() : locale);
+ if (classToProblemsMap == null) {
+ return Collections.emptySet();
}
- return errors;
+ Set<String> problems = classToProblemsMap.get(i18nClass);
+ if (problems == null) {
+ return Collections.emptySet();
+ }
+ return problems;
}
/**
@@ -100,18 +132,19 @@
}
/**
- * Set the repository of localized messages. If null, a {@link
ClasspathLocalizationRepository} instance that uses this class
- * loader will be used.
+ * Set the repository of localized messages. If <code>null</code>, a {@link
ClasspathLocalizationRepository} instance that
+ * uses this class loader will be used.
*
- * @param localizationRepository the localization repository to use; may be null if the
default repository should be used.
+ * @param localizationRepository the localization repository to use; may be
<code>null</code> if the default repository
+ * should be used.
*/
public static void setLocalizationRepository( LocalizationRepository
localizationRepository ) {
I18n.localizationRepository = localizationRepository != null ? localizationRepository :
DEFAULT_LOCALIZATION_REPOSITORY;
}
/**
- * Initializes the internationalization fields declared on the specified class.
Internationalization fields must be public,
- * static, not final, and of type <code>I18n</code>. The specified class
must not be an interface (of course), but has no
+ * Initializes the internationalization fields declared on the supplied class.
Internationalization fields must be public,
+ * static, not final, and of type <code>I18n</code>. The supplied class must
not be an interface (of course), but has no
* restrictions as to what class it may extend or what interfaces it must implement.
*
* @param i18nClass A class declaring one or more public, static, non-final fields of
type <code>I18n</code>.
@@ -122,82 +155,98 @@
throw new
IllegalArgumentException(CommonI18n.i18nClassInterface.text(i18nClass.getName()));
}
- // Find all public static non-final String fields in the specified class and
instantiate an I18n object for each.
- try {
- for (Field fld : i18nClass.getDeclaredFields()) {
+ synchronized (i18nClass) {
+ // Find all public static non-final String fields in the supplied class and
instantiate an I18n object for each.
+ try {
+ for (Field fld : i18nClass.getDeclaredFields()) {
- // Ensure field is of type I18n
- if (fld.getType() == I18n.class) {
+ // Ensure field is of type I18n
+ if (fld.getType() == I18n.class) {
- // Ensure field is not final
- if ((fld.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
- throw new SystemFailureException(CommonI18n.i18nFieldFinal.text(fld.getName(),
i18nClass));
- }
+ // Ensure field is public
+ if ((fld.getModifiers() & Modifier.PUBLIC) != Modifier.PUBLIC) {
+ throw new SystemFailureException(CommonI18n.i18nFieldNotPublic.text(fld.getName(),
i18nClass));
+ }
- // Ensure field is public
- if ((fld.getModifiers() & Modifier.PUBLIC) != Modifier.PUBLIC) {
- throw new SystemFailureException(CommonI18n.i18nFieldNotPublic.text(fld.getName(),
i18nClass));
- }
+ // Ensure field is static
+ if ((fld.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
+ throw new SystemFailureException(CommonI18n.i18nFieldNotStatic.text(fld.getName(),
i18nClass));
+ }
- // Ensure field is static
- if ((fld.getModifiers() & Modifier.STATIC) != Modifier.STATIC) {
- throw new SystemFailureException(CommonI18n.i18nFieldNotStatic.text(fld.getName(),
i18nClass));
- }
+ // Ensure field is not final
+ if ((fld.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
+ throw new SystemFailureException(CommonI18n.i18nFieldFinal.text(fld.getName(),
i18nClass));
+ }
- // Ensure we can access field even if it's in a private class
- ClassUtil.makeAccessible(fld);
+ // Ensure we can access field even if it's in a private class
+ ClassUtil.makeAccessible(fld);
- // Initialize field. Do this every time the class is initialized (or
re-initialized)
- fld.set(null, new I18n(fld.getName(), i18nClass));
+ // Initialize field. Do this every time the class is initialized (or
re-initialized)
+ fld.set(null, new I18n(fld.getName(), i18nClass));
+ }
}
+
+ // Remove all entries for the supplied i18n class to indicate it has not been
localized.
+ for (Entry<Locale, Map<Class, Set<String>>> entry :
LOCALE_TO_CLASS_TO_PROBLEMS_MAP.entrySet()) {
+ entry.getValue().remove(i18nClass);
+ }
+ } catch (IllegalAccessException err) {
+ // If this happens, it will happen with the first field visited in the above loop
+ throw new IllegalArgumentException(CommonI18n.i18nClassNotPublic.text(i18nClass));
}
- } catch (IllegalAccessException err) {
- throw new
IllegalArgumentException(CommonI18n.i18nClassNotPublic.text(i18nClass.getName()));
}
}
/**
- * Synchronized on the locale being loaded (this blocks loading all other locales, but
not reads for existing locales)
+ * Synchronized on the supplied internalization class.
*
- * @param i18nClass The internalization class being initialized
- * @param localization
- * @return
+ * @param i18nClass The internalization class being localized
+ * @param locale The locale to which the supplied internationalization class should be
localized.
*/
- private synchronized static Map<String, String> initializeIdToTextMap( final
Localization localization ) {
- Map<String, String> id2TextMap = new HashMap<String, String>();
-
- // Put in the new map and see if there's already one there ...
- Map<String, String> existingId2TextMap =
LOCALIZATION_2_ID_2_TEXT_MAP.putIfAbsent(localization, id2TextMap);
- // If there is already an existing map, then someone beat us to the punch and
there's nothing to do ...
- if (existingId2TextMap != null) {
- return existingId2TextMap;
+ private static void localize( final Class i18nClass,
+ final Locale locale ) {
+ assert i18nClass != null;
+ assert locale != null;
+ // Create a class-to-problem map for this locale if one doesn't exist, else get the
existing one.
+ Map<Class, Set<String>> classToProblemsMap = new
ConcurrentHashMap<Class, Set<String>>();
+ Map<Class, Set<String>> existingClassToProblemsMap =
LOCALE_TO_CLASS_TO_PROBLEMS_MAP.putIfAbsent(locale,
+
classToProblemsMap);
+ if (existingClassToProblemsMap != null) {
+ classToProblemsMap = existingClassToProblemsMap;
}
- // We're the first to put in the map for this locale, so populate the one we
created...
-
- // Get the URL to the localization properties file ...
- final LocalizationRepository repos = getLocalizationRepository();
- final String bundleName = localization.i18nClass.getName();
- URL url = null;
- Locale locale = new Locale(localization.language, localization.country,
localization.variant);
- url = repos.getLocalizationBundle(bundleName, locale);
-
- // Try the default locale (if it is different than the supplied locale) ...
- if (url == null) {
- // Nothing was found, so try the default locale
- Locale defaultLocale = Locale.getDefault();
- if (!defaultLocale.equals(locale)) {
- url = repos.getLocalizationBundle(bundleName, defaultLocale);
+ // Check if already localized outside of synchronization block for 99% use-case
+ if (classToProblemsMap.get(i18nClass) != null) {
+ return;
+ }
+ synchronized (i18nClass) {
+ // Return if the supplied i18n class has already been localized to the supplied
locale, despite the check outside of
+ // the synchronization block (1% use-case), else create a class-to-problems map for
the class.
+ Set<String> problems = classToProblemsMap.get(i18nClass);
+ if (problems == null) {
+ problems = new CopyOnWriteArraySet<String>();
+ classToProblemsMap.put(i18nClass, problems);
+ } else {
+ return;
}
- }
-
- String bundleMsg = null;
- if (url == null) {
- // Record no variant of the i18n properties file for the specified class found
- bundleMsg = CommonI18n.i18nPropertiesFileNotFound.text(bundleName);
- } else {
+ // Get the URL to the localization properties file ...
+ final LocalizationRepository repos = getLocalizationRepository();
+ final String localizationBaseName = i18nClass.getName();
+ URL url = repos.getLocalizationBundle(localizationBaseName, locale);
+ if (url == null) {
+ // Nothing was found, so try the default locale
+ Locale defaultLocale = Locale.getDefault();
+ if (!defaultLocale.equals(locale)) {
+ url = repos.getLocalizationBundle(localizationBaseName, defaultLocale);
+ }
+ // Return if no applicable localization file could be found
+ if (url == null) {
+ problems.add(CommonI18n.i18nLocalizationFileNotFound.text(localizationBaseName));
+ return;
+ }
+ }
// Initialize i18n map
- final Map<String, String> finalMap = id2TextMap;
final URL finalUrl = url;
+ final Set<String> finalProblems = problems;
Properties props = new Properties() {
@Override
@@ -207,23 +256,28 @@
String text = (String)value;
try {
- Field fld = localization.i18nClass.getDeclaredField(id);
+ Field fld = i18nClass.getDeclaredField(id);
if (fld.getType() != I18n.class) {
// Invalid field type
- mapErrorMessage(localization, id, CommonI18n.i18nFieldInvalidType.text(id,
- finalUrl,
-
getClass().getName()));
+ finalProblems.add(CommonI18n.i18nFieldInvalidType.text(id, finalUrl,
getClass().getName()));
+ } else {
+ I18n i18n = (I18n)fld.get(null);
+ if (i18n.localeToTextMap.putIfAbsent(locale, text) != null) {
+ // Duplicate id encountered
+ String prevProblem = i18n.localeToProblemMap.putIfAbsent(locale,
+
CommonI18n.i18nPropertyDuplicate.text(id,
+
finalUrl));
+ assert prevProblem == null;
+ }
}
} catch (NoSuchFieldException err) {
// No corresponding field exists
- mapErrorMessage(localization, id, CommonI18n.i18nPropertyUnused.text(id,
finalUrl));
+ finalProblems.add(CommonI18n.i18nPropertyUnused.text(id, finalUrl));
+ } catch (IllegalAccessException notPossible) {
+ // Would have already occurred in initialize method, but allowing for the
impossible...
+ finalProblems.add(notPossible.getMessage());
}
- if (finalMap.put(id, text) != null) {
- // Duplicate id encountered
- mapErrorMessage(localization, id, CommonI18n.i18nPropertyDuplicate.text(id,
finalUrl));
- }
-
return null;
}
};
@@ -232,38 +286,29 @@
InputStream propStream = url.openStream();
try {
props.load(propStream);
+ // Check for uninitialized fields
+ for (Field fld : i18nClass.getDeclaredFields()) {
+ if (fld.getType() == I18n.class) {
+ try {
+ I18n i18n = (I18n)fld.get(null);
+ if (i18n.localeToTextMap.get(locale) == null) {
+ i18n.localeToProblemMap.put(locale,
CommonI18n.i18nPropertyMissing.text(fld.getName(), url));
+ }
+ } catch (IllegalAccessException notPossible) {
+ // Would have already occurred in initialize method, but allowing for the
impossible...
+ finalProblems.add(notPossible.getMessage());
+ }
+ }
+ }
} finally {
propStream.close();
}
} catch (IOException err) {
- bundleMsg = err.getMessage();
+ finalProblems.add(err.getMessage());
}
}
-
- // Check for uninitialized fields
- for (Field fld : localization.i18nClass.getDeclaredFields()) {
- if (fld.getType() == I18n.class && id2TextMap.get(fld.getName()) == null) {
- mapErrorMessage(localization,
- fld.getName(),
- bundleMsg == null ?
CommonI18n.i18nPropertyMissing.text(fld.getName(), url) : bundleMsg);
- }
- }
-
- return id2TextMap;
}
- static void mapErrorMessage( Localization localization,
- String id,
- String message ) {
- Map<String, String> id2ErrorMap = new ConcurrentHashMap<String, String>();
- Map<String, String> existingId2ErrorMap =
LOCALIZATION_2_ID_2_ERROR_MAP.putIfAbsent(localization, id2ErrorMap);
- if (existingId2ErrorMap != null) {
- id2ErrorMap = existingId2ErrorMap;
- }
- message = id2ErrorMap.put(id, message);
- assert message == null;
- }
-
/**
* Substitute the arguments into the message, ensuring that the number of arguments
matches the number of parameters in the
* text.
@@ -299,25 +344,32 @@
}
}
if (err || argCount < arguments.length) {
- I18n msg = null;
+ String msg = null;
if (id != null) {
if (arguments.length == 1) {
- msg = CommonI18n.i18nArgumentMismatchedParameters;
+ msg = CommonI18n.i18nArgumentMismatchedParameters.text(id, argCount, text,
newText.toString());
} else if (argCount == 1) {
- msg = CommonI18n.i18nArgumentsMismatchedParameter;
+ msg = CommonI18n.i18nArgumentsMismatchedParameter.text(arguments.length, id, text,
newText.toString());
} else {
- msg = CommonI18n.i18nArgumentsMismatchedParameters;
+ msg = CommonI18n.i18nArgumentsMismatchedParameters.text(arguments.length,
+ id,
+ argCount,
+ text,
+ newText.toString());
}
- throw new IllegalArgumentException(msg.text(arguments.length, id, argCount, text,
newText.toString()));
+ throw new IllegalArgumentException(msg);
}
if (arguments.length == 1) {
- msg = CommonI18n.i18nReplaceArgumentMismatchedParameters;
+ msg = CommonI18n.i18nReplaceArgumentMismatchedParameters.text(argCount, text,
newText.toString());
} else if (argCount == 1) {
- msg = CommonI18n.i18nReplaceArgumentsMismatchedParameter;
+ msg = CommonI18n.i18nReplaceArgumentsMismatchedParameter.text(arguments.length, text,
newText.toString());
} else {
- msg = CommonI18n.i18nReplaceArgumentsMismatchedParameters;
+ msg = CommonI18n.i18nReplaceArgumentsMismatchedParameters.text(arguments.length,
+ argCount,
+ text,
+ newText.toString());
}
- throw new IllegalArgumentException(msg.text(arguments.length, argCount, text,
newText.toString()));
+ throw new IllegalArgumentException(msg);
}
matcher.appendTail(newText);
@@ -337,8 +389,10 @@
return replaceParameters(null, text, arguments);
}
- final String id;
+ private final String id;
private final Class i18nClass;
+ final ConcurrentHashMap<Locale, String> localeToTextMap = new
ConcurrentHashMap<Locale, String>();
+ final ConcurrentHashMap<Locale, String> localeToProblemMap = new
ConcurrentHashMap<Locale, String>();
private I18n( String id,
Class i18nClass ) {
@@ -346,23 +400,84 @@
this.i18nClass = i18nClass;
}
+ /**
+ * @return This internationalization object's ID, which will match both the name of
the relevant static field in the
+ * internationalization class and the relevant property name in the associated
localization files.
+ */
+ public String id() {
+ return id;
+ }
+
+ /**
+ * @return <code>true</code> if a problem was encountered while localizing
this internationalization object to the default
+ * locale.
+ */
+ public boolean hasProblem() {
+ return (problem() != null);
+ }
+
+ /**
+ * @param locale The locale for which to check whether a problem was encountered.
+ * @return <code>true</code> if a problem was encountered while localizing
this internationalization object to the supplied
+ * locale.
+ */
+ public boolean hasProblem( Locale locale ) {
+ return (problem(locale) != null);
+ }
+
+ /**
+ * @return The problem encountered while localizing this internationalization object to
the default locale, or
+ * <code>null</code> if none was encountered.
+ */
+ public String problem() {
+ return problem(null);
+ }
+
+ /**
+ * @param locale The locale for which to return the problem.
+ * @return The problem encountered while localizing this internationalization object to
the supplied locale, or
+ * <code>null</code> if none was encountered.
+ */
+ public String problem( Locale locale ) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ localize(i18nClass, locale);
+ // Check for field/property error
+ String problem = localeToProblemMap.get(locale);
+ if (problem != null) {
+ return problem;
+ }
+ // Check if text exists
+ if (localeToTextMap.get(locale) != null) {
+ // If so, no problem exists
+ return null;
+ }
+ // If we get here, which will be at most once, there was at least one global
localization error, so just return a message
+ // indicating to look them up.
+ problem = CommonI18n.i18nLocalizationProblems.text(i18nClass, locale);
+ localeToProblemMap.put(locale, problem);
+ return problem;
+ }
+
private String rawText( Locale locale ) {
assert locale != null;
- Map<String, String> id2TextMap = null;
- final Localization localization = new Localization(locale, i18nClass);
- id2TextMap = LOCALIZATION_2_ID_2_TEXT_MAP.get(localization);
- if (id2TextMap == null) {
- id2TextMap = initializeIdToTextMap(localization);
+ localize(i18nClass, locale);
+ // Check if text exists
+ String text = localeToTextMap.get(locale);
+ if (text != null) {
+ return text;
}
-
- return id2TextMap.get(id);
+ // If not, there was a problem, so throw it within an exception so upstream callers can
tell the difference between normal
+ // text and problem text.
+ throw new SystemFailureException(problem(locale));
}
/**
- * Get the internationalized text localized to the {@link Locale#getDefault() current
(default) locale}, replacing the
- * parameters in the text with those supplied.
+ * Get the localized text for the {@link Locale#getDefault() current (default) locale},
replacing the parameters in the text
+ * with those supplied.
*
- * @param arguments the arguments for the parameter replacement; may be null or empty
+ * @param arguments the arguments for the parameter replacement; may be
<code>null</code> or empty
* @return the localized text
*/
public String text( Object... arguments ) {
@@ -370,28 +485,20 @@
}
/**
- * Get the internationalized text localized to the supplied locale, replacing the
parameters in the text with those supplied.
+ * Get the localized text for the supplied locale, replacing the parameters in the text
with those supplied.
*
- * @param locale the locale, or null if the {@link Locale#getDefault() current (default)
locale} should be used
- * @param arguments the arguments for the parameter replacement; may be null or empty
+ * @param locale the locale, or <code>null</code> if the {@link
Locale#getDefault() current (default) locale} should be used
+ * @param arguments the arguments for the parameter replacement; may be
<code>null</code> or empty
* @return the localized text
*/
public String text( Locale locale,
Object... arguments ) {
- if (locale == null) {
- locale = Locale.getDefault();
+ try {
+ String rawText = rawText(locale == null ? Locale.getDefault() : locale);
+ return replaceParameters(id, rawText, arguments);
+ } catch (SystemFailureException err) {
+ return '<' + err.getMessage() + '>';
}
- String rawText = rawText(locale);
- if (rawText == null) {
- Map<String, String> id2ErrorMap = LOCALIZATION_2_ID_2_ERROR_MAP.get(new
Localization(locale, i18nClass));
- if (id2ErrorMap != null) {
- String msg = id2ErrorMap.get(id);
- if (msg != null) {
- return '<' + msg + '>';
- }
- }
- }
- return replaceParameters(id, rawText, arguments);
}
/**
@@ -399,71 +506,10 @@
*/
@Override
public String toString() {
- return rawText(Locale.getDefault());
- }
-
- @Immutable
- private static class Localization {
-
- final String language;
- final String country;
- final String variant;
- final Class i18nClass;
-
- Localization( Locale locale,
- Class i18nClass ) {
- this.language = locale.getLanguage();
- this.country = locale.getCountry();
- this.variant = locale.getVariant();
- this.i18nClass = i18nClass;
+ try {
+ return rawText(Locale.getDefault());
+ } catch (SystemFailureException err) {
+ return '<' + err.getMessage() + '>';
}
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- return HashCode.compute(country, i18nClass, language, variant);
- }
-
- /**
- * <p>
- * {@inheritDoc}
- * </p>
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals( Object obj ) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- Localization other = (Localization)obj;
- if (country == null) {
- if (other.country != null) return false;
- } else if (!country.equals(other.country)) {
- return false;
- }
- if (i18nClass == null) {
- if (other.i18nClass != null) return false;
- } else if (!i18nClass.equals(other.i18nClass)) {
- return false;
- }
- if (language == null) {
- if (other.language != null) return false;
- } else if (!language.equals(other.language)) {
- return false;
- }
- if (variant == null) {
- if (other.variant != null) return false;
- } else if (!variant.equals(other.variant)) {
- return false;
- }
- return true;
- }
}
}
Modified: trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties
===================================================================
---
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-04-22
20:42:49 UTC (rev 104)
+++
trunk/dna-common/src/main/resources/org/jboss/dna/common/CommonI18n.properties 2008-04-24
00:45:28 UTC (rev 105)
@@ -1,21 +1,22 @@
# Make sure the following I18n.java-related properties are defined before all other
properties to ensure a valid error message is
# produced in the event of a missing/duplicate/unused property
-i18nArgumentsMismatchedParameter = {0} arguments were specified for internationalization
object "{1}", but {2} parameter is required: "{3}" =>
"{4}"
-i18nArgumentMismatchedParameters = {0} argument was specified for internationalization
object "{1}", but {2} parameters are required: "{3}" =>
"{4}"
-i18nArgumentsMismatchedParameters = {0} arguments were specified for internationalization
object "{1}", but {2} parameters are required: "{3}" =>
"{4}"
-i18nReplaceArgumentsMismatchedParameter = {0} arguments were specified, but {1} parameter
is required: "{2}" => "{3}"
-i18nReplaceArgumentMismatchedParameters = {0} argument was specified, but {1} parameters
are required: "{2}" => "{3}"
-i18nReplaceArgumentsMismatchedParameters = {0} arguments were specified, but {1}
parameters are required: "{2}" => "{3}"
-i18nClassInterface = Class {0} must not be an interface.
-i18nClassNotPublic = Class {0} must be public.
+i18nArgumentsMismatchedParameter = {0} arguments were supplied to internationalization
object "{1}", but 1 parameter is required: "{2}" =>
"{3}"
+i18nArgumentMismatchedParameters = 1 argument was supplied to internationalization object
"{0}", but {1} parameters are required: "{2}" => "{3}"
+i18nArgumentsMismatchedParameters = {0} arguments were supplied to internationalization
object "{1}", but {2} parameters are required: "{3}" =>
"{4}"
+i18nReplaceArgumentsMismatchedParameter = {0} arguments were supplied, but 1 parameter is
required: "{1}" => "{2}"
+i18nReplaceArgumentMismatchedParameters = 1 argument was supplied, but {0} parameters are
required: "{1}" => "{2}"
+i18nReplaceArgumentsMismatchedParameters = {0} arguments were supplied, but {1}
parameters are required: "{2}" => "{3}"
+i18nClassInterface = Internationalization class {0} must not be an interface.
+i18nClassNotPublic = Internationalization {0} must be public.
i18nFieldFinal = Internationalization field "{0}" in {1} must not be final.
i18nFieldInvalidType = Internationalization field "{0}" in {1} must be of type
{2}.
i18nFieldNotPublic = Internationalization field "{0}" in {1} must be public.
i18nFieldNotStatic = Internationalization field "{0}" in {1} must be static.
-i18nPropertiesFileNotFound = No variant of the localization file for "{0}"
could be found.
+i18nLocalizationFileNotFound = No variant of the localization file for "{0}"
could be found.
+i18nLocalizationProblems = Problems were encountered while localizing
internationalization {0} to locale "{1}"
i18nPropertyDuplicate = Duplicate property values were found for property "{0}"
in localization file "{1}";
-i18nPropertyMissing = Missing property "{0}" in localization file {1}.
+i18nPropertyMissing = Missing property "{0}" in localization file
"{1}".
i18nPropertyUnused = An unused property, "{0}", was found in localization file
"{1}".
# Core-related fields
Added: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/CommonI18nTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/CommonI18nTest.java
(rev 0)
+++
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/CommonI18nTest.java 2008-04-24
00:45:28 UTC (rev 105)
@@ -0,0 +1,23 @@
+/*
+ *
+ */
+package org.jboss.dna.common.i18n;
+
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertThat;
+import java.util.Locale;
+import org.jboss.dna.common.CommonI18n;
+import org.junit.Test;
+
+/**
+ * @author John Verhaeg
+ */
+public class CommonI18nTest {
+
+ @Test
+ public void shouldNotHaveLocalizationProblems() {
+ for (Locale locale : CommonI18n.getLocalizationProblemLocales()) {
+ assertThat(CommonI18n.getLocalizationProblems(locale).isEmpty(), is(true));
+ }
+ }
+}
Property changes on:
trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/CommonI18nTest.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java
===================================================================
--- trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-22
20:42:49 UTC (rev 104)
+++ trunk/dna-common/src/test/java/org/jboss/dna/common/i18n/I18nTest.java 2008-04-24
00:45:28 UTC (rev 105)
@@ -28,6 +28,13 @@
import static org.hamcrest.core.IsNull.notNullValue;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
import org.jboss.dna.common.CommonI18n;
import org.jboss.dna.common.SystemFailureException;
import org.junit.Before;
@@ -39,222 +46,409 @@
*/
public final class I18nTest {
- @Before
- public void beforeEach() {
- I18n.initialize(TestI18n.class);
- }
+ @Before
+ public void beforeEach() throws Exception {
+ clearFields(TestI18n.class);
+ clearFields(TestI18nDuplicateProperty.class);
+ clearFields(TestI18nFinal.class);
+ clearFields(TestI18nFinalField.class);
+ clearFields(TestI18nInterface.class);
+ clearFields(TestI18nMissingLocalization.class);
+ clearFields(TestI18nMissingProperty.class);
+ clearFields(TestI18nNotPublicField.class);
+ clearFields(TestI18nNotStaticField.class);
+ clearFields(TestI18nPrivate.class);
+ clearFields(TestI18nUnusedProperty.class);
+ for (Entry<Locale, Map<Class, Set<String>>> localeToMapEntry :
I18n.LOCALE_TO_CLASS_TO_PROBLEMS_MAP.entrySet()) {
+ for (Iterator<Entry<Class, Set<String>>> iter =
localeToMapEntry.getValue().entrySet().iterator(); iter.hasNext();) {
+ if (iter.next().getKey() != CommonI18n.class) {
+ iter.remove();
+ }
+ }
+ }
+ }
- @Test( expected = IllegalArgumentException.class )
- public void getErrorsForDefaultLocaleShouldFailIfClassIsNull() {
- I18n.getErrorsForDefaultLocale(null);
+ private void clearFields( Class i18nClass ) throws Exception {
+ for (Field fld : i18nClass.getDeclaredFields()) {
+ if (fld.getType() == I18n.class && (fld.getModifiers() & Modifier.PUBLIC)
== Modifier.PUBLIC
+ && (fld.getModifiers() & Modifier.STATIC) == Modifier.STATIC
+ && (fld.getModifiers() & Modifier.FINAL) != Modifier.FINAL) {
+ fld.set(null, null);
+ }
+ }
}
- @Test
- public void getErrorsForLocaleShouldAllNullLocale() {
- I18n.getErrorsForLocale(TestI18n.class, null);
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToGetLocalizationProblemLocalesIfNoClassSupplied() {
+ I18n.getLocalizationProblemLocales(null);
}
@Test
- public void getErrorsForDefaultLocaleShouldNotReturnNull() {
- assertThat(I18n.getErrorsForDefaultLocale(TestI18n.class), notNullValue());
+ public void shouldNeverReturnNullWhenGettingLocalizationProblemLocales() {
+ assertThat(I18n.getLocalizationProblemLocales(TestI18n.class), notNullValue());
}
- @Test( expected = IllegalArgumentException.class )
- public void initializeShouldFailIfClassIsNull() {
- I18n.initialize(null);
- }
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToGetLocalizationProblemsForDefaultLocaleIfNoClassSupplied() {
+ I18n.getLocalizationProblems(null);
+ }
- @Test
- public void initializeShouldSkipNonI18nFields() {
- assertThat(TestI18n.nonI18n, is(nullValue()));
- }
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToGetLocalizationProblemsForSuppliedLocaleIfNoClassSupplied() {
+ I18n.getLocalizationProblems(null, Locale.US);
+ }
- @Test( expected = SystemFailureException.class )
- public void initializeShouldFailIfI18nFieldIsFinal() {
- try {
- I18n.initialize(TestI18nFinalField.class);
- } catch (SystemFailureException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nFieldFinal.text("testMessage", TestI18nFinalField.class)));
- System.err.println(err);
- throw err;
- }
- }
+ @Test
+ public void shouldNeverReturnNullWhenGettingLocalizationProblemsForDefaultLocale() {
+ assertThat(I18n.getLocalizationProblems(TestI18n.class), notNullValue());
+ }
- @Test( expected = RuntimeException.class )
- public void initializeShouldFailIfI18nFieldIsNotPublic() {
- try {
- I18n.initialize(TestI18nNotPublicField.class);
- } catch (RuntimeException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nFieldNotPublic.text("testMessage",
TestI18nNotPublicField.class)));
- System.err.println(err);
- throw err;
- }
- }
+ @Test
+ public void shouldNeverReturnNullWhenGettingLocalizationProblemsForSuppliedLocale() {
+ assertThat(I18n.getLocalizationProblems(TestI18n.class, Locale.US), notNullValue());
+ }
- @Test( expected = RuntimeException.class )
- public void initializeShouldFailIfI18nFieldIsNotStatic() {
- try {
- I18n.initialize(TestI18nNotStaticField.class);
- } catch (RuntimeException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nFieldNotStatic.text("testMessage",
TestI18nNotStaticField.class)));
- System.err.println(err);
- throw err;
- }
- }
+ @Test
+ public void shouldNotHaveLocalizationProblemsAfterInitializationButBeforeLocalization()
{
+ I18n.initialize(TestI18nUnusedProperty.class);
+ assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class, null).isEmpty(),
is(true));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).isEmpty(),
is(true));
+ }
- @Test
- public void initializeShouldAllowFinalClass() {
- I18n.initialize(TestI18nFinal.class);
- }
+ @Test
+ public void shouldGetLocalizationProblemsForDefaultLocaleIfNoLocaleSupplied() {
+ I18n.initialize(TestI18nUnusedProperty.class);
+ TestI18nUnusedProperty.testMessage.text("test");
+ assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class, null).isEmpty(),
is(false));
+ }
- @Test
- public void initializeShouldAllowPrivateClasses() {
- I18n.initialize(TestI18nPrivate.class);
- assertThat(TestI18nPrivate.testMessage, instanceOf(I18n.class));
- }
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToInitializeIfNoClassSupplied() {
+ I18n.initialize(null);
+ }
- @Test
- public void initializeShouldAssignI18nInstanceToI18nFields() {
- assertThat(TestI18n.testMessage, instanceOf(I18n.class));
- }
+ @Test( expected = SystemFailureException.class )
+ public void shouldFailToInitializeFinalI18nField() {
+ try {
+ I18n.initialize(TestI18nFinalField.class);
+ } catch (SystemFailureException err) {
+ assertThat(err.getMessage(),
is(CommonI18n.i18nFieldFinal.text("testMessage", TestI18nFinalField.class)));
+ System.err.println(err);
+ throw err;
+ }
+ }
- @Test( expected = IllegalArgumentException.class )
- public void initializeShouldFailIfClassIsInterface() {
- try {
- I18n.initialize(TestI18nInterface.class);
- } catch (IllegalArgumentException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nClassInterface.text(TestI18nInterface.class.getName())));
- System.err.println(err);
- throw err;
- }
- }
+ @Test( expected = SystemFailureException.class )
+ public void shouldFailToInitializeNonPublicI18nField() {
+ try {
+ I18n.initialize(TestI18nNotPublicField.class);
+ } catch (SystemFailureException err) {
+ assertThat(err.getMessage(),
is(CommonI18n.i18nFieldNotPublic.text("testMessage",
TestI18nNotPublicField.class)));
+ System.err.println(err);
+ throw err;
+ }
+ }
- @Test
- public void initializeShouldBeIdempotent() {
- I18n.initialize(TestI18n.class);
- }
+ @Test( expected = SystemFailureException.class )
+ public void shouldFailToInitializeNonStaticI18nField() {
+ try {
+ I18n.initialize(TestI18nNotStaticField.class);
+ } catch (SystemFailureException err) {
+ assertThat(err.getMessage(),
is(CommonI18n.i18nFieldNotStatic.text("testMessage",
TestI18nNotStaticField.class)));
+ System.err.println(err);
+ throw err;
+ }
+ }
- @Test
- public void i18nIdShouldMatchFieldName() throws Exception {
- assertThat(TestI18n.testMessage.id, is("testMessage"));
- }
+ @Test
+ public void shouldInitializeFinalClasses() {
+ I18n.initialize(TestI18nFinal.class);
+ assertThat(TestI18nFinal.testMessage, instanceOf(I18n.class));
+ }
- @Test
- public void i18nTextShouldHandleIfPropertyDuplicate() throws Exception {
- I18n.initialize(TestI18nDuplicateProperty.class);
- String text = TestI18nDuplicateProperty.testMessage.text("test");
+ @Test
+ public void shouldInitializePrivateClasses() {
+ I18n.initialize(TestI18nPrivate.class);
+ assertThat(TestI18nPrivate.testMessage, instanceOf(I18n.class));
+ }
+
+ @Test
+ public void shouldInitializeI18nFields() {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage, instanceOf(I18n.class));
+ }
+
+ @Test
+ public void shouldNotInitializeNonI18nFields() {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.nonI18n, nullValue());
+ }
+
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailToInitializeInterfaces() {
+ try {
+ I18n.initialize(TestI18nInterface.class);
+ } catch (IllegalArgumentException err) {
+ assertThat(err.getMessage(),
is(CommonI18n.i18nClassInterface.text(TestI18nInterface.class.getName())));
+ System.err.println(err);
+ throw err;
+ }
+ }
+
+ @Test
+ public void shouldProvideIdempotentInitialization() {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage1.text("test"), is("test"));
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage1.text("test"), is("test"));
+ }
+
+ @Test
+ public void shouldNotBeLocalizedAfterInitialization() {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()),
nullValue());
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()),
nullValue());
+ }
+
+ @Test
+ public void shouldHaveIdThatMatchesFieldName() throws Exception {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage.id(), is("testMessage"));
+ }
+
+ @Test
+ public void shouldNotBeLocalizedIfAskedForId() {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ TestI18nDuplicateProperty.testMessage.id();
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()),
nullValue());
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()),
nullValue());
+ }
+
+ @Test
+ public void shouldBeLocalizedIfAskedIfHasProblem() {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ TestI18nDuplicateProperty.testMessage.hasProblem();
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()),
notNullValue());
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()),
notNullValue());
+ }
+
+ @Test
+ public void shouldBeLocalizedIfAskedForProblem() {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ TestI18nDuplicateProperty.testMessage.problem();
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()),
notNullValue());
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()),
notNullValue());
+ }
+
+ @Test
+ public void shouldBeLocalizedIfConvertedToString() {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ TestI18nDuplicateProperty.testMessage.toString();
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToTextMap.get(Locale.getDefault()),
notNullValue());
+ assertThat(TestI18nDuplicateProperty.testMessage.localeToProblemMap.get(Locale.getDefault()),
notNullValue());
+ }
+
+ @Test
+ public void shouldContainAngleBracketedProblemInTextIfMissingLocalization() throws
Exception {
+ I18n.initialize(TestI18nMissingLocalization.class);
+ String text = TestI18nMissingLocalization.testMessage.text();
+ assertThat(text,
+ is('<' +
CommonI18n.i18nLocalizationProblems.text(TestI18nMissingLocalization.class,
Locale.getDefault()) + '>'));
+ System.out.println("Text: " + text);
+ }
+
+ @Test
+ public void shouldHaveProblemIfMissingLocalization() throws Exception {
+ I18n.initialize(TestI18nMissingLocalization.class);
+ assertThat(TestI18nMissingLocalization.testMessage.hasProblem(), is(true));
+ String problem = TestI18nMissingLocalization.testMessage.problem();
+ assertThat(problem,
is(CommonI18n.i18nLocalizationProblems.text(TestI18nMissingLocalization.class,
Locale.getDefault())));
+ System.out.println("Problem: " + problem);
+ }
+
+ @Test
+ public void shouldHaveLocalicationProblemIfMissingLocalization() throws Exception {
+ I18n.initialize(TestI18nMissingLocalization.class);
+ TestI18nMissingLocalization.testMessage.text();
+ assertThat(I18n.getLocalizationProblems(TestI18nMissingLocalization.class).size(),
is(1));
+ assertThat(I18n.getLocalizationProblems(TestI18nMissingLocalization.class).iterator().next(),
+
is(CommonI18n.i18nLocalizationFileNotFound.text(TestI18nMissingLocalization.class.getName())));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingLocalization.class).size(),
is(1));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingLocalization.class).iterator().next(),
+ is(Locale.getDefault()));
+ }
+
+ @Test
+ public void shouldHaveTextIfPropertyDuplicate() throws Exception {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ String text = TestI18nDuplicateProperty.testMessage.text("test");
assertThat(text.charAt(0), not('<'));
- assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(),
is(1));
- System.out.println(text);
- }
+ System.out.println("Text: " + text);
+ }
- @Test
- public void i18nTextShouldHandleIfPropertyMissing() throws Exception {
- I18n.initialize(TestI18nMissingProperty.class);
- String text = TestI18nMissingProperty.testMessage1.text();
+ @Test
+ public void shouldHaveProblemIfPropertyDuplicate() throws Exception {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ assertThat(TestI18nDuplicateProperty.testMessage.hasProblem(), is(true));
+ String problem = TestI18nDuplicateProperty.testMessage.problem();
+ assertThat(problem, notNullValue());
+ System.out.println("Problem: " + problem);
+ }
+
+ @Test
+ public void shouldNotHaveLocalicationProblemIfPropertyDuplicate() throws Exception {
+ I18n.initialize(TestI18nDuplicateProperty.class);
+ TestI18nDuplicateProperty.testMessage.text("test");
+ assertThat(I18n.getLocalizationProblems(TestI18nDuplicateProperty.class).isEmpty(),
is(true));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nDuplicateProperty.class).isEmpty(),
is(true));
+ }
+
+ @Test
+ public void shouldContainAngleBracketedProblemInTextIfPropertyMissing() throws Exception
{
+ I18n.initialize(TestI18nMissingProperty.class);
+ String text = TestI18nMissingProperty.testMessage1.text("test");
assertThat(text.charAt(0), is('<'));
- assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(),
is(1));
- System.out.println(text);
- }
+ System.out.println("Text: " + text);
+ }
- @Test
- public void i18nTextShouldHandleIfPropertyUnused() throws Exception {
- I18n.initialize(TestI18nUnusedProperty.class);
- String text = TestI18nUnusedProperty.testMessage.text("test");
- assertThat(text.charAt(0), not('<'));
- assertThat(I18n.getErrorsForDefaultLocale(TestI18nDuplicateProperty.class).size(),
is(1));
- System.out.println(text);
- }
+ @Test
+ public void shouldHaveProblemIfPropertyMissing() throws Exception {
+ I18n.initialize(TestI18nMissingProperty.class);
+ assertThat(TestI18nMissingProperty.testMessage1.hasProblem(), is(true));
+ String problem = TestI18nMissingProperty.testMessage1.problem();
+ assertThat(problem, notNullValue());
+ System.out.println("Problem: " + problem);
+ }
- @Test
- public void i18nTextShouldMatchPropertiesFile() throws Exception {
- assertThat(TestI18n.testMessage.text(), is("Test Message"));
- }
+ @Test
+ public void shouldNotHaveLocalicationProblemIfPropertyMissing() throws Exception {
+ I18n.initialize(TestI18nMissingProperty.class);
+ TestI18nMissingProperty.testMessage1.text("test");
+ assertThat(I18n.getLocalizationProblems(TestI18nMissingProperty.class).isEmpty(),
is(true));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nMissingProperty.class).isEmpty(),
is(true));
+ }
- @Test( expected = IllegalArgumentException.class )
- public void i18nTextShouldFailIfTooFewArgumentsSpecified() throws Exception {
- try {
- TestI18n.testMessage1.text();
- } catch (IllegalArgumentException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nArgumentsMismatchedParameter.text(0, "testMessage1", 1,
"{0}", "{0}")));
- System.err.println(err);
- throw err;
- }
- }
+ @Test
+ public void shouldHaveLocalicationProblemIfPropertyUnused() throws Exception {
+ I18n.initialize(TestI18nUnusedProperty.class);
+ TestI18nUnusedProperty.testMessage.text("test");
+ assertThat(I18n.getLocalizationProblems(TestI18nUnusedProperty.class).size(), is(1));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).size(),
is(1));
+ assertThat(I18n.getLocalizationProblemLocales(TestI18nUnusedProperty.class).iterator().next(),
is(Locale.getDefault()));
+ }
- @Test( expected = IllegalArgumentException.class )
- public void i18nTextShouldFailIfTooManyArgumentsSpecified() throws Exception {
- try {
- TestI18n.testMessage1.text("Test", "Message");
- } catch (IllegalArgumentException err) {
- assertThat(err.getMessage(),
is(CommonI18n.i18nArgumentsMismatchedParameter.text(2, "testMessage1", 1,
"{0}", "Test")));
- System.err.println(err);
- throw err;
- }
- }
+ @Test
+ public void shouldHaveTextMatchingLocalizationFilePropertyValue() throws Exception {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage.text(), is("Test Message"));
+ }
- @Test
- public void i18nTextShouldContainArgumentsInRightOrder() throws Exception {
- assertThat(TestI18n.testMessage2.text("Test", "Message"),
is("Message Test"));
- }
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailIfTooFewArgumentsSuppliedToText() throws Exception {
+ I18n.initialize(TestI18n.class);
+ try {
+ TestI18n.testMessage1.text();
+ } catch (IllegalArgumentException err) {
+ assertThat(err.getMessage(), is(CommonI18n.i18nArgumentsMismatchedParameter.text(0,
"testMessage1", 1, "{0}", "{0}")));
+ System.err.println(err);
+ throw err;
+ }
+ }
- @Test
- public void i18nTextShouldAllowReuseOfArguments() throws Exception {
- assertThat(TestI18n.testMessage3.text("Test", "Message"),
is("Message Test Message"));
- }
+ @Test( expected = IllegalArgumentException.class )
+ public void shouldFailIfTooManyArgumentsSuppliedToText() throws Exception {
+ I18n.initialize(TestI18n.class);
+ try {
+ TestI18n.testMessage1.text("Test", "Message");
+ } catch (IllegalArgumentException err) {
+ assertThat(err.getMessage(),
+ is(CommonI18n.i18nArgumentsMismatchedParameter.text(2,
"testMessage1", 1, "{0}", "Test")));
+ System.err.println(err);
+ throw err;
+ }
+ }
- public static class TestI18n {
+ @Test
+ public void shouldContainArgumentsInRightOrderInText() throws Exception {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage2.text("Test", "Message"),
is("Message Test"));
+ }
- public static I18n testMessage;
- public static I18n testMessage1;
- public static I18n testMessage2;
- public static I18n testMessage3;
- public static Object nonI18n;
- }
+ @Test
+ public void shouldAllowReuseOfArgumentsInText() throws Exception {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage3.text("Test", "Message"),
is("Message Test Message"));
+ }
- private static class TestI18nDuplicateProperty {
+ @Test
+ public void shouldContainLocaleSpecificText() {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage.text(Locale.FRENCH), is("Message de Test"));
+ }
- public static I18n testMessage;
- }
+ @Test
+ public void shouldContainTextForDefaultLocaleIfMissingLocalizationForSuppliedLocale() {
+ I18n.initialize(TestI18n.class);
+ assertThat(TestI18n.testMessage.text(Locale.CHINESE), is("Test Message"));
+ }
- public static final class TestI18nFinal {
+ public static class TestI18n {
- public static I18n testMessage;
- }
+ public static I18n testMessage;
+ public static I18n testMessage1;
+ public static I18n testMessage2;
+ public static I18n testMessage3;
+ public static Object nonI18n;
+ }
- public static class TestI18nFinalField {
+ private static class TestI18nDuplicateProperty {
- public static final I18n testMessage = null;
- }
+ public static I18n testMessage;
+ }
- public static interface TestI18nInterface {
+ public static final class TestI18nFinal {
- I18n testMessage = null;
- }
+ public static I18n testMessage;
+ }
- private static class TestI18nMissingProperty {
+ public static class TestI18nFinalField {
- public static I18n testMessage;
- public static I18n testMessage1;
- }
+ public static final I18n testMessage = null;
+ }
- public static class TestI18nNotPublicField {
+ public static interface TestI18nInterface {
- static I18n testMessage;
- }
+ I18n testMessage = null;
+ }
- public static class TestI18nNotStaticField {
+ private static class TestI18nMissingProperty {
- public I18n testMessage;
- }
+ public static I18n testMessage;
+ public static I18n testMessage1;
+ }
- private static class TestI18nPrivate {
+ public static class TestI18nNotPublicField {
- public static I18n testMessage;
- }
+ static I18n testMessage;
+ }
- private static class TestI18nUnusedProperty {
+ public static class TestI18nNotStaticField {
- public static I18n testMessage;
- }
+ public I18n testMessage;
+ }
+
+ private static class TestI18nPrivate {
+
+ public static I18n testMessage;
+ }
+
+ private static class TestI18nUnusedProperty {
+
+ public static I18n testMessage;
+ }
+
+ private static class TestI18nMissingLocalization {
+
+ public static I18n testMessage;
+ }
}
Deleted:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n.properties
===================================================================
---
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n.properties 2008-04-22
20:42:49 UTC (rev 104)
+++
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n.properties 2008-04-24
00:45:28 UTC (rev 105)
@@ -1,4 +0,0 @@
-testMessage = Test Message
-testMessage1 = {0}
-testMessage2 = {1} {0}
-testMessage3 = {1} {0} {1}
\ No newline at end of file
Copied:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_en.properties
(from rev 100,
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n.properties)
===================================================================
---
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_en.properties
(rev 0)
+++
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_en.properties 2008-04-24
00:45:28 UTC (rev 105)
@@ -0,0 +1,4 @@
+testMessage = Test Message
+testMessage1 = {0}
+testMessage2 = {1} {0}
+testMessage3 = {1} {0} {1}
\ No newline at end of file
Property changes on:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_en.properties
___________________________________________________________________
Name: svn:executable
+ *
Added:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_fr.properties
===================================================================
---
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_fr.properties
(rev 0)
+++
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_fr.properties 2008-04-24
00:45:28 UTC (rev 105)
@@ -0,0 +1,4 @@
+testMessage = Message de Test
+testMessage1 = {0}
+testMessage2 = {1} {0}
+testMessage3 = {1} {0} {1}
\ No newline at end of file
Property changes on:
trunk/dna-common/src/test/resources/org/jboss/dna/common/i18n/I18nTest$TestI18n_fr.properties
___________________________________________________________________
Name: svn:executable
+ *
Name: svn:mime-type
+ text/plain