Configuration
Configuration example
This is the minimal working example of the library's initialization. Put this in your src/__layout.svelte
file.
import { addMessages, init } from 'svelte-intl-precompile';
import en from '$locales/en';
import es from '$locales/es';
addMessages('en', en);
addMessages('es', es);
init({
initialLocale: 'en',
fallbackLocale: 'en'
});
This will get you going but lets dive deeper on it more.
Load locales statically
Like in the previous example, the easiest way to add your translation keys is to just import them as modules and register them using addMessages(langCode, translations)
.
import en from '$locales/en';
import es from '$locales/es';
addMessages('en', en);
addMessages('es', es);
Note that despite the fact that you defined your translations in JSON files, in here you are importing them as javascript modules from $locales
. This is because the compiler has transformed your translations into a module with inline functions at built time.
This approach is loading all those languages even if only one is being displayed. Usually okay when kicking out a new project or if you only have a few of keys, but when your app grows you should start loading languages on demand.
Load locales dynamically
Once you have a significant amount of translations and many locales it would be very wasteful to load every possible language for every possible user when they will only see their selected one. The library has a register(langCode, callback)
function to dynamically import languages when the user selects it and a waitLocale(locale = defaultLocale)
to wait for locales to be loaded.
If all your locales are dynamically loaded you want to stop the page from rendering initial locale has loaded. Calling it in Svelte's load
function with do exactly that.
import { init, register, waitLocale } from 'svelte-intl-precompile';
register('en', () => import('$locales/en'));
register('es', () => import('$locales/es'));
export async function load() {
init({ initialLocale: en });
await waitLocale(); // awaits the default locale, "en" in this case.
}
Load locales dynamically (but shorter this time)
If you just want to register all your available locales (all the locales for which you have a JSON file with translations) automatically, there's a nice shorthand for that. The $locales
folder for your translations doubles down as a module from which you can import two utilities: registerAll
and availableLocales
.
The first one is a function that when invoked is equivalent to calling register(langCode, callback)
for all your locales.
The second one is an array of the available locales (wether you've registered them or not), for whatever use you might want to put them to.
import { init, waitLocale } from 'svelte-intl-precompile';
import { registerAll, availableLocales } from '$locales';
registerAll();
export async function load() {
init({ initialLocale: selectBestMatchingLocale(availableLocales) });
await waitLocale();
}
Default & fallback locales
To the call to init(libOptions)
the most important options are initialLocale
and fallbackLocale
. The first determines the locale in which the app will be initially rendered and the second the locale that will be checking when a translation is not found in the currently selected locale.
init({
initialLocale: 'es',
fallbackLocale: 'en'
});
There's a lot we can do to achieve the best experience, like smartly initializing the initialLocale
to the users' configured locale if they are logged, read it from a cookie in case they are repeating visitors or choose it based on the requests
Accept-Languageheader when doing SSR, but the most straigtforward is to detect it from the browser or the URL with the provided utility functions.
Find the best locale
There are many valid strategies to select the best locale to pass to the init()
function. This library provides helpers for the most common ones:
getLocaleFromNavigator()
- Extracts the locale from browser, which in turn is the operative systems' locale.
getLocaleFromQueryString(key)
- Extracts the locale on the given key of the query string of the URL.
E.ggetLocaleFromQueryString('lang')
for/users?sort=name&dir=asc&lang=es
getLocaleFromHash(key)
- Like
getLocaleFromQueryString
but for the URL hash.
E.ggetLocaleFromHash('lang')
for/users#sort=name&dir=asc&lang=es
getLocaleFromPathname(regex)
- Extracts the locale from the path of the URL.
E.ggetLocaleFromPathname(/^/((es|en)(-\w\w)?)/)
formyapp.com/en-US/users
getLocaleFromHostname(regex)
- Extracts the locale from host.
E.ggetLocaleFromHostname(/^((es|en)(-\w\w)?)\./)
forhttps://pt.myapp.com
getLocaleFromAcceptLanguageHeader(header, availableLocales?)
- Extracts the locale from the Accept-Language header based on a list of available locales. If availableLocales is omitted, returns the first language from the header.
E.g.getLocaleFromAcceptLanguageHeader('en-GB,en;q=0.9,es-ES;q=0.8,en-US;q=0.6', ['fr', 'es', 'de'])
for'es'
Custom formats
This library can format numbers, dates and times. It does it without adding significant weight to your app by leveraging the Intl API already present in all modern browsers and in Node.js.
By default you app can use these formats, but you can add your own.
{
number: {
scientific: { notation: 'scientific' }
engineering: { notation: 'engineering' }
compactLong: { notation: 'compact', compactDisplay: 'long' }
compactShort: { notation: 'compact', compactDisplay: 'short' }
},
date: {
short: { month: 'numeric', day: 'numeric', year: '2-digit' }
medium: { month: 'short', day: 'numeric', year: 'numeric' }
long: { month: 'long', day: 'numeric', year: 'numeric' }
full: { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' }
},
time: {
short: { hour: 'numeric', minute: 'numeric' }
medium: { hour: 'numeric', minute: 'numeric', second: 'numeric' }
long: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' }
full: { hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' }
}
}
If you want to define your own formats pass them on initialization using the formats
option, which will be deep merged with the default formats listed above. The formats must be valid options to forward to
Intl.DateTimeFormat.
init({
fallbackLocale: 'en',
initialLocale: 'en',
formats: {
date: {
abbreviated: { weekday: 'long', month: 'short', day: 'numeric' }
},
time: {
'just-hour': { hour: 'numeric' }
}
}
});
For numbers specifically you can register your own formats like that or you can use Number Skeletons as a more flexible way of customizing every single aspect of how numbers are rendered. Check the crash course here