001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.util;
016    
017    import com.liferay.portal.kernel.language.LanguageUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.security.pacl.permission.PortalRuntimePermission;
021    
022    import java.util.HashMap;
023    import java.util.List;
024    import java.util.Locale;
025    import java.util.Map;
026    import java.util.Set;
027    import java.util.TreeMap;
028    
029    /**
030     * @author Brian Wing Shun Chan
031     * @author Raymond Aug??
032     * @author Eduardo Lundgren
033     */
034    public class LocaleUtil {
035    
036            public static final Locale BRAZIL = new Locale("pt", "BR");
037    
038            public static final Locale CANADA = Locale.CANADA;
039    
040            public static final Locale CANADA_FRENCH = Locale.CANADA_FRENCH;
041    
042            public static final Locale CHINA = Locale.CHINA;
043    
044            public static final Locale CHINESE = Locale.CHINESE;
045    
046            public static final Locale ENGLISH = Locale.ENGLISH;
047    
048            public static final Locale FRANCE = Locale.FRANCE;
049    
050            public static final Locale FRENCH = Locale.FRENCH;
051    
052            public static final Locale GERMAN = Locale.GERMAN;
053    
054            public static final Locale GERMANY = Locale.GERMANY;
055    
056            public static final Locale HUNGARY = new Locale("hu", "HU");
057    
058            public static final Locale ITALIAN = Locale.ITALIAN;
059    
060            public static final Locale ITALY = Locale.ITALY;
061    
062            public static final Locale JAPAN = Locale.JAPAN;
063    
064            public static final Locale JAPANESE = Locale.JAPANESE;
065    
066            public static final Locale KOREA = Locale.KOREA;
067    
068            public static final Locale KOREAN = Locale.KOREAN;
069    
070            public static final Locale NETHERLANDS = new Locale("nl", "NL");
071    
072            public static final Locale PORTUGAL = new Locale("pt", "PT");
073    
074            public static final Locale PRC = Locale.PRC;
075    
076            public static final Locale ROOT = Locale.ROOT;
077    
078            public static final Locale SIMPLIFIED_CHINESE = Locale.SIMPLIFIED_CHINESE;
079    
080            public static final Locale SPAIN = new Locale("es", "ES");
081    
082            public static final Locale TAIWAN = Locale.TAIWAN;
083    
084            public static final Locale TRADITIONAL_CHINESE = Locale.TRADITIONAL_CHINESE;
085    
086            public static final Locale UK = Locale.UK;
087    
088            public static final Locale US = Locale.US;
089    
090            public static boolean equals(Locale locale1, Locale locale2) {
091                    return getInstance()._equals(locale1, locale2);
092            }
093    
094            public static Locale fromLanguageId(String languageId) {
095                    return getInstance()._fromLanguageId(languageId, true);
096            }
097    
098            public static Locale fromLanguageId(String languageId, boolean validate) {
099                    return getInstance()._fromLanguageId(languageId, validate);
100            }
101    
102            public static Locale fromLanguageId(
103                    String languageId, boolean validate, boolean useDefault) {
104    
105                    return getInstance()._fromLanguageId(languageId, validate, useDefault);
106            }
107    
108            public static Locale[] fromLanguageIds(List<String> languageIds) {
109                    return getInstance()._fromLanguageIds(languageIds);
110            }
111    
112            public static Locale[] fromLanguageIds(String[] languageIds) {
113                    return getInstance()._fromLanguageIds(languageIds);
114            }
115    
116            public static Locale getDefault() {
117                    return getInstance()._getDefault();
118            }
119    
120            public static LocaleUtil getInstance() {
121                    PortalRuntimePermission.checkGetBeanProperty(LocaleUtil.class);
122    
123                    return _instance;
124            }
125    
126            public static Map<String, String> getISOLanguages(Locale locale) {
127                    return getInstance()._getISOLanguages(locale);
128            }
129    
130            public static String getLongDisplayName(
131                    Locale locale, Set<String> duplicateLanguages) {
132    
133                    return getInstance()._getLongDisplayName(locale, duplicateLanguages);
134            }
135    
136            public static Locale getMostRelevantLocale() {
137                    return getInstance()._getMostRelevantLocale();
138            }
139    
140            public static String getShortDisplayName(
141                    Locale locale, Set<String> duplicateLanguages) {
142    
143                    return getInstance()._getShortDisplayName(locale, duplicateLanguages);
144            }
145    
146            public static Locale getSiteDefault() {
147                    return getInstance()._getSiteDefault();
148            }
149    
150            public static void setDefault(
151                    String userLanguage, String userCountry, String userVariant) {
152    
153                    getInstance()._setDefault(userLanguage, userCountry, userVariant);
154            }
155    
156            public static String toBCP47LanguageId(Locale locale) {
157                    return getInstance()._toBCP47LanguageId(locale);
158            }
159    
160            public static String toBCP47LanguageId(String languageId) {
161                    return getInstance()._toBCP47LanguageId(languageId);
162            }
163    
164            public static String[] toBCP47LanguageIds(Locale[] locales) {
165                    return getInstance()._toBCP47LanguageIds(locales);
166            }
167    
168            public static String[] toBCP47LanguageIds(String[] languageIds) {
169                    return getInstance()._toBCP47LanguageIds(languageIds);
170            }
171    
172            public static String[] toDisplayNames(Locale[] locales, Locale locale) {
173                    return getInstance()._toDisplayNames(locales, locale);
174            }
175    
176            public static String toLanguageId(Locale locale) {
177                    return getInstance()._toLanguageId(locale);
178            }
179    
180            public static String[] toLanguageIds(Locale[] locales) {
181                    return getInstance()._toLanguageIds(locales);
182            }
183    
184            public static String toW3cLanguageId(Locale locale) {
185                    return getInstance()._toW3cLanguageId(locale);
186            }
187    
188            public static String toW3cLanguageId(String languageId) {
189                    return getInstance()._toW3cLanguageId(languageId);
190            }
191    
192            public static String[] toW3cLanguageIds(Locale[] locales) {
193                    return getInstance()._toW3cLanguageIds(locales);
194            }
195    
196            public static String[] toW3cLanguageIds(String[] languageIds) {
197                    return getInstance()._toW3cLanguageIds(languageIds);
198            }
199    
200            private LocaleUtil() {
201                    _locale = new Locale("en", "US");
202            }
203    
204            private boolean _equals(Locale locale1, Locale locale2) {
205                    String languageId1 = _toLanguageId(locale1);
206                    String languageId2 = _toLanguageId(locale2);
207    
208                    return StringUtil.equalsIgnoreCase(languageId1, languageId2);
209            }
210    
211            private Locale _fromLanguageId(String languageId, boolean validate) {
212                    return _fromLanguageId(languageId, validate, true);
213            }
214    
215            private Locale _fromLanguageId(
216                    String languageId, boolean validate, boolean useDefault) {
217    
218                    if (languageId == null) {
219                            if (useDefault) {
220                                    return _locale;
221                            }
222                            else {
223                                    return null;
224                            }
225                    }
226    
227                    Locale locale = _locales.get(languageId);
228    
229                    if (locale != null) {
230                            return locale;
231                    }
232    
233                    try {
234                            int pos = languageId.indexOf(CharPool.UNDERLINE);
235    
236                            if (pos == -1) {
237                                    locale = new Locale(languageId);
238                            }
239                            else {
240                                    String[] languageIdParts = StringUtil.split(
241                                            languageId, CharPool.UNDERLINE);
242    
243                                    String languageCode = languageIdParts[0];
244                                    String countryCode = languageIdParts[1];
245    
246                                    String variant = null;
247    
248                                    if (languageIdParts.length > 2) {
249                                            variant = languageIdParts[2];
250                                    }
251    
252                                    if (Validator.isNotNull(variant)) {
253                                            locale = new Locale(languageCode, countryCode, variant);
254                                    }
255                                    else {
256                                            locale = new Locale(languageCode, countryCode);
257                                    }
258                            }
259    
260                            if (validate && !LanguageUtil.isAvailableLanguageCode(languageId)) {
261                                    throw new IllegalArgumentException("Invalid locale " + locale);
262                            }
263    
264                            _locales.put(languageId, locale);
265                    }
266                    catch (Exception e) {
267                            locale = null;
268    
269                            if (_log.isWarnEnabled()) {
270                                    _log.warn(languageId + " is not a valid language id");
271                            }
272                    }
273    
274                    if ((locale == null) && useDefault) {
275                            locale = _locale;
276                    }
277    
278                    return locale;
279            }
280    
281            private Locale[] _fromLanguageIds(List<String> languageIds) {
282                    Locale[] locales = new Locale[languageIds.size()];
283    
284                    for (int i = 0; i < languageIds.size(); i++) {
285                            locales[i] = _fromLanguageId(languageIds.get(i), true);
286                    }
287    
288                    return locales;
289            }
290    
291            private Locale[] _fromLanguageIds(String[] languageIds) {
292                    Locale[] locales = new Locale[languageIds.length];
293    
294                    for (int i = 0; i < languageIds.length; i++) {
295                            locales[i] = _fromLanguageId(languageIds[i], true);
296                    }
297    
298                    return locales;
299            }
300    
301            private Locale _getDefault() {
302                    Locale locale = LocaleThreadLocal.getDefaultLocale();
303    
304                    if (locale != null) {
305                            return locale;
306                    }
307    
308                    return _locale;
309            }
310    
311            private String _getDisplayName(
312                    String language, String country, Locale locale,
313                    Set<String> duplicateLanguages) {
314    
315                    StringBundler sb = new StringBundler(6);
316    
317                    sb.append(language);
318    
319                    if (duplicateLanguages.contains(locale.getLanguage())) {
320                            sb.append(StringPool.SPACE);
321                            sb.append(StringPool.OPEN_PARENTHESIS);
322                            sb.append(country);
323                            sb.append(StringPool.CLOSE_PARENTHESIS);
324                    }
325    
326                    if (LanguageUtil.isBetaLocale(locale)) {
327                            sb.append(_BETA_SUFFIX);
328                    }
329    
330                    return sb.toString();
331            }
332    
333            private Map<String, String> _getISOLanguages(Locale locale) {
334                    Map<String, String> isoLanguages = new TreeMap<String, String>(
335                            String.CASE_INSENSITIVE_ORDER);
336    
337                    for (String isoLanguageId : Locale.getISOLanguages()) {
338                            Locale isoLocale = _fromLanguageId(isoLanguageId, true);
339    
340                            isoLanguages.put(
341                                    isoLocale.getDisplayLanguage(locale), isoLanguageId);
342                    }
343    
344                    return isoLanguages;
345            }
346    
347            private String _getLongDisplayName(
348                    Locale locale, Set<String> duplicateLanguages) {
349    
350                    return _getDisplayName(
351                            locale.getDisplayLanguage(locale), locale.getDisplayCountry(locale),
352                            locale, duplicateLanguages);
353            }
354    
355            private Locale _getMostRelevantLocale() {
356                    Locale locale = LocaleThreadLocal.getThemeDisplayLocale();
357    
358                    if (locale == null) {
359                            locale = _getDefault();
360                    }
361    
362                    return locale;
363            }
364    
365            private String _getShortDisplayName(
366                    Locale locale, Set<String> duplicateLanguages) {
367    
368                    String language = locale.getDisplayLanguage(locale);
369    
370                    if (language.length() > 3) {
371                            language = locale.getLanguage();
372                            language = StringUtil.toUpperCase(language);
373                    }
374    
375                    String country = locale.getCountry();
376    
377                    return _getDisplayName(
378                            language, StringUtil.toUpperCase(country), locale,
379                            duplicateLanguages);
380            }
381    
382            private Locale _getSiteDefault() {
383                    Locale locale = LocaleThreadLocal.getSiteDefaultLocale();
384    
385                    if (locale != null) {
386                            return locale;
387                    }
388    
389                    return _getDefault();
390            }
391    
392            private void _setDefault(
393                    String userLanguage, String userCountry, String userVariant) {
394    
395                    PortalRuntimePermission.checkSetBeanProperty(getClass());
396    
397                    if (Validator.isNotNull(userLanguage) &&
398                            Validator.isNull(userCountry) && Validator.isNull(userVariant)) {
399    
400                            _locale = new Locale(userLanguage);
401                    }
402                    else if (Validator.isNotNull(userLanguage) &&
403                                     Validator.isNotNull(userCountry) &&
404                                     Validator.isNull(userVariant)) {
405    
406                            _locale = new Locale(userLanguage, userCountry);
407                    }
408                    else if (Validator.isNotNull(userLanguage) &&
409                                     Validator.isNotNull(userCountry) &&
410                                     Validator.isNotNull(userVariant)) {
411    
412                            _locale = new Locale(userLanguage, userCountry, userVariant);
413                    }
414            }
415    
416            private String _toBCP47LanguageId(Locale locale) {
417                    return _toBCP47LanguageId(_toLanguageId(locale));
418            }
419    
420            private String _toBCP47LanguageId(String languageId) {
421                    if (languageId.equals("zh_CN")) {
422                            return "zh-Hans-CN";
423                    }
424                    else if (languageId.equals("zh_TW")) {
425                            return "zh-Hant-TW";
426                    }
427                    else {
428                            return StringUtil.replace(
429                                    languageId, CharPool.UNDERLINE, CharPool.MINUS);
430                    }
431            }
432    
433            private String[] _toBCP47LanguageIds(Locale[] locales) {
434                    return _toBCP47LanguageIds(_toLanguageIds(locales));
435            }
436    
437            private String[] _toBCP47LanguageIds(String[] languageIds) {
438                    String[] bcp47LanguageIds = new String[languageIds.length];
439    
440                    for (int i = 0; i < languageIds.length; i++) {
441                            bcp47LanguageIds[i] = _toBCP47LanguageId(languageIds[i]);
442                    }
443    
444                    return bcp47LanguageIds;
445            }
446    
447            private String[] _toDisplayNames(Locale[] locales, Locale locale) {
448                    String[] displayNames = new String[locales.length];
449    
450                    for (int i = 0; i < locales.length; i++) {
451                            displayNames[i] = locales[i].getDisplayName(locale);
452                    }
453    
454                    return displayNames;
455            }
456    
457            private String _toLanguageId(Locale locale) {
458                    if (locale == null) {
459                            locale = _locale;
460                    }
461    
462                    String country = locale.getCountry();
463    
464                    boolean hasCountry = false;
465    
466                    if (country.length() != 0) {
467                            hasCountry = true;
468                    }
469    
470                    String variant = locale.getVariant();
471    
472                    boolean hasVariant = false;
473    
474                    if (variant.length() != 0) {
475                            hasVariant = true;
476                    }
477    
478                    if (!hasCountry && !hasVariant) {
479                            return locale.getLanguage();
480                    }
481    
482                    int length = 3;
483    
484                    if (hasCountry && hasVariant) {
485                            length = 5;
486                    }
487    
488                    StringBundler sb = new StringBundler(length);
489    
490                    sb.append(locale.getLanguage());
491    
492                    if (hasCountry) {
493                            sb.append(StringPool.UNDERLINE);
494                            sb.append(country);
495                    }
496    
497                    if (hasVariant) {
498                            sb.append(StringPool.UNDERLINE);
499                            sb.append(variant);
500                    }
501    
502                    return sb.toString();
503            }
504    
505            private String[] _toLanguageIds(Locale[] locales) {
506                    String[] languageIds = new String[locales.length];
507    
508                    for (int i = 0; i < locales.length; i++) {
509                            languageIds[i] = _toLanguageId(locales[i]);
510                    }
511    
512                    return languageIds;
513            }
514    
515            private String _toW3cLanguageId(Locale locale) {
516                    return _toW3cLanguageId(_toLanguageId(locale));
517            }
518    
519            private String _toW3cLanguageId(String languageId) {
520                    return StringUtil.replace(
521                            languageId, CharPool.UNDERLINE, CharPool.MINUS);
522            }
523    
524            private String[] _toW3cLanguageIds(Locale[] locales) {
525                    return _toW3cLanguageIds(_toLanguageIds(locales));
526            }
527    
528            private String[] _toW3cLanguageIds(String[] languageIds) {
529                    String[] w3cLanguageIds = new String[languageIds.length];
530    
531                    for (int i = 0; i < languageIds.length; i++) {
532                            w3cLanguageIds[i] = _toW3cLanguageId(languageIds[i]);
533                    }
534    
535                    return w3cLanguageIds;
536            }
537    
538            private static final String _BETA_SUFFIX = " [Beta]";
539    
540            private static Log _log = LogFactoryUtil.getLog(LocaleUtil.class);
541    
542            private static LocaleUtil _instance = new LocaleUtil();
543    
544            private Locale _locale;
545            private Map<String, Locale> _locales = new HashMap<String, Locale>();
546    
547    }