- An absolute file path, pointing to the root directory of the Harvester utility.
- You must include the final slash.
+ Force VIVO to use a specific language or Locale instead of those
+ specified by the browser.
+ This affects RDF data retrieved from the model, if RDFService.languageFilter is true.
+ This also affects the text of pages that have been modified to support multiple languages.
+
+
+ languages.forceLocale
+
+
+ en_US
+
+
+
+
+
+ A list of supported languages or Locales that the user may choose to
+ use instead of the one specified by the browser. Selection images must
+ be available in the i18n/images directory of the theme.
+ This affects RDF data retrieved from the model, if RDFService.languageFilter is true.
+ This also affects the text of pages that have been modified to support multiple languages.
+
+
+
+
+ languages.selectableLocales
+
+
+ en, es, fr_FR
+
+
+
+
+
+ For developers only.
+ Defeat the Freemarker template cache, so each template
+ is read from disk on each request. This permits developers to immediately
+ see the effect of changes to the template. The default is false, which
+ means that a cached copy of each template will be used for 60 seconds
+ before the disk is checked for a new version.
+ Setting this option to "true" slows down VIVO performance.
+
+
+
+
+ developer.defeatFreemarkerCache
+
+
+ false
+
+
+
+
+
+ For developers only.
+ Defeat the cache of language-specific text strings,
+ so the language file is read from disk on each request.
+ This permits developers to immediately
+ see the effect of changes to the text strings.
+ The default is false, which means that the language file is
+ read when VIVO starts up, or when a new theme is selected.
+ Setting this option to "true" slows down VIVO performance.
+
+
+
+
+ developer.defeatI18nCache = true
+
+
+ false
+
+
+
VI. Compile and deploy
diff --git a/webapp/config/example.runtime.properties b/webapp/config/example.runtime.properties
index 691f98139..d0284a389 100644
--- a/webapp/config/example.runtime.properties
+++ b/webapp/config/example.runtime.properties
@@ -119,3 +119,46 @@ proxy.eligibleTypeList = http://www.w3.org/2002/07/owl#Thing
# header supplied by the browser. Default is true if not set.
#
RDFService.languageFilter = true
+
+#
+# Force VIVO to use a specific language or Locale instead of those
+# specified by the browser. This affects RDF data retrieved from the model,
+# if RDFService.languageFilter is true. This also affects the text of pages
+# that have been modified to support multiple languages.
+#
+# languages.forceLocale = en_US
+
+#
+# A list of supported languages or Locales that the user may choose to
+# use instead of the one specified by the browser. Selection images must
+# be available in the i18n/images directory of the theme. This affects
+# RDF data retrieved from the model, if RDFService.languageFilter is true.
+# This also affects the text of pages that have been modified to support
+# multiple languages.
+#
+# This should not be used with languages.forceLocale, which will override it.
+#
+# languages.selectableLocales = en, es, fr
+
+#
+# For developers only: Setting this option to "true" slows down VIVO performance.
+#
+# Defeat the Freemarker template cache, so each template is read from disk
+# on each request. This permits developers to immediately see the effect of
+# changes to the template. The default is false, which means
+# that a cached copy of each template will be used for 60 seconds before
+# the disk is checked for a new version.
+#
+# developer.defeatFreemarkerCache = true
+
+#
+# For developers only: Setting this option to "true" slows down VIVO performance.
+#
+# Defeat the cache of language-specific text strings, so the language file
+# is read from disk on each request. This permits developers to immediately
+# see the effect of changes to the text strings. The default is
+# false, which means that the language file is read when
+# VIVO starts up, or when a new theme is selected.
+#
+# developer.defeatI18nCache = true
+
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java
index 07a370779..6f8f46511 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfiguration.java
@@ -5,7 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.freemarker;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java
index 00af47192..5a6e72bd8 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/I18n.java
@@ -200,7 +200,7 @@ public class I18n {
log.debug("Paths are '" + themeI18nPath + "' and '" + appI18nPath
+ "'");
- return VivoResourceBundle.getBundle(bundleName, ctx, appI18nPath,
+ return VitroResourceBundle.getBundle(bundleName, ctx, appI18nPath,
themeI18nPath, this);
}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VivoResourceBundle.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VitroResourceBundle.java
similarity index 94%
rename from webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VivoResourceBundle.java
rename to webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VitroResourceBundle.java
index ba314ea36..d4c9754f9 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VivoResourceBundle.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/VitroResourceBundle.java
@@ -41,8 +41,8 @@ import org.apache.commons.logging.LogFactory;
*
* In all_es.properties: account_email_html = @@file accountEmail_es.html
*/
-public class VivoResourceBundle extends ResourceBundle {
- private static final Log log = LogFactory.getLog(VivoResourceBundle.class);
+public class VitroResourceBundle extends ResourceBundle {
+ private static final Log log = LogFactory.getLog(VitroResourceBundle.class);
private static final String FILE_FLAG = "@@file ";
private static final String MESSAGE_FILE_NOT_FOUND = "File {1} not found for property {0}.";
@@ -51,11 +51,11 @@ public class VivoResourceBundle extends ResourceBundle {
// Factory method
// ----------------------------------------------------------------------
- public static VivoResourceBundle getBundle(String bundleName,
+ public static VitroResourceBundle getBundle(String bundleName,
ServletContext ctx, String appI18nPath, String themeI18nPath,
Control control) {
try {
- return new VivoResourceBundle(bundleName, ctx, appI18nPath,
+ return new VitroResourceBundle(bundleName, ctx, appI18nPath,
themeI18nPath, control);
} catch (FileNotFoundException e) {
log.debug(e);
@@ -78,7 +78,7 @@ public class VivoResourceBundle extends ResourceBundle {
private final Properties defaults;
private final Properties properties;
- private VivoResourceBundle(String bundleName, ServletContext ctx,
+ private VitroResourceBundle(String bundleName, ServletContext ctx,
String appI18nPath, String themeI18nPath, Control control)
throws IOException {
this.bundleName = bundleName;
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionController.java
new file mode 100644
index 000000000..523a263a2
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionController.java
@@ -0,0 +1,100 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.i18n.selection;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.LocaleUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
+
+/**
+ * Call this at /selectLocale&selection=[locale_string]
+ *
+ * For example: /selectLocale&selection=en_US or /selectLocale&selection=es
+ *
+ * Write an error to the log (and to DisplayMessage) if the selection is not
+ * syntactically valid.
+ *
+ * Write a warning to the log if the selection code is not one of the selectable
+ * Locales from runtime.properties, or if the selection code is not recognized
+ * by the system.
+ *
+ * Set the new Locale in the Session using SelectedLocale and return to the
+ * referrer.
+ */
+public class LocaleSelectionController extends HttpServlet {
+ private static final Log log = LogFactory
+ .getLog(LocaleSelectionController.class);
+
+ public static final String PARAMETER_SELECTION = "selection";
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ String referrer = req.getHeader("referer");
+
+ String selectedLocale = req.getParameter(PARAMETER_SELECTION);
+
+ try {
+ processSelectedLocale(req, selectedLocale);
+ } catch (Exception e) {
+ log.error("Failed to process the user's Locale selection", e);
+ }
+
+ if (StringUtils.isEmpty(referrer)) {
+ resp.sendRedirect(UrlBuilder.getHomeUrl());
+ } else {
+ resp.sendRedirect(referrer);
+ }
+ }
+
+ private void processSelectedLocale(HttpServletRequest req,
+ String selectedLocale) {
+ if (StringUtils.isBlank(selectedLocale)) {
+ log.debug("No '" + PARAMETER_SELECTION + "' parameter");
+ return;
+ }
+
+ Locale locale = null;
+
+ try {
+ locale = LocaleUtils.toLocale(selectedLocale.trim());
+ log.debug("Locale selection is " + locale);
+ } catch (IllegalArgumentException e) {
+ log.error("Failed to convert the selection to a Locale", e);
+ DisplayMessage.setMessage(req,
+ "There was a problem in the system. "
+ + "Your language choice was rejected.");
+ return;
+ }
+
+ List selectables = SelectedLocale.getSelectableLocales(req);
+ if (!selectables.contains(locale)) {
+ log.warn("User selected a locale '" + locale
+ + "' that was not in the list: " + selectables);
+ } else if (!LocaleUtils.isAvailableLocale(locale)) {
+ log.warn("User selected an unrecognized locale: '" + locale + "'");
+ }
+
+ SelectedLocale.setSelectedLocale(req, locale);
+ log.debug("Setting selected locale to " + locale);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ doGet(req, resp);
+ }
+}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java
new file mode 100644
index 000000000..627ad04ca
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/i18n/selection/LocaleSelectionDataGetter.java
@@ -0,0 +1,95 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.i18n.selection;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
+import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
+import edu.cornell.mannlib.vitro.webapp.utils.dataGetter.DataGetter;
+
+/**
+ * Get the data for the selectable Locales, so the Freemarker template can
+ * create a row of flag images that will select the desired locale.
+ *
+ * If there are no selectable Locales in runtime.properties, we return an empty
+ * map. (selectLocale?? will return false)
+ *
+ * If the Locale has been forced by runtime.properties, we do the same.
+ *
+ * If there are selectable Locales, the returned map will contain a structure
+ * like this:
+ *
+ *
+ * {selectLocale={
+ * selectLocaleUrl = [the URL for the form action to select a Locale]
+ * locales={ [a list of maps]
+ * { [a map for each Locale]
+ * code = [the code for the Locale, e.g. "en_US"]
+ * label = [the alt text for the Locale, e.g. "Spanish (Spain)"]
+ * imageUrl = [the URL of the image that represents the Locale]
+ * }
+ * }
+ * }
+ * }
+ *
+ */
+public class LocaleSelectionDataGetter implements DataGetter {
+ private static final Log log = LogFactory
+ .getLog(LocaleSelectionDataGetter.class);
+
+ private final VitroRequest vreq;
+
+ public LocaleSelectionDataGetter(VitroRequest vreq) {
+ this.vreq = vreq;
+ }
+
+ @Override
+ public Map getData(Map valueMap) {
+ List selectables = SelectedLocale.getSelectableLocales(vreq);
+ if (selectables.isEmpty()) {
+ return Collections.emptyMap();
+ }
+
+ Map result = new HashMap();
+ result.put("selectLocaleUrl", UrlBuilder.getUrl("/selectLocale"));
+ result.put("locales", buildLocalesList(selectables));
+
+ Map bodyMap = new HashMap();
+ bodyMap.put("selectLocale", result);
+ log.debug("Sending these values: " + bodyMap);
+ return bodyMap;
+ }
+
+ private List