l10n updates

This commit is contained in:
Sampo Niskanen 2011-03-25 18:04:49 +00:00
parent 6a189e5a41
commit 8f9bdc832f
10 changed files with 308 additions and 23 deletions

Binary file not shown.

View File

@ -0,0 +1,92 @@
package net.sf.openrocket.l10n;
import java.util.MissingResourceException;
import net.sf.openrocket.logging.TraceException;
import net.sf.openrocket.util.BugException;
/**
* A translator that prepends a pre-defined class name in front of a translation key
* and retrieves the translator for that key, and only if that is missing reverts to
* the base key name. The base class name can either be provided to the constructor
* or retrieved from the stack.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class ClassBasedTranslator implements Translator {
private final Translator translator;
private final String className;
/**
* Construct a translator using a specified class name.
*
* @param translator the translator from which to obtain the translations.
* @param className the base class name to prepend.
*/
public ClassBasedTranslator(Translator translator, String className) {
this.translator = translator;
this.className = className;
}
/**
* Construct a translator by obtaining the base class name from the stack.
*
* @param translator the translator from which to obtain the translations.
* @param levels the number of levels to move upwards in the stack from the point where this method is called.
*/
public ClassBasedTranslator(Translator translator, int levels) {
this(translator, getStackClass(levels));
}
@Override
public String get(String key) {
String classKey = className + "." + key;
try {
return translator.get(classKey);
} catch (MissingResourceException e) {
// Ignore
}
try {
return translator.get(key);
} catch (MissingResourceException e) {
MissingResourceException mre = new MissingResourceException(
"Neither key '" + classKey + "' nor '" + key + "' could be found", e.getClassName(), key);
mre.initCause(e);
throw mre;
}
}
private static String getStackClass(int levels) {
TraceException trace = new TraceException();
StackTraceElement stack[] = trace.getStackTrace();
final int index = levels + 2;
if (stack.length <= index) {
throw new BugException("Stack trace is too short, length=" + stack.length + ", expected=" + index, trace);
}
StackTraceElement element = stack[index];
String cn = element.getClassName();
int pos = cn.lastIndexOf('.');
if (pos >= 0) {
cn = cn.substring(pos + 1);
}
return cn;
}
// For unit testing purposes
String getClassName() {
return className;
}
}

View File

@ -0,0 +1,58 @@
package net.sf.openrocket.l10n;
import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
import net.sf.openrocket.gui.main.ExceptionHandler;
/**
* A translator that suppresses MissingResourceExceptions and handles them gracefully.
* For every missing key this class calls the exception handler exactly once, and
* returns the key itself as the translation.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public class ExceptionSuppressingTranslator implements Translator {
private static final Set<String> errors = new HashSet<String>();
// For unit testing:
static int failures = 0;
private final Translator translator;
/**
* Sole constructor.
*
* @param translator the translator to use
*/
public ExceptionSuppressingTranslator(Translator translator) {
this.translator = translator;
}
@Override
public String get(String key) {
try {
return translator.get(key);
} catch (MissingResourceException e) {
handleError(key, e);
}
return key;
}
private static synchronized void handleError(String key, MissingResourceException e) {
if (errors.add(key)) {
failures++;
ExceptionHandler.handleErrorCondition("Can not find translation for '" + key + "' locale=" + Locale.getDefault(), e);
}
}
}

View File

