Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@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 ParaglideJS 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.
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
.
// 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
.
import * as m from "./paraglide/messages/de.js"
m.hello() // Hallo Welt
If you want to force a language, but don't know which language ahead of time you can pass the languageTag
option as the second parameter to a message function. This is often handy on the server.
import * as m from "./paraglide/messages.js"
const msg = m.hello({ name: "Samuel" }, { languageTag: "de" }) // Hallo Samuel!
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.
const lazyGerman = await import("./paraglide/messages/de.js")
lazyGerman.hello() // Hallo Welt
If you are using a bundler you should use the corresponding plugin. The plugin will keep your message-functions up-to-date by compiling whenever your messages change and before build.
Find examples for how to use paraglide on codesandbox or in our GitHub repository.
ParaglideJS leverages a compiler to generate vanilla JavaScript functions from your messages. We call these "message functions".
Message Functions are fully typed using JSDoc. They are exported individually from the messages.js
file making them tree-shakable. They aren't reactive, they just return a string.
This avoids many edge cases associated with reactivity, lazy-loading and namespacing that other i18n libraries have to work around.
In addition to the message functions, ParaglideJS also emits a runtime. The runtime is used to set the language tag. It contains less than 50 LOC (lines of code) and is less than 300 bytes minified & gzipped.
Paraglide 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}!"
}
Output
// src/paraglide/messages/en.js
/**
* @param {object} params
* @param {string} params.name
*/
export const hello = (params) => `Hello ${params.name}!`
By convention we import the compiled funcitions with a wildcard import.
import * as m from "../paraglide/messages.js"
Bundlers like Rollup, Webpack, or Turbopack tree-shake the messages that are not used, so using a wildcard import is perfectly fine.
An "Adapter" is a library that integrates with a framework's liefcycle and does two things:
setLanguageTag()
at appropriate times to set the languageonSetLanguageTag()
, usually by navigating or relading the page.This example adapts Paraglide to a fictitious fullstack framework.
import { setLanguageTag, onSetLanguageTag, type AvailableLanguageTag } from "../paraglide/runtime.js"
import { isServer, isClient, request, render } from "@example/framework"
import { detectLanguage } from "./utils.js"
if (isServer) {
// On the server the language tag needs to be resolved on a per-request basis.
// Pass a getter function that resolves the language from the correct request
const detectLanguage = (request: Request) : AvailableLanguageTag => {
//your logic ...
}
setLanguageTag(() => detectLanguage(request))
}
if(isClient) {
// On the client, the language tag can be resolved from
// the document's html lang tag.
setLanguageTag(() => document.documentElement.lang)
// When the language changes we want to re-render the page in the new language
// Here we just navigate to the new route
//
// Make sure to call `onSetLanguageTag` after `setLanguageTag` to avoid an infinite loop.
onSetLanguageTag((newLanguageTag) => {
window.location.pathname = `/${newLanguageTag}${window.location.pathname}`
})
}
// Render the app once the setup is done
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 and integrates nicely with all the other Inlang compatible tools.
As a developer, you will love the Sherlock IDE extension.
If you are working with translators or designers you will find these 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 18,613 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.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
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.