OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 83 | Rev 177 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 83 Rev 174
Line 23... Line 23...
23
import java.util.List;
23
import java.util.List;
24
import java.util.Locale;
24
import java.util.Locale;
25
import java.util.Map;
25
import java.util.Map;
26
import java.util.ResourceBundle.Control;
26
import java.util.ResourceBundle.Control;
27
 
27
 
-
 
28
import javax.xml.XMLConstants;
28
import javax.xml.parsers.DocumentBuilder;
29
import javax.xml.parsers.DocumentBuilder;
29
import javax.xml.parsers.DocumentBuilderFactory;
30
import javax.xml.parsers.DocumentBuilderFactory;
30
 
31
 
31
import net.jcip.annotations.GuardedBy;
-
 
32
import net.jcip.annotations.ThreadSafe;
-
 
33
 
-
 
34
import org.w3c.dom.Document;
32
import org.w3c.dom.Document;
35
import org.w3c.dom.Element;
33
import org.w3c.dom.Element;
36
import org.w3c.dom.NodeList;
34
import org.w3c.dom.NodeList;
37
 
35
 
-
 
36
import net.jcip.annotations.GuardedBy;
-
 
37
import net.jcip.annotations.ThreadSafe;
-
 
38
 
38
@ThreadSafe
39
@ThreadSafe
39
public class TranslationManager {
40
public class TranslationManager {
40
    private static final Locale FALLBACK_LOCALE = Locale.ENGLISH;
41
    private static final Locale FALLBACK_LOCALE = Locale.ENGLISH;
41
 
42
 
42
    private static final Control CONTROL = new I18nUtils.SameLanguageControl() {
43
    private static final Control CONTROL = new I18nUtils.SameLanguageControl() {
Line 62... Line 63...
62
    @GuardedBy("classes")
63
    @GuardedBy("classes")
63
    private final List<Class<?>> classes;
64
    private final List<Class<?>> classes;
64
    @GuardedBy("classes")
65
    @GuardedBy("classes")
65
    private Locale locale;
66
    private Locale locale;
66
 
67
 
67
    private final Object trMutex = new String("translations mutex");
68
    private final Object trMutex = new Object();
68
    @GuardedBy("trMutex")
69
    @GuardedBy("trMutex")
69
    private Map<String, String> menuTranslation;
70
    private Map<String, String> menuTranslation;
70
    @GuardedBy("trMutex")
71
    @GuardedBy("trMutex")
71
    private Map<String, String> itemTranslation;
72
    private Map<String, String> itemTranslation;
72
    @GuardedBy("trMutex")
73
    @GuardedBy("trMutex")
73
    private Map<String, String> actionTranslation;
74
    private Map<String, String> actionTranslation;
74
 
75
 
75
    private TranslationManager() {
76
    private TranslationManager() {
76
        this.classes = new ArrayList<Class<?>>();
77
        this.classes = new ArrayList<>();
77
    }
78
    }
78
 
79
 
79
    public void addTranslationStreamFromClass(Class<?> c) {
80
    public void addTranslationStreamFromClass(Class<?> c) {
80
        synchronized (this.classes) {
81
        synchronized (this.classes) {
81
            this.classes.add(c);
82
            this.classes.add(c);
Line 162... Line 163...
162
        }
163
        }
163
    }
164
    }
164
 
165
 
165
    private void loadAllTranslation() {
166
    private void loadAllTranslation() {
166
        synchronized (this.trMutex) {
167
        synchronized (this.trMutex) {
167
            this.menuTranslation = new HashMap<String, String>();
168
            this.menuTranslation = new HashMap<>();
168
            this.itemTranslation = new HashMap<String, String>();
169
            this.itemTranslation = new HashMap<>();
169
            this.actionTranslation = new HashMap<String, String>();
170
            this.actionTranslation = new HashMap<>();
170
            if (this.classes.size() == 0) {
171
            if (this.classes.isEmpty()) {
171
                Log.get().warning("TranslationManager has no resources to load (" + this.getLocale() + ")");
172
                Log.get().warning("TranslationManager has no resources to load (" + this.getLocale() + ")");
172
            }
173
            }
173
            for (Class<?> c : this.classes) {
174
            for (Class<?> c : this.classes) {
174
                boolean loaded = loadTranslation(this.getLocale(), c);
175
                boolean loaded = loadTranslation(this.getLocale(), c);
175
                if (!loaded) {
176
                if (!loaded) {
Line 180... Line 181...
180
    }
181
    }
181
 
182
 
182
    // return all existing (e.g fr_CA only specify differences with fr)
183
    // return all existing (e.g fr_CA only specify differences with fr)
183
    private List<InputStream> findStream(final Locale locale, final Class<?> c, final boolean rootLast) {
184
    private List<InputStream> findStream(final Locale locale, final Class<?> c, final boolean rootLast) {
184
        final Control cntrl = CONTROL;
185
        final Control cntrl = CONTROL;
185
        final List<InputStream> res = new ArrayList<InputStream>();
186
        final List<InputStream> res = new ArrayList<>();
186
        final String baseName = c.getPackage().getName() + "." + BASENAME;
187
        final String baseName = c.getPackage().getName() + "." + BASENAME;
187
 
188
 
188
        // test emptiness to not mix languages
189
        // test emptiness to not mix languages
189
        for (Locale targetLocale = locale; targetLocale != null && res.isEmpty(); targetLocale = cntrl.getFallbackLocale(baseName, targetLocale)) {
190
        for (Locale targetLocale = locale; targetLocale != null && res.isEmpty(); targetLocale = cntrl.getFallbackLocale(baseName, targetLocale)) {
190
            for (final Locale candidate : cntrl.getCandidateLocales(baseName, targetLocale)) {
191
            for (final Locale candidate : cntrl.getCandidateLocales(baseName, targetLocale)) {
Line 201... Line 202...
201
    private boolean loadTranslation(final Locale l, Class<?> c) {
202
    private boolean loadTranslation(final Locale l, Class<?> c) {
202
        boolean translationLoaded = false;
203
        boolean translationLoaded = false;
203
        // we want more specific translations to replace general ones, i.e. root Locale first
204
        // we want more specific translations to replace general ones, i.e. root Locale first
204
        for (final InputStream input : findStream(l, c, false)) {
205
        for (final InputStream input : findStream(l, c, false)) {
205
            // create new instances to check if there's no duplicates in each resource
206
            // create new instances to check if there's no duplicates in each resource
206
            final Map<String, String> menuTranslation = new HashMap<String, String>(), itemTranslation = new HashMap<String, String>(), actionTranslation = new HashMap<String, String>();
207
            final Map<String, String> menuTranslation = new HashMap<>(), itemTranslation = new HashMap<>(), actionTranslation = new HashMap<>();
207
            loadTranslation(input, menuTranslation, itemTranslation, actionTranslation);
208
            loadTranslation(input, menuTranslation, itemTranslation, actionTranslation);
208
            // on the other hand, it's OK for one resource to override another
209
            // on the other hand, it's OK for one resource to override another
209
            this.menuTranslation.putAll(menuTranslation);
210
            this.menuTranslation.putAll(menuTranslation);
210
            this.itemTranslation.putAll(itemTranslation);
211
            this.itemTranslation.putAll(itemTranslation);
211
            this.actionTranslation.putAll(actionTranslation);
212
            this.actionTranslation.putAll(actionTranslation);
212
            translationLoaded = true;
213
            translationLoaded = true;
213
        }
214
        }
214
        return translationLoaded;
215
        return translationLoaded;
215
    }
216
    }
216
 
217
 
217
    static private void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
218
    private static void loadTranslation(final InputStream input, final Map<String, String> menuTranslation, final Map<String, String> itemTranslation, final Map<String, String> actionTranslation) {
-
 
219
        // FIXME : l'implementation de Java est lente
-
 
220
        // com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl : 60 ms!
-
 
221
        // On pourrait passer à 1ms avec Piccolo...
218
        final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
222
        final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
219
 
-
 
220
        try {
223
        try {
-
 
224
            dbFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
-
 
225
            dbFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
221
            final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
226
            final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
222
            final Document doc = dBuilder.parse(input);
227
            final Document doc = dBuilder.parse(input);
223
            // Menus
228
            // Menus
224
            loadTranslation(doc, "menu", menuTranslation);
229
            loadTranslation(doc, "menu", menuTranslation);
225
            // Items (title, labels not related to fields...)
230
            // Items (title, labels not related to fields...)
Line 237... Line 242...
237
                e.printStackTrace();
242
                e.printStackTrace();
238
            }
243
            }
239
        }
244
        }
240
    }
245
    }
241
 
246
 
242
    static private void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
247
    private static void loadTranslation(final Document doc, final String tagName, final Map<String, String> m) {
243
        final NodeList menuChildren = doc.getElementsByTagName(tagName);
248
        final NodeList menuChildren = doc.getElementsByTagName(tagName);
244
        final int size = menuChildren.getLength();
249
        final int size = menuChildren.getLength();
245
        for (int i = 0; i < size; i++) {
250
        for (int i = 0; i < size; i++) {
246
            final Element element = (Element) menuChildren.item(i);
251
            final Element element = (Element) menuChildren.item(i);
247
            final String id = element.getAttributeNode("id").getValue();
252
            final String id = element.getAttributeNode("id").getValue();