优化 I18n (#2948)

* update

* update

* update

* update

* update
This commit is contained in:
Glavo 2024-03-23 14:11:52 +08:00 committed by GitHub
parent 8b94fe5b0b
commit 94ccee0b76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 67 additions and 84 deletions

View File

@ -25,8 +25,6 @@ import javafx.scene.control.ButtonType;
import javafx.scene.input.Clipboard;
import javafx.scene.input.DataFormat;
import javafx.stage.Stage;
import org.jackhuang.hmcl.mod.RemoteMod;
import org.jackhuang.hmcl.mod.RemoteModRepository;
import org.jackhuang.hmcl.setting.ConfigHolder;
import org.jackhuang.hmcl.setting.SambaException;
import org.jackhuang.hmcl.task.AsyncTaskExecutor;
@ -52,10 +50,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.stream.Stream;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.Logging.LOG;
@ -70,8 +66,6 @@ public final class Launcher extends Application {
CookieHandler.setDefault(COOKIE_MANAGER);
register();
LOG.info("JavaFX Version: " + System.getProperty("javafx.runtime.version"));
try {
Object pipeline = Class.forName("com.sun.prism.GraphicsPipeline").getMethod("getPipeline").invoke(null);
@ -127,20 +121,6 @@ public final class Launcher extends Application {
}
}
private static void register() {
RemoteMod.registerEmptyRemoteMod(new RemoteMod("", "", i18n("mods.broken_dependency.title"), i18n("mods.broken_dependency.desc"), new ArrayList<>(), "", "/assets/img/icon@8x.png", new RemoteMod.IMod() {
@Override
public List<RemoteMod> loadDependencies(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
@Override
public Stream<RemoteMod.Version> loadVersions(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
}));
}
private static ButtonType showAlert(AlertType alertType, String contentText, ButtonType... buttons) {
return new Alert(alertType, contentText, buttons).showAndWait().orElse(null);
}

View File

@ -29,7 +29,6 @@ import org.jackhuang.hmcl.util.versioning.GameVersionNumber;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
@ -72,7 +71,7 @@ public final class HMCLGameLauncher extends DefaultLauncher {
}
}
if (I18n.getCurrentLocale().getLocale() != Locale.CHINA) {
if (!I18n.isUseChinese()) {
return;
}

View File

@ -177,7 +177,7 @@ public abstract class SettingsView extends StackPane {
languagePane.setLeft(left);
cboLanguage = new JFXComboBox<>();
cboLanguage.setConverter(stringConverter(locale -> locale.getName(I18n.getCurrentLocale().getResourceBundle())));
cboLanguage.setConverter(stringConverter(I18n::getName));
FXUtils.setLimitWidth(cboLanguage, 300);
languagePane.setRight(cboLanguage);

View File

@ -477,7 +477,7 @@ public class DownloadListPage extends Control implements DecoratorPage, VersionP
protected void updateControl(RemoteMod dataItem, boolean empty) {
if (empty) return;
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(getSkinnable().repository.getType()).getModByCurseForgeId(dataItem.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : dataItem.getTitle());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : dataItem.getTitle());
content.setSubtitle(dataItem.getDescription());
content.getTags().setAll(dataItem.getCategories().stream()
.map(category -> getSkinnable().getLocalizedCategory(category))

View File

@ -240,7 +240,7 @@ public class DownloadPage extends Control implements DecoratorPage {
TwoLineListItem content = new TwoLineListItem();
HBox.setHgrow(content, Priority.ALWAYS);
ModTranslations.Mod mod = getSkinnable().translations.getModByCurseForgeId(getSkinnable().addon.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : getSkinnable().addon.getTitle());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : getSkinnable().addon.getTitle());
content.setSubtitle(getSkinnable().addon.getDescription());
content.getTags().setAll(getSkinnable().addon.getCategories().stream()
.map(category -> getSkinnable().page.getLocalizedCategory(category))
@ -352,15 +352,21 @@ public class DownloadPage extends Control implements DecoratorPage {
container.setOnMouseClicked(e -> Controllers.navigate(new DownloadPage(page, addon, version, callback)));
getChildren().setAll(container);
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug());
content.setTitle(mod != null && I18n.getCurrentLocale().getLocale() == Locale.CHINA ? mod.getDisplayName() : addon.getTitle());
content.setSubtitle(addon.getDescription());
content.getTags().setAll(addon.getCategories().stream()
.map(page::getLocalizedCategory)
.collect(Collectors.toList()));
if (addon != RemoteMod.BROKEN) {
ModTranslations.Mod mod = ModTranslations.getTranslationsByRepositoryType(page.repository.getType()).getModByCurseForgeId(addon.getSlug());
content.setTitle(mod != null && I18n.isUseChinese() ? mod.getDisplayName() : addon.getTitle());
content.setSubtitle(addon.getDescription());
content.getTags().setAll(addon.getCategories().stream()
.map(page::getLocalizedCategory)
.collect(Collectors.toList()));
if (StringUtils.isNotBlank(addon.getIconUrl())) {
imageView.setImage(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true, true));
if (StringUtils.isNotBlank(addon.getIconUrl())) {
imageView.setImage(FXUtils.newRemoteImage(addon.getIconUrl(), 40, 40, true, true, true));
}
} else {
content.setTitle(i18n("mods.broken_dependency.title"));
content.setSubtitle(i18n("mods.broken_dependency.desc"));
imageView.setImage(FXUtils.newBuiltinImage("/assets/img/icon@8x.png", 40, 40, true, true));
}
}
}

View File

@ -490,10 +490,8 @@ class ModListPageSkin extends SkinBase<ModListPage> {
content.getTags().add(i18n("install.installer.quilt"));
break;
}
if (dataItem.getMod() != null) {
if (I18n.getCurrentLocale().getLocale() == Locale.CHINA) {
content.getTags().add(dataItem.getMod().getDisplayName());
}
if (dataItem.getMod() != null && I18n.isUseChinese()) {
content.getTags().add(dataItem.getMod().getDisplayName());
}
content.setSubtitle(dataItem.getSubtitle());
if (booleanProperty != null) {

View File

@ -20,10 +20,9 @@ package org.jackhuang.hmcl.util.i18n;
import org.jackhuang.hmcl.util.i18n.Locales.SupportedLocale;
import java.time.Instant;
import java.util.Arrays;
import java.util.IllegalFormatException;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.logging.Level;
import static org.jackhuang.hmcl.util.Logging.LOG;
@ -34,17 +33,25 @@ public final class I18n {
}
private static volatile SupportedLocale locale = Locales.DEFAULT;
private static volatile ResourceBundle resourceBundle = locale.getResourceBundle();
private static volatile DateTimeFormatter dateTimeFormatter;
public static void setLocale(SupportedLocale locale) {
I18n.locale = locale;
resourceBundle = locale.getResourceBundle();
dateTimeFormatter = null;
}
public static SupportedLocale getCurrentLocale() {
return locale;
public static boolean isUseChinese() {
return locale.getLocale() == Locale.CHINA;
}
public static ResourceBundle getResourceBundle() {
return getCurrentLocale().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) {
@ -69,7 +76,12 @@ public final class I18n {
}
public static String formatDateTime(Instant instant) {
return getCurrentLocale().getDateTimeFormatter().format(instant);
DateTimeFormatter formatter = dateTimeFormatter;
if (formatter == null) {
formatter = dateTimeFormatter = DateTimeFormatter.ofPattern(getResourceBundle().getString("world.time")).withZone(ZoneId.systemDefault());
}
return formatter.format(instant);
}
public static boolean hasKey(String key) {

View File

@ -24,8 +24,6 @@ import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.platform.JavaVersion;
import java.io.IOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
@ -34,7 +32,7 @@ public final class Locales {
private Locales() {
}
public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault(), "lang.default");
public static final SupportedLocale DEFAULT = new SupportedLocale(Locale.getDefault());
/**
* English
@ -102,23 +100,10 @@ public final class Locales {
@JsonAdapter(SupportedLocale.TypeAdapter.class)
public static final class SupportedLocale {
private final Locale locale;
private final String name;
private final ResourceBundle resourceBundle;
private DateTimeFormatter dateTimeFormatter;
private ResourceBundle resourceBundle;
SupportedLocale(Locale locale) {
this(locale, null);
}
SupportedLocale(Locale locale, String name) {
this.locale = locale;
this.name = name;
if (JavaVersion.CURRENT_JAVA.getParsedVersion() == JavaVersion.JAVA_8) {
resourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE);
} else {
// UTF-8 is supported in Java 9+
resourceBundle = ResourceBundle.getBundle("assets.lang.I18N", locale);
}
}
public Locale getLocale() {
@ -126,20 +111,22 @@ public final class Locales {
}
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
ResourceBundle bundle = resourceBundle;
public DateTimeFormatter getDateTimeFormatter() {
if (dateTimeFormatter == null) {
dateTimeFormatter = DateTimeFormatter.ofPattern(resourceBundle.getString("world.time")).withZone(ZoneId.systemDefault());
if (resourceBundle == null) {
if (this != DEFAULT && this.locale == DEFAULT.locale) {
bundle = DEFAULT.getResourceBundle();
} else if (JavaVersion.CURRENT_JAVA.getParsedVersion() < 9) {
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale, UTF8Control.INSTANCE);
} else {
// Java 9+ uses UTF-8 as the default encoding for resource bundles
bundle = ResourceBundle.getBundle("assets.lang.I18N", locale);
}
resourceBundle = bundle;
}
return dateTimeFormatter;
}
public String getName(ResourceBundle newResourceBundle) {
if (name == null) return resourceBundle.getString("lang");
else return newResourceBundle.getString(name);
return bundle;
}
public static final class TypeAdapter extends com.google.gson.TypeAdapter<SupportedLocale> {

View File

@ -23,6 +23,7 @@ import org.jackhuang.hmcl.task.FileDownloadTask;
import java.io.IOException;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
@ -30,18 +31,18 @@ import java.util.stream.Stream;
import static org.jackhuang.hmcl.util.io.NetworkUtils.encodeLocation;
public class RemoteMod {
private static RemoteMod EMPTY = null;
public static void registerEmptyRemoteMod(RemoteMod empty) {
EMPTY = empty;
}
public static RemoteMod getEmptyRemoteMod() {
if (EMPTY == null) {
throw new NullPointerException();
public static final RemoteMod BROKEN = new RemoteMod("", "", "RemoteMod.BROKEN", "", Collections.emptyList(), "", "", new RemoteMod.IMod() {
@Override
public List<RemoteMod> loadDependencies(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
return EMPTY;
}
@Override
public Stream<RemoteMod.Version> loadVersions(RemoteModRepository modRepository) throws IOException {
throw new IOException();
}
});
private final String slug;
private final String author;
@ -158,7 +159,7 @@ public class RemoteMod {
public RemoteMod load() throws IOException {
if (this.remoteMod == null) {
if (this.type == DependencyType.BROKEN) {
this.remoteMod = RemoteMod.getEmptyRemoteMod();
this.remoteMod = RemoteMod.BROKEN;
} else {
this.remoteMod = this.remoteModRepository.getModById(this.id);
}