Translations
See original GitHub issueIs your feature request related to a problem? Please describe. Translations are largely an unsolved problem. There are good libraries out there, like svelte-i18n and svelte-intl-precompile, but because they are not tightly integrated with an app framework, there are drawbacks in existing solutions:
- Usage is somewhat verbose (e.g.
{$_("awesome", { values: { name: "svelte-i18n" } })}) from the svelte-i18n docs - Loading translations is generally a bit awkward
- Messages are untyped
Without getting too far into the weeds of implementation, what follows is a sketch for what I think the developer experience could and should look like for using translations in SvelteKit. It builds upon the aforementioned prior art (using ICU MessageFormat, precompiling translations etc) while leveraging SvelteKit’s unique position as an opinionated app framework. It follows the discussion in #553, but doesn’t address issues like picking a locale or handling canonical/alternate URLs, which overlap with translations but can be designed and implemented separately to a large extent.
Describe the solution you’d like
In the translations directory, we have a series of [language].json files with ICU MessageFormat strings:
// en.json
{
"brand": {
"name": "SvelteKit",
"tagline": "The fastest way to build Svelte apps",
"description": "SvelteKit is the official Svelte application framework"
},
"greeting": "Welcome!",
"clicked_n_times": "{n, plural,=0 {Click the button} =1 {Clicked once} other {Clicked {n} times}}"
}
Regional dialects inherit from the base language:
// en-AU.json
{
"greeting": "G'day mate!"
}
These files are human-editable, but could also be manipulated by tooling. For example, the SvelteKit CLI could provide an editor along the lines of this one or this one out of the box.
SvelteKit watches these files, and populates an ambient.d.ts file that lives… somewhere (but is picked up by a default SvelteKit installation) with types based on the actual translations that are present (using the default locale, which could be specified in svelte.config.cjs, for the example strings):
declare module '$app/i18n' {
import { Readable } from 'svelte/store';
/**
* A dictionary of translations generated from translations/*.json
*/
export const t: Readable<{
brand: {
name: 'SvelteKit';
tagline: 'The fastest way to build Svelte apps';
description: 'SvelteKit is the official Svelte application framework'
};
greeting: 'Hello!',
clicked_n_times: (n: number) => string;
}>;
}
As well as generating the types, SvelteKit precompiles the strings into a module, similar to svelte-intl-precompile:
export default {
brand: {
name: 'SvelteKit',
tagline: 'The fastest way to build Svelte apps',
description: 'SvelteKit is the official Svelte application framework'
},
greeting: 'Hello!',
clicked_n_times: (n) => n === 0 ? 'Click the button' : n === 1 ? 'Clicked once' : `Clicked ${n} times`
};
In a large enough app this module could get very large. We could theoretically use static analysis to determine which translations are used by which routes, and only load the translations needed for the current route, but I don’t think that’s necessary as a starting point.
This module is using for server-rendering, and is also loaded by the client runtime to populate the t store. (Because it’s a store, we can change the language without a full-page reload, if necessary. That might be overkill, but if Next can do it then we should too!)
A relatively unique thing about this approach is that we get typing and autocompletion:

This extends to parameters (which I think should be positional), for messages that need them:

Because everything is just JSON files, it’s trivial to build tooling that can e.g. identify untranslated phrases for a given language. I don’t know what common translation workflows look like, but it would presumably be possible to convert between the file format used here and the output of translation software that uses ICU.
Describe alternatives you’ve considered
- Leaving it to userland. I think i18n is too central to be treated as not-our-problem, and the potential ergonomic benefits from having it in the framework are considerable. (Our solution need not preclude userland solutions, if people have strong preferences)
- Using a different message format. Fluent and Banana both came up in #553. We could theoretically support multiple formats but it would be preferable to pick one that most people are happy with
How important is this feature to you? It’s time. Though we need to solve the problem of selecting a locale before we can make much of a start on this; will open an issue in due course.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:121
- Comments:143 (64 by maintainers)

Top Related StackOverflow Question
See what is wrong with
svelte-i18nAn example from svelte-i18n
I think this is a 100% bull sheet. Look at all of the work that you need to do, just to set a default value for a translateable value. You are not done, you also need to create a .json file and write you all strings there. Also, you need to pick a name for your translatable string as a reference. for example:
So what is wrong with svelte-i18n?
$character is here too!!. I hate this, but no worries, because of my PHP background experience I’m immune 😜I know that this was the best possible way for them to create this library. I know that they put in a lot of work and they did what they were possible of doing it.
I explained what I expect from a layout system here and nothing, we are going to experience the same problems in the SvelteKit too. Now I want to explain what I expect from a translation system because I need to say what I think about it and how I think it needs to be solved because if I don’t, I think it’s gonna be really bad 😞.
Also, I want to say that I get banned (2 of my accounts) from the community discord group. Admins were like “Nah, I don’t like this guy, clicking on the ban button”. (The person that reading this, if you get banned from the discord channel, knows that there was no problem with you). If you didn’t like what I explain here, you can stick with this subject that 2 of my accounts get banned, instead of saying what you don’t agree with 😄. I wanted to complain about it with Mr. Rich Harris but, it seems he is so busy. Oh God, now I feel like I complaining like a baby 😆
Let’s keep going
What I expect from a translation system?
Exactly the same that we are using in the current tools. For example Wordpress:
I sawed the same syntax in Laravel but I don’t have a lot of information about it. Any Laravel developers here to explain to us about how it worlds and how was the experience?
With this, you don’t need to write all of those
svelte-i18njunk you sowed above!.How it works?
Automatically the strings inside the functions get write inside the
.potfile. You insert the.potfile inside a software called Poedit. You select the language and then Poedit will show you the all translatable strings. Translate the strings that you see and much more features, that will make life easier for you, rather than creating a.jsonfile and blah blah blah.You are gonna have 3 files
.pot: Your all strings live here (input).translatable-strings.pot..po: Translated string (output).[language].po..moSame as the.pobut the file isn’t editable!.[language].mo.You are confused?
You are just gonna write your string inside the
__()function. All of the other work going to take care of by the system it selves.Pros
$t(), oh my brain 😟Cons
Hello worldand after:Hello World.Hellostring and thehellostring are treated as different strings.Why I hate
$t()$t(), oh my brain 😟Welcomeinstead ofgreeting. https://github.com/sveltejs/kit/issues/1274#issue-871199686$Any updates on this? It’s been a while since this issue was last updated. Is the translations feature still being actively developed?