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