From b65115616cb1a367ef9d767d9d440b8e6445c8d9 Mon Sep 17 00:00:00 2001 From: Matthew Miller Date: Sat, 1 Jun 2019 23:14:37 +1000 Subject: [PATCH] Setup the file loading system for translations --- worldedit-core/build.gradle | 22 +++++ .../java/com/sk89q/worldedit/WorldEdit.java | 2 +- .../worldedit/util/io/ResourceLoader.java | 13 +++ .../util/translation/TranslationManager.java | 85 +++++++++++++++++-- .../src/main/resources/lang/.gitignore | 1 + .../src/main/resources/lang/strings.json | 3 + 6 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 worldedit-core/src/main/resources/lang/.gitignore create mode 100644 worldedit-core/src/main/resources/lang/strings.json diff --git a/worldedit-core/build.gradle b/worldedit-core/build.gradle index 9ed0f8b2aa..4025618f31 100644 --- a/worldedit-core/build.gradle +++ b/worldedit-core/build.gradle @@ -1,5 +1,6 @@ plugins { id("net.ltgt.apt") version "0.21" + id "com.mendhak.gradlecrowdin" version "0.1.0" } apply plugin: 'java-library' @@ -50,3 +51,24 @@ sourceSets { } } } + +if (project.hasProperty("crowdin_apikey")) { + build.dependsOn(crowdinUpload) + build.dependsOn(crowdinDownload) +} else { + ext.crowdin_apikey = "" +} + +crowdinUpload { + apiKey = "${crowdin_apikey}" + projectId = 'worldedit-core' + files = [ + [ name: 'strings.json', source: "$projectDir/worldedit-core/src/main/resources/lang/strings.json" ] + ] +} + +crowdinDownload { + apiKey = "${crowdin_apikey}" + destination = "$projectDir/worldedit-core/src/main/resources/lang" + projectId = 'worldedit-core' +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java index 7a281dd435..d60addf1fc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/WorldEdit.java @@ -108,7 +108,7 @@ public final class WorldEdit { private final SessionManager sessions = new SessionManager(this); private final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));; private final Supervisor supervisor = new SimpleSupervisor(); - private final TranslationManager translationManager = new TranslationManager(); + private final TranslationManager translationManager = new TranslationManager(this); private final BlockFactory blockFactory = new BlockFactory(this); private final ItemFactory itemFactory = new ItemFactory(this); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java index 09ac4724f3..1f35553537 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/io/ResourceLoader.java @@ -40,4 +40,17 @@ public static URL getResource(Class clazz, String name) throws IOException { } return url; } + + public static URL getResourceRoot(String name) throws IOException { + URL url = ResourceLoader.class.getResource("/" + name); + if (url == null) { + try { + return new URL("modjar://worldedit/" + name); + } catch (Exception e) { + // Not forge. + } + throw new IOException("Could not find " + name); + } + return url; + } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java index 69fbf9c5fd..25b7fe7a6c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/translation/TranslationManager.java @@ -19,38 +19,109 @@ package com.sk89q.worldedit.util.translation; +import com.google.common.io.Files; +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.util.formatting.text.renderer.FriendlyComponentRenderer; +import com.sk89q.worldedit.util.io.ResourceLoader; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Type; +import java.net.URL; +import java.nio.charset.Charset; import java.text.MessageFormat; import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; public class TranslationManager { + private static final Gson gson = new GsonBuilder().create(); + private static final Type STRING_MAP_TYPE = new TypeToken>() {}.getType(); + private final Map> translationMap = new HashMap<>(); private final FriendlyComponentRenderer friendlyComponentRenderer = FriendlyComponentRenderer.from( (locale, key) -> new MessageFormat(getTranslationMap(locale).getOrDefault(key, key), locale)); - private Locale defaultLocale = Locale.US; + private Locale defaultLocale = Locale.ENGLISH; + + private final WorldEdit worldEdit; + + private final Set checkedLocales = new HashSet<>(); - public TranslationManager() { - // Temporary store until we have file loads - Map us = new HashMap<>(); - us.put("worldedit.region.expanded", "Region expanded {0} block(s)"); - translationMap.put(Locale.US, us); + public TranslationManager(WorldEdit worldEdit) { + this.worldEdit = worldEdit; } public void setDefaultLocale(Locale defaultLocale) { this.defaultLocale = defaultLocale; } + private Map parseTranslationFile(File file) throws IOException { + return gson.fromJson(Files.toString(file, Charset.defaultCharset()), STRING_MAP_TYPE); + } + + private Map parseTranslationFile(URL file) throws IOException { + return gson.fromJson(Resources.toString(file, Charset.defaultCharset()), STRING_MAP_TYPE); + } + + private Optional> loadTranslationFile(String filename) { + File localFile = worldEdit.getWorkingDirectoryFile("lang/" + filename); + if (localFile.exists()) { + try { + return Optional.of(parseTranslationFile(localFile)); + } catch (IOException e) { + return Optional.empty(); + } + } else { + try { + return Optional.of(parseTranslationFile(ResourceLoader.getResourceRoot("lang/" + filename))); + } catch (IOException e) { + return Optional.empty(); + } + } + } + + private boolean tryLoadTranslations(Locale locale) { + if (checkedLocales.contains(locale)) { + return false; + } + checkedLocales.add(locale); + Optional> langData = loadTranslationFile(locale.getLanguage() + "-" + locale.getCountry() + "/strings.json"); + if (!langData.isPresent()) { + langData = loadTranslationFile(locale.getLanguage() + "/strings.json"); + } + if (langData.isPresent()) { + translationMap.put(locale, langData.get()); + return true; + } + if (locale.equals(defaultLocale)) { + translationMap.put(Locale.ENGLISH, loadTranslationFile("strings.json").orElseThrow( + () -> new RuntimeException("Failed to load WorldEdit strings!") + )); + return true; + } + return false; + } + private Map getTranslationMap(Locale locale) { Map translations = translationMap.get(locale); if (translations == null) { - translations = translationMap.get(defaultLocale); + if (tryLoadTranslations(locale)) { + return getTranslationMap(locale); + } + if (!locale.equals(defaultLocale)) { + translations = getTranslationMap(defaultLocale); + } } return translations; diff --git a/worldedit-core/src/main/resources/lang/.gitignore b/worldedit-core/src/main/resources/lang/.gitignore new file mode 100644 index 0000000000..0a00d70141 --- /dev/null +++ b/worldedit-core/src/main/resources/lang/.gitignore @@ -0,0 +1 @@ +*/ \ No newline at end of file diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json new file mode 100644 index 0000000000..aefeb2d34c --- /dev/null +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -0,0 +1,3 @@ +{ + "worldedit.region.expanded": "Region expanded {0} block(s)" +} \ No newline at end of file