blob: 590f744eef61c096e53865e8708f7a6939d38093 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.i18n;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.environment.Cookie;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.Session;
import org.apache.cocoon.environment.Response;
import org.apache.cocoon.util.Deprecation;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
/**
* A utility class for i18n formatting and parsing routing.
*
* @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
* @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
* @version $Id$
*/
public class I18nUtils {
/**
* Locale string delimiter
*/
private static final String LOCALE_DELIMITER = "_-@.";
/**
* Did we already encountered an old namespace? This is static to ensure
* that the associated message will be logged only once.
*/
private static boolean deprecationFound = false;
/**
* The namespace for i18n is "http://apache.org/cocoon/i18n/2.1".
*/
public static final String NAMESPACE_URI =
"http://apache.org/cocoon/i18n/2.1";
/**
* The old namespace for i18n is "http://apache.org/cocoon/i18n/2.0".
*/
public static final String OLD_NAMESPACE_URI =
"http://apache.org/cocoon/i18n/2.0";
private I18nUtils() {
// Disable instantiation
}
/**
* Parses given locale string to Locale object. If the string is null
* or empty then the given locale is returned.
*
* @param localeString - a string containing locale in
* <code>language_country_variant</code> format.
* @param defaultLocale - returned if localeString is <code>null</code>
* or <code>""</code>
*/
public static Locale parseLocale(String localeString, Locale defaultLocale) {
if (localeString != null && localeString.length() > 0) {
StringTokenizer st = new StringTokenizer(localeString, LOCALE_DELIMITER);
String l = st.hasMoreElements() ? st.nextToken() : defaultLocale.getLanguage();
String c = st.hasMoreElements() ? st.nextToken() : "";
String v = st.hasMoreElements() ? st.nextToken() : "";
return new Locale(l, c, v);
}
return defaultLocale;
}
/**
* Parses given locale string to Locale object. If the string is null
* then the VM default locale is returned.
*
* @param localeString a string containing locale in
* <code>language_country_variant</code> format.
*
* @see #parseLocale(String, Locale)
* @see java.util.Locale#getDefault()
*/
public static Locale parseLocale(String localeString) {
return parseLocale(localeString, Locale.getDefault());
}
/**
* Callback interface for
* {@link I18nUtils#findLocale(Map, String, Parameters, Locale, boolean, boolean, boolean, I18nUtils.LocaleValidator)}
* @since 2.1.6
*/
public interface LocaleValidator {
/**
* @param name of the locale (for debugging)
* @param locale to test
* @return true if locale satisfies validator's criteria
*/
public boolean test(String name, Locale locale);
}
/**
* Find a suitable locale from an objectModel.
* @since 2.1.6
* @return locale found, or null if none found.
*/
public static Locale findLocale(Map objectModel,
String attribute,
Parameters parameters,
Locale defaultLocale,
boolean useLocale,
boolean useLocales,
boolean useBlankLocale,
LocaleValidator test) {
String localeStr;
Locale locale;
Request request = ObjectModelHelper.getRequest(objectModel);
// 1. Request parameter 'locale'
localeStr = request.getParameter(attribute);
if (localeStr != null) {
locale = parseLocale(localeStr);
if (test == null || test.test("request", locale)) {
return locale;
}
}
// 2. Session attribute 'locale'
Session session = request.getSession(false);
if (session != null &&
((localeStr = (String) session.getAttribute(attribute)) != null)) {
locale = parseLocale(localeStr);
if (test == null || test.test("session", locale)) {
return locale;
}
}
// 3. First matching cookie parameter 'locale' within each cookie sent
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
Cookie cookie = cookies[i];
if (cookie.getName().equals(attribute)) {
localeStr = cookie.getValue();
locale = parseLocale(localeStr);
if (test == null || test.test("cookie", locale)) {
return locale;
}
break;
}
}
}
// 4. Sitemap parameter "locale"
if (parameters != null) {
localeStr = parameters.getParameter("locale", null);
if (localeStr != null) {
locale = parseLocale(localeStr);
if (test == null || test.test("sitemap", locale)) {
return locale;
}
}
}
// 5. Locale setting of the requesting browser or server default
if (useLocale && !useLocales) {
locale = request.getLocale();
if (test == null || test.test("request", locale)) {
return locale;
}
}
if (useLocales) {
Enumeration locales = request.getLocales();
while (locales.hasMoreElements()) {
locale = (Locale)locales.nextElement();
if (test == null || test.test("request", locale)) {
return locale;
}
}
}
// 6. Default
if (defaultLocale != null) {
locale = defaultLocale;
if (test == null || test.test("default", locale)) {
return locale;
}
}
// 7. Blank
if (useBlankLocale) {
locale = new Locale("", ""); // Use JDK1.3 constructor
if (test == null || test.test("blank", locale)) {
return locale;
}
}
// 8. Fail
return null;
}
/**
* Find a suitable locale from an objectModel.
* @since 2.1.6
* @return locale found, or server default (never null).
*/
public static Locale findLocale(Map objectModel,
String attribute,
Parameters parameters,
Locale defaultLocale,
boolean useLocale) {
return findLocale(objectModel, attribute, parameters, defaultLocale, useLocale, false, false, null);
}
/**
* Store locale in request, session, or cookie.
* @since 2.1.6
*/
public static void storeLocale(Map objectModel,
String attribute,
String locale,
boolean storeInRequest,
boolean storeInSession,
boolean storeInCookie,
boolean createSession) {
// store in a request if so configured
if (storeInRequest) {
Request request = ObjectModelHelper.getRequest(objectModel);
request.setAttribute(attribute, locale);
}
// store in session if so configured
if (storeInSession) {
Request request = ObjectModelHelper.getRequest(objectModel);
Session session = request.getSession(createSession);
if (session != null) {
session.setAttribute(attribute, locale);
}
}
// store in a cookie if so configured
if (storeInCookie) {
Response response = ObjectModelHelper.getResponse(objectModel);
response.addCookie(response.createCookie(attribute, locale));
}
}
public static boolean matchesI18nNamespace(String uri) {
if (NAMESPACE_URI.equals(uri)) {
return true;
} else if (OLD_NAMESPACE_URI.equals(uri)) {
if (!deprecationFound) {
deprecationFound = true;
Deprecation.logger.warn("The namespace <" + OLD_NAMESPACE_URI +
"> is deprecated, use: <" + NAMESPACE_URI + ">");
}
return true;
}
return false;
}
}