001: package org.apache.velocity.tools.view.i18n;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.util.Locale;
023: import javax.servlet.ServletContext;
024: import org.apache.velocity.app.VelocityEngine;
025: import org.apache.velocity.context.Context;
026: import org.apache.velocity.tools.view.context.ViewContext;
027:
028: /**
029: * Allows for transparent content negotiation in a manner mimicking
030: * Apache httpd's <a
031: * href="http://httpd.apache.org/docs-2.0/content-negotiation.html">MultiViews</a>.
032: *
033: * <p>Reads the default language out of the ViewContext as
034: * <code>org.apache.velocity.tools.view.i18n.defaultLanguage</code>.
035: * See {@link #findLocalizedResource(String, String)} and {@link
036: * #findLocalizedResource(String, Locale)} for usage.</p>
037: *
038: * @version $Id: MultiViewsTool.java 477914 2006-11-21 21:52:11Z henning $
039: * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
040: */
041: public class MultiViewsTool {
042: /**
043: * The key used to search initialization, context, and JVM
044: * parameters for the default language to use.
045: */
046: protected static final String DEFAULT_LANGUAGE_KEY = "org.apache.velocity.tools.view.i18n.defaultLanguage";
047:
048: /**
049: * The two character abbreviation for the request's default
050: * language.
051: */
052: protected String defaultLanguage;
053:
054: protected VelocityEngine engine;
055:
056: /**
057: * Creates a new uninitialized instance. Call {@link #init}
058: * to initialize it.
059: */
060: public MultiViewsTool() {
061: }
062:
063: /**
064: * Extracts the default language from the specified
065: * <code>ViewContext</code>, looking first at the Velocity
066: * context, then the servlet context, then lastly at the JVM
067: * default. This "narrow scope to wide scope" pattern makes it
068: * easy to setup language overrides at different levels within
069: * your application.
070: *
071: * @param obj the current ViewContext
072: * @throws IllegalArgumentException if the param is not a ViewContext
073: */
074: public void init(Object obj) {
075: if (!(obj instanceof ViewContext)) {
076: throw new IllegalArgumentException(
077: "Tool can only be initialized with a ViewContext");
078: }
079:
080: ViewContext context = (ViewContext) obj;
081: Context vc = context.getVelocityContext();
082: this .engine = context.getVelocityEngine();
083:
084: defaultLanguage = (String) vc.get(DEFAULT_LANGUAGE_KEY);
085: if (defaultLanguage == null
086: || defaultLanguage.trim().equals("")) {
087: ServletContext sc = context.getServletContext();
088: defaultLanguage = (String) sc
089: .getAttribute(DEFAULT_LANGUAGE_KEY);
090: if (defaultLanguage == null
091: || defaultLanguage.trim().equals("")) {
092: // Use JVM default.
093: defaultLanguage = Locale.getDefault().getLanguage();
094: }
095: }
096: }
097:
098: /**
099: * Calls {@link #findLocalizedResource(String, String)} using the
100: * language extracted from <code>locale</code>.
101: *
102: * @see #findLocalizedResource(String, String)
103: */
104: public String findLocalizedResource(String name, Locale locale) {
105: return findLocalizedResource(name, locale.getLanguage());
106: }
107:
108: /**
109: * Calls {@link #findLocalizedResource(String, String)} using the
110: * default language.
111: *
112: * @see #findLocalizedResource(String, String)
113: */
114: public String findLocalizedResource(String name) {
115: return findLocalizedResource(defaultLanguage);
116: }
117:
118: /**
119: * <p>Finds the a localized version of the requested Velocity
120: * resource (such as a file or template) which is most appropriate
121: * for the locale of the current request. Use in conjuction with
122: * Apache httpd's <code>MultiViews</code>, or by itself.</p>
123: *
124: * <p>Usage from a template would be something like the following:
125: * <blockquote><code><pre>
126: * #parse ($multiviews.findLocalizedResource("header.vm", "en"))
127: * #include ($multiviews.findLocalizedResource("my_page.html", "en"))
128: * #parse ($multiviews.findLocalizedResource("footer.vm", "en"))
129: * </pre></code></blockquote>
130: *
131: * You might also wrap this method using another pull/view tool
132: * which does internationalization/localization/content negation
133: * for a single point of access.</p>
134: *
135: * @param name The unlocalized name of the file to find.
136: * @param language The language to find localized context for.
137: * @return The localized file name, or <code>name</code> if it is
138: * not localizable.
139: */
140: public String findLocalizedResource(String name, String language) {
141: String localizedName = name + '.' + language;
142: // templateExists() checks for static content as well
143: if (!engine.templateExists(localizedName)) {
144: // Fall back to the default lanaguage.
145: String defaultLangSuffix = '.' + defaultLanguage;
146: if (localizedName.endsWith(defaultLangSuffix)) {
147: // Assume no localized version of the resource.
148: localizedName = name;
149: } else {
150: localizedName = name + defaultLangSuffix;
151: if (!engine.templateExists(localizedName)) {
152: localizedName = name;
153: }
154: }
155: }
156: return localizedName;
157: }
158:
159: }
|