New i18n/config system. Close #4.

This commit is contained in:
IzzelAliz 2020-06-09 21:22:16 +08:00
parent 1cdf76895c
commit 089216b6a6
25 changed files with 579 additions and 84 deletions

View File

@ -60,6 +60,7 @@ dependencies {
compile 'mysql:mysql-connector-java:5.1.47'
compile 'org.yaml:snakeyaml:1.23'
compile project(':arclight-api')
compile project(':i18n-config')
}
remapSpigotJar {

View File

@ -1,12 +1,12 @@
package io.izzel.arclight.common.mixin.bukkit;
import io.izzel.arclight.common.mod.util.log.ArclightPluginLogger;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLogger;
import org.bukkit.plugin.java.JavaPlugin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import io.izzel.arclight.common.mod.util.ArclightPluginLogger;
@Mixin(JavaPlugin.class)
public class JavaPluginMixin {

View File

@ -128,10 +128,10 @@ public abstract class PlayerListMixin implements PlayerListBridge {
t.printStackTrace();
}
try {
ArclightMod.LOGGER.info("Registering for bukkit... ");
ArclightMod.LOGGER.info("registry.begin");
BukkitRegistry.registerAll();
} catch (Throwable t) {
ArclightMod.LOGGER.error("Error handling Forge registries ", t);
ArclightMod.LOGGER.error("registry.error", t);
}
}

View File

@ -1,41 +0,0 @@
package io.izzel.arclight.common.mod;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
public class ArclightConfig {
public static ArclightConfig INSTANCE;
public Optimization optimizations;
static void init(Path path) {
ArclightConnector.LOGGER.info("Loading configurations from {}", path);
try {
if (!Files.exists(path)) {
InputStream stream = ArclightConfig.class.getResourceAsStream("/arclight.yml");
Files.copy(stream, path);
}
} catch (IOException e) {
ArclightConnector.LOGGER.error("Failed to save default configurations", e);
}
try {
Yaml yaml = new Yaml(new Constructor(ArclightConfig.class));
Object load = yaml.load(Files.newInputStream(path));
INSTANCE = (ArclightConfig) load;
} catch (IOException e) {
ArclightConnector.LOGGER.error("Failed to load configurations", e);
}
}
public static class Optimization {
public boolean removeStreams = true;
}
}

View File

@ -1,27 +1,33 @@
package io.izzel.arclight.common.mod;
import org.apache.logging.log4j.LogManager;
import cpw.mods.modlauncher.api.ITransformingClassLoader;
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
import io.izzel.arclight.i18n.ArclightConfig;
import org.apache.logging.log4j.Logger;
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.asm.mixin.connect.IMixinConnector;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
public class ArclightConnector implements IMixinConnector {
public static final Logger LOGGER = LogManager.getLogger("Arclight");
public static final Logger LOGGER = ArclightI18nLogger.getLogger("Arclight");
private static final List<String> FILTER_PACKAGE = Arrays.asList("com.google.common", "com.google.gson", "ninja.leaping.configurate");
@Override
public void connect() {
((ITransformingClassLoader) Thread.currentThread().getContextClassLoader()).addTargetPackageFilter(
s -> FILTER_PACKAGE.stream().noneMatch(s::startsWith)
);
Mixins.addConfiguration("mixins.arclight.core.json");
Mixins.addConfiguration("mixins.arclight.bukkit.json");
Mixins.addConfiguration("mixins.arclight.forge.json");
LOGGER.info("Arclight core mixin added.");
ArclightConfig.init(Paths.get("arclight.yml"));
LOGGER.info("mixin-load.core");
Mixins.addConfiguration("mixins.arclight.optimization.json");
if (ArclightConfig.INSTANCE.optimizations.removeStreams) {
if (ArclightConfig.spec().getOptimization().isRemoveStream()) {
Mixins.addConfiguration("mixins.arclight.optimization.stream.json");
}
LOGGER.info("Arclight optimization mixin added.");
LOGGER.info("mixin-load.optimization");
}
}

View File

@ -4,8 +4,6 @@ import com.google.common.collect.ImmutableList;
import net.minecraftforge.fml.loading.moddiscovery.AbstractJarFileLocator;
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
import net.minecraftforge.forgespi.locating.IModFile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.net.URISyntaxException;
@ -14,8 +12,6 @@ import java.util.Map;
public class ArclightLocator extends AbstractJarFileLocator {
private static final Logger LOGGER = LogManager.getLogger("Arclight");
private final IModFile arclight;
public ArclightLocator() {
@ -39,6 +35,5 @@ public class ArclightLocator extends AbstractJarFileLocator {
@Override
public void initArguments(Map<String, ?> arguments) {
LOGGER.info("Arclight locator loaded.");
}
}

View File

@ -1,23 +1,23 @@
package io.izzel.arclight.common.mod;
import io.izzel.arclight.common.mod.server.event.ArclightEventDispatcherRegistry;
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
import net.minecraftforge.fml.CrashReportExtender;
import net.minecraftforge.fml.ExtensionPoint;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.network.FMLNetworkConstants;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.craftbukkit.v.CraftCrashReport;
@Mod("arclight")
public class ArclightMod {
public static final Logger LOGGER = LogManager.getLogger("Arclight");
public static final Logger LOGGER = ArclightI18nLogger.getLogger("Arclight");
public ArclightMod() {
LOGGER.info("Arclight Mod loaded.");
LOGGER.info("mod-load");
ArclightEventDispatcherRegistry.registerAllEventDispatchers();
CrashReportExtender.registerCrashCallable("Arclight", () -> new CraftCrashReport().call().toString());
ModLoadingContext.get().registerExtensionPoint(ExtensionPoint.DISPLAYTEST, () -> Pair.of(() -> FMLNetworkConstants.IGNORESERVERONLY, (a, b) -> true));

View File

@ -2,6 +2,11 @@ package io.izzel.arclight.common.mod.server;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import io.izzel.arclight.api.EnumHelper;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.potion.ArclightPotionEffect;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.potion.Effect;
@ -15,11 +20,6 @@ import org.bukkit.craftbukkit.v.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.v.util.CraftNamespacedKey;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.potion.PotionEffectType;
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.potion.ArclightPotionEffect;
import io.izzel.arclight.api.EnumHelper;
import io.izzel.arclight.api.Unsafe;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -31,12 +31,12 @@ import java.util.Set;
@SuppressWarnings({"unchecked", "ConstantConditions"})
public class BukkitRegistry {
private static List<Class<?>> MAT_CTOR = ImmutableList.of(int.class, int.class, int.class);
private static Map<String, Material> BY_NAME = getStatic(Material.class, "BY_NAME");
private static Map<Block, Material> BLOCK_MATERIAL = getStatic(CraftMagicNumbers.class, "BLOCK_MATERIAL");
private static Map<Item, Material> ITEM_MATERIAL = getStatic(CraftMagicNumbers.class, "ITEM_MATERIAL");
private static Map<Material, Item> MATERIAL_ITEM = getStatic(CraftMagicNumbers.class, "MATERIAL_ITEM");
private static Map<Material, Block> MATERIAL_BLOCK = getStatic(CraftMagicNumbers.class, "MATERIAL_BLOCK");
private static final List<Class<?>> MAT_CTOR = ImmutableList.of(int.class, int.class, int.class);
private static final Map<String, Material> BY_NAME = getStatic(Material.class, "BY_NAME");
private static final Map<Block, Material> BLOCK_MATERIAL = getStatic(CraftMagicNumbers.class, "BLOCK_MATERIAL");
private static final Map<Item, Material> ITEM_MATERIAL = getStatic(CraftMagicNumbers.class, "ITEM_MATERIAL");
private static final Map<Material, Item> MATERIAL_ITEM = getStatic(CraftMagicNumbers.class, "MATERIAL_ITEM");
private static final Map<Material, Block> MATERIAL_BLOCK = getStatic(CraftMagicNumbers.class, "MATERIAL_BLOCK");
public static void registerAll() {
loadMaterials();
@ -52,7 +52,7 @@ public class BukkitRegistry {
Enchantment.registerEnchantment(new CraftEnchantment(entry.getValue()));
}
Enchantment.stopAcceptingRegistrations();
ArclightMod.LOGGER.info("Registered {} new enchantments", size - origin);
ArclightMod.LOGGER.info("registry.enchantment", size - origin);
}
private static void loadPotions() {
@ -68,7 +68,7 @@ public class BukkitRegistry {
ArclightMod.LOGGER.debug("Registered {}: {} as potion", entry.getKey(), effect);
}
PotionEffectType.stopAcceptingRegistrations();
ArclightMod.LOGGER.info("Registered {} new potion effect types", size - origin);
ArclightMod.LOGGER.info("registry.potion", size - origin);
}
private static void loadMaterials() {
@ -122,7 +122,7 @@ public class BukkitRegistry {
ITEM_MATERIAL.put(item, material);
MATERIAL_ITEM.put(material, item);
}
ArclightMod.LOGGER.info("Registered {} new materials, with {} blocks and {} items", i - origin, blocks, items);
ArclightMod.LOGGER.info("registry.material", i - origin, blocks, items);
}
private static String toName(ResourceLocation location) {

View File

@ -1,12 +1,11 @@
package io.izzel.arclight.common.mod.server.event;
import net.minecraftforge.common.MinecraftForge;
import io.izzel.arclight.common.mod.ArclightMod;
import net.minecraftforge.common.MinecraftForge;
public abstract class ArclightEventDispatcherRegistry {
public static void registerAllEventDispatchers() {
ArclightMod.LOGGER.info("Arclight register all event dispatchers.");
MinecraftForge.EVENT_BUS.register(new BlockBreakEventDispatcher());
MinecraftForge.EVENT_BUS.register(new BlockPlaceEventDispatcher());
MinecraftForge.EVENT_BUS.register(new EntityPotionEffectEventDispatcher());
@ -15,6 +14,7 @@ public abstract class ArclightEventDispatcherRegistry {
MinecraftForge.EVENT_BUS.register(new NetworkEventDispatcher());
MinecraftForge.EVENT_BUS.register(new EntityTeleportEventDispatcher());
MinecraftForge.EVENT_BUS.register(new ItemEntityEventDispatcher());
ArclightMod.LOGGER.info("registry.forge-event");
}
}

View File

@ -0,0 +1,113 @@
package io.izzel.arclight.common.mod.util.log;
import io.izzel.arclight.i18n.ArclightLocale;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.spi.ExtendedLogger;
import org.apache.logging.log4j.spi.ExtendedLoggerWrapper;
import org.apache.logging.log4j.util.MessageSupplier;
import org.apache.logging.log4j.util.Supplier;
public class ArclightI18nLogger extends ExtendedLoggerWrapper {
public ArclightI18nLogger(ExtendedLogger logger) {
super(logger, logger.getName(), logger.getMessageFactory());
}
public static Logger getLogger(String name) {
return new ArclightI18nLogger((ExtendedLogger) LogManager.getLogger(name));
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, CharSequence message, Throwable t) {
this.info("", "");
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message.toString()), t);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, Object message, Throwable t) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message.toString()), t);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, MessageSupplier msgSupplier, Throwable t) {
super.logMessage(fqcn, level, marker, msgSupplier, t);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, Supplier<?> msgSupplier, Throwable t) {
super.logMessage(fqcn, level, marker, msgSupplier, t);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Throwable t) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), t);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message));
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object... params) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), params);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7, p8);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);
}
@Override
protected void logMessage(String fqcn, Level level, Marker marker, String message, Supplier<?>... paramSuppliers) {
super.logMessage(fqcn, level, marker, ArclightLocale.getInstance().get(message), paramSuppliers);
}
}

