diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java index a4a3b396e..bdfda1e7f 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/config/ConfigurationPropertiesSmokeTests.java @@ -4,6 +4,13 @@ package edu.cornell.mannlib.vitro.webapp.config; import java.net.URI; import java.net.URISyntaxException; +import java.io.IOException; +import java.util.List; +import java.util.Arrays; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.stream.Collectors; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -25,10 +32,11 @@ public class ConfigurationPropertiesSmokeTests implements .getLog(ConfigurationPropertiesSmokeTests.class); private static final String PROPERTY_DEFAULT_NAMESPACE = "Vitro.defaultNamespace"; - private static final String PROPERTY_LANGUAGE_BUILD = "languages.addToBuild"; private static final String PROPERTY_LANGUAGE_SELECTABLE = "languages.selectableLocales"; private static final String PROPERTY_LANGUAGE_FORCE = "languages.forceLocale"; private static final String PROPERTY_LANGUAGE_FILTER = "RDFService.languageFilter"; + private static final String VIVO_BUNDLE_PREFIX = "vivo_all_"; + private static final String VITRO_BUNDLE_PREFIX = "all_"; private static final String PROPERTY_ARGON2_TIME = "argon2.time"; private static final String PROPERTY_ARGON2_MEMORY = "argon2.memory"; private static final String PROPERTY_ARGON2_PARALLELISM = "argon2.parallelism"; @@ -41,8 +49,9 @@ public class ConfigurationPropertiesSmokeTests implements checkDefaultNamespace(ctx, props, ss); checkMultipleRPFs(ctx, props, ss); - checkLanguages(props, ss); + checkLanguages(ctx, props, ss); checkEncryptionParameters(props, ss); + } /** @@ -110,10 +119,7 @@ public class ConfigurationPropertiesSmokeTests implements * languages and force language. Shouldn't build with language unless * language filtering is enabled. */ - private void checkLanguages(ConfigurationProperties props, StartupStatus ss) { - String buildString = props.getProperty(PROPERTY_LANGUAGE_BUILD); - boolean buildWithLanguages = StringUtils.isNotBlank(buildString); - + private void checkLanguages(ServletContext ctx, ConfigurationProperties props, StartupStatus ss) { String selectString = props.getProperty(PROPERTY_LANGUAGE_SELECTABLE); boolean selectableLanguages = StringUtils.isNotBlank(selectString); @@ -121,16 +127,44 @@ public class ConfigurationPropertiesSmokeTests implements boolean forceLanguage = StringUtils.isNotBlank(forceString); String filterString = props.getProperty(PROPERTY_LANGUAGE_FILTER, - "true"); + "false"); boolean languageFilter = Boolean.valueOf(filterString); + String i18nDirPath = ctx.getRealPath("/i18n"); - if (selectableLanguages && !buildWithLanguages) { - ss.warning(this, String.format("Problem with Language setup - " - + "runtime.properties specifies a " - + "list of selectable languages (%s = %s), but " - + "build.properties did not include any languages with %s", - PROPERTY_LANGUAGE_SELECTABLE, selectString, - PROPERTY_LANGUAGE_BUILD)); + if (i18nDirPath == null) { + throw new IllegalStateException( + "Application does not have an /i18n directory."); + } + + List i18nNames = null; + + i18nNames = geti18nNames(i18nDirPath); + + log.debug("i18nNames: " + i18nNames); + + if (i18nNames.isEmpty()) { + ss.fatal(this, "The application found no files in '" + + i18nDirPath + + "' ."); + } + else { + ss.info(this, "Base language files loaded: " + i18nNames); + } + + /* Make sure language files exist for values in the selectableLocales propery. + The prefixes of vitro and vivo are hard coded into the app, + so we can assume the bundle names must have the same file format */ + if (selectableLanguages) { + List selectableLanguagesList = Arrays.asList(selectString.split("\\s*,\\s*")); + for (String language : selectableLanguagesList) { + String vivoBundle = VIVO_BUNDLE_PREFIX + language + ".properties"; + String vitroBundle = VITRO_BUNDLE_PREFIX + language + ".properties"; + if (!i18nNames.contains(vivoBundle) && !i18nNames.contains(vitroBundle)) { + ss.warning(this, language + " was found in the value for " + + PROPERTY_LANGUAGE_SELECTABLE + " but no corresponding " + + "language file was found."); + } + } } if (selectableLanguages && forceLanguage) { @@ -142,17 +176,31 @@ public class ConfigurationPropertiesSmokeTests implements PROPERTY_LANGUAGE_SELECTABLE, selectString)); } - if (buildWithLanguages && !languageFilter) { + if (selectableLanguages && !languageFilter) { ss.warning(this, String.format("Problem with Language setup - " - + "build.properties includes one or more additional " + + "languages.selectableLocales in runtime.properties " + + "includes one or more additional " + "languages (%s = %s), but runtime.properties has " + "disabled language filtering (%s = %s). This will " + "likely result in a mix of languages in the " - + "application.", PROPERTY_LANGUAGE_BUILD, buildString, + + "application.", PROPERTY_LANGUAGE_SELECTABLE, selectString, PROPERTY_LANGUAGE_FILTER, filterString)); } } + /** Create a list of the names of available language files. */ + private List geti18nNames(String i18nBaseDirPath) { + try { + return Files.walk(Paths.get(i18nBaseDirPath)) + .filter(Files::isRegularFile) + .map(Path::getFileName) + .map(p -> {return p.toString();}) + .collect(Collectors.toList()); + } catch (IOException e) { + throw new RuntimeException("Failed to find language files", e); + } + } + /** * Fail if there are no config properties for the Argon2 encryption. */ @@ -170,6 +218,7 @@ public class ConfigurationPropertiesSmokeTests implements ss.fatal(this, "runtime.properties does not contain a value for '" + name + "'"); return; + } }