001
014
015 package com.liferay.portal.language;
016
017 import com.liferay.portal.kernel.language.LanguageUtil;
018 import com.liferay.portal.kernel.log.Log;
019 import com.liferay.portal.kernel.log.LogFactoryUtil;
020 import com.liferay.portal.kernel.util.CharPool;
021 import com.liferay.portal.kernel.util.GetterUtil;
022 import com.liferay.portal.kernel.util.LocaleUtil;
023 import com.liferay.portal.kernel.util.PropertiesUtil;
024 import com.liferay.portal.kernel.util.StringBundler;
025 import com.liferay.portal.kernel.util.StringPool;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.tools.LangBuilder;
029 import com.liferay.registry.Filter;
030 import com.liferay.registry.Registry;
031 import com.liferay.registry.RegistryUtil;
032 import com.liferay.registry.ServiceReference;
033 import com.liferay.registry.ServiceTracker;
034 import com.liferay.registry.ServiceTrackerCustomizer;
035
036 import java.io.InputStream;
037
038 import java.net.URL;
039
040 import java.util.Collections;
041 import java.util.Enumeration;
042 import java.util.HashMap;
043 import java.util.Locale;
044 import java.util.Map;
045 import java.util.Properties;
046 import java.util.ResourceBundle;
047 import java.util.Set;
048 import java.util.concurrent.ConcurrentHashMap;
049
050
054 public class LanguageResources {
055
056 public static String fixValue(String value) {
057 if (value.endsWith(LangBuilder.AUTOMATIC_COPY)) {
058 value = value.substring(
059 0, value.length() - LangBuilder.AUTOMATIC_COPY.length());
060 }
061
062 if (value.endsWith(LangBuilder.AUTOMATIC_TRANSLATION)) {
063 value = value.substring(
064 0, value.length() - LangBuilder.AUTOMATIC_TRANSLATION.length());
065 }
066
067 return value;
068 }
069
070 public static void fixValues(
071 Map<String, String> languageMap, Properties properties) {
072
073 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
074 String key = (String)entry.getKey();
075 String value = (String)entry.getValue();
076
077 value = fixValue(value);
078
079 languageMap.put(key, value);
080 }
081 }
082
083 public static String getMessage(Locale locale, String key) {
084 if (locale == null) {
085 return null;
086 }
087
088 Map<String, String> languageMap = _languageMaps.get(locale);
089
090 if (languageMap == null) {
091 languageMap = _loadLocale(locale);
092 }
093
094 String value = languageMap.get(key);
095
096 if (value == null) {
097 return getMessage(getSuperLocale(locale), key);
098 }
099 else {
100 return value;
101 }
102 }
103
104 public static ResourceBundle getResourceBundle(Locale locale) {
105 return new LanguageResourcesBundle(locale);
106 }
107
108 public static Locale getSuperLocale(Locale locale) {
109 Locale superLocale = _superLocales.get(locale);
110
111 if (superLocale != null) {
112 if (superLocale == _nullLocale) {
113 return null;
114 }
115
116 return superLocale;
117 }
118
119 superLocale = _getSuperLocale(locale);
120
121 if (superLocale == null) {
122 _superLocales.put(locale, _nullLocale);
123 }
124 else {
125 _superLocales.put(locale, superLocale);
126 }
127
128 return superLocale;
129 }
130
131 public void setConfig(String config) {
132 _configNames = StringUtil.split(
133 config.replace(CharPool.PERIOD, CharPool.SLASH));
134 }
135
136 private static Locale _getSuperLocale(Locale locale) {
137 String variant = locale.getVariant();
138
139 if (variant.length() > 0) {
140 return new Locale(locale.getLanguage(), locale.getCountry());
141 }
142
143 String country = locale.getCountry();
144
145 if (country.length() > 0) {
146 Locale priorityLocale = LanguageUtil.getLocale(
147 locale.getLanguage());
148
149 if ((priorityLocale != null) && !locale.equals(priorityLocale)) {
150 return new Locale(
151 priorityLocale.getLanguage(), priorityLocale.getCountry());
152 }
153
154 return LocaleUtil.fromLanguageId(locale.getLanguage(), false, true);
155 }
156
157 String language = locale.getLanguage();
158
159 if (language.length() > 0) {
160 return _blankLocale;
161 }
162
163 return null;
164 }
165
166 private static Map<String, String> _loadLocale(Locale locale) {
167 Map<String, String> languageMap = null;
168
169 if (_configNames.length > 0) {
170 String localeName = locale.toString();
171
172 languageMap = new HashMap<String, String>();
173
174 for (String name : _configNames) {
175 StringBundler sb = new StringBundler(4);
176
177 sb.append(name);
178
179 if (localeName.length() > 0) {
180 sb.append(StringPool.UNDERLINE);
181 sb.append(localeName);
182 }
183
184 sb.append(".properties");
185
186 Properties properties = _loadProperties(sb.toString());
187
188 fixValues(languageMap, properties);
189 }
190 }
191 else {
192 languageMap = Collections.emptyMap();
193 }
194
195 _languageMaps.put(locale, languageMap);
196
197 return languageMap;
198 }
199
200 private static Properties _loadProperties(String name) {
201 Properties properties = new Properties();
202
203 try {
204 ClassLoader classLoader = LanguageResources.class.getClassLoader();
205
206 Enumeration<URL> enu = classLoader.getResources(name);
207
208 if (_log.isDebugEnabled() && !enu.hasMoreElements()) {
209 _log.debug("No resources found for " + name);
210 }
211
212 while (enu.hasMoreElements()) {
213 URL url = enu.nextElement();
214
215 if (_log.isInfoEnabled()) {
216 _log.info("Loading " + name + " from " + url);
217 }
218
219 try (InputStream inputStream = url.openStream()) {
220 Properties inputStreamProperties = PropertiesUtil.load(
221 inputStream, StringPool.UTF8);
222
223 properties.putAll(inputStreamProperties);
224
225 if (_log.isInfoEnabled()) {
226 _log.info(
227 "Loading " + url + " with " +
228 inputStreamProperties.size() + " values");
229 }
230 }
231 }
232 }
233 catch (Exception e) {
234 if (_log.isWarnEnabled()) {
235 _log.warn(e, e);
236 }
237 }
238
239 return properties;
240 }
241
242 private static Map<String, String> _putLanguageMap(
243 Locale locale, Map<String, String> languageMap) {
244
245 Map<String, String> oldLanguageMap = _languageMaps.get(locale);
246
247 if (oldLanguageMap == null) {
248 _loadLocale(locale);
249
250 oldLanguageMap = _languageMaps.get(locale);
251 }
252
253 Map<String, String> newLanguageMap = new HashMap<String, String>();
254
255 if (oldLanguageMap != null) {
256 newLanguageMap.putAll(oldLanguageMap);
257 }
258
259 newLanguageMap.putAll(languageMap);
260
261 _languageMaps.put(locale, newLanguageMap);
262
263 return oldLanguageMap;
264 }
265
266 private static final Log _log = LogFactoryUtil.getLog(
267 LanguageResources.class);
268
269 private static final Locale _blankLocale = new Locale(StringPool.BLANK);
270 private static String[] _configNames;
271 private static final Map<Locale, Map<String, String>> _languageMaps =
272 new ConcurrentHashMap<Locale, Map<String, String>>(64);
273 private static final Locale _nullLocale = new Locale(StringPool.BLANK);
274 private static final ServiceTracker<ResourceBundle, ResourceBundle>
275 _serviceTracker;
276 private static final Map<Locale, Locale> _superLocales =
277 new ConcurrentHashMap<Locale, Locale>();
278
279 static {
280 Registry registry = RegistryUtil.getRegistry();
281
282 Filter languageResourceFilter = registry.getFilter(
283 "(&(!(javax.portlet.name=*))(language.id=*)(objectClass=" +
284 ResourceBundle.class.getName() + "))");
285
286 _serviceTracker = registry.trackServices(
287 languageResourceFilter,
288 new LanguageResourceServiceTrackerCustomizer());
289
290 _serviceTracker.open();
291 }
292
293 private static class LanguageResourcesBundle extends ResourceBundle {
294
295 @Override
296 public Enumeration<String> getKeys() {
297 Set<String> keySet = _languageMap.keySet();
298
299 if (parent == null) {
300 return Collections.enumeration(keySet);
301 }
302
303 return new ResourceBundleEnumeration(keySet, parent.getKeys());
304 }
305
306 @Override
307 public Locale getLocale() {
308 return _locale;
309 }
310
311 @Override
312 protected Object handleGetObject(String key) {
313 return _languageMap.get(key);
314 }
315
316 @Override
317 protected Set<String> handleKeySet() {
318 return _languageMap.keySet();
319 }
320
321 private LanguageResourcesBundle(Locale locale) {
322 _locale = locale;
323
324 Map<String, String> languageMap = _languageMaps.get(locale);
325
326 if (languageMap == null) {
327 languageMap = _loadLocale(locale);
328 }
329
330 _languageMap = languageMap;
331
332 Locale superLocale = getSuperLocale(locale);
333
334 if (superLocale != null) {
335 setParent(new LanguageResourcesBundle(superLocale));
336 }
337 }
338
339 private final Map<String, String> _languageMap;
340 private final Locale _locale;
341
342 }
343
344 private static class LanguageResourceServiceTrackerCustomizer
345 implements ServiceTrackerCustomizer<ResourceBundle, ResourceBundle> {
346
347 @Override
348 public ResourceBundle addingService(
349 ServiceReference<ResourceBundle> serviceReference) {
350
351 Registry registry = RegistryUtil.getRegistry();
352
353 ResourceBundle resourceBundle = registry.getService(
354 serviceReference);
355
356 String languageId = GetterUtil.getString(
357 serviceReference.getProperty("language.id"), StringPool.BLANK);
358 Map<String, String> languageMap = new HashMap<String, String>();
359 Locale locale = null;
360
361 if (Validator.isNotNull(languageId)) {
362 locale = LocaleUtil.fromLanguageId(languageId, true);
363 }
364 else {
365 locale = new Locale(StringPool.BLANK);
366 }
367
368 Enumeration<String> keys = resourceBundle.getKeys();
369
370 while (keys.hasMoreElements()) {
371 String key = keys.nextElement();
372
373 String value = resourceBundle.getString(key);
374
375 languageMap.put(key, value);
376 }
377
378 Map<String, String> oldLanguageMap = _putLanguageMap(
379 locale, languageMap);
380
381 _oldLanguageMaps.put(serviceReference, oldLanguageMap);
382
383 return resourceBundle;
384 }
385
386 @Override
387 public void modifiedService(
388 ServiceReference<ResourceBundle> serviceReference,
389 ResourceBundle resourceBundle) {
390 }
391
392 @Override
393 public void removedService(
394 ServiceReference<ResourceBundle> serviceReference,
395 ResourceBundle resourceBundle) {
396
397 Registry registry = RegistryUtil.getRegistry();
398
399 registry.ungetService(serviceReference);
400
401 String languageId = GetterUtil.getString(
402 serviceReference.getProperty("language.id"), StringPool.BLANK);
403 Locale locale = null;
404
405 if (Validator.isNotNull(languageId)) {
406 locale = LocaleUtil.fromLanguageId(languageId, true);
407 }
408 else {
409 locale = new Locale(StringPool.BLANK);
410 }
411
412 Map<String, String> languageMap = _oldLanguageMaps.get(
413 serviceReference);
414
415 _putLanguageMap(locale, languageMap);
416 }
417
418 private final Map<ServiceReference<?>, Map<String, String>>
419 _oldLanguageMaps = new HashMap<>();
420
421 }
422
423 }