9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-24 09:29:33 +00:00

refactor translation

This commit is contained in:
XiaoMoMi
2025-04-04 03:36:27 +08:00
parent 30588d86eb
commit a3f7780902
9 changed files with 141 additions and 168 deletions

View File

@@ -54,7 +54,6 @@ command.search_usage.not_found: "<red>No usage found for this item</red>"
command.search_recipe.no_item: "<red>Please hold an item before running this command</red>"
command.search_usage.no_item: "<red>Please hold an item before running this command</red>"
command.totem.not_totem: "<red>'<arg:0>' is not type of totem_of_undying</red>"
warning.config.image.lack_height: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'height' argument.</yellow>"
warning.config.image.height_smaller_than_ascent: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' violates the bitmap image rule: 'height' should be no lower than 'ascent'.</yellow>"
warning.config.image.no_file: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is missing the required 'file' argument.</yellow>"
@@ -64,4 +63,5 @@ warning.config.image.lack_char: "<yellow>Issue found in file <arg:0> - The image
warning.config.image.codepoint_in_use: "<yellow>Issue found in file <arg:0> - The image '<arg:1>' is using a character[<arg:3>(<arg:4>)] in font <arg:2> that has been used by another image '<arg:5>'.</yellow>"
warning.config.image.invalid_codepoint_grid: "<yellow>Issue found in file <arg:0> - Image '<arg:1>' has an invalid 'chars' codepoint grind.</yellow>"
warning.config.image.file_not_exist: "<yellow>Issue found in file <arg:0> - PNG file <arg:2> not found for image '<arg:1>'.</yellow>"
warning.config.recipe.duplicated: "<yellow>Issue found in file <arg:0> - Duplicated recipe '<arg:1>'.</yellow>"
warning.config.recipe.duplicated: "<yellow>Issue found in file <arg:0> - Duplicated recipe '<arg:1>'.</yellow>"
warning.config.i18n.unknown_locale: "<yellow>Issue found in file <arg:0> - Unknown locale '<arg:1>'.</yellow>"

View File

