优化对颠倒的英语的支持 (#4577)
This commit is contained in:
@@ -72,6 +72,7 @@ import org.jackhuang.hmcl.util.Holder;
|
|||||||
import org.jackhuang.hmcl.util.Lang;
|
import org.jackhuang.hmcl.util.Lang;
|
||||||
import org.jackhuang.hmcl.util.StringUtils;
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
import org.jackhuang.hmcl.util.TaskCancellationAction;
|
||||||
|
import org.jackhuang.hmcl.util.i18n.I18n;
|
||||||
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
import org.jackhuang.hmcl.util.javafx.BindingMapping;
|
||||||
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
|
||||||
|
|
||||||
@@ -115,6 +116,10 @@ public final class MainPage extends StackPane implements DecoratorPage {
|
|||||||
|
|
||||||
ImageView titleIcon = new ImageView(FXUtils.newBuiltinImage("/assets/img/icon-title.png"));
|
ImageView titleIcon = new ImageView(FXUtils.newBuiltinImage("/assets/img/icon-title.png"));
|
||||||
Label titleLabel = new Label(Metadata.FULL_TITLE);
|
Label titleLabel = new Label(Metadata.FULL_TITLE);
|
||||||
|
if (I18n.isUpsideDown()) {
|
||||||
|
titleIcon.setRotate(180);
|
||||||
|
titleLabel.setRotate(180);
|
||||||
|
}
|
||||||
titleLabel.getStyleClass().add("jfx-decorator-title");
|
titleLabel.getStyleClass().add("jfx-decorator-title");
|
||||||
titleNode.getChildren().setAll(titleIcon, titleLabel);
|
titleNode.getChildren().setAll(titleIcon, titleLabel);
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ public final class I18n {
|
|||||||
return locale;
|
return locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isUpsideDown() {
|
||||||
|
return LocaleUtils.getScript(locale.getLocale()).equals("Qabs");
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isUseChinese() {
|
public static boolean isUseChinese() {
|
||||||
return LocaleUtils.isChinese(locale.getLocale());
|
return LocaleUtils.isChinese(locale.getLocale());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,37 +17,46 @@
|
|||||||
*/
|
*/
|
||||||
package org.jackhuang.hmcl.util.i18n;
|
package org.jackhuang.hmcl.util.i18n;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.jackhuang.hmcl.util.logging.Logger.LOG;
|
||||||
|
|
||||||
/// @author Glavo
|
/// @author Glavo
|
||||||
public final class UpsideDownUtils {
|
public final class UpsideDownUtils {
|
||||||
private static final Map<Integer, Integer> MAPPER = new LinkedHashMap<>();
|
private static final Map<Integer, Integer> MAPPER = loadMap();
|
||||||
|
|
||||||
private static void putChars(char baseChar, String upsideDownChars) {
|
private static Map<Integer, Integer> loadMap() {
|
||||||
for (int i = 0; i < upsideDownChars.length(); i++) {
|
var map = new LinkedHashMap<Integer, Integer>();
|
||||||
MAPPER.put(baseChar + i, (int) upsideDownChars.charAt(i));
|
|
||||||
|
InputStream inputStream = UpsideDownUtils.class.getResourceAsStream("/assets/lang/upside_down.txt");
|
||||||
|
if (inputStream != null) {
|
||||||
|
try (inputStream) {
|
||||||
|
new String(inputStream.readAllBytes(), StandardCharsets.UTF_8).lines().forEach(line -> {
|
||||||
|
if (line.isBlank() || line.startsWith("#"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (line.length() != 2) {
|
||||||
|
LOG.warning("Invalid line: " + line);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put((int) line.charAt(0), (int) line.charAt(1));
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warning("Failed to load upside_down.txt", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.warning("upside_down.txt not found");
|
||||||
}
|
}
|
||||||
}
|
return Collections.unmodifiableMap(map);
|
||||||
|
|
||||||
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ɥıظʞןɯuodbɹsʇnʌʍxʎz");
|
|
||||||
putChars('A', "ⱯᗺƆᗡƎℲ⅁HIſʞꞀWNOԀὉᴚS⟘∩ΛMXʎZ");
|
|
||||||
putChars('0', "0ƖᘔƐㄣϛ9ㄥ86");
|
|
||||||
putChars("_,;.?!/\\'", "‾'⸵˙¿¡/\\,");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String translate(String str) {
|
public static String translate(String str) {
|
||||||
@@ -56,7 +65,7 @@ public final class UpsideDownUtils {
|
|||||||
return builder.reverse().toString();
|
return builder.reverse().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DateTimeFormatter BASE_FORMATTER = DateTimeFormatter.ofPattern("MMM d, yyyy, h:mm:ss a")
|
private static final DateTimeFormatter BASE_FORMATTER = DateTimeFormatter.ofPattern("MMM d, yyyy, h:mm:ss a")
|
||||||
.withZone(ZoneId.systemDefault());
|
.withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
public static String formatDateTime(TemporalAccessor time) {
|
public static String formatDateTime(TemporalAccessor time) {
|
||||||
|
|||||||
71
HMCLCore/src/main/resources/assets/lang/upside_down.txt
Normal file
71
HMCLCore/src/main/resources/assets/lang/upside_down.txt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
aɐ
|
||||||
|
bq
|
||||||
|
cɔ
|
||||||
|
dp
|
||||||
|
eǝ
|
||||||
|
fɟ
|
||||||
|
gᵷ
|
||||||
|
hɥ
|
||||||
|
iᴉ
|
||||||
|
jɾ
|
||||||
|
kʞ
|
||||||
|
lꞁ
|
||||||
|
mɯ
|
||||||
|
nu
|
||||||
|
oo
|
||||||
|
pd
|
||||||
|
qb
|
||||||
|
rɹ
|
||||||
|
ss
|
||||||
|
tʇ
|
||||||
|
un
|
||||||
|
vʌ
|
||||||
|
wʍ
|
||||||
|
xx
|
||||||
|
yʎ
|
||||||
|
zz
|
||||||
|
AⱯ
|
||||||
|
Bᗺ
|
||||||
|
CƆ
|
||||||
|
Dᗡ
|
||||||
|
EƎ
|
||||||
|
FℲ
|
||||||
|
G⅁
|
||||||
|
HH
|
||||||
|
II
|
||||||
|
Jſ
|
||||||
|
Kʞ
|
||||||
|
LꞀ
|
||||||
|
MW
|
||||||
|
NN
|
||||||
|
OO
|
||||||
|
PԀ
|
||||||
|
QὉ
|
||||||
|
Rᴚ
|
||||||
|
SS
|
||||||
|
T⟘
|
||||||
|
U∩
|
||||||
|
VΛ
|
||||||
|
WM
|
||||||
|
XX
|
||||||
|
Yʎ
|
||||||
|
ZZ
|
||||||
|
00
|
||||||
|
1Ɩ
|
||||||
|
2ᘔ
|
||||||
|
3Ɛ
|
||||||
|
4ㄣ
|
||||||
|
5ϛ
|
||||||
|
69
|
||||||
|
7ㄥ
|
||||||
|
88
|
||||||
|
96
|
||||||
|
_‾
|
||||||
|
,'
|
||||||
|
;⸵
|
||||||
|
.˙
|
||||||
|
?¿
|
||||||
|
!¡
|
||||||
|
//
|
||||||
|
\\
|
||||||
|
',
|
||||||
@@ -18,18 +18,18 @@
|
|||||||
package org.jackhuang.hmcl.gradle.l10n;
|
package org.jackhuang.hmcl.gradle.l10n;
|
||||||
|
|
||||||
import org.gradle.api.DefaultTask;
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.GradleException;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
import org.gradle.api.tasks.InputFile;
|
import org.gradle.api.tasks.InputFile;
|
||||||
import org.gradle.api.tasks.OutputFile;
|
import org.gradle.api.tasks.OutputFile;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.*;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@@ -75,29 +75,31 @@ public abstract class UpsideDownTranslate extends DefaultTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static final class Translator {
|
static final class Translator {
|
||||||
private static final Map<Integer, Integer> MAPPER = new LinkedHashMap<>();
|
private static final Map<Integer, Integer> MAPPER = loadMap();
|
||||||
|
|
||||||
private static void putChars(char baseChar, String upsideDownChars) {
|
private static Map<Integer, Integer> loadMap() {
|
||||||
for (int i = 0; i < upsideDownChars.length(); i++) {
|
var map = new LinkedHashMap<Integer, Integer>();
|
||||||
MAPPER.put(baseChar + i, (int) upsideDownChars.charAt(i));
|
|
||||||
|
InputStream inputStream = UpsideDownTranslate.class.getResourceAsStream("upside_down.txt");
|
||||||
|
if (inputStream != null) {
|
||||||
|
try (inputStream) {
|
||||||
|
new String(inputStream.readAllBytes(), StandardCharsets.UTF_8).lines().forEach(line -> {
|
||||||
|
if (line.isBlank() || line.startsWith("#"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (line.length() != 2) {
|
||||||
|
throw new GradleException("Invalid line: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put((int) line.charAt(0), (int) line.charAt(1));
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new GradleException("Failed to load upside_down.txt", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new GradleException("upside_down.txt not found");
|
||||||
}
|
}
|
||||||
}
|
return Collections.unmodifiableMap(map);
|
||||||
|
|
||||||
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ɥıظʞןɯuodbɹsʇnʌʍxʎz");
|
|
||||||
putChars('A', "ⱯᗺƆᗡƎℲ⅁HIſʞꞀWNOԀὉᴚS⟘∩ΛMXʎZ");
|
|
||||||
putChars('0', "0ƖᘔƐㄣϛ9ㄥ86");
|
|
||||||
putChars("_,;.?!/\\'", "‾'⸵˙¿¡/\\,");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern FORMAT_PATTERN = Pattern.compile("^%(\\d\\$)?(\\d+)?(\\.\\d+)?([sdf])");
|
private static final Pattern FORMAT_PATTERN = Pattern.compile("^%(\\d\\$)?(\\d+)?(\\.\\d+)?([sdf])");
|
||||||
|
|||||||
Reference in New Issue
Block a user