001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2007
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * flx
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.common.web.view.freemarker;
025:
026: import java.util.Locale;
027: import java.util.Map;
028:
029: import org.springframework.core.GenericCollectionTypeResolver;
030: import org.springframework.core.JdkVersion;
031:
032: import freemarker.core.Environment;
033: import freemarker.template.TemplateModel;
034: import freemarker.template.TemplateModelException;
035:
036: /**
037: * ObjectWrapper that supports Maps containing {@link Locale} keys. When the
038: * map is to be wrapped, the entry for the current locale is returned instead
039: * of the map itself.
040: *
041: * @author Felix Gnass [fgnass at neteye dot de]
042: * @since 6.5
043: */
044: public class LocalizedObjectWrapper implements ObjectWrapperPlugin {
045:
046: private boolean exact = false;
047:
048: private Locale fallbackLocale = null;
049:
050: /**
051: * Sets whether the current locale must exactly match the key. If set to
052: * <code>false</code> (which is the default), a second lookup is performed
053: * with the language only in case no entry can be found.
054: */
055: public void setExact(boolean exact) {
056: this .exact = exact;
057: }
058:
059: /**
060: * Sets a fallback locale that is used in case no entry is found for the
061: * current locale. Default is <code>null</code>.
062: */
063: public void setFallbackLocale(Locale fallbackLocale) {
064: this .fallbackLocale = fallbackLocale;
065: }
066:
067: public boolean supports(Object obj) {
068: if (obj instanceof Map) {
069: Map map = (Map) obj;
070: return hasLocaleKey(map);
071: }
072: return false;
073: }
074:
075: public TemplateModel wrapSupportedObject(Object obj,
076: PluginObjectWrapper wrapper) throws TemplateModelException {
077:
078: Environment env = Environment.getCurrentEnvironment();
079: Locale locale = env.getLocale();
080: Object localizedEntry = getLocalizedEntry((Map) obj, locale);
081: return wrapper.wrap(localizedEntry);
082: }
083:
084: private boolean hasLocaleKey(Map map) {
085: if (JdkVersion.isAtLeastJava15()) {
086: Class keyType = GenericCollectionTypeResolver
087: .getMapKeyType(map.getClass());
088:
089: if (keyType != null) {
090: return keyType.isAssignableFrom(Locale.class);
091: }
092: }
093: if (!map.isEmpty()) {
094: Object firstKey = map.keySet().iterator().next();
095: return firstKey instanceof Locale;
096: }
097: return false;
098: }
099:
100: private Object getLocalizedEntry(Map map, Locale locale) {
101: Object value = map.get(locale);
102: if (value == null && !exact) {
103: Locale lang = new Locale(locale.getLanguage());
104: value = map.get(lang);
105: }
106: if (value == null && fallbackLocale != null
107: && !fallbackLocale.equals(locale)) {
108:
109: value = getLocalizedEntry(map, fallbackLocale);
110: }
111: return value;
112: }
113:
114: }
|