@Override public String translate(LocaleProvider localeProvider, String[] keys) { return translate(localeProvider, null, keys); }
message = legacyLookup(locale, basename, keys[0]); if (message != null) { return message + (isDebug() ? this.addDebugInfo(keys, keys[0], locale, basename) : StringUtils.EMPTY); message = doGetMessage(keys, locale); if (country != null) { final Locale newLocale = new Locale(locale.getLanguage(), country); message = doGetMessage(keys, newLocale); message = doGetMessage(keys, newLocale); message = doGetMessage(keys, getFallbackLocale()); message = handleUnknownKey(locale, basename, keys);
@Override public String translate(LocaleProvider localeProvider, String basename, String[] keys) { final Locale locale = localeProvider.getLocale(); if (locale == null) { throw new IllegalArgumentException("Locale can't be null"); } if (keys == null || keys.length < 1) { throw new IllegalArgumentException("Keys can't be null or empty"); } if (basename != null) { log.debug("Got an explicit basename ({}) for keys {}", basename, Arrays.asList(keys)); } final String message = lookUpKeyUntilFound(keys, locale, basename); if (message != null) { return message; } else { return handleUnknownKey(locale, basename, keys); } }
protected String handleUnknownKey(Locale locale, String basename, String[] keys) { // TODO - this method could be context dependent, or delegate to a configured component. In dev mode, for instance, we could at least print this out, or return the key, while in production this is neither useful nor needed. log.debug("No translation found for any of {} with locale {} and basename {}", keys, locale, basename != null ? basename : "<unspecified>"); return keys[0] + (isDebug() ? this.addDebugInfo(keys, null, locale, basename) : StringUtils.EMPTY); }
/** * Looks up a particular key using the given basename and Locale, using the legacy MessagesManager. */ private String legacyLookup(Locale locale, String basename, String key) { // Note that this internally chains the given locale with the fallback locale (as known by the MessagesManager), so if a key is known in english, it will be returned in english before we lookup in the default bundles String message = MessagesManager.getMessages(basename, locale).get(key); if (legacyMessageNotFound(message)) { message = MessagesManager.getMessages(MessagesManager.DEFAULT_BASENAME, locale).get(key); } if (legacyMessageNotFound(message)) { // Let's not get any of the legacy "???" markers out of here return null; } else { Document document = Jsoup.parseBodyFragment(message, ""); if (!CLEANER.isValid(document)) { return CLEANER.clean(document).body().html(); } else { return message; } } }
@Test public void isDebugReturnsFalseWhenI18nModuleProviderIsNotReady() throws Exception { // GIVEN Provider<I18nModule> i18nModuleProvider = mock(Provider.class); given(i18nModuleProvider.get()).willThrow(RuntimeException.class); final TranslationService translationService = new TranslationServiceImpl(i18nModuleProvider, GuiceUtils.providerForInstance(mock(DefaultMessageBundlesLoader.class))); // WHEN String translatedTextWithoutDebugInformation = translationService.translate(newFixedLocaleProvider(USERLOCALE), new String[] { "about.title" }); // THEN assertThat(translatedTextWithoutDebugInformation, is("about.title")); }
private String doGetMessage(String[] keys, Locale locale) { final Properties properties = defaultMessageBundlesLoaderProvider.get().getMessages().get(locale); if (properties != null) { for (String key : keys) { if (key == null) { // Keys can sometimes be null (e.g when using NullKeyGenerator and the undecorated or configured text is null) continue; } final String message = properties.getProperty(key); if (message != null) { return message + (isDebug() ? this.addDebugInfo(keys, key, locale, null) : StringUtils.EMPTY); } } } return null; }
@Override public String translate(LocaleProvider localeProvider, String basename, String[] keys) { if (translationOff) { return keys == null || keys.length == 0 ? null : keys[0]; } else { return super.translate(localeProvider, basename, keys); } }
@Test public void handleLegacyTranslationSanitation() throws Exception { // GIVEN / WHEN String notSanitisedHarmlessCode = translationService.translate(userLocaleProvider, LEGACY_BUNDLE, new String[] { "foo" }); String sanitizedMaliciousHtml = translationService.translate(userLocaleProvider, LEGACY_BUNDLE, new String[] { "bar" }); String weirdChoiceFormat = translationService.translate(userLocaleProvider, LEGACY_BUNDLE, new String[] { "baz" }); String imageTagShouldBeSanitized = translationService.translate(userLocaleProvider, LEGACY_BUNDLE, new String[] { "bax" }); // THEN assertThat(sanitizedMaliciousHtml, is("")); assertThat(notSanitisedHarmlessCode, is("<strong>This will stay strong</strong>")); assertThat(imageTagShouldBeSanitized, is("")); assertThat(weirdChoiceFormat, is("Failed to mark {0,choice,1# folder|1< folders} as deleted.")); }
@Test public void messageFallsBackToClosestAvailableMessage() { assertEquals("Version Deutsch Schweiz", translationService.translate(newFixedLocaleProvider(new Locale("de", "CH", "Non-Existant-Variant")), new String[] { "about.version" })); assertEquals("Only German", translationService.translate(newFixedLocaleProvider(new Locale("de", "CH", "Non-Existant-Variant")), new String[] { "only.de" })); assertEquals("Only in English", translationService.translate(newFixedLocaleProvider(new Locale("de", "CH", "Non-Existant-Variant")), new String[] { "only.en" })); }
@Test public void shouldPreferUserLocaleWithSecondaryKey() { // GIVEN final String[] keys = new String[] { "only.en", "about.version" }; // WHEN final String translated = translationService.translate(userLocaleProvider, keys); // THEN assertEquals("Version Deutsch", translated); }
@Test public void messageWithNoKeys() { try { translationService.translate(userLocaleProvider, new String[0]); fail("should have failed"); } catch (IllegalArgumentException e) { assertEquals("Keys can't be null or empty", e.getMessage()); } }
@Test public void messageWithNullKeys() { try { translationService.translate(userLocaleProvider, null, null); fail("should have failed"); } catch (IllegalArgumentException e) { assertEquals("Keys can't be null or empty", e.getMessage()); } }
@Test public void messageWithBasenameAndLocaleFallsBackToDefaultLocaleIfNotFound() throws Exception { // WHEN String message = translationService.translate(newFixedLocaleProvider(USERLOCALE), LEGACY_BUNDLE, new String[] { "only.en" }); // THEN assertEquals("Only in English legacy", message); }
@Test public void messageFallsBackToDefaultLanguage() { // this key doesn't exist in the french message bundle assertEquals("Version English", translationService.translate(newFixedLocaleProvider(Locale.FRENCH), new String[] { "about.version" })); }
@Test public void messageWithBasename() throws Exception { // WHEN String message = translationService.translate(newFixedLocaleProvider(USERLOCALE), LEGACY_BUNDLE, new String[] { "about.title" }); // THEN assertEquals("Das ist ein Test legacy", message); }
@Test public void givenBasenameFallbacksToDefaultLegacy() throws Exception { // WHEN String message = translationService.translate(newFixedLocaleProvider(USERLOCALE), LEGACY_BUNDLE, new String[] { "about.version" }); // THEN // This is not the behavior we want, but this is the behavior of MessagesManager. assertEquals("Version English from default bundle", message); }
@Test public void messageFallsBackToDefautLocaleFromAVariantLocale() { assertEquals("Only in English", translationService.translate(newFixedLocaleProvider(GERMAN_CH_BASEL), new String[] { "only.en" })); }
@Test public void messageWithGermanLocale() { assertEquals("Das ist ein Titel", translationService.translate(newFixedLocaleProvider(Locale.GERMAN), new String[] { "about.title" })); }
@Test public void messageWithSwissGermanVariantLocale() { assertEquals("Titel Schweiz Basel", translationService.translate(newFixedLocaleProvider(GERMAN_CH_BASEL), new String[] { "about.title" })); }