From b7361c8da4c485694c48e56577c367784489f7e1 Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 31 Aug 2025 00:18:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=AD=E8=A8=80=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=20(#4362)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jackhuang/hmcl/ui/main/SettingsView.java | 10 +- .../org/jackhuang/hmcl/util/i18n/I18n.java | 10 +- .../org/jackhuang/hmcl/util/i18n/Locales.java | 159 ++++++++++-------- .../resources/assets/lang/I18N.properties | 1 - .../resources/assets/lang/I18N_es.properties | 1 - .../resources/assets/lang/I18N_ja.properties | 1 - .../resources/assets/lang/I18N_lzh.properties | 1 - .../resources/assets/lang/I18N_ru.properties | 1 - .../resources/assets/lang/I18N_zh.properties | 1 - .../assets/lang/I18N_zh_CN.properties | 1 - .../hmcl/launch/DefaultLauncher.java | 2 +- 11 files changed, 108 insertions(+), 80 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java index 0dece1e9a..c6ff64abd 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsView.java @@ -38,6 +38,7 @@ import org.jackhuang.hmcl.ui.construct.ComponentList; import org.jackhuang.hmcl.ui.construct.ComponentSublist; import org.jackhuang.hmcl.ui.construct.MultiFileItem; import org.jackhuang.hmcl.util.i18n.I18n; +import org.jackhuang.hmcl.util.i18n.Locales; import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale; import java.util.Arrays; @@ -177,8 +178,15 @@ public abstract class SettingsView extends StackPane { BorderPane.setAlignment(left, Pos.CENTER_LEFT); languagePane.setLeft(left); + SupportedLocale currentLocale = I18n.getLocale(); cboLanguage = new JFXComboBox<>(); - cboLanguage.setConverter(stringConverter(I18n::getName)); + cboLanguage.setConverter(stringConverter(locale -> { + if (locale.isSameLanguage(currentLocale) || locale == Locales.DEFAULT) + return locale.getDisplayName(currentLocale); + else + return locale.getDisplayName(currentLocale) + " - " + locale.getDisplayName(locale); + })); + FXUtils.setLimitWidth(cboLanguage, 300); languagePane.setRight(cboLanguage); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java index 3df2fc80b..47dbb25fe 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/I18n.java @@ -38,18 +38,18 @@ public final class I18n { resourceBundle = locale.getResourceBundle(); } + public static SupportedLocale getLocale() { + return locale; + } + public static boolean isUseChinese() { - return locale.getLocale() == Locale.CHINA; + return locale.getLocale().getLanguage().equals("zh"); } public static ResourceBundle getResourceBundle() { return resourceBundle; } - public static String getName(SupportedLocale locale) { - return locale == Locales.DEFAULT ? resourceBundle.getString("lang.default") : locale.getResourceBundle().getString("lang"); - } - public static String i18n(String key, Object... formatArgs) { try { return String.format(getResourceBundle().getString(key), formatArgs); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/Locales.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/Locales.java index a2fb4c6a4..f661eb6a1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/Locales.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/Locales.java @@ -32,46 +32,70 @@ import java.util.List; import java.util.Locale; import java.util.ResourceBundle; +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + public final class Locales { private Locales() { } - public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault()); + public static final SupportedLocale DEFAULT = new SupportedLocale("def", Locale.getDefault()) { + @Override + public String getDisplayName(SupportedLocale inLocale) { + try { + return inLocale.getResourceBundle().getString("lang.default"); + } catch (Throwable e) { + LOG.warning("Failed to get localized name for default locale", e); + return "Default"; + } + } + }; /** * English */ - public static final SupportedLocale EN = new SupportedLocale(Locale.ROOT); + public static final SupportedLocale EN = new SupportedLocale("en", Locale.ENGLISH); /** * Spanish */ - public static final SupportedLocale ES = new SupportedLocale(Locale.forLanguageTag("es")); + public static final SupportedLocale ES = new SupportedLocale("es", Locale.forLanguageTag("es")); /** * Russian */ - public static final SupportedLocale RU = new SupportedLocale(Locale.forLanguageTag("ru")); + public static final SupportedLocale RU = new SupportedLocale("ru", Locale.forLanguageTag("ru")); /** * Japanese */ - public static final SupportedLocale JA = new SupportedLocale(Locale.JAPANESE); + public static final SupportedLocale JA = new SupportedLocale("ja", Locale.JAPANESE); /** * Traditional Chinese */ - public static final SupportedLocale ZH = new SupportedLocale(Locale.TRADITIONAL_CHINESE); + public static final SupportedLocale ZH_HANT = new SupportedLocale("zh", Locale.forLanguageTag("zh-Hant")); /** * Simplified Chinese */ - public static final SupportedLocale ZH_CN = new SupportedLocale(Locale.SIMPLIFIED_CHINESE); + public static final SupportedLocale ZH_HANS = new SupportedLocale("zh_CN", Locale.forLanguageTag("zh-Hans")); /** * Wenyan (Classical Chinese) */ - public static final SupportedLocale WENYAN = new SupportedLocale(Locale.forLanguageTag("lzh")) { + public static final SupportedLocale WENYAN = new SupportedLocale("lzh", Locale.forLanguageTag("lzh")) { + + @Override + public String getDisplayName(SupportedLocale inLocale) { + if (isChinese(inLocale.locale)) + return "文言"; + + String name = super.getDisplayName(inLocale); + return name.equals("lzh") || name.equals("Literary Chinese") + ? "Classical Chinese" + : name; + } + @Override public String formatDateTime(TemporalAccessor time) { return WenyanUtils.formatDateTime(time); @@ -86,96 +110,94 @@ public final class Locales { } }; - public static final List LOCALES = List.of(DEFAULT, EN, ES, JA, RU, ZH_CN, ZH, WENYAN); + public static final List LOCALES = List.of(DEFAULT, EN, ES, JA, RU, ZH_HANS, ZH_HANT, WENYAN); public static SupportedLocale getLocaleByName(String name) { if (name == null) return DEFAULT; - switch (name.toLowerCase(Locale.ROOT)) { - case "en": - return EN; - case "es": - return ES; - case "ja": - return JA; - case "ru": - return RU; - case "zh": - return ZH; - case "zh_cn": - return ZH_CN; - case "lzh": - return WENYAN; - default: - return DEFAULT; + + for (SupportedLocale locale : LOCALES) { + if (locale.getName().equalsIgnoreCase(name)) + return locale; } + + return DEFAULT; } - public static String getNameByLocale(SupportedLocale locale) { - if (locale == EN) return "en"; - else if (locale == ES) return "es"; - else if (locale == RU) return "ru"; - else if (locale == JA) return "ja"; - else if (locale == ZH) return "zh"; - else if (locale == ZH_CN) return "zh_CN"; - else if (locale == WENYAN) return "lzh"; - else if (locale == DEFAULT) return "def"; - else throw new IllegalArgumentException("Unknown locale: " + locale); + public static boolean isEnglish(Locale locale) { + return locale.getLanguage().equals("en") || locale.getLanguage().isEmpty(); + } + + public static boolean isChinese(Locale locale) { + return locale.getLanguage().equals("zh") || locale.getLanguage().equals("lzh"); } @JsonAdapter(SupportedLocale.TypeAdapter.class) public static class SupportedLocale { + private final String name; private final Locale locale; private ResourceBundle resourceBundle; private DateTimeFormatter dateTimeFormatter; - SupportedLocale(Locale locale) { + SupportedLocale(String name, Locale locale) { + this.name = name; this.locale = locale; } + public String getName() { + return name; + } + public Locale getLocale() { return locale; } + public String getDisplayName(SupportedLocale inLocale) { + if (inLocale.locale.getLanguage().equals("lzh")) + inLocale = ZH_HANT; + return locale.getDisplayName(inLocale.getLocale()); + } + public ResourceBundle getResourceBundle() { ResourceBundle bundle = resourceBundle; if (resourceBundle == null) { - if (this != DEFAULT && this.locale == DEFAULT.locale) { - bundle = DEFAULT.getResourceBundle(); - } else { - bundle = ResourceBundle.getBundle("assets.lang.I18N", locale, new ResourceBundle.Control() { - @Override - public List getCandidateLocales(String baseName, Locale locale) { - if (locale.getLanguage().equals("zh")) { - boolean simplified; + bundle = ResourceBundle.getBundle("assets.lang.I18N", locale, new ResourceBundle.Control() { + @Override + public List getCandidateLocales(String baseName, Locale locale) { + if (locale.getLanguage().equals("zh")) { + boolean simplified; - String script = locale.getScript(); - String region = locale.getCountry(); - if (script.isEmpty()) - simplified = region.equals("CN") || region.equals("SG"); - else - simplified = script.equals("Hans"); + String script = locale.getScript(); + String region = locale.getCountry(); + if (script.isEmpty()) + simplified = region.equals("CN") || region.equals("SG"); + else + simplified = script.equals("Hans"); - if (simplified) { - return List.of( - Locale.SIMPLIFIED_CHINESE, - Locale.CHINESE, - Locale.ROOT - ); - } - } - - if (locale.getLanguage().equals("lzh")) { + if (simplified) { return List.of( - locale, + Locale.SIMPLIFIED_CHINESE, Locale.CHINESE, Locale.ROOT ); } - return super.getCandidateLocales(baseName, locale); } - }); - } + + if (locale.getLanguage().equals("lzh")) { + return List.of( + locale, + Locale.CHINESE, + Locale.ROOT + ); + } + + if (locale.getLanguage().equals("en")) { + return List.of(Locale.ROOT); + } + + return super.getCandidateLocales(baseName, locale); + } + }); resourceBundle = bundle; } @@ -194,10 +216,15 @@ public final class Locales { return version.getSelfVersion(); } + public boolean isSameLanguage(SupportedLocale other) { + return this.getLocale().getLanguage().equals(other.getLocale().getLanguage()) + || isChinese(this.getLocale()) && isChinese(other.getLocale()); + } + public static final class TypeAdapter extends com.google.gson.TypeAdapter { @Override public void write(JsonWriter out, SupportedLocale value) throws IOException { - out.value(getNameByLocale(value)); + out.value(value.getName()); } @Override diff --git a/HMCL/src/main/resources/assets/lang/I18N.properties b/HMCL/src/main/resources/assets/lang/I18N.properties index 5928f129d..bd26eaf60 100644 --- a/HMCL/src/main/resources/assets/lang/I18N.properties +++ b/HMCL/src/main/resources/assets/lang/I18N.properties @@ -766,7 +766,6 @@ java.installing=Installing Java java.uninstall=Uninstall Java java.uninstall.confirm=Are you sure you want to uninstall this Java? This action cannot be undone! -lang=English lang.default=Use System Locales launch.advice=%s Do you still want to continue to launch? diff --git a/HMCL/src/main/resources/assets/lang/I18N_es.properties b/HMCL/src/main/resources/assets/lang/I18N_es.properties index 6ece2869f..63d50ab0e 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_es.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_es.properties @@ -772,7 +772,6 @@ java.installing=Instalando Java java.uninstall=Desinstalar Java java.uninstall.confirm=¿Está seguro de que desea desinstalar este Java? ¡Esta acción no se puede deshacer! -lang=Español lang.default=Usar idioma del sistema launch.advice=%s ¿Todavía quieres continuar? diff --git a/HMCL/src/main/resources/assets/lang/I18N_ja.properties b/HMCL/src/main/resources/assets/lang/I18N_ja.properties index 51d1d56cc..768b72fcd 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ja.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ja.properties @@ -492,7 +492,6 @@ java.install.warning.invalid_character=名前に不正な文字が含まれて java.uninstall=このJavaをアンインストールする java.uninstall.confirm=本当にこのJavaをアンインストールしますか?この操作は元に戻せません! -lang=日本語 lang.default=システム言語を使用する launch.advice.java.auto=現在選択されているJavaVMは、ゲームの要件を満たしていません。適切なJavaVMを選択することを許可しますか?または、ゲーム設定で適切なJavaVMを選択することもできます。 diff --git a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties index 99bf4da9c..354bf8464 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_lzh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_lzh.properties @@ -510,7 +510,6 @@ java.installing=置爪哇 java.uninstall=移除此爪哇 java.uninstall.confirm=君真欲移除此爪哇乎?此舉不可復! -lang=文言 lang.default=依械綱預定 launch.advice=%s 誠欲續啟? diff --git a/HMCL/src/main/resources/assets/lang/I18N_ru.properties b/HMCL/src/main/resources/assets/lang/I18N_ru.properties index 8cba759a9..dbf6e15f5 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_ru.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_ru.properties @@ -768,7 +768,6 @@ java.installing=Установка Java java.uninstall=Удалить Java java.uninstall.confirm=Вы уверены, что хотите удалить эту Java? Это действие нельзя отменить! -lang=Русский lang.default=Использовать язык системы launch.advice=%s Вы все еще хотите продолжить запуск? diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh.properties b/HMCL/src/main/resources/assets/lang/I18N_zh.properties index 3de10670f..61d7c33c1 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh.properties @@ -575,7 +575,6 @@ java.installing=安裝 Java java.uninstall=移除此 Java java.uninstall.confirm=你確定要移除此 Java 嗎?此操作無法復原! -lang=繁體中文 lang.default=使用系統語言 launch.advice=%s 是否繼續啟動? diff --git a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties index f0922281a..496d768cf 100644 --- a/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties +++ b/HMCL/src/main/resources/assets/lang/I18N_zh_CN.properties @@ -585,7 +585,6 @@ java.installing=安装 Java java.uninstall=卸载此 Java java.uninstall.confirm=你确定要卸载此 Java 吗?此操作无法撤销! -lang=简体中文 lang.default=跟随系统语言 launch.advice=%s 是否继续启动? diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java index 595b66822..815c25ddc 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/launch/DefaultLauncher.java @@ -442,7 +442,7 @@ public class DefaultLauncher extends Launcher { pair("${library_directory}", repository.getLibrariesDirectory(version).getAbsolutePath()), pair("${classpath_separator}", File.pathSeparator), pair("${primary_jar}", repository.getVersionJar(version).getAbsolutePath()), - pair("${language}", Locale.getDefault().toString()), + pair("${language}", Locale.getDefault().toLanguageTag()), // defined by HMCL // libraries_directory stands for historical reasons here. We don't know the official launcher