All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.freya02.botcommands.api.localization.DefaultLocalizationTemplate Maven / Gradle / Ivy

package com.freya02.botcommands.api.localization;

import com.freya02.botcommands.internal.localization.*;
import org.jetbrains.annotations.NotNull;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Default implementation for {@link LocalizationTemplate}
 * 

Specification: *
In a nutshell, this is a copy of the {@link MessageFormat} specification, but with named parameters *
To declare a variable inside your localization template, you may use "{variable_name}" *
As this supports {@link MessageFormat}, you can also specify format types, such as: "{variable_name, number}", * and format styles, such as: "{@literal {user_amount, choice, 0#users|1#user|2" * *

Full example: {@literal "There are {user_amount} {user_amount, choice, 0#users|1#user|2 */ public class DefaultLocalizationTemplate implements LocalizationTemplate { private static final Pattern BRACKETS_PATTERN = Pattern.compile("\\{.*?}"); private static final Pattern TEMPLATE_PATTERN = Pattern.compile("\\{(\\w+?)(?::(%.+))?}"); private static final Pattern MESSAGE_FORMAT_PATTERN = Pattern.compile("\\{(\\w+)(,?.*?)}"); private final List localizableStrings = new ArrayList<>(); private final String template; public DefaultLocalizationTemplate(@NotNull String template, @NotNull Locale locale) { this.template = template; final Matcher bracketMatcher = BRACKETS_PATTERN.matcher(template); int start = 0; while (bracketMatcher.find()) { addRawString(template.substring(start, bracketMatcher.start())); final Matcher templateMatcher = TEMPLATE_PATTERN.matcher(bracketMatcher.group()); if (templateMatcher.matches()) { final String formatterName = templateMatcher.group(1); final String formatter = templateMatcher.group(2); localizableStrings.add(new JavaFormattableString(formatterName, formatter)); } else { final Matcher messageFormatMatcher = MESSAGE_FORMAT_PATTERN.matcher(bracketMatcher.group()); if (!messageFormatMatcher.matches()) { throw new IllegalArgumentException("Invalid MessageFormat format '%s' in template '%s'".formatted(bracketMatcher.group(), template)); } final String formatterName = messageFormatMatcher.group(1); final String messageFormatter = messageFormatMatcher.replaceFirst("{0$2}"); //Replace named index by integer index localizableStrings.add(new MessageFormatString(formatterName, messageFormatter, locale)); } start = bracketMatcher.end(); } addRawString(template.substring(start)); } private void addRawString(String substring) { if (substring.isEmpty()) return; localizableStrings.add(new RawString(substring)); } @Override @NotNull public String localize(Localization.Entry... args) { final StringBuilder sb = new StringBuilder(); for (LocalizableString localizableString : localizableStrings) { if (localizableString instanceof RawString rawString) { sb.append(rawString.get()); } else if (localizableString instanceof FormattableString formattableString) { final Object value = getValueByFormatterName(args, formattableString.getFormatterName()); sb.append(formattableString.format(value)); } } return sb.toString(); } private Object getValueByFormatterName(Localization.Entry[] args, String formatterName) { for (Localization.Entry entry : args) { if (entry.key().equals(formatterName)) { return entry.value(); } } throw new IllegalArgumentException("Could not find format '%s' in template: '%s'".formatted(formatterName, template)); } @Override public String toString() { return template; } }