@ -1,26 +1,16 @@
package net.sf.openrocket.l10n; package net.sf.openrocket.l10n;
import java.util.Locale; import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.startup.Application;
/** /**
* A translator that obtains translated strings from a resource bundle. * A translator that obtains translated strings from a resource bundle.
* <p>
* If a message is not found in any resource bundle, an error is logged and the key itself
* is returned.
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public class ResourceBundleTranslator implements Translator { public class ResourceBundleTranslator implements Translator {
private static final LogHelper log = Application.getLogger();
private final ResourceBundle bundle; private final ResourceBundle bundle;
private final String baseName;
private final Locale locale;
/** /**
* Create a ResourceBundleTranslator using the default Locale. * Create a ResourceBundleTranslator using the default Locale.
@ -39,8 +29,6 @@ public class ResourceBundleTranslator implements Translator {
*/ */
public ResourceBundleTranslator(String baseName, Locale locale) { public ResourceBundleTranslator(String baseName, Locale locale) {
this.bundle = ResourceBundle.getBundle(baseName, locale); this.bundle = ResourceBundle.getBundle(baseName, locale);
this.baseName = baseName;
this.locale = locale;
} }
@ -49,12 +37,7 @@ public class ResourceBundleTranslator implements Translator {
*/ */
@Override @Override
public synchronized String get(String key) { public synchronized String get(String key) {
try {
return bundle.getString(key); return bundle.getString(key);
} catch (MissingResourceException e) {
log.error("String not found for key '" + key + "' in bundle '" + baseName + "' with locale " + locale, e);
}
return key;
} }
} }

View File

@ -1,5 +1,7 @@
package net.sf.openrocket.l10n; package net.sf.openrocket.l10n;
import java.util.MissingResourceException;
/** /**
* An interface for obtaining translations from logical keys. * An interface for obtaining translations from logical keys.
* <p> * <p>
@ -15,6 +17,7 @@ public interface Translator {
* *
* @param key the logical string key. * @param key the logical string key.
* @return the translated string. * @return the translated string.
* @throws MissingResourceException if the translation corresponding to the key is not found.
* @throws NullPointerException if key is null. * @throws NullPointerException if key is null.
*/ */
public String get(String key); public String get(String key);

View File

@ -1,7 +1,9 @@
package net.sf.openrocket.startup; package net.sf.openrocket.startup;
import net.sf.openrocket.database.ThrustCurveMotorSetDatabase; import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
import net.sf.openrocket.l10n.ClassBasedTranslator;
import net.sf.openrocket.l10n.DebugTranslator; import net.sf.openrocket.l10n.DebugTranslator;
import net.sf.openrocket.l10n.ExceptionSuppressingTranslator;
import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LogHelper; import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.logging.LogLevel; import net.sf.openrocket.logging.LogLevel;
@ -18,7 +20,7 @@ public final class Application {
private static LogHelper logger; private static LogHelper logger;
private static LogLevelBufferLogger logBuffer; private static LogLevelBufferLogger logBuffer;
private static Translator translator = new DebugTranslator(); private static Translator baseTranslator = new DebugTranslator();
private static ThrustCurveMotorSetDatabase motorSetDatabase; private static ThrustCurveMotorSetDatabase motorSetDatabase;
@ -87,15 +89,18 @@ public final class Application {
* @return a translator. * @return a translator.
*/ */
public static Translator getTranslator() { public static Translator getTranslator() {
return translator; Translator t = baseTranslator;
t = new ClassBasedTranslator(t, 1);
t = new ExceptionSuppressingTranslator(t);
return t;
} }
/** /**
* Set the translator used in obtaining translated strings. * Set the translator used in obtaining translated strings.
* @param translator the translator to set. * @param translator the translator to set.
*/ */
public static void setTranslator(Translator translator) { public static void setBaseTranslator(Translator translator) {
Application.translator = translator; Application.baseTranslator = translator;
} }

View File

@ -134,6 +134,7 @@ public class Startup {
} else { } else {
l = new Locale(split[0], split[1], split[2]); l = new Locale(split[0], split[1], split[2]);
} }
log.info("Setting custom locale " + l);
Locale.setDefault(l); Locale.setDefault(l);
} }
@ -147,7 +148,7 @@ public class Startup {
log.info("Set up translation for locale " + Locale.getDefault() + log.info("Set up translation for locale " + Locale.getDefault() +
", debug.currentFile=" + t.get("debug.currentFile")); ", debug.currentFile=" + t.get("debug.currentFile"));
Application.setTranslator(t); Application.setBaseTranslator(t);
} }

