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 440b58d82..892ad574c 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 @@ -71,6 +71,11 @@ public final class I18n { else return WenyanUtils.translateGenericVersion(version.getSelfVersion()); } + + if (LocaleUtils.isEnglish(locale.getLocale()) && "Qabs".equals(LocaleUtils.getScript(locale.getLocale()))) { + return UpsideDownUtils.translate(version.getSelfVersion()); + } + return version.getSelfVersion(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/UpsideDownUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/UpsideDownUtils.java new file mode 100644 index 000000000..6ed4c545b --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/util/i18n/UpsideDownUtils.java @@ -0,0 +1,58 @@ +/* + * 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; + +import java.util.LinkedHashMap; +import java.util.Map; + +/// @author Glavo +public final class UpsideDownUtils { + private static final Map MAPPER = new LinkedHashMap<>(); + + private static void putChars(char baseChar, String upsideDownChars) { + for (int i = 0; i < upsideDownChars.length(); i++) { + MAPPER.put(baseChar + i, (int) upsideDownChars.charAt(i)); + } + } + + private static void putChars(String baseChars, String upsideDownChars) { + if (baseChars.length() != upsideDownChars.length()) { + throw new IllegalArgumentException("baseChars and upsideDownChars must have same length"); + } + + for (int i = 0; i < baseChars.length(); i++) { + MAPPER.put((int) baseChars.charAt(i), (int) upsideDownChars.charAt(i)); + } + } + + static { + putChars('a', "ɐqɔpǝɟbɥıظʞןɯuuodbɹsʇnʌʍxʎz"); + putChars('A', "ⱯᗺƆᗡƎℲ⅁HIſʞꞀWNOԀὉᴚS⟘∩ΛMXʎZ"); + putChars('0', "0ƖᘔƐ߈ϛ9ㄥ86"); + putChars("_,;.?!/\\'", "‾'؛˙¿¡/\\,"); + } + + public static String translate(String str) { + StringBuilder builder = new StringBuilder(str.length()); + str.codePoints().forEach(ch -> builder.appendCodePoint(MAPPER.getOrDefault(ch, ch))); + return builder.reverse().toString(); + } + + private UpsideDownUtils() { + } +} diff --git a/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/UpsideDownTranslate.java b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/UpsideDownTranslate.java index 54e2cdf84..9c4c1c47f 100644 --- a/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/UpsideDownTranslate.java +++ b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/UpsideDownTranslate.java @@ -72,11 +72,11 @@ public abstract class UpsideDownTranslate extends DefaultTask { } private static final class Translator { - private static final Map mapper = new LinkedHashMap<>(); + private static final Map MAPPER = new LinkedHashMap<>(); private static void putChars(char baseChar, String upsideDownChars) { for (int i = 0; i < upsideDownChars.length(); i++) { - mapper.put(baseChar + i, (int) upsideDownChars.charAt(i)); + MAPPER.put(baseChar + i, (int) upsideDownChars.charAt(i)); } } @@ -86,14 +86,14 @@ public abstract class UpsideDownTranslate extends DefaultTask { } for (int i = 0; i < baseChars.length(); i++) { - mapper.put((int) baseChars.charAt(i), (int) upsideDownChars.charAt(i)); + MAPPER.put((int) baseChars.charAt(i), (int) upsideDownChars.charAt(i)); } } static { putChars('a', "ɐqɔpǝɟbɥıظʞןɯuuodbɹsʇnʌʍxʎz"); putChars('A', "ⱯᗺƆᗡƎℲ⅁HIſʞꞀWNOԀὉᴚS⟘∩ΛMXʎZ"); - putChars('0', "0ƖᄅƐㄣϛ9ㄥ86"); + putChars('0', "0ƖᘔƐ߈ϛ9ㄥ86"); putChars("_,;.?!/\\'", "‾'؛˙¿¡/\\,"); } @@ -132,7 +132,7 @@ public abstract class UpsideDownTranslate extends DefaultTask { } } - int udCh = mapper.getOrDefault(ch, ch); + int udCh = MAPPER.getOrDefault(ch, ch); if (Character.isBmpCodePoint(udCh)) { lineBuilder.insert(0, (char) udCh); } else { diff --git a/docs/Localization_zh.md b/docs/Localization_zh.md index 59b821db4..47022ecac 100644 --- a/docs/Localization_zh.md +++ b/docs/Localization_zh.md @@ -13,6 +13,7 @@ HMCL 为多种语言提供本地化支持。 | 语言 | 语言标签 | 首选本地化文件后缀 | 首选本地化键 | [游戏语言文件](https://minecraft.wiki/w/Language) | 支持状态 | 志愿者 | |---------|-----------|------------|-----------|---------------------------------------------|--------|-------------------------------------------| | 英语 | `en` | (空) | `default` | `en_us` | **主要** | [Glavo](https://github.com/Glavo) | +| 英语 (颠倒) | `en-Qabs` | `en_Qabs` | `en-Qabs` | `en_ud` | 自动 | | | 中文 (简体) | `zh-Hans` | `_zh` | `zh` | `zh_cn` | **主要** | [Glavo](https://github.com/Glavo) | | 中文 (繁体) | `zh-Hant` | `_zh_Hant` | `zh-Hant` | `zh_tw`
`zh_hk` | **主要** | [Glavo](https://github.com/Glavo) | | 中文 (文言) | `lzh` | `_lzh` | `lzh` | `lzh` | 次要 | | @@ -48,20 +49,24 @@ HMCL 欢迎任何人参与翻译和贡献。但是维护更多语言的翻译需 我们希望能够找到擅长该语言者帮助我们长期维护新增的本地化文件。 如果可能缺少长期维护者,我们会更慎重地考虑是否要加入对该语言的支持。 -我们建议贡献者在提供新语言翻译之前先通过 [Issue](https://github.com/HMCL-dev/HMCL/issues/new?template=feature.yml) 提出一个功能请求, +我们建议贡献者在提供新语言翻译之前先通过 [Issue](https://github.com/HMCL-dev/HMCL/issues/new?template=feature.yml) +提出一个功能请求, 与其他贡献者先进行讨论,确定了未来的维护方式后再进行翻译工作。 ### 开始翻译 -如果你想为 HMCL 添加新的语言支持,请从翻译 [`I18N.properties`](../HMCL/src/main/resources/assets/lang/I18N.properties) 开始。 +如果你想为 HMCL 添加新的语言支持,请从翻译 [`I18N.properties`](../HMCL/src/main/resources/assets/lang/I18N.properties) +开始。 HMCL 的绝大多数文本都位于这个文件中,翻译此文件就能翻译整个界面。 -这是一个 Java Properties 文件,格式非常简单。在翻译前请先阅读该格式的介绍: [Properties 文件](https://en.wikipedia.org/wiki/.properties)。 +这是一个 Java Properties +文件,格式非常简单。在翻译前请先阅读该格式的介绍: [Properties 文件](https://en.wikipedia.org/wiki/.properties)。 作为翻译的第一步,请从[这张表格](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes)中查询这个语言对应的两字母或三字母语言标签。 例如,英语的语言标签为 `en`。 -在确定了语言标签后,请在 [`I18N.properties` 文件旁](../HMCL/src/main/resources/assets/lang)创建 `I18N_<语言标签>.properites` (例如 `I18N_en.properties`) 文件。 +在确定了语言标签后,请在 [`I18N.properties` 文件旁](../HMCL/src/main/resources/assets/lang)创建 +`I18N_<语言标签>.properites` (例如 `I18N_en.properties`) 文件。 随后,你就可以开始在这个文件中进行翻译工作了。 `I18N.properties` 文件会遵循[资源回退机制](#资源回退机制)查询缺失的译文。