com.mindquarry.desktop.I18N.java Source code

Java tutorial

Introduction

Here is the source code for com.mindquarry.desktop.I18N.java

Source

/*
 * Copyright (C) 2006-2007 Mindquarry GmbH, All Rights Reserved
 * 
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 */
package com.mindquarry.desktop;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import com.mindquarry.desktop.util.TranslationMessageParser;

/**
 * Loads the translation for the current default locale from an XML
 * file in the classpath, falls back to English if there's no translation.
 * 
 * @author dnaber
 */
public class I18N {

    private static Log log = LogFactory.getLog(I18N.class);

    private static final String BUNDLE_FILE_BASE = "/com/mindquarry/desktop/messages_"; //$NON-NLS-1$
    private static final String BUNDLE_FILE_SUFFIX = ".xml"; //$NON-NLS-1$

    private static Map<String, String> translationMap = null;

    public static String get(String key) {
        return get(key, new String[] {});
    }

    public static String get(String key, String... args) {
        if (translationMap == null) {
            translationMap = initTranslationMap(BUNDLE_FILE_BASE, BUNDLE_FILE_SUFFIX);
        }
        return getTranslation(key, translationMap, args);
    }

    protected static Map<String, String> initTranslationMap(String fileBase, String fileSuffix) {
        try {
            SAXParserFactory parserFactory = SAXParserFactory.newInstance();
            parserFactory.setValidating(false);
            SAXParser parser = parserFactory.newSAXParser();
            XMLReader reader = parser.getXMLReader();
            TranslationMessageParser translationParser = new TranslationMessageParser();
            reader.setContentHandler(translationParser);
            reader.setErrorHandler(translationParser);
            // TODO: use "xx_YY" if available, use "xx" otherwise:
            String transFile = fileBase + Locale.getDefault().getLanguage() + fileSuffix;
            InputStream is = I18N.class.getResourceAsStream(transFile);
            if (is == null) {
                // no translation available for this language
                log.debug("No translation file available for language: " + Locale.getDefault().getLanguage());
                return new HashMap<String, String>();
            }
            log.debug("Loading translation file " + transFile + " from JAR");
            reader.parse(new InputSource(is));
            return translationParser.getMap();
        } catch (Exception e) {
            throw new RuntimeException(e.toString(), e);
        }
    }

    protected static String getTranslation(String key, Map<String, String> translationMap, String... args) {
        String translation = translationMap.get(key);
        if (translation == null) {
            // quotes are as >>\"<< in the map, but as >>"<< in the key:
            key = key.replaceAll("\"", "\\\\\"");
            // line breaks are entered as "\n" (literally) but we get them as a line
            // break from the parser:
            translation = translationMap.get(key.replace("\n", "\\n"));
            if (translation == null) {
                if (!"en".equals(Locale.getDefault().getLanguage())) {
                    // don't log if GUI is English
                    log.warn("No translation found for '" + key + "'");
                }
                translation = key;
            }
            translation = translation.replace("\\n", "\n");
            translation = translation.replace("\\\"", "\"");
        }
        int i = 0;
        // "{n}" can be used as a placeholder in the message, it refers
        // to the n-th argument (n starts at 0):
        while (true) {
            Pattern p = Pattern.compile("\\{" + i + "\\}");
            Matcher m = p.matcher(translation);
            if (!m.find()) {
                break;
            }
            try {
                // need to escape backslashes and dollar signs, so that they
                // survive the replaceAll
                translation = m.replaceAll(args[i].replace("\\", "\\\\").replace("$", "\\$"));
            } catch (ArrayIndexOutOfBoundsException e) {
                // happens if the translation contains a "{n}" but there's
                // no parameter for it - fall back to non-translated text:
                log.error("Missing parameter " + i + " for key '" + key + "'");
                return key;
            }
            i++;
        }
        return translation;
    }

}