From 5b55e9f74a3007992006decc6c5fd92da2840c1d Mon Sep 17 00:00:00 2001 From: Glavo Date: Sun, 21 Sep 2025 22:35:19 +0800 Subject: [PATCH] update --- HMCL/build.gradle.kts | 40 ++++-- .../main/resources/assets/lang/languages.json | 11 -- .../hmcl/gradle/l10n/CreateLanguageList.java | 125 ++++++++++++++++++ 3 files changed, 152 insertions(+), 24 deletions(-) delete mode 100644 HMCL/src/main/resources/assets/lang/languages.json create mode 100644 buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/CreateLanguageList.java diff --git a/HMCL/build.gradle.kts b/HMCL/build.gradle.kts index bef641313..8aaa9f61f 100644 --- a/HMCL/build.gradle.kts +++ b/HMCL/build.gradle.kts @@ -1,4 +1,5 @@ import org.jackhuang.hmcl.gradle.l10n.CheckTranslations +import org.jackhuang.hmcl.gradle.l10n.CreateLanguageList import org.jackhuang.hmcl.gradle.l10n.CreateLocaleNames import org.jackhuang.hmcl.gradle.l10n.UpsideDownTranslate import org.jackhuang.hmcl.gradle.mod.ParseModDataTask @@ -206,21 +207,11 @@ 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(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 { dependsOn(createPropertiesFile) dependsOn(upsideDownTranslate) + dependsOn(createLocaleNames) + dependsOn(createLanguageList) into("assets/") { from(hmclPropertiesFile) @@ -228,10 +219,10 @@ tasks.processResources { } into("assets/lang") { + from(createLanguageList.map { it.outputFile }) from(upsideDownTranslate.map { it.outputFile }) from(createLocaleNames.map { it.outputDirectory }) } - } val makeExecutables by tasks.registering { @@ -365,6 +356,29 @@ tasks.register("checkTranslations") { classicalChineseFile.set(dir.file("I18N_lzh.properties")) } +// l10n + +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(generatedDir.map { it.file("generated/i18n/I18N_en_Qabs.properties") }) +} + +val createLanguageList by tasks.registering(CreateLanguageList::class) { + resourceBundleDir.set(layout.projectDirectory.dir("src/main/resources/assets/lang")) + resourceBundleBaseName.set("I18N") + additionalLanguages.set(listOf("en-Qabs")) + outputFile.set(generatedDir.map { it.file("languages.json") }) +} + +val createLocaleNames by tasks.registering(CreateLocaleNames::class) { + dependsOn(createLanguageList) + + languagesFile.set(createLanguageList.flatMap { it.outputFile }) + outputDirectory.set(generatedDir.map { it.dir("generated/LocaleNames") }) +} + // mcmod data tasks.register("parseModData") { diff --git a/HMCL/src/main/resources/assets/lang/languages.json b/HMCL/src/main/resources/assets/lang/languages.json deleted file mode 100644 index 01cc511c6..000000000 --- a/HMCL/src/main/resources/assets/lang/languages.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - "en", - "en-Qabs", - "es", - "ru", - "uk", - "ja", - "zh-Hans", - "zh-Hant", - "lzh" -] \ No newline at end of file diff --git a/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/CreateLanguageList.java b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/CreateLanguageList.java new file mode 100644 index 000000000..3e887bdc8 --- /dev/null +++ b/buildSrc/src/main/java/org/jackhuang/hmcl/gradle/l10n/CreateLanguageList.java @@ -0,0 +1,125 @@ +/* + * 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.gradle.l10n; + +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.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.stream.Collectors; + +/// @author Glavo +public abstract class CreateLanguageList extends DefaultTask { + @InputDirectory + public abstract DirectoryProperty getResourceBundleDir(); + + @Input + public abstract Property<@NotNull String> getResourceBundleBaseName(); + + @Input + public abstract ListProperty<@NotNull String> getAdditionalLanguages(); + + @OutputFile + public abstract RegularFileProperty getOutputFile(); + + @TaskAction + public void run() throws IOException { + Path inputDir = getResourceBundleDir().get().getAsFile().toPath(); + if (!Files.isDirectory(inputDir)) + throw new GradleException("Input directory not exists: " + inputDir); + + + SortedSet locales = new TreeSet<>(CreateLanguageList::compareLocale); + locales.addAll(getAdditionalLanguages().getOrElse(List.of()).stream() + .map(Locale::forLanguageTag) + .toList()); + + String baseName = getResourceBundleBaseName().get(); + String suffix = ".properties"; + + try (var stream = Files.newDirectoryStream(inputDir, file -> { + String fileName = file.getFileName().toString(); + return fileName.startsWith(baseName) && fileName.endsWith(suffix); + })) { + for (Path file : stream) { + String fileName = file.getFileName().toString(); + if (fileName.length() == baseName.length() + suffix.length()) + locales.add(Locale.ENGLISH); + else if (fileName.charAt(baseName.length()) == '_') { + String localeName = fileName.substring(baseName.length() + 1, fileName.length() - suffix.length()); + + // TODO: Delete this if the I18N file naming is changed + if (baseName.equals("I18N")) { + if (localeName.equals("zh")) + locales.add(Locale.forLanguageTag("zh-Hant")); + else if (localeName.equals("zh_CN")) + locales.add(Locale.forLanguageTag("zh-Hans")); + else + locales.add(Locale.forLanguageTag(localeName.replace('_', '-'))); + } else { + if (localeName.equals("zh")) + locales.add(Locale.forLanguageTag("zh-Hans")); + else + locales.add(Locale.forLanguageTag(localeName.replace('_', '-'))); + } + } + } + } + + Path outputFile = getOutputFile().get().getAsFile().toPath(); + Files.createDirectories(outputFile.getParent()); + Files.writeString(outputFile, locales.stream().map(locale -> '"' + locale.toLanguageTag() + '"') + .collect(Collectors.joining(",\n", "[\n", "\n]"))); + } + + private static int compareLanguage(String l1, String l2) { + return l1.compareTo(l2); // TODO + } + + private static int compareLocale(Locale l1, Locale l2) { + int c = compareLanguage(l1.getLanguage(), l2.getLanguage()); + if (c != 0) + return c; + + c = l1.getScript().compareTo(l2.getScript()); + if (c != 0) + return c; + + c = l1.getCountry().compareTo(l2.getCountry()); + if (c != 0) + return c; + + c = l1.getVariant().compareTo(l2.getVariant()); + if (c != 0) + return c; + + return l1.toString().compareTo(l2.toLanguageTag()); + } +}