
Paraglide JS
AppBasics
Adding and removing locales
To add a new locale, add it to the locales array in <project0name>.inlang/settings.json file.
// project.inlang/settings.json
{
"baseLocale": "en",
+ "locales": ["en", "de"]
}
Adding and editing messages
Messages are stored in messages/{locale}.json as key-value pairs. You can add parameters with curly braces.
// messages/en.json
{
+ "greeting": "Hello {name}!"
}
Importing messages
After compiling your project, you'll have access to all your messages through the generated messages.js file:
// Import all messages at once
import { m } from "./paraglide/messages.js";
// Use a message
console.log(m.hello_world()); // "Hello World!"
Using parameters
For messages with parameters, simply pass an object with the parameter values:
// messages/en.json
// { "greeting": "Hello {name}!" }
import { m } from "./paraglide/messages.js";
// Pass parameters as an object
console.log(m.greeting({ name: "Samuel" })); // "Hello Samuel!"
Forcing a locale
You can override the locale by passing a locale option as the second parameter:
import { m } from "./paraglide/messages.js";
// Force the message to be in German
console.log(m.greeting({ name: "Samuel" }, { locale: "de" })); // "Hallo Samuel!"
Setting the locale
To change the current locale, use the setLocale function:
import { setLocale } from "./paraglide/runtime.js";
// Change locale to German
setLocale("de");
Disabling reloading
By default, setLocale() triggers a full page reload. This is a deliberate design decision that:
- Enables a small, efficient runtime without complex state management
- Makes Paraglide work in any framework without requiring framework-specific adapters
- Follows the pattern used by major websites like YouTube, as language switching is an infrequent action that doesn't justify the complexity of a no-reload approach
If you need to change the locale without a page reload, you can pass { reload: false } as the second parameter, but then you'll need to handle UI updates yourself.
// Change locale without reloading the page
setLocale("de", { reload: false });
Getting the current locale
To get the current locale, use the getLocale function:
import { getLocale } from "./paraglide/runtime.js";
console.log(getLocale()); // "de"
Routing
<a> tag localization has been removed in v2. See changelog and this issue for more information.
You must explicitly use localizeHref() for URL localization:
<a href={localizeHref("/blog")}>Blog</a>
Important: If you route to a different locale, ensure a reload happens afterwards. See https://inlang.com/m/gerre34r/library-inlang-paraglideJs/errors#switching-locales-via-links-doesnt-work
Choosing your strategy
You likely want to use one of the built-in strategies. Visit the strategy documentation to learn more.
Message keys and organization
Paraglide supports nested keys through bracket notation but recommends flat keys due to management complexity. Learn more about message key structures and best practices.
// messages/en.json
{
// Recommended: flat keys with snake_case
"user_profile_title": "User Profile",
// Also supported but not recommended: nested keys
"user": {
"profile": {
"title": "User Profile"
}
}
}
import { m } from "./paraglide/messages.js";
console.log(m.user_profile_title()); // "User Profile" (recommended)
console.log(m["user.profile.title"]()); // "User Profile" (also works)
Dynamically calling messages
You can dynamically call messages by specifying what messages you expect beforehand. Specifying the messages beforehand preserves tree-shaking.
import { m } from "./paraglide/messages.js";
const messages = {
greeting: m.greeting,
goodbye: m.goodbye,
};
let messageKey = "greeting";
console.log(messages[messageKey]());
// "Hello World!"
Type-safe localized strings
Message functions return a LocalizedString type instead of a plain string. This branded type lets TypeScript distinguish between translated and untranslated strings at compile time, helping you enforce that only localized content is used in your UI.
import { m } from "./paraglide/messages.js";
import type { LocalizedString } from "./paraglide/runtime.js";
// Enforce localized strings in your components
function PageTitle(props: { title: LocalizedString }) {
return <h1>{props.title}</h1>;
}
// ✅ Correct: using a message function
<PageTitle title={m.welcome_title()} />
// ❌ Type error: raw strings are not LocalizedString
<PageTitle title="Welcome" />
Since LocalizedString is a branded subtype of string, it's fully backward compatible—you can pass it anywhere a string is expected:
const localized: LocalizedString = m.greeting();
const str: string = localized; // ✅ works fine
const raw: LocalizedString = "Hello"; // ❌ Type error
This also catches accidental string concatenation, which would bypass translation:
function showMessage(msg: LocalizedString) { /* ... */ }
showMessage(m.hello()); // ✅
showMessage("Hello " + userName); // ❌ Type error
showMessage(m.hello_user({ name: userName })); // ✅ use message params instead
LocalizedString if you don't want to—since it's a subtype of string, existing code that expects string will continue to work without changes.