This page gives guidelines to I18n for:
- Plugin developers who would like to apply the i18n mechanism in their own plugin, so that this plugin can be available in several languages
- People who would like to help the community by making the platform available in a new language
Principles
Although the basics of the i18n mechanism are the same for every part of the ecosystem, the packaging differs depending on what you are developing:
- Translations for the SonarQube Platform: making the SonarQube Platform available in a new language requires you to develop and publish a new Language Pack plugin.
- By default SonarQube embeds the English Pack.
- All other Language Pack plugins (like the French Pack plugin) are hosted in the Plugins Forge, are maintained by the community, and are available through Update Center (category "Localization").
- Translations for the SonarQube Community Plugins: open-source plugins from the SonarQube Community (hosted in the Plugins Forge) must embed only the bundles for the default locale (en). Translations will be done in the Language Pack plugins.
- Translations for other Plugins: closed-source/commercial/independent plugins must embed the bundles for the default locale and the translations for every language they want to support.
To sum up
- SonarQube Platform and SonarQube Community Plugins rely on Language Pack plugins for translations
- Other independent SonarQube plugins must themselves embed all the translations they need
Translation Bundles
There are two types of files for localized messages:
Properties files
- These are regular properties files with key/value pairs where you will put most translations
- These files must be stored in the
org.sonar.l10n
package (usually in the src/main/resources/org/sonar/l10n directory) - The names of these files must follow the convention "<key of the plugin to translate>_<language>.properties", for example "technicaldebt_fr.properties" or "core_fr.properties". See sonar-packaging-maven-plugin for details on plugin key derivation.
Messages can accept arguments. Such entries would look like:
myplugin.foo=This is a message with 2 params: the first "{0}" and the second "{1}".
HTML files
- They are used for rule descriptions, which might be long and need HTML tags
- The files should be stored in the
org.sonar.l10n.<key of the plugin to translate>_<language>.rules.<repository key>
package.- Before SonarQube 3.0, the location is
org.sonar.l10n.<plugin key>_<language>
package. Backward compatibility is ensured for l10n plugins which use this old location.
- Before SonarQube 3.0, the location is
- The names of these files should correspond to the keys of the rules they translate
- Example: the French description of the Squid Architectural Constraint rule is: src/main/resources/org/sonar/l10n/squidjava_fr/rules/squid/ArchitecturalConstraint.html (since squidjava is the plugin key, and squid is the repository key)
- Prior to SonarQube 3.0: src/main/resources/org/sonar/l10n/squidjava_fr/ArchitecturalConstraint.html
UTF-8 encoding
In the Java API, properties files are supposed to be encoded in ISO-8859 charset. Without good tooling, it can be quite annoying to write translations for languages that do not fit in this charset.
This is why we decided to encode the properties files in UTF-8, and let Maven turn them into ASCII at build time thanks to native2ascii-maven-plugin (check the French plugin pom.xml). This makes the process of writing translations with a standard editor far easier.
HTML files must also be encoded in UTF-8.
Naming conventions for keys
Here is what you need to know about conventions for keys:
Key | Description | Example |
---|---|---|
| Metric name |
|
| Metric description |
|
| Name of notification channel |
|
| Subscription to notification channel |
|
| Rule name |
|
| Description of rule parameter |
|
dashboard.<key>.name | Dashboard name, since 2.14. | dashboard.Hotstpots.name=Point Chauds |
| Qualifier name, since 2.13. |
|
| Widget name |
|
| Widget description |
|
widget.<key>.property.<property key>.name | Name of widget property | widget.hotspot_most_violated_rules.property.defaultSeverity.name=Default severity |
widget.<key>.property.<property key>.desc | Description of widget property | widget.hotspot_most_violated_rules.property.defaultSeverity.desc=If selected, |
widget.<key>.property.<property>.option.<option>.name | Name of item of dropdown list | |
| Any other widget message |
|
| Page names shown in the left sidebar |
|
| Any other keys used in a page |
|
| Category name of properties, since 2.11 |
|
property.category.<category key>.description | Short description of category of properties, since 3.6 | property.category.General.description=General properties of SonarQube |
property.category. | Subcategory name of properties, since 3.6 | property.category.exclusions.global=Global exclusions |
property.category. | Short description of subcategory of properties, since 3.6 | property.category.exclusions.global.description=Configuration of global exclusions |
| Property name, since 2.11 |
|
| Property description, since 2.11 |
|
| Any other keys used by plugin |
|
How to use localized messages?
Ruby on Rails API
This API is used when implementing Ruby widgets or pages. It's really simple, and works with just a single method:
message(property_key, options={})
Options are :
:default
is the default value when the property key does not exist in bundles. If it's not set, then the key itself is returned.:params
is an array of string message arguments.
Examples :
message('cloud.size') message('cloud.size', :default => 'Cloud') message('with.arguments', :params => ['First', 'Two']) message('with.arguments', :params => ['First', 'Two'], :default => 'Not found')
Of course, the Rails framework provides other formatting methods like :
# localize dates or datetimes l(date_or_time)
Java API
The component org.sonar.api.i18n.I18n
is available for server extensions. Batch extensions are not supported yet and can not load bundles.
How to handle a Language Pack
A Language Pack defines bundles for the SonarQube platform and for the SonarQube community plugins.
Creating a new Language Pack
The easiest way to create a new pack is to copy the French Pack and adapt it to your language.
Maintaining a Language Pack
In the pom file, set the versions of the plugins you want to translate:
<properties> ... <!-- Versions of the plugins translated by this language pack --> <bundle.abacus>0.1</bundle.abacus> <bundle.branding>0.3</bundle.branding> <bundle.core>3.4-RC3</bundle.core> <bundle.javasquid>1.1</bundle.javasquid> <bundle.jira>1.0</bundle.jira> <bundle.motionchart>1.4</bundle.motionchart> <bundle.squidjava>1.0</bundle.squidjava> <bundle.violationdensity>1.2</bundle.violationdensity> ... </properties>
When it's time to update your language pack for a new version of SonarQube or a plugin, the easiest way to see what keys are missing is to run:
mvn test
If the build fails, it means that some keys are missing. Go to target/l10n to check the reports for each bundle.
Missing keys are listed under 'Missing translations are:'
Missing translations are: code_viewer.no_info_displayed_due_to_security=Due to security settings, no information can be displayed. comparison.version.latest=LATEST ...
Each time you add a new bundle or update an existing one, please create a JIRA ticket on the corresponding L10n component in order to track changes.
How to localize an independent plugin
This section applies if you are developing a commercial / closed-source plugin, or an open-source plugin that is not part of the SonarSonarQube Community Plugins forge.
If your plugin falls in this category, it must embed its own bundles. Bundles must be added to src/main/resources with the following naming convention :
- Standard messages : org/sonar/l10n/<plugin key>_<language>.properties
- Rule descriptions :
- org/sonar/l10n/<plugin key>_<language>/rules/<repository key>/*.html
- Prior to SonarSonarQube 3.0: org/sonar/l10n/<plugin key>_<language>/*.html
- org/sonar/l10n/<plugin key>_<language>/rules/<repository key>/*.html
The default bundle is mandatory, and must be the English translation. For example the plugin with key "mysonarplugin" must define the following files in order to enable the French translation:
- org/sonar/l10n/mysonarplugin.properties
- org/sonar/l10n/mysonarplugin_fr.properties