l10n updates
This commit is contained in:
parent
6a189e5a41
commit
8f9bdc832f
BIN
pix-src/icon/icon-large-close.xcf.gz
Normal file
BIN
pix-src/icon/icon-large-close.xcf.gz
Normal file
Binary file not shown.
92
src/net/sf/openrocket/l10n/ClassBasedTranslator.java
Normal file
92
src/net/sf/openrocket/l10n/ClassBasedTranslator.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,26 +1,16 @@
|
||||
package net.sf.openrocket.l10n;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
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.
|
||||
* <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>
|
||||
*/
|
||||
public class ResourceBundleTranslator implements Translator {
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private final ResourceBundle bundle;
|
||||
private final String baseName;
|
||||
private final Locale locale;
|
||||
|
||||
/**
|
||||
* Create a ResourceBundleTranslator using the default Locale.
|
||||
@ -39,8 +29,6 @@ public class ResourceBundleTranslator implements Translator {
|
||||
*/
|
||||
public ResourceBundleTranslator(String baseName, Locale locale) {
|
||||
this.bundle = ResourceBundle.getBundle(baseName, locale);
|
||||
this.baseName = baseName;
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
|
||||
@ -49,12 +37,7 @@ public class ResourceBundleTranslator implements Translator {
|
||||
*/
|
||||
@Override
|
||||
public synchronized String get(String key) {
|
||||
try {
|
||||
return bundle.getString(key);
|
||||
} catch (MissingResourceException e) {
|
||||
log.error("String not found for key '" + key + "' in bundle '" + baseName + "' with locale " + locale, e);
|
||||
}
|
||||
return key;
|
||||
return bundle.getString(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.sf.openrocket.l10n;
|
||||
|
||||
import java.util.MissingResourceException;
|
||||
|
||||
/**
|
||||
* An interface for obtaining translations from logical keys.
|
||||
* <p>
|
||||
@ -15,6 +17,7 @@ public interface Translator {
|
||||
*
|
||||
* @param key the logical string key.
|
||||
* @return the translated string.
|
||||
* @throws MissingResourceException if the translation corresponding to the key is not found.
|
||||
* @throws NullPointerException if key is null.
|
||||
*/
|
||||
public String get(String key);
|
||||
|
@ -1,7 +1,9 @@
|
||||
package net.sf.openrocket.startup;
|
||||
|
||||
import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
|
||||
import net.sf.openrocket.l10n.ClassBasedTranslator;
|
||||
import net.sf.openrocket.l10n.DebugTranslator;
|
||||
import net.sf.openrocket.l10n.ExceptionSuppressingTranslator;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.logging.LogLevel;
|
||||
@ -18,7 +20,7 @@ public final class Application {
|
||||
private static LogHelper logger;
|
||||
private static LogLevelBufferLogger logBuffer;
|
||||
|
||||
private static Translator translator = new DebugTranslator();
|
||||
private static Translator baseTranslator = new DebugTranslator();
|
||||
|
||||
private static ThrustCurveMotorSetDatabase motorSetDatabase;
|
||||
|
||||
@ -87,15 +89,18 @@ public final class Application {
|
||||
* @return a translator.
|
||||
*/
|
||||
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.
|
||||
* @param translator the translator to set.
|
||||
*/
|
||||
public static void setTranslator(Translator translator) {
|
||||
Application.translator = translator;
|
||||
public static void setBaseTranslator(Translator translator) {
|
||||
Application.baseTranslator = translator;
|
||||
}
|
||||
|
||||
|
||||
|
@ -134,6 +134,7 @@ public class Startup {
|
||||
} else {
|
||||
l = new Locale(split[0], split[1], split[2]);
|
||||
}
|
||||
log.info("Setting custom locale " + l);
|
||||
Locale.setDefault(l);
|
||||
}
|
||||
|
||||
@ -147,7 +148,7 @@ public class Startup {
|
||||
log.info("Set up translation for locale " + Locale.getDefault() +
|
||||
", debug.currentFile=" + t.get("debug.currentFile"));
|
||||
|
||||
Application.setTranslator(t);
|
||||
Application.setBaseTranslator(t);
|
||||
}
|
||||
|
||||
|
||||
|
79
test/net/sf/openrocket/l10n/TestClassBasedTranslator.java
Normal file
79
test/net/sf/openrocket/l10n/TestClassBasedTranslator.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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 |
Loading…
x
Reference in New Issue
Block a user