All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.freedomotic.i18n.I18nImpl Maven / Gradle / Ivy

/**
 *
 * Copyright (c) 2009-2014 Freedomotic team http://freedomotic.com
 *
 * This file is part of Freedomotic
 *
 * This Program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2, or (at your option) any later version.
 *
 * This Program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Freedomotic; see the file COPYING. If not, see
 * .
 */
package com.freedomotic.i18n;

import com.freedomotic.api.API;
import com.freedomotic.api.Client;
import com.freedomotic.api.Plugin;
import com.freedomotic.app.AppConfig;
import com.freedomotic.util.Info;
import com.google.inject.Inject;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Matteo Mazzoni 
 */
class I18nImpl implements I18n {

	private static class CustomSecurityManager extends SecurityManager {

		public Class getCallerClass() {
			return getClassContext()[2];
		}
	}

	private static final CustomSecurityManager customSecurityManager = new CustomSecurityManager();

		private Locale currentLocale;
    private final HashMap messages;
    private final UTF8control RB_Control;
    private static final ArrayList locales = new ArrayList();
    private final AppConfig config;
    private final HashMap packageBundleDir;
    private final Locale fallBackLocale = Locale.ENGLISH;
    private final API api;

    @Inject
    public I18nImpl(AppConfig config, API api) {
        this.config = config;
        this.api = api;
        currentLocale = Locale.getDefault();
        messages = new HashMap();
        RB_Control = new UTF8control();
        packageBundleDir = new HashMap();
        // add mapping for base strings
        packageBundleDir.put("com.freedomotic", new File(Info.PATHS.PATH_WORKDIR + "/i18n"));
    }

    /*
     * For Freedomotic core: translations are inside /i18n/Freedomotic.properties
     * For Plugin: translations are inside plugins/_plugin_type_/_plugin_package_/i18n/_package_last_part_.properties
     */
    protected String msg(String packageName, String key, Object[] fields) {
        // scorri packageNamefino a trovarne uno presente in packageBundleDir

        File folder = null;
        String workingPackage = packageName;
        while (workingPackage.lastIndexOf('.') != -1) {
            folder = packageBundleDir.get(workingPackage);
            if (folder == null) {
                workingPackage = workingPackage.substring(0, workingPackage.lastIndexOf('.'));
            } else {
                // try and get string for current package
                String value = msg(folder, workingPackage, key, fields, true, currentLocale);
                if (value != null) {
                    return value;
                }
                break;
            }
        }
//        if (folder == null) {
        folder = packageBundleDir.get("com.freedomotic");
//        }
        return msg(folder, "com.freedomotic", key, fields, false, currentLocale);
    }

    private String msg(File folder, String packageName, String key, Object[] fields, boolean reThrow, Locale locale) {
        // estrai locale corrente

        if (locale == null) {
            locale = Locale.ENGLISH;
        }
        String loc = locale.toString(); //currentLocale.getLanguage() + "_" + currentLocale.getCountry();

        // cerca in messages (ed eventualmente aggiungi) la risorsa per il package e la lingua

        if (!messages.containsKey(packageName + ":" + loc)) {
            try {

                ClassLoader loader;
                URL[] urls = {folder.toURI().toURL()};
                loader = new URLClassLoader(urls);

                int lastSize = packageName.split("\\.").length;
                String baseName = packageName.split("\\.")[lastSize - 1];

                messages.put(packageName + ":" + loc, ResourceBundle.getBundle(baseName, currentLocale, loader, RB_Control));
                LOG.log(Level.INFO, "Adding resourceBundle: package={0}, locale={1} pointing at {2}", new Object[]{packageName, loc, folder.getAbsolutePath()});
            } catch (MalformedURLException ex) {
                LOG.log(Level.SEVERE, "Cannot find folder while loading resourceBundle for package{0}", packageName);
            } catch (MissingResourceException ex) {
                LOG.log(Level.SEVERE, "Cannot find resourceBundle files inside folder {1} for package{0}", new Object[]{packageName, folder.getAbsolutePath()});
            }
        }

        // estrai stringa

        if (messages.containsKey(packageName + ":" + loc)) {
            try {
                // try and extract strig for current locale...
                if (messages.get(packageName + ":" + loc).containsKey(key)) {
                    return java.text.MessageFormat.format(messages.get(packageName + ":" + loc).getString(key), fields) + " ";
                } else if (locale != fallBackLocale) {
                    // ... otherwise search string translation in FALLBACKLOCALE
                    String searchDefaultTranslation = msg(folder, packageName, key, fields, reThrow, fallBackLocale);
                    if (searchDefaultTranslation != null) {
                        return searchDefaultTranslation;
                    } else if (reThrow) {
                        return null;
                    } else {
                        //instead of showing nothing we use the key
                        return key;
                    }
                }

            } catch (MissingResourceException ex) {
                LOG.log(Level.SEVERE, "Cannot find resourceBundle files inside folder {0} for package{1}", new Object[]{folder.getAbsolutePath(), packageName});
            }
        }
        return null;
    }

