mirror of
https://github.com/DiscordSRV/Ascension.git
synced 2025-02-28 03:42:46 +01:00
Translations
This commit is contained in:
parent
c3c5104dfa
commit
8a673875a6
@ -33,6 +33,7 @@ import com.discordsrv.bukkit.player.BukkitPlayerProvider;
|
||||
import com.discordsrv.bukkit.plugin.BukkitPluginManager;
|
||||
import com.discordsrv.bukkit.scheduler.BukkitScheduler;
|
||||
import com.discordsrv.common.command.game.handler.ICommandHandler;
|
||||
import com.discordsrv.common.component.translation.Translation;
|
||||
import com.discordsrv.common.config.manager.ConnectionConfigManager;
|
||||
import com.discordsrv.common.config.manager.MainConfigManager;
|
||||
import com.discordsrv.common.debug.data.OnlineMode;
|
||||
@ -40,6 +41,7 @@ import com.discordsrv.common.logging.Logger;
|
||||
import com.discordsrv.common.messageforwarding.game.MinecraftToDiscordChatModule;
|
||||
import com.discordsrv.common.plugin.PluginManager;
|
||||
import com.discordsrv.common.server.ServerDiscordSRV;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import dev.vankka.dependencydownload.classpath.ClasspathAppender;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import org.bukkit.Server;
|
||||
@ -47,8 +49,14 @@ import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class BukkitDiscordSRV extends ServerDiscordSRV<BukkitConfig, BukkitConnectionConfig> {
|
||||
|
||||
@ -169,13 +177,63 @@ public class BukkitDiscordSRV extends ServerDiscordSRV<BukkitConfig, BukkitConne
|
||||
return configManager;
|
||||
}
|
||||
|
||||
private URL findResource(String name) {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
URL url = null;
|
||||
while (classLoader != null && url == null) {
|
||||
url = classLoader.getResource(name);
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private void loadMCTranslations() {
|
||||
Map<String, Translation> translations = new HashMap<>();
|
||||
try {
|
||||
URL enUS = findResource("assets/minecraft/lang/en_US.lang");
|
||||
if (enUS == null) {
|
||||
enUS = findResource("assets/minecraft/lang/en_us.lang");
|
||||
}
|
||||
if (enUS != null) {
|
||||
Properties properties = new Properties();
|
||||
try (InputStream inputStream = enUS.openStream()) {
|
||||
properties.load(inputStream);
|
||||
}
|
||||
|
||||
properties.forEach((k, v) -> translations.put((String) k, Translation.stringFormat((String) v)));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger().debug("Failed to load locale", t);
|
||||
}
|
||||
try {
|
||||
URL enUS = findResource("assets/minecraft/lang/en_us.json");
|
||||
if (enUS != null) {
|
||||
JsonNode node = json().readTree(enUS);
|
||||
node.fields().forEachRemaining(entry -> translations.put(
|
||||
entry.getKey(),
|
||||
Translation.stringFormat(entry.getValue().textValue()))
|
||||
);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger().debug("Failed to load locale", t);
|
||||
}
|
||||
|
||||
if (translations.isEmpty()) {
|
||||
logger().warning("No Minecraft translations were found, some components may not render correctly");
|
||||
} else {
|
||||
componentFactory().translationRegistry().register(Locale.US, translations);
|
||||
logger().debug("Found " + translations.size() + " Minecraft translations for en_us");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void enable() throws Throwable {
|
||||
// Service provider
|
||||
server().getServicesManager().register(DiscordSRVApi.class, this, plugin(), ServicePriority.Normal);
|
||||
|
||||
// Adventure audiences
|
||||
// Adventure related stuff
|
||||
this.audiences = BukkitAudiences.create(bootstrap.getPlugin());
|
||||
loadMCTranslations();
|
||||
|
||||
// Command handler
|
||||
commandHandler = AbstractBukkitCommandHandler.get(this);
|
||||
|
@ -52,7 +52,7 @@ dependencies {
|
||||
runtimeDownloadApi 'org.spongepowered:configurate-hocon:' + rootProject.configurateVersion
|
||||
|
||||
// Jackson (transitive in :api)
|
||||
compileOnly 'com.fasterxml.jackson.core:jackson-databind:2.13.1'
|
||||
compileOnlyApi 'com.fasterxml.jackson.core:jackson-databind:2.10.1'
|
||||
|
||||
// Logging
|
||||
compileOnlyApi project(':common:common-slf4j-hack')
|
||||
|
@ -23,25 +23,49 @@ import com.discordsrv.api.component.MinecraftComponent;
|
||||
import com.discordsrv.api.component.MinecraftComponentFactory;
|
||||
import com.discordsrv.common.DiscordSRV;
|
||||
import com.discordsrv.common.component.renderer.DiscordSRVMinecraftRenderer;
|
||||
import com.discordsrv.common.component.translation.Translation;
|
||||
import com.discordsrv.common.component.translation.TranslationRegistry;
|
||||
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializer;
|
||||
import dev.vankka.mcdiscordreserializer.discord.DiscordSerializerOptions;
|
||||
import dev.vankka.mcdiscordreserializer.minecraft.MinecraftSerializer;
|
||||
import dev.vankka.mcdiscordreserializer.minecraft.MinecraftSerializerOptions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class ComponentFactory implements MinecraftComponentFactory {
|
||||
|
||||
private final DiscordSRV discordSRV;
|
||||
private final MinecraftSerializer minecraftSerializer;
|
||||
private final DiscordSerializer discordSerializer;
|
||||
|
||||
// Not the same as Adventure's TranslationRegistry
|
||||
private final TranslationRegistry translationRegistry = new TranslationRegistry();
|
||||
|
||||
public ComponentFactory(DiscordSRV discordSRV) {
|
||||
this.discordSRV = discordSRV;
|
||||
this.minecraftSerializer = new MinecraftSerializer(
|
||||
MinecraftSerializerOptions.defaults()
|
||||
.addRenderer(new DiscordSRVMinecraftRenderer(discordSRV))
|
||||
);
|
||||
this.discordSerializer = new DiscordSerializer(DiscordSerializerOptions.defaults());
|
||||
this.discordSerializer = new DiscordSerializer();
|
||||
discordSerializer.setDefaultOptions(
|
||||
DiscordSerializerOptions.defaults()
|
||||
.withTranslationProvider(translatableComponent -> {
|
||||
Translation translation = translationRegistry.lookup(Locale.US, translatableComponent.key());
|
||||
if (translation == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return translation.translate(
|
||||
translatableComponent.args()
|
||||
.stream()
|
||||
.map(discordSerializer::serialize)
|
||||
.map(str -> (Object) str)
|
||||
.toArray(Object[]::new)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -61,4 +85,8 @@ public class ComponentFactory implements MinecraftComponentFactory {
|
||||
public DiscordSerializer discordSerializer() {
|
||||
return discordSerializer;
|
||||
}
|
||||
|
||||
public TranslationRegistry translationRegistry() {
|
||||
return translationRegistry;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV 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.discordsrv.common.component.translation;
|
||||
|
||||
public class StringFormatTranslation implements Translation {
|
||||
|
||||
private final String format;
|
||||
|
||||
public StringFormatTranslation(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String translate(Object[] arguments) {
|
||||
return String.format(format, arguments);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV 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.discordsrv.common.component.translation;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Translation {
|
||||
|
||||
static Translation stringFormat(String format) {
|
||||
return new StringFormatTranslation(format);
|
||||
}
|
||||
|
||||
String translate(Object[] arguments);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of DiscordSRV, licensed under the GPLv3 License
|
||||
* Copyright (c) 2016-2022 Austin "Scarsz" Shapiro, Henri "Vankka" Schubin and DiscordSRV 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.discordsrv.common.component.translation;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Our own simple class that stores abstract {@link Translation}s instead of MessageFormats,
|
||||
* to be more flexible, and support Minecraft's own language files.
|
||||
*/
|
||||
public class TranslationRegistry {
|
||||
|
||||
private static final Locale DEFAULT_LOCALE = Locale.US;
|
||||
|
||||
private final Map<Locale, Map<String, Translation>> translations = new LinkedHashMap<>();
|
||||
|
||||
public TranslationRegistry() {}
|
||||
|
||||
public void register(Locale locale, Map<String, Translation> translations) {
|
||||
synchronized (this.translations) {
|
||||
this.translations.computeIfAbsent(locale, key -> new LinkedHashMap<>()).putAll(translations);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Translation lookup(Locale locale, String key) {
|
||||
synchronized (translations) {
|
||||
return translations.getOrDefault(
|
||||
locale, // Try the suggested locale first
|
||||
translations.getOrDefault(
|
||||
DEFAULT_LOCALE, // Then try the default locale
|
||||
Collections.emptyMap() // Then fail
|
||||
)
|
||||
).get(key);
|
||||
}
|
||||
}
|
||||
}
|
@ -307,6 +307,7 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
try {
|
||||
return mapExceptions(futureSupplier.get());
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
CompletableFuture<T> future = new CompletableFuture<>();
|
||||
future.completeExceptionally(t);
|
||||
return future;
|
||||
@ -314,16 +315,16 @@ public class DiscordAPIImpl implements DiscordAPI {
|
||||
}
|
||||
|
||||
public <T> CompletableFuture<T> mapExceptions(CompletableFuture<T> future) {
|
||||
return future.handle((msg, t) -> {
|
||||
return future.handle((response, t) -> {
|
||||
if (t instanceof ErrorResponseException) {
|
||||
ErrorResponseException exception = (ErrorResponseException) t;
|
||||
int code = exception.getErrorCode();
|
||||
ErrorResponse response = exception.getErrorResponse();
|
||||
throw new RestErrorResponseException(code, response != null ? response.getMeaning() : "Unknown", t);
|
||||
ErrorResponse errorResponse = exception.getErrorResponse();
|
||||
throw new RestErrorResponseException(code, errorResponse != null ? errorResponse.getMeaning() : "Unknown", t);
|
||||
} else if (t != null) {
|
||||
throw (RuntimeException) t;
|
||||
}
|
||||
return msg;
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user