001    /*
002    Copyright (c) 1996-2011, Damon Hart-Davis
003    All rights reserved.
004    
005    Redistribution and use in source and binary forms, with or without
006    modification, are permitted provided that the following conditions are
007    met:
008    
009      * Redistributions of source code must retain the above copyright
010        notice, this list of conditions and the following disclaimer.
011    
012      * Redistributions in binary form must reproduce the above copyright
013        notice, this list of conditions and the following disclaimer in the
014        documentation and/or other materials provided with the
015        distribution.
016    
017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
018    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
019    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
020    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
021    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
022    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
023    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
024    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
025    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
027    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028    */
029    
030    package org.hd.d.pg2k.svrCore;
031    
032    import java.util.ArrayList;
033    import java.util.Collections;
034    import java.util.HashMap;
035    import java.util.HashSet;
036    import java.util.List;
037    import java.util.Locale;
038    import java.util.Map;
039    import java.util.Set;
040    
041    import org.hd.d.pg2k.svrCore.location.GeoUtils;
042    
043    /**
044     * Created by IntelliJ IDEA.
045     * User: Damon Hart-Davis
046     * Date: 14-Sep-2003
047     * Time: 20:02:02
048     */
049    
050    /**Holds constants and some utility methods for internationalisation (i18n).
051     * These are features common to the core system, Web presentation, etc.
052     */
053    public final class I18NTools
054        {
055        /**Name of common resource bundle for core i18n messages. */
056        public static final String BUNDLE_COMMON = "common";
057    
058        /**Name of tree-description i18n resource bundle. */
059        public static final String BUNDLE_TREEDESC = "treedesc";
060    
061        /**Default locale to use in the system and on the Web site.
062         * This is British English, and reflects what we expect to
063         * find in the base messages (files) that the Web sites
064         * will use.
065         * <p>
066         * This locale is one that we should always be able to support.
067         */
068        public static final Locale DEFAULT_SYSTEM_LOCALE = new Locale("en", "GB");
069    
070        /**Main locales that we support i18n for in an immutable List.
071         * Earlier items are preferred (eg more commonly used by visitors);
072         * the site default is the first value.
073         * <p>
074         * Every item in this list is a Locale whose String version is of the form
075         * <tt>ll</tt> or <tt>ll_CC</tt>
076         * where "ll" is the language and "CC" the optional country code,
077         * eg <tt>fr</tt> for French and <tt>en_GB</tt> for UK English.
078         * <p>
079         * Every item that appears in this list has at least:
080         * <ul>
081         * <li>Most or all of the common message catalogue translated.
082         * <li>A standard flag icon.
083         * </ul>
084         * <p>
085         * There may be partial support for languages/locales other than those
086         * listed here.
087         */
088        public static final List<Locale> MAIN_LOCALES;
089    
090        /**Initialise MAIN_LOCALES. */
091        static
092            {
093            final List<Locale> l = new ArrayList<Locale>();
094    
095            // Default system value is first.
096            l.add(DEFAULT_SYSTEM_LOCALE); // Some variety of English (en).
097    
098            // Then other (hopefully) well-supported locales
099            // in approximate descending order of use by visitors.
100            // List should be kept as small as possible since
101            // each extra choice consumes bandwidth and space on most pages,
102            // and, for example, we have very limited space on handheld/mobile devices.
103            l.add(new Locale("de", ""));
104            l.add(new Locale("es", ""));
105            //l.add(new Locale("zh", "CN")); // Decommissioned cn-bj1 2009/04/12.
106    
107            MAIN_LOCALES = Collections.unmodifiableList(l);
108            }
109    
110        /**Immutable map from (a small set of common) top-level ccTLDs to best overall locale in our supported set for that location.
111         * This is not comprehensive
112         * (though we try to cover common cases where we have any explicit support),
113         * and is mainly to help when a browser (or search engine) does not indicate
114         * a preferred locale explicitly.
115         */
116        public static final Map<GeoUtils.CCTLD, Locale> LOCALE_BY_CCTLD;
117    
118        /**Initialise LOCALE_BY_CCTLD. */
119        static
120            {
121            // We use a HashMap for lookup speed.
122            final Map<GeoUtils.CCTLD, Locale> m = new HashMap<GeoUtils.CCTLD, Locale>(31);
123    
124            m.put(MemoryTools.intern(new GeoUtils.CCTLD("uk")), new Locale("en", "GB")); // Default.
125            m.put(MemoryTools.intern(new GeoUtils.CCTLD("us")), new Locale("en", "US")); // Where most users with no language set in their browsers are from.
126            m.put(MemoryTools.intern(new GeoUtils.CCTLD("ca")), new Locale("en", "CA"));
127            m.put(MemoryTools.intern(new GeoUtils.CCTLD("au")), new Locale("en", "AU"));
128            m.put(MemoryTools.intern(new GeoUtils.CCTLD("nz")), new Locale("en", "NZ"));
129            m.put(MemoryTools.intern(new GeoUtils.CCTLD("za")), new Locale("en", "ZA"));
130            m.put(MemoryTools.intern(new GeoUtils.CCTLD("in")), new Locale("en", "IN"));
131    
132            m.put(MemoryTools.intern(new GeoUtils.CCTLD("cn")), new Locale("zh", "CN"));
133            m.put(MemoryTools.intern(new GeoUtils.CCTLD("tw")), new Locale("zh", "TW"));
134            m.put(MemoryTools.intern(new GeoUtils.CCTLD("hk")), new Locale("zh", "HK"));
135    
136            m.put(MemoryTools.intern(new GeoUtils.CCTLD("nl")), new Locale("nl", ""));
137            m.put(MemoryTools.intern(new GeoUtils.CCTLD("fr")), new Locale("fr", ""));
138            m.put(MemoryTools.intern(new GeoUtils.CCTLD("de")), new Locale("de", ""));
139            m.put(MemoryTools.intern(new GeoUtils.CCTLD("at")), new Locale("de", "AT"));
140            m.put(MemoryTools.intern(new GeoUtils.CCTLD("es")), new Locale("es", ""));
141            m.put(MemoryTools.intern(new GeoUtils.CCTLD("mx")), new Locale("es", "MX"));
142            m.put(MemoryTools.intern(new GeoUtils.CCTLD("it")), new Locale("it", ""));
143            m.put(MemoryTools.intern(new GeoUtils.CCTLD("jp")), new Locale("ja", ""));
144    
145            m.put(MemoryTools.intern(new GeoUtils.CCTLD("mt")), new Locale("mt", ""));
146    
147            LOCALE_BY_CCTLD = Collections.unmodifiableMap(m);
148            }
149    
150    
151        /**Immutable Set of most locales supported by the system.
152         * Designed for relatively fast lookup.
153         */
154        public static final Set<Locale> LOCALES;
155    
156        /**Initialise LOCALES. */
157        static
158            {
159    //        final TreeSet<Locale> s = new TreeSet<Locale>(new Comparator<Locale>(){
160    //            /**Compares its two arguments for order.
161    //             * Sorts in toString() order, but is designed to be fairly fast.
162    //             */
163    //            public int compare(final Locale locale1, final Locale locale2)
164    //                {
165    //                // For speed, do initial compare on language component
166    //                // which avoids contructing new String values dynamically.
167    //                final int llComp = locale1.getLanguage().compareTo(locale2.getLanguage());
168    //                if(llComp != 0) { return(llComp); }
169    //                // Total ordering on full String representation.
170    //                return(locale1.toString().compareTo(locale2.toString()));
171    //                }
172    //            });
173    
174            final HashSet<Locale> s = new HashSet<Locale>(2 * (MAIN_LOCALES.size() + LOCALE_BY_CCTLD.size()));
175            s.addAll(MAIN_LOCALES);
176            s.addAll(LOCALE_BY_CCTLD.values());
177    
178            LOCALES = Collections.unmodifiableSet(s);
179            }
180        }