    @Override
    public String msg(String key) {
        String caller = customSecurityManager.getCallerClass().getPackage().getName();
        return msg(caller, key, null);
    }

    @Override
    public String msg(String key, Object[] fields) {
        String caller = customSecurityManager.getCallerClass().getPackage().getName();
        return msg(caller, key, fields);
    }

    private void registerBundleDir(String packageName, File path) {
        if (!packageBundleDir.containsKey(packageName)) {
            packageBundleDir.put(packageName, path);
        }
    }

    @Override
    public void registerPluginBundleDir(Client client) {
        if (client instanceof Plugin) {
            Plugin plug = (Plugin) client;
            if (plug.configuration.getBooleanProperty("enable-i18n", false)) {
                registerBundleDir(plug.getClass().getPackage().getName(), new File(plug.getFile().getParentFile() + "/data/i18n"));
            }
        }
    }

    /**
     *
     */
    protected class UTF8control
            extends ResourceBundle.Control {

        protected static final String BUNDLE_EXTENSION = "properties";

        @Override
        public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader,
                boolean reload)
                throws IllegalAccessException, InstantiationException, IOException {
            // The below code is copied from default Control#newBundle() implementation.
            // Only the PropertyResourceBundle line is changed to read the file as UTF-8.
            String bundleName = toBundleName(baseName, locale);
            String resourceName = toResourceName(bundleName, BUNDLE_EXTENSION);
            ResourceBundle bundle = null;
            InputStream stream = null;

            if (reload) {
                URL url = loader.getResource(resourceName);

                if (url != null) {
                    URLConnection connection = url.openConnection();

                    if (connection != null) {
                        connection.setUseCaches(false);
                        stream = connection.getInputStream();
                    }
                }
            } else {
                stream = loader.getResourceAsStream(resourceName);
            }

            if (stream != null) {
                try {
                    bundle = new PropertyResourceBundle(new InputStreamReader(stream, "UTF-8"));
                } finally {
                    stream.close();
                }
            }

            return bundle;
        }
    }

    @Override
    public void setDefaultLocale(String loc) {
        //if (loc.equals("no") || loc.equals("false")){
        currentLocale = null;
        if (loc == null || loc.isEmpty() || loc.equals("auto") || loc.equals("yes") || loc.equals("true")) {
            currentLocale = Locale.getDefault();
            config.put("KEY_ENABLE_I18N", "auto");
        } else if (loc.length() >= 5) {
            currentLocale = new Locale(loc.substring(0, 2), loc.substring(3, 5));
            config.put("KEY_ENABLE_I18N", currentLocale.toString());
        }
    }

    // should be replaced by user specific Locale
    @Deprecated
    @Override
    public Locale getDefaultLocale() {
        return currentLocale;
    }

    @Override
    public ArrayList getAvailableLocales() {
        final String bundlename = "freedomotic";
        locales.clear();
        File root = new File(Info.PATHS.PATH_WORKDIR + "/i18n");
        File[] files = root.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.matches("^" + bundlename + "(_\\w{2}(_\\w{2})?)?\\.properties$");
            }
        });


        for (File file : files) {
            String value = file.getName().replaceAll("^" + bundlename + "(_)?|\\.properties$", "");

            if (!value.isEmpty()) {
                Locale loc = new Locale(value.substring(0, 2), value.substring(3, 5));
                locales.add(loc);
               
            }
        }
        return locales;
    }
    
    private static final Logger LOG = Logger.getLogger(I18n.class.getName());
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy