001    /**
002     * Copyright (c) 2000-2010 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.exception.SystemException;
018    import com.liferay.portal.kernel.language.Language;
019    import com.liferay.portal.kernel.language.LanguageWrapper;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.GetterUtil;
024    import com.liferay.portal.kernel.util.JavaConstants;
025    import com.liferay.portal.kernel.util.LocaleUtil;
026    import com.liferay.portal.kernel.util.ParamUtil;
027    import com.liferay.portal.kernel.util.PropsKeys;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Time;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.model.CompanyConstants;
033    import com.liferay.portal.model.Portlet;
034    import com.liferay.portal.security.auth.CompanyThreadLocal;
035    import com.liferay.portal.service.PortletLocalServiceUtil;
036    import com.liferay.portal.theme.ThemeDisplay;
037    import com.liferay.portal.util.CookieKeys;
038    import com.liferay.portal.util.PortalUtil;
039    import com.liferay.portal.util.PortletKeys;
040    import com.liferay.portal.util.PrefsPropsUtil;
041    import com.liferay.portal.util.PropsValues;
042    import com.liferay.portal.util.WebKeys;
043    import com.liferay.portlet.PortletConfigFactoryUtil;
044    
045    import java.text.MessageFormat;
046    
047    import java.util.HashMap;
048    import java.util.HashSet;
049    import java.util.Locale;
050    import java.util.Map;
051    import java.util.MissingResourceException;
052    import java.util.ResourceBundle;
053    import java.util.Set;
054    import java.util.concurrent.ConcurrentHashMap;
055    
056    import javax.portlet.PortletConfig;
057    import javax.portlet.PortletRequest;
058    
059    import javax.servlet.http.Cookie;
060    import javax.servlet.http.HttpServletRequest;
061    import javax.servlet.http.HttpServletResponse;
062    import javax.servlet.jsp.PageContext;
063    
064    /**
065     * @author Brian Wing Shun Chan
066     * @author Andrius Vitkauskas
067     */
068    public class LanguageImpl implements Language {
069    
070            public String format(Locale locale, String pattern, Object argument) {
071                    return format(locale, pattern, new Object[] {argument}, true);
072            }
073    
074            public String format(
075                    Locale locale, String pattern, Object argument,
076                    boolean translateArguments) {
077    
078                    return format(
079                            locale, pattern, new Object[] {argument}, translateArguments);
080            }
081    
082            public String format(Locale locale, String pattern, Object[] arguments) {
083                    return format(locale, pattern, arguments, true);
084            }
085    
086            public String format(
087                    Locale locale, String pattern, Object[] arguments,
088                    boolean translateArguments) {
089    
090                    String value = null;
091    
092                    try {
093                            pattern = get(locale, pattern);
094    
095                            if (arguments != null) {
096                                    pattern = _escapePattern(pattern);
097    
098                                    Object[] formattedArguments = new Object[arguments.length];
099    
100                                    for (int i = 0; i < arguments.length; i++) {
101                                            if (translateArguments) {
102                                                    formattedArguments[i] = get(
103                                                            locale, arguments[i].toString());
104                                            }
105                                            else {
106                                                    formattedArguments[i] = arguments[i];
107                                            }
108                                    }
109    
110                                    value = MessageFormat.format(pattern, formattedArguments);
111                            }
112                            else {
113                                    value = pattern;
114                            }
115                    }
116                    catch (Exception e) {
117                            if (_log.isWarnEnabled()) {
118                                    _log.warn(e, e);
119                            }
120                    }
121    
122                    return value;
123            }
124    
125            public String format(
126                    PageContext pageContext, String pattern, Object argument) {
127    
128                    return format(pageContext, pattern, new Object[] {argument}, true);
129            }
130    
131            public String format(
132                    PageContext pageContext, String pattern, Object argument,
133                    boolean translateArguments) {
134    
135                    return format(
136                            pageContext, pattern, new Object[] {argument}, translateArguments);
137            }
138    
139            public String format(
140                    PageContext pageContext, String pattern, Object[] arguments) {
141    
142                    return format(pageContext, pattern, arguments, true);
143            }
144    
145            public String format(
146                    PageContext pageContext, String pattern, Object[] arguments,
147                    boolean translateArguments) {
148    
149                    String value = null;
150    
151                    try {
152                            pattern = get(pageContext, pattern);
153    
154                            if (arguments != null) {
155                                    pattern = _escapePattern(pattern);
156    
157                                    Object[] formattedArguments = new Object[arguments.length];
158    
159                                    for (int i = 0; i < arguments.length; i++) {
160                                            if (translateArguments) {
161                                                    formattedArguments[i] =
162                                                            get(pageContext, arguments[i].toString());
163                                            }
164                                            else {
165                                                    formattedArguments[i] = arguments[i];
166                                            }
167                                    }
168    
169                                    value = MessageFormat.format(pattern, formattedArguments);
170                            }
171                            else {
172                                    value = pattern;
173                            }
174                    }
175                    catch (Exception e) {
176                            if (_log.isWarnEnabled()) {
177                                    _log.warn(e, e);
178                            }
179                    }
180    
181                    return value;
182            }
183    
184            public String format(
185                    PageContext pageContext, String pattern, LanguageWrapper argument) {
186    
187                    return format(
188                            pageContext, pattern, new LanguageWrapper[] {argument}, true);
189            }
190    
191            public String format(
192                    PageContext pageContext, String pattern, LanguageWrapper argument,
193                    boolean translateArguments) {
194    
195                    return format(
196                            pageContext, pattern, new LanguageWrapper[] {argument},
197                            translateArguments);
198            }
199    
200            public String format(
201                    PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
202    
203                    return format(pageContext, pattern, arguments, true);
204            }
205    
206            public String format(
207                    PageContext pageContext, String pattern, LanguageWrapper[] arguments,
208                    boolean translateArguments) {
209    
210                    String value = null;
211    
212                    try {
213                            pattern = get(pageContext, pattern);
214    
215                            if (arguments != null) {
216                                    pattern = _escapePattern(pattern);
217    
218                                    Object[] formattedArguments = new Object[arguments.length];
219    
220                                    for (int i = 0; i < arguments.length; i++) {
221                                            if (translateArguments) {
222                                                    formattedArguments[i] =
223                                                            arguments[i].getBefore() +
224                                                            get(pageContext, arguments[i].getText()) +
225                                                            arguments[i].getAfter();
226                                            }
227                                            else {
228                                                    formattedArguments[i] =
229                                                            arguments[i].getBefore() +
230                                                            arguments[i].getText() +
231                                                            arguments[i].getAfter();
232                                            }
233                                    }
234    
235                                    value = MessageFormat.format(pattern, formattedArguments);
236                            }
237                            else {
238                                    value = pattern;
239                            }
240                    }
241                    catch (Exception e) {
242                            if (_log.isWarnEnabled()) {
243                                    _log.warn(e, e);
244                            }
245                    }
246    
247                    return value;
248            }
249    
250            public String format(
251                    PortletConfig portletConfig, Locale locale, String pattern,
252                    Object argument) {
253    
254                    return format(
255                    portletConfig, locale, pattern, new Object[] {argument}, true);
256            }
257    
258            public String format(
259                    PortletConfig portletConfig, Locale locale, String pattern,
260                    Object argument, boolean translateArguments) {
261    
262                    return format(
263                            portletConfig, locale, pattern, new Object[] {argument},
264                            translateArguments);
265            }
266    
267            public String format(
268                    PortletConfig portletConfig, Locale locale, String pattern,
269                    Object[] arguments) {
270    
271                    return format(portletConfig, locale, pattern, arguments, true);
272            }
273    
274            public String format(
275                    PortletConfig portletConfig, Locale locale, String pattern,
276                    Object[] arguments, boolean translateArguments) {
277    
278                    String value = null;
279    
280                    try {
281                            pattern = get(portletConfig, locale, pattern);
282    
283                            if (arguments != null) {
284                                    pattern = _escapePattern(pattern);
285    
286                                    Object[] formattedArguments = new Object[arguments.length];
287    
288                                    for (int i = 0; i < arguments.length; i++) {
289                                            if (translateArguments) {
290                                                    formattedArguments[i] = get(
291                                                            locale, arguments[i].toString());
292                                            }
293                                            else {
294                                                    formattedArguments[i] = arguments[i];
295                                            }
296                                    }
297    
298                                    value = MessageFormat.format(pattern, formattedArguments);
299                            }
300                            else {
301                                    value = pattern;
302                            }
303                    }
304                    catch (Exception e) {
305                            if (_log.isWarnEnabled()) {
306                                    _log.warn(e, e);
307                            }
308                    }
309    
310                    return value;
311            }
312    
313            public void init() {
314                    _instances.clear();
315            }
316    
317            public String get(Locale locale, String key) {
318                    return get(locale, key, key);
319            }
320    
321            public String get(Locale locale, String key, String defaultValue) {
322                    try {
323                            return _get(null, null, locale, key, defaultValue);
324                    }
325                    catch (Exception e) {
326                            if (_log.isWarnEnabled()) {
327                                    _log.warn(e, e);
328                            }
329    
330                            return defaultValue;
331                    }
332            }
333    
334            public String get(PageContext pageContext, String key) {
335                    return get(pageContext, key, key);
336            }
337    
338            public String get(
339                    PageContext pageContext, String key, String defaultValue) {
340    
341                    try {
342                            return _get(pageContext, null, null, key, defaultValue);
343                    }
344                    catch (Exception e) {
345                            if (_log.isWarnEnabled()) {
346                                    _log.warn(e, e);
347                            }
348    
349                            return defaultValue;
350                    }
351            }
352    
353            public String get(PortletConfig portletConfig, Locale locale, String key) {
354                    return get(portletConfig, locale, key, key);
355            }
356    
357            public String get(
358                    PortletConfig portletConfig, Locale locale, String key,
359                    String defaultValue) {
360    
361                    try {
362                            return _get(null, portletConfig, locale, key, defaultValue);
363                    }
364                    catch (Exception e) {
365                            if (_log.isWarnEnabled()) {
366                                    _log.warn(e, e);
367                            }
368    
369                            return defaultValue;
370                    }
371            }
372    
373            public Locale[] getAvailableLocales() {
374                    return _getInstance()._locales;
375            }
376    
377            public String getCharset(Locale locale) {
378                    return _getInstance()._getCharset(locale);
379            }
380    
381            public String getLanguageId(PortletRequest portletRequest) {
382                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
383                            portletRequest);
384    
385                    return getLanguageId(request);
386            }
387    
388            public String getLanguageId(HttpServletRequest request) {
389                    String languageId = ParamUtil.getString(request, "languageId");
390    
391                    if (Validator.isNotNull(languageId)) {
392                            if (_localesMap.containsKey(languageId) ||
393                                    _charEncodings.containsKey(languageId)) {
394    
395                                    return languageId;
396                            }
397                    }
398    
399                    Locale locale = PortalUtil.getLocale(request);
400    
401                    return getLanguageId(locale);
402            }
403    
404            public String getLanguageId(Locale locale) {
405                    return LocaleUtil.toLanguageId(locale);
406            }
407    
408            public Locale getLocale(String languageCode) {
409                    return _getInstance()._getLocale(languageCode);
410            }
411    
412            public String getTimeDescription(
413                    PageContext pageContext, Long milliseconds) {
414    
415                    return getTimeDescription(pageContext, milliseconds.longValue());
416            }
417    
418            public String getTimeDescription(
419                    PageContext pageContext, long milliseconds) {
420    
421                    String desc = Time.getDescription(milliseconds);
422    
423                    String value = null;
424    
425                    try {
426                            int pos = desc.indexOf(CharPool.SPACE);
427    
428                            int x = GetterUtil.getInteger(desc.substring(0, pos));
429    
430                            value =
431                                    x + " " +
432                                    get(
433                                            pageContext,
434                                            desc.substring(pos + 1, desc.length()).toLowerCase());
435                    }
436                    catch (Exception e) {
437                            if (_log.isWarnEnabled()) {
438                                    _log.warn(e, e);
439                            }
440                    }
441    
442                    return value;
443            }
444    
445            public boolean isAvailableLocale(Locale locale) {
446                    return _getInstance()._localesSet.contains(locale);
447            }
448    
449            public boolean isDuplicateLanguageCode(String languageCode) {
450                    return _getInstance()._duplicateLanguageCodes.contains(languageCode);
451            }
452    
453            public void resetAvailableLocales(long companyId) {
454                     _resetAvailableLocales(companyId);
455            }
456    
457            public void updateCookie(
458                    HttpServletRequest request, HttpServletResponse response,
459                    Locale locale) {
460    
461                    String languageId = LocaleUtil.toLanguageId(locale);
462    
463                    Cookie languageIdCookie = new Cookie(
464                            CookieKeys.GUEST_LANGUAGE_ID, languageId);
465    
466                    languageIdCookie.setPath(StringPool.SLASH);
467                    languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
468    
469                    CookieKeys.addCookie(request, response, languageIdCookie);
470            }
471    
472            private static LanguageImpl _getInstance() {
473                    Long companyId = CompanyThreadLocal.getCompanyId();
474    
475                    LanguageImpl instance = _instances.get(companyId);
476    
477                    if (instance == null) {
478                            instance = new LanguageImpl(companyId);
479    
480                            _instances.put(companyId, instance);
481                    }
482    
483                    return instance;
484            }
485    
486            private LanguageImpl() {
487                    this(CompanyConstants.SYSTEM);
488            }
489    
490            private LanguageImpl(long companyId) {
491                    String[] localesArray = PropsValues.LOCALES;
492    
493                    if (companyId != CompanyConstants.SYSTEM) {
494                            try {
495                                    localesArray = PrefsPropsUtil.getStringArray(
496                                            companyId, PropsKeys.LOCALES, StringPool.COMMA,
497                                            PropsValues.LOCALES);
498                            }
499                            catch (SystemException se) {
500                                    localesArray = PropsValues.LOCALES;
501                            }
502                    }
503    
504                    _charEncodings = new HashMap<String, String>();
505                    _duplicateLanguageCodes = new HashSet<String>();
506                    _locales = new Locale[localesArray.length];
507                    _localesMap = new HashMap<String, Locale>(localesArray.length);
508                    _localesSet = new HashSet<Locale>(localesArray.length);
509    
510                    for (int i = 0; i < localesArray.length; i++) {
511                            String languageId = localesArray[i];
512    
513                            int pos = languageId.indexOf(CharPool.UNDERLINE);
514    
515                            String language = languageId.substring(0, pos);
516                            //String country = languageId.substring(pos + 1);
517    
518                            Locale locale = LocaleUtil.fromLanguageId(languageId);
519    
520                            _charEncodings.put(locale.toString(), StringPool.UTF8);
521    
522                            if (_localesMap.containsKey(language)) {
523                                    _duplicateLanguageCodes.add(language);
524                            }
525    
526                            _locales[i] = locale;
527    
528                            if (!_localesMap.containsKey(language)) {
529                                    _localesMap.put(language, locale);
530                            }
531    
532                            _localesSet.add(locale);
533                    }
534            }
535    
536            private String _escapePattern(String pattern) {
537                    return StringUtil.replace(
538                            pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
539            }
540    
541            private String _get(
542                            PageContext pageContext, PortletConfig portletConfig, Locale locale,
543                            String key, String defaultValue)
544                    throws Exception {
545    
546                    if (key == null) {
547                            return null;
548                    }
549    
550                    String value = null;
551    
552                    if (pageContext != null) {
553                            HttpServletRequest request =
554                                    (HttpServletRequest)pageContext.getRequest();
555    
556                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
557                                    WebKeys.THEME_DISPLAY);
558    
559                            locale = themeDisplay.getLocale();
560    
561                            portletConfig = (PortletConfig)request.getAttribute(
562                                    JavaConstants.JAVAX_PORTLET_CONFIG);
563                    }
564    
565                    if (portletConfig != null) {
566                            ResourceBundle resourceBundle = portletConfig.getResourceBundle(
567                                    locale);
568    
569                            try {
570                                    value = resourceBundle.getString(key);
571                            }
572                            catch (MissingResourceException mre) {
573                            }
574    
575                            // LEP-7393
576    
577                            if (((value == null) || (value.equals(defaultValue))) &&
578                                    (portletConfig.getPortletName().equals(
579                                            PortletKeys.PORTLET_CONFIGURATION))) {
580    
581                                    try {
582                                            value = _getPortletConfigurationValue(
583                                                    pageContext, locale, key);
584                                    }
585                                    catch (MissingResourceException mre) {
586                                    }
587                            }
588    
589                            if (value != null) {
590                                    value = LanguageResources.fixValue(value);
591                            }
592                    }
593    
594                    if ((value == null) || value.equals(defaultValue)) {
595                            value = LanguageResources.getMessage(locale, key);
596                    }
597    
598                    if ((value == null) || value.equals(defaultValue)) {
599                            if (key.endsWith(StringPool.CLOSE_BRACKET)) {
600                                    int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
601    
602                                    if (pos != -1) {
603                                            key = key.substring(0, pos);
604    
605                                            return _get(
606                                                    pageContext, portletConfig, locale, key, defaultValue);
607                                    }
608                            }
609                    }
610    
611                    if (value == null) {
612                            value = defaultValue;
613                    }
614    
615                    return value;
616            }
617    
618            private String _getCharset(Locale locale) {
619                    return StringPool.UTF8;
620            }
621    
622            private Locale _getLocale(String languageCode) {
623                    return _localesMap.get(languageCode);
624            }
625    
626            private String _getPortletConfigurationValue(
627                            PageContext pageContext, Locale locale, String key)
628                    throws Exception {
629    
630                    HttpServletRequest request =
631                            (HttpServletRequest)pageContext.getRequest();
632    
633                    String portletResource = ParamUtil.getString(
634                            request, "portletResource");
635    
636                    long companyId = PortalUtil.getCompanyId(request);
637    
638                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
639                            companyId, portletResource);
640    
641                    PortletConfig portletConfig = PortletConfigFactoryUtil.create(
642                            portlet, pageContext.getServletContext());
643    
644                    ResourceBundle resourceBundle = portletConfig.getResourceBundle(
645                            locale);
646    
647                    return resourceBundle.getString(key);
648            }
649    
650            private void _resetAvailableLocales(long companyId) {
651                    _instances.remove(companyId);
652            }
653    
654            private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
655    
656            private static Map<Long, LanguageImpl> _instances =
657                    new ConcurrentHashMap<Long, LanguageImpl>();
658    
659            private Map<String, String> _charEncodings;
660            private Set<String> _duplicateLanguageCodes;
661            private Locale[] _locales;
662            private Map<String, Locale> _localesMap;
663            private Set<Locale> _localesSet;
664    
665    }