View Javadoc
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 }