001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2013 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.utils;
021
022import com.google.common.collect.Iterators;
023import com.google.common.collect.Lists;
024import org.slf4j.Logger;
025import org.slf4j.LoggerFactory;
026
027import java.util.*;
028
029public class LocalizedMessages extends ResourceBundle {
030
031  private static final Logger LOG = LoggerFactory.getLogger(LocalizedMessages.class);
032
033  private Locale locale;
034  private List<ResourceBundle> bundles;
035
036  /**
037   * Constructs a resource bundle from a list of other resource bundles. If
038   * there are duplicate keys, the key from the resource bundle with the
039   * smallest index takes precedence.
040   */
041  public LocalizedMessages(Locale locale, String... basenames) {
042    this.locale = locale;
043    bundles = new ArrayList<ResourceBundle>(basenames.length);
044    for (String basename : basenames) {
045      bundles.add(getBundle("sonar.bundles." + basename, locale));
046    }
047  }
048
049  @Override
050  public Locale getLocale() {
051    return locale;
052  }
053
054  public String format(String key, Object... args) {
055    return format(true, key, args);
056  }
057
058  public String formatQuietly(String key, Object... args) {
059    return format(false, key, args);
060  }
061
062  private String format(boolean logIfMissing, String key, Object... args) {
063    try {
064      String message = getString(key);
065      return String.format(locale, message, args);
066
067    } catch (MissingResourceException e) {
068      if (logIfMissing) {
069        LOG.warn("Missing translation: key==" + key + ",locale=" + locale);
070      }
071      return key;
072    }
073  }
074
075  /*
076   * (non-Javadoc)
077   *
078   * @see java.util.ResourceBundle#getKeys()
079   */
080  @Override
081  public Enumeration<String> getKeys() {
082    return new KeyEnumeration();
083  }
084
085  /*
086    * (non-Javadoc)
087    *
088    * @see java.util.ResourceBundle#handleGetObject(java.lang.String)
089    */
090  @Override
091  protected Object handleGetObject(String key) {
092    for (ResourceBundle b : bundles) {
093      try {
094        return b.getObject(key);
095      } catch (MissingResourceException mre) {
096        // iterate 
097      }
098    }
099    throw new MissingResourceException(null, null, key);
100  }
101
102  private class KeyEnumeration implements Enumeration<String> {
103    private Set<String> keys = new HashSet<String>();
104
105    // Set iterator to simulate enumeration
106    private Iterator<String> i;
107
108    // Constructor
109    {
110      for (ResourceBundle b : bundles) {
111        keys.addAll(Lists.newArrayList(Iterators.forEnumeration(b.getKeys())));
112      }
113      i = keys.iterator();
114    }
115
116    public boolean hasMoreElements() {
117      return i.hasNext();
118    }
119
120    public String nextElement() {
121      return i.next();
122    }
123  }
124}