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