OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 156 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 156 Rev 177
Line 37... Line 37...
37
import com.ibm.icu.text.MessageFormat;
37
import com.ibm.icu.text.MessageFormat;
38
import com.ibm.icu.text.MessagePattern;
38
import com.ibm.icu.text.MessagePattern;
39
import com.ibm.icu.text.MessagePattern.Part;
39
import com.ibm.icu.text.MessagePattern.Part;
40
import com.ibm.icu.text.MessagePattern.Part.Type;
40
import com.ibm.icu.text.MessagePattern.Part.Type;
41
 
41
 
-
 
42
import net.jcip.annotations.ThreadSafe;
-
 
43
 
42
/**
44
/**
43
 * Translation manager. The translations are provided by {@link Translator} instances, they are
45
 * Translation manager. The translations are provided by {@link Translator} instances, they are
44
 * created either from a class ending in a language tag that implements it, or by properties files
46
 * created either from a class ending in a language tag that implements it, or by properties files
45
 * that must contain values that will be passed to {@link MessageFormat}. In the latter case,
47
 * that must contain values that will be passed to {@link MessageFormat}. In the latter case,
46
 * messages can reference {@link #createValue(Map, Object[], String) virtual named arguments}.
48
 * messages can reference {@link #createValue(Map, Object[], String) virtual named arguments}.
47
 * 
49
 * 
48
 * @author Sylvain
50
 * @author Sylvain
49
 * @see LocalizedInstances
51
 * @see LocalizedInstances
50
 */
52
 */
-
 
