优化语言设置 (#4362)

This commit is contained in:
Glavo
2025-08-31 00:18:25 +08:00
committed by GitHub
parent 73531dbf60
commit b7361c8da4
11 changed files with 108 additions and 80 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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<SupportedLocale> LOCALES = List.of(DEFAULT, EN, ES, JA, RU, ZH_CN, ZH, WENYAN);
public static final List<SupportedLocale> 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<Locale> 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<Locale> 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<SupportedLocale> {
@Override
public void write(JsonWriter out, SupportedLocale value) throws IOException {
out.value(getNameByLocale(value));
out.value(value.getName());
}
@Override

View File

@@ -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?

View File

@@ -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?

View File

@@ -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を選択することもできます。

View File

@@ -510,7 +510,6 @@ java.installing=置爪哇
java.uninstall=移除此爪哇
java.uninstall.confirm=君真欲移除此爪哇乎?此舉不可復!
lang=文言
lang.default=依械綱預定
launch.advice=%s 誠欲續啟?

View File

@@ -768,7 +768,6 @@ java.installing=Установка Java
java.uninstall=Удалить Java
java.uninstall.confirm=Вы уверены, что хотите удалить эту Java? Это действие нельзя отменить!
lang=Русский
lang.default=Использовать язык системы
launch.advice=%s Вы все еще хотите продолжить запуск?

View File

@@ -575,7 +575,6 @@ java.installing=安裝 Java
java.uninstall=移除此 Java
java.uninstall.confirm=你確定要移除此 Java 嗎?此操作無法復原!
lang=繁體中文
lang.default=使用系統語言
launch.advice=%s 是否繼續啟動?

View File

@@ -585,7 +585,6 @@ java.installing=安装 Java
java.uninstall=卸载此 Java
java.uninstall.confirm=你确定要卸载此 Java 吗?此操作无法撤销!
lang=简体中文
lang.default=跟随系统语言
launch.advice=%s 是否继续启动?

View File

@@ -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