Created
June 13, 2026 09:42
-
-
Save A248/b9ca1204961b5b9dace76a6f762ff21d to your computer and use it in GitHub Desktop.
Translation mockup that includes comment and default value translation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * DazzleConf | |
| * Copyright � 2026 Anand Beh | |
| * | |
| * DazzleConf is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation, either version 3 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * DazzleConf 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 Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public License | |
| * along with DazzleConf. If not, see <https://www.gnu.org/licenses/> | |
| * and navigate to version 3 of the GNU Lesser General Public License. | |
| */ | |
| package space.arim.dazzleconf.engine; | |
| import org.checkerframework.checker.nullness.qual.NonNull; | |
| import org.checkerframework.checker.nullness.qual.Nullable; | |
| import space.arim.dazzleconf.Configuration; | |
| import space.arim.dazzleconf.LoadResult; | |
| import space.arim.dazzleconf.backend.CommentData; | |
| import space.arim.dazzleconf.backend.KeyPath; | |
| import java.io.IOException; | |
| import java.io.StringReader; | |
| import java.util.HashMap; | |
| import java.util.Locale; | |
| import java.util.Map; | |
| import java.util.Properties; | |
| public class LanguageExample { | |
| /* | |
| New API | |
| */ | |
| /** | |
| * Provides a default value that differs depending on the language | |
| * | |
| */ | |
| public @interface LangDefault { | |
| /** | |
| * The language key. | |
| * <p> | |
| * This will be parsed into a {@link KeyPath} and fed to {@link TranslationResolve#resolveValueKey(KeyPath)} | |
| * | |
| * @return the language key | |
| */ | |
| String value(); | |
| } | |
| public interface TranslationResolve { | |
| // Maps key path of configuration entry -> comments on entry | |
| @Nullable CommentData resolveComments(@NonNull KeyPath key); | |
| // Typically used for default values | |
| // Maps key chosen in @LangValue -> translated value | |
| @Nullable String resolveValueKey(@NonNull KeyPath valueKey); | |
| } | |
| /* | |
| Integration | |
| */ | |
| private record MyResolver(Map<String, String> translationBundle) implements TranslationResolve { | |
| @Override | |
| public @Nullable CommentData resolveComments(@NonNull KeyPath key) { | |
| String resolved = translationBundle.get("comment." + key); | |
| return resolved == null ? null : CommentData.empty().setAt(CommentLocation.ABOVE, resolved); | |
| } | |
| @Override | |
| public @Nullable String resolveValueKey(@NonNull KeyPath valueKey) { | |
| return translationBundle.get("defaults." + valueKey); | |
| } | |
| } | |
| private interface Config { | |
| @LangDefault("messages.join") | |
| String joinMessage(); | |
| } | |
| private class ConfigManager { | |
| private static final Locale RUSSIAN_DEFAULT = Locale.of("ru", "RU"); | |
| private final Map<Locale, Config> allConfigs = new HashMap<>(); | |
| void reload() { | |
| Locale[] supportedLocales = new Locale[] { | |
| RUSSIAN_DEFAULT, Locale.US, Locale.SIMPLIFIED_CHINESE | |
| }; | |
| for (Locale locale : supportedLocales) { | |
| allConfigs.compute(locale, (l, previousConfig) -> { | |
| MyResolver resolver = loadResolver(); | |
| Configuration<Config> definition = Configuration.defaultBuilder(Config.class) | |
| .locale(l) | |
| .translations(resolver) | |
| .build(); | |
| LoadResult<Config> result = definition.configureWith(new XXXBackend(...)); | |
| if (result.isFailure()) { | |
| // Fall back to previous/default configuration | |
| return (previousConfig == null) ? definition.loadDefaults() : previousConfig; | |
| } | |
| return result.getOrThrow(); | |
| }); | |
| } | |
| } | |
| Config getConfig(Locale locale) { | |
| Config found = allConfigs.get(locale); | |
| if (found == null) { | |
| found = allConfigs.get(RUSSIAN_DEFAULT); | |
| } | |
| return found; | |
| } | |
| Config getPlayerMessages(Player player) { | |
| return getConfig(player.getLocale()); | |
| } | |
| Config getJoinMessage(Player player) { | |
| return getConfig(player.getLocale()).joinMessage(); | |
| } | |
| private MyResolver loadResolver(Locale locale) { | |
| Properties translationFile = new Properties(); | |
| try { | |
| translationFile.load(new StringReader(""" | |
| comments.joinMessage=The greeting to players when they join the server | |
| defaults.messages.join=Hello and welcome | |
| """)); | |
| } catch (IOException e) { | |
| throw new RuntimeException(e); | |
| } | |
| Map<String, String> props = new HashMap<>(); | |
| translationFile.forEach((k, v) -> { | |
| props.put(k.toString(), v.toString()); | |
| }); | |
| return new MyResolver(props); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment