Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
@inlang/paraglide-js
Advanced tools
[ Watch the demo of Paraglide JS](https://www.youtube.com/watch?v=-YES3CCAG90)
Watch the demo of Paraglide JS
Get started with:
npx @inlang/paraglide-js@latest init
Treeshaking gives us superpowers. With it, each page of your app only loads the messages that it actually uses. Incremental loading like this would usually take hours of manual tweaking to get right. With Paraglide-JS you get it for free. Say goodbye to huge bundles.
Initialize paraglide-js whith:
npx @inlang/paraglide-js@latest init
This will:
build
scriptAdapters are framework-integrations for Paraglide. If you are using a framework, using an adapter is recommended , but not required.
Running your build
script will generate a src/paraglide
folder. This folder contains all the code that you need to use paraglide-js.
Tip: If you are using a bundler, you can set up an alias to
./src/paraglide
to make the imports shorter.
By default, paraglide expects your messages to be in messages/{lang}.json
.
{
"hello": "Hello world!"
"loginHeader": "Hello {name}, please login to continue."
}
You can import messages with import * as m from "./paraglide/messages"
. Don't worry, your bundler will only include the messages that you actually use.
import * as m from "./paraglide/messages.js"
import { setLanguageTag } from "./paraglide/runtime.js"
m.hello() // Hello world!
m.loginHeader({ name: "Samuel" }) // Hello Samuel, please login to continue.
If you want to choose between messages at runtime, you can create a record of messages and index into it.
import * as m from "./paraglide/messages.js"
const season = {
spring: m.spring,
summer: m.summer,
autumn: m.autumn,
winter: m.winter,
} as const;
const msg = season["spring"]() // Hello spring!
Sherlock integrates with paraglide to give you the optimal dev-experience.
You can declare which languages you support in ./project.inlang/settings.json
in the languageTags
array.
// project.inlang/settings.json
{
"languageTags": ["en", "de"]
}
Then create another messages/{lang}.json
file and get translating!
You can set the language tag by calling setLanguageTag()
. Any subsequent calls to either languageTag()
or a message function will use the new language tag.
import { setLanguageTag } from "./paraglide/runtime.js"
import * as m from "./paraglide/messages.js"
setLanguageTag("de")
m.hello() // Hallo Welt!
setLanguageTag("en")
m.hello() // Hello world!
The language tag is global, so you need to be careful with it on the server to make sure multiple requests don't interfere with each other.
You will need to call setLanguageTag
on both the server and the client, since they run in separate processes.
Messages aren't reactive, so you will need to trigger a re-render when the language changes. You can register a callback using onSetLanguageTag()
. It is called whenever the language tag changes.
If you are using an adapter this is likely done for you.
import { setLanguageTag, onSetLanguageTag } from "./paraglide/runtime.js"
import * as m from "./paraglide/messages.js"
onSetLanguageTag((newLanguageTag) => {
console.log(`The language changed to ${newLanguageTag}`)
})
setLanguageTag("de") // The language changed to de
setLanguageTag("en") // The language changed to en
There are a few things to know about onSetLanguageTag()
:
setLanguageTag
shouldn't be used on the server.You can import a message in a specific language from paraglide/messages/{lang}.js
. This is great if you always need the same language in a given file.
import * as m from "./paraglide/messages/de.js"
m.hello() // Hallo Welt
If you want to force a language, but don't know ahead of time which language you can pass the languageTag
option as the second parameter to a message function. This is often needed on the server.
import * as m from "./paraglide/messages.js"
const msg = m.hello({ name: "Samuel" }, { languageTag: "de" }) // Hallo Samuel!
## Lazy-Loading
Paraglide consciously discourages lazy-loading translations since it seriously hurts your web-vitals. Learn more about why lazy-loading is bad & what to do instead in this blog post.
If you really want to do it anway, you can lazily import the language-specific message files. Be careful with this, as it's easy to accidenally break tree-shaking.
const lazyGerman = await import("./paraglide/messages/de.js")
We provide bundler plugins to make it easier to use Paraglide with a bundler. If you are using one we recommed using the corresponding plugin.
These plugins make sure to compile your messages whenever you build your project. If your bundler has a dev-server, like Vite, the plugin also makes sure to recompile whenever your messages change.
You can find many examples for how to use paraglide on codesandbox, or in our GitHub repository.
Inlang Paraglide JS leverages a compiler to emit vanilla JavaScript functions.
The emitted functions are referred to as "message functions". By emitting message functions, inlang Paraglide JS eliminates a whole class of edge cases while also being simpler, faster, and more reliable than other i18n libraries. The compiled runtime contains less than 50 LOC (lines of code) and is less than 300 bytes minified & gzipped.
Inlang Paraglide-JS consists of four main parts:
Part | Description |
---|---|
Compiler | Compiles messages into tree-shakable message functions |
Messages | The compiled tree-shakable message functions |
Runtime | A runtime that resolves the language tag of the current user |
Adapter | (optional) An adapter that adjusts the runtime for different frameworks |
The compiler loads an inlang project and compiles the messages into tree-shakable and typesafe message functions.
Input
// messages/en.json
{
"hello": "Hello {name}!",
"loginButton": "Login"
}
Output
// src/paraglide/messages/en.js
/**
* @param {object} params
* @param {string} params.name
*/
export const hello = (params) => `Hello ${params.name}!`
/** ... */
export const loginButton = () => "Login"
The compiled messages are importable as a namespace import (import * as m
).
The namespace import ensures that bundlers like Rollup, Webpack, or Turbopack can tree-shake the messages that are not used.
Three compiled message functions exist in an example project.
// src/paraglide/messages.js
/** ... */
export const hello = (params) => `Hello ${params.name}!`
/** ... */
export const loginButton = () => "Login"
/** ... */
export const loginHeader = (params) => `Hello ${params.name}, please login to continue.`
Only the message hello
is used in the source code.
// src/my-code.js
import * as m from "../paraglide/messages.js"
console.log(m.hello({ name: "Samuel" }))
The bundler tree shakes (removes) loginButton
and loginHeader
and only includes hello
in the output.
// dist/my-code.js
const hello = (params) => `Hello ${params.name}!`
console.log(hello({ name: "Samuel" }))
An "adapter" is a library that integrates with a framework's liefcycle and does two main things:
setLanguageTag()
at appropriate times to set the languageonSetLanguageTag()
, usually by navigating or relading the page.Here is an example that adapts Paraglide-JS to a fictitious metaframework like NextJS or SvelteKit.
import { setLanguageTag, onSetLanguageTag } from "../paraglide/runtime.js"
import { isServer, request, render } from "@example/framework"
// On a server, the language tag needs to be resolved on a
// per-request basis. Hence, we need to pass a getter
// function () => string to setLanguageTag.
//
// Most frameworks offer a way to access the current
// request. In this example, we assume that the language tag
// is available in the request object.
if (isServer) {
setLanguageTag(() => request.languageTag)
}
// On a client, the language tag could be resolved from
// the document's html lang tag.
//
// In addition, we also want to trigger a side-effect
// to request the site if the language changes.
else {
setLanguageTag(() => document.documentElement.lang)
//! Make sure to call `onSetLanguageTag` after
//! the initial language tag has been set to
//! avoid an infinite loop.
// route to the page in the new language
onSetLanguageTag((newLanguageTag) => {
window.location.pathname = `/${newLanguageTag}${window.location.pathname}`
})
}
// make sure the app renders _after_ you've done your setup
render((page) => (
<html lang={request.languageTag}>
<body>{page}</body>
</html>
))
We are grateful for all the support we get from the community. Here are a few comments we've received recently.
If you have any feedback / problems, please let us know on GitHub
Of course, we're not done yet! We plan on adding the following features to Paraglide JS soon:
Paraglide JS is part of the inlang ecosystem, so it integrates nicely with all the other inlang compatible tools. If you are working with translators and/or designers you will find the following tools useful:
FAQs
[![Inlang-ecosystem compatibility badge](https://cdn.jsdelivr.net/gh/opral/monorepo@main/inlang/assets/md-badges/inlang.svg)](https://inlang.com)
The npm package @inlang/paraglide-js receives a total of 16,547 weekly downloads. As such, @inlang/paraglide-js popularity was classified as popular.
We found that @inlang/paraglide-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.