dashy/docs/multi-language-support.md
Harald Töpfer ab450a13e4
Update multi-language-support.md
Fixed the code example in ## Config File

`lang: de` throws a `Validation Warning: .appConfig should NOT have additional property: lang` while `language: de` works as expected.
2023-09-05 14:30:54 +02:00

7.4 KiB

Internationalization

Internationalization is the process of making an application available in other languages. This is important, as not everyone is a native English speaker. This page explains how you can switch languages, how to add a new language, and how to make text translatable when writing a new component.


Setting Language

By default, Dashy will attempt to use the language of your browser or system. If a translation for your language does not yet exist, it will fallback to English.

In the UI

You can manually select your language in the UI. Under the Config Menu, click the Language button, and select your language from the dropdown menu. Your preference will be saved in local storage.

Config File

You can also set your language in the config file. Specify the ISO code of one of the supported languages, under appConfig.lang. For example:

appConfig:
  language: de

Available Languages

At the time of writing the following languages are supported: en, zh-CN, nl, fr, de, es, sl, it, pt, ru, ar, hi, ja, but an up-to-date list of all implemented translations can be found in ./src/utils/languages.js. Languages are specified by their 2-digit ISO-639 code, or sometimes a 4-digit code if it's a regional dialect.


Adding a new Language

Dashy is using vue-i18n to manage multi-language support.

Adding a new language is pretty straightforward, with just three steps:

1. Create a new Language File

Create a new JSON file in ./src/assets/locales for your language.

You should name it with the 2-digit ISO-639 code for your locale (e.g. for German de.json, French fr.json or Spanish es.json) - You can find a list of all ISO codes at iso.org. If your language is a specific dialect or regional translation, then use the Posfix CLDR format, where, e.g. en-GB.json (British English), es-MX.json (Spanish, in Mexico) or zh-CN.json (Chinese, simplified) - A list of which can be found here

2. Translate

Using en.json as an example, translate the JSON values to your language, while leaving the keys as they are. It's fine to leave out certain items, as if they're missing they will fall-back to English. If you see any attribute which include curly braces ({xxx}), then leave the inner value of these braces as is, as this is for variables.

{
  "theme-maker": {
    "export-button": "Benutzerdefinierte Variablen exportieren",
    "reset-button": "Stile zurücksetzen für",
    "show-all-button": "Alle Variablen anzeigen",
    "save-button": "Speichern",
    "cancel-button": "Abbrechen",
    "saved-toast": "{theme} Erfolgreich aktualisiert",
    "reset-toast": "Benutzerdefinierte Farben für {theme} entfernt"
  },
}

3. Add your file to the app

In ./src/utils/languages.js, you need to do 2 small things:

First import your new translation file, do this at the top of the page. E.g. import de from '@/assets/locales/de.json';

Second, add it to the array of languages, e.g:

export const languages = [
  {
    name: 'English',
    code: 'en',
    locale: en,
    flag: '🇬🇧',
  },
  {
    name: 'German', // The name of your language
    code: 'de', // The ISO code of your language
    locale: de, // The name of the file you imported (no quotes)
    flag: '🇩🇪', // An optional flag emoji
  },
];

You can also add your new language to the readme, under the Language Switching section and optionally include your name/ username if you'd like to be credited for your work. Done!

If you are not comfortable with making pull requests, or do not want to modify the code, then feel free to instead send the translated file to me, and I can add it into the application. I will be sure to credit you appropriately.


Adding New Text to a Component

If you're working on a new component, then any text that is displayed to the user should be extracted out of the component, and stored in the file. This also applies to any existing components, that might have been forgotten to be translated. Thankfully, everything is already setup, so this is a pretty easy job.

1. Add Translated Text

Firstly, go to ./src/assets/locales/en.json, and either find the appropriate section, or create a new section. Lets say you're new component is called my-widget, you could add "my-widget": {} to store all your text as key-value-pairs. E.g.

"my-widget": {
	"awesome-text": "I am some text, that will be seen by the user"
}

Note that you must add English translations for all text. Missing languages are not a problem, as they will always fallback to English, but if the English is missing, then nothing can be displayed.

2. Use Text within Component

Once your text is in the translation file, you can now use it within your component. There is a global $t function, with takes the key of your new translation, and returns the value. For example:

<p>{{ $t('my-widget.awesome-text') }}</p>

Note that the {{ }} just tells Vue that this is JavaScript/ dynamic. This will render: <p>I am some text, that will be seen by the user</p>

If you need to display text programmatically, from within the components JavaScript (e.g. in a toast popup), then use this.$t. For example: alert(this.$t('my-widget.awesome-text')).

You may also need to pass a variable to be displayed within a translation. Vue I18n supports Interpolations using mustache-like syntax.

For example, you would set your translation to:

{
	"welcome-message": "Hello {name}!"
}

And then pass that variable (name) within a JSON object as the second parameter on $t, like:

$t('welcome-message', { name: 'Alicia' })

Which will render:

Hello Alicia!

There are many other advanced features, including Pluralization, Datetime & Number Formatting, Message Support and more, all of which are outlined in the Vue-i18n Docs.

Basic Example

Using the search bar as an example, this would look something like:

In ./src/components/Settings/SearchBar.vue:

<template>
  <form>
    <label for="search-input">{{ $t('search.search-label') }}</label>
    <input
      v-model="searchValue"
      :placeholder="$t('search.search-placeholder')"
    />
  </form>
</template>

Then in ./src/assets/locales/en.json:

{
"search": {
    "search-label": "Search",
    "search-placeholder": "Start typing to filter",
  },
  ...
}