View File

@ -0,0 +1,40 @@
package io.izzel.arclight.common.mod.util.log;
import java.util.Enumeration;
import java.util.logging.LogManager;
import java.util.logging.Logger;
public class ArclightLazyLogManager extends LogManager {
private volatile LogManager delegate;
@Override
public boolean addLogger(Logger logger) {
tryGet();
if (delegate != null) return delegate.addLogger(logger);
return super.addLogger(logger);
}
@Override
public Logger getLogger(String name) {
tryGet();
if (delegate != null) return delegate.getLogger(name);
return super.getLogger(name);
}
@Override
public Enumeration<String> getLoggerNames() {
tryGet();
if (delegate != null) return delegate.getLoggerNames();
return super.getLoggerNames();
}
private void tryGet() {
if (delegate != null) return;
try {
Class<?> name = Class.forName("org.apache.logging.log4j.jul.LogManager");
delegate = (LogManager) name.newInstance();
} catch (Exception ignored) {
}
}
}

View File

@ -1,4 +1,4 @@
package io.izzel.arclight.common.mod.util;
package io.izzel.arclight.common.mod.util.log;
import org.apache.logging.log4j.jul.ApiLogger;
import org.apache.logging.log4j.jul.CoreLoggerAdapter;

View File

@ -1,4 +1,4 @@
package io.izzel.arclight.common.mod.util;
package io.izzel.arclight.common.mod.util.log;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLogger;

