Skip to content

Commit

Permalink
Merge pull request #23473 from mkouba/issue-19617
Browse files Browse the repository at this point in the history
Type-safe message bundles - add a missing validation for localized files
  • Loading branch information
geoand authored Feb 8, 2022
2 parents 6614c3c + 86aeeb1 commit 8c61e3f
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,17 @@ List<MessageBundleBuildItem> processBundles(BeanArchiveIndexBuildItem beanArchiv
Map<String, ClassInfo> localeToInterface = new HashMap<>();
for (ClassInfo localizedInterface : localized) {
String locale = localizedInterface.classAnnotation(Names.LOCALIZED).value().asString();
if (defaultLocale.equals(locale)) {
throw new MessageBundleException(
String.format(
"Locale of [%s] conflicts with the locale [%s] of the default message bundle [%s]",
localizedInterface, locale, bundleClass));
}
ClassInfo previous = localeToInterface.put(locale, localizedInterface);
if (defaultLocale.equals(locale) || previous != null) {
if (previous != null) {
throw new MessageBundleException(String.format(
"A localized message bundle interface [%s] already exists for locale %s: [%s]",
previous != null ? previous : bundleClass, locale, localizedInterface));
"Cannot register [%s] - a localized message bundle interface exists for locale [%s]: %s",
localizedInterface, locale, previous));
}
localizedInterfaces.add(localizedInterface.name());
}
Expand All @@ -172,12 +178,18 @@ List<MessageBundleBuildItem> processBundles(BeanArchiveIndexBuildItem beanArchiv
if (fileName.startsWith(name)) {
// msg_en.txt -> en
String locale = fileName.substring(fileName.indexOf('_') + 1, fileName.indexOf('.'));
if (defaultLocale.equals(locale)) {
throw new MessageBundleException(
String.format(
"Locale of [%s] conflicts with the locale [%s] of the default message bundle [%s]",
fileName, locale, bundleClass));
}
ClassInfo localizedInterface = localeToInterface.get(locale);
if (localizedInterface != null) {
throw new MessageBundleException(
String.format(
"A localized message bundle interface [%s] already exists for locale %s: [%s]",
localizedInterface, locale, fileName));
"Cannot register [%s] - a localized message bundle interface exists for locale [%s]: %s",
fileName, locale, localizedInterface));
}
localeToFile.put(locale, messageFile);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.quarkus.qute.deployment.i18n;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.qute.deployment.MessageBundleException;
import io.quarkus.qute.i18n.Localized;
import io.quarkus.qute.i18n.Message;
import io.quarkus.qute.i18n.MessageBundle;
import io.quarkus.runtime.util.ExceptionUtil;
import io.quarkus.test.QuarkusUnitTest;

public class LocalizedBundleDefaultLocaleConflictTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root
.addClasses(Messages.class, EnMessages.class))
.overrideConfigKey("quarkus.default-locale", "en")
.assertException(t -> {
Throwable rootCause = ExceptionUtil.getRootCause(t);
if (rootCause instanceof MessageBundleException) {
assertEquals(
"Locale of [io.quarkus.qute.deployment.i18n.LocalizedBundleDefaultLocaleConflictTest$EnMessages] conflicts with the locale [en] of the default message bundle [io.quarkus.qute.deployment.i18n.LocalizedBundleDefaultLocaleConflictTest$Messages]",
rootCause.getMessage());
} else {
fail("No message bundle exception thrown: " + t);
}
});

@Test
public void testValidation() {
fail();
}

@MessageBundle
public interface Messages {

@Message("Ahoj svete!")
String helloWorld();

}

