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.CreateLocaleNames
import org.jackhuang.hmcl.gradle.l10n.UpsideDownTranslate
import org.jackhuang.hmcl.gradle.mod.ParseModDataTask
import java.net.URI
@ -205,9 +206,16 @@ tasks.shadowJar {
}
}
val generatedDir = layout.buildDirectory.dir("generated")
val upsideDownTranslate by tasks.registering(UpsideDownTranslate::class) {
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 {
@ -221,7 +229,9 @@ tasks.processResources {
into("assets/lang") {
from(upsideDownTranslate.map { it.outputFile })
from(createLocaleNames.map { it.outputDirectory })
}
}
val makeExecutables by tasks.registering {

View File

@ -42,15 +42,18 @@ public final class Locales {
public static final SupportedLocale DEFAULT = new SupportedLocale();
public static List<SupportedLocale> getSupportedLocales() {
List<SupportedLocale> list = new ArrayList<>();
list.add(DEFAULT);
InputStream locales = Locales.class.getResourceAsStream("/assets/lang/languages.json");
if (locales != null) {
try (locales) {
return JsonUtils.fromNonNullJsonFully(locales, JsonUtils.listTypeOf(SupportedLocale.class));
list.addAll(JsonUtils.fromNonNullJsonFully(locales, JsonUtils.listTypeOf(SupportedLocale.class)));
} catch (Throwable 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<>();
@ -60,10 +63,10 @@ public final class Locales {
}
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 getLocale(Locale.forLanguageTag(name));
return getLocale(Locale.forLanguageTag(name.trim()));
}
@JsonAdapter(SupportedLocale.TypeAdapter.class)

View File

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

View File

@ -17,28 +17,51 @@
*/
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.GradleException;
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.TaskAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Collectors;
/// @author Glavo
public abstract class CreateLocaleNames extends DefaultTask {
@InputFile
public abstract RegularFileProperty getLanguagesFile();
@OutputDirectory
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
public void run() throws IOException {
Path languagesFile = getLanguagesFile().get().getAsFile().toPath();
Path outputDir = getOutputDirectory().get().getAsFile().toPath();
if (Files.isDirectory(outputDir)) {
@ -60,6 +83,95 @@ public abstract class CreateLocaleNames extends DefaultTask {
Files.deleteIfExists(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=颠倒