Skip to content

Commit

Permalink
fix: loading of i18n resources as UTF-8 (see #363) (PR #386)
Browse files Browse the repository at this point in the history
  • Loading branch information
jpstotz authored and skylot committed Nov 7, 2018
1 parent bedbf94 commit 5281eed
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 103 deletions.
2 changes: 1 addition & 1 deletion jadx-gui/src/main/java/jadx/gui/ui/MainWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ public void actionPerformed(ActionEvent e) {
openFile();
}
};
openAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.open"));
openAction.putValue(Action.SHORT_DESCRIPTION, NLS.str("file.open_action"));
openAction.putValue(Action.ACCELERATOR_KEY, getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_DOWN_MASK));

Action saveAllAction = new AbstractAction(NLS.str("file.save_all"), ICON_SAVE_ALL) {
Expand Down
201 changes: 99 additions & 102 deletions jadx-gui/src/main/java/jadx/gui/utils/NLS.java
Original file line number Diff line number Diff line change
@@ -1,102 +1,99 @@
package jadx.gui.utils;

import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Vector;

import org.jetbrains.annotations.NotNull;

public class NLS {
private static final Charset JAVA_CHARSET = Charset.forName("ISO-8859-1");
private static final Charset UTF8_CHARSET = Charset.forName("UTF-8");

private static Vector<LangLocale> i18nLocales = new Vector<>();

private static Map<LangLocale, Map<String, String>> i18nMessagesMap = new HashMap<>();

// Use these two fields to avoid invoking Map.get() method twice.
private static Map<String, String> localizedMessagesMap;
private static Map<String, String> fallbackMessagesMap;

private static LangLocale currentLocale;
private static LangLocale localLocale;

static {
localLocale = new LangLocale(Locale.getDefault());

i18nLocales.add(new LangLocale("en", "US")); // As default language
i18nLocales.add(new LangLocale("zh", "CN"));
i18nLocales.add(new LangLocale("es", "ES"));

i18nLocales.forEach(NLS::load);

LangLocale defLang = i18nLocales.get(0);
fallbackMessagesMap = i18nMessagesMap.get(defLang);
localizedMessagesMap = i18nMessagesMap.get(defLang);
}

private NLS() {
}

private static void load(LangLocale locale) {
ResourceBundle bundle = ResourceBundle.getBundle("i18n/Messages", locale.get());
Map<String, String> resMap = new HashMap<>();
for (String key : bundle.keySet()) {
String str = bundle.getString(key);
resMap.put(key, convertCharset(str));
}
i18nMessagesMap.put(locale, resMap);
}

@NotNull
private static String convertCharset(String str) {
return new String(str.getBytes(JAVA_CHARSET), UTF8_CHARSET);
}

public static String str(String key) {
String str = localizedMessagesMap.get(key);
if (str != null) {
return str;
}
return fallbackMessagesMap.get(key); // definitely exists
}

public static String str(String key, LangLocale locale) {
Map<String, String> strings = i18nMessagesMap.get(locale);
if (strings != null) {
String str = strings.get(key);
if (str != null) {
return str;
}
}
return fallbackMessagesMap.get(key); // definitely exists
}

public static void setLocale(LangLocale locale) {
if (i18nMessagesMap.containsKey(locale)) {
currentLocale = locale;
} else {
currentLocale = i18nLocales.get(0);
}
localizedMessagesMap = i18nMessagesMap.get(currentLocale);
}

public static Vector<LangLocale> getI18nLocales() {
return i18nLocales;
}

public static LangLocale currentLocale() {
return currentLocale;
}

public static LangLocale defaultLocale() {
if (i18nMessagesMap.containsKey(localLocale)) {
return localLocale;
}
// fallback to english if unsupported
return i18nLocales.get(0);
}
}
package jadx.gui.utils;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

import org.jetbrains.annotations.NotNull;

public class NLS {

private static Vector<LangLocale> i18nLocales = new Vector<>();

private static Map<LangLocale, ResourceBundle> i18nMessagesMap = new HashMap<>();

// Use these two fields to avoid invoking Map.get() method twice.
private static ResourceBundle localizedMessagesMap;
private static ResourceBundle fallbackMessagesMap;

private static LangLocale currentLocale;
private static LangLocale localLocale;

static {
localLocale = new LangLocale(Locale.getDefault());

i18nLocales.add(new LangLocale("en", "US")); // As default language
i18nLocales.add(new LangLocale("zh", "CN"));
i18nLocales.add(new LangLocale("es", "ES"));

i18nLocales.forEach(NLS::load);

LangLocale defLang = i18nLocales.get(0);
fallbackMessagesMap = i18nMessagesMap.get(defLang);
localizedMessagesMap = i18nMessagesMap.get(defLang);
}

private NLS() {
}

private static void load(LangLocale locale) {
ResourceBundle bundle;
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
String resName = String.format("i18n/Messages_%s.properties", locale.get());
URL bundleUrl = classLoader.getResource(resName);
try (Reader reader = new InputStreamReader(bundleUrl.openStream(), StandardCharsets.UTF_8)) {
bundle = new PropertyResourceBundle(reader);
} catch (IOException e) {
throw new RuntimeException("Failed to load " + resName, e);
}
i18nMessagesMap.put(locale, bundle);
}

public static String str(String key) {
try {
return localizedMessagesMap.getString(key);
} catch (MissingResourceException e) {
return fallbackMessagesMap.getString(key); // definitely exists
}
}

public static String str(String key, LangLocale locale) {
ResourceBundle bundle = i18nMessagesMap.get(locale);
if (bundle != null) {
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
}
}
return fallbackMessagesMap.getString(key); // definitely exists
}

public static void setLocale(LangLocale locale) {
if (i18nMessagesMap.containsKey(locale)) {
currentLocale = locale;
} else {
currentLocale = i18nLocales.get(0);
}
localizedMessagesMap = i18nMessagesMap.get(currentLocale);
}

public static Vector<LangLocale> getI18nLocales() {
return i18nLocales;
}

public static LangLocale currentLocale() {
return currentLocale;
}

public static LangLocale defaultLocale() {
if (i18nMessagesMap.containsKey(localLocale)) {
return localLocale;
}
// fallback to english if unsupported
return i18nLocales.get(0);
}
}

0 comments on commit 5281eed

Please sign in to comment.