Skip to content

Instantly share code, notes, and snippets.

@A248
Created June 13, 2026 09:42
Show Gist options
  • Select an option

  • Save A248/b9ca1204961b5b9dace76a6f762ff21d to your computer and use it in GitHub Desktop.

Select an option

Save A248/b9ca1204961b5b9dace76a6f762ff21d to your computer and use it in GitHub Desktop.
Translation mockup that includes comment and default value translation
/*
* 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