package net.minecraft.locale; import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.mojang.logging.LogUtils; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Map.Entry; import java.util.function.BiConsumer; import java.util.regex.Pattern; import net.minecraft.network.chat.FormattedText; import net.minecraft.network.chat.Style; import net.minecraft.util.FormattedCharSequence; import net.minecraft.util.GsonHelper; import net.minecraft.util.StringDecomposer; import org.slf4j.Logger; public abstract class Language { private static final Logger LOGGER = LogUtils.getLogger(); private static final Gson GSON = new Gson(); /** * Pattern that matches numeric variable placeholders in a resource string, such as "%d", "%3$d", "%.2f" */ private static final Pattern UNSUPPORTED_FORMAT_PATTERN = Pattern.compile("%(\\d+\\$)?[\\d.]*[df]"); public static final String DEFAULT = "en_us"; private static volatile Language instance = loadDefault(); private static Language loadDefault() { DeprecatedTranslationsInfo deprecatedTranslationsInfo = DeprecatedTranslationsInfo.loadFromDefaultResource(); Map map = new HashMap(); BiConsumer biConsumer = map::put; parseTranslations(biConsumer, "/assets/minecraft/lang/en_us.json"); deprecatedTranslationsInfo.applyToMap(map); final Map map2 = Map.copyOf(map); return new Language() { @Override public String getOrDefault(String key, String defaultValue) { return (String)map2.getOrDefault(key, defaultValue); } @Override public boolean has(String id) { return map2.containsKey(id); } @Override public boolean isDefaultRightToLeft() { return false; } @Override public FormattedCharSequence getVisualOrder(FormattedText text) { return formattedCharSink -> text.visit( (style, string) -> StringDecomposer.iterateFormatted(string, style, formattedCharSink) ? Optional.empty() : FormattedText.STOP_ITERATION, Style.EMPTY ) .isPresent(); } }; } private static void parseTranslations(BiConsumer output, String languagePath) { try { InputStream inputStream = Language.class.getResourceAsStream(languagePath); try { loadFromJson(inputStream, output); } catch (Throwable var6) { if (inputStream != null) { try { inputStream.close(); } catch (Throwable var5) { var6.addSuppressed(var5); } } throw var6; } if (inputStream != null) { inputStream.close(); } } catch (JsonParseException | IOException var7) { LOGGER.error("Couldn't read strings from {}", languagePath, var7); } } public static void loadFromJson(InputStream stream, BiConsumer output) { JsonObject jsonObject = GSON.fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), JsonObject.class); for (Entry entry : jsonObject.entrySet()) { String string = UNSUPPORTED_FORMAT_PATTERN.matcher(GsonHelper.convertToString((JsonElement)entry.getValue(), (String)entry.getKey())).replaceAll("%$1s"); output.accept((String)entry.getKey(), string); } } /** * Return the StringTranslate singleton instance */ public static Language getInstance() { return instance; } public static void inject(Language instance) { Language.instance = instance; } public String getOrDefault(String id) { return this.getOrDefault(id, id); } public abstract String getOrDefault(String key, String defaultValue); public abstract boolean has(String id); public abstract boolean isDefaultRightToLeft(); public abstract FormattedCharSequence getVisualOrder(FormattedText text); public List getVisualOrder(List text) { return (List)text.stream().map(this::getVisualOrder).collect(ImmutableList.toImmutableList()); } }