Add i18n to Svelte/Sveltekit projects using Lingui, with gettext-style message as catalog id.
$t`Hello world`
Messages that should be translated to different languages need to be marked for extraction. There are two ways to do this:
Firstly, install this package along with the Lingui packages.
npm install --save @lingui/core svelte-i18n-lingui
npm install --save-dev @lingui/cli
After the packages are installed, create a lingui.config.ts
(or js depending on your project config) and add a basic configuration. An example of a simple project with English base language and Japanese localization:
import { jstsExtractor, svelteExtractor } from 'svelte-i18n-lingui/extractor';
export default {
locales: ['en', 'ja'],
sourceLocale: 'en',
catalogs: [
{
path: 'src/locales/{locale}',
include: ['src/lib', 'src/routes']
}
],
extractors: [jstsExtractor, svelteExtractor]
};
Here we are using svelte-i18n-lingui
's extractors to allow for extracting messages with customized tags from both svelte components and plain js/ts files.
To extract messages as catalogs and compile them for production, @lingui/cli
provides cli commands that we can integrate to our project's workflow. Inside package.json
, add these two commands:
{
"scripts": {
// Add these commands
"extract": "lingui extract",
"compile": "lingui compile --typescript"
}
}
These can be added to pre-commit hooks to make sure that new text are properly extracted and compiled.
Importing the store for the first time will initiate Lingui's i18n instance with a default language and an empty message catalog.
Locale can be changed by accessing the set
method of the locale
store, passing in the desired locale and message catalog. To make sure that only the necessary message catalog is downloaded, use dynamic import, e.g.:
<script lang="ts">
import { locale } from 'svelte-i18n-lingui';
async function setLocale(lang) {
const { messages } = await import(`../locales/${lang}.ts`);
locale.set(lang, messages);
}
</script>
<button on:click={() => setLocale('en')}>Switch to English</button>
<button on:click={() => setLocale('ja')}>Switch to Japanese</button>
To start translating in Svelte files, import the t
store and auto-subscribe to it by prefixing with $
:
<script lang="ts">
import { t } from 'svelte-i18n-lingui';
</script>
<!-- Use directly as text element -->
{$t`hello`}
<!-- Use as attribute or prop -->
<ComponentA propName={$t`hello`} />
<!-- Supports parameterized text, for cases where different language has different order -->
{$t`Proceed to ${$t`cart`}`}
Since the extractor does a static parse of the code, messages must be in plain string to be extractable. Template literals or variables names won't work.
<script lang="ts">
import { t } from 'svelte-i18n-lingui';
const text = 'message';
</script>
{$t`${text}`}<!-- !!! Will not work, extractor cannot find the message to extract !!! -->
Instead, mark the string as extractable first with the provided msg
function, and pass it to the store later on as a plain string (not as tagged template literal)
<script lang="ts">
import { t, msg } from 'svelte-i18n-lingui';
const text = msg`message`;
</script>
{$t(text)}
To include components or elements in the middle of the message, use the provided <T>
component and use #
characters to add slots in the middle of the text to insert elements or components. The first parameter is supplied through the default children snippet (as the content of the component), while subsequent parameters use snippets (second
, third
, fourth
, fifth
corresponding to the index of the parameter, starting from 1 for the default children snippet).
<script lang="ts">
import { T } from 'svelte-i18n-lingui';
</script>
<T msg="Click # for #">
<a href="https://github.com/HenryLie/svelte-i18n-lingui/blob/main/about">{$t`here`}</a>
{#snippet second()}{$t`more information`}{/snippet}
</T>
Sometimes we'll need to add a context info for messages that are exactly the same in the base language, but has different meanings in different places (e.g. in English right
can either refer to direction or correctness). We can add a context by passing a message descriptor instead of plain string or literal string:
{$t({
message: 'right',
context: 'direction'
})}
The context will be added on top of the message in the catalog, both of them combined are treated as a unique key for the message. Therefore, the same message with a different context will be extracted as separate entries in the catalog and can have its own translations.
We can also add a comment for the translators reading the message catalog e.g. to let them know how the message is going to be used. This is added as a pure comment on the message catalog and won't affect how the message is extracted or compiled.
{$t({
message: 'text',
context: 'message for translator'
})}
To provide different messages for text with numbers, use the provided $plural
store:
{$plural(count, {
one: '# item',
other: '# items'
})}
Refer to Lingui's pluralization guide for more information on what keys are accepted on different locales.
Since Svelte's stores are meant to be used in Svelte components, using them inside plain js/ts files is a bit awkward since you need to use the get
helper to subscribe, get the value, and then immediately unsubscribe afterwards. svelte-i18n-lingui
provides another way to access Lingui's i18n object through plain strings:
$t
=> gt
$plural
=> gPlural
origins
option, the line numbers are always empty for <T>
components usage. The line numbers work on any other syntax.
Found a bug? Feel free to open an issue or PR to fix it!