Rebase translation work for easier rebasing

This commit is contained in:
Matthew Miller
2019-10-13 21:47:26 +10:00
parent 77ef0ae417
commit 96e56bdd0c
80 changed files with 1155 additions and 359 deletions

View File

@ -19,11 +19,14 @@
package com.sk89q.worldedit.util.formatting;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.util.formatting.text.Component;
import org.enginehub.piston.config.ConfigHolder;
import org.enginehub.piston.config.TextConfig;
import org.enginehub.piston.util.TextHelper;
import java.util.Locale;
public class WorldEditText {
public static final ConfigHolder CONFIG_HOLDER = ConfigHolder.create();
@ -31,12 +34,12 @@ public class WorldEditText {
CONFIG_HOLDER.getConfig(TextConfig.commandPrefix()).setValue("/");
}
public static Component format(Component component) {
return CONFIG_HOLDER.replace(component);
public static Component format(Component component, Locale locale) {
return CONFIG_HOLDER.replace(WorldEdit.getInstance().getTranslationManager().convertText(component, locale));
}
public static String reduceToText(Component component) {
return TextHelper.reduceToText(format(component));
public static String reduceToText(Component component, Locale locale) {
return TextHelper.reduceToText(format(component, locale));
}
private WorldEditText() {

View File

@ -36,13 +36,22 @@ public class MessageBox extends TextComponentProducer {
private static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 47;
private TextComponentProducer contents;
private TextColor borderColor;
/**
* Create a new box.
*/
public MessageBox(String title, TextComponentProducer contents) {
this(title, contents, TextColor.YELLOW);
}
/**
* Create a new box.
*/
public MessageBox(String title, TextComponentProducer contents, TextColor borderColor) {
checkNotNull(title);
this.borderColor = borderColor;
append(centerAndBorder(TextComponent.of(title))).newline();
this.contents = contents;
}
@ -74,7 +83,7 @@ public class MessageBox extends TextComponentProducer {
private TextComponent createBorder(int count) {
return TextComponent.of(Strings.repeat("-", count),
TextColor.YELLOW, Sets.newHashSet(TextDecoration.STRIKETHROUGH));
borderColor, Sets.newHashSet(TextDecoration.STRIKETHROUGH));
}
/**

View File

@ -0,0 +1,49 @@
/*
* 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 Lesser 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.
*
* 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/>.
*/
package com.sk89q.worldedit.util.formatting.component;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import java.util.List;
public class TextUtils {
private TextUtils() {
}
/**
* Join an array of components with a joiner component.
*
* @param components The components to join
* @param joiner The joiner component
* @return The joined component
*/
public static Component join(List<Component> components, Component joiner) {
TextComponent.Builder builder = TextComponent.builder();
for (int i = 0; i < components.size(); i++) {
builder.append(components.get(i));
if (i < components.size() - 1) {
builder.append(joiner);
}
}
return builder.build();
}
}

View File

@ -40,4 +40,17 @@ public class ResourceLoader {
}
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;
}
}

View File

@ -21,6 +21,8 @@ package com.sk89q.worldedit.util.paste;
import com.sk89q.worldedit.command.util.AsyncCommandBuilder;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.task.Supervisor;
import java.net.URL;
@ -41,7 +43,9 @@ public final class ActorCallbackPaste {
* @param sender The sender
* @param content The content
* @param successMessage The message, formatted with {@link String#format(String, Object...)} on success
* @deprecated Use the Component-based version
*/
@Deprecated
public static void pastebin(Supervisor supervisor, final Actor sender, String content, final String successMessage) {
Callable<URL> task = paster.paste(content);
@ -53,4 +57,24 @@ public final class ActorCallbackPaste {
.buildAndExec(Pasters.getExecutor());
}
/**
* Submit data to a pastebin service and inform the sender of
* success or failure.
*
* @param supervisor The supervisor instance
* @param sender The sender
* @param content The content
* @param successMessage The message builder, given the URL as an arg
*/
public static void pastebin(Supervisor supervisor, final Actor sender, String content, final TranslatableComponent.Builder successMessage) {
Callable<URL> task = paster.paste(content);
AsyncCommandBuilder.wrap(task, sender)
.registerWithSupervisor(supervisor, "Submitting content to a pastebin service.")
.sendMessageAfterDelay(TranslatableComponent.of("worldedit.pastebin.uploading"))
.onSuccess((String) null, url -> sender.printInfo(successMessage.args(TextComponent.of(url.toString())).build()))
.onFailure("Failed to submit paste", null)
.buildAndExec(Pasters.getExecutor());
}
}

View File

@ -0,0 +1,42 @@
/*
* 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 Lesser 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.
*
* 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/>.
*/
package com.sk89q.worldedit.util.translation;
public class LocalisationHelpers {
private LocalisationHelpers() {
}
/**
* Turn a translation key into a ".singular" or ".plural"
* depending on what the given number is.
*
* @param translationKey The base translation key
* @param number The number
* @return The key with .plural or .singular appended
*/
public static String pluraliseI18n(String translationKey, float number) {
if (number == 1) {
return translationKey + ".singular";
} else {
return translationKey + ".plural";
}
}
}

View File

@ -0,0 +1,144 @@
/*
* 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 Lesser 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.
*
* 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/>.
*/
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.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.nio.charset.StandardCharsets;
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;
/**
* Handles translations for the plugin.
*
* These should be in the following format:
* plugin.component.message[.meta]*
*
* 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)
*/
public class TranslationManager {
private static final Gson gson = new GsonBuilder().create();
private static final Type STRING_MAP_TYPE = new TypeToken<Map<String, String>>() {}.getType();
private final Map<Locale, Map<String, String>> translationMap = new HashMap<>();
private final FriendlyComponentRenderer<Locale> friendlyComponentRenderer = FriendlyComponentRenderer.from(
(locale, key) -> new MessageFormat(getTranslationMap(locale).getOrDefault(key, key), locale));
private Locale defaultLocale = Locale.ENGLISH;
private final WorldEdit worldEdit;
private final Set<Locale> checkedLocales = new HashSet<>();
public TranslationManager(WorldEdit worldEdit) {
this.worldEdit = worldEdit;
}
public void setDefaultLocale(Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}
private Map<String, String> parseTranslationFile(File file) throws IOException {
return gson.fromJson(Files.toString(file, StandardCharsets.UTF_8), STRING_MAP_TYPE);
}
private Map<String, String> parseTranslationFile(URL file) throws IOException {
return gson.fromJson(Resources.toString(file, StandardCharsets.UTF_8), STRING_MAP_TYPE);
}
private Optional<Map<String, String>> 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<Map<String, String>> 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<String, String> getTranslationMap(Locale locale) {
Map<String, String> translations = translationMap.get(locale);
if (translations == null) {
if (tryLoadTranslations(locale)) {
return getTranslationMap(locale);
}
if (!locale.equals(defaultLocale)) {
translations = getTranslationMap(defaultLocale);
}
}
return translations;
}
public Component convertText(Component component, Locale locale) {
return friendlyComponentRenderer.render(component, locale);
}
}