package me.egg82.antivpn.utils; import com.velocitypowered.api.plugin.PluginDescription; import java.io.*; import java.nio.file.Files; import java.util.Locale; import java.util.Optional; import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.loader.ConfigurationLoader; import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; import org.yaml.snakeyaml.DumperOptions; public class LanguageFileUtil { private LanguageFileUtil() {} public static Optional<File> getLanguage(Object plugin, PluginDescription description, Locale locale) throws IOException { return getLanguage(plugin, description, locale, false); } public static Optional<File> getLanguage(Object plugin, PluginDescription description, Locale locale, boolean ignoreCountry) throws IOException { // Build resource path & file path for language // Use country is specified (and lang provides country) String resourcePath = ignoreCountry || locale.getCountry() == null || locale.getCountry().isEmpty() ? "lang_" + locale.getLanguage() + ".yml" : "lang_" + locale.getLanguage() + "_" + locale.getCountry() + ".yml"; File langDir = new File(new File(description.getSource().get().getParent().toFile(), description.getName().get()), "lang"); File fileOnDisk = new File(langDir, resourcePath); // Clean up/build language path on disk if (langDir.exists() && !langDir.isDirectory()) { Files.delete(langDir.toPath()); } if (!langDir.exists()) { if (!langDir.mkdirs()) { throw new IOException("Could not create parent directory structure."); } } if (fileOnDisk.exists() && fileOnDisk.isDirectory()) { Files.delete(fileOnDisk.toPath()); } // Check language version if (fileOnDisk.exists()) { try (InputStream inStream = plugin.getClass().getClassLoader().getResourceAsStream(resourcePath)) { if (inStream != null) { ConfigurationLoader<ConfigurationNode> fileLoader = YAMLConfigurationLoader.builder().setFlowStyle(DumperOptions.FlowStyle.BLOCK).setIndent(2).setFile(fileOnDisk).build(); ConfigurationNode fileRoot = fileLoader.load(); double fileVersion = fileRoot.getNode("acf-minecraft", "version").getDouble(1.0d); try (InputStreamReader reader = new InputStreamReader(inStream); BufferedReader in = new BufferedReader(reader)) { ConfigurationLoader<ConfigurationNode> streamLoader = YAMLConfigurationLoader.builder().setFlowStyle(DumperOptions.FlowStyle.BLOCK).setIndent(2).setSource(() -> in).build(); ConfigurationNode streamRoot = streamLoader.load(); double streamVersion = streamRoot.getNode("acf-minecraft", "version").getDouble(1.0d); if (streamVersion > fileVersion) { // Version update, backup & delete file on disk File backupFile = new File(fileOnDisk.getParent(), fileOnDisk.getName() + ".bak"); if (backupFile.exists()) { Files.delete(backupFile.toPath()); } com.google.common.io.Files.copy(fileOnDisk, backupFile); Files.delete(fileOnDisk.toPath()); } } } } } // Write language file to disk if not exists if (!fileOnDisk.exists()) { try (InputStream inStream = plugin.getClass().getClassLoader().getResourceAsStream(resourcePath)) { if (inStream != null) { try (InputStreamReader reader = new InputStreamReader(inStream); BufferedReader in = new BufferedReader(reader); FileWriter writer = new FileWriter(fileOnDisk); BufferedWriter out = new BufferedWriter(writer)) { String line; while ((line = in.readLine()) != null) { out.write(line + System.lineSeparator()); } } } } } if (fileOnDisk.exists()) { // Return file on disk return Optional.of(fileOnDisk); } else { // If we need a more generic language (eg. if we have "en_US" and we don't have "en_US.yml" but we do have "en.yml") then return the more generic language file // Otherwise, no language found return ignoreCountry ? Optional.empty() : getLanguage(plugin, description, locale, true); } } }