Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@inlang/paraglide-js

Package Overview
Dependencies
Maintainers
2
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@inlang/paraglide-js

[

  • 1.3.7
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
20K
increased by6.33%
Maintainers
2
Weekly downloads
 
Created
Source

Dead Simple i18n. Typesafe, Small Footprint, Treeshsakeable Messages, IDE Integration, Framework Agnostic

Why Paraglide?

With Paraglide's Treeshsakeable messages, each page only loads the messages it actually uses. Incremental loading like this would usually take forever to get right, with Paraglide you get it for free.

Use it with your Favorite Framework

Paraglide is framework agnostic, but it's even better if you pair it with a framework specific library. If you are using one of these frameworks you will want to follow the framework specific documentation instead. If you aren't, that's fine too! You can read on.

People Love It

Here are a few comments we've received recently.

Getting started

To use Paraglide stanadlone without a framework, run the following command:

npx @inlang/paraglide-js@latest init

This will:

  • Install necessary dependencies
  • Generate a messages/ folder where your translation files live
  • Add the Paraglide compiler to your build script
  • Create necessary configuration files

Running the paraglide compiler will generate a src/paraglide folder. This folder contains all the code that you need to use paraglide-js.

Adding and Editing Messages

Messages are stored in messages/{lang}.json. To add a message simply add a key-value pair. You can add parameters with curly braces.

// messages/en.json
{
	"$schema": "https://inlang.com/schema/inlang-message-format",
+ 	"greeting": "Hello {name}!"
}

Make sure to re-run the paraglide compiler after editing your messages.

npx @inlang/paraglide-js compile --project ./project.inlang

If you are using Vite, you can instead use the paraglide vite-plugin to do this automatically.

Using Messages in Code

After running the compiler, you can import messages with import * as m from "./paraglide/messages".

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.

To choose between messages at runtime create a map 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!

Configuration

You can configure the languages you intend to support

Languages

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!

Setting the language

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.

Reacting to language changes

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():

  • You can only register one listener. If you register a second listener it will throw an error.
  • setLanguageTag shouldn't be used on the server.

Getting a message in a specific language

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!

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.

const lazyGerman = await import("./paraglide/messages/de.js")
lazyGerman.hello() // Hallo Welt

Usage with a Bundler

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.

Playground

Find examples for how to use paraglide on codesandbox or in our GitHub repository.

Architecture

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 JS architecture

Paraglide consists of four main parts:

PartDescription
CompilerCompiles messages into tree-shakable message functions
MessagesThe compiled tree-shakable message functions
RuntimeA runtime that resolves the language tag of the current user
Adapter(optional) An adapter that adjusts the runtime for different frameworks

Compiler

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}!`

Messages

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.

Writing an Adapter

An "Adapter" is a library that integrates with a framework's liefcycle and does two things:

  1. Calls setLanguageTag() at appropriate times to set the language
  2. Reacts to onSetLanguageTag(), 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>
))

Roadmap

Of course, we're not done yet! We plan on adding the following features to Paraglide JS soon:

Talks

Tooling

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 VsCode extension.

If you are working with translators or designers you will find these tools useful:

  • Fink - An Online UI for editing translations. Changes made in Fink are committed to a translation branch or submitted via pull request.
  • Parrot - A Figma Plugin for previewing translations right in your Figma designs. This avoids any layout issues that might occur due to different text lengths in different languages.

Pricing

Keywords

FAQs

Package last updated on 04 Apr 2024

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc