HDS comes with a built-in internationalization (i18n) system.
"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.
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"
}
}
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>
strings
should be imported statically. Also, set the default
property to true
.loader
property.To avoid repitition and enfore type safety, set up an export in a i18n.ts
file. Use the
type of the default language JSON file.
import type { InternationalizationService } from "@hyvor/design/components";
import { getContext } from "svelte";
import type enJson from "../locale/en.json";
type I18nType = InternationalizationService<typeof enJson>;
export function getI18n() {
return getContext<I18nType>("i18n");
}
Now, you can use the strings in your components using the helper method and the t
function and the T
component.
<script>
import { getI18n } from '$lib/i18n';
const I18n = getI18n();
</script>
{I18n.t('home.title')}
{I18n.t('welcome', { name: 'John' })}
<I18n.T key="home.title" />
<I18n.T key="welcome" params={{ name: 'John' }} />
HDS uses the ICU MessageFormat for string formatting. Strings are parsed using the intl-messageformat library. Here are some examples:
You can use variables in the strings.
{
"welcome": "Welcome, {name}!"
}
Then, you can pass the value using the params
prop.
{I18n.t('welcome', { name: 'John' })}
<!-- or -->
<I18n.T key="welcome" params={{ name: 'John' }} />
You can also set the value to a reactive variable.
{I18n.t('welcome', { name: myName })}
<!-- or -->
<I18n.T key="welcome" params={{ name: myName }} />
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.
<I18n.T key="home.title" />
{
"start": "Starts on {startDate, date, long}"
}
Then, pass the date as a parameter.
<I18n.T key="start" params={{ startDate: new Date() }} />
{
"price": "The price is {price, number, :: compact-short currency/EUR}"
}
Then, pass the number as a parameter.
<I18n.T key="price" params={{ price: 100 }} />
The result will be The price is €100
.
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}}"
}
<I18n.T key="users" params={{ count: 10 }} />
See the Message Syntax documentation on formatjs.io for more available formatting options.
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.
<I18n.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'
}
}
}} />
Similar to components, you can also render HTML elements.
{
"withElement": "Please try again with a <b>different email</b>."
}
The following code maps the <b>
in the string to a <strong>
HTML element.
<I18n.T key="withElement" params={{b: {element: 'strong'}}} />