i18n

HDS comes with a built-in internationalization (i18n) system.

App Internationalization

"App Internationalization" means that the app is translated at the runtime. This is the method to be used in dynamic apps such as the Console.

Step 1: Add JSON Files

First, add the strings in JSON files, preferable in a locales directory. Set the file name to the language code (ex: en.json).

{
    "home": {
        "title": "Welcome to HDS",
        "subtitle": "This is a subtitle",
        "welcome": "Welcome, {name}!"
    },
    "footer": {
        "about": "About us",
        "contact": "Contact us"
    }
}

Step 2: Add the InternationalizationProvider

Next, add the InternationalizationProvider to the +layout.svelte file (highest level possible) and set up the languages you want to support within the provider.

<script>
    import InternationalizationProvider from "@hyvor/design/components";
    import en from './locale/en.json';
</script>

<InternationalizationProvider
    languages={[
        {
            code: 'en',
            flag: '🇺🇸',
            name: 'English',
            region: 'United States',
            strings: en,
            default: true,
        },
        {
            code: 'fr',
            flag: '🇫🇷',
            name: 'Français',
            region: 'France',
            loader: () => import('./locale/fr.json')
        }
    ]}
>
    <slot />
</InternationalizationProvider>
  • The default language strings should be imported statically. Also, set the default property to true.
  • The other languages can be loaded dynamically using the loader property.

Step 3: Use the Strings

Now, you can use the strings in your components using the <T> component.

<T key="home.title" />
<T key="welcome" params={{ name: 'John' }} />

Strings

HDS uses the ICU MessageFormat for string formatting. Strings are passed using the intl-messageformat library. Here are some examples:

Variables

You can use variables in the strings.

{
    "welcome": "Welcome, {name}!"
}

Then, you can pass the value using the params prop.

<T key="welcome" params={{ name: 'John' }} />

You can also set the value to a reactive variable.

<T key="welcome" params={{ name: myName }} />

Nested keys

You can use nested keys to organize the strings.

{
    "home": {
        "title": "Welcome to HDS",
        "subtitle": "This is a subtitle"
    }
}

Then, use dot notation to access the nested keys.

<T key="home.title" />

Formatting

Dates

{
    "start": "Starts on {startDate, date, long}"
}

Then, pass the date as a parameter.

<T key="start" params={{ startDate: new Date() }} />

Numbers

{
    "price": "The price is {price, number, :: compact-short currency/EUR}"
}

Then, pass the number as a parameter.

<T key="price" params={{ price: 100 }} />

The result will be The price is €100.

Plural

The plural format is used to handle pluralization. The value is expected to be a number. These plural categories are supported:

  • zero
  • one
  • two
  • few
  • many
  • other
  • =value

Here is an example (both lines produce the same result):

{
    "users": "{count} {count, plural, one {user} other {users}}",
    "usersShort": "{count, plural, one {# user} other {# users}}"
}
<T key="users" params={{ count: 10 }} />

See the Message Syntax documentation on formatjs.io for more available formatting options.

Components

You can pass components as parameters to the strings. In the following code, <a></a> is a placeholder for a component. The content within it ("this article") will be sent to the component as the children prop.

{
    "withComponent": "For advanced features, check out <a>this article</a>"
}

Then, pass the component as a parameter.

<T key="withComponent" params={{ 
    a: {component: MyCustomLink} 
}} />

Your MyCustomLink component will look like this:

<script lang="ts">
    export let children: string;
</script>
<a>
    {children} <SomeIcon />
</a>

You may pass additional to the component.

<T key="withComponent" params={{ 
    a: {
        component: MyCustomLink, 
        props: {
            href: '/advanced'
        }
    } 
}} />
Components are rendered only when the frontend is hydrated. In SSR, only the strings are rendered.

t Function

There is also a t utility function that can be used to get translated strings in the code.

const title = t('home.title')
const welcome = t('welcome', { name: 'John' })

The t function depends on the Svelte getContext function. So, it can only be used in Svelte Components or any typescript functions that are called in the component top-level. If you want to use it in other places, send the i18n context to the function.

import { getContext } from 'svelte';

const i18n = getContext('i18n');

onMount(() => {
    const title = t('home.title', {}, i18n)
    const welcome = t('welcome', { name: 'John' }, i18n)
})