aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
authorFabrice Bellingard <bellingard@gmail.com>2011-07-14 18:02:57 +0200
committerFabrice Bellingard <bellingard@gmail.com>2011-07-14 18:04:38 +0200
commit75eeadcdaa600a5d2e2729125f7258ebddeb8101 (patch)
tree8abf6b893fb79ca7c088b1343d066f458d9d482e /plugins
parent35f9971bac62375e6771ce9e39f4b7da786b9f96 (diff)
downloadsonarqube-75eeadcdaa600a5d2e2729125f7258ebddeb8101.tar.gz
sonarqube-75eeadcdaa600a5d2e2729125f7258ebddeb8101.zip
SONAR-2591 API : translation mechanism of rule descriptions
- Added mechanism to look for rule descriptions in HTML files - Put all the rule names and descriptions of Squid Java in the English Pack using this system
Diffstat (limited to 'plugins')
-rw-r--r--plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/i18n/I18nManager.java162
-rw-r--r--plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/i18n/I18nManagerTest.java40
-rwxr-xr-xplugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin.jarbin767 -> 1113 bytes
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test.properties1
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test/fakerule.html2
-rwxr-xr-x[-rw-r--r--]plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin.jarbin1058 -> 1130 bytes
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr.properties2
-rw-r--r--plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr/fakerule.html2
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/java/org/sonar/plugins/i18n/en/EnglishPack.java2
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava.properties12
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ArchitecturalConstraint.html11
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidBreakOutsideSwitch.html18
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidContinueStatement.html16
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/CallToDeprecatedMethod.html2
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ClassCyclomaticComplexity.html14
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/EmptyFile.html7
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MaximumInheritanceDepth.html9
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MethodCyclomaticComplexity.html14
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/NoSonar.html5
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UndocumentedApi.html8
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedPrivateMethod.html13
-rw-r--r--plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedProtectedMethod.html11
-rw-r--r--plugins/sonar-squid-java-plugin/src/main/resources/org/sonar/i18n/squidjava.properties44
23 files changed, 310 insertions, 85 deletions
diff --git a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/i18n/I18nManager.java b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/i18n/I18nManager.java
index b8a4c4e5472..66cd05dc970 100644
--- a/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/i18n/I18nManager.java
+++ b/plugins/sonar-core-plugin/src/main/java/org/sonar/plugins/core/i18n/I18nManager.java
@@ -19,6 +19,7 @@
*/
package org.sonar.plugins.core.i18n;
+import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
@@ -36,6 +37,7 @@ import java.util.Set;
import org.apache.commons.collections.EnumerationUtils;
import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchExtension;
@@ -46,6 +48,7 @@ import org.sonar.api.platform.PluginRepository;
import org.sonar.api.utils.Logs;
import org.sonar.api.utils.SonarException;
+import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -59,6 +62,7 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
private Map<String, String> keys = Maps.newHashMap();
private Properties unknownKeys = new Properties();
private BundleClassLoader bundleClassLoader = new BundleClassLoader();
+ private List<Locale> registeredLocales = Lists.newArrayList();
public I18nManager(PluginRepository pluginRepository, LanguagePack[] languagePacks) {
this.pluginRepository = pluginRepository;
@@ -73,13 +77,16 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
doStart(InstalledPlugin.create(pluginRepository));
}
- void doStart(List<InstalledPlugin> installedPlugins) {
+ protected void doStart(List<InstalledPlugin> installedPlugins) {
Logs.INFO.info("Loading i18n bundles");
Set<URI> alreadyLoadedResources = Sets.newHashSet();
LanguagePack englishPack = findEnglishPack();
for (InstalledPlugin plugin : installedPlugins) {
+ // look first in the classloader of the English I18n Plugin of the Sonar platform
searchAndStoreBundleNames(plugin.key, englishPack.getClass().getClassLoader(), alreadyLoadedResources);
+ // then look in the classloader of the plugin
+ searchAndStoreBundleNames(plugin.key, plugin.classloader, alreadyLoadedResources);
}
for (LanguagePack pack : languagePacks) {
@@ -89,7 +96,7 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
}
}
- private LanguagePack findEnglishPack() {
+ protected LanguagePack findEnglishPack() {
LanguagePack englishPack = null;
for (LanguagePack pack : languagePacks) {
if (pack.getLocales().contains(Locale.ENGLISH)) {
@@ -103,7 +110,7 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
return englishPack;
}
- private void addLanguagePack(LanguagePack languagePack) {
+ protected void addLanguagePack(LanguagePack languagePack) {
LOG.debug("Search for bundles in language pack : {}", languagePack);
for (String pluginKey : languagePack.getPluginKeys()) {
String bundleBaseName = buildBundleBaseName(pluginKey);
@@ -113,16 +120,17 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
ClassLoader classloader = languagePack.getClass().getClassLoader();
LOG.info("Adding locale {} for bundleName : {} from classloader : {}", new Object[] { locale, bundleBaseName, classloader });
bundleClassLoader.addResource(bundlePropertiesFile, classloader);
+ registeredLocales.add(locale);
}
}
}
- private String buildBundleBaseName(String pluginKey) {
+ protected String buildBundleBaseName(String pluginKey) {
return packagePathToSearchIn + "/" + pluginKey;
}
@SuppressWarnings("unchecked")
- private void searchAndStoreBundleNames(String pluginKey, ClassLoader classloader, Set<URI> alreadyLoadedResources) {
+ protected void searchAndStoreBundleNames(String pluginKey, ClassLoader classloader, Set<URI> alreadyLoadedResources) {
String bundleBaseName = buildBundleBaseName(pluginKey);
String bundleDefaultPropertiesFile = bundleBaseName + ".properties";
try {
@@ -168,61 +176,127 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
}
public String message(final Locale locale, final String key, final String defaultText, final Object... objects) {
- String result = defaultText;
+ String translatedMessage = defaultText;
try {
- String bundleBaseName = keys.get(key);
- if (bundleBaseName == null) {
- if (result == null) {
- throw new MissingResourceException("UNKNOWN KEY : Key '" + key
- + "' not found in any bundle, and no default value provided. The key is returned.", bundleBaseName, key);
- }
- LOG.warn("UNKNOWN KEY : Key '{}' not found in any bundle. Default value '{}' is returned.", key, defaultText);
- unknownKeys.put(key, defaultText);
+ if (isKeyForRuleDescription(key)) {
+ // Rule descriptions are in HTML files, not in regular bundles
+ translatedMessage = findRuleDescription(locale, key, defaultText);
} else {
- try {
- ResourceBundle bundle = ResourceBundle.getBundle(bundleBaseName, locale, bundleClassLoader);
-
- String value = bundle.getString(key);
- if ("".equals(value)) {
- if (result == null) {
- throw new MissingResourceException("VOID KEY : Key '" + key + "' (from bundle '" + bundleBaseName
- + "') returns a void value.", bundleBaseName, key);
- }
- LOG.warn("VOID KEY : Key '{}' (from bundle '{}') returns a void value. Default value '{}' is returned.", new Object[] { key,
- bundleBaseName, defaultText });
- } else {
- result = value;
- }
- } catch (MissingResourceException e) {
- if (result == null) {
- throw e;
- }
- LOG.warn("BUNDLE NOT LOADED : Failed loading bundle {} from classloader {}. Default value '{}' is returned.", new Object[] {
- bundleBaseName, bundleClassLoader, defaultText });
- }
+ translatedMessage = findStandardMessage(locale, key, defaultText, objects);
}
} catch (MissingResourceException e) {
LOG.warn(e.getMessage());
- if (result == null) {
+ if (translatedMessage == null) {
// when no translation has been found, the key is returned
return key;
}
} catch (Exception e) {
LOG.error("Exception when retrieving I18n string: ", e);
- if (result == null) {
+ if (translatedMessage == null) {
// when no translation has been found, the key is returned
return key;
}
}
+ return translatedMessage;
+ }
+
+ protected boolean isKeyForRuleDescription(String key) {
+ return StringUtils.startsWith(key, "rule.") && StringUtils.endsWith(key, ".description");
+ }
+
+ protected String findRuleDescription(final Locale locale, final String ruleDescriptionKey, final String defaultText) throws IOException {
+ String translation = defaultText;
+ String ruleNameKey = ruleDescriptionKey.replace(".description", ".name");
+
+ String bundleBaseName = keys.get(ruleNameKey);
+ if (bundleBaseName == null) {
+ handleMissingBundle(ruleNameKey, defaultText, bundleBaseName);
+ } else {
+ Locale localeToUse = defineLocaleToUse(locale);
+ String htmlFilePath = computeHtmlFilePath(bundleBaseName, ruleDescriptionKey, localeToUse);
+ ClassLoader classLoader = bundleClassLoader.getClassLoaderForBundle(bundleBaseName, localeToUse);
+ InputStream stream = classLoader.getResourceAsStream(htmlFilePath);
+ if (stream == null) {
+ throw new MissingResourceException("MISSING RULE DESCRIPTION : file '" + htmlFilePath
+ + "' not found in any bundle. Default value is returned.", bundleBaseName, ruleDescriptionKey);
+ }
+ translation = IOUtils.toString(stream, "UTF-8");
+ }
+
+ return translation;
+ }
+
+ protected Locale defineLocaleToUse(final Locale locale) {
+ Locale localeToUse = locale;
+ if ( !registeredLocales.contains(locale)) {
+ localeToUse = Locale.ENGLISH;
+ }
+ return localeToUse;
+ }
+
+ protected String extractRuleName(String ruleDescriptionKey) {
+ int firstDotIndex = ruleDescriptionKey.indexOf(".");
+ int secondDotIndex = ruleDescriptionKey.indexOf(".", firstDotIndex + 1);
+ int thirdDotIndex = ruleDescriptionKey.indexOf(".", secondDotIndex + 1);
+ return ruleDescriptionKey.substring(secondDotIndex + 1, thirdDotIndex);
+ }
+
+ protected String computeHtmlFilePath(String bundleBaseName, String ruleDescriptionKey, Locale locale) {
+ String ruleName = extractRuleName(ruleDescriptionKey);
+ if (Locale.ENGLISH.equals(locale)) {
+ return bundleBaseName + "/" + ruleName + ".html";
+ } else {
+ return bundleBaseName + "_" + locale.toString() + "/" + ruleName + ".html";
+ }
+ }
+
+ protected String findStandardMessage(final Locale locale, final String key, final String defaultText, final Object... objects) {
+ String translation = defaultText;
+
+ String bundleBaseName = keys.get(key);
+ if (bundleBaseName == null) {
+ handleMissingBundle(key, defaultText, bundleBaseName);
+ } else {
+ try {
+ ResourceBundle bundle = ResourceBundle.getBundle(bundleBaseName, locale, bundleClassLoader);
+
+ String value = bundle.getString(key);
+ if ("".equals(value)) {
+ if (translation == null) {
+ throw new MissingResourceException("VOID KEY : Key '" + key + "' (from bundle '" + bundleBaseName + "') returns a void value.",
+ bundleBaseName, key);
+ }
+ LOG.warn("VOID KEY : Key '{}' (from bundle '{}') returns a void value. Default value '{}' is returned.", new Object[] { key,
+ bundleBaseName, defaultText });
+ } else {
+ translation = value;
+ }
+ } catch (MissingResourceException e) {
+ if (translation == null) {
+ throw e;
+ }
+ LOG.warn("BUNDLE NOT LOADED : Failed loading bundle {} from classloader {}. Default value '{}' is returned.", new Object[] {
+ bundleBaseName, bundleClassLoader, defaultText });
+ }
+ }
if (objects.length > 0) {
LOG.debug("Translation : {}, {}, {}, {}", new String[] { locale.toString(), key, defaultText, Arrays.deepToString(objects) });
- return MessageFormat.format(result, objects);
+ return MessageFormat.format(translation, objects);
} else {
- return result;
+ return translation;
}
}
+ protected void handleMissingBundle(final String key, final String defaultText, String bundleBaseName) {
+ if (defaultText == null) {
+ throw new MissingResourceException("UNKNOWN KEY : Key '" + key
+ + "' not found in any bundle, and no default value provided. The key is returned.", bundleBaseName, key);
+ }
+ LOG.warn("UNKNOWN KEY : Key '{}' not found in any bundle. Default value '{}' is returned.", key, defaultText);
+ unknownKeys.put(key, defaultText);
+ }
+
/**
* @return the unknownKeys
*/
@@ -242,6 +316,16 @@ public final class I18nManager implements I18n, ServerExtension, BatchExtension
resources.put(resourceName, classloader);
}
+ public ClassLoader getClassLoaderForBundle(String bundleBaseName, Locale locale) {
+ StringBuilder resourceName = new StringBuilder(bundleBaseName);
+ if (locale != null && !locale.equals(Locale.ENGLISH)) {
+ resourceName.append("_");
+ resourceName.append(locale);
+ }
+ resourceName.append(".properties");
+ return resources.get(resourceName.toString());
+ }
+
@Override
public URL findResource(String name) {
if (resources.containsKey(name)) {
diff --git a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/i18n/I18nManagerTest.java b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/i18n/I18nManagerTest.java
index f8b8a299975..bf66390c9e6 100644
--- a/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/i18n/I18nManagerTest.java
+++ b/plugins/sonar-core-plugin/src/test/java/org/sonar/plugins/core/i18n/I18nManagerTest.java
@@ -19,7 +19,11 @@
*/
package org.sonar.plugins.core.i18n;
+import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.net.URL;
@@ -106,6 +110,42 @@ public class I18nManagerTest {
Assert.assertEquals(0, manager.getUnknownKeys().size());
}
+ @Test
+ public void testIsKeyForRuleDescription() throws Exception {
+ assertTrue(manager.isKeyForRuleDescription("rule.squid.ArchitecturalConstraint.description"));
+ assertFalse(manager.isKeyForRuleDescription("rule.squid.ArchitecturalConstraint.name"));
+ assertFalse(manager.isKeyForRuleDescription("another.key"));
+ }
+
+ @Test
+ public void testDefineLocaleToUse() throws Exception {
+ assertThat(manager.defineLocaleToUse(Locale.CANADA_FRENCH), is(Locale.CANADA_FRENCH));
+ // Locale not supported => get the English one
+ assertThat(manager.defineLocaleToUse(Locale.JAPAN), is(Locale.ENGLISH));
+ }
+
+ @Test
+ public void testExtractRuleName() throws Exception {
+ assertThat(manager.extractRuleName("rule.squid.ArchitecturalConstraint.description"), is("ArchitecturalConstraint"));
+ }
+
+ @Test
+ public void testComputeHtmlFilePath() throws Exception {
+ assertThat(manager.computeHtmlFilePath("org/sonar/i18n/test", "rule.test.fakerule.description", Locale.FRENCH),
+ is("org/sonar/i18n/test_fr/fakerule.html"));
+ assertThat(manager.computeHtmlFilePath("org/sonar/i18n/test", "rule.test.fakerule.description", Locale.ENGLISH),
+ is("org/sonar/i18n/test/fakerule.html"));
+ }
+
+ @Test
+ public void shouldReturnRuleDescriptionFromHTMLFile() throws Exception {
+ String result = manager.message(Locale.FRENCH, "rule.test.fakerule.description", "foo");
+ assertThat(result, is("<h1>Règle bidon</h1>\nC'est la description de la règle bidon."));
+ // Locale not supported => get the English translation
+ result = manager.message(Locale.JAPAN, "rule.test.fakerule.description", "foo");
+ assertThat(result, is("<h1>Fake Rule</h1>\nThis is the description of the fake rule."));
+ }
+
public static class TestClassLoader extends URLClassLoader {
public TestClassLoader(URL url) {
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin.jar b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin.jar
index a0398457179..14d66ce530d 100755
--- a/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin.jar
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin.jar
Binary files differ
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test.properties b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test.properties
index 88aabfe61a2..7aba645661f 100644
--- a/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test.properties
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test.properties
@@ -2,3 +2,4 @@ it=It
is=is
cold=cold
only.english=Ketchup
+rule.test.fakerule.name=Fake Rule \ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test/fakerule.html b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test/fakerule.html
new file mode 100644
index 00000000000..7e7d84dea8b
--- /dev/null
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/EnglishPlugin/org/sonar/i18n/test/fakerule.html
@@ -0,0 +1,2 @@
+<h1>Fake Rule</h1>
+This is the description of the fake rule. \ No newline at end of file
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin.jar b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin.jar
index ab61bd88697..383c767d26d 100644..100755
--- a/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin.jar
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin.jar
Binary files differ
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr.properties b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr.properties
index cc8efa7afc3..a1d8766e962 100644
--- a/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr.properties
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr.properties
@@ -1,4 +1,4 @@
it=Il
is=fait
cold=froid
-
+rule.test.fakerule.name=R\u00e8gle bidon
diff --git a/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr/fakerule.html b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr/fakerule.html
new file mode 100644
index 00000000000..94c0d0869f8
--- /dev/null
+++ b/plugins/sonar-core-plugin/src/test/resources/I18n/FrenchPlugin/org/sonar/i18n/test_fr/fakerule.html
@@ -0,0 +1,2 @@
+<h1>Règle bidon</h1>
+C'est la description de la règle bidon. \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/java/org/sonar/plugins/i18n/en/EnglishPack.java b/plugins/sonar-i18n-en-plugin/src/main/java/org/sonar/plugins/i18n/en/EnglishPack.java
index de0c47bc0e1..62213736882 100644
--- a/plugins/sonar-i18n-en-plugin/src/main/java/org/sonar/plugins/i18n/en/EnglishPack.java
+++ b/plugins/sonar-i18n-en-plugin/src/main/java/org/sonar/plugins/i18n/en/EnglishPack.java
@@ -28,7 +28,7 @@ import java.util.Locale;
public class EnglishPack extends LanguagePack {
public List<String> getPluginKeys() {
- return Arrays.asList("core", "design");
+ return Arrays.asList("core", "design", "squidjava");
}
public List<Locale> getLocales() {
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava.properties b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava.properties
new file mode 100644
index 00000000000..1470cf5dfd2
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava.properties
@@ -0,0 +1,12 @@
+rule.squid.ArchitecturalConstraint.name=Architectural constraint
+rule.squid.AvoidBreakOutsideSwitch.name=Avoid using 'break' branching statement outside a 'switch' statement
+rule.squid.AvoidContinueStatement.name=Avoid using 'continue' branching statement
+rule.squid.CallToDeprecatedMethod.name=Avoid use of deprecated method
+rule.squid.ClassCyclomaticComplexity.name=Avoid too complex class
+rule.squid.EmptyFile.name=Empty file
+rule.squid.MaximumInheritanceDepth.name=Avoid too deep inheritance tree
+rule.squid.MethodCyclomaticComplexity.name=Avoid too complex method
+rule.squid.NoSonar.name=Avoid use of //NOSONAR marker
+rule.squid.UndocumentedApi.name=Undocumented API
+rule.squid.UnusedPrivateMethod.name=Unused private method
+rule.squid.UnusedProtectedMethod.name=Unused protected method
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ArchitecturalConstraint.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ArchitecturalConstraint.html
new file mode 100644
index 00000000000..2af771f2944
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ArchitecturalConstraint.html
@@ -0,0 +1,11 @@
+<p>A source code comply to an architectural model when it fully
+ adheres to a set of architectural constraints. A constraint allows to
+ deny references between classes by pattern.</p>
+<p>You can for instance use this rule to :</p>
+<ul>
+ <li>forbid access to **.web.** from **.dao.** classes</li>
+ <li>forbid access to java.util.Vector, java.util.Hashtable and
+ java.util.Enumeration from any classes</li>
+ <li>forbid access to java.sql.** from **.ui.** and **.web.**
+ classes</li>
+</ul> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidBreakOutsideSwitch.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidBreakOutsideSwitch.html
new file mode 100644
index 00000000000..d691586270a
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidBreakOutsideSwitch.html
@@ -0,0 +1,18 @@
+<p>The use of the 'break' branching statement increases the
+ essential complexity of the source code and so prevents any refactoring
+ of this source code to replace all well structured control structures
+ with a single statement.</p>
+<p>For instance, with the following java program fragment, it's not
+ possible to apply the 'extract method' refactoring pattern :</p>
+<pre>
+mylabel : for (int i = 0 ; i< 3; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ doSomething();
+ if (checkSomething()) {
+ break mylabel;
+ }
+ }
+}
+</pre>
+<p>The use of the 'break' branching statement is only authorized
+ inside a 'switch' statement.</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidContinueStatement.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidContinueStatement.html
new file mode 100644
index 00000000000..d52b67eba23
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/AvoidContinueStatement.html
@@ -0,0 +1,16 @@
+<p>The use of the 'continue' branching statement increase the
+ essential complexity of the source code and so prevent any refactoring
+ of this source code to replace all well structured control structures
+ with a single statement.</p>
+<p>For instance, in the following java program fragment, it's not
+ possible to apply the 'extract method' refactoring pattern :</p>
+<pre>
+mylabel : for(int i = 0 ; i< 3; i++) {
+ for (int j = 0; j < 4 ; j++) {
+ doSomething();
+ if (checkSomething()) {
+ continue mylabel;
+ }
+ }
+}
+</pre> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/CallToDeprecatedMethod.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/CallToDeprecatedMethod.html
new file mode 100644
index 00000000000..146b8f3b13d
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/CallToDeprecatedMethod.html
@@ -0,0 +1,2 @@
+<p>Once deprecated, a method should no longer be used as it means
+ that the method might be removed sooner or later.</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ClassCyclomaticComplexity.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ClassCyclomaticComplexity.html
new file mode 100644
index 00000000000..a2837927eeb
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/ClassCyclomaticComplexity.html
@@ -0,0 +1,14 @@
+<p>The Cyclomatic Complexity is measured by the number of (&&, ||)
+ operators and (if, while, do, for, ?:, catch, switch, case, return,
+ throw) statements in the body of a class plus one for each constructor,
+ method (but not getter/setter), static initializer, or instance
+ initializer in the class. The last return stament in method, if exists,
+ is not taken into account.</p>
+<p>
+ Even when the Cyclomatic Complexity of a class is very high, this
+ complexity might be well distributed among all methods. Nevertheless,
+ most of the time, a very complex class is a class which breaks the <a
+ href='http://en.wikipedia.org/wiki/Single_responsibility_principle'>Single
+ Responsibility Principle</a> and which should be re-factored to be split
+ in several classes.
+</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/EmptyFile.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/EmptyFile.html
new file mode 100644
index 00000000000..9b3a8772360
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/EmptyFile.html
@@ -0,0 +1,7 @@
+<p>Detect empty files, which do not have any lines of code.</p>
+<p>Example:</p>
+<pre>
+//package org.foo;
+//
+//public class Bar {}
+</pre> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MaximumInheritanceDepth.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MaximumInheritanceDepth.html
new file mode 100644
index 00000000000..61fc1884394
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MaximumInheritanceDepth.html
@@ -0,0 +1,9 @@
+<p>Inheritance is certainly one of the most valuable concept of
+ object-oriented programming. It's a way to compartmentalize and reuse
+ code by creating collections of attributes and behaviors called classes
+ which can be based on previously created classes. But abusing of this
+ concept by creating a deep inheritance tree can lead to very complex
+ and unmaintainable source code.</p>
+<p>Most of the time a too deep inheritance tree is due to bad object
+ oriented design which has led to systematically use 'inheritance' when
+ 'composition' would suit better.</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MethodCyclomaticComplexity.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MethodCyclomaticComplexity.html
new file mode 100644
index 00000000000..d50d8825d7a
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/MethodCyclomaticComplexity.html
@@ -0,0 +1,14 @@
+<p>The Cyclomatic Complexity is measured by the number of
+ (&amp;&amp;, ||) operators and (if, while, do, for, ?:, catch, switch,
+ case, return, throw) statements in the body of a class plus one for
+ each constructor, method (but not getter/setter), static initializer,
+ or instance initializer in the class. The last return stament in
+ method, if exists, is not taken into account.</p>
+<p>
+ Even when the Cyclomatic Complexity of a class is very high, this
+ complexity might be well distributed among all methods. Nevertheless,
+ most of the time, a very complex class is a class which breaks the <a
+ href="http://en.wikipedia.org/wiki/Single_responsibility_principle">Single
+ Responsibility Principle</a> and which should be re-factored to be split
+ in several classes.
+</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/NoSonar.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/NoSonar.html
new file mode 100644
index 00000000000..c56106d83c1
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/NoSonar.html
@@ -0,0 +1,5 @@
+<p>Any violation to quality rule can be deactivated with the
+ //NOSONAR marker. This marker is pretty useful to exclude
+ false-positive results but sometimes it can abusively be used to hide
+ real quality flaws.</p>
+<p>This rule allows to track and/or forbid use of this marker</p> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UndocumentedApi.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UndocumentedApi.html
new file mode 100644
index 00000000000..9745f9eab3d
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UndocumentedApi.html
@@ -0,0 +1,8 @@
+<p>Check that each public class, interface, method and constructor
+ has a Javadoc comment. The following public methods/constructors are
+ not concerned by this rule :</p>
+<ul>
+ <li>Getter / Setter</li>
+ <li>Method with @Override annotation</li>
+ <li>Empty constructor</li>
+</ul> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedPrivateMethod.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedPrivateMethod.html
new file mode 100644
index 00000000000..fd3901a49fa
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedPrivateMethod.html
@@ -0,0 +1,13 @@
+<p>Private methods that are never executed are dead code. Dead code
+ means unnecessary, inoperative code that should be removed. This helps
+ in maintenance by decreasing the maintained code size, making it easier
+ to understand the program and preventing bugs from being introduced.</p>
+<p>In the following two cases, private methods are not considered as
+ dead code by Sonar :</p>
+<ul>
+ <li>Private empty constructors that are intentionally used to
+ prevent any direct instantiation of a class.</li>
+ <li>Private methods : readObject(...), writeObject(...),
+ writeReplace(...), readResolve(...) which can contractually be used
+ when implementing the Serializable interface.</li>
+</ul> \ No newline at end of file
diff --git a/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedProtectedMethod.html b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedProtectedMethod.html
new file mode 100644
index 00000000000..ec8ed1032fd
--- /dev/null
+++ b/plugins/sonar-i18n-en-plugin/src/main/resources/org/sonar/i18n/squidjava/UnusedProtectedMethod.html
@@ -0,0 +1,11 @@
+<p>Protected methods that are never used by any classes in the same
+ project are strongly suspected to be dead code. Dead code means
+ unnecessary, inoperative code that should be removed. This helps in
+ maintenance by decreasing the maintained code size, making it easier to
+ understand the program and preventing bugs from being introduced.</p>
+<p>In the following case, unused protected methods are not
+ considered as dead code by Sonar :</p>
+<ul>
+ <li>Protected methods which override a method from a parent class.</li>
+ <li>Protected methods of an abstract class.</li>
+</ul> \ No newline at end of file
diff --git a/plugins/sonar-squid-java-plugin/src/main/resources/org/sonar/i18n/squidjava.properties b/plugins/sonar-squid-java-plugin/src/main/resources/org/sonar/i18n/squidjava.properties
deleted file mode 100644
index 65fd6542851..00000000000
--- a/plugins/sonar-squid-java-plugin/src/main/resources/org/sonar/i18n/squidjava.properties
+++ /dev/null
@@ -1,44 +0,0 @@
-rule.squid.ArchitecturalConstraint.name=Architectural constraint
-rule.squid.ArchitecturalConstraint.description=<p>A source code comply to an architectural model when it fully adheres to a set of architectural constraints. A constraint allows to deny references between classes by pattern.</p><p>You can for instance use this rule to :</p><ul><li>forbid access to **.web.** from **.dao.** classes</li><li>forbid access to java.util.Vector, java.util.Hashtable and java.util.Enumeration from any classes</li><li>forbid access to java.sql.** from **.ui.** and **.web.** classes</li></ul>
-rule.squid.AvoidBreakOutsideSwitch.name=Avoid using 'break' branching statement outside a 'switch' statement
-rule.squid.AvoidBreakOutsideSwitch.description=<p>The use of the 'break' branching statement increases the essential complexity of the source code and so prevents any refactoring of this source code to replace all well structured control structures with a single statement.</p><p>For instance, with the following java program fragment, it's not possible to apply the 'extract method' refactoring pattern :</p><pre>mylabel : for (int i = 0 ; i< 3; i++) {\
- for (int j = 0; j < 4 ; j++) {\
- doSomething();\
- if (checkSomething()) {\
- break mylabel;\
- }\
- }\
-}\
-</pre><p>The use of the 'break' branching statement is only authorized inside a 'switch' statement.</p>
-rule.squid.AvoidContinueStatement.name=Avoid using 'continue' branching statement
-rule.squid.AvoidContinueStatement.description=<p>The use of the 'continue' branching statement increase the essential complexity of the source code and so prevent any refactoring of this source code to replace all well structured control structures with a single statement.</p><p>For instance, in the following java program fragment, it's not possible to apply the 'extract method' refactoring pattern :</p><pre>mylabel : for(int i = 0 ; i< 3; i++) {\
- for (int j = 0; j < 4 ; j++) {\
- doSomething();\
- if (checkSomething()) {\
- continue mylabel;\
- }\
- }\
-}\
-</pre>
-rule.squid.CallToDeprecatedMethod.name=Avoid use of deprecated method
-rule.squid.CallToDeprecatedMethod.description=<p>Once deprecated, a method should no longer be used as it means that the method might be removed sooner or later.</p>
-rule.squid.ClassCyclomaticComplexity.name=Avoid too complex class
-rule.squid.ClassCyclomaticComplexity.description=<p>The Cyclomatic Complexity is measured by the number of (&&, ||) operators and (if, while, do, for, ?:, catch, switch, case, return, throw) statements in the body of a class plus one for each constructor, method (but not getter/setter), static initializer, or instance initializer in the class. The last return stament in method, if exists, is not taken into account.</p><p>Even when the Cyclomatic Complexity of a class is very high, this complexity might be well distributed among all methods. Nevertheless, most of the time, a very complex class is a class which breaks the <a href='http://en.wikipedia.org/wiki/Single_responsibility_principle'>Single Responsibility Principle</a> and which should be re-factored to be split in several classes.</p>
-rule.squid.EmptyFile.name=Empty file
-rule.squid.EmptyFile.description=Detect empty files, which do not have any lines of code. Example: <pre>\
-//package org.foo;\
-//\
-//public class Bar {}\
-</pre>
-rule.squid.MaximumInheritanceDepth.name=Avoid too deep inheritance tree
-rule.squid.MaximumInheritanceDepth.description=<p>Inheritance is certainly one of the most valuable concept of object-oriented programming. It's a way to compartmentalize and reuse code by creating collections of attributes and behaviors called classes which can be based on previously created classes. But abusing of this concept by creating a deep inheritance tree can lead to very complex and unmaintainable source code.</p><p>Most of the time a too deep inheritance tree is due to bad object oriented design which has led to systematically use 'inheritance' when 'composition' would suit better.</p>
-rule.squid.MethodCyclomaticComplexity.name=Avoid too complex method
-rule.squid.MethodCyclomaticComplexity.description=<p>The Cyclomatic Complexity is measured by the number of (&&, ||) operators and (if, while, do, for, ?:, catch, switch, case, return, throw) statements in the body of a constructor, method, static initializer, or instance initializer. The minimun Cyclomatic Complexity of a method is 1 and the last return stament, if exists, is not taken into account. The more complex is a method, the more possible different paths through the source code exist. Generally 1-4 is considered good, 5-7 ok, 8-10 consider re-factoring, and 11+ re-factor now. Indeed above 10, it's pretty difficult to be able to think about all possible paths when maintaining the source code, so the risk of regression increases exponentially.</p>
-rule.squid.NoSonar.name=Avoid use of //NOSONAR marker
-rule.squid.NoSonar.description=<p>Any violation to quality rule can be deactivated with the //NOSONAR marker. This marker is pretty useful to exclude false-positive results but sometimes it can abusively be used to hide real quality flaws.</p><p>This rule allows to track and/or forbid use of this marker</p>
-rule.squid.UndocumentedApi.name=Undocumented API
-rule.squid.UndocumentedApi.description=<p>Check that each public class, interface, method and constructor has a Javadoc comment. The following public methods/constructors are not concerned by this rule :</p><ul><li>Getter / Setter</li><li>Method with @Override annotation</li><li>Empty constructor</li></ul>
-rule.squid.UnusedPrivateMethod.name=Unused private method
-rule.squid.UnusedPrivateMethod.description=<p>Private methods that are never executed are dead code. Dead code means unnecessary, inoperative code that should be removed. This helps in maintenance by decreasing the maintained code size, making it easier to understand the program and preventing bugs from being introduced.</p><p>In the following two cases, private methods are not considered as dead code by Sonar :</p><ul><li>Private empty constructors that are intentionally used to prevent any direct instantiation of a class.</li><li>Private methods : readObject(...), writeObject(...), writeReplace(...), readResolve(...) which can contractually be used when implementing the Serializable interface.</li></ul>
-rule.squid.UnusedProtectedMethod.name=Unused protected method
-rule.squid.UnusedProtectedMethod.description=<p>Protected methods that are never used by any classes in the same project are strongly suspected to be dead code. Dead code means unnecessary, inoperative code that should be removed. This helps in maintenance by decreasing the maintained code size, making it easier to understand the program and preventing bugs from being introduced.</p><p>In the following case, unused protected methods are not considered as dead code by Sonar :</p><ul><li>Protected methods which override a method from a parent class.</li></ul><ul><li>Protected methods of an abstract class.</li></ul>