Comparisons to other Libraries
There are quite a few i18n libraries available for Svelte. Here is how t18s compares to the most popular ones.
There are quite a few i18n libraries available for Svelte. Here is how t18s compares to the most popular ones.
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
console.log('Hello World')
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
console.log('Hello World')
There are quite a few i18n libraries available for Svelte. Here is how t18s compares to the most popular ones.
There are quite a few i18n libraries available for Svelte. Here is how t18s compares to the most popular ones.
First you need to install t18s as a dev dependency.
T18S isn't just a library, it's a vite-plugin, so you will need to register it in your vite config.
import { sveltekit } from "@sveltejs/kit/vite";
+ Getting Started
First you need to install t18s as a dev dependency.
Installation
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
T18S isn't just a library, it's a vite-plugin, so you will need to register it in your vite config.
vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
import { t18s } from "t18s";
import { defineConfig } from "vite";
@@ -11,4 +11,4 @@
}),
],
});
-
Aaaand we're off.
\ No newline at end of file
+
Aaaand we're off.
T18S is not done. There is still a lot we want to add. Here are some of our ideas for the future in no particular order.
TODO
T18S is not done. There is still a lot we want to add. Here are some of our ideas for the future in no particular order.
T18S is still relatively new, and hasn't handled all the edge cases yet. This causes occasional problems with the dev-server, reloading translations and other inconveniences. We want to make sure that t18s is as robust as possible and can deliver the best experience possible.
There exists a wide range of file formats for translations. We want to support as many of them as possible in order to allow developers and translators to use the tools they are most comfortable with.
SvelteKit currently doesn't offer a built in way to internationalize routes. It's left to the developer to implement this. We want to provide a standard and straight forward way to do this. Due to the complexity of the problem there are still a lot of open questions here, and there is a lot of experimenting left to be done.
There are a few proof-of-concept tools & sites out there that push the boundary of how we interact with the things we build. One of those is better-i18n-for-svelte. It's a proof of concept for editing translations in your dev-browser directly, instead of files.
We want to experiment with implementing features like this in t18s. There are a lot of open questions with this though. How do we determine which text came from a translation? How do we handle variable interpolation in the editor, how do we add new translations?
Until we have answers to these questions, this will remain relatively low priority.
There are quite a few SEO related things you need to keep in mind when developing a multi-language site. This page will give you a quick overview of the most important ones.
Alternate links are a way to tell search engines that a page exists in multiple languages, and where to find them. This is done by adding a link tag to the head of your page.
You should add a link tag for each language your site is available in, including the one the page is currently in.
<head>
+ <link rel="alternate" href="/en" hreflang="en" />
+ <link rel="alternate" href="/de" hreflang="de" />
+</head>
If you have a "default lanugage" that you want to use when the user's language is not available, you should add a link tag with the hreflang
attribute set to x-default
. This tells search engines that this is the default language.
<head>
+ <link rel="alternate" href="/en" hreflang="en" />
+ <link rel="alternate" href="/de" hreflang="de" />
+
+ <!--Use the english site as the default-->
+ <link rel="alternate" href="/en"; hreflang="x-default" />
+</head>
+
It is recommended that you use a
tags for your locale switchers. This is because search engines and the SvelteKit prerenderer will follow these links, and index the pages they lead to. They also work if JavaScript is disabled.
But, we need to make sure to tell the search engines that these links just lead to the same page in a different language, not separate pages. We do this by adding an hreflang
attribute.
<a href="/de" hreflang="de">Deutsch</a>
Browsers determine the page's language by looking at the lang
attribute on the html
tag. We need to make sure that this attribute is set to the correct language, both during server rendering, and when switching languages on the client.
SvelteKit offers a relatively simple way to set the lang
attribute during server rendering. We can set it in a hook.
In the app template, let's add a placeholder string in the lang
attribute.
<!DOCTYPE html>
+<html lang="%lang%">
+ <!-- ... -->
+</html>
+
Then in the server handle
hook, we can replace it with the correct language.
export const handle = async ({ event, resolve }) => {
+ //Determine the locale from the URL.
+ //Implementing this is up to you, depending on your routing solution.
+ const locale = getLocale(event);
+
+ const response = await resolve(event, {
+ //Replace the placeholder %lang% with the current locale.
+ transformPageChunk({ html }) {
+ html = html.replace("%lang%", locale);
+ return html;
+ },
+ });
+
+ return response;
+};
+
T18S does not do a full page reload when switching languages, so we need to make sure that the lang
attribute gets set correctly when switching languages on the client.
In the root layout. Check that we are in the browser, and then reactively set the lang
attribute base on the $locale
store exported by T18S.
<script>
+ import { locale } from "$t18s";
+ import { browser } from "$app/environment";
+ $: if(browser) document.documentElement.lang = $locale;
+</script>
+
+<slot />
This may become built in behavior in the future, depending on feedback. Old code probably won't break, so you can add this now without worrying about it.
T18s uses the ICU MessageFormat Syntax for messages, the de-facto standard in the JavaScript ecosystem. Let's learn how to use it.
Intl
API under the hood. Generally the format for interpolating values is always this. Select allows you to use one of multiple values based on a key. This is useful for things like grammatical gender.
You use it by using the select
type, and then listing out each option with a key and a value in curly braces.
The special key other
is used as a fallback if no other key matches.
Some i18n libraries require you to define a fallback case for all selects. T18s does not, instead relying on typesafety to ensure all values match a key.
You cannot use any additional values inside tags.
T18s uses the ICU MessageFormat Syntax for messages, the de-facto standard in the JavaScript ecosystem. Let's learn how to use it.
You can specify that a value is not a string by adding a type-annotation in the curly braces. The known types are number
, date
, and time
.
There are {count, number} people here +Today is {date, date} +Sarah shows up at {time, time}
Intl
API under the hood. Generally the format for interpolating values is always this. Select allows you to use one of multiple values based on a key. This is useful for things like grammatical gender.
You use it by using the select
type, and then listing out each option with a key and a value in curly braces.
The special key other
is used as a fallback if no other key matches.
Some i18n libraries require you to define a fallback case for all selects. T18s does not, instead relying on typesafety to ensure all values match a key.
You cannot use any additional values inside tags.
First you need to install t18s as a dev dependency.
T18S isn't just a library, it's a vite-plugin, so you will need to register it in your vite config.
import { sveltekit } from "@sveltejs/kit/vite";
+ Getting Started
First you need to install t18s as a dev dependency.
Installation
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
T18S isn't just a library, it's a vite-plugin, so you will need to register it in your vite config.
vite.config.js
import { sveltekit } from "@sveltejs/kit/vite";
import { t18s } from "t18s";
import { defineConfig } from "vite";
@@ -11,4 +11,4 @@
}),
],
});
-
Aaaand we're off.
\ No newline at end of file
+
Aaaand we're off.
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
console.log('Hello World')
npm install --save-dev t18s
yarn add --dev t18s
pnpm add --save-dev t18s
console.log('Hello World')
T18S is not done. There is still a lot we want to add. Here are some of our ideas for the future in no particular order.
TODO
T18S is not done. There is still a lot we want to add. Here are some of our ideas for the future in no particular order.
T18S is still relatively new, and hasn't handled all the edge cases yet. This causes occasional problems with the dev-server, reloading translations and other inconveniences. We want to make sure that t18s is as robust as possible and can deliver the best experience possible.
There exists a wide range of file formats for translations. We want to support as many of them as possible in order to allow developers and translators to use the tools they are most comfortable with.
SvelteKit currently doesn't offer a built in way to internationalize routes. It's left to the developer to implement this. We want to provide a standard and straight forward way to do this. Due to the complexity of the problem there are still a lot of open questions here, and there is a lot of experimenting left to be done.
There are a few proof-of-concept tools & sites out there that push the boundary of how we interact with the things we build. One of those is better-i18n-for-svelte. It's a proof of concept for editing translations in your dev-browser directly, instead of files.
We want to experiment with implementing features like this in t18s. There are a lot of open questions with this though. How do we determine which text came from a translation? How do we handle variable interpolation in the editor, how do we add new translations?
Until we have answers to these questions, this will remain relatively low priority.
There are quite a few SEO related things you need to keep in mind when developing a multi-language site. This page will give you a quick overview of the most important ones.
Alternate links are a way to tell search engines that a page exists in multiple languages, and where to find them. This is done by adding a link tag to the head of your page.
You should add a link tag for each language your site is available in, including the one the page is currently in.
<head>
+ <link rel="alternate" href="/en" hreflang="en" />
+ <link rel="alternate" href="/de" hreflang="de" />
+</head>
If you have a "default lanugage" that you want to use when the user's language is not available, you should add a link tag with the hreflang
attribute set to x-default
. This tells search engines that this is the default language.
<head>
+ <link rel="alternate" href="/en" hreflang="en" />
+ <link rel="alternate" href="/de" hreflang="de" />
+
+ <!--Use the english site as the default-->
+ <link rel="alternate" href="/en"; hreflang="x-default" />
+</head>
+
It is recommended that you use a
tags for your locale switchers. This is because search engines and the SvelteKit prerenderer will follow these links, and index the pages they lead to. They also work if JavaScript is disabled.
But, we need to make sure to tell the search engines that these links just lead to the same page in a different language, not separate pages. We do this by adding an hreflang
attribute.
<a href="/de" hreflang="de">Deutsch</a>
Browsers determine the page's language by looking at the lang
attribute on the html
tag. We need to make sure that this attribute is set to the correct language, both during server rendering, and when switching languages on the client.
SvelteKit offers a relatively simple way to set the lang
attribute during server rendering. We can set it in a hook.
In the app template, let's add a placeholder string in the lang
attribute.
<!DOCTYPE html>
+<html lang="%lang%">
+ <!-- ... -->
+</html>
+
Then in the server handle
hook, we can replace it with the correct language.
export const handle = async ({ event, resolve }) => {
+ //Determine the locale from the URL.
+ //Implementing this is up to you, depending on your routing solution.
+ const locale = getLocale(event);
+
+ const response = await resolve(event, {
+ //Replace the placeholder %lang% with the current locale.
+ transformPageChunk({ html }) {
+ html = html.replace("%lang%", locale);
+ return html;
+ },
+ });
+
+ return response;
+};
+
T18S does not do a full page reload when switching languages, so we need to make sure that the lang
attribute gets set correctly when switching languages on the client.
In the root layout. Check that we are in the browser, and then reactively set the lang
attribute base on the $locale
store exported by T18S.
<script>
+ import { locale } from "$t18s";
+ import { browser } from "$app/environment";
+ $: if(browser) document.documentElement.lang = $locale;
+</script>
+
+<slot />
This may become built in behavior in the future, depending on feedback. Old code probably won't break, so you can add this now without worrying about it.
T18s uses the ICU MessageFormat Syntax for messages, the de-facto standard in the JavaScript ecosystem. Let's learn how to use it.
Intl
API under the hood. Generally the format for interpolating values is always this. Select allows you to use one of multiple values based on a key. This is useful for things like grammatical gender.
You use it by using the select
type, and then listing out each option with a key and a value in curly braces.
The special key other
is used as a fallback if no other key matches.
Some i18n libraries require you to define a fallback case for all selects. T18s does not, instead relying on typesafety to ensure all values match a key.
You cannot use any additional values inside tags.
T18s uses the ICU MessageFormat Syntax for messages, the de-facto standard in the JavaScript ecosystem. Let's learn how to use it.
You can specify that a value is not a string by adding a type-annotation in the curly braces. The known types are number
, date
, and time
.
There are {count, number} people here +Today is {date, date} +Sarah shows up at {time, time}
Intl
API under the hood. Generally the format for interpolating values is always this. Select allows you to use one of multiple values based on a key. This is useful for things like grammatical gender.
You use it by using the select
type, and then listing out each option with a key and a value in curly braces.
The special key other
is used as a fallback if no other key matches.
Some i18n libraries require you to define a fallback case for all selects. T18s does not, instead relying on typesafety to ensure all values match a key.
You cannot use any additional values inside tags.