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