Skip to content

Commit 41d9b5f

Browse files
committed
Improve query prefixes
1 parent 677b585 commit 41d9b5f

12 files changed

+148
-139
lines changed

README.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,6 @@ If there is still no match then the default locale (followed by a less strict de
182182
I18nMessagePack messages = I18nMessagePack.builder()
183183
.scanClassPath("/i18n/messages-{locale}.yml")
184184
.setDefaultLocale(PL_PL)
185-
.addFallbackKeyPrefix("glossary")
186185
.build();
187186

188187
String message = messages.getMessage(Locales.en_US, "hello");
@@ -203,7 +202,7 @@ Sometimes it is useful to specify a common path prefix for all unmatched queries
203202
I18nMessagePack messages = I18nMessagePack.builder()
204203
.scanClassPath("/i18n/messages-{locale}.yml")
205204
.setDefaultLocale(PL_PL)
206-
.addMessageFallbackKeyPrefix("common")
205+
.prefixQueries("", "common")
207206
.build();
208207

209208
String message = messages.getMessage(Locales.en_US, "hello");
@@ -304,7 +303,7 @@ I18nMessagePack messagePack = I18nMessagePack.builder()
304303
.addMessage(EN_US, "msg", "${company.name} was established on 1988")
305304
.scanClassPath("/i18n/messages-{locale}.yml")
306305
.setDefaultLocale(PL_PL)
307-
.addFallbackKeyPrefix("fallback")
306+
.prefixQueries("", "fallback")
308307
.build();
309308
```
310309

@@ -325,7 +324,7 @@ If the reference is defined in a message stored in a prefixed file it will be au
325324
I18nMessagePack messagePack = I18nMessagePack.builder()
326325
.scanClassPathLocation("i18n/{prefix}/message_{locale}.yml")
327326
.setDefaultLocale(PL_PL)
328-
.addFallbackKeyPrefix("fallback")
327+
.prefixQueries("", "fallback")
329328
.build();
330329
```
331330

@@ -442,7 +441,7 @@ You can skip them using a custom missing message detector:
442441
I18nMissingMessagesDetector detector = I18nMissingMessagesDetector.builder()
443442
.skipPath(skipPath)
444443
.logMissingMessages()
445-
.build()
444+
.build();
446445

447446
I18nMessagePack.
448447

build-logic/src/main/kotlin/build.version.gradle.kts

+19-15
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ data class Semver(
4141
fun nextPatchSnapshot(): Semver {
4242
return copy(
4343
patch = patch + 1,
44-
suffix = "SNAPSHOT"
44+
suffix = "SNAPSHOT",
4545
)
4646
}
4747

@@ -60,7 +60,10 @@ data class Semver(
6060
companion object {
6161
private val REGEX = Regex("v?([0-9]+)\\.([0-9]+)\\.([0-9]+)(-.+)?")
6262

63-
fun parse(text: String, strict: Boolean = true): Semver? {
63+
fun parse(
64+
text: String,
65+
strict: Boolean = true,
66+
): Semver? {
6467
val groups = REGEX.matchEntire(text)?.groups ?: return null
6568
if (groups.size < 4 || groups.size > 5) return null
6669
if (strict && groups[0]?.value?.startsWith("v") == true) return null
@@ -84,19 +87,20 @@ data class Semver(
8487
command: String,
8588
workingDir: File = File("."),
8689
timeoutAmount: Long = 60,
87-
timeoutUnit: TimeUnit = TimeUnit.SECONDS
88-
): String = ProcessBuilder("sh", "-c", command)
89-
.directory(workingDir)
90-
.redirectOutput(ProcessBuilder.Redirect.PIPE)
91-
.redirectError(ProcessBuilder.Redirect.PIPE)
92-
.start()
93-
.apply { waitFor(timeoutAmount, timeoutUnit) }
94-
.run {
95-
val error = errorStream.bufferedReader().readText().trim()
96-
if (error.isNotEmpty()) {
97-
throw IOException(error)
90+
timeoutUnit: TimeUnit = TimeUnit.SECONDS,
91+
): String =
92+
ProcessBuilder("sh", "-c", command)
93+
.directory(workingDir)
94+
.redirectOutput(ProcessBuilder.Redirect.PIPE)
95+
.redirectError(ProcessBuilder.Redirect.PIPE)
96+
.start()
97+
.apply { waitFor(timeoutAmount, timeoutUnit) }
98+
.run {
99+
val error = errorStream.bufferedReader().readText().trim()
100+
if (error.isNotEmpty()) {
101+
throw IOException(error)
102+
}
103+
inputStream.bufferedReader().readText().trim()
98104
}
99-
inputStream.bufferedReader().readText().trim()
100-
}
101105
}
102106
}

src/main/java/com/coditory/quark/i18n/I18nKeyGenerator.java

+33-31
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,69 @@
88

99
final class I18nKeyGenerator {
1010
private final List<Locale> defaultLocales;
11-
private final List<I18nPath> globalPrefixes;
11+
private final List<I18nPath> defaultPrefixes;
1212
private final LocaleResolver localeResolver;
1313

14-
public I18nKeyGenerator(Locale defaultLocale, List<I18nPath> globalPrefixes, LocaleResolver localeResolver) {
14+
public I18nKeyGenerator(Locale defaultLocale, List<I18nPath> prefixes, LocaleResolver localeResolver) {
15+
this(defaultLocale != null ? localeResolver.getLocaleHierarchy(defaultLocale) : List.of(), prefixes, localeResolver);
16+
}
17+
18+
private I18nKeyGenerator(List<Locale> defaultLocales, List<I18nPath> prefixes, LocaleResolver localeResolver) {
19+
expectNonNull(defaultLocales, "defaultLocales");
1520
expectNonNull(localeResolver, "localeResolver");
16-
expectNonNull(globalPrefixes, "globalPrefixes");
17-
this.defaultLocales = defaultLocale != null
18-
? localeResolver.getLocaleHierarchy(defaultLocale)
19-
: List.of();
20-
this.globalPrefixes = List.copyOf(globalPrefixes);
21+
expectNonNull(prefixes, "prefixes");
22+
this.defaultLocales = defaultLocales;
23+
this.defaultPrefixes = prefixes.isEmpty() ? List.of(I18nPath.root()) : List.copyOf(prefixes);
2124
this.localeResolver = localeResolver;
2225
}
2326

27+
I18nKeyGenerator withPrefixes(List<I18nPath> prefixes) {
28+
expectNonNull(prefixes, "prefixes");
29+
return new I18nKeyGenerator(defaultLocales, prefixes, localeResolver);
30+
}
31+
2432
List<I18nKey> keys(I18nKey key) {
2533
expectNonNull(key, "key");
2634
return keys(key, List.of());
2735
}
2836

2937
List<I18nKey> keys(I18nKey key, I18nPath prefix) {
3038
expectNonNull(key, "key");
31-
return prefix == null || prefix.isRoot()
32-
? keys(key)
33-
: keys(key, List.of(prefix));
39+
return keys(key, List.of(prefix));
3440
}
3541

3642
List<I18nKey> keys(I18nKey key, List<I18nPath> prefixes) {
3743
expectNonNull(key, "key");
3844
expectNonNull(prefixes, "prefixes");
3945
List<Locale> locales = localeResolver.getLocaleHierarchy(key.locale());
4046
I18nPath path = key.path();
41-
List<I18nKey> keys = new ArrayList<>(6 * (1 + prefixes.size() + globalPrefixes.size()));
42-
// locales x prefix + path
47+
List<I18nKey> keys = new ArrayList<>(6 * (1 + prefixes.size() + this.defaultPrefixes.size()));
48+
// locales x (prefix + path)
4349
for (I18nPath prefix : prefixes) {
50+
I18nPath prefixed = prefix.child(path);
4451
for (Locale loc : locales) {
45-
keys.add(I18nKey.of(loc, prefix.child(path)));
52+
keys.add(I18nKey.of(loc, prefixed));
4653
}
4754
}
48-
// locales x path
49-
for (Locale loc : locales) {
50-
keys.add(I18nKey.of(loc, path));
51-
}
52-
// locales x globalPrefixes
53-
for (I18nPath prefix : globalPrefixes) {
55+
// locales * (defaultPrefixes + path)
56+
for (I18nPath prefix : this.defaultPrefixes) {
57+
I18nPath prefixed = prefix.child(path);
5458
for (Locale loc : locales) {
55-
keys.add(I18nKey.of(loc, prefix.child(path)));
59+
keys.add(I18nKey.of(loc, prefixed));
5660
}
5761
}
58-
// defaultLocales x prefix + path
62+
// defaultLocales x (prefix + path)
5963
for (I18nPath prefix : prefixes) {
60-
for (Locale loc : defaultLocales) {
61-
keys.add(I18nKey.of(loc, prefix.child(path)));
64+
I18nPath prefixed = prefix.child(path);
65+
for (Locale loc : this.defaultLocales) {
66+
keys.add(I18nKey.of(loc, prefixed));
6267
}
6368
}
64-
// defaultLocales x path
65-
for (Locale loc : defaultLocales) {
66-
keys.add(I18nKey.of(loc, path));
67-
}
68-
// defaultLocales x globalPrefixes
69-
for (I18nPath prefix : globalPrefixes) {
70-
for (Locale loc : defaultLocales) {
71-
keys.add(I18nKey.of(loc, prefix.child(path)));
69+
// defaultLocales * (defaultPrefixes + path)
70+
for (I18nPath prefix : this.defaultPrefixes) {
71+
I18nPath prefixed = prefix.child(path);
72+
for (Locale loc : this.defaultLocales) {
73+
keys.add(I18nKey.of(loc, prefixed));
7274
}
7375
}
7476
return keys;

src/main/java/com/coditory/quark/i18n/I18nMessagePack.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import org.jetbrains.annotations.NotNull;
44
import org.jetbrains.annotations.Nullable;
55

6+
import java.util.Arrays;
7+
import java.util.List;
68
import java.util.Locale;
79
import java.util.Map;
810

@@ -114,11 +116,18 @@ default I18nMessages localize(@NotNull String locale) {
114116
}
115117

116118
@NotNull
117-
I18nMessagePack prefixQueries(I18nPath prefix);
119+
I18nMessagePack prefixQueries(@NotNull List<I18nPath> prefixes);
118120

119121
@NotNull
120-
default I18nMessagePack prefixQueries(@NotNull String prefix) {
121-
expectNonNull(prefix, "prefix");
122-
return prefixQueries(I18nPath.of(prefix));
122+
default I18nMessagePack prefixQueries(@NotNull I18nPath... prefixes) {
123+
expectNonNull(prefixes, "prefixes");
124+
return prefixQueries(List.of(prefixes));
125+
}
126+
127+
@NotNull
128+
default I18nMessagePack prefixQueries(@NotNull String... prefixes) {
129+
expectNonNull(prefixes, "prefix");
130+
List<I18nPath> paths = Arrays.stream(prefixes).map(I18nPath::of).toList();
131+
return prefixQueries(paths);
123132
}
124133
}

src/main/java/com/coditory/quark/i18n/I18nMessagePackBuilder.java

+26-54
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121

2222
public final class I18nMessagePackBuilder {
2323
private final AggregatedI18nLoader loader = new AggregatedI18nLoader();
24-
private final List<I18nPath> referenceFallbackPaths = new ArrayList<>();
25-
private final List<I18nPath> messageFallbackPaths = new ArrayList<>();
2624
private final List<I18nArgTransformer<?>> argTransformers = new ArrayList<>();
2725
private I18nMissingMessageHandler missingMessageHandler = I18nMissingMessageHandler.errorThrowingHandler();
2826
private Locale defaultLocale;
2927
private boolean transformJava8TimeTypes = true;
3028
private boolean normalizeWhitespaces = false;
3129
private boolean resolveReferences = true;
30+
private List<I18nPath> referencePrefixes = new ArrayList<>();
31+
private List<I18nPath> queryPrefixes = new ArrayList<>();
3232
private I18nMissingMessagesDetector missingMessagesDetector;
3333

3434
I18nMessagePackBuilder() {
@@ -38,8 +38,8 @@ public final class I18nMessagePackBuilder {
3838
private I18nMessagePackBuilder copy() {
3939
I18nMessagePackBuilder builder = new I18nMessagePackBuilder();
4040
builder.loader.addLoader(loader.copy());
41-
builder.referenceFallbackPaths.addAll(referenceFallbackPaths);
42-
builder.messageFallbackPaths.addAll(messageFallbackPaths);
41+
builder.referencePrefixes.addAll(referencePrefixes);
42+
builder.queryPrefixes.addAll(queryPrefixes);
4343
builder.argTransformers.addAll(argTransformers);
4444
builder.missingMessageHandler = missingMessageHandler;
4545
builder.defaultLocale = defaultLocale;
@@ -251,71 +251,43 @@ public I18nMessagePackBuilder setDefaultLocale(@NotNull Locale defaultLocale) {
251251
}
252252

253253
@NotNull
254-
public I18nMessagePackBuilder addReferenceFallbackKeyPrefixes(@NotNull List<String> keyPrefixes) {
255-
expectNonNull(keyPrefixes, "keyPrefixes");
256-
keyPrefixes.forEach(this::addReferenceFallbackKeyPrefix);
254+
public I18nMessagePackBuilder prefixReferenceQueries(@NotNull List<I18nPath> prefixes) {
255+
expectNonNull(prefixes, "prefixes");
256+
this.referencePrefixes = List.copyOf(prefixes);
257257
return this;
258258
}
259259

260260
@NotNull
261-
public I18nMessagePackBuilder addReferenceFallbackKeyPrefixes(@NotNull String... keyPrefixes) {
262-
expectNonNull(keyPrefixes, "keyPrefixes");
263-
Arrays.stream(keyPrefixes).forEach(this::addReferenceFallbackKeyPrefix);
264-
return this;
265-
}
266-
267-
@NotNull
268-
public I18nMessagePackBuilder addReferenceFallbackKeyPrefix(@NotNull String keyPrefix) {
269-
expectNonBlank(keyPrefix, "keyPrefix");
270-
I18nPath i18nPath = I18nPath.of(keyPrefix);
271-
this.referenceFallbackPaths.add(i18nPath);
272-
return this;
273-
}
274-
275-
@NotNull
276-
public I18nMessagePackBuilder addMessageFallbackKeyPrefixes(@NotNull List<String> keyPrefixes) {
277-
expectNonNull(keyPrefixes, "keyPrefixes");
278-
keyPrefixes.forEach(this::addMessageFallbackKeyPrefix);
279-
return this;
280-
}
281-
282-
@NotNull
283-
public I18nMessagePackBuilder addMessageFallbackKeyPrefixes(@NotNull String... keyPrefixes) {
284-
expectNonNull(keyPrefixes, "keyPrefixes");
285-
Arrays.stream(keyPrefixes).forEach(this::addMessageFallbackKeyPrefix);
286-
return this;
261+
public I18nMessagePackBuilder prefixReferenceQueries(@NotNull I18nPath... prefixes) {
262+
expectNonNull(prefixes, "prefixes");
263+
return prefixReferenceQueries(List.of(prefixes));
287264
}
288265

289266
@NotNull
290-
public I18nMessagePackBuilder addMessageFallbackKeyPrefix(@NotNull String keyPrefix) {
291-
expectNonBlank(keyPrefix, "keyPrefix");
292-
I18nPath i18nPath = I18nPath.of(keyPrefix);
293-
this.messageFallbackPaths.add(i18nPath);
294-
return this;
267+
public I18nMessagePackBuilder prefixReferenceQueries(@NotNull String... prefixes) {
268+
expectNonNull(prefixes, "prefixes");
269+
List<I18nPath> mapped = Arrays.stream(prefixes).map(I18nPath::of).toList();
270+
return prefixReferenceQueries(mapped);
295271
}
296272

297273
@NotNull
298-
public I18nMessagePackBuilder addFallbackKeyPrefixes(@NotNull List<String> keyPrefixes) {
299-
expectNonNull(keyPrefixes, "keyPrefixes");
300-
addMessageFallbackKeyPrefixes(keyPrefixes);
301-
addReferenceFallbackKeyPrefixes(keyPrefixes);
274+
public I18nMessagePackBuilder prefixQueries(@NotNull List<I18nPath> prefixes) {
275+
expectNonNull(prefixes, "prefixes");
276+
this.queryPrefixes = List.copyOf(prefixes);
302277
return this;
303278
}
304279

305280
@NotNull
306-
public I18nMessagePackBuilder addFallbackKeyPrefixes(@NotNull String... keyPrefixes) {
307-
expectNonNull(keyPrefixes, "keyPrefixes");
308-
addMessageFallbackKeyPrefixes(keyPrefixes);
309-
addReferenceFallbackKeyPrefixes(keyPrefixes);
310-
return this;
281+
public I18nMessagePackBuilder prefixQueries(@NotNull String... prefixes) {
282+
expectNonNull(prefixes, "prefixes");
283+
List<I18nPath> mapped = Arrays.stream(prefixes).map(I18nPath::of).toList();
284+
return prefixQueries(mapped);
311285
}
312286

313287
@NotNull
314-
public I18nMessagePackBuilder addFallbackKeyPrefix(@NotNull String keyPrefix) {
315-
expectNonBlank(keyPrefix, "keyPrefix");
316-
addMessageFallbackKeyPrefix(keyPrefix);
317-
addReferenceFallbackKeyPrefix(keyPrefix);
318-
return this;
288+
public I18nMessagePackBuilder prefixQueries(@NotNull I18nPath... prefixes) {
289+
expectNonNull(prefixes, "prefixes");
290+
return prefixQueries(List.of(prefixes));
319291
}
320292

321293
@NotNull
@@ -349,14 +321,14 @@ private I18nMessagePack build(List<I18nMessageBundle> bundles) {
349321
bundles = TemplatesBundlePrefixes.prefix(bundles);
350322
detectMissingMessages(bundles);
351323
LocaleResolver localeResolver = LocaleResolver.of(defaultLocale, bundles);
352-
I18nKeyGenerator messageKeyGenerator = new I18nKeyGenerator(defaultLocale, messageFallbackPaths, localeResolver);
324+
I18nKeyGenerator messageKeyGenerator = new I18nKeyGenerator(defaultLocale, queryPrefixes, localeResolver);
353325
MessageTemplateParser parser = buildMessageTemplateParser(bundles, localeResolver);
354326
Map<I18nKey, MessageTemplate> templates = parser.parseTemplates(bundles);
355327
return new ImmutableI18nMessagePack(templates, parser, missingMessageHandler, messageKeyGenerator);
356328
}
357329

358330
private MessageTemplateParser buildMessageTemplateParser(List<I18nMessageBundle> bundles, LocaleResolver localeResolver) {
359-
I18nKeyGenerator referenceKeyGenerator = new I18nKeyGenerator(defaultLocale, referenceFallbackPaths, localeResolver);
331+
I18nKeyGenerator referenceKeyGenerator = new I18nKeyGenerator(defaultLocale, referencePrefixes, localeResolver);
360332
ReferenceResolver referenceResolver = new ReferenceResolver(bundles, referenceKeyGenerator, resolveReferences);
361333
ArgumentResolver argumentResolver = buildArgumentResolver();
362334
MessageTemplateNormalizer messageTemplateNormalizer = new MessageTemplateNormalizer(normalizeWhitespaces);

src/main/java/com/coditory/quark/i18n/I18nMessages.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public String getMessageOrNull(@NotNull String key) {
8686
}
8787

8888
@NotNull
89-
public I18nMessages prefixQueries(@NotNull String prefix) {
89+
public I18nMessages addMessagePrefix(@NotNull String prefix) {
9090
return messagePack.prefixQueries(prefix).localize(locale);
9191
}
9292

0 commit comments

Comments
 (0)