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 PORTUGAL = new Locale("pt", "PT");
071    
072            public static final Locale PRC = Locale.PRC;
073    
074            public static final Locale ROOT = Locale.ROOT;
075    
076            public static final Locale SIMPLIFIED_CHINESE = Locale.SIMPLIFIED_CHINESE;
077    
078            public static final Locale SPAIN = new Locale("es", "ES");
079    
080            public static final Locale TAIWAN = Locale.TAIWAN;
081    
082            public static final Locale TRADITIONAL_CHINESE = Locale.TRADITIONAL_CHINESE;
083    
084            public static final Locale UK = Locale.UK;
085    
086            public static final Locale US = Locale.US;
087    
088            public static boolean equals(Locale locale1, Locale locale2) {
089                    return getInstance()._equals(locale1, locale2);
090            }
091    
092            public static Locale fromLanguageId(String languageId) {
093                    return getInstance()._fromLanguageId(languageId, true);
094            }
095    
096            public static Locale fromLanguageId(String languageId, boolean validate) {
097                    return getInstance()._fromLanguageId(languageId, validate);
098            }
099    
100            public static Locale fromLanguageId(
101                    String languageId, boolean validate, boolean useDefault) {
102    
103                    return getInstance()._fromLanguageId(languageId, validate, useDefault);
104            }
105    
106            public static Locale[] fromLanguageIds(List<String> languageIds) {
107                    return getInstance()._fromLanguageIds(languageIds);
108            }
109    
110            public static Locale[] fromLanguageIds(String[] languageIds) {
111                    return getInstance()._fromLanguageIds(languageIds);
112            }
113    
114            public static Locale getDefault() {
115                    return getInstance()._getDefault();
116            }
117    
118            public static LocaleUtil getInstance() {
119                    PortalRuntimePermission.checkGetBeanProperty(LocaleUtil.class);
120    
121                    return _instance;
122            }
123    
124            public static Map<String, String> getISOLanguages(Locale locale) {
125                    return getInstance()._getISOLanguages(locale);
126            }
127    
128            public static String getLongDisplayName(
129                    Locale locale, Set<String> duplicateLanguages) {
130    
131                    return getInstance()._getLongDisplayName(locale, duplicateLanguages);
132            }
133    
134            public static Locale getMostRelevantLocale() {
135                    return getInstance()._getMostRelevantLocale();
136            }
137    
138            public static String getShortDisplayName(
139                    Locale locale, Set<String> duplicateLanguages) {
140    
141                    return getInstance()._getShortDisplayName(locale, duplicateLanguages);
142            }
143    
144            public static Locale getSiteDefault() {
145                    return getInstance()._getSiteDefault();
146            }
147    
148            public static void setDefault(
149                    String userLanguage, String userCountry, String userVariant) {
150    
151                    getInstance()._setDefault(userLanguage, userCountry, userVariant);
152            }
153    
154            public static String toBCP47LanguageId(Locale locale) {
155                    return getInstance()._toBCP47LanguageId(locale);
156            }
157    
158            public static String toBCP47LanguageId(String languageId) {
159                    return getInstance()._toBCP47LanguageId(languageId);
160            }
161    
162            public static String[] toBCP47LanguageIds(Locale[] locales) {
163                    return getInstance()._toBCP47LanguageIds(locales);
164            }
165    
166            public static String[] toBCP47LanguageIds(String[] languageIds) {
167                    return getInstance()._toBCP47LanguageIds(languageIds);
168            }
169    
170            public static String[] toDisplayNames(Locale[] locales, Locale locale) {
171                    return getInstance()._toDisplayNames(locales, locale);
172            }
173    
174            public static String toLanguageId(Locale locale) {
175                    return getInstance()._toLanguageId(locale);
176            }
177    
178            public static String[] toLanguageIds(Locale[] locales) {
179                    return getInstance()._toLanguageIds(locales);
180            }
181    
182            public static String toW3cLanguageId(Locale locale) {
183                    return getInstance()._toW3cLanguageId(locale);
184            }
185    
186            public static String toW3cLanguageId(String languageId) {
187                    return getInstance()._toW3cLanguageId(languageId);
188            }
189    
190            public static String[] toW3cLanguageIds(Locale[] locales) {
191                    return getInstance()._toW3cLanguageIds(locales);
192            }
193    
194            public static String[] toW3cLanguageIds(String[] languageIds) {
195                    return getInstance()._toW3cLanguageIds(languageIds);
196            }
197    
198            private LocaleUtil() {
199                    _locale = new Locale("en", "US");
200            }
201    
202            private boolean _equals(Locale locale1, Locale locale2) {
203                    String languageId1 = _toLanguageId(locale1);
204                    String languageId2 = _toLanguageId(locale2);
205    
206                    return languageId1.equalsIgnoreCase(languageId2);
207            }
208    
209            private Locale _fromLanguageId(String languageId, boolean validate) {
210                    return _fromLanguageId(languageId, validate, true);
211            }
212    
213            private Locale _fromLanguageId(
214                    String languageId, boolean validate, boolean useDefault) {
215    
216                    if (languageId == null) {
217                            if (useDefault) {
218                                    return _locale;
219                            }
220                            else {
221                                    return null;
222                            }
223                    }
224    
225                    Locale locale = _locales.get(languageId);
226    
227                    if (locale != null) {
228                            return locale;
229                    }
230    
231                    try {
232                            int pos = languageId.indexOf(CharPool.UNDERLINE);
233    
234                            if (pos == -1) {
235                                    locale = new Locale(languageId);
236                            }
237                            else {
238                                    String[] languageIdParts = StringUtil.split(
239                                            languageId, CharPool.UNDERLINE);
240    
241                                    String languageCode = languageIdParts[0];
242                                    String countryCode = languageIdParts[1];
243    
244                                    String variant = null;
245    
246                                    if (languageIdParts.length > 2) {
247                                            variant = languageIdParts[2];
248                                    }
249    
250                                    if (Validator.isNotNull(variant)) {
251                                            locale = new Locale(languageCode, countryCode, variant);
252                                    }
253                                    else {
254                                            locale = new Locale(languageCode, countryCode);
255                                    }
256                            }
257    
258                            if (validate && !LanguageUtil.isAvailableLanguageCode(languageId)) {
259                                    throw new IllegalArgumentException("Invalid locale " + locale);
260                            }
261    
262                            _locales.put(languageId, locale);
263                    }
264                    catch (Exception e) {
265                            locale = null;
266    
267                            if (_log.isWarnEnabled()) {
268                                    _log.warn(languageId + " is not a valid language id");
269                            }
270                    }
271    
272                    if ((locale == null) && useDefault) {
273                            locale = _locale;
274                    }
275    
276                    return locale;
277            }
278    
279            private Locale[] _fromLanguageIds(List<String> languageIds) {
280                    Locale[] locales = new Locale[languageIds.size()];
281    
282                    for (int i = 0; i < languageIds.size(); i++) {
283                            locales[i] = _fromLanguageId(languageIds.get(i), true);
284                    }
285    
286                    return locales;
287            }
288    
289            private Locale[] _fromLanguageIds(String[] languageIds) {
290                    Locale[] locales = new Locale[languageIds.length];
291    
292                    for (int i = 0; i < languageIds.length; i++) {
293                            locales[i] = _fromLanguageId(languageIds[i], true);
294                    }
295    
296                    return locales;
297            }
298    
299            private Locale _getDefault() {
300                    Locale locale = LocaleThreadLocal.getDefaultLocale();
301    
302                    if (locale != null) {
303                            return locale;
304                    }
305    
306                    return _locale;
307            }
308    
309            private String _getDisplayName(
310                    String language, String country, Locale locale,
311                    Set<String> duplicateLanguages) {
312    
313                    StringBundler sb = new StringBundler(6);
314    
315                    sb.append(language);
316    
317                    if (duplicateLanguages.contains(locale.getLanguage())) {
318                            sb.append(StringPool.SPACE);
319                            sb.append(StringPool.OPEN_PARENTHESIS);
320                            sb.append(country);
321                            sb.append(StringPool.CLOSE_PARENTHESIS);
322                    }
323    
324                    if (LanguageUtil.isBetaLocale(locale)) {
325                            sb.append(_BETA_SUFFIX);
326                    }
327    
328                    return sb.toString();
329            }
330    
331            private Map<String, String> _getISOLanguages(Locale locale) {
332                    Map<String, String> isoLanguages = new TreeMap<String, String>(
333                            String.CASE_INSENSITIVE_ORDER);
334    
335                    for (String isoLanguageId : Locale.getISOLanguages()) {
336                            Locale isoLocale = _fromLanguageId(isoLanguageId, true);
337    
338                            isoLanguages.put(
339                                    isoLocale.getDisplayLanguage(locale), isoLanguageId);
340                    }
341    
342                    return isoLanguages;
343            }
344    
345            private String _getLongDisplayName(
346                    Locale locale, Set<String> duplicateLanguages) {
347    
348                    return _getDisplayName(
349                            locale.getDisplayLanguage(locale), locale.getDisplayCountry(locale),
350                            locale, duplicateLanguages);
351            }
352    
353            private Locale _getMostRelevantLocale() {
354                    Locale locale = LocaleThreadLocal.getThemeDisplayLocale();
355    
356                    if (locale == null) {
357                            locale = _getDefault();
358                    }
359    
360                    return locale;
361            }
362    
363            private String _getShortDisplayName(
364                    Locale locale, Set<String> duplicateLanguages) {
365    
366                    String language = locale.getDisplayLanguage(locale);
367    
368                    if (language.length() > 3) {
369                            language = locale.getLanguage();
370                            language = language.toUpperCase();
371                    }
372    
373                    String country = locale.getCountry();
374    
375                    return _getDisplayName(
376                            language, country.toUpperCase(), locale, duplicateLanguages);
377            }
378    
379            private Locale _getSiteDefault() {
380                    Locale locale = LocaleThreadLocal.getSiteDefaultLocale();
381    
382                    if (locale != null) {
383                            return locale;
384                    }
385    
386                    return _getDefault();
387            }
388    
389            private void _setDefault(
390                    String userLanguage, String userCountry, String userVariant) {
391    
392                    PortalRuntimePermission.checkSetBeanProperty(getClass());
393    
394                    if (Validator.isNotNull(userLanguage) &&
395                            Validator.isNull(userCountry) && Validator.isNull(userVariant)) {
396    
397                            _locale = new Locale(userLanguage);
398                    }
399                    else if (Validator.isNotNull(userLanguage) &&
400                                     Validator.isNotNull(userCountry) &&
401                                     Validator.isNull(userVariant)) {
402    
403                            _locale = new Locale(userLanguage, userCountry);
404                    }
405                    else if (Validator.isNotNull(userLanguage) &&
406                                     Validator.isNotNull(userCountry) &&
407                                     Validator.isNotNull(userVariant)) {
408    
409                            _locale = new Locale(userLanguage, userCountry, userVariant);
410                    }
411            }
412    
413            private String _toBCP47LanguageId(Locale locale) {
414                    return _toBCP47LanguageId(_toLanguageId(locale));
415            }
416    
417            private String _toBCP47LanguageId(String languageId) {
418                    if (languageId.equals("zh_CN")) {
419                            return "zh-Hans-CN";
420                    }
421                    else if (languageId.equals("zh_TW")) {
422                            return "zh-Hant-TW";
423                    }
424                    else {
425                            return StringUtil.replace(
426                                    languageId, CharPool.UNDERLINE, CharPool.MINUS);
427                    }
428            }
429    
430            private String[] _toBCP47LanguageIds(Locale[] locales) {
431                    return _toBCP47LanguageIds(_toLanguageIds(locales));
432            }
433    
434            private String[] _toBCP47LanguageIds(String[] languageIds) {
435                    String[] bcp47LanguageIds = new String[languageIds.length];
436    
437                    for (int i = 0; i < languageIds.length; i++) {
438                            bcp47LanguageIds[i] = _toBCP47LanguageId(languageIds[i]);
439                    }
440    
441                    return bcp47LanguageIds;
442            }
443    
444            private String[] _toDisplayNames(Locale[] locales, Locale locale) {
445                    String[] displayNames = new String[locales.length];
446    
447                    for (int i = 0; i < locales.length; i++) {
448                            displayNames[i] = locales[i].getDisplayName(locale);
449                    }
450    
451                    return displayNames;
452            }
453    
454            private String _toLanguageId(Locale locale) {
455                    if (locale == null) {
456                            locale = _locale;
457                    }
458    
459                    String country = locale.getCountry();
460    
461                    boolean hasCountry = false;
462    
463                    if (country.length() != 0) {
464                            hasCountry = true;
465                    }
466    
467                    String variant = locale.getVariant();
468    
469                    boolean hasVariant = false;
470    
471                    if (variant.length() != 0) {
472                            hasVariant = true;
473                    }
474    
475                    if (!hasCountry && !hasVariant) {
476                            return locale.getLanguage();
477                    }
478    
479                    int length = 3;
480    
481                    if (hasCountry && hasVariant) {
482                            length = 5;
483                    }
484    
485                    StringBundler sb = new StringBundler(length);
486    
487                    sb.append(locale.getLanguage());
488    
489                    if (hasCountry) {
490                            sb.append(StringPool.UNDERLINE);
491                            sb.append(country);
492                    }
493    
494                    if (hasVariant) {
495                            sb.append(StringPool.UNDERLINE);
496                            sb.append(variant);
497                    }
498    
499                    return sb.toString();
500            }
501    
502            private String[] _toLanguageIds(Locale[] locales) {
503                    String[] languageIds = new String[locales.length];
504    
505                    for (int i = 0; i < locales.length; i++) {
506                            languageIds[i] = _toLanguageId(locales[i]);
507                    }
508    
509                    return languageIds;
510            }
511    
512            private String _toW3cLanguageId(Locale locale) {
513                    return _toW3cLanguageId(_toLanguageId(locale));
514            }
515    
516            private String _toW3cLanguageId(String languageId) {
517                    return StringUtil.replace(
518                            languageId, CharPool.UNDERLINE, CharPool.MINUS);
519            }
520    
521            private String[] _toW3cLanguageIds(Locale[] locales) {
522                    return _toW3cLanguageIds(_toLanguageIds(locales));
523            }
524    
525            private String[] _toW3cLanguageIds(String[] languageIds) {
526                    String[] w3cLanguageIds = new String[languageIds.length];
527    
528                    for (int i = 0; i < languageIds.length; i++) {
529                            w3cLanguageIds[i] = _toW3cLanguageId(languageIds[i]);
530                    }
531    
532                    return w3cLanguageIds;
533            }
534    
535            private static final String _BETA_SUFFIX = " [Beta]";
536    
537            private static Log _log = LogFactoryUtil.getLog(LocaleUtil.class);
538    
539            private static LocaleUtil _instance = new LocaleUtil();
540    
541            private Locale _locale;
542            private Map<String, Locale> _locales = new HashMap<String, Locale>();
543    
544    }