mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-11-22 14:56:25 +01:00
Add support for adding custom translations. (#4047)
* Add support for loading locale overwrites. Any lang files in this new folder will be appended to the main lang file when loaded. * A locale will no longer attempt to be downloaded and loaded if it already is loaded. Previously a lang file was reloaded everytime a player joins. * Switch some io bits to nio * formatting fixes * Update core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java * Rename isLocalLoaded to isLocaleLoaded * Rename overwrites to overrides * Catch separate exceptions when parsing locale file. Similar to previous implementation * Add //no-op to try/catch * Apply suggestions to fix issues that might arise with the Norwegian locale * Properly resolve override locale path for nb_no * Yeet temporary fix - addresses @Camotoy's review * Catch IOException properly --------- Co-authored-by: onebeastchris <github@onechris.mozmail.com>
This commit is contained in:
parent
f1e7ef92f4
commit
d63a70daa9
1 changed files with 72 additions and 46 deletions
|
@ -35,6 +35,7 @@ import org.geysermc.geyser.util.WebUtils;
|
|||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
@ -44,16 +45,15 @@ public class MinecraftLocale {
|
|||
|
||||
public static final Map<String, Map<String, String>> LOCALE_MAPPINGS = new HashMap<>();
|
||||
|
||||
static {
|
||||
// Create the locales folder
|
||||
File localesFolder = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales").toFile();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
localesFolder.mkdir();
|
||||
private static final Path LOCALE_FOLDER = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales");
|
||||
|
||||
// FIXME TEMPORARY
|
||||
static {
|
||||
try {
|
||||
Files.delete(localesFolder.toPath().resolve("en_us.hash"));
|
||||
} catch (IOException ignored) {
|
||||
// Create the locales folder
|
||||
Files.createDirectories(LOCALE_FOLDER);
|
||||
Files.createDirectories(LOCALE_FOLDER.resolve("overrides"));
|
||||
} catch (IOException exception) {
|
||||
throw new RuntimeException("Unable to create locale folders! " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,12 +69,18 @@ public class MinecraftLocale {
|
|||
}
|
||||
|
||||
/**
|
||||
* Downloads a locale from Mojang if its not already loaded
|
||||
* Downloads a locale from Mojang if it's not already loaded
|
||||
*
|
||||
* @param locale Locale to download and load
|
||||
*/
|
||||
public static void downloadAndLoadLocale(String locale) {
|
||||
locale = locale.toLowerCase(Locale.ROOT);
|
||||
|
||||
if (isLocaleLoaded(locale)) {
|
||||
GeyserImpl.getInstance().getLogger().debug("Locale already loaded: " + locale);
|
||||
return;
|
||||
}
|
||||
|
||||
if (locale.equals("nb_no")) {
|
||||
// Different locale code - https://minecraft.wiki/w/Language
|
||||
locale = "no_no";
|
||||
|
@ -99,7 +105,7 @@ public class MinecraftLocale {
|
|||
}
|
||||
|
||||
/**
|
||||
* Downloads the specified locale if its not already downloaded
|
||||
* Downloads the specified locale if it's not already downloaded
|
||||
*
|
||||
* @param locale Locale to download
|
||||
*/
|
||||
|
@ -132,34 +138,56 @@ public class MinecraftLocale {
|
|||
}
|
||||
|
||||
private static Path getPath(String locale) {
|
||||
return GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales/" + locale + ".json");
|
||||
return LOCALE_FOLDER.resolve(locale + ".json");
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a locale already downloaded, if the file doesn't exist it just logs a warning
|
||||
*
|
||||
* @param locale Locale to load
|
||||
* @param locale Bedrock locale to load
|
||||
*/
|
||||
private static boolean loadLocale(String locale) {
|
||||
File localeFile = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("locales/" + locale + ".json").toFile();
|
||||
String lowercaseLocale = locale.toLowerCase(Locale.ROOT);
|
||||
|
||||
// Load the locale
|
||||
if (localeFile.exists()) {
|
||||
// Read the localefile
|
||||
InputStream localeStream;
|
||||
try {
|
||||
localeStream = new FileInputStream(localeFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage()));
|
||||
}
|
||||
// Need to grab this before we change the locale - downloaded/override locales are stored under the Java locale name
|
||||
Path localeFile = getPath(lowercaseLocale);
|
||||
Path localeOverride = getPath("overrides/" + lowercaseLocale);
|
||||
|
||||
if (lowercaseLocale.equals("no_no")) {
|
||||
// Store this locale under the Bedrock locale, so we don't need to do this check over and over
|
||||
lowercaseLocale = "nb_no";
|
||||
}
|
||||
|
||||
Map<String, String> langMap = new HashMap<>();
|
||||
if (Files.exists(localeFile) && Files.isReadable(localeFile)) {
|
||||
langMap.putAll(parseLangFile(localeFile, lowercaseLocale));
|
||||
}
|
||||
|
||||
// Load the locale overwrites
|
||||
if (Files.exists(localeOverride) && Files.isReadable(localeOverride)) {
|
||||
langMap.putAll(parseLangFile(localeOverride, lowercaseLocale));
|
||||
}
|
||||
|
||||
if (!langMap.isEmpty()) {
|
||||
LOCALE_MAPPINGS.put(lowercaseLocale, langMap);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse a json lang file.
|
||||
*
|
||||
* @param localeFile Path of locale file
|
||||
* @param locale Locale to load
|
||||
* @return a Map of the loaded translations
|
||||
*/
|
||||
public static Map<String, String> parseLangFile(Path localeFile, String locale) {
|
||||
// Read the localefile
|
||||
try (InputStream localeStream = Files.newInputStream(localeFile, StandardOpenOption.READ)) {
|
||||
// Parse the file as json
|
||||
JsonNode localeObj;
|
||||
try {
|
||||
localeObj = GeyserImpl.JSON_MAPPER.readTree(localeStream);
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.json", locale), e);
|
||||
}
|
||||
JsonNode localeObj = GeyserImpl.JSON_MAPPER.readTree(localeStream);
|
||||
|
||||
// Parse all the locale fields
|
||||
Iterator<Map.Entry<String, JsonNode>> localeIterator = localeObj.fields();
|
||||
|
@ -168,24 +196,12 @@ public class MinecraftLocale {
|
|||
Map.Entry<String, JsonNode> entry = localeIterator.next();
|
||||
langMap.put(entry.getKey(), entry.getValue().asText());
|
||||
}
|
||||
|
||||
String bedrockLocale = locale.toLowerCase(Locale.ROOT);
|
||||
if (bedrockLocale.equals("no_no")) {
|
||||
// Store this locale under the Bedrock locale so we don't need to do this check over and over
|
||||
bedrockLocale = "nb_no";
|
||||
}
|
||||
|
||||
// Insert the locale into the mappings
|
||||
LOCALE_MAPPINGS.put(bedrockLocale, langMap);
|
||||
|
||||
try {
|
||||
localeStream.close();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage()));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
localeStream.close();
|
||||
return langMap;
|
||||
} catch (FileNotFoundException e){
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage()));
|
||||
} catch (Exception e) {
|
||||
throw new AssertionError(GeyserLocale.getLocaleStringLog("geyser.locale.fail.json", locale), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +242,16 @@ public class MinecraftLocale {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a locale has been loaded.
|
||||
*
|
||||
* @param locale Locale to check
|
||||
* @return true if the locale has been loaded
|
||||
*/
|
||||
public static boolean isLocaleLoaded(String locale) {
|
||||
return LOCALE_MAPPINGS.containsKey(locale.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a byte array into a hex string
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue