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(locale);
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                    UnicodeProperties groupTypeSettings =
724                            liveGroup.getTypeSettingsProperties();
725    
726                    return GetterUtil.getBoolean(
727                            groupTypeSettings.getProperty("inheritLocales"), true);
728            }
729    
730            @Override
731            public String process(
732                    ResourceBundle resourceBundle, Locale locale, String content) {
733    
734                    StringBundler sb = new StringBundler();
735    
736                    Matcher matcher = _pattern.matcher(content);
737    
738                    int x = 0;
739    
740                    while (matcher.find()) {
741                            int y = matcher.start(0);
742    
743                            String key = matcher.group(1);
744    
745                            sb.append(content.substring(x, y));
746                            sb.append(StringPool.APOSTROPHE);
747    
748                            String value = get(resourceBundle, key);
749    
750                            sb.append(HtmlUtil.escapeJS(value));
751                            sb.append(StringPool.APOSTROPHE);
752    
753                            x = matcher.end(0);
754                    }
755    
756                    sb.append(content.substring(x));
757    
758                    return sb.toString();
759            }
760    
761            @Override
762            public void resetAvailableGroupLocales(long groupId) {
763                    _resetAvailableGroupLocales(groupId);
764            }
765    
766            @Override
767            public void resetAvailableLocales(long companyId) {
768                    _resetAvailableLocales(companyId);
769            }
770    
771            @Override
772            public void updateCookie(
773                    HttpServletRequest request, HttpServletResponse response,
774                    Locale locale) {
775    
776                    String languageId = LocaleUtil.toLanguageId(locale);
777    
778                    Cookie languageIdCookie = new Cookie(
779                            CookieKeys.GUEST_LANGUAGE_ID, languageId);
780    
781                    languageIdCookie.setPath(StringPool.SLASH);
782                    languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
783    
784                    CookieKeys.addCookie(request, response, languageIdCookie);
785            }
786    
787            private static LanguageImpl _getInstance() {
788                    Long companyId = CompanyThreadLocal.getCompanyId();
789    
790                    LanguageImpl instance = _instances.get(companyId);
791    
792                    if (instance == null) {
793                            instance = new LanguageImpl(companyId);
794    
795                            _instances.put(companyId, instance);
796                    }
797    
798                    return instance;
799            }
800    
801            private LanguageImpl() {
802                    this(CompanyConstants.SYSTEM);
803            }
804    
805            private LanguageImpl(long companyId) {
806                    String[] languageIds = PropsValues.LOCALES;
807    
808                    if (companyId != CompanyConstants.SYSTEM) {
809                            try {
810                                    languageIds = PrefsPropsUtil.getStringArray(
811                                            companyId, PropsKeys.LOCALES, StringPool.COMMA,
812                                            PropsValues.LOCALES_ENABLED);
813                            }
814                            catch (SystemException se) {
815                                    languageIds = PropsValues.LOCALES_ENABLED;
816                            }
817                    }
818    
819                    _charEncodings = new HashMap<String, String>();
820                    _duplicateLanguageCodes = new HashSet<String>();
821                    _locales = new Locale[languageIds.length];
822                    _localesMap = new HashMap<String, Locale>(languageIds.length);
823                    _localesSet = new HashSet<Locale>(languageIds.length);
824    
825                    for (int i = 0; i < languageIds.length; i++) {
826                            String languageId = languageIds[i];
827    
828                            Locale locale = LocaleUtil.fromLanguageId(languageId, false);
829    
830                            _charEncodings.put(locale.toString(), StringPool.UTF8);
831    
832                            String language = languageId;
833    
834                            int pos = languageId.indexOf(CharPool.UNDERLINE);
835    
836                            if (pos > 0) {
837                                    language = languageId.substring(0, pos);
838                            }
839    
840                            if (_localesMap.containsKey(language)) {
841                                    _duplicateLanguageCodes.add(language);
842                            }
843    
844                            _locales[i] = locale;
845    
846                            if (!_localesMap.containsKey(language)) {
847                                    _localesMap.put(language, locale);
848                            }
849    
850                            _localesSet.add(locale);
851                    }
852    
853                    String[] localesBetaArray = PropsValues.LOCALES_BETA;
854    
855                    _localesBetaSet = new HashSet<Locale>(localesBetaArray.length);
856    
857                    for (String languageId : localesBetaArray) {
858                            Locale locale = LocaleUtil.fromLanguageId(languageId, false);
859    
860                            _localesBetaSet.add(locale);
861                    }
862            }
863    
864            private String _escapePattern(String pattern) {
865                    return StringUtil.replace(
866                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
867            }
868    
869            private String _get(ResourceBundle resourceBundle, String key) {
870                    if (PropsValues.TRANSLATIONS_DISABLED) {
871                            return key;
872                    }
873    
874                    if ((resourceBundle == null) || (key == null)) {
875                            return null;
876                    }
877    
878                    String value = ResourceBundleUtil.getString(resourceBundle, key);
879    
880                    if (value != null) {
881                            return LanguageResources.fixValue(value);
882                    }
883    
884                    if ((key.length() > 0) &&
885                            (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
886    
887                            int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
888    
889                            if (pos != -1) {
890                                    key = key.substring(0, pos);
891    
892                                    return _get(resourceBundle, key);
893                            }
894                    }
895    
896                    return null;
897            }
898    
899            private String _getCharset(Locale locale) {
900                    return StringPool.UTF8;
901            }
902    
903            private Locale _getLocale(HttpServletRequest request) {
904                    Locale locale = null;
905    
906                    ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
907                            WebKeys.THEME_DISPLAY);
908    
909                    if (themeDisplay != null) {
910                            locale = themeDisplay.getLocale();
911                    }
912                    else {
913                            locale = request.getLocale();
914    
915                            if (!isAvailableLocale(locale)) {
916                                    locale = LocaleUtil.getDefault();
917                            }
918                    }
919    
920                    return locale;
921            }
922    
923            private Locale _getLocale(String languageCode) {
924                    return _localesMap.get(languageCode);
925            }
926    
927            private void _initGroupLocales(long groupId) {
928                    String[] languageIds = null;
929    
930                    try {
931                            Group group = GroupLocalServiceUtil.getGroup(groupId);
932    
933                            UnicodeProperties typeSettingsProperties =
934                                    group.getTypeSettingsProperties();
935    
936                            languageIds = StringUtil.split(
937                                    typeSettingsProperties.getProperty(PropsKeys.LOCALES));
938                    }
939                    catch (Exception e) {
940                            languageIds = PropsValues.LOCALES_ENABLED;
941                    }
942    
943                    Locale[] locales = new Locale[languageIds.length];
944                    Map<String, Locale> localesMap = new HashMap<String, Locale>(
945                            languageIds.length);
946                    Set<Locale> localesSet = new HashSet<Locale>(languageIds.length);
947    
948                    for (int i = 0; i < languageIds.length; i++) {
949                            String languageId = languageIds[i];
950    
951                            Locale locale = LocaleUtil.fromLanguageId(languageId, false);
952    
953                            String language = languageId;
954    
955                            int pos = languageId.indexOf(CharPool.UNDERLINE);
956    
957                            if (pos > 0) {
958                                    language = languageId.substring(0, pos);
959                            }
960    
961                            locales[i] = locale;
962    
963                            if (!localesMap.containsKey(language)) {
964                                    localesMap.put(language, locale);
965                            }
966    
967                            localesSet.add(locale);
968                    }
969    
970                    _groupLocalesMap.put(groupId, locales);
971                    _groupLocalesSet.put(groupId, localesSet);
972            }
973    
974            private void _resetAvailableGroupLocales(long groupId) {
975                    _groupLocalesMap.remove(groupId);
976                    _groupLocalesSet.remove(groupId);
977            }
978    
979            private void _resetAvailableLocales(long companyId) {
980                    _portalCache.remove(companyId);
981            }
982    
983            private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
984    
985            private static Map<Long, LanguageImpl> _instances =
986                    new ConcurrentHashMap<Long, LanguageImpl>();
987            private static Pattern _pattern = Pattern.compile(
988                    "Liferay\\.Language\\.get\\([\"']([^)]+)[\"']\\)");
989            private static PortalCache<Long, Serializable> _portalCache =
990                    MultiVMPoolUtil.getCache(LanguageImpl.class.getName());
991    
992            static {
993                    PortalCacheMapSynchronizeUtil.<Long, Serializable>synchronize(
994                            _portalCache, _instances,
995                            new Synchronizer<Long, Serializable>() {
996    
997                                    @Override
998                                    public void onSynchronize(
999                                            Map<? extends Long, ? extends Serializable> map, Long key,
1000                                            Serializable value, int timeToLive) {
1001    
1002                                            _instances.remove(key);
1003                                    }
1004    
1005                            });
1006            }
1007    
1008            private Map<String, String> _charEncodings;
1009            private Set<String> _duplicateLanguageCodes;
1010            private Map<Long, Locale[]> _groupLocalesMap =
1011                    new HashMap<Long, Locale[]>();
1012            private Map<Long, Set<Locale>> _groupLocalesSet =
1013                    new HashMap<Long, Set<Locale>>();
1014            private Locale[] _locales;
1015            private Set<Locale> _localesBetaSet;
1016            private Map<String, Locale> _localesMap;
1017            private Set<Locale> _localesSet;
1018    
1019    }