1 /*
2 * $Source$
3 * $Revision$
4 *
5 * Copyright (C) 2000 William Chesters
6 *
7 * Part of Melati (http://melati.org), a framework for the rapid
8 * development of clean, maintainable web applications.
9 *
10 * Melati is free software; Permission is granted to copy, distribute
11 * and/or modify this software under the terms either:
12 *
13 * a) the GNU General Public License as published by the Free Software
14 * Foundation; either version 2 of the License, or (at your option)
15 * any later version,
16 *
17 * or
18 *
19 * b) any version of the Melati Software License, as published
20 * at http://melati.org
21 *
22 * You should have received a copy of the GNU General Public License and
23 * the Melati Software License along with this program;
24 * if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26 * GNU General Public License and visit http://melati.org to obtain the
27 * Melati Software License.
28 *
29 * Feel free to contact the Developers of Melati (http://melati.org),
30 * if you would like to work out a different arrangement than the options
31 * outlined here. It is our intention to allow Melati to be used by as
32 * wide an audience as possible.
33 *
34 * This program is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 * GNU General Public License for more details.
38 *
39 * Contact details for copyright holder:
40 *
41 * William Chesters <williamc At paneris.org>
42 * http://paneris.org/~williamc
43 * Obrechtstraat 114, 2517VX Den Haag, The Netherlands
44 */
45
46 package org.melati.poem;
47
48 import java.text.SimpleDateFormat;
49 import java.time.format.DateTimeFormatter;
50 import java.util.HashMap;
51 import java.util.Locale;
52 import java.text.DateFormat;
53 import java.text.DateFormatSymbols;
54
55 import org.melati.poem.util.StringUtils;
56
57 /**
58 * A wrapper for a <code>Locale</code> for use within Melati.
59 */
60 public class PoemLocale {
61
62 private static final HashMap<Locale, PoemLocale> localeCache = new HashMap<Locale, PoemLocale>();
63
64 /** Default Locale: GB. */
65 public static final PoemLocale HERE = new PoemLocale(Locale.UK);
66
67 private final Locale locale;
68
69 private final DateFormatSymbols dateFormatSymbols;
70 private final String[] months, shortMonths;
71 private final DateFormat[] dateFormats;
72 private final DateFormat[] timestampFormats;
73
74 /**
75 * Creates a melati locale from a language tag as defined in RFC3066.
76 *
77 * @param tag A language tag, for example, "en-gb"
78 * @return A melati locale from the tag if we can parse it, otherwise null
79 */
80 public static PoemLocale fromLanguageTag(String tag) {
81 String subtags[] = StringUtils.split(tag, '-');
82
83 // if 1st subtag is 2 letters, then it's a 2 letter language code
84 if (subtags.length > 0 && subtags[0].length() == 2) {
85 Locale locale = null;
86 // if 2nd subtag exists and is 2 letters, then it's a 2 letter county code
87 if (subtags.length > 1 && subtags[1].length() == 2)
88 locale = new Locale(subtags[0], subtags[1]);
89 else
90 locale = new Locale(subtags[0], "");
91 return new PoemLocale(locale);
92 }
93 return null;
94 }
95
96 public static PoemLocale from(Locale locale) {
97 if (locale == null)
98 throw new NullPointerException();
99 PoemLocale it = localeCache.get(locale);
100 if(it == null)
101 localeCache.put(locale, new PoemLocale(locale));
102 return localeCache.get(locale);
103 }
104
105 /**
106 * Constructor given a non-null Locale.
107 *
108 * @param locale The Locale to base ours on.
109 */
110 public PoemLocale(Locale locale) {
111 if (locale == null)
112 throw new NullPointerException();
113 this.locale = locale;
114
115 dateFormatSymbols = new DateFormatSymbols(locale);
116 months = dateFormatSymbols.getMonths();
117 shortMonths = dateFormatSymbols.getShortMonths();
118
119 dateFormats = new DateFormat[4]; // don't tell me this will break
120 dateFormats[DateFormat.FULL] =
121 DateFormat.getDateInstance(DateFormat.FULL, locale);
122 dateFormats[DateFormat.LONG] =
123 DateFormat.getDateInstance(DateFormat.LONG, locale);
124 // Not happy about the change, even if it is an 'improvement' in java8
125 dateFormats[DateFormat.MEDIUM] = locale == Locale.UK ? new SimpleDateFormat("DD-MMM-YYYY") :
126 DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
127 dateFormats[DateFormat.SHORT] =
128 DateFormat.getDateInstance(DateFormat.SHORT, locale);
129
130 timestampFormats = new DateFormat[4]; // don't tell me this will break
131 timestampFormats[DateFormat.FULL] =
132 DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL,
133 locale);
134 timestampFormats[DateFormat.LONG] =
135 DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG,
136 locale);
137 timestampFormats[DateFormat.MEDIUM] =
138 DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM,
139 locale);
140 timestampFormats[DateFormat.SHORT] =
141 DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
142 locale);
143 }
144
145 /**
146 * @return the Locale
147 */
148 public final Locale locale() {
149 return locale;
150 }
151
152 /**
153 * @param monthNum numeric month
154 * @return full name of month
155 */
156 public String monthName(int monthNum) {
157 return months[monthNum - 1];
158 }
159
160 /**
161 * @param monthNum numeric month
162 * @return short name of month
163 */
164 public String shortMonthName(int monthNum) {
165 return shortMonths[monthNum - 1];
166 }
167
168 /**
169 * @param style as defined in DateFormat
170 * @return a format of that style
171 */
172 public DateFormat dateFormat(int style) {
173 return dateFormats[style];
174 }
175
176 /**
177 * @param style as defined in DateFormat
178 * @return a format of that style
179 */
180 public DateFormat timestampFormat(int style) {
181 return timestampFormats[style];
182 }
183
184 /**
185 * Delegated to Locale.
186 *
187 * @see java.util.Locale#hashCode()
188 * {@inheritDoc}
189 * @see java.lang.Object#hashCode()
190 */
191 public int hashCode() {
192 return locale.hashCode();
193 }
194
195 /**
196 * {@inheritDoc}
197 * @see java.lang.Object#equals(java.lang.Object)
198 */
199 public boolean equals(Object o) {
200 if (this == o) // quick check
201 return true;
202 if (o instanceof PoemLocale)
203 return locale.equals(((PoemLocale)o).locale());
204 else
205 return false;
206 }
207
208 /**
209 * Delegated to Locale.
210 *
211 * {@inheritDoc}
212 * @see java.lang.Object#toString()
213 */
214 public String toString() {
215 return locale.toString();
216 }
217 }