This commit is contained in:
Glavo 2025-09-21 21:33:55 +08:00
parent 8c2b65c876
commit 746729859a
6 changed files with 176 additions and 6 deletions

View File

@ -1,4 +1,5 @@
import org.jackhuang.hmcl.gradle.l10n.CheckTranslations import org.jackhuang.hmcl.gradle.l10n.CheckTranslations
import org.jackhuang.hmcl.gradle.l10n.CreateLocaleNames
import org.jackhuang.hmcl.gradle.l10n.UpsideDownTranslate import org.jackhuang.hmcl.gradle.l10n.UpsideDownTranslate
import org.jackhuang.hmcl.gradle.mod.ParseModDataTask import org.jackhuang.hmcl.gradle.mod.ParseModDataTask
import java.net.URI import java.net.URI
@ -205,9 +206,16 @@ tasks.shadowJar {
} }
} }
val generatedDir = layout.buildDirectory.dir("generated")
val upsideDownTranslate by tasks.registering(UpsideDownTranslate::class) { val upsideDownTranslate by tasks.registering(UpsideDownTranslate::class) {
inputFile.set(layout.projectDirectory.file("src/main/resources/assets/lang/I18N.properties")) inputFile.set(layout.projectDirectory.file("src/main/resources/assets/lang/I18N.properties"))
outputFile.set(layout.buildDirectory.file("generated/i18n/I18N_en_Qabs.properties")) outputFile.set(generatedDir.map { it.file("generated/i18n/I18N_en_Qabs.properties") })
}
val createLocaleNames by tasks.registering(CreateLocaleNames::class) {
languagesFile.set(layout.projectDirectory.file("src/main/resources/assets/lang/languages.json"))
outputDirectory.set(generatedDir.map { it.dir("generated/LocaleNames") })
} }
tasks.processResources { tasks.processResources {
@ -221,7 +229,9 @@ tasks.processResources {
into("assets/lang") { into("assets/lang") {
from(upsideDownTranslate.map { it.outputFile }) from(upsideDownTranslate.map { it.outputFile })
from(createLocaleNames.map { it.outputDirectory })
} }
} }
val makeExecutables by tasks.registering { val makeExecutables by tasks.registering {

View File

@ -42,15 +42,18 @@ public final class Locales {
public static final SupportedLocale DEFAULT = new SupportedLocale(); public static final SupportedLocale DEFAULT = new SupportedLocale();
public static List<SupportedLocale> getSupportedLocales() { public static List<SupportedLocale> getSupportedLocales() {
List<SupportedLocale> list = new ArrayList<>();
list.add(DEFAULT);
InputStream locales = Locales.class.getResourceAsStream("/assets/lang/languages.json"); InputStream locales = Locales.class.getResourceAsStream("/assets/lang/languages.json");
if (locales != null) { if (locales != null) {
try (locales) { try (locales) {
return JsonUtils.fromNonNullJsonFully(locales, JsonUtils.listTypeOf(SupportedLocale.class)); list.addAll(JsonUtils.fromNonNullJsonFully(locales, JsonUtils.listTypeOf(SupportedLocale.class)));
} catch (Throwable e) { } catch (Throwable e) {
LOG.warning("Failed to load languages.json", e); LOG.warning("Failed to load languages.json", e);
} }
} }
return List.of(DEFAULT); return List.copyOf(list);
} }
private static final ConcurrentMap<Locale, SupportedLocale> LOCALES = new ConcurrentHashMap<>(); private static final ConcurrentMap<Locale, SupportedLocale> LOCALES = new ConcurrentHashMap<>();
@ -60,10 +63,10 @@ public final class Locales {
} }
public static SupportedLocale getLocaleByName(String name) { public static SupportedLocale getLocaleByName(String name) {
if (name == null || "def".equals(name) || "default".equals(name)) if (name == null || name.isEmpty() || "def".equals(name) || "default".equals(name))
return DEFAULT; return DEFAULT;
return getLocale(Locale.forLanguageTag(name)); return getLocale(Locale.forLanguageTag(name.trim()));
} }
@JsonAdapter(SupportedLocale.TypeAdapter.class) @JsonAdapter(SupportedLocale.TypeAdapter.class)

View File

@ -1,5 +1,4 @@
[ [
"default",
"en", "en",
"en-Qabs", "en-Qabs",
"es", "es",

View File

@ -17,28 +17,51 @@
*/ */
package org.jackhuang.hmcl.gradle.l10n; package org.jackhuang.hmcl.gradle.l10n;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.gradle.api.DefaultTask; import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileVisitResult; import java.nio.file.FileVisitResult;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor; import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Collectors;
/// @author Glavo /// @author Glavo
public abstract class CreateLocaleNames extends DefaultTask { public abstract class CreateLocaleNames extends DefaultTask {
@InputFile
public abstract RegularFileProperty getLanguagesFile();
@OutputDirectory @OutputDirectory
public abstract DirectoryProperty getOutputDirectory(); public abstract DirectoryProperty getOutputDirectory();
private static String mapToFileName(String base, String ext, Locale locale) {
if (locale.getLanguage().isEmpty() || locale.equals(Locale.ENGLISH))
return base + "." + ext;
else if (locale.toLanguageTag().equals("zh-Hans"))
return base + "_zh." + ext;
else
return base + "_" + locale.toLanguageTag().replace('-', '_') + "." + ext;
}
@TaskAction @TaskAction
public void run() throws IOException { public void run() throws IOException {
Path languagesFile = getLanguagesFile().get().getAsFile().toPath();
Path outputDir = getOutputDirectory().get().getAsFile().toPath(); Path outputDir = getOutputDirectory().get().getAsFile().toPath();
if (Files.isDirectory(outputDir)) { if (Files.isDirectory(outputDir)) {
@ -60,6 +83,95 @@ public abstract class CreateLocaleNames extends DefaultTask {
Files.deleteIfExists(outputDir); Files.deleteIfExists(outputDir);
Files.createDirectories(outputDir); Files.createDirectories(outputDir);
List<Locale> supportedLanguages;
try (var reader = Files.newBufferedReader(languagesFile)) {
supportedLanguages = new Gson().fromJson(reader, new TypeToken<List<String>>() {
}).stream()
.map(Locale::forLanguageTag)
.toList();
}
SortedSet<String> languages = supportedLanguages.stream()
.map(Locale::getLanguage)
.filter(it -> !it.isBlank())
.collect(Collectors.toCollection(TreeSet::new));
SortedSet<String> scripts = supportedLanguages.stream()
.map(Locale::getScript)
.filter(it -> !it.isBlank())
.collect(Collectors.toCollection(TreeSet::new));
for (Locale currentLanguage : supportedLanguages) {
InputStream overrideFile = CreateLocaleNames.class.getResourceAsStream(
mapToFileName("LocaleNamesOverride", "properties", currentLanguage));
Properties overrideProperties = new Properties();
if (overrideFile != null) {
try (var reader = new InputStreamReader(overrideFile, StandardCharsets.UTF_8)) {
overrideProperties.load(reader);
}
}
Path targetFile = outputDir.resolve(mapToFileName("LocaleNames", "properties", currentLanguage));
if (Files.exists(targetFile))
throw new GradleException(String.format("File %s already exists", targetFile));
try (var writer = Files.newBufferedWriter(targetFile)) {
writer.write("""
#
# Hello Minecraft! Launcher
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
#
""");
writer.write("# Languages\n");
for (String language : languages) {
String displayName = overrideProperties.getProperty(language);
if (displayName == null) {
displayName = new Locale.Builder()
.setLanguage(language)
.build()
.getDisplayLanguage(currentLanguage);
if (displayName.equals(language))
continue; // Skip
}
writer.write(language + "=" + displayName + "\n");
}
writer.write('\n');
writer.write("# Scripts\n");
for (String script : scripts) {
String displayName = overrideProperties.getProperty(script);
if (displayName == null) {
displayName = new Locale.Builder()
.setScript(script)
.build()
.getDisplayScript(currentLanguage);
if (displayName.equals(script))
continue; // Skip
}
writer.write(script + "=" + displayName + "\n");
}
writer.write('\n');
}
}
} }
} }

View File

@ -0,0 +1,23 @@
#
# Hello Minecraft! Launcher
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
#
# Languages
lzh=Classical Chinese
# Scripts
Qabs=Upside down

View File

@ -0,0 +1,23 @@
#
# Hello Minecraft! Launcher
# Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
#
# Languages
lzh=文言
# Scripts
Qabs=颠倒