/
MikhailShad
/
ArchDB
Обзор
Документация
Войти
/
MikhailShad
/
ArchDB
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/main/java/org/archdb/plugins/idea/Bundle.java
145 строк
5 KB
Андрей Барсуков
Improve AsciiDoc integration
20 апр 2026, 21:54
20 апр 2026, 21:54
82f5ed2
Код
Авторство
О чём код?
package org.archdb.plugins.idea; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.PropertyKey; import java.text.MessageFormat; import java.util.LinkedHashSet; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public final class Bundle { @NotNull static final String MESSAGES_BUNDLE = "messages.ArchDBBundle"; private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{([^}]*)}"); private static final Locale EN_LOCALE = Locale.ENGLISH; private static final Locale RU_LOCALE = new Locale("ru"); private static final Control NO_FALLBACK_CONTROL = Control.getNoFallbackControl(Control.FORMAT_DEFAULT); private static final ConcurrentMap<CacheKey, String> RESOLVED_PATTERN_CACHE = new ConcurrentHashMap<CacheKey, String>(); private Bundle() { } @NotNull public static String message(@NotNull @PropertyKey(resourceBundle = MESSAGES_BUNDLE) String key, Object... params) { return message(resolveActiveLocale(), key, params); } static @NotNull String message(@NotNull Locale locale, @NotNull @PropertyKey(resourceBundle = MESSAGES_BUNDLE) String key, Object... params) { Locale effectiveLocale = normalizeLocale(locale); String pattern = resolvePattern(key, effectiveLocale, new LinkedHashSet<String>()); if (params == null || params.length == 0) { return pattern; } return new MessageFormat(pattern, effectiveLocale).format(params); } static @NotNull Locale resolveActiveLocale() { return normalizeLocale(Locale.getDefault()); } private static @NotNull Locale normalizeLocale(@NotNull Locale locale) { return RU_LOCALE.getLanguage().equals(locale.getLanguage()) ? RU_LOCALE : EN_LOCALE; } private static @NotNull String resolvePattern(@NotNull String key, @NotNull Locale locale, @NotNull Set<String> resolutionStack) { CacheKey cacheKey = new CacheKey(key, locale); String cached = RESOLVED_PATTERN_CACHE.get(cacheKey); if (cached != null) { return cached; } if (!resolutionStack.add(key)) { throw new IllegalArgumentException("Циклическая ссылка в Bundle: " + formatCycle(resolutionStack, key)); } try { String rawValue = getRawMessage(key, locale); String resolvedValue = processPlaceholders(rawValue, locale, resolutionStack); RESOLVED_PATTERN_CACHE.putIfAbsent(cacheKey, resolvedValue); return resolvedValue; } finally { resolutionStack.remove(key); } } private static @NotNull String getRawMessage(@NotNull String key, @NotNull Locale locale) { try { return ResourceBundle.getBundle(MESSAGES_BUNDLE, locale, Bundle.class.getClassLoader(), NO_FALLBACK_CONTROL) .getString(key); } catch (MissingResourceException e) { throw new IllegalArgumentException("Не найден ключ Bundle '" + key + "' для locale '" + locale + "'", e); } } private static @NotNull String processPlaceholders(@NotNull String value, @NotNull Locale locale, @NotNull Set<String> resolutionStack) { Matcher matcher = PLACEHOLDER_PATTERN.matcher(value); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String nestedKey = matcher.group(1); String nestedValue = resolvePattern(nestedKey, locale, resolutionStack); matcher.appendReplacement(sb, Matcher.quoteReplacement(nestedValue)); } matcher.appendTail(sb); return sb.toString(); } private static @NotNull String formatCycle(@NotNull Set<String> resolutionStack, @NotNull String repeatedKey) { StringBuilder builder = new StringBuilder(); boolean first = true; for (String key : resolutionStack) { if (!first) { builder.append(" -> "); } builder.append(key); first = false; } if (!resolutionStack.isEmpty()) { builder.append(" -> "); } builder.append(repeatedKey); return builder.toString(); } private static final class CacheKey { private final String key; private final Locale locale; private CacheKey(@NotNull String key, @NotNull Locale locale) { this.key = key; this.locale = locale; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof CacheKey)) { return false; } CacheKey other = (CacheKey) o; return key.equals(other.key) && locale.equals(other.locale); } @Override public int hashCode() { return 31 * key.hashCode() + locale.hashCode(); } } }