@@ -603,7 +603,7 @@ public abstract class AbstractPackManager implements PackManager {
}
private void generateClientLang(Path generatedPackPath) {
for (Map.Entry<String, I18NData> entry : this.plugin.translationManager().clientLangManager().langData().entrySet()) {
for (Map.Entry<String, I18NData> entry : this.plugin.translationManager().clientLangData().entrySet()) {
JsonObject json = new JsonObject();
for (Map.Entry<String, String> pair : entry.getValue().translations.entrySet()) {
json.addProperty(pair.getKey(), pair.getValue());

View File

@@ -46,7 +46,7 @@ public class ObfC {
}
private static String normalizeCharset(String input) {
return input.toLowerCase(Locale.ROOT);
return input.toLowerCase(Locale.ENGLISH);
}
private static String generateDefaultCharset() {

View File

@@ -201,8 +201,7 @@ public abstract class CraftEngine implements Plugin {
// register category parser
this.packManager.registerConfigSectionParser(this.itemBrowserManager);
// register translation parser
this.packManager.registerConfigSectionParser(this.translationManager);
this.packManager.registerConfigSectionParser(this.translationManager.clientLangManager());
this.packManager.registerConfigSectionParsers(this.translationManager.parsers());
// register sound parser
this.packManager.registerConfigSectionParser(this.soundManager);
this.packManager.registerConfigSectionParser(this.soundManager.jukeboxSongManager());

View File

@@ -55,7 +55,7 @@ public class Dependency {
}
public String fileName(String classifier) {
String name = customArtifactID.toLowerCase(Locale.ROOT).replace('_', '-');
String name = customArtifactID.toLowerCase(Locale.ENGLISH).replace('_', '-');
String extra = classifier == null || classifier.isEmpty()
? ""
: "-" + classifier;

View File

@@ -1,56 +0,0 @@
package net.momirealms.craftengine.core.plugin.locale;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public interface ClientLangManager extends Reloadable, ConfigSectionParser {
Set<String> ALL_LANG = Set.of(
"af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn",
"bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk",
"de_at", "de_ch", "de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz",
"en_pt", "en_ud", "en_us", "enp", "enws", "eo_uy", "es_ar", "es_cl",
"es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es",
"fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_fr", "fra_de", "fur_it",
"fy_nl", "ga_ie", "gd_gb", "gl_es", "haw_us", "he_il", "hi_in", "hn_no",
"hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv",
"it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh",
"kw_gb", "ky_kg", "la_la", "lb_lu", "li_li", "lmo", "lo_la", "lol_us", "lt_lt",
"lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt", "nah", "nds_de",
"nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pls",
"pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "sah_sah",
"se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_cs", "sr_sp", "sv_se",
"sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr",
"tt_ru", "tzo_mx", "uk_ua", "val_es", "vec_it", "vi_vn", "vp_vl", "yi_de",
"yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab"
);
Map<String, List<String>> LOCALE_2_COUNTRIES = ALL_LANG.stream()
.map(lang -> lang.split("_"))
.filter(split -> split.length >= 2)
.collect(Collectors.groupingBy(
split -> split[0],
Collectors.mapping(split -> split[1], Collectors.toUnmodifiableList())
));
String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"};
Map<String, I18NData> langData();
@Override
default int loadingSequence() {
return LoadingSequence.LANG;
}
@Override
default String[] sectionId() {
return CONFIG_SECTION_NAME;
}
void addTranslation(String langId, Map<String, String> translations);
}

View File

@@ -1,63 +0,0 @@
package net.momirealms.craftengine.core.plugin.locale;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.util.Key;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
public class ClientLangMangerImpl implements ClientLangManager {
private final Map<String, I18NData> i18nData = new HashMap<>();
protected ClientLangMangerImpl() {}
@Override
public void reload() {
this.i18nData.clear();
}
@Override
public void parseSection(Pack pack, Path path, Key id, Map<String, Object> section) {
String langId = id.value().toLowerCase(Locale.ROOT);
Map<String, String> sectionData = section.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> String.valueOf(entry.getValue())
));
addTranslation(langId, sectionData);
}
@Override
public Map<String, I18NData> langData() {
return Collections.unmodifiableMap(this.i18nData);
}
@Override
public void addTranslation(String langId, Map<String, String> translations) {
if ("all".equals(langId)) {
ALL_LANG.forEach(lang -> this.i18nData.computeIfAbsent(lang, k -> new I18NData())
.addTranslations(translations));
return;
}
if (ALL_LANG.contains(langId)) {
this.i18nData.computeIfAbsent(langId, k -> new I18NData())
.addTranslations(translations);
return;
}
List<String> langCountries = LOCALE_2_COUNTRIES.getOrDefault(langId, Collections.emptyList());
for (String lang : langCountries) {
this.i18nData.computeIfAbsent(langId + "_" + lang, k -> new I18NData())
.addTranslations(translations);
}
}
@Override
public void delayedLoad() {
this.i18nData.values().forEach(I18NData::processTranslations);
}
}

View File

@@ -7,16 +7,45 @@ import net.momirealms.craftengine.core.plugin.Reloadable;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
public interface TranslationManager extends Reloadable, ConfigSectionParser {
String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"};
public interface TranslationManager extends Reloadable {
Set<String> ALL_LANG = Set.of(
"af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "be_latn",
"bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk",
"de_at", "de_ch", "de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz",
"en_pt", "en_ud", "en_us", "enp", "enws", "eo_uy", "es_ar", "es_cl",
"es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es",
"fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_fr", "fra_de", "fur_it",
"fy_nl", "ga_ie", "gd_gb", "gl_es", "haw_us", "he_il", "hi_in", "hn_no",
"hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv",
"it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh",
"kw_gb", "ky_kg", "la_la", "lb_lu", "li_li", "lmo", "lo_la", "lol_us", "lt_lt",
"lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt", "nah", "nds_de",
"nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pls",
"pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "sah_sah",
"se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_cs", "sr_sp", "sv_se",
"sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr",
"tt_ru", "tzo_mx", "uk_ua", "val_es", "vec_it", "vi_vn", "vp_vl", "yi_de",
"yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab"
);
Map<String, List<String>> LOCALE_2_COUNTRIES = ALL_LANG.stream()
.map(lang -> lang.split("_"))
.filter(split -> split.length >= 2)
.collect(Collectors.groupingBy(
split -> split[0],
Collectors.mapping(split -> split[1], Collectors.toUnmodifiableList())
));
static TranslationManager instance() {
return TranslationManagerImpl.instance;
}
ClientLangManager clientLangManager();
ConfigSectionParser[] parsers();
default String miniMessageTranslation(String key) {
return miniMessageTranslation(key, null);
@@ -36,15 +65,9 @@ public interface TranslationManager extends Reloadable, ConfigSectionParser {
return locale == null || locale.isEmpty() ? null : Translator.parseLocale(locale);
}
@Override
default int loadingSequence() {
return LoadingSequence.TRANSLATION;
}
@Override
default String[] sectionId() {
return CONFIG_SECTION_NAME;
}
void log(String id, String... args);
Map<String, I18NData> clientLangData();
void addClientTranslation(String langId, Map<String, String> translations);
}

View File

@@ -2,10 +2,12 @@ package net.momirealms.craftengine.core.plugin.locale;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.momirealms.craftengine.core.pack.LoadingSequence;
import net.momirealms.craftengine.core.pack.Pack;
import net.momirealms.craftengine.core.plugin.CraftEngine;
import net.momirealms.craftengine.core.plugin.Plugin;
import net.momirealms.craftengine.core.plugin.PluginProperties;
import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser;
import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor;
import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag;
import net.momirealms.craftengine.core.util.AdventureHelper;
@@ -34,22 +36,24 @@ public class TranslationManagerImpl implements TranslationManager {
private final Plugin plugin;
private final Set<Locale> installed = ConcurrentHashMap.newKeySet();
private final Path translationsDirectory;
private final ClientLangManager clientLangManager;
private final String langVersion;
private final String[] supportedLanguages;
private final Map<String, Object> translationFallback = new LinkedHashMap<>();
private Locale forcedLocale = null;
private Locale selectedLocale = DEFAULT_LOCALE;
private MiniMessageTranslationRegistry registry;
private final Map<String, I18NData> clientLangData = new HashMap<>();
private final LangParser langParser;
private final I18NParser i18nParser;
public TranslationManagerImpl(Plugin plugin) {
instance = this;
this.plugin = plugin;
this.translationsDirectory = this.plugin.dataFolderPath().resolve("translations");
this.clientLangManager = new ClientLangMangerImpl();
this.langVersion = PluginProperties.getValue("lang-version");
this.supportedLanguages = PluginProperties.getValue("supported-languages").split(",");
instance = this;
this.langParser = new LangParser();
this.i18nParser = new I18NParser();
Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions()));
try (InputStream is = plugin.resourceStream("translations/en.yml")) {
this.translationFallback.putAll(yaml.load(is));
@@ -58,6 +62,11 @@ public class TranslationManagerImpl implements TranslationManager {
}
}
@Override
public ConfigSectionParser[] parsers() {
return new ConfigSectionParser[] {this.langParser, this.i18nParser};
}
@Override
public void forcedLocale(Locale locale) {
this.forcedLocale = locale;
@@ -65,13 +74,13 @@ public class TranslationManagerImpl implements TranslationManager {
@Override
public void delayedLoad() {
this.clientLangManager.delayedLoad();
this.clientLangData.values().forEach(I18NData::processTranslations);
}
@Override
public void reload() {
// clear old data
this.clientLangManager.reload();
this.clientLangData.clear();
// remove any previous registry
if (this.registry != null) {
@@ -109,7 +118,7 @@ public class TranslationManagerImpl implements TranslationManager {
return;
}
this.plugin.logger().warn(localLocale.toString().toLowerCase(Locale.ENGLISH) + ".yml not exists, using " + DEFAULT_LOCALE.toString().toLowerCase(Locale.ENGLISH) + ".yml as default locale.");
this.plugin.logger().warn("translations/" + localLocale.toString().toLowerCase(Locale.ENGLISH) + ".yml not exists, using " + DEFAULT_LOCALE.toString().toLowerCase(Locale.ENGLISH) + ".yml as default locale.");
this.selectedLocale = DEFAULT_LOCALE;
}
@@ -214,28 +223,6 @@ public class TranslationManagerImpl implements TranslationManager {
return Pair.of(locale, bundle);
}
@Override
public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map<String, Object> section) {
Locale locale = TranslationManager.parseLocale(id.value());
if (locale == null) {
throw new IllegalStateException("Unknown locale '" + id.value() + "' - unable to register.");
}
Map<String, String> bundle = new HashMap<>();
for (Map.Entry<String, Object> entry : section.entrySet()) {
String key = entry.getKey();
bundle.put(key, entry.getValue().toString());
}
this.registry.registerAll(locale, bundle);
this.installed.add(locale);
}
@Override
public ClientLangManager clientLangManager() {
return clientLangManager;
}
@Override
public void log(String id, String... args) {
String translation = miniMessageTranslation(id);
@@ -263,4 +250,87 @@ public class TranslationManagerImpl implements TranslationManager {
return newFileContents;
}
}
@Override
public Map<String, I18NData> clientLangData() {
return Collections.unmodifiableMap(this.clientLangData);
}
@Override
public void addClientTranslation(String langId, Map<String, String> translations) {
if ("all".equals(langId)) {
ALL_LANG.forEach(lang -> this.clientLangData.computeIfAbsent(lang, k -> new I18NData())
.addTranslations(translations));
return;
}
if (ALL_LANG.contains(langId)) {
this.clientLangData.computeIfAbsent(langId, k -> new I18NData())
.addTranslations(translations);
return;
}
List<String> langCountries = LOCALE_2_COUNTRIES.getOrDefault(langId, Collections.emptyList());
for (String lang : langCountries) {
this.clientLangData.computeIfAbsent(langId + "_" + lang, k -> new I18NData())
.addTranslations(translations);
}
}
public class I18NParser implements ConfigSectionParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"};
@Override
public int loadingSequence() {
return LoadingSequence.TRANSLATION;
}
@Override
public String[] sectionId() {
return CONFIG_SECTION_NAME;
}
@Override
public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map<String, Object> section) {
Locale locale = TranslationManager.parseLocale(id.value());
if (locale == null) {
log("warning.config.i18n.unknown_locale", path.toString(), id.value());
return;
}
Map<String, String> bundle = new HashMap<>();
for (Map.Entry<String, Object> entry : section.entrySet()) {
String key = entry.getKey();
bundle.put(key, entry.getValue().toString());
}
TranslationManagerImpl.this.registry.registerAll(locale, bundle);
TranslationManagerImpl.this.installed.add(locale);
}
}
public class LangParser implements ConfigSectionParser {
public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"};
@Override
public int loadingSequence() {
return LoadingSequence.LANG;
}
@Override
public String[] sectionId() {
return CONFIG_SECTION_NAME;
}
@Override
public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map<String, Object> section) {
String langId = id.value().toLowerCase(Locale.ENGLISH);
Map<String, String> sectionData = section.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> String.valueOf(entry.getValue())
));
TranslationManagerImpl.this.addClientTranslation(langId, sectionData);
}
}
}