001 /** 002 * Copyright (c) 2000-present Liferay, Inc. All rights reserved. 003 * 004 * This library is free software; you can redistribute it and/or modify it under 005 * the terms of the GNU Lesser General Public License as published by the Free 006 * Software Foundation; either version 2.1 of the License, or (at your option) 007 * any later version. 008 * 009 * This library is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 011 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 012 * details. 013 */ 014 015 package com.liferay.portal.language; 016 017 import com.liferay.portal.kernel.cache.MultiVMPool; 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.auth.CompanyThreadLocal; 028 import com.liferay.portal.kernel.security.pacl.DoPrivileged; 029 import com.liferay.portal.kernel.util.ArrayUtil; 030 import com.liferay.portal.kernel.util.CharPool; 031 import com.liferay.portal.kernel.util.CookieKeys; 032 import com.liferay.portal.kernel.util.GetterUtil; 033 import com.liferay.portal.kernel.util.HtmlUtil; 034 import com.liferay.portal.kernel.util.JavaConstants; 035 import com.liferay.portal.kernel.util.LocaleUtil; 036 import com.liferay.portal.kernel.util.ObjectValuePair; 037 import com.liferay.portal.kernel.util.ParamUtil; 038 import com.liferay.portal.kernel.util.PropsKeys; 039 import com.liferay.portal.kernel.util.ResourceBundleUtil; 040 import com.liferay.portal.kernel.util.StringBundler; 041 import com.liferay.portal.kernel.util.StringPool; 042 import com.liferay.portal.kernel.util.StringUtil; 043 import com.liferay.portal.kernel.util.Time; 044 import com.liferay.portal.kernel.util.UnicodeProperties; 045 import com.liferay.portal.kernel.util.Validator; 046 import com.liferay.portal.kernel.util.WebKeys; 047 import com.liferay.portal.model.CompanyConstants; 048 import com.liferay.portal.model.Group; 049 import com.liferay.portal.model.GroupConstants; 050 import com.liferay.portal.service.GroupLocalServiceUtil; 051 import com.liferay.portal.theme.ThemeDisplay; 052 import com.liferay.portal.util.PortalUtil; 053 import com.liferay.portal.util.PrefsPropsUtil; 054 import com.liferay.portal.util.PropsValues; 055 import com.liferay.registry.Registry; 056 import com.liferay.registry.RegistryUtil; 057 import com.liferay.registry.dependency.ServiceDependencyListener; 058 import com.liferay.registry.dependency.ServiceDependencyManager; 059 060 import java.io.Serializable; 061 062 import java.text.MessageFormat; 063 064 import java.util.HashMap; 065 import java.util.HashSet; 066 import java.util.List; 067 import java.util.Locale; 068 import java.util.Map; 069 import java.util.ResourceBundle; 070 import java.util.Set; 071 import java.util.concurrent.ConcurrentHashMap; 072 import java.util.regex.Matcher; 073 import java.util.regex.Pattern; 074 075 import javax.portlet.PortletConfig; 076 import javax.portlet.PortletRequest; 077 078 import javax.servlet.http.Cookie; 079 import javax.servlet.http.HttpServletRequest; 080 import javax.servlet.http.HttpServletResponse; 081 082 /** 083 * Provides various translation related functionalities for language keys 084 * specified in portlet configurations and portal resource bundles. 085 * 086 * <p> 087 * You can disable translations by setting the 088 * <code>translations.disabled</code> property to <code>true</code> in 089 * <code>portal.properties</code>. 090 * </p> 091 * 092 * <p> 093 * Depending on the context passed into these methods, the lookup might be 094 * limited to the portal's resource bundle (e.g. when only a locale is passed), 095 * or extended to include an individual portlet's resource bundle (e.g. when a 096 * request object is passed). A portlet's resource bundle overrides the portal's 097 * resources when both are present. 098 * </p> 099 * 100 * @author Brian Wing Shun Chan 101 * @author Andrius Vitkauskas 102 * @author Eduardo Lundgren 103 */ 104 @DoPrivileged 105 public class LanguageImpl implements Language, Serializable { 106 107 public void afterPropertiesSet() { 108 ServiceDependencyManager serviceDependencyManager = 109 new ServiceDependencyManager(); 110 111 serviceDependencyManager.addServiceDependencyListener( 112 new ServiceDependencyListener() { 113 114 @Override 115 public void dependenciesFulfilled() { 116 Registry registry = RegistryUtil.getRegistry(); 117 118 MultiVMPool multiVMPool = registry.getService( 119 MultiVMPool.class); 120 121 _portalCache = 122 (PortalCache<Long, Serializable>) 123 multiVMPool.getPortalCache( 124 LanguageImpl.class.getName()); 125 126 PortalCacheMapSynchronizeUtil.synchronize( 127 _portalCache, _companyLocalesBags, 128 new Synchronizer<Long, Serializable>() { 129 130 @Override 131 public void onSynchronize( 132 Map<? extends Long, ? extends Serializable> map, 133 Long key, Serializable value, int timeToLive) { 134 135 _companyLocalesBags.remove(key); 136 } 137 138 }); 139 } 140 141 @Override 142 public void destroy() { 143 } 144 145 } 146 ); 147 148 serviceDependencyManager.registerDependencies(MultiVMPool.class); 149 } 150 151 /** 152 * Returns the translated pattern using the current request's locale or, if 153 * the current request locale is not available, the server's default locale. 154 * 155 * <p> 156 * The lookup is done on the portlet configuration first, and if it's not 157 * found, it is done on the portal's resource bundle. If a translation for a 158 * given key does not exist, this method returns the requested key as the 159 * translation. 160 * </p> 161 * 162 * <p> 163 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 164 * argument, following the standard Java {@link ResourceBundle} notion of 165 * index based substitution. 166 * </p> 167 * 168 * @param request the request used to determine the current locale 169 * @param pattern the key to look up in the current locale's resource file. 170 * The key follows the standard Java resource specification. 171 * @param argument the single argument to be substituted into the pattern 172 * and translated, if possible 173 * @return the translated pattern, with the argument substituted in for the 174 * pattern's placeholder 175 */ 176 @Override 177 public String format( 178 HttpServletRequest request, String pattern, LanguageWrapper argument) { 179 180 return format(request, pattern, new LanguageWrapper[] {argument}, true); 181 } 182 183 /** 184 * Returns the translated pattern using the current request's locale or, if 185 * the current request locale is not available, the server's default locale. 186 * 187 * <p> 188 * The lookup is done on the portlet configuration first, and if it's not 189 * found, it is done on the portal's resource bundle. If a translation for a 190 * given key does not exist, this method returns the requested key as the 191 * translation. 192 * </p> 193 * 194 * <p> 195 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 196 * argument, following the standard Java {@link ResourceBundle} notion of 197 * index based substitution. 198 * </p> 199 * 200 * @param request the request used to determine the current locale 201 * @param pattern the key to look up in the current locale's resource file. 202 * The key follows the standard Java resource specification. 203 * @param argument the single argument to be substituted into the pattern 204 * and translated, if possible 205 * @param translateArguments whether the argument is translated 206 * @return the translated pattern, with the argument substituted in for the 207 * pattern's placeholder 208 */ 209 @Override 210 public String format( 211 HttpServletRequest request, String pattern, LanguageWrapper argument, 212 boolean translateArguments) { 213 214 return format( 215 request, pattern, new LanguageWrapper[] {argument}, 216 translateArguments); 217 } 218 219 /** 220 * Returns the translated pattern using the current request's locale or, if 221 * the current request locale is not available, the server's default locale. 222 * 223 * <p> 224 * The lookup is done on the portlet configuration first, and if it's not 225 * found, it is done on the portal's resource bundle. If a translation for a 226 * given key does not exist, this method returns the requested key as the 227 * translation. 228 * </p> 229 * 230 * <p> 231 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 232 * <code>{2}</code>, etc.) are replaced with the arguments, following the 233 * standard Java {@link ResourceBundle} notion of index based substitution. 234 * </p> 235 * 236 * @param request the request used to determine the current locale 237 * @param pattern the key to look up in the current locale's resource file. 238 * The key follows the standard Java resource specification. 239 * @param arguments the arguments to be substituted into the pattern and 240 * translated, if possible 241 * @return the translated pattern, with the arguments substituted in for the 242 * pattern's placeholders 243 */ 244 @Override 245 public String format( 246 HttpServletRequest request, String pattern, 247 LanguageWrapper[] arguments) { 248 249 return format(request, pattern, arguments, true); 250 } 251 252 /** 253 * Returns the translated pattern using the current request's locale or, if 254 * the current request locale is not available, the server's default locale. 255 * 256 * <p> 257 * The lookup is done on the portlet configuration first, and if it's not 258 * found, it is done on the portal's resource bundle. If a translation for a 259 * given key does not exist, this method returns the requested key as the 260 * translation. 261 * </p> 262 * 263 * <p> 264 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 265 * <code>{2}</code>, etc.) are replaced with the arguments, following the 266 * standard Java {@link ResourceBundle} notion of index based substitution. 267 * </p> 268 * 269 * @param request the request used to determine the current locale 270 * @param pattern the key to look up in the current locale's resource file. 271 * The key follows the standard Java resource specification. 272 * @param arguments the arguments to be substituted into the pattern 273 * @param translateArguments whether the arguments are translated 274 * @return the translated pattern, with the arguments substituted in for the 275 * pattern's placeholders 276 */ 277 @Override 278 public String format( 279 HttpServletRequest request, String pattern, LanguageWrapper[] arguments, 280 boolean translateArguments) { 281 282 if (PropsValues.TRANSLATIONS_DISABLED) { 283 return pattern; 284 } 285 286 String value = null; 287 288 try { 289 pattern = get(request, pattern); 290 291 if (ArrayUtil.isNotEmpty(arguments)) { 292 pattern = _escapePattern(pattern); 293 294 Object[] formattedArguments = new Object[arguments.length]; 295 296 for (int i = 0; i < arguments.length; i++) { 297 if (translateArguments) { 298 formattedArguments[i] = 299 arguments[i].getBefore() + 300 get(request, arguments[i].getText()) + 301 arguments[i].getAfter(); 302 } 303 else { 304 formattedArguments[i] = 305 arguments[i].getBefore() + arguments[i].getText() + 306 arguments[i].getAfter(); 307 } 308 } 309 310 value = MessageFormat.format(pattern, formattedArguments); 311 } 312 else { 313 value = pattern; 314 } 315 } 316 catch (Exception e) { 317 if (_log.isWarnEnabled()) { 318 _log.warn(e, e); 319 } 320 } 321 322 return value; 323 } 324 325 /** 326 * Returns the translated pattern using the current request's locale or, if 327 * the current request locale is not available, the server's default locale. 328 * 329 * <p> 330 * The lookup is done on the portlet configuration first, and if it's not 331 * found, it is done on the portal's resource bundle. If a translation for a 332 * given key does not exist, this method returns the requested key as the 333 * translation. 334 * </p> 335 * 336 * <p> 337 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 338 * argument, following the standard Java {@link ResourceBundle} notion of 339 * index based substitution. 340 * </p> 341 * 342 * @param request the request used to determine the current locale 343 * @param pattern the key to look up in the current locale's resource file. 344 * The key follows the standard Java resource specification. 345 * @param argument the single argument to be substituted into the pattern 346 * and translated, if possible 347 * @return the translated pattern, with the argument substituted in for the 348 * pattern's placeholder 349 */ 350 @Override 351 public String format( 352 HttpServletRequest request, String pattern, Object argument) { 353 354 return format(request, pattern, new Object[] {argument}, true); 355 } 356 357 /** 358 * Returns the translated pattern using the current request's locale or, if 359 * the current request locale is not available, the server's default locale. 360 * 361 * <p> 362 * The lookup is done on the portlet configuration first, and if it's not 363 * found, it is done on the portal's resource bundle. If a translation for a 364 * given key does not exist, this method returns the requested key as the 365 * translation. 366 * </p> 367 * 368 * <p> 369 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 370 * argument, following the standard Java {@link ResourceBundle} notion of 371 * index based substitution. 372 * </p> 373 * 374 * @param request the request used to determine the current locale 375 * @param pattern the key to look up in the current locale's resource file. 376 * The key follows the standard Java resource specification. 377 * @param argument the single argument to be substituted into the pattern 378 * and translated, if possible 379 * @param translateArguments whether the argument is translated 380 * @return the translated pattern, with the argument substituted in for the 381 * pattern's placeholder 382 */ 383 @Override 384 public String format( 385 HttpServletRequest request, String pattern, Object argument, 386 boolean translateArguments) { 387 388 return format( 389 request, pattern, new Object[] {argument}, translateArguments); 390 } 391 392 /** 393 * Returns the translated pattern using the current request's locale or, if 394 * the current request locale is not available, the server's default locale. 395 * 396 * <p> 397 * The lookup is done on the portlet configuration first, and if it's not 398 * found, it is done on the portal's resource bundle. If a translation for a 399 * given key does not exist, this method returns the requested key as the 400 * translation. 401 * </p> 402 * 403 * <p> 404 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 405 * <code>{2}</code>, etc.) are replaced with the arguments, following the 406 * standard Java {@link ResourceBundle} notion of index based substitution. 407 * </p> 408 * 409 * @param request the request used to determine the current locale 410 * @param pattern the key to look up in the current locale's resource file. 411 * The key follows the standard Java resource specification. 412 * @param arguments the arguments to be substituted into the pattern and 413 * translated, if possible 414 * @return the translated pattern, with the arguments substituted in for the 415 * pattern's placeholders 416 */ 417 @Override 418 public String format( 419 HttpServletRequest request, String pattern, Object[] arguments) { 420 421 return format(request, pattern, arguments, true); 422 } 423 424 /** 425 * Returns the translated pattern using the current request's locale or, if 426 * the current request locale is not available, the server's default locale. 427 * 428 * <p> 429 * The lookup is done on the portlet configuration first, and if it's not 430 * found, it is done on the portal's resource bundle. If a translation for a 431 * given key does not exist, this method returns the requested key as the 432 * translation. 433 * </p> 434 * 435 * <p> 436 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 437 * <code>{2}</code>, etc.) are replaced with the arguments, following the 438 * standard Java {@link ResourceBundle} notion of index based substitution. 439 * </p> 440 * 441 * @param request the request used to determine the current locale 442 * @param pattern the key to look up in the current locale's resource file. 443 * The key follows the standard Java resource specification. 444 * @param arguments the arguments to be substituted into the pattern 445 * @param translateArguments whether the arguments are translated 446 * @return the translated pattern, with the arguments substituted in for the 447 * pattern's placeholders 448 */ 449 @Override 450 public String format( 451 HttpServletRequest request, String pattern, Object[] arguments, 452 boolean translateArguments) { 453 454 if (PropsValues.TRANSLATIONS_DISABLED) { 455 return pattern; 456 } 457 458 String value = null; 459 460 try { 461 pattern = get(request, pattern); 462 463 if (ArrayUtil.isNotEmpty(arguments)) { 464 pattern = _escapePattern(pattern); 465 466 Object[] formattedArguments = new Object[arguments.length]; 467 468 for (int i = 0; i < arguments.length; i++) { 469 if (translateArguments) { 470 formattedArguments[i] = get( 471 request, arguments[i].toString()); 472 } 473 else { 474 formattedArguments[i] = arguments[i]; 475 } 476 } 477 478 value = MessageFormat.format(pattern, formattedArguments); 479 } 480 else { 481 value = pattern; 482 } 483 } 484 catch (Exception e) { 485 if (_log.isWarnEnabled()) { 486 _log.warn(e, e); 487 } 488 } 489 490 return value; 491 } 492 493 /** 494 * Returns the translated pattern using the locale or, if the locale is not 495 * available, the server's default locale. 496 * 497 * <p> 498 * The lookup is done on the portal's resource bundle. If a translation for 499 * a given key does not exist, this method returns the requested key as the 500 * translation. 501 * </p> 502 * 503 * <p> 504 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 505 * <code>{2}</code>, etc.) are replaced with the arguments, following the 506 * standard Java {@link ResourceBundle} notion of index based substitution. 507 * </p> 508 * 509 * @param locale the locale to translate to 510 * @param pattern the key to look up in the current locale's resource file. 511 * The key follows the standard Java resource specification. 512 * @param arguments the arguments to be substituted into the pattern 513 * @return the translated pattern, with the arguments substituted in for the 514 * pattern's placeholders 515 */ 516 @Override 517 public String format( 518 Locale locale, String pattern, List<Object> arguments) { 519 520 return format(locale, pattern, arguments.toArray(), true); 521 } 522 523 /** 524 * Returns the translated pattern using the locale or, if the locale is not 525 * available, the server's default locale. 526 * 527 * <p> 528 * The lookup is done on the portal's resource bundle. If a translation for 529 * a given key does not exist, this method returns the requested key as the 530 * translation. 531 * </p> 532 * 533 * <p> 534 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 535 * argument, following the standard Java {@link ResourceBundle} notion of 536 * index based substitution. 537 * </p> 538 * 539 * @param locale the locale to translate to 540 * @param pattern the key to look up in the current locale's resource file. 541 * The key follows the standard Java resource specification. 542 * @param argument the argument to be substituted into the pattern 543 * @return the translated pattern, with the argument substituted in for the 544 * pattern's placeholder 545 */ 546 @Override 547 public String format(Locale locale, String pattern, Object argument) { 548 return format(locale, pattern, new Object[] {argument}, true); 549 } 550 551 /** 552 * Returns the translated pattern using the locale or, if the locale is not 553 * available, the server's default locale. 554 * 555 * <p> 556 * The lookup is done on the portal's resource bundle. If a translation for 557 * a given key does not exist, this method returns the requested key as the 558 * translation. 559 * </p> 560 * 561 * <p> 562 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 563 * argument, following the standard Java {@link ResourceBundle} notion of 564 * index based substitution. 565 * </p> 566 * 567 * @param locale the locale to translate to 568 * @param pattern the key to look up in the current locale's resource file. 569 * The key follows the standard Java resource specification. 570 * @param argument the argument to be substituted into the pattern 571 * @param translateArguments whether the argument is translated 572 * @return the translated pattern, with the argument substituted in for the 573 * pattern's placeholder 574 */ 575 @Override 576 public String format( 577 Locale locale, String pattern, Object argument, 578 boolean translateArguments) { 579 580 return format( 581 locale, pattern, new Object[] {argument}, translateArguments); 582 } 583 584 /** 585 * Returns the translated pattern using the locale or, if the locale is not 586 * available, the server's default locale. 587 * 588 * <p> 589 * The lookup is done on the portal's resource bundle. If a translation for 590 * a given key does not exist, this method returns the requested key as the 591 * translation. 592 * </p> 593 * 594 * <p> 595 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 596 * <code>{2}</code>, etc.) are replaced with the arguments, following the 597 * standard Java {@link ResourceBundle} notion of index based substitution. 598 * </p> 599 * 600 * @param locale the locale to translate to 601 * @param pattern the key to look up in the current locale's resource file. 602 * The key follows the standard Java resource specification. 603 * @param arguments the arguments to be substituted into the pattern 604 * @return the translated pattern, with the arguments substituted in for the 605 * pattern's placeholders 606 */ 607 @Override 608 public String format(Locale locale, String pattern, Object[] arguments) { 609 return format(locale, pattern, arguments, true); 610 } 611 612 /** 613 * Returns the translated pattern using the locale or, if the locale is not 614 * available, the server's default locale. 615 * 616 * <p> 617 * The lookup is done on the portal's resource bundle. If a translation for 618 * a given key does not exist, this method returns the requested key as the 619 * translation. 620 * </p> 621 * 622 * <p> 623 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 624 * <code>{2}</code>, etc.) are replaced with the arguments, following the 625 * standard Java {@link ResourceBundle} notion of index based substitution. 626 * </p> 627 * 628 * @param locale the locale to translate to 629 * @param pattern the key to look up in the current locale's resource file. 630 * The key follows the standard Java resource specification. 631 * @param arguments the arguments to be substituted into the pattern 632 * @param translateArguments whether the arguments are translated 633 * @return the translated pattern, with the arguments substituted in for the 634 * pattern's placeholders 635 */ 636 @Override 637 public String format( 638 Locale locale, String pattern, Object[] arguments, 639 boolean translateArguments) { 640 641 if (PropsValues.TRANSLATIONS_DISABLED) { 642 return pattern; 643 } 644 645 String value = null; 646 647 try { 648 pattern = get(locale, pattern); 649 650 if (ArrayUtil.isNotEmpty(arguments)) { 651 pattern = _escapePattern(pattern); 652 653 Object[] formattedArguments = new Object[arguments.length]; 654 655 for (int i = 0; i < arguments.length; i++) { 656 if (translateArguments) { 657 formattedArguments[i] = get( 658 locale, arguments[i].toString()); 659 } 660 else { 661 formattedArguments[i] = arguments[i]; 662 } 663 } 664 665 value = MessageFormat.format(pattern, formattedArguments); 666 } 667 else { 668 value = pattern; 669 } 670 } 671 catch (Exception e) { 672 if (_log.isWarnEnabled()) { 673 _log.warn(e, e); 674 } 675 } 676 677 return value; 678 } 679 680 /** 681 * Returns the translated pattern in the resource bundle or, if the resource 682 * bundle is not available, the untranslated key. If a translation for a 683 * given key does not exist, this method returns the requested key as the 684 * translation. 685 * 686 * <p> 687 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 688 * argument, following the standard Java {@link ResourceBundle} notion of 689 * index based substitution. 690 * </p> 691 * 692 * @param resourceBundle the requested key's resource bundle 693 * @param pattern the key to look up in the resource bundle. The key 694 * follows the standard Java resource specification. 695 * @param argument the argument to be substituted into the pattern 696 * @return the translated pattern, with the argument substituted in for the 697 * pattern's placeholder 698 */ 699 @Override 700 public String format( 701 ResourceBundle resourceBundle, String pattern, Object argument) { 702 703 return format(resourceBundle, pattern, new Object[] {argument}, true); 704 } 705 706 /** 707 * Returns the translated pattern in the resource bundle or, if the resource 708 * bundle is not available, the untranslated key. If a translation for a 709 * given key does not exist, this method returns the requested key as the 710 * translation. 711 * 712 * <p> 713 * The substitute placeholder (e.g. <code>{0}</code>) is replaced with the 714 * argument, following the standard Java {@link ResourceBundle} notion of 715 * index based substitution. 716 * </p> 717 * 718 * @param resourceBundle the requested key's resource bundle 719 * @param pattern the key to look up in the resource bundle. The key 720 * follows the standard Java resource specification. 721 * @param argument the argument to be substituted into the pattern 722 * @param translateArguments whether the argument is translated 723 * @return the translated pattern, with the argument substituted in for the 724 * pattern's placeholder 725 */ 726 @Override 727 public String format( 728 ResourceBundle resourceBundle, String pattern, Object argument, 729 boolean translateArguments) { 730 731 return format( 732 resourceBundle, pattern, new Object[] {argument}, 733 translateArguments); 734 } 735 736 /** 737 * Returns the translated pattern in the resource bundle or, if the resource 738 * bundle is not available, the untranslated key. If a translation for a 739 * given key does not exist, this method returns the requested key as the 740 * translation. 741 * 742 * <p> 743 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 744 * <code>{2}</code>, etc.) are replaced with the arguments, following the 745 * standard Java {@link ResourceBundle} notion of index based substitution. 746 * </p> 747 * 748 * @param resourceBundle the requested key's resource bundle 749 * @param pattern the key to look up in the resource bundle. The key 750 * follows the standard Java resource specification. 751 * @param arguments the arguments to be substituted into the pattern 752 * @return the translated pattern, with the arguments substituted in for the 753 * pattern's placeholder 754 */ 755 @Override 756 public String format( 757 ResourceBundle resourceBundle, String pattern, Object[] arguments) { 758 759 return format(resourceBundle, pattern, arguments, true); 760 } 761 762 /** 763 * Returns the translated pattern in the resource bundle or, if the resource 764 * bundle is not available, the untranslated key. If a translation for a 765 * given key does not exist, this method returns the requested key as the 766 * translation. 767 * 768 * <p> 769 * The substitute placeholders (e.g. <code>{0}</code>, <code>{1}</code>, 770 * <code>{2}</code>, etc.) are replaced with the arguments, following the 771 * standard Java {@link ResourceBundle} notion of index based substitution. 772 * </p> 773 * 774 * @param resourceBundle the requested key's resource bundle 775 * @param pattern the key to look up in the resource bundle. The key 776 * follows the standard Java resource specification. 777 * @param arguments the arguments to be substituted into the pattern 778 * @param translateArguments whether the arguments are translated 779 * @return the translated pattern, with the arguments substituted in for the 780 * pattern's placeholder 781 */ 782 @Override 783 public String format( 784 ResourceBundle resourceBundle, String pattern, Object[] arguments, 785 boolean translateArguments) { 786 787 if (PropsValues.TRANSLATIONS_DISABLED) { 788 return pattern; 789 } 790 791 String value = null; 792 793 try { 794 pattern = get(resourceBundle, pattern); 795 796 if (ArrayUtil.isNotEmpty(arguments)) { 797 pattern = _escapePattern(pattern); 798 799 Object[] formattedArguments = new Object[arguments.length]; 800 801 for (int i = 0; i < arguments.length; i++) { 802 if (translateArguments) { 803 formattedArguments[i] = get( 804 resourceBundle, arguments[i].toString()); 805 } 806 else { 807 formattedArguments[i] = arguments[i]; 808 } 809 } 810 811 value = MessageFormat.format(pattern, formattedArguments); 812 } 813 else { 814 value = pattern; 815 } 816 } 817 catch (Exception e) { 818 if (_log.isWarnEnabled()) { 819 _log.warn(e, e); 820 } 821 } 822 823 return value; 824 } 825 826 /** 827 * Returns the key's translation from the portlet configuration, or from the 828 * portal's resource bundle if the portlet configuration is unavailable. 829 * 830 * @param request the request used to determine the key's context and 831 * locale 832 * @param resourceBundle the requested key's resource bundle 833 * @param key the translation key 834 * @return the key's translation, or the key if the translation is 835 * unavailable 836 */ 837 @Override 838 public String get( 839 HttpServletRequest request, ResourceBundle resourceBundle, String key) { 840 841 return get(request, resourceBundle, key, key); 842 } 843 844 @Override 845 public String get( 846 HttpServletRequest request, ResourceBundle resourceBundle, String key, 847 String defaultValue) { 848 849 String value = _get(resourceBundle, key); 850 851 if (value != null) { 852 return value; 853 } 854 855 return get(request, key, defaultValue); 856 } 857 858 @Override 859 public String get(HttpServletRequest request, String key) { 860 return get(request, key, key); 861 } 862 863 /** 864 * Returns the key's translation from the portlet configuration, or from the 865 * portal's resource bundle if the portlet configuration is unavailable. 866 * 867 * @param request the request used to determine the key's context and 868 * locale 869 * @param key the translation key 870 * @param defaultValue the value to return if there is no matching 871 * translation 872 * @return the key's translation, or the default value if the translation is 873 * unavailable 874 */ 875 @Override 876 public String get( 877 HttpServletRequest request, String key, String defaultValue) { 878 879 if ((request == null) || (key == null)) { 880 return defaultValue; 881 } 882 883 PortletConfig portletConfig = (PortletConfig)request.getAttribute( 884 JavaConstants.JAVAX_PORTLET_CONFIG); 885 886 Locale locale = _getLocale(request); 887 888 if (portletConfig == null) { 889 return get(locale, key, defaultValue); 890 } 891 892 ResourceBundle resourceBundle = portletConfig.getResourceBundle(locale); 893 894 if (resourceBundle.containsKey(key)) { 895 return _get(resourceBundle, key); 896 } 897 898 return get(locale, key, defaultValue); 899 } 900 901 /** 902 * Returns the key's translation from the portal's resource bundle. 903 * 904 * @param locale the key's locale 905 * @param key the translation key 906 * @return the key's translation 907 */ 908 @Override 909 public String get(Locale locale, String key) { 910 return get(locale, key, key); 911 } 912 913 /** 914 * Returns the key's translation from the portal's resource bundle. 915 * 916 * @param locale the key's locale 917 * @param key the translation key 918 * @param defaultValue the value to return if there is no matching 919 * translation 920 * @return the key's translation, or the default value if the translation is 921 * unavailable 922 */ 923 @Override 924 public String get(Locale locale, String key, String defaultValue) { 925 if (PropsValues.TRANSLATIONS_DISABLED) { 926 return key; 927 } 928 929 if ((locale == null) || (key == null)) { 930 return defaultValue; 931 } 932 933 String value = LanguageResources.getMessage(locale, key); 934 935 if (value != null) { 936 return LanguageResources.fixValue(value); 937 } 938 939 if (value == null) { 940 if ((key.length() > 0) && 941 (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) { 942 943 int pos = key.lastIndexOf(CharPool.OPEN_BRACKET); 944 945 if (pos != -1) { 946 key = key.substring(0, pos); 947 948 return get(locale, key, defaultValue); 949 } 950 } 951 } 952 953 return defaultValue; 954 } 955 956 /** 957 * Returns the key's translation from the resource bundle. 958 * 959 * @param resourceBundle the requested key's resource bundle 960 * @param key the translation key 961 * @return the key's translation 962 */ 963 @Override 964 public String get(ResourceBundle resourceBundle, String key) { 965 return get(resourceBundle, key, key); 966 } 967 968 /** 969 * Returns the key's translation from the resource bundle. 970 * 971 * @param resourceBundle the requested key's resource bundle 972 * @param key the translation key 973 * @param defaultValue the value to return if there is no matching 974 * translation 975 * @return the key's translation, or the default value if the translation is 976 * unavailable 977 */ 978 @Override 979 public String get( 980 ResourceBundle resourceBundle, String key, String defaultValue) { 981 982 String value = _get(resourceBundle, key); 983 984 if (value != null) { 985 return value; 986 } 987 988 return defaultValue; 989 } 990 991 /** 992 * Returns the locales configured for the portal. Locales can be configured 993 * in <code>portal.properties</code> using the <code>locales</code> and 994 * <code>locales.enabled</code> keys. 995 * 996 * @return the locales configured for the portal 997 */ 998 @Override 999 public Set<Locale> getAvailableLocales() { 1000 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1001 1002 return companyLocalesBag.getAvailableLocales(); 1003 } 1004 1005 @Override 1006 public Set<Locale> getAvailableLocales(long groupId) { 1007 if (groupId <= 0) { 1008 return getAvailableLocales(); 1009 } 1010 1011 try { 1012 if (isInheritLocales(groupId)) { 1013 return getAvailableLocales(); 1014 } 1015 } 1016 catch (Exception e) { 1017 } 1018 1019 Map<String, Locale> groupLanguageIdLocalesMap = 1020 _getGroupLanguageIdLocalesMap(groupId); 1021 1022 return new HashSet<>(groupLanguageIdLocalesMap.values()); 1023 } 1024 1025 @Override 1026 public String getBCP47LanguageId(HttpServletRequest request) { 1027 Locale locale = PortalUtil.getLocale(request); 1028 1029 return getBCP47LanguageId(locale); 1030 } 1031 1032 @Override 1033 public String getBCP47LanguageId(Locale locale) { 1034 return LocaleUtil.toBCP47LanguageId(locale); 1035 } 1036 1037 @Override 1038 public String getBCP47LanguageId(PortletRequest portletRequest) { 1039 Locale locale = PortalUtil.getLocale(portletRequest); 1040 1041 return getBCP47LanguageId(locale); 1042 } 1043 1044 /** 1045 * Returns the language ID that the request is served with. The language ID 1046 * is returned as a language code (e.g. <code>en</code>) or a specific 1047 * variant (e.g. <code>en_GB</code>). 1048 * 1049 * @param request the request used to determine the language ID 1050 * @return the language ID that the request is served with 1051 */ 1052 @Override 1053 public String getLanguageId(HttpServletRequest request) { 1054 String languageId = ParamUtil.getString(request, "languageId"); 1055 1056 if (Validator.isNotNull(languageId)) { 1057 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1058 1059 if (companyLocalesBag.containsLanguageCode(languageId) || 1060 companyLocalesBag.containsLanguageId(languageId)) { 1061 1062 return languageId; 1063 } 1064 } 1065 1066 Locale locale = PortalUtil.getLocale(request); 1067 1068 return getLanguageId(locale); 1069 } 1070 1071 /** 1072 * Returns the language ID from the locale. The language ID is returned as a 1073 * language code (e.g. <code>en</code>) or a specific variant (e.g. 1074 * <code>en_GB</code>). 1075 * 1076 * @param locale the locale used to determine the language ID 1077 * @return the language ID from the locale 1078 */ 1079 @Override 1080 public String getLanguageId(Locale locale) { 1081 return LocaleUtil.toLanguageId(locale); 1082 } 1083 1084 /** 1085 * Returns the language ID that the {@link PortletRequest} is served with. 1086 * The language ID is returned as a language code (e.g. <code>en</code>) or 1087 * a specific variant (e.g. <code>en_GB</code>). 1088 * 1089 * @param portletRequest the portlet request used to determine the language 1090 * ID 1091 * @return the language ID that the portlet request is served with 1092 */ 1093 @Override 1094 public String getLanguageId(PortletRequest portletRequest) { 1095 HttpServletRequest request = PortalUtil.getHttpServletRequest( 1096 portletRequest); 1097 1098 return getLanguageId(request); 1099 } 1100 1101 @Override 1102 public Locale getLocale(long groupId, String languageCode) { 1103 Map<String, Locale> groupLanguageCodeLocalesMap = 1104 _getGroupLanguageCodeLocalesMap(groupId); 1105 1106 return groupLanguageCodeLocalesMap.get(languageCode); 1107 } 1108 1109 /** 1110 * Returns the locale associated with the language code. 1111 * 1112 * @param languageCode the code representation of a language (e.g. 1113 * <code>en</code> and <code>en_GB</code>) 1114 * @return the locale associated with the language code 1115 */ 1116 @Override 1117 public Locale getLocale(String languageCode) { 1118 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1119 1120 return companyLocalesBag.getByLanguageCode(languageCode); 1121 } 1122 1123 @Override 1124 public Set<Locale> getSupportedLocales() { 1125 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1126 1127 return companyLocalesBag._supportedLocalesSet; 1128 } 1129 1130 /** 1131 * Returns an exact localized description of the time interval (in 1132 * milliseconds) in the largest unit possible. 1133 * 1134 * <p> 1135 * For example, the following time intervals would be converted to the 1136 * following time descriptions, using the English locale: 1137 * </p> 1138 * 1139 * <ul> 1140 * <li> 1141 * 1000 = 1 Second 1142 * </li> 1143 * <li> 1144 * 1001 = 1001 Milliseconds 1145 * </li> 1146 * <li> 1147 * 86400000 = 1 Day 1148 * </li> 1149 * <li> 1150 * 86401000 = 86401 Seconds 1151 * </li> 1152 * </ul> 1153 * 1154 * @param request the request used to determine the current locale 1155 * @param milliseconds the time interval in milliseconds to describe 1156 * @return an exact localized description of the time interval in the 1157 * largest unit possible 1158 */ 1159 @Override 1160 public String getTimeDescription( 1161 HttpServletRequest request, long milliseconds) { 1162 1163 return getTimeDescription(request, milliseconds, false); 1164 } 1165 1166 /** 1167 * Returns an approximate or exact localized description of the time 1168 * interval (in milliseconds) in the largest unit possible. 1169 * 1170 * <p> 1171 * Approximate descriptions round the time to the largest possible unit and 1172 * ignores the rest. For example, using the English locale: 1173 * </p> 1174 * 1175 * <ul> 1176 * <li> 1177 * Any time interval 1000-1999 = 1 Second 1178 * </li> 1179 * <li> 1180 * Any time interval 86400000-172799999 = 1 Day 1181 * </li> 1182 * </ul> 1183 * 1184 * <p> 1185 * Otherwise, exact descriptions would follow a similar conversion pattern 1186 * as below: 1187 * </p> 1188 * 1189 * <ul> 1190 * <li> 1191 * 1000 = 1 Second 1192 * </li> 1193 * <li> 1194 * 1001 = 1001 Milliseconds 1195 * </li> 1196 * <li> 1197 * 86400000 = 1 Day 1198 * </li> 1199 * <li> 1200 * 86401000 = 86401 Seconds 1201 * </li> 1202 * </ul> 1203 * 1204 * @param request the request used to determine the current locale 1205 * @param milliseconds the time interval in milliseconds to describe 1206 * @param approximate whether the time description is approximate 1207 * @return a localized description of the time interval in the largest unit 1208 * possible 1209 */ 1210 @Override 1211 public String getTimeDescription( 1212 HttpServletRequest request, long milliseconds, boolean approximate) { 1213 1214 String description = Time.getDescription(milliseconds, approximate); 1215 1216 String value = null; 1217 1218 try { 1219 int pos = description.indexOf(CharPool.SPACE); 1220 1221 String x = description.substring(0, pos); 1222 1223 value = x.concat(StringPool.SPACE).concat( 1224 get( 1225 request, 1226 StringUtil.toLowerCase( 1227 description.substring(pos + 1, description.length())))); 1228 } 1229 catch (Exception e) { 1230 if (_log.isWarnEnabled()) { 1231 _log.warn(e, e); 1232 } 1233 } 1234 1235 return value; 1236 } 1237 1238 /** 1239 * Returns an exact localized description of the time interval (in 1240 * milliseconds) in the largest unit possible. 1241 * 1242 * <p> 1243 * For example, the following time intervals would be converted to the 1244 * following time descriptions, using the English locale: 1245 * </p> 1246 * 1247 * <ul> 1248 * <li> 1249 * 1000 = 1 Second 1250 * </li> 1251 * <li> 1252 * 1001 = 1001 Milliseconds 1253 * </li> 1254 * <li> 1255 * 86400000 = 1 Day 1256 * </li> 1257 * <li> 1258 * 86401000 = 86401 Seconds 1259 * </li> 1260 * </ul> 1261 * 1262 * @param request the request used to determine the current locale 1263 * @param milliseconds the time interval in milliseconds to describe 1264 * @return an exact localized description of the time interval in the 1265 * largest unit possible 1266 */ 1267 @Override 1268 public String getTimeDescription( 1269 HttpServletRequest request, Long milliseconds) { 1270 1271 return getTimeDescription(request, milliseconds.longValue()); 1272 } 1273 1274 /** 1275 * Returns an exact localized description of the time interval (in 1276 * milliseconds) in the largest unit possible. 1277 * 1278 * <p> 1279 * For example, the following time intervals would be converted to the 1280 * following time descriptions, using the English locale: 1281 * </p> 1282 * 1283 * <ul> 1284 * <li> 1285 * 1000 = 1 Second 1286 * </li> 1287 * <li> 1288 * 1001 = 1001 Milliseconds 1289 * </li> 1290 * <li> 1291 * 86400000 = 1 Day 1292 * </li> 1293 * <li> 1294 * 86401000 = 86401 Seconds 1295 * </li> 1296 * </ul> 1297 * 1298 * @param locale the locale used to determine the language 1299 * @param milliseconds the time interval in milliseconds to describe 1300 * @return an exact localized description of the time interval in the 1301 * largest unit possible 1302 */ 1303 @Override 1304 public String getTimeDescription(Locale locale, long milliseconds) { 1305 return getTimeDescription(locale, milliseconds, false); 1306 } 1307 1308 /** 1309 * Returns an approximate or exact localized description of the time 1310 * interval (in milliseconds) in the largest unit possible. 1311 * 1312 * <p> 1313 * Approximate descriptions round the time to the largest possible unit and 1314 * ignores the rest. For example, using the English locale: 1315 * </p> 1316 * 1317 * <ul> 1318 * <li> 1319 * Any time interval 1000-1999 = 1 Second 1320 * </li> 1321 * <li> 1322 * Any time interval 86400000-172799999 = 1 Day 1323 * </li> 1324 * </ul> 1325 * 1326 * <p> 1327 * Otherwise, exact descriptions would follow a similar conversion pattern 1328 * as below: 1329 * </p> 1330 * 1331 * <ul> 1332 * <li> 1333 * 1000 = 1 Second 1334 * </li> 1335 * <li> 1336 * 1001 = 1001 Milliseconds 1337 * </li> 1338 * <li> 1339 * 86400000 = 1 Day 1340 * </li> 1341 * <li> 1342 * 86401000 = 86401 Seconds 1343 * </li> 1344 * </ul> 1345 * 1346 * @param locale the locale used to determine the language 1347 * @param milliseconds the time interval in milliseconds to describe 1348 * @param approximate whether the time description is approximate 1349 * @return a localized description of the time interval in the largest unit 1350 * possible 1351 */ 1352 @Override 1353 public String getTimeDescription( 1354 Locale locale, long milliseconds, boolean approximate) { 1355 1356 String description = Time.getDescription(milliseconds, approximate); 1357 1358 String value = null; 1359 1360 try { 1361 int pos = description.indexOf(CharPool.SPACE); 1362 1363 String x = description.substring(0, pos); 1364 1365 value = x.concat(StringPool.SPACE).concat( 1366 get( 1367 locale, 1368 StringUtil.toLowerCase( 1369 description.substring(pos + 1, description.length())))); 1370 } 1371 catch (Exception e) { 1372 if (_log.isWarnEnabled()) { 1373 _log.warn(e, e); 1374 } 1375 } 1376 1377 return value; 1378 } 1379 1380 /** 1381 * Returns an exact localized description of the time interval (in 1382 * milliseconds) in the largest unit possible. 1383 * 1384 * <p> 1385 * For example, the following time intervals would be converted to the 1386 * following time descriptions, using the English locale: 1387 * </p> 1388 * 1389 * <ul> 1390 * <li> 1391 * 1000 = 1 Second 1392 * </li> 1393 * <li> 1394 * 1001 = 1001 Milliseconds 1395 * </li> 1396 * <li> 1397 * 86400000 = 1 Day 1398 * </li> 1399 * <li> 1400 * 86401000 = 86401 Seconds 1401 * </li> 1402 * </ul> 1403 * 1404 * @param locale the locale used to determine the language 1405 * @param milliseconds the time interval in milliseconds to describe 1406 * @return an exact localized description of the time interval in the 1407 * largest unit possible 1408 */ 1409 @Override 1410 public String getTimeDescription(Locale locale, Long milliseconds) { 1411 return getTimeDescription(locale, milliseconds.longValue()); 1412 } 1413 1414 @Override 1415 public void init() { 1416 _companyLocalesBags.clear(); 1417 } 1418 1419 /** 1420 * Returns <code>true</code> if the language code is configured to be 1421 * available. Locales can be configured in <code>portal.properties</code> 1422 * using the <code>locales</code> and <code>locales.enabled</code> keys. 1423 * 1424 * @param languageCode the code representation of a language (e.g. 1425 * <code>en</code> and <code>en_GB</code>) to search for 1426 * @return <code>true</code> if the language code is configured to be 1427 * available; <code>false</code> otherwise 1428 */ 1429 @Override 1430 public boolean isAvailableLanguageCode(String languageCode) { 1431 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1432 1433 return companyLocalesBag.containsLanguageCode(languageCode); 1434 } 1435 1436 /** 1437 * Returns <code>true</code> if the locale is configured to be available. 1438 * Locales can be configured in <code>portal.properties</code> using the 1439 * <code>locales</code> and <code>locales.enabled</code> keys. 1440 * 1441 * @param locale the locale to search for 1442 * @return <code>true</code> if the locale is configured to be available; 1443 * <code>false</code> otherwise 1444 */ 1445 @Override 1446 public boolean isAvailableLocale(Locale locale) { 1447 if (locale == null) { 1448 return false; 1449 } 1450 1451 return isAvailableLocale(LocaleUtil.toLanguageId(locale)); 1452 } 1453 1454 /** 1455 * Returns <code>true</code> if the locale is configured to be available in 1456 * the group. 1457 * 1458 * @param groupId the primary key of the group 1459 * @param locale the locale to search for 1460 * @return <code>true</code> if the locale is configured to be available in 1461 * the group; <code>false</code> otherwise 1462 */ 1463 @Override 1464 public boolean isAvailableLocale(long groupId, Locale locale) { 1465 if (locale == null) { 1466 return false; 1467 } 1468 1469 return isAvailableLocale(groupId, LocaleUtil.toLanguageId(locale)); 1470 } 1471 1472 /** 1473 * Returns <code>true</code> if the language ID is configured to be 1474 * available in the group. 1475 * 1476 * @param groupId the primary key of the group 1477 * @param languageId the language ID to search for 1478 * @return <code>true</code> if the language ID is configured to be 1479 * available in the group; <code>false</code> otherwise 1480 */ 1481 @Override 1482 public boolean isAvailableLocale(long groupId, String languageId) { 1483 if (groupId <= 0) { 1484 return isAvailableLocale(languageId); 1485 } 1486 1487 try { 1488 if (isInheritLocales(groupId)) { 1489 return isAvailableLocale(languageId); 1490 } 1491 } 1492 catch (Exception e) { 1493 } 1494 1495 Map<String, Locale> groupLanguageIdLocalesMap = 1496 _getGroupLanguageIdLocalesMap(groupId); 1497 1498 return groupLanguageIdLocalesMap.containsKey(languageId); 1499 } 1500 1501 /** 1502 * Returns <code>true</code> if the language ID is configured to be 1503 * available. 1504 * 1505 * @param languageId the language ID to search for 1506 * @return <code>true</code> if the language ID is configured to be 1507 * available; <code>false</code> otherwise 1508 */ 1509 @Override 1510 public boolean isAvailableLocale(String languageId) { 1511 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1512 1513 return companyLocalesBag.containsLanguageId(languageId); 1514 } 1515 1516 /** 1517 * Returns <code>true</code> if the locale is configured to be a beta 1518 * language. 1519 * 1520 * @param locale the locale to search for 1521 * @return <code>true</code> if the locale is configured to be a beta 1522 * language; <code>false</code> otherwise 1523 */ 1524 @Override 1525 public boolean isBetaLocale(Locale locale) { 1526 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1527 1528 return companyLocalesBag.isBetaLocale(locale); 1529 } 1530 1531 @Override 1532 public boolean isDuplicateLanguageCode(String languageCode) { 1533 CompanyLocalesBag companyLocalesBag = _getCompanyLocalesBag(); 1534 1535 return companyLocalesBag.isDuplicateLanguageCode(languageCode); 1536 } 1537 1538 @Override 1539 public boolean isInheritLocales(long groupId) throws PortalException { 1540 Group group = GroupLocalServiceUtil.getGroup(groupId); 1541 1542 if (group.isStagingGroup()) { 1543 group = group.getLiveGroup(); 1544 } 1545 1546 if (!group.isSite() || group.isCompany()) { 1547 return true; 1548 } 1549 1550 return GetterUtil.getBoolean( 1551 group.getTypeSettingsProperty( 1552 GroupConstants.TYPE_SETTINGS_KEY_INHERIT_LOCALES), 1553 true); 1554 } 1555 1556 @Override 1557 public String process( 1558 ResourceBundle resourceBundle, Locale locale, String content) { 1559 1560 StringBundler sb = new StringBundler(); 1561 1562 Matcher matcher = _pattern.matcher(content); 1563 1564 int x = 0; 1565 1566 while (matcher.find()) { 1567 int y = matcher.start(0); 1568 1569 String key = matcher.group(1); 1570 1571 sb.append(content.substring(x, y)); 1572 sb.append(StringPool.APOSTROPHE); 1573 1574 String value = get(resourceBundle, key); 1575 1576 sb.append(HtmlUtil.escapeJS(value)); 1577 sb.append(StringPool.APOSTROPHE); 1578 1579 x = matcher.end(0); 1580 } 1581 1582 sb.append(content.substring(x)); 1583 1584 return sb.toString(); 1585 } 1586 1587 @Override 1588 public void resetAvailableGroupLocales(long groupId) { 1589 _resetAvailableGroupLocales(groupId); 1590 } 1591 1592 @Override 1593 public void resetAvailableLocales(long companyId) { 1594 _resetAvailableLocales(companyId); 1595 } 1596 1597 @Override 1598 public void updateCookie( 1599 HttpServletRequest request, HttpServletResponse response, 1600 Locale locale) { 1601 1602 String languageId = LocaleUtil.toLanguageId(locale); 1603 1604 Cookie languageIdCookie = new Cookie( 1605 CookieKeys.GUEST_LANGUAGE_ID, languageId); 1606 1607 languageIdCookie.setPath(StringPool.SLASH); 1608 languageIdCookie.setMaxAge(CookieKeys.MAX_AGE); 1609 1610 CookieKeys.addCookie(request, response, languageIdCookie); 1611 } 1612 1613 private static CompanyLocalesBag _getCompanyLocalesBag() { 1614 Long companyId = CompanyThreadLocal.getCompanyId(); 1615 1616 CompanyLocalesBag companyLocalesBag = _companyLocalesBags.get( 1617 companyId); 1618 1619 if (companyLocalesBag == null) { 1620 companyLocalesBag = new CompanyLocalesBag(companyId); 1621 1622 _companyLocalesBags.put(companyId, companyLocalesBag); 1623 } 1624 1625 return companyLocalesBag; 1626 } 1627 1628 private ObjectValuePair<Map<String, Locale>, Map<String, Locale>> 1629 _createGroupLocales(long groupId) { 1630 1631 String[] languageIds = PropsValues.LOCALES_ENABLED; 1632 1633 try { 1634 Group group = GroupLocalServiceUtil.getGroup(groupId); 1635 1636 UnicodeProperties typeSettingsProperties = 1637 group.getTypeSettingsProperties(); 1638 1639 languageIds = StringUtil.split( 1640 typeSettingsProperties.getProperty(PropsKeys.LOCALES)); 1641 } 1642 catch (Exception e) { 1643 } 1644 1645 Map<String, Locale> groupLanguageCodeLocalesMap = new HashMap<>(); 1646 Map<String, Locale> groupLanguageIdLocalesMap = new HashMap<>(); 1647 1648 for (String languageId : languageIds) { 1649 Locale locale = LocaleUtil.fromLanguageId(languageId, false); 1650 1651 String languageCode = languageId; 1652 1653 int pos = languageId.indexOf(CharPool.UNDERLINE); 1654 1655 if (pos > 0) { 1656 languageCode = languageId.substring(0, pos); 1657 } 1658 1659 if (!groupLanguageCodeLocalesMap.containsKey(languageCode)) { 1660 groupLanguageCodeLocalesMap.put(languageCode, locale); 1661 } 1662 1663 groupLanguageIdLocalesMap.put(languageId, locale); 1664 } 1665 1666 _groupLanguageCodeLocalesMapMap.put( 1667 groupId, groupLanguageCodeLocalesMap); 1668 _groupLanguageIdLocalesMap.put(groupId, groupLanguageIdLocalesMap); 1669 1670 return new ObjectValuePair<>( 1671 groupLanguageCodeLocalesMap, groupLanguageIdLocalesMap); 1672 } 1673 1674 private String _escapePattern(String pattern) { 1675 return StringUtil.replace( 1676 pattern, StringPool.APOSTROPHE, StringPool.DOUBLE_APOSTROPHE); 1677 } 1678 1679 private String _get(ResourceBundle resourceBundle, String key) { 1680 if (PropsValues.TRANSLATIONS_DISABLED) { 1681 return key; 1682 } 1683 1684 if ((resourceBundle == null) || (key == null)) { 1685 return null; 1686 } 1687 1688 String value = ResourceBundleUtil.getString(resourceBundle, key); 1689 1690 if (value != null) { 1691 return LanguageResources.fixValue(value); 1692 } 1693 1694 if ((key.length() > 0) && 1695 (key.charAt(key.length() - 1) == CharPool.CLOSE_BRACKET)) { 1696 1697 int pos = key.lastIndexOf(CharPool.OPEN_BRACKET); 1698 1699 if (pos != -1) { 1700 key = key.substring(0, pos); 1701 1702 return _get(resourceBundle, key); 1703 } 1704 } 1705 1706 return null; 1707 } 1708 1709 private Map<String, Locale> _getGroupLanguageCodeLocalesMap(long groupId) { 1710 Map<String, Locale> groupLanguageCodeLocalesMap = 1711 _groupLanguageCodeLocalesMapMap.get(groupId); 1712 1713 if (groupLanguageCodeLocalesMap == null) { 1714 ObjectValuePair<Map<String, Locale>, Map<String, Locale>> 1715 objectValuePair = _createGroupLocales(groupId); 1716 1717 groupLanguageCodeLocalesMap = objectValuePair.getKey(); 1718 } 1719 1720 return groupLanguageCodeLocalesMap; 1721 } 1722 1723 private Map<String, Locale> _getGroupLanguageIdLocalesMap(long groupId) { 1724 Map<String, Locale> groupLanguageIdLocalesMap = 1725 _groupLanguageIdLocalesMap.get(groupId); 1726 1727 if (groupLanguageIdLocalesMap == null) { 1728 ObjectValuePair<Map<String, Locale>, Map<String, Locale>> 1729 objectValuePair = _createGroupLocales(groupId); 1730 1731 groupLanguageIdLocalesMap = objectValuePair.getValue(); 1732 } 1733 1734 return groupLanguageIdLocalesMap; 1735 } 1736 1737 private Locale _getLocale(HttpServletRequest request) { 1738 Locale locale = null; 1739 1740 ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute( 1741 WebKeys.THEME_DISPLAY); 1742 1743 if (themeDisplay != null) { 1744 locale = themeDisplay.getLocale(); 1745 } 1746 else { 1747 locale = request.getLocale(); 1748 1749 if (!isAvailableLocale(locale)) { 1750 locale = LocaleUtil.getDefault(); 1751 } 1752 } 1753 1754 return locale; 1755 } 1756 1757 private void _resetAvailableGroupLocales(long groupId) { 1758 _groupLanguageCodeLocalesMapMap.remove(groupId); 1759 _groupLanguageIdLocalesMap.remove(groupId); 1760 } 1761 1762 private void _resetAvailableLocales(long companyId) { 1763 _portalCache.remove(companyId); 1764 } 1765 1766 private static final Log _log = LogFactoryUtil.getLog(LanguageImpl.class); 1767 1768 private static final Map<Long, CompanyLocalesBag> _companyLocalesBags = 1769 new ConcurrentHashMap<>(); 1770 private static final Pattern _pattern = Pattern.compile( 1771 "Liferay\\.Language\\.get\\([\"']([^)]+)[\"']\\)"); 1772 private static PortalCache<Long, Serializable> _portalCache; 1773 1774 private final Map<Long, Map<String, Locale>> 1775 _groupLanguageCodeLocalesMapMap = new ConcurrentHashMap<>(); 1776 private final Map<Long, Map<String, Locale>> _groupLanguageIdLocalesMap = 1777 new ConcurrentHashMap<>(); 1778 1779 private static class CompanyLocalesBag implements Serializable { 1780 1781 public boolean containsLanguageCode(String languageCode) { 1782 return _languageCodeLocalesMap.containsKey(languageCode); 1783 } 1784 1785 public boolean containsLanguageId(String languageId) { 1786 return _languageIdLocalesMap.containsKey(languageId); 1787 } 1788 1789 public Set<Locale> getAvailableLocales() { 1790 return new HashSet<>(_languageIdLocalesMap.values()); 1791 } 1792 1793 public Locale getByLanguageCode(String languageCode) { 1794 return _languageCodeLocalesMap.get(languageCode); 1795 } 1796 1797 public boolean isBetaLocale(Locale locale) { 1798 return _localesBetaSet.contains(locale); 1799 } 1800 1801 public boolean isDuplicateLanguageCode(String languageCode) { 1802 return _duplicateLanguageCodes.contains(languageCode); 1803 } 1804 1805 private CompanyLocalesBag(long companyId) { 1806 String[] languageIds = PropsValues.LOCALES; 1807 1808 if (companyId != CompanyConstants.SYSTEM) { 1809 try { 1810 languageIds = PrefsPropsUtil.getStringArray( 1811 companyId, PropsKeys.LOCALES, StringPool.COMMA, 1812 PropsValues.LOCALES_ENABLED); 1813 } 1814 catch (SystemException se) { 1815 languageIds = PropsValues.LOCALES_ENABLED; 1816 } 1817 } 1818 1819 for (String languageId : languageIds) { 1820 Locale locale = LocaleUtil.fromLanguageId(languageId, false); 1821 1822 String languageCode = languageId; 1823 1824 int pos = languageId.indexOf(CharPool.UNDERLINE); 1825 1826 if (pos > 0) { 1827 languageCode = languageId.substring(0, pos); 1828 } 1829 1830 if (_languageCodeLocalesMap.containsKey(languageCode)) { 1831 _duplicateLanguageCodes.add(languageCode); 1832 } 1833 else { 1834 _languageCodeLocalesMap.put(languageCode, locale); 1835 } 1836 1837 _languageIdLocalesMap.put(languageId, locale); 1838 } 1839 1840 for (String languageId : PropsValues.LOCALES_BETA) { 1841 _localesBetaSet.add( 1842 LocaleUtil.fromLanguageId(languageId, false)); 1843 } 1844 1845 _supportedLocalesSet = new HashSet<>( 1846 _languageIdLocalesMap.values()); 1847 1848 _supportedLocalesSet.removeAll(_localesBetaSet); 1849 } 1850 1851 private final Set<String> _duplicateLanguageCodes = new HashSet<>(); 1852 private final Map<String, Locale> _languageCodeLocalesMap = 1853 new HashMap<>(); 1854 private final Map<String, Locale> _languageIdLocalesMap = 1855 new HashMap<>(); 1856 private final Set<Locale> _localesBetaSet = new HashSet<>(); 1857 private final Set<Locale> _supportedLocalesSet; 1858 1859 } 1860 1861 }