001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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_IN_SECONDS);
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                    _synchronizeGroupLocalesPortalCache();
844            }
845    
846            private String _escapePattern(String pattern) {
847                    return StringUtil.replace(
848                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
849            }
850    
851            private String _get(
852                            PageContext pageContext, PortletConfig portletConfig, Locale locale,
853                            String key, String defaultValue)
854                    throws Exception {
855    
856                    if (PropsValues.TRANSLATIONS_DISABLED) {
857                            return key;
858                    }
859    
860                    if (key == null) {
861                            return null;
862                    }
863    
864                    String value = null;
865    
866                    if (pageContext != null) {
867                            HttpServletRequest request =
868                                    (HttpServletRequest)pageContext.getRequest();
869    
870                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
871                                    WebKeys.THEME_DISPLAY);
872    
873                            if (themeDisplay != null) {
874                                    locale = themeDisplay.getLocale();
875                            }
876                            else {
877                                    locale = request.getLocale();
878    
879                                    if (!isAvailableLocale(locale)) {
880                                            locale = LocaleUtil.getDefault();
881                                    }
882                            }
883    
884                            portletConfig = (PortletConfig)request.getAttribute(
885                                    JavaConstants.JAVAX_PORTLET_CONFIG);
886                    }
887    
888                    if (portletConfig != null) {
889                            ResourceBundle resourceBundle = portletConfig.getResourceBundle(
890                                    locale);
891    
892                            value = ResourceBundleUtil.getString(resourceBundle, key);
893    
894                            // LEP-7393
895    
896                            String portletName = portletConfig.getPortletName();
897    
898                            if (((value == null) || value.equals(defaultValue)) &&
899                                    portletName.equals(PortletKeys.PORTLET_CONFIGURATION)) {
900    
901                                    value = _getPortletConfigurationValue(pageContext, locale, key);
902                            }
903    
904                            if (value != null) {
905                                    value = LanguageResources.fixValue(value);
906                            }
907                    }
908    
909                    if ((value == null) || value.equals(defaultValue)) {
910                            value = LanguageResources.getMessage(locale, key);
911                    }
912    
913                    if ((value == null) || value.equals(defaultValue)) {
914                            if ((key.length() > 0) &&
915                                    (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
916    
917                                    int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
918    
919                                    if (pos != -1) {
920                                            key = key.substring(0, pos);
921    
922                                            return _get(
923                                                    pageContext, portletConfig, locale, key, defaultValue);
924                                    }
925                            }
926                    }
927    
928                    if ((value == null) || value.equals(key)) {
929                            value = defaultValue;
930                    }
931    
932                    return value;
933            }
934    
935            private String _getCharset(Locale locale) {
936                    return StringPool.UTF8;
937            }
938    
939            private Locale _getLocale(long groupId, String languageCode) {
940                    Map<String, Locale> localesMap = _groupLanguageCodeLocalesMap.get(
941                            groupId);
942    
943                    if (localesMap == null) {
944                            _initGroupLocales(groupId);
945    
946                            localesMap = _groupLanguageCodeLocalesMap.get(groupId);
947                    }
948    
949                    return localesMap.get(languageCode);
950            }
951    
952            private Locale _getLocale(String languageCode) {
953                    return _localesMap.get(languageCode);
954            }
955    
956            private String _getPortletConfigurationValue(
957                            PageContext pageContext, Locale locale, String key)
958                    throws Exception {
959    
960                    if (PropsValues.TRANSLATIONS_DISABLED) {
961                            return key;
962                    }
963    
964                    HttpServletRequest request =
965                            (HttpServletRequest)pageContext.getRequest();
966    
967                    String portletResource = ParamUtil.getString(
968                            request, "portletResource");
969    
970                    long companyId = PortalUtil.getCompanyId(request);
971    
972                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
973                            companyId, portletResource);
974    
975                    PortletConfig portletConfig = PortletConfigFactoryUtil.create(
976                            portlet, pageContext.getServletContext());
977    
978                    ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
979    
980                    return ResourceBundleUtil.getString(resourceBundle, key);
981            }
982    
983            private void _initGroupLocales(long groupId) {
984                    String[] languageIds = null;
985    
986                    try {
987                            Group group = GroupLocalServiceUtil.getGroup(groupId);
988    
989                            UnicodeProperties typeSettingsProperties =
990                                    group.getTypeSettingsProperties();
991    
992                            languageIds = StringUtil.split(
993                                    typeSettingsProperties.getProperty(PropsKeys.LOCALES));
994                    }
995                    catch (Exception e) {
996                            languageIds = PropsValues.LOCALES_ENABLED;
997                    }
998    
999                    Locale[] locales = new Locale[languageIds.length];
1000                    HashMap<String, Locale> localesMap = new HashMap<String, Locale>(
1001                            languageIds.length);
1002                    HashSet<Locale> localesSet = new HashSet<Locale>(languageIds.length);
1003    
1004                    for (int i = 0; i < languageIds.length; i++) {
1005                            String languageId = languageIds[i];
1006    
1007                            Locale locale = LocaleUtil.fromLanguageId(languageId, false);
1008    
1009                            String language = languageId;
1010    
1011                            int pos = languageId.indexOf(CharPool.UNDERLINE);
1012    
1013                            if (pos > 0) {
1014                                    language = languageId.substring(0, pos);
1015                            }
1016    
1017                            locales[i] = locale;
1018    
1019                            if (!localesMap.containsKey(language)) {
1020                                    localesMap.put(language, locale);
1021                            }
1022    
1023                            localesSet.add(locale);
1024                    }
1025    
1026                    _groupLanguageCodeLocalesMap.put(groupId, localesMap);
1027                    _groupLocalesMap.put(groupId, locales);
1028                    _groupLocalesSet.put(groupId, localesSet);
1029            }
1030    
1031            private void _resetAvailableGroupLocales(long groupId) {
1032                    _groupLocalesPortalCache.remove(groupId);
1033            }
1034    
1035            private void _resetAvailableLocales(long companyId) {
1036                    _companyLocalesPortalCache.remove(companyId);
1037            }
1038    
1039            private void _synchronizeGroupLocalesPortalCache() {
1040                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
1041                            _groupLocalesPortalCache, _groupLanguageCodeLocalesMap,
1042                            _removeSynchronizer);
1043    
1044                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
1045                            _groupLocalesPortalCache, _groupLocalesMap, _removeSynchronizer);
1046    
1047                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
1048                            _groupLocalesPortalCache, _groupLocalesSet, _removeSynchronizer);
1049            }
1050    
1051            private static final String _COMPANY_LOCALES_PORTAL_CACHE_NAME =
1052                    LanguageImpl.class.getName() + "._companyLocalesPortalCache";
1053    
1054            private static final String _GROUP_LOCALES_PORTAL_CACHE_NAME =
1055                    LanguageImpl.class.getName() + "._groupLocalesPortalCache";
1056    
1057            private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
1058    
1059            private static PortalCache<Long, Serializable> _companyLocalesPortalCache =
1060                    MultiVMPoolUtil.getCache(_COMPANY_LOCALES_PORTAL_CACHE_NAME);
1061    
1062            private static PortalCache<Long, Serializable> _groupLocalesPortalCache =
1063                    MultiVMPoolUtil.getCache(_GROUP_LOCALES_PORTAL_CACHE_NAME);
1064    
1065            private static Map<Long, LanguageImpl> _instances =
1066                    new ConcurrentHashMap<Long, LanguageImpl>();
1067    
1068            private static final Synchronizer<Long, Serializable> _removeSynchronizer =
1069                    new Synchronizer<Long, Serializable>() {
1070    
1071                    @Override
1072                    public void onSynchronize(
1073                            Map<? extends Long, ? extends Serializable> map, Long key,
1074                            Serializable value) {
1075    
1076                            map.remove(key);
1077                    }
1078    
1079            };
1080    
1081            static {
1082                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
1083                            _companyLocalesPortalCache, _instances, _removeSynchronizer);
1084            }
1085    
1086            private Map<String, String> _charEncodings;
1087            private Set<String> _duplicateLanguageCodes;
1088            private final Map<Long, HashMap<String, Locale>>
1089                    _groupLanguageCodeLocalesMap =
1090                    new HashMap<Long, HashMap<String, Locale>>();
1091            private Map<Long, Locale[]> _groupLocalesMap =
1092                    new HashMap<Long, Locale[]>();
1093            private Map<Long, HashSet<Locale>> _groupLocalesSet =
1094                    new HashMap<Long, HashSet<Locale>>();
1095            private Locale[] _locales;
1096            private Set<Locale> _localesBetaSet;
1097            private Map<String, Locale> _localesMap;
1098            private Set<Locale> _localesSet;
1099    
1100    }