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.language;
016    
017    import com.liferay.portal.kernel.cache.MultiVMPoolUtil;
018    import com.liferay.portal.kernel.cache.PortalCache;
019    import com.liferay.portal.kernel.cache.PortalCacheMapSynchronizeUtil;
020    import com.liferay.portal.kernel.cache.PortalCacheMapSynchronizeUtil.Synchronizer;
021    import com.liferay.portal.kernel.exception.PortalException;
022    import com.liferay.portal.kernel.exception.SystemException;
023    import com.liferay.portal.kernel.language.Language;
024    import com.liferay.portal.kernel.language.LanguageWrapper;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028    import com.liferay.portal.kernel.util.ArrayUtil;
029    import com.liferay.portal.kernel.util.CharPool;
030    import com.liferay.portal.kernel.util.CookieKeys;
031    import com.liferay.portal.kernel.util.GetterUtil;
032    import com.liferay.portal.kernel.util.HtmlUtil;
033    import com.liferay.portal.kernel.util.JavaConstants;
034    import com.liferay.portal.kernel.util.LocaleUtil;
035    import com.liferay.portal.kernel.util.ObjectValuePair;
036    import com.liferay.portal.kernel.util.ParamUtil;
037    import com.liferay.portal.kernel.util.PropsKeys;
038    import com.liferay.portal.kernel.util.ResourceBundleUtil;
039    import com.liferay.portal.kernel.util.StringBundler;
040    import com.liferay.portal.kernel.util.StringPool;
041    import com.liferay.portal.kernel.util.StringUtil;
042    import com.liferay.portal.kernel.util.Time;
043    import com.liferay.portal.kernel.util.UnicodeProperties;
044    import com.liferay.portal.kernel.util.Validator;
045    import com.liferay.portal.model.CompanyConstants;
046    import com.liferay.portal.model.Group;
047    import com.liferay.portal.model.GroupConstants;
048    import com.liferay.portal.security.auth.CompanyThreadLocal;
049    import com.liferay.portal.service.GroupLocalServiceUtil;
050    import com.liferay.portal.theme.ThemeDisplay;
051    import com.liferay.portal.util.PortalUtil;
052    import com.liferay.portal.util.PrefsPropsUtil;
053    import com.liferay.portal.util.PropsValues;
054    import com.liferay.portal.util.WebKeys;
055    
056    import java.io.Serializable;
057    
058    import java.text.MessageFormat;
059    
060    import java.util.HashMap;
061    import java.util.HashSet;
062    import java.util.List;
063    import java.util.Locale;
064    import java.util.Map;
065    import java.util.ResourceBundle;
066    import java.util.Set;
067    import java.util.concurrent.ConcurrentHashMap;
068    import java.util.regex.Matcher;
069    import java.util.regex.Pattern;
070    
071    import javax.portlet.PortletConfig;
072    import javax.portlet.PortletRequest;
073    
074    import javax.servlet.http.Cookie;
075    import javax.servlet.http.HttpServletRequest;
076    import javax.servlet.http.HttpServletResponse;
077    
078    /**
079     * @author Brian Wing Shun Chan
080     * @author Andrius Vitkauskas
081     * @author Eduardo Lundgren
082     */
083    @DoPrivileged
084    public class LanguageImpl implements Language, Serializable {
085    
086            @Override
087            public String format(
088                    HttpServletRequest request, String pattern, LanguageWrapper argument) {
089    
090                    return format(request, pattern, new LanguageWrapper[] {argument}, true);
091            }
092    
093            @Override
094            public String format(
095                    HttpServletRequest request, String pattern, LanguageWrapper argument,
096                    boolean translateArguments) {
097    
098                    return format(
099                            request, pattern, new LanguageWrapper[] {argument},
100                            translateArguments);
101            }
102    
103            @Override
104            public String format(
105                    HttpServletRequest request, String pattern,
106                    LanguageWrapper[] arguments) {
107    
108                    return format(request, pattern, arguments, true);
109            }
110    
111            @Override
112            public String format(
113                    HttpServletRequest request, String pattern, LanguageWrapper[] arguments,
114                    boolean translateArguments) {
115    
116                    if (PropsValues.TRANSLATIONS_DISABLED) {
117                            return pattern;
118                    }
119    
120                    String value = null;
121    
122                    try {
123                            pattern = get(request, pattern);
124    
125                            if (ArrayUtil.isNotEmpty(arguments)) {
126                                    pattern = _escapePattern(pattern);
127    
128                                    Object[] formattedArguments = new Object[arguments.length];
129    
130                                    for (int i = 0; i < arguments.length; i++) {
131                                            if (translateArguments) {
132                                                    formattedArguments[i] =
133                                                            arguments[i].getBefore() +
134                                                            get(request, arguments[i].getText()) +
135                                                            arguments[i].getAfter();
136                                            }
137                                            else {
138                                                    formattedArguments[i] =
139                                                            arguments[i].getBefore() +
140                                                            arguments[i].getText() +
141                                                            arguments[i].getAfter();
142                                            }
143                                    }
144    
145                                    value = MessageFormat.format(pattern, formattedArguments);
146                            }
147                            else {
148                                    value = pattern;
149                            }
150                    }
151                    catch (Exception e) {
152                            if (_log.isWarnEnabled()) {
153                                    _log.warn(e, e);
154                            }
155                    }
156    
157                    return value;
158            }
159    
160            @Override
161            public String format(
162                    HttpServletRequest request, String pattern, Object argument) {
163    
164                    return format(request, pattern, new Object[] {argument}, true);
165            }
166    
167            @Override
168            public String format(
169                    HttpServletRequest request, String pattern, Object argument,
170                    boolean translateArguments) {
171    
172                    return format(
173                            request, pattern, new Object[] {argument}, translateArguments);
174            }
175    
176            @Override
177            public String format(
178                    HttpServletRequest request, String pattern, Object[] arguments) {
179    
180                    return format(request, pattern, arguments, true);
181            }
182    
183            @Override
184            public String format(
185                    HttpServletRequest request, String pattern, Object[] arguments,
186                    boolean translateArguments) {
187    
188                    if (PropsValues.TRANSLATIONS_DISABLED) {
189                            return pattern;
190                    }
191    
192                    String value = null;
193    
194                    try {
195                            pattern = get(request, pattern);
196    
197                            if (ArrayUtil.isNotEmpty(arguments)) {
198                                    pattern = _escapePattern(pattern);
199    
200                                    Object[] formattedArguments = new Object[arguments.length];
201    
202                                    for (int i = 0; i < arguments.length; i++) {
203                                            if (translateArguments) {
204                                                    formattedArguments[i] = get(
205                                                            request, arguments[i].toString());
206                                            }
207                                            else {
208                                                    formattedArguments[i] = arguments[i];
209                                            }
210                                    }
211    
212                                    value = MessageFormat.format(pattern, formattedArguments);
213                            }
214                            else {
215                                    value = pattern;
216                            }
217                    }
218                    catch (Exception e) {
219                            if (_log.isWarnEnabled()) {
220                                    _log.warn(e, e);
221                            }
222                    }
223    
224                    return value;
225            }
226    
227            @Override
228            public String format(
229                    Locale locale, String pattern, List<Object> arguments) {
230    
231                    return format(locale, pattern, arguments.toArray(), true);
232            }
233    
234            @Override
235            public String format(Locale locale, String pattern, Object argument) {
236                    return format(locale, pattern, new Object[] {argument}, true);
237            }
238    
239            @Override
240            public String format(
241                    Locale locale, String pattern, Object argument,
242                    boolean translateArguments) {
243    
244                    return format(
245                            locale, pattern, new Object[] {argument}, translateArguments);
246            }
247    
248            @Override
249            public String format(Locale locale, String pattern, Object[] arguments) {
250                    return format(locale, pattern, arguments, true);
251            }
252    
253            @Override
254            public String format(
255                    Locale locale, String pattern, Object[] arguments,
256                    boolean translateArguments) {
257    
258                    if (PropsValues.TRANSLATIONS_DISABLED) {
259                            return pattern;
260                    }
261    
262                    String value = null;
263    
264                    try {
265                            pattern = get(locale, pattern);
266    
267                            if (ArrayUtil.isNotEmpty(arguments)) {
268                                    pattern = _escapePattern(pattern);
269    
270                                    Object[] formattedArguments = new Object[arguments.length];
271    
272                                    for (int i = 0; i < arguments.length; i++) {
273                                            if (translateArguments) {
274                                                    formattedArguments[i] = get(
275                                                            locale, arguments[i].toString());
276                                            }
277                                            else {
278                                                    formattedArguments[i] = arguments[i];
279                                            }
280                                    }
281    
282                                    value = MessageFormat.format(pattern, formattedArguments);
283                            }
284                            else {
285                                    value = pattern;
286                            }
287                    }
288                    catch (Exception e) {
289                            if (_log.isWarnEnabled()) {
290                                    _log.warn(e, e);
291                            }
292                    }
293    
294                    return value;
295            }
296    
297            @Override
298            public String format(
299                    ResourceBundle resourceBundle, String pattern, Object argument) {
300    
301                    return format(resourceBundle, pattern, new Object[] {argument}, true);
302            }
303    
304            @Override
305            public String format(
306                    ResourceBundle resourceBundle, String pattern, Object argument,
307                    boolean translateArguments) {
308    
309                    return format(
310                            resourceBundle, pattern, new Object[] {argument},
311                            translateArguments);
312            }
313    
314            @Override
315            public String format(
316                    ResourceBundle resourceBundle, String pattern, Object[] arguments) {
317    
318                    return format(resourceBundle, pattern, arguments, true);
319            }
320    
321            @Override
322            public String format(
323                    ResourceBundle resourceBundle, String pattern, Object[] arguments,
324                    boolean translateArguments) {
325    
326                    if (PropsValues.TRANSLATIONS_DISABLED) {
327                            return pattern;
328                    }
329    
330                    String value = null;
331    
332                    try {
333                            pattern = get(resourceBundle, pattern);
334    
335                            if (ArrayUtil.isNotEmpty(arguments)) {
336                                    pattern = _escapePattern(pattern);
337    
338                                    Object[] formattedArguments = new Object[arguments.length];
339    
340                                    for (int i = 0; i < arguments.length; i++) {
341                                            if (translateArguments) {
342                                                    formattedArguments[i] = get(
343                                                            resourceBundle, arguments[i].toString());
344                                            }
345                                            else {
346                                                    formattedArguments[i] = arguments[i];
347                                            }
348                                    }
349    
350                                    value = MessageFormat.format(pattern, formattedArguments);
351                            }
352                            else {
353                                    value = pattern;
354                            }
355                    }
356                    catch (Exception e) {
357                            if (_log.isWarnEnabled()) {
358                                    _log.warn(e, e);
359                            }
360                    }
361    
362                    return value;
363            }
364    
365            @Override
366            public String get(
367                    HttpServletRequest request, ResourceBundle resourceBundle, String key) {
368    
369                    return get(request, resourceBundle, key, key);
370            }
371    
372            @Override
373            public String get(
374                    HttpServletRequest request, ResourceBundle resourceBundle, String key,
375                    String defaultValue) {
376    
377                    String value = _get(resourceBundle, key);
378    
379                    if (value != null) {
380                            return value;
381                    }
382    
383                    return get(request, key, defaultValue);
384            }
385    
386            @Override
387            public String get(HttpServletRequest request, String key) {
388                    return get(request, key, key);
389            }
390    
391            @Override
392            public String get(
393                    HttpServletRequest request, String key, String defaultValue) {
394    
395                    if ((request == null) || (key == null)) {
396                            return defaultValue;
397                    }
398    
399                    PortletConfig portletConfig = (PortletConfig)request.getAttribute(
400                            JavaConstants.JAVAX_PORTLET_CONFIG);
401    
402                    Locale locale = _getLocale(request);
403    
404                    if (portletConfig == null) {
405                            return get(locale, key, defaultValue);
406                    }
407    
408                    ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
409    
410                    if (resourceBundle.containsKey(key)) {
411                            return _get(resourceBundle, key);
412                    }
413    
414                    return get(locale, key, defaultValue);
415            }
416    
417            @Override
418            public String get(Locale locale, String key) {
419                    return get(locale, key, key);
420            }
421    
422            @Override
423            public String get(Locale locale, String key, String defaultValue) {
424                    if (PropsValues.TRANSLATIONS_DISABLED) {
425                            return key;
426                    }
427    
428                    if ((locale == null) || (key == null)) {
429                            return defaultValue;
430                    }
431    
432                    String value = LanguageResources.getMessage(locale, key);
433    
434                    if (value != null) {
435                            return LanguageResources.fixValue(value);
436                    }
437    
438                    if (value == null) {
439                            if ((key.length() > 0) &&
440                                    (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
441    
442                                    int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
443    
444                                    if (pos != -1) {
445                                            key = key.substring(0, pos);
446    
447                                            return get(locale, key, defaultValue);
448                                    }
449                            }
450                    }
451    
452                    return defaultValue;
453            }
454    
455            @Override
456            public String get(ResourceBundle resourceBundle, String key) {
457                    return get(resourceBundle, key, key);
458            }
459    
460            @Override
461            public String get(
462                    ResourceBundle resourceBundle, String key, String defaultValue) {
463    
464                    String value = _get(resourceBundle, key);
465    
466                    if (value != null) {
467                            return value;
468                    }
469    
470                    return defaultValue;
471            }
472    
473            @Override
474            public Set<Locale> getAvailableLocales() {
475                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
476    
477                    return companyLocalesBag.getAvailableLocales();
478            }
479    
480            @Override
481            public Set<Locale> getAvailableLocales(long groupId) {
482                    if (groupId <= 0) {
483                            return getAvailableLocales();
484                    }
485    
486                    try {
487                            if (isInheritLocales(groupId)) {
488                                    return getAvailableLocales();
489                            }
490                    }
491                    catch (Exception e) {
492                    }
493    
494                    Map<String, Locale> groupLanguageIdLocalesMap =
495                            _getGroupLanguageIdLocalesMap(groupId);
496    
497                    return new HashSet<>(groupLanguageIdLocalesMap.values());
498            }
499    
500            @Override
501            public String getBCP47LanguageId(HttpServletRequest request) {
502                    Locale locale = PortalUtil.getLocale(request);
503    
504                    return getBCP47LanguageId(locale);
505            }
506    
507            @Override
508            public String getBCP47LanguageId(Locale locale) {
509                    return LocaleUtil.toBCP47LanguageId(locale);
510            }
511    
512            @Override
513            public String getBCP47LanguageId(PortletRequest portletRequest) {
514                    Locale locale = PortalUtil.getLocale(portletRequest);
515    
516                    return getBCP47LanguageId(locale);
517            }
518    
519            @Override
520            public String getLanguageId(HttpServletRequest request) {
521                    String languageId = ParamUtil.getString(request, "languageId");
522    
523                    if (Validator.isNotNull(languageId)) {
524                            CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
525    
526                            if (companyLocalesBag.containsLanguageCode(languageId) ||
527                                    companyLocalesBag.containsLanguageId(languageId)) {
528    
529                                    return languageId;
530                            }
531                    }
532    
533                    Locale locale = PortalUtil.getLocale(request);
534    
535                    return getLanguageId(locale);
536            }
537    
538            @Override
539            public String getLanguageId(Locale locale) {
540                    return LocaleUtil.toLanguageId(locale);
541            }
542    
543            @Override
544            public String getLanguageId(PortletRequest portletRequest) {
545                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
546                            portletRequest);
547    
548                    return getLanguageId(request);
549            }
550    
551            @Override
552            public Locale getLocale(long groupId, String languageCode) {
553                    Map<String, Locale> groupLanguageCodeLocalesMap =
554                            _getGroupLanguageCodeLocalesMap(groupId);
555    
556                    return groupLanguageCodeLocalesMap.get(languageCode);
557            }
558    
559            @Override
560            public Locale getLocale(String languageCode) {
561                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
562    
563                    return companyLocalesBag.getByLanguageCode(languageCode);
564            }
565    
566            @Override
567            public Set<Locale> getSupportedLocales() {
568                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
569    
570                    return companyLocalesBag._supportedLocalesSet;
571            }
572    
573            @Override
574            public String getTimeDescription(
575                    HttpServletRequest request, long milliseconds) {
576    
577                    return getTimeDescription(request, milliseconds, false);
578            }
579    
580            @Override
581            public String getTimeDescription(
582                    HttpServletRequest request, long milliseconds, boolean approximate) {
583    
584                    String description = Time.getDescription(milliseconds, approximate);
585    
586                    String value = null;
587    
588                    try {
589                            int pos = description.indexOf(CharPool.SPACE);
590    
591                            String x = description.substring(0, pos);
592    
593                            value = x.concat(StringPool.SPACE).concat(
594                                    get(
595                                            request,
596                                            StringUtil.toLowerCase(
597                                                    description.substring(pos + 1, description.length()))));
598                    }
599                    catch (Exception e) {
600                            if (_log.isWarnEnabled()) {
601                                    _log.warn(e, e);
602                            }
603                    }
604    
605                    return value;
606            }
607    
608            @Override
609            public String getTimeDescription(
610                    HttpServletRequest request, Long milliseconds) {
611    
612                    return getTimeDescription(request, milliseconds.longValue());
613            }
614    
615            @Override
616            public String getTimeDescription(Locale locale, long milliseconds) {
617                    return getTimeDescription(locale, milliseconds, false);
618            }
619    
620            @Override
621            public String getTimeDescription(
622                    Locale locale, long milliseconds, boolean approximate) {
623    
624                    String description = Time.getDescription(milliseconds, approximate);
625    
626                    String value = null;
627    
628                    try {
629                            int pos = description.indexOf(CharPool.SPACE);
630    
631                            String x = description.substring(0, pos);
632    
633                            value = x.concat(StringPool.SPACE).concat(
634                                    get(
635                                            locale,
636                                            StringUtil.toLowerCase(
637                                                    description.substring(pos + 1, description.length()))));
638                    }
639                    catch (Exception e) {
640                            if (_log.isWarnEnabled()) {
641                                    _log.warn(e, e);
642                            }
643                    }
644    
645                    return value;
646            }
647    
648            @Override
649            public String getTimeDescription(Locale locale, Long milliseconds) {
650                    return getTimeDescription(locale, milliseconds.longValue());
651            }
652    
653            @Override
654            public void init() {
655                    _companyLocalesBags.clear();
656            }
657    
658            @Override
659            public boolean isAvailableLanguageCode(String languageCode) {
660                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
661    
662                    return companyLocalesBag.containsLanguageCode(languageCode);
663            }
664    
665            @Override
666            public boolean isAvailableLocale(Locale locale) {
667                    return isAvailableLocale(LocaleUtil.toLanguageId(locale));
668            }
669    
670            @Override
671            public boolean isAvailableLocale(long groupId, Locale locale) {
672                    return isAvailableLocale(groupId, LocaleUtil.toLanguageId(locale));
673            }
674    
675            @Override
676            public boolean isAvailableLocale(long groupId, String languageId) {
677                    if (groupId <= 0) {
678                            return isAvailableLocale(languageId);
679                    }
680    
681                    try {
682                            if (isInheritLocales(groupId)) {
683                                    return isAvailableLocale(languageId);
684                            }
685                    }
686                    catch (Exception e) {
687                    }
688    
689                    Map<String, Locale> groupLanguageIdLocalesMap =
690                            _getGroupLanguageIdLocalesMap(groupId);
691    
692                    return groupLanguageIdLocalesMap.containsKey(languageId);
693            }
694    
695            @Override
696            public boolean isAvailableLocale(String languageId) {
697                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
698    
699                    return companyLocalesBag.containsLanguageId(languageId);
700            }
701    
702            @Override
703            public boolean isBetaLocale(Locale locale) {
704                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
705    
706                    return companyLocalesBag.isBetaLocale(locale);
707            }
708    
709            @Override
710            public boolean isDuplicateLanguageCode(String languageCode) {
711                    CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag();
712    
713                    return companyLocalesBag.isDuplicateLanguageCode(languageCode);
714            }
715    
716            @Override
717            public boolean isInheritLocales(long groupId) throws PortalException {
718                    Group group = GroupLocalServiceUtil.getGroup(groupId);
719    
720                    if (group.isStagingGroup()) {
721                            group = group.getLiveGroup();
722                    }
723    
724                    if (!group.isSite() || group.isCompany()) {
725                            return true;
726                    }
727    
728                    return GetterUtil.getBoolean(
729                            group.getTypeSettingsProperty(
730                                    GroupConstants.TYPE_SETTINGS_KEY_INHERIT_LOCALES),
731                            true);
732            }
733    
734            @Override
735            public String process(
736                    ResourceBundle resourceBundle, Locale locale, String content) {
737    
738                    StringBundler sb = new StringBundler();
739    
740                    Matcher matcher = _pattern.matcher(content);
741    
742                    int x = 0;
743    
744                    while (matcher.find()) {
745                            int y = matcher.start(0);
746    
747                            String key = matcher.group(1);
748    
749                            sb.append(content.substring(x, y));
750                            sb.append(StringPool.APOSTROPHE);
751    
752                            String value = get(resourceBundle, key);
753    
754                            sb.append(HtmlUtil.escapeJS(value));
755                            sb.append(StringPool.APOSTROPHE);
756    
757                            x = matcher.end(0);
758                    }
759    
760                    sb.append(content.substring(x));
761    
762                    return sb.toString();
763            }
764    
765            @Override
766            public void resetAvailableGroupLocales(long groupId) {
767                    _resetAvailableGroupLocales(groupId);
768            }
769    
770            @Override
771            public void resetAvailableLocales(long companyId) {
772                    _resetAvailableLocales(companyId);
773            }
774    
775            @Override
776            public void updateCookie(
777                    HttpServletRequest request, HttpServletResponse response,
778                    Locale locale) {
779    
780                    String languageId = LocaleUtil.toLanguageId(locale);
781    
782                    Cookie languageIdCookie = new Cookie(
783                            CookieKeys.GUEST_LANGUAGE_ID, languageId);
784    
785                    languageIdCookie.setPath(StringPool.SLASH);
786                    languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
787    
788                    CookieKeys.addCookie(request, response, languageIdCookie);
789            }
790    
791            private static CompanyLocalesBag _getCompanyLocalesBag() {
792                    Long companyId = CompanyThreadLocal.getCompanyId();
793    
794                    CompanyLocalesBag companyLocalesBag = _companyLocalesBags.get(
795                            companyId);
796    
797                    if (companyLocalesBag == null) {
798                            companyLocalesBag = new CompanyLocalesBag(companyId);
799    
800                            _companyLocalesBags.put(companyId, companyLocalesBag);
801                    }
802    
803                    return companyLocalesBag;
804            }
805    
806            private ObjectValuePair<Map<String, Locale>, Map<String, Locale>>
807                    _createGroupLocales(long groupId) {
808    
809                    String[] languageIds = PropsValues.LOCALES_ENABLED;
810    
811                    try {
812                            Group group = GroupLocalServiceUtil.getGroup(groupId);
813    
814                            UnicodeProperties typeSettingsProperties =
815                                    group.getTypeSettingsProperties();
816    
817                            languageIds = StringUtil.split(
818                                    typeSettingsProperties.getProperty(PropsKeys.LOCALES));
819                    }
820                    catch (Exception e) {
821                    }
822    
823                    Map<String, Locale> groupLanguageCodeLocalesMap = new HashMap<>();
824                    Map<String, Locale> groupLanguageIdLocalesMap = new HashMap<>();
825    
826                    for (String languageId : languageIds) {
827                            Locale locale = LocaleUtil.fromLanguageId(languageId, false);
828    
829                            String languageCode = languageId;
830    
831                            int pos = languageId.indexOf(CharPool.UNDERLINE);
832    
833                            if (pos > 0) {
834                                    languageCode = languageId.substring(0, pos);
835                            }
836    
837                            if (!groupLanguageCodeLocalesMap.containsKey(languageCode)) {
838                                    groupLanguageCodeLocalesMap.put(languageCode, locale);
839                            }
840    
841                            groupLanguageIdLocalesMap.put(languageId, locale);
842                    }
843    
844                    _groupLanguageCodeLocalesMapMap.put(
845                            groupId, groupLanguageCodeLocalesMap);
846                    _groupLanguageIdLocalesMap.put(groupId, groupLanguageIdLocalesMap);
847    
848                    return new ObjectValuePair<>(
849                            groupLanguageCodeLocalesMap, groupLanguageIdLocalesMap);
850            }
851    
852            private String _escapePattern(String pattern) {
853                    return StringUtil.replace(
854                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
855            }
856    
857            private String _get(ResourceBundle resourceBundle, String key) {
858                    if (PropsValues.TRANSLATIONS_DISABLED) {
859                            return key;
860                    }
861    
862                    if ((resourceBundle == null) || (key == null)) {
863                            return null;
864                    }
865    
866                    String value = ResourceBundleUtil.getString(resourceBundle, key);
867    
868                    if (value != null) {
869                            return LanguageResources.fixValue(value);
870                    }
871    
872                    if ((key.length() > 0) &&
873                            (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
874    
875                            int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
876    
877                            if (pos != -1) {
878                                    key = key.substring(0, pos);
879    
880                                    return _get(resourceBundle, key);
881                            }
882                    }
883    
884                    return null;
885            }
886    
887            private Map<String, Locale> _getGroupLanguageCodeLocalesMap(long groupId) {
888                    Map<String, Locale> groupLanguageCodeLocalesMap =
889                            _groupLanguageCodeLocalesMapMap.get(groupId);
890    
891                    if (groupLanguageCodeLocalesMap == null) {
892                            ObjectValuePair<Map<String, Locale>, Map<String, Locale>>
893                                    objectValuePair = _createGroupLocales(groupId);
894    
895                            groupLanguageCodeLocalesMap = objectValuePair.getKey();
896                    }
897    
898                    return groupLanguageCodeLocalesMap;
899            }
900    
901            private Map<String, Locale> _getGroupLanguageIdLocalesMap(long groupId) {
902                    Map<String, Locale> groupLanguageIdLocalesMap =
903                            _groupLanguageIdLocalesMap.get(groupId);
904    
905                    if (groupLanguageIdLocalesMap == null) {
906                            ObjectValuePair<Map<String, Locale>, Map<String, Locale>>
907                                    objectValuePair = _createGroupLocales(groupId);
908    
909                            groupLanguageIdLocalesMap = objectValuePair.getValue();
910                    }
911    
912                    return groupLanguageIdLocalesMap;
913            }
914    
915            private Locale _getLocale(HttpServletRequest request) {
916                    Locale locale = null;
917    
918                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
919                            WebKeys.THEME_DISPLAY);
920    
921                    if (themeDisplay != null) {
922                            locale = themeDisplay.getLocale();
923                    }
924                    else {
925                            locale = request.getLocale();
926    
927                            if (!isAvailableLocale(locale)) {
928                                    locale = LocaleUtil.getDefault();
929                            }
930                    }
931    
932                    return locale;
933            }
934    
935            private void _resetAvailableGroupLocales(long groupId) {
936                    _groupLanguageCodeLocalesMapMap.remove(groupId);
937                    _groupLanguageIdLocalesMap.remove(groupId);
938            }
939    
940            private void _resetAvailableLocales(long companyId) {
941                    _portalCache.remove(companyId);
942            }
943    
944            private static final Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
945    
946            private static final Map<Long, CompanyLocalesBag> _companyLocalesBags =
947                    new ConcurrentHashMap<>();
948            private static final Pattern _pattern = Pattern.compile(
949                    "Liferay\\.Language\\.get\\([\"']([^)]+)[\"']\\)");
950            private static final PortalCache<Long, Serializable> _portalCache =
951                    MultiVMPoolUtil.getCache(LanguageImpl.class.getName());
952    
953            static {
954                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
955                            _portalCache, _companyLocalesBags,
956                            new Synchronizer<Long, Serializable>() {
957    
958                                    @Override
959                                    public void onSynchronize(
960                                            Map<? extends Long, ? extends Serializable> map, Long key,
961                                            Serializable value, int timeToLive) {
962    
963                                            _companyLocalesBags.remove(key);
964                                    }
965    
966                            });
967            }
968    
969            private final Map<Long, Map<String, Locale>>
970                    _groupLanguageCodeLocalesMapMap = new ConcurrentHashMap<>();
971            private final Map<Long, Map<String, Locale>> _groupLanguageIdLocalesMap =
972                    new ConcurrentHashMap<>();
973    
974            private static class CompanyLocalesBag implements Serializable {
975    
976                    public boolean containsLanguageCode(String languageCode) {
977                            return _languageCodeLocalesMap.containsKey(languageCode);
978                    }
979    
980                    public boolean containsLanguageId(String languageId) {
981                            return _languageIdLocalesMap.containsKey(languageId);
982                    }
983    
984                    public Set<Locale> getAvailableLocales() {
985                            return new HashSet<>(_languageIdLocalesMap.values());
986                    }
987    
988                    public Locale getByLanguageCode(String languageCode) {
989                            return _languageCodeLocalesMap.get(languageCode);
990                    }
991    
992                    public boolean isBetaLocale(Locale locale) {
993                            return _localesBetaSet.contains(locale);
994                    }
995    
996                    public boolean isDuplicateLanguageCode(String languageCode) {
997                            return _duplicateLanguageCodes.contains(languageCode);
998                    }
999    
1000                    private CompanyLocalesBag(long companyId) {
1001                            String[] languageIds = PropsValues.LOCALES;
1002    
1003                            if (companyId != CompanyConstants.SYSTEM) {
1004                                    try {
1005                                            languageIds = PrefsPropsUtil.getStringArray(
1006                                                    companyId, PropsKeys.LOCALES, StringPool.COMMA,
1007                                                    PropsValues.LOCALES_ENABLED);
1008                                    }
1009                                    catch (SystemException se) {
1010                                            languageIds = PropsValues.LOCALES_ENABLED;
1011                                    }
1012                            }
1013    
1014                            for (String languageId : languageIds) {
1015                                    Locale locale = LocaleUtil.fromLanguageId(languageId, false);
1016    
1017                                    String languageCode = languageId;
1018    
1019                                    int pos = languageId.indexOf(CharPool.UNDERLINE);
1020    
1021                                    if (pos > 0) {
1022                                            languageCode = languageId.substring(0, pos);
1023                                    }
1024    
1025                                    if (_languageCodeLocalesMap.containsKey(languageCode)) {
1026                                            _duplicateLanguageCodes.add(languageCode);
1027                                    }
1028                                    else {
1029                                            _languageCodeLocalesMap.put(languageCode, locale);
1030                                    }
1031    
1032                                    _languageIdLocalesMap.put(languageId, locale);
1033                            }
1034    
1035                            for (String languageId : PropsValues.LOCALES_BETA) {
1036                                    _localesBetaSet.add(
1037                                            LocaleUtil.fromLanguageId(languageId, false));
1038                            }
1039    
1040                            _supportedLocalesSet = new HashSet<>(
1041                                    _languageIdLocalesMap.values());
1042    
1043                            _supportedLocalesSet.removeAll(_localesBetaSet);
1044                    }
1045    
1046                    private final Set<String> _duplicateLanguageCodes = new HashSet<>();
1047                    private final Map<String, Locale> _languageCodeLocalesMap =
1048                            new HashMap<>();
1049                    private final Map<String, Locale> _languageIdLocalesMap =
1050                            new HashMap<>();
1051                    private final Set<Locale> _localesBetaSet = new HashSet<>();
1052                    private final Set<Locale> _supportedLocalesSet;
1053    
1054            }
1055    
1056    }