001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.i18n;
018:
019: import org.apache.avalon.framework.parameters.Parameters;
020:
021: import org.apache.cocoon.environment.Cookie;
022: import org.apache.cocoon.environment.ObjectModelHelper;
023: import org.apache.cocoon.environment.Request;
024: import org.apache.cocoon.environment.Session;
025: import org.apache.cocoon.environment.Response;
026: import org.apache.cocoon.util.Deprecation;
027:
028: import java.util.Enumeration;
029: import java.util.Locale;
030: import java.util.Map;
031: import java.util.StringTokenizer;
032:
033: /**
034: * A utility class for i18n formatting and parsing routing.
035: *
036: * @author <a href="mailto:kpiroumian@apache.org">Konstantin Piroumian</a>
037: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
038: * @version $Id: I18nUtils.java 474832 2006-11-14 15:56:43Z vgritsenko $
039: */
040: public class I18nUtils {
041:
042: /**
043: * Locale string delimiter
044: */
045: private static final String LOCALE_DELIMITER = "_-@.";
046:
047: /**
048: * Did we already encountered an old namespace? This is static to ensure
049: * that the associated message will be logged only once.
050: */
051: private static boolean deprecationFound = false;
052:
053: /**
054: * The namespace for i18n is "http://apache.org/cocoon/i18n/2.1".
055: */
056: public static final String NAMESPACE_URI = "http://apache.org/cocoon/i18n/2.1";
057:
058: /**
059: * The old namespace for i18n is "http://apache.org/cocoon/i18n/2.0".
060: */
061: public static final String OLD_NAMESPACE_URI = "http://apache.org/cocoon/i18n/2.0";
062:
063: private I18nUtils() {
064: // Disable instantiation
065: }
066:
067: /**
068: * Parses given locale string to Locale object. If the string is null
069: * or empty then the given locale is returned.
070: *
071: * @param localeString - a string containing locale in
072: * <code>language_country_variant</code> format.
073: * @param defaultLocale - returned if localeString is <code>null</code>
074: * or <code>""</code>
075: */
076: public static Locale parseLocale(String localeString,
077: Locale defaultLocale) {
078: if (localeString != null && localeString.length() > 0) {
079: StringTokenizer st = new StringTokenizer(localeString,
080: LOCALE_DELIMITER);
081: String l = st.hasMoreElements() ? st.nextToken()
082: : defaultLocale.getLanguage();
083: String c = st.hasMoreElements() ? st.nextToken() : "";
084: String v = st.hasMoreElements() ? st.nextToken() : "";
085: return new Locale(l, c, v);
086: }
087: return defaultLocale;
088: }
089:
090: /**
091: * Parses given locale string to Locale object. If the string is null
092: * then the VM default locale is returned.
093: *
094: * @param localeString a string containing locale in
095: * <code>language_country_variant</code> format.
096: *
097: * @see #parseLocale(String, Locale)
098: * @see java.util.Locale#getDefault()
099: */
100: public static Locale parseLocale(String localeString) {
101: return parseLocale(localeString, Locale.getDefault());
102: }
103:
104: /**
105: * Callback interface for
106: * {@link I18nUtils#findLocale(Map, String, Parameters, Locale, boolean, boolean, boolean, I18nUtils.LocaleValidator)}
107: * @since 2.1.6
108: */
109: public interface LocaleValidator {
110:
111: /**
112: * @param name of the locale (for debugging)
113: * @param locale to test
114: * @return true if locale satisfies validator's criteria
115: */
116: public boolean test(String name, Locale locale);
117: }
118:
119: /**
120: * Find a suitable locale from an objectModel.
121: * @since 2.1.6
122: * @return locale found, or null if none found.
123: */
124: public static Locale findLocale(Map objectModel, String attribute,
125: Parameters parameters, Locale defaultLocale,
126: boolean useLocale, boolean useLocales,
127: boolean useBlankLocale, LocaleValidator test) {
128: String localeStr;
129: Locale locale;
130:
131: Request request = ObjectModelHelper.getRequest(objectModel);
132:
133: // 1. Request parameter 'locale'
134: localeStr = request.getParameter(attribute);
135: if (localeStr != null) {
136: locale = parseLocale(localeStr);
137: if (test == null || test.test("request", locale)) {
138: return locale;
139: }
140: }
141:
142: // 2. Session attribute 'locale'
143: Session session = request.getSession(false);
144: if (session != null
145: && ((localeStr = (String) session
146: .getAttribute(attribute)) != null)) {
147: locale = parseLocale(localeStr);
148: if (test == null || test.test("session", locale)) {
149: return locale;
150: }
151: }
152:
153: // 3. First matching cookie parameter 'locale' within each cookie sent
154: Cookie[] cookies = request.getCookies();
155: if (cookies != null) {
156: for (int i = 0; i < cookies.length; i++) {
157: Cookie cookie = cookies[i];
158: if (cookie.getName().equals(attribute)) {
159: localeStr = cookie.getValue();
160: locale = parseLocale(localeStr);
161: if (test == null || test.test("cookie", locale)) {
162: return locale;
163: }
164: break;
165: }
166: }
167: }
168:
169: // 4. Sitemap parameter "locale"
170: if (parameters != null) {
171: localeStr = parameters.getParameter("locale", null);
172: if (localeStr != null) {
173: locale = parseLocale(localeStr);
174: if (test == null || test.test("sitemap", locale)) {
175: return locale;
176: }
177: }
178: }
179:
180: // 5. Locale setting of the requesting browser or server default
181: if (useLocale && !useLocales) {
182: locale = request.getLocale();
183: if (test == null || test.test("request", locale)) {
184: return locale;
185: }
186: }
187: if (useLocales) {
188: Enumeration locales = request.getLocales();
189: while (locales.hasMoreElements()) {
190: locale = (Locale) locales.nextElement();
191: if (test == null || test.test("request", locale)) {
192: return locale;
193: }
194: }
195: }
196:
197: // 6. Default
198: if (defaultLocale != null) {
199: locale = defaultLocale;
200: if (test == null || test.test("default", locale)) {
201: return locale;
202: }
203: }
204:
205: // 7. Blank
206: if (useBlankLocale) {
207: locale = new Locale("", ""); // Use JDK1.3 constructor
208: if (test == null || test.test("blank", locale)) {
209: return locale;
210: }
211: }
212:
213: // 8. Fail
214: return null;
215: }
216:
217: /**
218: * Find a suitable locale from an objectModel.
219: * @since 2.1.6
220: * @return locale found, or server default (never null).
221: */
222: public static Locale findLocale(Map objectModel, String attribute,
223: Parameters parameters, Locale defaultLocale,
224: boolean useLocale) {
225: return findLocale(objectModel, attribute, parameters,
226: defaultLocale, useLocale, false, false, null);
227: }
228:
229: /**
230: * Store locale in request, session, or cookie.
231: * @since 2.1.6
232: */
233: public static void storeLocale(Map objectModel, String attribute,
234: String locale, boolean storeInRequest,
235: boolean storeInSession, boolean storeInCookie,
236: boolean createSession) {
237: // store in a request if so configured
238: if (storeInRequest) {
239: Request request = ObjectModelHelper.getRequest(objectModel);
240: request.setAttribute(attribute, locale);
241: }
242:
243: // store in session if so configured
244: if (storeInSession) {
245: Request request = ObjectModelHelper.getRequest(objectModel);
246: Session session = request.getSession(createSession);
247: if (session != null) {
248: session.setAttribute(attribute, locale);
249: }
250: }
251:
252: // store in a cookie if so configured
253: if (storeInCookie) {
254: Response response = ObjectModelHelper
255: .getResponse(objectModel);
256: response
257: .addCookie(response.createCookie(attribute, locale));
258: }
259: }
260:
261: public static boolean matchesI18nNamespace(String uri) {
262: if (NAMESPACE_URI.equals(uri)) {
263: return true;
264: } else if (OLD_NAMESPACE_URI.equals(uri)) {
265: if (!deprecationFound) {
266: deprecationFound = true;
267: Deprecation.logger.warn("The namespace <"
268: + OLD_NAMESPACE_URI + "> is deprecated, use: <"
269: + NAMESPACE_URI + ">");
270: }
271: return true;
272: }
273: return false;
274: }
275: }
|