]> git.basschouten.com Git - openhab-addons.git/blob
2ad00e5968f7c004f9b44bc62ea47b34ba07fa35
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2024 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.knx.internal.i18n;
14
15 import java.text.MessageFormat;
16 import java.util.Locale;
17
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.openhab.core.i18n.LocaleProvider;
21 import org.openhab.core.i18n.TranslationProvider;
22 import org.osgi.framework.Bundle;
23 import org.osgi.framework.FrameworkUtil;
24
25 /**
26  * This class provides translations. It is a helper class for i18n / localization efforts.
27  *
28  * @implNote It is implemented as a static singleton, enforced by the single-element enum pattern.
29  * @apiNote {@link #setProvider(LocaleProvider, TranslationProvider)} must be called to provide tanslation service,
30  *          otherwise all functions will return untranslated text.
31  *          Thread safety is ensured.
32  * @author Holger Friedrich - Initial contribution
33  *
34  */
35 @NonNullByDefault
36 public enum KNXTranslationProvider {
37     I18N;
38
39     private @Nullable LocaleProvider localeProvider;
40     private @Nullable TranslationProvider translationProvider;
41     private Bundle bundle;
42
43     private KNXTranslationProvider() {
44         localeProvider = null;
45         translationProvider = null;
46         bundle = FrameworkUtil.getBundle(this.getClass());
47     }
48
49     /**
50      * get translated text
51      *
52      * @param text text to be translated, may contain placeholders \{n\} for the n-th optional argument of this function
53      * @param arguments any optional arguments, will be inserted
54      * @return translated text with substitutions if translationProvider is set and provides a translation, otherwise
55      *         returns original text with substitutions
56      */
57     public String get(final String text, @Nullable Object @Nullable... arguments) {
58         // ensure thread safety: calls to setProvider(..) should not lead to race condition
59         final TranslationProvider translationProvider = this.translationProvider;
60         final LocaleProvider localeProvider = this.localeProvider;
61         if (translationProvider != null) {
62             // localeProvider might be null, but if not, getLocale will return NonNull Locale
63             // locale cannot be cached, as getLocale() will return different result once locale is changed by user
64             final Locale locale = (localeProvider != null) ? localeProvider.getLocale() : Locale.getDefault();
65             final String res = translationProvider.getText(bundle, text, text, locale, arguments);
66             if (res != null) {
67                 return res;
68             }
69         }
70         // translating not possible, we still have the original text without any subsititutions
71         if (arguments == null || arguments.length == 0) {
72             return text;
73         }
74         // else execute pattern substitution in untranslated text
75         return MessageFormat.format(text, arguments);
76     }
77
78     /**
79      * get exception in user readable (and possibly localized) form
80      *
81      * @param e any exception
82      * @return localized message in form [description (translated)] [class name], [e.getLocalizedMessage (not
83      *         translated)]), empty string for null. May possibly change in further releases.
84      */
85     public String getLocalizedException(final Throwable e) {
86         StringBuilder res = new StringBuilder();
87         final String exName = e.getClass().getSimpleName();
88         final String key = "exception." + exName;
89         final String translatedDescription = KNXTranslationProvider.I18N.get(key);
90         Boolean foundTranslation = !key.equals(translatedDescription);
91         // detailed message cannot be translated, e.getLocalizedMessage will likely return English
92         String detail = e.getLocalizedMessage();
93         if (detail == null) {
94             detail = "";
95         }
96
97         if (foundTranslation) {
98             res.append(translatedDescription);
99             res.append(" (");
100             res.append(exName);
101             if (!detail.isBlank()) {
102                 res.append(", ");
103                 res.append(detail);
104             }
105             res.append(")");
106         } else {
107             res.append(exName);
108             if (!detail.isBlank()) {
109                 res.append(", ");
110                 res.append(detail);
111             }
112         }
113         return res.toString();
114     }
115
116     /**
117      * Set translation providers. To be called to make any translation work.
118      *
119      * @param localeProvider openHAB locale provider, can be generated via {@literal @}Activate / {@literal @}Reference
120      *            LocaleProvider in handler factory
121      * @param translationProvider openHAB locale provider, can be generated via {@literal @}Activate /
122      *            {@literal @}Reference TranslationProvider in handler factory
123      */
124     public void setProvider(@Nullable LocaleProvider localeProvider,
125             @Nullable TranslationProvider translationProvider) {
126         this.localeProvider = localeProvider;
127         this.translationProvider = translationProvider;
128     }
129 }