53
@ThreadSafe
51
public class TM {
54
public class TM {
52
 
55
 
53
    static public enum MissingMode {
56
    static public enum MissingMode {
54
        EXCEPTION {
57
        EXCEPTION {
55
            @Override
58
            @Override
Line 87... Line 90...
87
        assert NOUN_CLASS_PROP.equals(Introspector.decapitalize(NounClass.class.getSimpleName()));
90
        assert NOUN_CLASS_PROP.equals(Introspector.decapitalize(NounClass.class.getSimpleName()));
88
    }
91
    }
89
 
92
 
90
    static private final MissingMode DEFAULT_MISSING_MODE = MissingMode.STRING;
93
    static private final MissingMode DEFAULT_MISSING_MODE = MissingMode.STRING;
91
 
94
 
92
    static private final TM INSTANCE = new TM();
95
    private static final TMPool<TM> POOL = new TMPool<TM>(TM::new);
93
    static private final Pattern splitPtrn = Pattern.compile("__", Pattern.LITERAL);
96
    static private final Pattern splitPtrn = Pattern.compile("__", Pattern.LITERAL);
94
    static private boolean USE_DYNAMIC_MAP = true;
97
    static private boolean USE_DYNAMIC_MAP = true;
95
 
98
 
96
    public static void setUseDynamicMap(boolean b) {
99
    public static synchronized void setUseDynamicMap(boolean b) {
97
        USE_DYNAMIC_MAP = b;
100
        USE_DYNAMIC_MAP = b;
98
    }
101
    }
99
 
102
 
100
    /**
103
    /**
101
     * Whether to use a {@link DynamicMap} or add all possible keys up front.
104
     * Whether to use a {@link DynamicMap} or add all possible keys up front.
Line 104... Line 107...
104
     * plurals and choices it might make a difference. However <code>DynamicMap</code> is less
107
     * plurals and choices it might make a difference. However <code>DynamicMap</code> is less
105
     * robust, since it twists a little the definition of {@link Map}.
108
     * robust, since it twists a little the definition of {@link Map}.
106
     * 
109
     * 
107
     * @return <code>true</code> if <code>DynamicMap</code> should be used.
110
     * @return <code>true</code> if <code>DynamicMap</code> should be used.
108
     */
111
     */
109
    public static boolean useDynamicMap() {
112
    public static synchronized boolean useDynamicMap() {
110
        return USE_DYNAMIC_MAP;
113
        return USE_DYNAMIC_MAP;
111
    }
114
    }
112
 
115
 
-
 
116
    /**
-
 
117
     * The default locale for {@link #getInstance()}. Currently just {@link Locale#getDefault()}.
-
 
118
     * 
-
 
119
     * @return the default locale.
-
 
120
     */
-
 
121
    public static final Locale getDefaultLocale() {
-
 
122
        return Locale.getDefault();
-
 
123
    }
-
 
124
 
113
    static public TM getInstance() {
125
    static public TM getInstance() {
-
 
126
        return getInstance(getDefaultLocale());
-
 
127
    }
-
 
128
 
-
 
129
    static public TM getInstance(final Locale l) {
114
        return INSTANCE;
130
        return POOL.get(l);
-
 
131
    }
-
 
132
 
-
 
133
    static public String tr(final Locale l, final String key, final Object... args) {
-
 
134
        return getInstance(l).translate(key, args);
115
    }
135
    }
116
 
136
 
117
    static public String tr(final String key, final Object... args) {
137
    static public String tr(final String key, final Object... args) {
118
        return getInstance().translate(key, args);
138
        return getInstance().translate(key, args);
119
    }
139
    }
120
 
140
 
121
    private Locale locale;
141
    private Locale locale;
122
    private TranslatorChain translations;
142
    private TranslatorChain translations;
123
    private Locale translationsLocale;
143
    private Locale translationsLocale;
124
 
144
 
125
    protected TM() {
-
 
126
        init();
-
 
127
    }
-
 
128
 
-
 
129
    protected void init() {
145
    protected TM(final Locale locale) {
130
        setLocale(Locale.getDefault());
146
        setLocale(locale);
131
    }
147
    }
132
 
148
 
133
    public final void setLocale(final Locale locale) {
149
    private final void setLocale(final Locale locale) {
134
        this.locale = locale;
-
 
135
        final LocalizedInstances<Translator> localizedInstances = new LocalizedInstances<Translator>(Translator.class, TranslationManager.getControl()) {
150
        final LocalizedInstances<Translator> localizedInstances = new LocalizedInstances<Translator>(Translator.class, TranslationManager.getControl()) {
136
            @Override
151
            @Override
137
            protected Translator createInstance(final String bundleName, final Locale l, final Class<?> cl) throws IOException {
152
            protected Translator createInstance(final String bundleName, final Locale l, final Class<?> cl) throws IOException {
138
                final Properties props = PropertiesUtils.createFromResource(cl, '/' + this.getControl().toResourceName(bundleName, "properties"));
153
                final Properties props = PropertiesUtils.createFromResource(cl, '/' + this.getControl().toResourceName(bundleName, "properties"));
139
                if (props == null) {
154
                if (props == null) {
Line 152... Line 167...
152
                    };
167
                    };
153
                }
168
                }
154
            };
169
            };
155
        };
170
        };
156
        final Tuple2<Locale, List<Translator>> createInstances = localizedInstances.createInstances(getBaseName(), locale);
171
        final Tuple2<Locale, List<Translator>> createInstances = localizedInstances.createInstances(getBaseName(), locale);
-
 
172
        synchronized (this) {
-
 
173
            this.locale = locale;
157
        this.translationsLocale = createInstances.get0();
174
            this.translationsLocale = createInstances.get0();
158
        this.translations = new TranslatorChain(createInstances.get1());
175
            this.translations = new TranslatorChain(createInstances.get1());
159
    }
176
        }
-
 
177
    }
160
 
178
 
161
    /**
179
    /**
162
     * The requested locale.
180
     * The requested locale.
163
     * 
181
     * 
164
     * @return the requested locale.
182
     * @return the requested locale.
165
     * @see #setLocale(Locale)
183
     * @see #setLocale(Locale)
166
     */
184
     */
167
    public final Locale getLocale() {
185
    public final synchronized Locale getLocale() {
168
        return this.locale;
186
        return this.locale;
169
    }
187
    }
170
 
188
 
171
    /**
189
    /**
172
     * The actual locale of the loaded translations.
190
     * The actual locale of the loaded translations.
173
     * 
191
     * 
174
     * @return the actual locale.
192
     * @return the actual locale.
175
     */
193
     */
176
    public final Locale getTranslationsLocale() {
194
    public final synchronized Locale getTranslationsLocale() {
177
        return this.translationsLocale;
195
        return this.translationsLocale;
178
    }
196
    }
179
 
197
 
-
 
198
    private final synchronized TranslatorChain getTranslations() {
-
 
199
        return this.translations;
-
 
200
    }
-
 
201
 
180
    protected String getBaseName() {
202
    protected String getBaseName() {
181
        return I18nUtils.getBaseName(this.getClass());
203
        return I18nUtils.getBaseName(this.getClass());
182
    }
204
    }
183
 
205
 
184
    // translate array
206
    // translate array
Line 237... Line 259...
237
 
259
 
238
    private final String translate(final MissingMode mode, final String key, MessageArgs args) throws MissingResourceException {
260
    private final String translate(final MissingMode mode, final String key, MessageArgs args) throws MissingResourceException {
239
        Objects.requireNonNull(mode, "Null mode");
261
        Objects.requireNonNull(mode, "Null mode");
240
        Objects.requireNonNull(key, "Null key");
262
        Objects.requireNonNull(key, "Null key");
241
        Objects.requireNonNull(args, "Null arguments");
263
        Objects.requireNonNull(args, "Null arguments");
242
        final String res = this.translations.translate(key, args);
264
        final String res = this.getTranslations().translate(key, args);
243
        return mode.returnResult(this, res, key);
265
        return mode.returnResult(this, res, key);
244
    }
266
    }
245
 
267
 
246
    protected MessageArgs replaceMap(final MessageArgs args, final String msg) {
268
    protected MessageArgs replaceMap(final MessageArgs args, final String msg) {
247
        final MessageArgs res;
269
        final MessageArgs res;