1 package org.apache.turbine.services.localization;
2
3 /* ====================================================================
4 * The Apache Software License, Version 1.1
5 *
6 * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
7 * reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the
19 * distribution.
20 *
21 * 3. The end-user documentation included with the redistribution,
22 * if any, must include the following acknowledgment:
23 * "This product includes software developed by the
24 * Apache Software Foundation (http://www.apache.org/)."
25 * Alternately, this acknowledgment may appear in the software itself,
26 * if and wherever such third-party acknowledgments normally appear.
27 *
28 * 4. The names "Apache" and "Apache Software Foundation" and
29 * "Apache Turbine" must not be used to endorse or promote products
30 * derived from this software without prior written permission. For
31 * written permission, please contact apache@apache.org.
32 *
33 * 5. Products derived from this software may not be called "Apache",
34 * "Apache Turbine", nor may "Apache" appear in their name, without
35 * prior written permission of the Apache Software Foundation.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48 * SUCH DAMAGE.
49 * ====================================================================
50 *
51 * This software consists of voluntary contributions made by many
52 * individuals on behalf of the Apache Software Foundation. For more
53 * information on the Apache Software Foundation, please see
54 * <http://www.apache.org/>.
55 */
56
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.Iterator;
60 import java.util.Locale;
61 import java.util.NoSuchElementException;
62 import java.util.StringTokenizer;
63
64 /***
65 * Parses the HTTP <code>Accept-Language</code> header as per section
66 * 14.4 of RFC 2068 (HTTP 1.1 header field definitions).
67 *
68 * @deprecated Use the Fulcrum Localization component instead.
69 * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
70 * @version $Id: LocaleTokenizer.java,v 1.4 2003/09/09 15:04:51 epugh Exp $
71 */
72 public class LocaleTokenizer
73 implements Iterator
74 {
75 /***
76 * Separates elements of the <code>Accept-Language</code> HTTP
77 * header.
78 */
79 private static final String LOCALE_SEPARATOR = ",";
80
81 /***
82 * Separates locale from quality within elements.
83 */
84 private static final char QUALITY_SEPARATOR = ';';
85
86 /***
87 * The default quality value for an <code>AcceptLanguage</code>
88 * object.
89 */
90 private static final Float DEFAULT_QUALITY = new Float(1.0f);
91
92 /***
93 * The parsed locales.
94 */
95 private ArrayList locales = new ArrayList(3);
96
97 /***
98 * Parses the <code>Accept-Language</code> header.
99 *
100 * @param header The <code>Accept-Language</code> header
101 * (i.e. <code>en, es;q=0.8, zh-TW;q=0.1</code>).
102 */
103 public LocaleTokenizer(String header)
104 {
105 StringTokenizer tok = new StringTokenizer(header, LOCALE_SEPARATOR);
106 while (tok.hasMoreTokens())
107 {
108 AcceptLanguage acceptLang = new AcceptLanguage();
109 String element = tok.nextToken().trim();
110 int index;
111
112 // Record and cut off any quality value that comes after a
113 // semi-colon.
114 if ((index = element.indexOf(QUALITY_SEPARATOR)) != -1)
115 {
116 String q = element.substring(index);
117 element = element.substring(0, index);
118 if ((index = q.indexOf('=')) != -1)
119 {
120 try
121 {
122 acceptLang.quality =
123 Float.valueOf(q.substring(index + 1));
124 }
125 catch (NumberFormatException useDefault)
126 {
127 }
128 }
129 }
130
131 element = element.trim();
132
133 // Create a Locale from the language. A dash may separate the
134 // language from the country.
135 if ((index = element.indexOf('-')) == -1)
136 {
137 // No dash means no country.
138 acceptLang.locale = new Locale(element, "");
139 }
140 else
141 {
142 acceptLang.locale = new Locale(element.substring(0, index),
143 element.substring(index + 1));
144 }
145
146 locales.add(acceptLang);
147 }
148
149 // Sort by quality in descending order.
150 Collections.sort(locales, Collections.reverseOrder());
151 }
152
153 /***
154 * @return Whether there are more locales.
155 */
156 public boolean hasNext()
157 {
158 return !locales.isEmpty();
159 }
160
161 /***
162 * Creates a <code>Locale</code> from the next element of the
163 * <code>Accept-Language</code> header.
164 *
165 * @return The next highest-rated <code>Locale</code>.
166 * @throws NoSuchElementException No more locales.
167 */
168 public Object next()
169 {
170 if (locales.isEmpty())
171 {
172 throw new NoSuchElementException();
173 }
174 return ((AcceptLanguage) locales.remove(0)).locale;
175 }
176
177 /***
178 * Not implemented.
179 */
180 public final void remove()
181 {
182 throw new UnsupportedOperationException(getClass().getName() +
183 " does not support remove()");
184 }
185
186 /***
187 * Struct representing an element of the HTTP
188 * <code>Accept-Language</code> header.
189 */
190 private class AcceptLanguage implements Comparable
191 {
192 /***
193 * The language and country.
194 */
195 Locale locale;
196
197 /***
198 * The quality of our locale (as values approach
199 * <code>1.0</code>, they indicate increased user preference).
200 */
201 Float quality = DEFAULT_QUALITY;
202
203 public final int compareTo(Object acceptLang)
204 {
205 return quality.compareTo(((AcceptLanguage) acceptLang).quality);
206 }
207 }
208 }