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