diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/SupportedLocale.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/SupportedLocale.java index a1d2b4ca9..820b5c0c2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/SupportedLocale.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/SupportedLocale.java @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - package org.jackhuang.hmcl.util.i18n; import com.google.gson.annotations.JsonAdapter; @@ -73,6 +72,8 @@ public final class SupportedLocale { private final boolean isDefault; private final String name; private final Locale locale; + private final TextDirection textDirection; + private ResourceBundle resourceBundle; private ResourceBundle localeNamesBundle; private List candidateLocales; @@ -86,12 +87,14 @@ public final class SupportedLocale { this.locale = StringUtils.isBlank(language) ? LocaleUtils.SYSTEM_DEFAULT : Locale.forLanguageTag(language); + this.textDirection = LocaleUtils.getTextDirection(locale); } SupportedLocale(Locale locale) { this.isDefault = false; this.name = locale.toLanguageTag(); this.locale = locale; + this.textDirection = LocaleUtils.getTextDirection(locale); } public boolean isDefault() { @@ -106,6 +109,10 @@ public final class SupportedLocale { return locale; } + public TextDirection getTextDirection() { + return textDirection; + } + public String getDisplayName(SupportedLocale inLocale) { if (isDefault()) { try { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocaleUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocaleUtils.java index f254c30fb..783c95163 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocaleUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/LocaleUtils.java @@ -27,14 +27,7 @@ import org.jetbrains.annotations.Unmodifiable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.stream.Stream; @@ -55,6 +48,7 @@ public final class LocaleUtils { private static final Map subLanguageToParent = new HashMap<>(); private static final Map iso3To2 = new HashMap<>(); + private static final Set rtl = new HashSet<>(); static { try { @@ -96,6 +90,17 @@ public final class LocaleUtils { } catch (Throwable e) { LOG.warning("Failed to load iso_languages.csv", e); } + + try { + for (String line : Lang.toIterable(IOUtils.readFullyAsString(LocaleUtils.class.getResourceAsStream("/assets/lang/rtl.txt")).lines())) { + if (line.startsWith("#") || line.isBlank()) { + continue; + } + rtl.add(line.trim()); + } + } catch (Throwable e) { + LOG.warning("Failed to load rtl.txt", e); + } } private static Locale getInstance(String language, String script, String region, @@ -163,6 +168,21 @@ public final class LocaleUtils { return locale.getScript(); } + public static @NotNull TextDirection getTextDirection(Locale locale) { + TextDirection direction = rtl.contains(getRootLanguage(locale)) + ? TextDirection.RIGHT_TO_LEFT + : TextDirection.LEFT_TO_RIGHT; + + if ("Qabs".equals(getScript(locale))) { + direction = switch (direction) { + case RIGHT_TO_LEFT -> TextDirection.LEFT_TO_RIGHT; + case LEFT_TO_RIGHT -> TextDirection.RIGHT_TO_LEFT; + }; + } + + return direction; + } + private static final ConcurrentMap> CANDIDATE_LOCALES = new ConcurrentHashMap<>(); public static @NotNull List getCandidateLocales(Locale locale) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/TextDirection.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/TextDirection.java new file mode 100644 index 000000000..f9f00f190 --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/i18n/TextDirection.java @@ -0,0 +1,24 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util.i18n; + +/// @author Glavo +public enum TextDirection { + LEFT_TO_RIGHT, + RIGHT_TO_LEFT; +} diff --git a/HMCLCore/src/main/resources/assets/lang/rtl.txt b/HMCLCore/src/main/resources/assets/lang/rtl.txt new file mode 100644 index 000000000..cbd40fc72 --- /dev/null +++ b/HMCLCore/src/main/resources/assets/lang/rtl.txt @@ -0,0 +1,6 @@ +ar +fa +he +ps +ur +yi \ No newline at end of file diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/i18n/LocaleUtilsTest.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/i18n/LocaleUtilsTest.java index 9074138e5..64bce19f4 100644 --- a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/i18n/LocaleUtilsTest.java +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/i18n/LocaleUtilsTest.java @@ -220,4 +220,18 @@ public final class LocaleUtilsTest { assertNull(LocaleUtils.getParentLanguage("zh")); assertNull(LocaleUtils.getParentLanguage("zho")); } + + @Test + public void testGetTextDirection() { + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("en"))); + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("en-US"))); + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("zh"))); + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("zh-Hans"))); + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("zh-CN"))); + assertEquals(TextDirection.LEFT_TO_RIGHT, LocaleUtils.getTextDirection(Locale.forLanguageTag("ar-Qabs"))); + + assertEquals(TextDirection.RIGHT_TO_LEFT, LocaleUtils.getTextDirection(Locale.forLanguageTag("en-Qabs"))); + assertEquals(TextDirection.RIGHT_TO_LEFT, LocaleUtils.getTextDirection(Locale.forLanguageTag("ar"))); + assertEquals(TextDirection.RIGHT_TO_LEFT, LocaleUtils.getTextDirection(Locale.forLanguageTag("ara"))); + } }