001
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.security.pacl.DoPrivileged;
023 import com.liferay.portal.kernel.util.CharPool;
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.ResourceBundleUtil;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.Time;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.model.CompanyConstants;
034 import com.liferay.portal.model.Portlet;
035 import com.liferay.portal.security.auth.CompanyThreadLocal;
036 import com.liferay.portal.service.PortletLocalServiceUtil;
037 import com.liferay.portal.theme.ThemeDisplay;
038 import com.liferay.portal.util.CookieKeys;
039 import com.liferay.portal.util.PortalUtil;
040 import com.liferay.portal.util.PortletKeys;
041 import com.liferay.portal.util.PrefsPropsUtil;
042 import com.liferay.portal.util.PropsValues;
043 import com.liferay.portal.util.WebKeys;
044 import com.liferay.portlet.PortletConfigFactoryUtil;
045
046 import java.text.MessageFormat;
047
048 import java.util.ArrayList;
049 import java.util.HashMap;
050 import java.util.HashSet;
051 import java.util.List;
052 import java.util.Locale;
053 import java.util.Map;
054 import java.util.ResourceBundle;
055 import java.util.Set;
056 import java.util.concurrent.ConcurrentHashMap;
057
058 import javax.portlet.PortletConfig;
059 import javax.portlet.PortletRequest;
060
061 import javax.servlet.http.Cookie;
062 import javax.servlet.http.HttpServletRequest;
063 import javax.servlet.http.HttpServletResponse;
064 import javax.servlet.jsp.PageContext;
065
066
070 @DoPrivileged
071 public class LanguageImpl implements Language {
072
073 @Override
074 public String format(Locale locale, String pattern, Object argument) {
075 return format(locale, pattern, new Object[] {argument}, true);
076 }
077
078 @Override
079 public String format(
080 Locale locale, String pattern, Object argument,
081 boolean translateArguments) {
082
083 return format(
084 locale, pattern, new Object[] {argument}, translateArguments);
085 }
086
087 @Override
088 public String format(Locale locale, String pattern, Object[] arguments) {
089 return format(locale, pattern, arguments, true);
090 }
091
092 @Override
093 public String format(
094 Locale locale, String pattern, Object[] arguments,
095 boolean translateArguments) {
096
097 if (PropsValues.TRANSLATIONS_DISABLED) {
098 return pattern;
099 }
100
101 String value = null;
102
103 try {
104 pattern = get(locale, pattern);
105
106 if ((arguments != null) && (arguments.length > 0)) {
107 pattern = _escapePattern(pattern);
108
109 Object[] formattedArguments = new Object[arguments.length];
110
111 for (int i = 0; i < arguments.length; i++) {
112 if (translateArguments) {
113 formattedArguments[i] = get(
114 locale, arguments[i].toString());
115 }
116 else {
117 formattedArguments[i] = arguments[i];
118 }
119 }
120
121 value = MessageFormat.format(pattern, formattedArguments);
122 }
123 else {
124 value = pattern;
125 }
126 }
127 catch (Exception e) {
128 if (_log.isWarnEnabled()) {
129 _log.warn(e, e);
130 }
131 }
132
133 return value;
134 }
135
136 @Override
137 public String format(
138 PageContext pageContext, String pattern, LanguageWrapper argument) {
139
140 return format(
141 pageContext, pattern, new LanguageWrapper[] {argument}, true);
142 }
143
144 @Override
145 public String format(
146 PageContext pageContext, String pattern, LanguageWrapper argument,
147 boolean translateArguments) {
148
149 return format(
150 pageContext, pattern, new LanguageWrapper[] {argument},
151 translateArguments);
152 }
153
154 @Override
155 public String format(
156 PageContext pageContext, String pattern, LanguageWrapper[] arguments) {
157
158 return format(pageContext, pattern, arguments, true);
159 }
160
161 @Override
162 public String format(
163 PageContext pageContext, String pattern, LanguageWrapper[] arguments,
164 boolean translateArguments) {
165
166 if (PropsValues.TRANSLATIONS_DISABLED) {
167 return pattern;
168 }
169
170 String value = null;
171
172 try {
173 pattern = get(pageContext, pattern);
174
175 if ((arguments != null) && (arguments.length > 0)) {
176 pattern = _escapePattern(pattern);
177
178 Object[] formattedArguments = new Object[arguments.length];
179
180 for (int i = 0; i < arguments.length; i++) {
181 if (translateArguments) {
182 formattedArguments[i] =
183 arguments[i].getBefore() +
184 get(pageContext, arguments[i].getText()) +
185 arguments[i].getAfter();
186 }
187 else {
188 formattedArguments[i] =
189 arguments[i].getBefore() +
190 arguments[i].getText() +
191 arguments[i].getAfter();
192 }
193 }
194
195 value = MessageFormat.format(pattern, formattedArguments);
196 }
197 else {
198 value = pattern;
199 }
200 }
201 catch (Exception e) {
202 if (_log.isWarnEnabled()) {
203 _log.warn(e, e);
204 }
205 }
206
207 return value;
208 }
209
210 @Override
211 public String format(
212 PageContext pageContext, String pattern, Object argument) {
213
214 return format(pageContext, pattern, new Object[] {argument}, true);
215 }
216
217 @Override
218 public String format(
219 PageContext pageContext, String pattern, Object argument,
220 boolean translateArguments) {
221
222 return format(
223 pageContext, pattern, new Object[] {argument}, translateArguments);
224 }
225
226 @Override
227 public String format(
228 PageContext pageContext, String pattern, Object[] arguments) {
229
230 return format(pageContext, pattern, arguments, true);
231 }
232
233 @Override
234 public String format(
235 PageContext pageContext, String pattern, Object[] arguments,
236 boolean translateArguments) {
237
238 if (PropsValues.TRANSLATIONS_DISABLED) {
239 return pattern;
240 }
241
242 String value = null;
243
244 try {
245 pattern = get(pageContext, pattern);
246
247 if ((arguments != null) && (arguments.length > 0)) {
248 pattern = _escapePattern(pattern);
249
250 Object[] formattedArguments = new Object[arguments.length];
251
252 for (int i = 0; i < arguments.length; i++) {
253 if (translateArguments) {
254 formattedArguments[i] = get(
255 pageContext, arguments[i].toString());
256 }
257 else {
258 formattedArguments[i] = arguments[i];
259 }
260 }
261
262 value = MessageFormat.format(pattern, formattedArguments);
263 }
264 else {
265 value = pattern;
266 }
267 }
268 catch (Exception e) {
269 if (_log.isWarnEnabled()) {
270 _log.warn(e, e);
271 }
272 }
273
274 return value;
275 }
276
277 @Override
278 public String format(
279 PortletConfig portletConfig, Locale locale, String pattern,
280 Object argument) {
281
282 return format(
283 portletConfig, locale, pattern, new Object[] {argument}, true);
284 }
285
286 @Override
287 public String format(
288 PortletConfig portletConfig, Locale locale, String pattern,
289 Object argument, boolean translateArguments) {
290
291 return format(
292 portletConfig, locale, pattern, new Object[] {argument},
293 translateArguments);
294 }
295
296 @Override
297 public String format(
298 PortletConfig portletConfig, Locale locale, String pattern,
299 Object[] arguments) {
300
301 return format(portletConfig, locale, pattern, arguments, true);
302 }
303
304 @Override
305 public String format(
306 PortletConfig portletConfig, Locale locale, String pattern,
307 Object[] arguments, boolean translateArguments) {
308
309 if (PropsValues.TRANSLATIONS_DISABLED) {
310 return pattern;
311 }
312
313 String value = null;
314
315 try {
316 pattern = get(portletConfig, locale, pattern);
317
318 if ((arguments != null) && (arguments.length > 0)) {
319 pattern = _escapePattern(pattern);
320
321 Object[] formattedArguments = new Object[arguments.length];
322
323 for (int i = 0; i < arguments.length; i++) {
324 if (translateArguments) {
325 formattedArguments[i] = get(
326 locale, arguments[i].toString());
327 }
328 else {
329 formattedArguments[i] = arguments[i];
330 }
331 }
332
333 value = MessageFormat.format(pattern, formattedArguments);
334 }
335 else {
336 value = pattern;
337 }
338 }
339 catch (Exception e) {
340 if (_log.isWarnEnabled()) {
341 _log.warn(e, e);
342 }
343 }
344
345 return value;
346 }
347
348 @Override
349 public String get(Locale locale, String key) {
350 return get(locale, key, key);
351 }
352
353 @Override
354 public String get(Locale locale, String key, String defaultValue) {
355 if (PropsValues.TRANSLATIONS_DISABLED) {
356 return key;
357 }
358
359 if (key == null) {
360 return null;
361 }
362
363 String value = LanguageResources.getMessage(locale, key);
364
365 while ((value == null) || value.equals(defaultValue)) {
366 if ((key.length() > 0) &&
367 (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
368
369 int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
370
371 if (pos != -1) {
372 key = key.substring(0, pos);
373
374 value = LanguageResources.getMessage(locale, key);
375
376 continue;
377 }
378 }
379
380 break;
381 }
382
383 if (value == null) {
384 value = defaultValue;
385 }
386
387 return value;
388 }
389
390 @Override
391 public String get(PageContext pageContext, String key) {
392 return get(pageContext, key, key);
393 }
394
395 @Override
396 public String get(
397 PageContext pageContext, String key, String defaultValue) {
398
399 try {
400 return _get(pageContext, null, null, key, defaultValue);
401 }
402 catch (Exception e) {
403 if (_log.isWarnEnabled()) {
404 _log.warn(e, e);
405 }
406
407 return defaultValue;
408 }
409 }
410
411 @Override
412 public String get(PortletConfig portletConfig, Locale locale, String key) {
413 return get(portletConfig, locale, key, key);
414 }
415
416 @Override
417 public String get(
418 PortletConfig portletConfig, Locale locale, String key,
419 String defaultValue) {
420
421 try {
422 return _get(null, portletConfig, locale, key, defaultValue);
423 }
424 catch (Exception e) {
425 if (_log.isWarnEnabled()) {
426 _log.warn(e, e);
427 }
428
429 return defaultValue;
430 }
431 }
432
433 @Override
434 public Locale[] getAvailableLocales() {
435 return _getInstance()._locales;
436 }
437
438 @Override
439 public String getCharset(Locale locale) {
440 return _getInstance()._getCharset(locale);
441 }
442
443 @Override
444 public String getLanguageId(HttpServletRequest request) {
445 String languageId = ParamUtil.getString(request, "languageId");
446
447 if (Validator.isNotNull(languageId)) {
448 if (_localesMap.containsKey(languageId) ||
449 _charEncodings.containsKey(languageId)) {
450
451 return languageId;
452 }
453 }
454
455 Locale locale = PortalUtil.getLocale(request);
456
457 return getLanguageId(locale);
458 }
459
460 @Override
461 public String getLanguageId(Locale locale) {
462 return LocaleUtil.toLanguageId(locale);
463 }
464
465 @Override
466 public String getLanguageId(PortletRequest portletRequest) {
467 HttpServletRequest request = PortalUtil.getHttpServletRequest(
468 portletRequest);
469
470 return getLanguageId(request);
471 }
472
473 @Override
474 public Locale getLocale(String languageCode) {
475 return _getInstance()._getLocale(languageCode);
476 }
477
478 @Override
479 public Locale[] getSupportedLocales() {
480 List<Locale> supportedLocales = new ArrayList<Locale>();
481
482 Locale[] locales = getAvailableLocales();
483
484 for (Locale locale : locales) {
485 if (!isBetaLocale(locale)) {
486 supportedLocales.add(locale);
487 }
488 }
489
490 return supportedLocales.toArray(new Locale[supportedLocales.size()]);
491 }
492
493 @Override
494 public String getTimeDescription(Locale locale, long milliseconds) {
495 return getTimeDescription(locale, milliseconds, false);
496 }
497
498 @Override
499 public String getTimeDescription(
500 Locale locale, long milliseconds, boolean approximate) {
501
502 String description = Time.getDescription(milliseconds, approximate);
503
504 String value = null;
505
506 try {
507 int pos = description.indexOf(CharPool.SPACE);
508
509 String x = description.substring(0, pos);
510
511 value = x.concat(StringPool.SPACE).concat(
512 get(
513 locale,
514 description.substring(
515 pos + 1, description.length()).toLowerCase()));
516 }
517 catch (Exception e) {
518 if (_log.isWarnEnabled()) {
519 _log.warn(e, e);
520 }
521 }
522
523 return value;
524 }
525
526 @Override
527 public String getTimeDescription(Locale locale, Long milliseconds) {
528 return getTimeDescription(locale, milliseconds.longValue());
529 }
530
531 @Override
532 public String getTimeDescription(
533 PageContext pageContext, long milliseconds) {
534
535 return getTimeDescription(pageContext, milliseconds, false);
536 }
537
538 @Override
539 public String getTimeDescription(
540 PageContext pageContext, long milliseconds, boolean approximate) {
541
542 String description = Time.getDescription(milliseconds, approximate);
543
544 String value = null;
545
546 try {
547 int pos = description.indexOf(CharPool.SPACE);
548
549 String x = description.substring(0, pos);
550
551 value = x.concat(StringPool.SPACE).concat(
552 get(
553 pageContext,
554 description.substring(
555 pos + 1, description.length()).toLowerCase()));
556 }
557 catch (Exception e) {
558 if (_log.isWarnEnabled()) {
559 _log.warn(e, e);
560 }
561 }
562
563 return value;
564 }
565
566 @Override
567 public String getTimeDescription(
568 PageContext pageContext, Long milliseconds) {
569
570 return getTimeDescription(pageContext, milliseconds.longValue());
571 }
572
573 @Override
574 public void init() {
575 _instances.clear();
576 }
577
578 @Override
579 public boolean isAvailableLanguageCode(String languageCode) {
580 return _getInstance()._localesMap.containsKey(languageCode);
581 }
582
583 @Override
584 public boolean isAvailableLocale(Locale locale) {
585 return _getInstance()._localesSet.contains(locale);
586 }
587
588 @Override
589 public boolean isAvailableLocale(String languageId) {
590 Locale[] locales = getAvailableLocales();
591
592 for (Locale locale : locales) {
593 if (languageId.equals(locale.toString())) {
594 return true;
595 }
596 }
597
598 return false;
599 }
600
601 @Override
602 public boolean isBetaLocale(Locale locale) {
603 return _getInstance()._localesBetaSet.contains(locale);
604 }
605
606 @Override
607 public boolean isDuplicateLanguageCode(String languageCode) {
608 return _getInstance()._duplicateLanguageCodes.contains(languageCode);
609 }
610
611 @Override
612 public void resetAvailableLocales(long companyId) {
613 _resetAvailableLocales(companyId);
614 }
615
616 @Override
617 public void updateCookie(
618 HttpServletRequest request, HttpServletResponse response,
619 Locale locale) {
620
621 String languageId = LocaleUtil.toLanguageId(locale);
622
623 Cookie languageIdCookie = new Cookie(
624 CookieKeys.GUEST_LANGUAGE_ID, languageId);
625
626 languageIdCookie.setPath(StringPool.SLASH);
627 languageIdCookie.setMaxAge(CookieKeys.MAX_AGE);
628
629 CookieKeys.addCookie(request, response, languageIdCookie);
630 }
631
632 private static LanguageImpl _getInstance() {
633 Long companyId = CompanyThreadLocal.getCompanyId();
634
635 LanguageImpl instance = _instances.get(companyId);
636
637 if (instance == null) {
638 instance = new LanguageImpl(companyId);
639
640 _instances.put(companyId, instance);
641 }
642
643 return instance;
644 }
645
646 private LanguageImpl() {
647 this(CompanyConstants.SYSTEM);
648 }
649
650 private LanguageImpl(long companyId) {
651 String[] localesArray = PropsValues.LOCALES;
652
653 if (companyId != CompanyConstants.SYSTEM) {
654 try {
655 localesArray = PrefsPropsUtil.getStringArray(
656 companyId, PropsKeys.LOCALES, StringPool.COMMA,
657 PropsValues.LOCALES);
658 }
659 catch (SystemException se) {
660 localesArray = PropsValues.LOCALES;
661 }
662 }
663
664 _charEncodings = new HashMap<String, String>();
665 _duplicateLanguageCodes = new HashSet<String>();
666 _locales = new Locale[localesArray.length];
667 _localesMap = new HashMap<String, Locale>(localesArray.length);
668 _localesSet = new HashSet<Locale>(localesArray.length);
669
670 for (int i = 0; i < localesArray.length; i++) {
671 String languageId = localesArray[i];
672
673 Locale locale = LocaleUtil.fromLanguageId(languageId, false);
674
675 _charEncodings.put(locale.toString(), StringPool.UTF8);
676
677 String language = languageId;
678
679 int pos = languageId.indexOf(CharPool.UNDERLINE);
680
681 if (pos > 0) {
682 language = languageId.substring(0, pos);
683 }
684
685 if (_localesMap.containsKey(language)) {
686 _duplicateLanguageCodes.add(language);
687 }
688
689 _locales[i] = locale;
690
691 if (!_localesMap.containsKey(language)) {
692 _localesMap.put(language, locale);
693 }
694
695 _localesSet.add(locale);
696 }
697
698 String[] localesBetaArray = PropsValues.LOCALES_BETA;
699
700 _localesBetaSet = new HashSet<Locale>(localesBetaArray.length);
701
702 for (String languageId : localesBetaArray) {
703 Locale locale = LocaleUtil.fromLanguageId(languageId, false);
704
705 _localesBetaSet.add(locale);
706 }
707 }
708
709 private String _escapePattern(String pattern) {
710 return StringUtil.replace(
711 pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE);
712 }
713
714 private String _get(
715 PageContext pageContext, PortletConfig portletConfig, Locale locale,
716 String key, String defaultValue)
717 throws Exception {
718
719 if (PropsValues.TRANSLATIONS_DISABLED) {
720 return key;
721 }
722
723 if (key == null) {
724 return null;
725 }
726
727 String value = null;
728
729 if (pageContext != null) {
730 HttpServletRequest request =
731 (HttpServletRequest)pageContext.getRequest();
732
733 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
734 WebKeys.THEME_DISPLAY);
735
736 locale = themeDisplay.getLocale();
737
738 portletConfig = (PortletConfig)request.getAttribute(
739 JavaConstants.JAVAX_PORTLET_CONFIG);
740 }
741
742 if (portletConfig != null) {
743 ResourceBundle resourceBundle = portletConfig.getResourceBundle(
744 locale);
745
746 value = ResourceBundleUtil.getString(resourceBundle, key);
747
748
749
750 String portletName = portletConfig.getPortletName();
751
752 if (((value == null) || value.equals(defaultValue)) &&
753 portletName.equals(PortletKeys.PORTLET_CONFIGURATION)) {
754
755 value = _getPortletConfigurationValue(pageContext, locale, key);
756 }
757
758 if (value != null) {
759 value = LanguageResources.fixValue(value);
760 }
761 }
762
763 if ((value == null) || value.equals(defaultValue)) {
764 value = LanguageResources.getMessage(locale, key);
765 }
766
767 if ((value == null) || value.equals(defaultValue)) {
768 if ((key.length() > 0) &&
769 (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) {
770
771 int pos = key.lastIndexOf(CharPool.OPEN_BRACKET);
772
773 if (pos != -1) {
774 key = key.substring(0, pos);
775
776 return _get(
777 pageContext, portletConfig, locale, key, defaultValue);
778 }
779 }
780 }
781
782 if ((value == null) || value.equals(key)) {
783 value = defaultValue;
784 }
785
786 return value;
787 }
788
789 private String _getCharset(Locale locale) {
790 return StringPool.UTF8;
791 }
792
793 private Locale _getLocale(String languageCode) {
794 return _localesMap.get(languageCode);
795 }
796
797 private String _getPortletConfigurationValue(
798 PageContext pageContext, Locale locale, String key)
799 throws Exception {
800
801 if (PropsValues.TRANSLATIONS_DISABLED) {
802 return key;
803 }
804
805 HttpServletRequest request =
806 (HttpServletRequest)pageContext.getRequest();
807
808 String portletResource = ParamUtil.getString(
809 request, "portletResource");
810
811 long companyId = PortalUtil.getCompanyId(request);
812
813 Portlet portlet = PortletLocalServiceUtil.getPortletById(
814 companyId, portletResource);
815
816 PortletConfig portletConfig = PortletConfigFactoryUtil.create(
817 portlet, pageContext.getServletContext());
818
819 ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale);
820
821 return ResourceBundleUtil.getString(resourceBundle, key);
822 }
823
824 private void _resetAvailableLocales(long companyId) {
825 _instances.remove(companyId);
826 }
827
828 private static Log _log = LogFactoryUtil.getLog(LanguageImpl.class);
829
830 private static Map<Long, LanguageImpl> _instances =
831 new ConcurrentHashMap<Long, LanguageImpl>();
832
833 private Map<String, String> _charEncodings;
834 private Set<String> _duplicateLanguageCodes;
835 private Locale[] _locales;
836 private Set<Locale> _localesBetaSet;
837 private Map<String, Locale> _localesMap;
838 private Set<Locale> _localesSet;
839
840 }