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