diff --git a/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java b/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java index 9d4af43..9c1b4d4 100755 --- a/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java +++ b/src/main/java/ru/windcorp/progressia/client/graphics/gui/LayerTestGUI.java @@ -27,6 +27,9 @@ import ru.windcorp.progressia.client.graphics.gui.event.HoverEvent; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical; import ru.windcorp.progressia.client.graphics.input.KeyEvent; +import ru.windcorp.progressia.client.localization.Localizer; + +import java.net.http.WebSocket; public class LayerTestGUI extends GUILayer { @@ -77,13 +80,15 @@ public class LayerTestGUI extends GUILayer { Component charlie = new DebugComponent("Charlie", null, 0x222222); charlie.setLayout(new LayoutVertical()); - + + //Debug + Localizer.getInstance().setLanguage("ru-RU"); // These two are swapped in code due to a bug in layouts, fixing ATM charlie.addChild( new Label( "Epsilon", new Font().withColor(0x4444BB).deriveItalic(), - "Hooray?.. \u269b" + Localizer.getInstance().getValue("Epsilon")+"\u269b" ) ); charlie.addChild( diff --git a/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java new file mode 100644 index 0000000..933e75a --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/localization/LocaleListener.java @@ -0,0 +1,6 @@ +package ru.windcorp.progressia.client.localization; + +@FunctionalInterface +public interface LocaleListener { + void onLocaleChanged(String newLanguage); +} \ No newline at end of file diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java new file mode 100644 index 0000000..99780e6 --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/localization/Localizer.java @@ -0,0 +1,76 @@ +package ru.windcorp.progressia.client.localization; + +import java.lang.ref.WeakReference; +import java.util.*; + +public class Localizer { + private static final Localizer instance = new Localizer("assets/languages/lang_list.txt"); + + private final Parser langParser; + + private String language; + private final String langFolder; + + private Map data; + private final Map langList; + + private final Collection> listeners = + Collections.synchronizedCollection(new LinkedList<>()); + + //lang list must be in the same folder as .lang files + public Localizer(String langList) { + this.langFolder = langList.concat("/../"); + langParser = new Parser(langList); + this.langList = langParser.parse(); + } + + public synchronized void setLanguage(String language) { + if (langList.containsKey(language)) { + this.language = language; + langParser.setFilePath(langFolder + language + ".lang"); + data = langParser.parse(); + pokeListeners(language); + } else { + throw new RuntimeException("Language not found: " + language); + } + } + + public synchronized String getLanguage() { + return language; + } + + public synchronized String getValue(String key) { + try { + return data.getOrDefault(key, key); + } catch (NullPointerException e) { + e.printStackTrace(); + return key; + } + } + + private void pokeListeners(String newLanguage) { + synchronized (listeners) { + Iterator> iterator = listeners.iterator(); + while (iterator.hasNext()) { + LocaleListener listenerOrNull = iterator.next().get(); + if (listenerOrNull == null) { + iterator.remove(); + } else { + listenerOrNull.onLocaleChanged(newLanguage); + } + } + } + } + + public static Localizer getInstance() { + return instance; + } + + public void addListener(LocaleListener listener) { + listeners.add(new WeakReference<>(listener)); + } + + public void removeListener(LocaleListener listener) { + listeners.removeIf(ref -> listener.equals(ref.get())); + } +} diff --git a/src/main/java/ru/windcorp/progressia/client/localization/Parser.java b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java new file mode 100644 index 0000000..bb09b2d --- /dev/null +++ b/src/main/java/ru/windcorp/progressia/client/localization/Parser.java @@ -0,0 +1,94 @@ +package ru.windcorp.progressia.client.localization; + +import ru.windcorp.jputil.chars.EscapeException; +import ru.windcorp.jputil.chars.Escaper; +import ru.windcorp.progressia.common.resource.ResourceManager; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.util.HashMap; +import java.util.Map; + +public class Parser { + + public Parser(String filePath) { + this.filePath = filePath; + } + + public void setFilePath(String filePath) { + this.filePath = filePath; + } + + public Map parse() { + Map parsedData = new HashMap<>(); + try (Reader rawData = ResourceManager + .getResource(filePath) + .getReader() + ) { + int code; + char c; + StringBuilder stringBuilder = new StringBuilder(); + while (true) { + code = rawData.read(); + if (code == -1) { + break; + } + c = (char)code; + if (c == '#') { + while (c != '\n') { + code = rawData.read(); + if (code == -1) { + break; + } + c = (char)code; + } + } else if (c == ' ') { + code = rawData.read(); + if (code == -1) { + break; + } + c = (char) code; + if (c == '=') { + String key = escaper.escape(stringBuilder.toString()); + stringBuilder.setLength(0); + rawData.read(); //skip a char + while (true) { + code = rawData.read(); + if (code == -1) { + break; + } + + c = (char) code; + if (code == '\n') { + break; + } else { + stringBuilder.append(c); + } + } + parsedData.put(escaper.unescape(key), + escaper.unescape(stringBuilder.toString())); + stringBuilder.setLength(0); + } + } else if (c == '\n') { + stringBuilder.setLength(0); + } else { + stringBuilder.append(c); + } + } + + } catch (IOException | EscapeException e) { + throw new RuntimeException(e); + } + return parsedData; + } + + public String getFilePath() { + return filePath; + } + + + private String filePath; + static private final Escaper escaper = new Escaper.EscaperBuilder() + .withChars("n", "\n").build(); +} diff --git a/src/main/resources/assets/languages/en-US.lang b/src/main/resources/assets/languages/en-US.lang new file mode 100644 index 0000000..47af087 --- /dev/null +++ b/src/main/resources/assets/languages/en-US.lang @@ -0,0 +1,3 @@ +# ru-RU +#test +Epsilon = Hooray?.. \ No newline at end of file diff --git a/src/main/resources/assets/languages/lang_list.txt b/src/main/resources/assets/languages/lang_list.txt new file mode 100644 index 0000000..d2d4cc1 --- /dev/null +++ b/src/main/resources/assets/languages/lang_list.txt @@ -0,0 +1,2 @@ +en-US = US English +ru-RU = Русский \ No newline at end of file diff --git a/src/main/resources/assets/languages/ru-RU.lang b/src/main/resources/assets/languages/ru-RU.lang new file mode 100644 index 0000000..823e6ad --- /dev/null +++ b/src/main/resources/assets/languages/ru-RU.lang @@ -0,0 +1,3 @@ +# ru-RU +#test +Epsilon = Ура? \ No newline at end of file