View File

@ -0,0 +1,79 @@
package net.sf.openrocket.l10n;
import static org.junit.Assert.*;
import java.util.MissingResourceException;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.auto.Mock;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JMock.class)
public class TestClassBasedTranslator {
Mockery context = new JUnit4Mockery();
@Mock
Translator translator;
@Test
public void testClassName() {
ClassBasedTranslator cbt = new ClassBasedTranslator(null, 0);
assertEquals("TestClassBasedTranslator", cbt.getClassName());
cbt = new ClassBasedTranslator(null, "foobar");
assertEquals("foobar", cbt.getClassName());
}
@Test
public void testGetWithClassName() {
ClassBasedTranslator cbt = new ClassBasedTranslator(translator, 0);
// @formatter:off
context.checking(new Expectations() {{
oneOf(translator).get("TestClassBasedTranslator.fake.key"); will(returnValue("foobar"));
}});
// @formatter:on
assertEquals("foobar", cbt.get("fake.key"));
}
@Test
public void testGetWithoutClassName() {
ClassBasedTranslator cbt = new ClassBasedTranslator(translator, 0);
// @formatter:off
context.checking(new Expectations() {{
oneOf(translator).get("TestClassBasedTranslator.fake.key"); will(throwException(new MissingResourceException("a", "b", "c")));
oneOf(translator).get("fake.key"); will(returnValue("barbaz"));
}});
// @formatter:on
assertEquals("barbaz", cbt.get("fake.key"));
}
@Test
public void testMissing() {
ClassBasedTranslator cbt = new ClassBasedTranslator(translator, 0);
// @formatter:off
context.checking(new Expectations() {{
oneOf(translator).get("TestClassBasedTranslator.fake.key"); will(throwException(new MissingResourceException("a", "b", "c")));
oneOf(translator).get("fake.key"); will(throwException(new MissingResourceException("a", "b", "c")));
}});
// @formatter:on
try {
fail("Returned: " + cbt.get("fake.key"));
} catch (MissingResourceException e) {
assertEquals("Neither key 'TestClassBasedTranslator.fake.key' nor 'fake.key' could be found", e.getMessage());
}
}
}

View File

@ -0,0 +1,64 @@
package net.sf.openrocket.l10n;
import static org.junit.Assert.assertEquals;
import java.util.MissingResourceException;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.auto.Mock;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(JMock.class)
public class TestExceptionSuppressingTranslator {
Mockery context = new JUnit4Mockery();
@Mock
Translator translator;
@Test
public void testSuccessful() {
ExceptionSuppressingTranslator est = new ExceptionSuppressingTranslator(translator);
// @formatter:off
context.checking(new Expectations() {{
oneOf(translator).get("fake.key"); will(returnValue("foobar"));
}});
// @formatter:on
assertEquals("foobar", est.get("fake.key"));
}
@Test
public void testFailure() {
ExceptionSuppressingTranslator est = new ExceptionSuppressingTranslator(translator);
assertEquals("Prerequisite failed", 0, ExceptionSuppressingTranslator.failures);
// @formatter:off
context.checking(new Expectations() {{
oneOf(translator).get("fake.key"); will(throwException(new MissingResourceException("a", "b", "c")));
oneOf(translator).get("fake.key"); will(throwException(new MissingResourceException("a", "b", "c")));
oneOf(translator).get("fake.key2"); will(throwException(new MissingResourceException("a", "b", "c")));
}});
// @formatter:on
// Test first failure
assertEquals("fake.key", est.get("fake.key"));
assertEquals(1, ExceptionSuppressingTranslator.failures);
// Test second failure
assertEquals("fake.key", est.get("fake.key"));
assertEquals(1, ExceptionSuppressingTranslator.failures);
// Test failure with other key
assertEquals("fake.key2", est.get("fake.key"));
assertEquals(2, ExceptionSuppressingTranslator.failures);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB