Skip to content

Latest commit

 

History

History
202 lines (143 loc) · 7.07 KB

I18N.md

File metadata and controls

202 lines (143 loc) · 7.07 KB

i18n

Our implementation is based on the "classic" Jenkins approach of locale. This means we need to store the translations in a specific format and follow naming conventions.

This means you have to store the translations in the src/main/resources folder of your Jenkins plugin. To identify the resources you should choose a unique path within the resource directory. This path will become namespace of the keys of your plugin.

e.g. ./jenkins/plugins/blueocean/dashboard/Messages.properties leads to following namespace jenkins.plugins.blueocean.dashboard.Messages. This is true for all resources store in Jenkins. e.g. core resource jenkins/management/Messages.properties has namespace jenkins.management.Messages

Submit new translations

You can submit a new PR for french (fr) like following

# with aliases:
# g=git
# and git aliases
# co=checkout
# nb=checkout -b
# You may have to fork and use that fork
git clone [email protected]:jenkinsci/blueocean-plugin.git
g co JENKINS-35845
g nb JENKINS-39225_fr

Then create a locale version for your translation. In our case we will create fr

cp ./blueocean-dashboard/src/main/resources/jenkins/plugins/blueocean/dashboard/Messages.properties ./blueocean-dashboard/src/main/resources/jenkins/plugins/blueocean/dashboard/Messages_fr.properties
cp ./blueocean-web/src/main/resources/jenkins/plugins/blueocean/web/Messages.properties ./blueocean-web/src/main/resources/jenkins/plugins/blueocean/web/Messages_fr.properties

Then do your translations and create a new PR in this repository. Please link to JENKINS-39225 in that PR and state which locale you are submitting.

iso-8859-1 only

Since java properties are supporting only iso-8859-1 (at least in Jenkins core) we need to ensure that all special characters like ñ are getting translated into their corresponding utf code \u00F1. There are multiple tools to convert UTF-8 to valid ISO we recommend native2ascii which comes in each JDK.

native2ascii Messages_fr.properties Messages_fr.properties.new
# control that everything is still fine
mv Messages_fr.properties.new Messages_fr.properties

country related variants

We are using traditional java properties based locale as described in Internationalization: Understanding Locale in the Java Platform you can create region/country and variants codes.

If we want to follow the example of above page and create a new translation for language: "en", country; "US" and variant: "SiliconValley"). We could create a file named:

Messages_en_US_SiliconValley.properties

However best practise is to create first the "common" language and then the country specific one.

 Messages_en_au.properties
 Messages_en_US_SiliconValley.properties

Should be

Messages_en.properties
Messages_en_au.properties
Messages_en_US_SiliconValley.properties

where Messages_en.properties is where the general translations are kept and in e.g. Messages_en_au.properties only overrides/adds some keys

Quoting the mozilla wiki page: Locale Codes for the identifiers a browser uses to negotiate languages:

The basic for of our new locale identifiers is <language>-<region>-<dialect>, where the region and dialect parts are optional.

Further information see W3C Internationalization

keys and translations

Our client code is based on i18next so basically you can do everything described there. However since we are using properties and not json format, our keys are flat and cannot be nested.

Further to maintain java compatible we are using numeric arguments for substitutions {0} in our standard components.

  const text = i18n.t('toast.run.stopping', {
    0: name,
    1: runId,
  });

with properties:

toast.run.stopping=Stopping "{0}" #{1}...

If you do not care about java you can use as well named parameters #~name~#.

  const text = i18n.t('toast.run.stopping', {
    name,
    runId,
    interpolation: {
      prefix: '~#',
      suffix: '~#',
    }
  });

with properties:

toast.run.stopping=Stopping "~#name~#" #~#runId~#...

Plural

Note: in case you want to use i18next plural you actually have to use the last example and the param you have to use is count

With interpolation

key.count=__count__ item
key.count_plural=__count__ items

and in your code

const interpolation = {prefix: '__', suffix: '__'};
const options = (number = 0) => {return {count: number, interpolation}};
console.log(translate('key.count', options()))
console.log(translate('key.count', options(1)))
console.log(translate('key.count', options(2)))
console.log(translate('key.count', options(3)))

Without interpolation

There is as well a way to have plural without using interpolation. Basically we "trick" the library by passing the count but not using it.

key.count={0} item
key.count_plural={0} items
key.count.second={1} item
key.count.second_plural={1} items

and in your code

const options = (number = 0, position = 0) => {
    const pluralized = { count: number }
    pluralized[position] = number
    return pluralized
}

// then
console.log(translate('key.count', options()))
console.log(translate('key.count', options(1)))
console.log(translate('key.count', options(2)))
console.log(translate('key.count', options(3)))
console.log(translate('key.count.second', options(0, 1)))
console.log(translate('key.count.second', options(1, 1)))
console.log(translate('key.count.second', options(2, 1)))
console.log(translate('key.count.second', options(3, 1)))

This way you can still use the keys in your java code.

Markdown

In case you are having lager paragraph which need to contain some kind of markup, you can use markdown grammar in the value and later parse that.

<Markdown>
  {t('EmptyState.branches.notSupported')}
</Markdown>

with properties:

EmptyState.branches.notSupported=# Ramas no soportadas\nLa construcci\u00f3n de ramas (Branch) solo funciona con el tipo de job _Multibranch Pipeline_. Esto es solo uno de las muchas razones para cambiar a "Jenkins Pipeline".\n\n[M\u00e1s motivos](https://jenkins.io/doc/book/pipeline-as-code/)

EmptyState.branches.notSupported

Related jira issues

Related PR's

[FIX JENKINS-39225/JENKINS-35845] Internationalisation for Blue Ocean and JDL