-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Is 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 i18n brainstorming #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.