@Localized("en")
public interface EnMessages extends Messages {

@Message("Hello world!")
String helloWorld();

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.quarkus.qute.deployment.i18n;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.qute.deployment.MessageBundleException;
import io.quarkus.qute.i18n.Localized;
import io.quarkus.qute.i18n.Message;
import io.quarkus.qute.i18n.MessageBundle;
import io.quarkus.runtime.util.ExceptionUtil;
import io.quarkus.test.QuarkusUnitTest;

public class LocalizedBundleLocaleConflictTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot(root -> root
.addClasses(Messages.class, EnMessages.class, AnotherEnMessages.class))
.overrideConfigKey("quarkus.default-locale", "cs")
.assertException(t -> {
Throwable rootCause = ExceptionUtil.getRootCause(t);
if (rootCause instanceof MessageBundleException) {
assertTrue(rootCause.getMessage().contains("a localized message bundle interface exists for locale [en]"));
} else {
fail("No message bundle exception thrown: " + t);
}
});

@Test
public void testValidation() {
fail();
}

@MessageBundle
public interface Messages {

@Message("Ahoj svete!")
String helloWorld();

}

@Localized("en")
public interface EnMessages extends Messages {

@Message("Hello world!")
String helloWorld();

}

@Localized("en")
public interface AnotherEnMessages extends Messages {

@Message("Hello world!")
String helloWorld();

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.quarkus.qute.deployment.i18n;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.qute.deployment.MessageBundleException;
import io.quarkus.qute.i18n.Localized;
import io.quarkus.qute.i18n.Message;
import io.quarkus.qute.i18n.MessageBundle;
import io.quarkus.runtime.util.ExceptionUtil;
import io.quarkus.test.QuarkusUnitTest;

public class LocalizedFileBundleLocaleConflictTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(Messages.class, EnMessages.class)
// This localized file conflicts with the default locale
.addAsResource(new StringAsset(
"hello=Hello!"),
"messages/msg_en.properties"))
.overrideConfigKey("quarkus.default-locale", "cs")
.assertException(t -> {
Throwable rootCause = ExceptionUtil.getRootCause(t);
if (rootCause instanceof MessageBundleException) {
assertEquals(
"Cannot register [msg_en.properties] - a localized message bundle interface exists for locale [en]: io.quarkus.qute.deployment.i18n.LocalizedFileBundleLocaleConflictTest$EnMessages",
rootCause.getMessage());
} else {
fail("No message bundle exception thrown: " + t);
}

});;

@Test
public void testValidation() {
fail();
}

@MessageBundle
public interface Messages {

@Message("Ahoj svete!")
String helloWorld();

}

@Localized("en")
public interface EnMessages extends Messages {

@Message("Hello world!")
String helloWorld();

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.quarkus.qute.deployment.i18n;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.qute.deployment.MessageBundleException;
import io.quarkus.qute.i18n.Message;
import io.quarkus.qute.i18n.MessageBundle;
import io.quarkus.runtime.util.ExceptionUtil;
import io.quarkus.test.QuarkusUnitTest;

public class LocalizedFileDefaultLocaleConflictTest {

@RegisterExtension
static final QuarkusUnitTest config = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(Messages.class)
// This localized file conflicts with the default locale
.addAsResource(new StringAsset(
"hello=Hello!"),
"messages/msg_en.properties"))
.overrideConfigKey("quarkus.default-locale", "en")
.assertException(t -> {
Throwable rootCause = ExceptionUtil.getRootCause(t);
if (rootCause instanceof MessageBundleException) {
assertEquals(
"Locale of [msg_en.properties] conflicts with the locale [en] of the default message bundle [io.quarkus.qute.deployment.i18n.LocalizedFileDefaultLocaleConflictTest$Messages]",
rootCause.getMessage());
} else {
fail("No message bundle exception thrown: " + t);
}
});

@Test
public void testValidation() {
fail();
}

@MessageBundle
public interface Messages {

@Message("Hello world!")
String helloWorld();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,16 @@ static void setupNamespaceResolvers(@Observes EngineBuilder builder, BundleConte
continue;
}
Instance<?> found = container.select(locEntry.getValue(), new Localized.Literal(locEntry.getKey()));
if (!found.isResolvable()) {
if (found.isUnsatisfied()) {
throw new IllegalStateException(
Qute.fmt("Bean not found for localized interface [{e.value}] and locale [{e.key}]")
.data("e", locEntry).render());
}
if (found.isAmbiguous()) {
throw new IllegalStateException(
Qute.fmt("Multiple beans found for localized interface [{e.value}] and locale [{e.key}]")
.data("e", locEntry).render());
}
interfaces.put(locEntry.getKey(), (Resolver) found.get());
}
final Resolver defaultResolver = resolver;
Expand Down

0 comments on commit 8c61e3f

Please sign in to comment.