diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java index 2fab3f6b8..b08d414d9 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java @@ -14,6 +14,8 @@ import java.util.ResourceBundle; */ public abstract class I18nBase { + public static final String PLURAL_SUFFIX = "PLURAL"; + public static final String KEY_DELIMITER = "_"; private Locale locale; private ResourceBundle i18nMessages; private PluralRules pluralRules; @@ -72,17 +74,17 @@ public abstract class I18nBase { * @return The formatted, internationalized, {@link String} */ public String formatMessage(String theMessage, Object... theMessageArguments) { - if (theMessage.endsWith("_PLURAL")) { + if (isPluralKey(theMessage)) { throw new Error("I18n error: Plural Message called in non-plural mode"); } - return formatMessageP(theMessage, theMessageArguments); + return formatMessagePlural(theMessage, theMessageArguments); } protected String getPluralKey(Integer number, String baseKey) { - return baseKey + "_" + pluralRules.select(number); + return baseKey + KEY_DELIMITER + pluralRules.select(number); } - private String formatMessageP(String theMessage, Object... theMessageArguments) { + private String formatMessagePlural(String theMessage, Object... theMessageArguments) { String message = theMessage; if (messageExistsForLocale(theMessage, (theMessageArguments != null && theMessageArguments.length > 0))) { if (Objects.nonNull(theMessageArguments) && theMessageArguments.length > 0) { @@ -93,8 +95,24 @@ public abstract class I18nBase { } return message; } - public String formatMessagePL(Integer plural, String theMessage, Object... theMessageArguments) { - if (!theMessage.endsWith("_PLURAL")) { + + /** + * Formats the message with locale correct pluralization using the passed in + * message arguments. + * + * In the message properties files, each plural specific message will have a + * key consisting of a root key and a suffix denoting the plurality rule (_one + * for singular, _other for multiple in English, for example). Suffixes are + * provided by th ICU4J library from unicode.org + * + * @param plural The number that indicates the plurality of the phrase + * @param theMessage the root key of the phrase. + * @param theMessageArguments Placeholder arguments, if needed. + * @return The formatted, internationalized, {@link String} + */ + public String formatMessagePlural(Integer plural, String theMessage, Object... theMessageArguments) { + + if (!isPluralKey(theMessage)) { throw new Error("I18n error: Non-plural Message called in plural mode"); } Object[] args = new Object[theMessageArguments.length+1]; @@ -104,7 +122,11 @@ public abstract class I18nBase { } checkPluralRulesAreLoaded(); String pluralKey = getPluralKey(plural, theMessage); - return formatMessageP(pluralKey, args); + return formatMessagePlural(pluralKey, args); + } + + private static boolean isPluralKey(String theMessage) { + return theMessage.endsWith(KEY_DELIMITER + PLURAL_SUFFIX); } /** diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/i18n/I18nBaseTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/i18n/I18nBaseTest.java index 52f7f92c7..c79d4973e 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/i18n/I18nBaseTest.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/i18n/I18nBaseTest.java @@ -52,11 +52,11 @@ class I18nBaseTest { I18nTestClass testClass = new I18nTestClass(); //Answer value must be of the type {1} - String resultOne = testClass.formatMessagePL(1, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); + String resultOne = testClass.formatMessagePlural(1, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); assertThat(resultOne, containsString("be of the type")); //Answer value must be one of the {0} types {1} - String resultMany = testClass.formatMessagePL(3, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); + String resultMany = testClass.formatMessagePlural(3, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); assertThat(resultMany, containsString("one of the 3 types ")); } @@ -65,14 +65,14 @@ class I18nBaseTest { @DisplayName("Test pluralization works with initializing Locale.") void testFormatMessagePluralWithInitLocale() { I18nTestClass testClass = new I18nTestClass(); - + testClass.setLocale(Locale.GERMAN); //Answer value muss vom Typ {0} sein. - String resultOne = testClass.formatMessagePL(1, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); + String resultOne = testClass.formatMessagePlural(1, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); assertThat(resultOne, containsString("muss vom Typ")); //Answer value muss einer der Typen {1} sein - String resultMany = testClass.formatMessagePL(3, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); + String resultMany = testClass.formatMessagePlural(3, I18nConstants.QUESTIONNAIRE_QR_ITEM_WRONGTYPE_PLURAL); assertThat(resultMany, containsString("einer der Typen ")); } @@ -123,11 +123,11 @@ class I18nBaseTest { ResourceBundle loadedBundle = ResourceBundle.getBundle("Messages", Locale.GERMAN); PluralRules pluralRules = PluralRules.forLocale(Locale.GERMANY); for (String key : loadedBundle.keySet()) { - String[] keyComponent = key.split("_"); + String[] keyComponent = key.split(I18nBase.KEY_DELIMITER); - assertFalse(keyComponent[keyComponent.length - 1].equalsIgnoreCase("PLURAL"), "Invalid use of PLURAL keyword for key: " + key); + assertFalse(keyComponent[keyComponent.length - 1].equalsIgnoreCase(I18nBase.PLURAL_SUFFIX), "Invalid use of PLURAL keyword for key: " + key); if (keyComponent.length > 2 - && keyComponent[keyComponent.length - 2].equalsIgnoreCase("PLURAL")) { + && keyComponent[keyComponent.length - 2].equalsIgnoreCase(I18nBase.PLURAL_SUFFIX)) { assertTrue(pluralRules.getKeywords().contains(keyComponent[keyComponent.length - 1])); } }