View File

@ -69,6 +69,7 @@ dependencies {
minecraft "net.minecraftforge:forge:$minecraftVersion-$forgeVersion"
compile group: 'org.jetbrains', name: 'annotations', version: '19.0.0'
compile project(':arclight-common')
embed project(':i18n-config')
embed project(':forge-installer')
for (def lib : embedLibs) {
arclight lib

View File

@ -1,17 +1,23 @@
package io.izzel.arclight.server;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.forgeinstaller.ForgeInstaller;
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
import io.izzel.arclight.api.EnumHelper;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.mod.util.log.ArclightI18nLogger;
import io.izzel.arclight.common.mod.util.log.ArclightLazyLogManager;
import io.izzel.arclight.common.mod.util.remapper.ArclightRemapper;
import io.izzel.arclight.forgeinstaller.ForgeInstaller;
import io.izzel.arclight.i18n.ArclightConfig;
import io.izzel.arclight.i18n.ArclightLocale;
import net.minecraftforge.server.ServerMain;
import org.apache.logging.log4j.LogManager;
import java.util.Objects;
public class Main {
public static void main(String[] args) throws Throwable {
System.setProperty("java.util.logging.manager", ArclightLazyLogManager.class.getCanonicalName());
System.setProperty("log4j.jul.LoggerAdapter", "io.izzel.arclight.common.mod.util.log.ArclightLoggerAdapter");
ArclightLocale.info("i18n.using-language", ArclightConfig.spec().getLocale().getCurrent(), ArclightConfig.spec().getLocale().getFallback());
ForgeInstaller.install();
try { // Java 9 & Java 兼容性
int javaVersion = (int) Float.parseFloat(System.getProperty("java.class.version"));
@ -25,9 +31,7 @@ public class Main {
return;
}
try {
System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager");
System.setProperty("log4j.jul.LoggerAdapter", "io.izzel.arclight.common.mod.util.ArclightLoggerAdapter");
LogManager.getLogger("Arclight").info("Loading mappings ...");
ArclightI18nLogger.getLogger("Arclight").info("loading-mapping");
Objects.requireNonNull(ArclightRemapper.INSTANCE);
ServerMain.main(args);
} catch (Exception e) {

19
i18n-config/build.gradle Normal file
View File

@ -0,0 +1,19 @@
plugins {
id 'java'
}
repositories {
mavenCentral()
maven {
name = 'sponge'
url = 'https://repo.spongepowered.org/maven'
}
}
dependencies {
compile 'org.spongepowered:configurate-hocon:3.6.1'
}
jar {
from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) })
}

View File

@ -0,0 +1,91 @@
package io.izzel.arclight.i18n;
import com.google.common.reflect.TypeToken;
import io.izzel.arclight.i18n.conf.ConfigSpec;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
import ninja.leaping.configurate.objectmapping.ObjectMappingException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.StringJoiner;
public class ArclightConfig {
private static ArclightConfig instance;
private final CommentedConfigurationNode node;
private final ConfigSpec spec;
public ArclightConfig(CommentedConfigurationNode node) throws ObjectMappingException {
this.node = node;
this.spec = this.node.getValue(TypeToken.of(ConfigSpec.class));
}
public CommentedConfigurationNode getNode() {
return node;
}
public ConfigSpec getSpec() {
return spec;
}
public ConfigurationNode get(String path) {
return this.node.getNode((Object[]) path.split("\\."));
}
public static ConfigSpec spec() {
return instance.spec;
}
private static void load() throws Exception {
Path path = Paths.get("arclight.conf");
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setSource(
() -> new BufferedReader(new InputStreamReader(ArclightConfig.class.getResourceAsStream("/META-INF/arclight.conf"), StandardCharsets.UTF_8))
).build().load();
HoconConfigurationLoader loader = HoconConfigurationLoader.builder().setPath(path).build();
CommentedConfigurationNode cur = loader.load();
cur.mergeValuesFrom(node);
cur.getNode("locale", "current").setValue(ArclightLocale.getInstance().getCurrent());
fillComments(cur, ArclightLocale.getInstance());
instance = new ArclightConfig(cur);
loader.save(cur);
}
private static void fillComments(CommentedConfigurationNode node, ArclightLocale locale) {
if (!node.getComment().isPresent()) {
String path = pathOf(node);
Optional<String> option = locale.getOption("comments." + path + ".comment");
option.ifPresent(node::setComment);
}
if (node.hasMapChildren()) {
for (CommentedConfigurationNode value : node.getChildrenMap().values()) {
fillComments(value, locale);
}
}
}
private static String pathOf(ConfigurationNode node) {
StringJoiner joiner = new StringJoiner(".");
for (Object o : node.getPath()) {
if (o != null) {
joiner.add(o.toString());
}
}
String s = joiner.toString();
return s.isEmpty() ? "__root__" : s;
}
static {
try {
load();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,132 @@
package io.izzel.arclight.i18n;
import ninja.leaping.configurate.ValueType;
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.AbstractMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.concurrent.Callable;
public class ArclightLocale {
private static ArclightLocale instance;
private final String current, fallback;
private final CommentedConfigurationNode node;
public ArclightLocale(String current, String fallback, CommentedConfigurationNode node) {
this.current = current;
this.fallback = fallback;
this.node = node;
}
public String getCurrent() {
return current;
}
public String getFallback() {
return fallback;
}
public CommentedConfigurationNode getNode() {
return node;
}
public String format(String node, Object... args) {
return MessageFormat.format(get(node), args);
}
public String get(String path) {
return getOption(path).orElse(path);
}
public Optional<String> getOption(String path) {
CommentedConfigurationNode node = this.node.getNode((Object[]) path.split("\\."));
if (node.getValueType() == ValueType.LIST) {
StringJoiner joiner = new StringJoiner("\n");
for (CommentedConfigurationNode configurationNode : node.getChildrenList()) {
joiner.add(configurationNode.getString());
}
return Optional.ofNullable(joiner.toString());
} else {
return Optional.ofNullable(node.getString());
}
}
public static void info(String path, Object... args) {
System.out.println(instance.format(path, args));
}
public static void error(String path, Object... args) {
System.err.println(instance.format(path, args));
}
public static ArclightLocale getInstance() {
return instance;
}
private static void init() throws Exception {
Map.Entry<String, String> entry = getLocale();
String current = entry.getKey();
String fallback = entry.getValue();
InputStream stream = ArclightLocale.class.getResourceAsStream("/META-INF/i18n/" + fallback + ".conf");
if (stream == null) throw new RuntimeException("Fallback locale is not found: " + fallback);
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setSource(localeSource(fallback)).build().load();
instance = new ArclightLocale(current, fallback, node);
if (!current.equals(fallback)) {
try {
CommentedConfigurationNode curNode = HoconConfigurationLoader.builder().setSource(localeSource(current)).build().load();
curNode.mergeValuesFrom(node);
instance = new ArclightLocale(current, fallback, curNode);
} catch (Exception e) {
System.err.println(instance.format("i18n.current-not-available", current));
}
}
}
private static Callable<BufferedReader> localeSource(String path) {
return () -> new BufferedReader(new InputStreamReader(ArclightLocale.class.getResourceAsStream("/META-INF/i18n/" + path + ".conf"), StandardCharsets.UTF_8));
}
private static Map.Entry<String, String> getLocale() {
try {
Path path = Paths.get("arclight.conf");
if (!Files.exists(path)) {
throw new Exception();
} else {
CommentedConfigurationNode node = HoconConfigurationLoader.builder().setPath(path).build().load();
CommentedConfigurationNode locale = node.getNode("locale");
String current = locale.getNode("current").getString(currentLocale());
String fallback = locale.getNode("fallback").getString("zh_cn");
return new AbstractMap.SimpleImmutableEntry<>(current, fallback);
}
} catch (Throwable t) {
return new AbstractMap.SimpleImmutableEntry<>(currentLocale(), "zh_cn");
}
}
private static String currentLocale() {
Locale locale = Locale.getDefault();
return locale.getLanguage().toLowerCase(Locale.ROOT) + "_" + locale.getCountry().toLowerCase(Locale.ROOT);
}
static {
try {
init();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,29 @@
package io.izzel.arclight.i18n.conf;
import ninja.leaping.configurate.objectmapping.Setting;
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable
public class ConfigSpec {
@Setting("_v")
private int version;
@Setting("optimization")
private OptimizationSpec optimizationSpec;
@Setting("locale")
private LocaleSpec localeSpec;
public int getVersion() {
return version;
}
public OptimizationSpec getOptimization() {
return optimizationSpec;
}
public LocaleSpec getLocale() {
return localeSpec;
}
}

View File

@ -0,0 +1,22 @@
package io.izzel.arclight.i18n.conf;
import ninja.leaping.configurate.objectmapping.Setting;
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable
public class LocaleSpec {
@Setting("current")
private String current;
@Setting("fallback")
private String fallback;
public String getCurrent() {
return current;
}
public String getFallback() {
return fallback;
}
}

View File

@ -0,0 +1,15 @@
package io.izzel.arclight.i18n.conf;
import ninja.leaping.configurate.objectmapping.Setting;
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable
public class OptimizationSpec {
@Setting("remove-stream")
private boolean removeStream;
public boolean isRemoveStream() {
return removeStream;
}
}

View File

@ -0,0 +1,8 @@
_v = 1
locale {
fallback = "zh_cn"
}
optimization {
remove-stream = true
}

View File

@ -0,0 +1,29 @@
i18n {
current-not-available = "Current locale {0} is not available"
using-language = "Using locale {0} and fallback locale {1}"
}
loading-mapping = "Loading mappings ..."
mixin-load {
core = "Arclight core mixin added."
optimization = "Arclight optimization mixin added."
}
mod-load = "Arclight Mod loaded."
registry {
forge-event = "Arclight events registered."
begin = "Regitring for Bukkit ..."
error = "Error occured registring Forge "
enchantment = "Registered {} enchantments"
potion = "Registered {} new potion effect types"
material = "Registered {} new materials with {} blocks and {} items"
}
comments {
_v.comment = [
"Repository: https://github.com/IzzelAliz/Arclight"
"Issue Tracker: https://github.com/IzzelAliz/Arclight/issues"
""
""
"Config version number, do not edit."
]
locale.comment = "Language/I18n settings"
}

View File

@ -0,0 +1,30 @@
i18n {
current-not-available = "选择的语言 {0} 不可用"
using-language = "正在使用 {0} 语言,{1} 作为备选语言"
}
loading-mapping = "正在加载混淆数据 ..."
mixin-load {
core = "核心 Mixin 配置已加载"
optimization = "服务端优化 Mixin 配置已加载"
}
mod-load = "Arclight Mod 已加载"
registry {
forge-event = "Arclight 事件系统已注册"
begin = "正在向 Bukkit 注册 ..."
error = "处理 Forge 注册时出错 "
enchantment = "注册了 {} 个新的附魔"
potion = "注册了 {} 个新的药水效果"
material = "注册了 {} 个材料,其中 {} 个方块 {} 个物品"
}
comments {
_v.comment = [
"源代码仓库: https://github.com/IzzelAliz/Arclight"
"提交反馈/错误报告: https://github.com/IzzelAliz/Arclight/issues"
""
""
"配置文件版本号,请勿编辑"
]
locale.comment = "语言/国际化相关设置"
optimization.comment = "服务端优化相关设置"
}

View File

@ -4,4 +4,5 @@ include 'arclight-testplugin'
include 'arclight-common'
include 'forge-installer'
include 'arclight-api'
include 'i18n-config'