mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-07-01 02:46:41 +00:00
Upstream merge of TranslationManager and ResourceLoader
This commit is contained in:
@ -3,52 +3,79 @@
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class ResourceLoader {
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
private ResourceLoader() {
|
||||
/**
|
||||
* An abstract loader that handles loading resources from bundled URLs or local
|
||||
* files.
|
||||
*/
|
||||
public interface ResourceLoader {
|
||||
|
||||
/**
|
||||
* Gets the bundled resource URL by name, relative to the provided class.
|
||||
*
|
||||
* <p>
|
||||
* The path name <b>must not</b> start with {@code /}.
|
||||
* </p>
|
||||
*
|
||||
* @param clazz The class to search relative to
|
||||
* @param pathName The path name
|
||||
* @return The URL to this bundled resource
|
||||
* @throws IOException if an IO issue occurs
|
||||
*/
|
||||
@Nullable
|
||||
default URL getResource(Class<?> clazz, String pathName) throws IOException {
|
||||
checkArgument(!pathName.startsWith("/"), "pathName must not start with /");
|
||||
String qualifiedName = clazz.getName().substring(0, clazz.getName().lastIndexOf('.'))
|
||||
.replace(".", "/") + "/" + pathName;
|
||||
return getRootResource(qualifiedName);
|
||||
}
|
||||
|
||||
private static URL getResourceForgeHack(String location) throws IOException {
|
||||
try {
|
||||
return new URL("modjar://worldedit/" + location);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Could not find " + location);
|
||||
}
|
||||
/**
|
||||
* Gets the bundled resource URL by name.
|
||||
*
|
||||
* <p>
|
||||
* The path name <b>must not</b> start with {@code /}. It is always
|
||||
* absolute.
|
||||
* </p>
|
||||
*
|
||||
* @param pathName The path name
|
||||
* @return The URL to this bundled resource
|
||||
* @throws IOException if an IO issue occurs
|
||||
*/
|
||||
@Nullable
|
||||
default URL getRootResource(String pathName) throws IOException {
|
||||
checkArgument(!pathName.startsWith("/"), "pathName must not start with /");
|
||||
return this.getClass().getClassLoader().getResource(pathName);
|
||||
}
|
||||
|
||||
public static URL getResource(Class clazz, String name) throws IOException {
|
||||
URL url = clazz.getResource(name);
|
||||
if (url == null) {
|
||||
return getResourceForgeHack(clazz.getName().substring(0, clazz.getName().lastIndexOf('.')).replace(".", "/")
|
||||
+ "/" + name);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
public static URL getResourceRoot(String name) throws IOException {
|
||||
URL url = ResourceLoader.class.getResource("/" + name);
|
||||
if (url == null) {
|
||||
return getResourceForgeHack(name);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
/**
|
||||
* Gets the {@link Path} reference to this local resource. The file may not
|
||||
* exist.
|
||||
*
|
||||
* @param pathName The path name
|
||||
* @return The path reference
|
||||
*/
|
||||
Path getLocalResource(String pathName);
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* WorldEdit, a Minecraft world manipulation toolkit
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.io;
|
||||
|
||||
import com.sk89q.worldedit.WorldEdit;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class WorldEditResourceLoader implements ResourceLoader {
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
|
||||
public WorldEditResourceLoader(WorldEdit worldEdit) {
|
||||
this.worldEdit = worldEdit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getLocalResource(String pathName) {
|
||||
return this.worldEdit.getWorkingDirectoryPath(pathName);
|
||||
}
|
||||
}
|
@ -3,18 +3,18 @@
|
||||
* Copyright (C) sk89q <http://www.sk89q.com>
|
||||
* Copyright (C) WorldEdit team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sk89q.worldedit.util.translation;
|
||||
@ -23,19 +23,19 @@ import com.google.common.collect.Maps;
|
||||
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.renderer.FriendlyComponentRenderer;
|
||||
import com.sk89q.worldedit.util.formatting.text.renderer.TranslatableComponentRenderer;
|
||||
import com.sk89q.worldedit.util.io.ResourceLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
@ -44,36 +44,55 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static java.util.stream.Collectors.toMap;
|
||||
|
||||
/**
|
||||
* Handles translations for the plugin.
|
||||
*
|
||||
* <p>
|
||||
* These should be in the following format:
|
||||
* plugin.component.message[.meta]*
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Where,
|
||||
* plugin = worldedit
|
||||
* component = The part of the plugin, eg expand
|
||||
* message = A descriptor for which message, eg, expanded
|
||||
* meta = Any extra information such as plural/singular (Can have none to infinite)
|
||||
* </p>
|
||||
*/
|
||||
public class TranslationManager {
|
||||
|
||||
private static final Gson gson = new GsonBuilder().create();
|
||||
private static final Type STRING_MAP_TYPE = new TypeToken<Map<String, String>>() {}.getType();
|
||||
|
||||
public static String makeTranslationKey(String type, String id) {
|
||||
String[] parts = id.split(":", 2);
|
||||
return type + '.' + parts[0] + '.' + parts[1].replace('/', '.');
|
||||
}
|
||||
|
||||
private final Map<Locale, Map<String, String>> translationMap = new ConcurrentHashMap<>();
|
||||
private final FriendlyComponentRenderer<Locale> friendlyComponentRenderer = FriendlyComponentRenderer.from(
|
||||
(locale, key) -> new MessageFormat(getTranslationMap(locale).getOrDefault(key, key), locale));
|
||||
private final TranslatableComponentRenderer<Locale> friendlyComponentRenderer = TranslatableComponentRenderer.from(
|
||||
(locale, key) -> {
|
||||
String translation = getTranslationMap(locale).get(key);
|
||||
if (translation == null) {
|
||||
// let it pass through (for e.g. MC messages)
|
||||
return null;
|
||||
}
|
||||
return new MessageFormat(translation, locale);
|
||||
}
|
||||
);
|
||||
private Locale defaultLocale = Locale.ENGLISH;
|
||||
|
||||
private final WorldEdit worldEdit;
|
||||
private final ResourceLoader resourceLoader;
|
||||
|
||||
private final Set<Locale> checkedLocales = new HashSet<>();
|
||||
|
||||
public TranslationManager(WorldEdit worldEdit) {
|
||||
this.worldEdit = worldEdit;
|
||||
public TranslationManager(ResourceLoader resourceLoader) {
|
||||
checkNotNull(resourceLoader);
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
public void setDefaultLocale(Locale defaultLocale) {
|
||||
@ -94,18 +113,22 @@ public class TranslationManager {
|
||||
}
|
||||
|
||||
private Optional<Map<String, String>> loadTranslationFile(String filename) {
|
||||
Map<String, String> baseTranslations;
|
||||
Map<String, String> baseTranslations = new ConcurrentHashMap<>();
|
||||
|
||||
try (InputStream stream = ResourceLoader.getResourceRoot("lang/" + filename).openStream()) {
|
||||
baseTranslations = parseTranslationFile(stream);
|
||||
try {
|
||||
URL resource = resourceLoader.getRootResource("lang/" + filename);
|
||||
if (resource != null) {
|
||||
try (InputStream stream = resource.openStream()) {
|
||||
baseTranslations = parseTranslationFile(stream);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Seem to be missing base. If the user has provided a file use that.
|
||||
baseTranslations = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
File localFile = worldEdit.getWorkingDirectoryFile("lang/" + filename);
|
||||
if (localFile.exists()) {
|
||||
try (InputStream stream = new FileInputStream(localFile)) {
|
||||
Path localFile = resourceLoader.getLocalResource("lang/" + filename);
|
||||
if (Files.exists(localFile)) {
|
||||
try (InputStream stream = Files.newInputStream(localFile)) {
|
||||
baseTranslations.putAll(parseTranslationFile(stream));
|
||||
} catch (IOException e) {
|
||||
// Failed to parse custom language file. Worth printing.
|
||||
@ -126,7 +149,10 @@ public class TranslationManager {
|
||||
if (!locale.equals(defaultLocale)) {
|
||||
baseTranslations.putAll(getTranslationMap(defaultLocale));
|
||||
}
|
||||
Optional<Map<String, String>> langData = loadTranslationFile(locale.getLanguage() + "-" + locale.getCountry() + "/strings.json");
|
||||
Optional<Map<String, String>> langData = Optional.empty();
|
||||
if (!locale.getCountry().isEmpty()) {
|
||||
langData = loadTranslationFile(locale.getLanguage() + "-" + locale.getCountry() + "/strings.json");
|
||||
}
|
||||
if (!langData.isPresent()) {
|
||||
langData = loadTranslationFile(locale.getLanguage() + "/strings.json");
|
||||
}
|
||||
@ -137,7 +163,7 @@ public class TranslationManager {
|
||||
}
|
||||
if (locale.equals(defaultLocale)) {
|
||||
translationMap.put(Locale.ENGLISH, loadTranslationFile("strings.json").orElseThrow(
|
||||
() -> new RuntimeException("Failed to load WorldEdit strings!")
|
||||
() -> new RuntimeException("Failed to load WorldEdit strings!")
|
||||
));
|
||||
return true;
|
||||
}
|
||||
|
Reference in New Issue
Block a user