mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-10 04:12:54 +08:00
Flatten language translation keys in-memory
This commit is contained in:
parent
a4f10208de
commit
98ac42a6c6
@ -14,8 +14,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
|
|
||||||
@ -46,9 +44,8 @@ import java.util.Map;
|
|||||||
public final class Language {
|
public final class Language {
|
||||||
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
|
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final JsonObject languageData;
|
|
||||||
private final String languageCode;
|
private final String languageCode;
|
||||||
private final Map<String, String> cachedTranslations = new ConcurrentHashMap<>();
|
private final Map<String, String> translations = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a language instance from a code.
|
* Creates a language instance from a code.
|
||||||
@ -139,20 +136,36 @@ public final class Language {
|
|||||||
return languageCode;
|
return languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive helper function to flatten a Json tree
|
||||||
|
* Converts input like {"foo": {"bar": "baz"}} to {"foo.bar": "baz"}
|
||||||
|
* @param map The map to insert the keys into
|
||||||
|
* @param key The flattened key of the current element
|
||||||
|
* @param element The current element
|
||||||
|
*/
|
||||||
|
private static void putFlattenedKey(Map<String,String> map, String key, JsonElement element) {
|
||||||
|
if (element.isJsonObject()) {
|
||||||
|
element.getAsJsonObject().entrySet().forEach(entry -> {
|
||||||
|
String keyPrefix = key.isEmpty() ? "" : key + ".";
|
||||||
|
putFlattenedKey(map, keyPrefix + entry.getKey(), entry.getValue());
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
map.put(key, element.getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a file and creates a language instance.
|
* Reads a file and creates a language instance.
|
||||||
*/
|
*/
|
||||||
private Language(LanguageStreamDescription description) {
|
private Language(LanguageStreamDescription description) {
|
||||||
@Nullable JsonObject languageData = null;
|
|
||||||
languageCode = description.getLanguageCode();
|
languageCode = description.getLanguageCode();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
languageData = JsonUtils.decode(Utils.readFromInputStream(description.getLanguageFile()), JsonObject.class);
|
var object = JsonUtils.decode(Utils.readFromInputStream(description.getLanguageFile()), JsonObject.class);
|
||||||
|
object.entrySet().forEach(entry -> putFlattenedKey(translations, entry.getKey(), entry.getValue()));
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Grasscutter.getLogger().warn("Failed to load language file: " + description.getLanguageCode(), exception);
|
Grasscutter.getLogger().warn("Failed to load language file: " + description.getLanguageCode(), exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.languageData = languageData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,41 +212,16 @@ public final class Language {
|
|||||||
* @return The value (as a string) from a nested key.
|
* @return The value (as a string) from a nested key.
|
||||||
*/
|
*/
|
||||||
public String get(String key) {
|
public String get(String key) {
|
||||||
if (this.cachedTranslations.containsKey(key)) {
|
if (translations.containsKey(key)) return translations.get(key);
|
||||||
return this.cachedTranslations.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] keys = key.split("\\.");
|
|
||||||
JsonObject object = this.languageData;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
String valueNotFoundPattern = "This value does not exist. Please report this to the Discord: ";
|
String valueNotFoundPattern = "This value does not exist. Please report this to the Discord: ";
|
||||||
String result = valueNotFoundPattern + key;
|
String result = valueNotFoundPattern + key;
|
||||||
boolean isValueFound = false;
|
if (!languageCode.equals("en-US")) {
|
||||||
|
String englishValue = getLanguage("en-US").get(key);
|
||||||
while (true) {
|
|
||||||
if (index == keys.length) break;
|
|
||||||
|
|
||||||
String currentKey = keys[index++];
|
|
||||||
if (object.has(currentKey)) {
|
|
||||||
JsonElement element = object.get(currentKey);
|
|
||||||
if (element.isJsonObject())
|
|
||||||
object = element.getAsJsonObject();
|
|
||||||
else {
|
|
||||||
isValueFound = true;
|
|
||||||
result = element.getAsString(); break;
|
|
||||||
}
|
|
||||||
} else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValueFound && !languageCode.equals("en-US")) {
|
|
||||||
var englishValue = getLanguage("en-US").get(key);
|
|
||||||
if (!englishValue.contains(valueNotFoundPattern)) {
|
if (!englishValue.contains(valueNotFoundPattern)) {
|
||||||
result += "\nhere is english version:\n" + englishValue;
|
result += "\nhere is english version:\n" + englishValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
this.cachedTranslations.put(key, result); return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LanguageStreamDescription {
|
private static class LanguageStreamDescription {
|
||||||
|
Loading…
Reference in New Issue
Block a user