@inlang/paraglide-js 1.3.3 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -106
- package/dist/index.js +21058 -4856
- package/package.json +8 -10
package/README.md
CHANGED
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
<!--  -->
|
|
4
4
|
|
|
5
|
-
# Simple, adaptable, and tiny i18n library for JS
|
|
6
|
-
|
|
7
5
|
Get started with:
|
|
8
6
|
|
|
9
7
|
```bash
|
|
@@ -13,9 +11,9 @@ npx @inlang/paraglide-js@latest init
|
|
|
13
11
|
# Features
|
|
14
12
|
|
|
15
13
|
<doc-features>
|
|
16
|
-
<doc-feature title="
|
|
17
|
-
<doc-feature title="
|
|
18
|
-
<doc-feature title="
|
|
14
|
+
<doc-feature title="Only used translations are shipped" image="https://cdn.jsdelivr.net/gh/opral/monorepo@latest/inlang/source-code/paraglide/paraglide-js/assets/unused-translations.png"></doc-feature>
|
|
15
|
+
<doc-feature title="Tiny Bundle-Size" image="https://cdn.jsdelivr.net/gh/opral/monorepo@latest/inlang/source-code/paraglide/paraglide-js/assets/reduced-payload.png"></doc-feature>
|
|
16
|
+
<doc-feature title="Typesafe" image="https://cdn.jsdelivr.net/gh/opral/monorepo@latest/inlang/source-code/paraglide/paraglide-js/assets/typesafe.png"></doc-feature>
|
|
19
17
|
</doc-features>
|
|
20
18
|
|
|
21
19
|
### Treeshaking
|
|
@@ -29,7 +27,7 @@ Treeshaking gives us superpowers. With it, each page of your app only loads the
|
|
|
29
27
|
|
|
30
28
|
### 1. Initialize paraglide-js
|
|
31
29
|
|
|
32
|
-
Initialize
|
|
30
|
+
Initialize ParaglideJS whith:
|
|
33
31
|
|
|
34
32
|
```bash
|
|
35
33
|
npx @inlang/paraglide-js@latest init
|
|
@@ -46,10 +44,10 @@ This will:
|
|
|
46
44
|
Adapters are framework-integrations for Paraglide. If you are using a framework, using an adapter is recommended , but not required.
|
|
47
45
|
|
|
48
46
|
<doc-links>
|
|
49
|
-
<doc-link title="Adapter for NextJS" icon="tabler:brand-nextjs" href="
|
|
50
|
-
<doc-link title="Adapter for SvelteKit" icon="simple-icons:svelte" href="
|
|
51
|
-
<doc-link title="Adapter for
|
|
52
|
-
<doc-link title="Adapter for
|
|
47
|
+
<doc-link title="Adapter for NextJS" icon="tabler:brand-nextjs" href="/m/osslbuzt/library-inlang-paraglideJsAdapterNextJs" description="Go to Library"></doc-link>
|
|
48
|
+
<doc-link title="Adapter for SvelteKit" icon="simple-icons:svelte" href="/m/dxnzrydw/library-inlang-paraglideJsAdapterSvelteKit" description="Go to Library"></doc-link>
|
|
49
|
+
<doc-link title="Adapter for Astro" icon="devicon-plain:astro" href="/m/iljlwzfs/library-inlang-paraglideJsAdapterAstro" description="Go to Library"></doc-link>
|
|
50
|
+
<doc-link title="Adapter for SolidJS" icon="tabler:brand-solidjs" href="/m/n860p17j/library-inlang-paraglideJsAdapterSolidStart" description="Go to Library"></doc-link>
|
|
53
51
|
</doc-links>
|
|
54
52
|
|
|
55
53
|
#### Alternatively, [you can write your own adapter](#writing-an-adapter)
|
|
@@ -58,11 +56,10 @@ Adapters are framework-integrations for Paraglide. If you are using a framework,
|
|
|
58
56
|
|
|
59
57
|
Running your `build` script will generate a `src/paraglide` folder. This folder contains all the code that you need to use paraglide-js.
|
|
60
58
|
|
|
61
|
-
> Tip: If you are using a bundler, you can set up an alias to `./src/paraglide` to make the imports shorter.
|
|
62
|
-
|
|
63
59
|
## Adding Messages
|
|
64
60
|
|
|
65
|
-
By default, paraglide expects your messages to be in `messages/{lang}.json`.
|
|
61
|
+
By default, paraglide expects your messages to be in `messages/{lang}.json`.
|
|
62
|
+
|
|
66
63
|
```json
|
|
67
64
|
{
|
|
68
65
|
"hello": "Hello world!"
|
|
@@ -92,22 +89,20 @@ const season = {
|
|
|
92
89
|
summer: m.summer,
|
|
93
90
|
autumn: m.autumn,
|
|
94
91
|
winter: m.winter,
|
|
95
|
-
} as const
|
|
92
|
+
} as const
|
|
96
93
|
|
|
97
94
|
const msg = season["spring"]() // Hello spring!
|
|
98
95
|
```
|
|
99
96
|
|
|
97
|
+
### Using the [Sherlock IDE Extension](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) (optional)
|
|
100
98
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
[Sherlock](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) integrates with paraglide to give you the optimal dev-experience.
|
|
99
|
+
[Sherlock](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) integrates with paraglide to give you the optimal dev-experience.
|
|
104
100
|
|
|
105
101
|

|
|
106
102
|
|
|
107
103
|
## Adding Languages
|
|
108
104
|
|
|
109
|
-
You can declare which languages you support in `./project.inlang/settings.json
|
|
110
|
-
|
|
105
|
+
You can declare which languages you support in `./project.inlang/settings.json`.
|
|
111
106
|
```json
|
|
112
107
|
// project.inlang/settings.json
|
|
113
108
|
{
|
|
@@ -161,45 +156,45 @@ There are a few things to know about `onSetLanguageTag()`:
|
|
|
161
156
|
|
|
162
157
|
## Getting a message in a specific language
|
|
163
158
|
|
|
164
|
-
You can import a message in a specific language from `paraglide/messages/{lang}.js`.
|
|
159
|
+
You can import a message in a specific language from `paraglide/messages/{lang}.js`.
|
|
165
160
|
|
|
166
161
|
```ts
|
|
167
162
|
import * as m from "./paraglide/messages/de.js"
|
|
168
163
|
m.hello() // Hallo Welt
|
|
169
164
|
```
|
|
170
165
|
|
|
171
|
-
If you want to force a language, but don't know ahead of time
|
|
166
|
+
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.
|
|
172
167
|
|
|
173
168
|
```js
|
|
174
169
|
import * as m from "./paraglide/messages.js"
|
|
175
170
|
const msg = m.hello({ name: "Samuel" }, { languageTag: "de" }) // Hallo Samuel!
|
|
176
171
|
```
|
|
177
172
|
|
|
178
|
-
##
|
|
173
|
+
## Lazy-Loading
|
|
179
174
|
|
|
180
175
|
Paraglide consciously discourages lazy-loading translations since it seriously hurts
|
|
181
176
|
your web-vitals. Learn more about why lazy-loading is bad & what to do instead in [this blog post](https://inlang.com/g/mqlyfa7l/guide-lorissigrist-dontlazyload).
|
|
182
177
|
|
|
183
|
-
If you _really_ want to do it anway, you can lazily import the language-specific message files. Be careful with this
|
|
178
|
+
If you _really_ want to do it anway, you can lazily import the language-specific message files. Be careful with this.
|
|
184
179
|
|
|
185
180
|
```ts
|
|
186
181
|
const lazyGerman = await import("./paraglide/messages/de.js")
|
|
182
|
+
lazyGerman.hello() // Hallo Welt
|
|
187
183
|
```
|
|
188
184
|
|
|
189
185
|
## Usage with a Bundler
|
|
190
186
|
|
|
191
|
-
|
|
192
|
-
are using one we recommed using the corresponding plugin.
|
|
187
|
+
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.
|
|
193
188
|
|
|
194
|
-
-
|
|
195
|
-
-
|
|
196
|
-
-
|
|
197
|
-
|
|
198
|
-
|
|
189
|
+
<doc-links>
|
|
190
|
+
<doc-link title="Vite Plugin" icon="tabler:brand-vite" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-js-adapter-vite" description="Go to Github"></doc-link>
|
|
191
|
+
<doc-link title="Rollup Plugin" icon="file-icons:rollup" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-js-adapter-rollup" description="Go to Github"></doc-link>
|
|
192
|
+
<doc-link title="Webpack Plugin" icon="mdi:webpack" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-js-adapter-webpack" description="Go to Github"></doc-link>
|
|
193
|
+
</doc-links>
|
|
199
194
|
|
|
200
195
|
# Playground
|
|
201
196
|
|
|
202
|
-
|
|
197
|
+
Find examples for how to use paraglide on codesandbox or in [our GitHub repository](https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide).
|
|
203
198
|
|
|
204
199
|
<doc-links>
|
|
205
200
|
<doc-link title="NextJS + Paraglide JS" icon="lucide:codesandbox" href="https://stackblitz.com/~/LorisSigrist/paraglide-next-app-router-example" description="Play around with NextJS and Paraglide JS"></doc-link>
|
|
@@ -209,13 +204,17 @@ You can find many examples for how to use paraglide on codesandbox, or in [our G
|
|
|
209
204
|
|
|
210
205
|
# Architecture
|
|
211
206
|
|
|
212
|
-
|
|
207
|
+
ParaglideJS leverages a compiler to generate vanilla JavaScript functions from your messages. We call these "message functions".
|
|
208
|
+
|
|
209
|
+
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.
|
|
213
210
|
|
|
214
|
-
|
|
211
|
+
This avoids many edge cases associated with reactivity, lazy-loading and namespacing that other i18n libraries have to work around.
|
|
212
|
+
|
|
213
|
+
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.
|
|
215
214
|
|
|
216
215
|

|
|
217
216
|
|
|
218
|
-
|
|
217
|
+
Paraglide consists of four main parts:
|
|
219
218
|
|
|
220
219
|
| Part | Description |
|
|
221
220
|
| ------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -226,17 +225,14 @@ Inlang Paraglide-JS consists of four main parts:
|
|
|
226
225
|
|
|
227
226
|
## Compiler
|
|
228
227
|
|
|
229
|
-
The compiler loads an
|
|
230
|
-
|
|
231
|
-
#### Example
|
|
228
|
+
The compiler loads an Inlang project and compiles the messages into tree-shakable and typesafe message functions.
|
|
232
229
|
|
|
233
230
|
**Input**
|
|
234
231
|
|
|
235
232
|
```js
|
|
236
233
|
// messages/en.json
|
|
237
234
|
{
|
|
238
|
-
"hello": "Hello {name}!"
|
|
239
|
-
"loginButton": "Login"
|
|
235
|
+
"hello": "Hello {name}!"
|
|
240
236
|
}
|
|
241
237
|
```
|
|
242
238
|
|
|
@@ -250,94 +246,57 @@ The compiler loads an inlang project and compiles the messages into tree-shakabl
|
|
|
250
246
|
* @param {string} params.name
|
|
251
247
|
*/
|
|
252
248
|
export const hello = (params) => `Hello ${params.name}!`
|
|
253
|
-
|
|
254
|
-
/** ... */
|
|
255
|
-
export const loginButton = () => "Login"
|
|
256
249
|
```
|
|
257
250
|
|
|
258
251
|
## Messages
|
|
259
252
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
The namespace import ensures that bundlers like Rollup, Webpack, or Turbopack can tree-shake the messages that are not used.
|
|
263
|
-
|
|
264
|
-
#### Example
|
|
265
|
-
|
|
266
|
-
Three compiled message functions exist in an example project.
|
|
267
|
-
|
|
268
|
-
```js
|
|
269
|
-
// src/paraglide/messages.js
|
|
270
|
-
|
|
271
|
-
/** ... */
|
|
272
|
-
export const hello = (params) => `Hello ${params.name}!`
|
|
273
|
-
|
|
274
|
-
/** ... */
|
|
275
|
-
export const loginButton = () => "Login"
|
|
276
|
-
|
|
277
|
-
/** ... */
|
|
278
|
-
export const loginHeader = (params) => `Hello ${params.name}, please login to continue.`
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
Only the message `hello` is used in the source code.
|
|
253
|
+
By convention we import the compiled funcitions with a wildcard import.
|
|
282
254
|
|
|
283
255
|
```js
|
|
284
|
-
// src/my-code.js
|
|
285
256
|
import * as m from "../paraglide/messages.js"
|
|
286
|
-
|
|
287
|
-
console.log(m.hello({ name: "Samuel" }))
|
|
288
257
|
```
|
|
289
258
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
```js
|
|
293
|
-
// dist/my-code.js
|
|
294
|
-
const hello = (params) => `Hello ${params.name}!`
|
|
295
|
-
|
|
296
|
-
console.log(hello({ name: "Samuel" }))
|
|
297
|
-
```
|
|
259
|
+
Bundlers like Rollup, Webpack, or Turbopack tree-shake the messages that are not used, so using a wildcard import is perfectly fine.
|
|
298
260
|
|
|
299
261
|
# Writing an Adapter
|
|
300
262
|
|
|
301
|
-
An "
|
|
263
|
+
An "Adapter" is a library that integrates with a framework's liefcycle and does two things:
|
|
302
264
|
|
|
303
|
-
|
|
304
|
-
|
|
265
|
+
1. Calls `setLanguageTag()` at appropriate times to set the language
|
|
266
|
+
2. Reacts to `onSetLanguageTag()`, usually by navigating or relading the page.
|
|
305
267
|
|
|
306
|
-
|
|
268
|
+
This example adapts Paraglide to a fictitious fullstack framework.
|
|
307
269
|
|
|
308
270
|
```tsx
|
|
309
|
-
import { setLanguageTag, onSetLanguageTag } from "../paraglide/runtime.js"
|
|
310
|
-
import { isServer, request, render } from "@example/framework"
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
// per-request basis. Hence, we need to pass a getter
|
|
314
|
-
// function () => string to setLanguageTag.
|
|
315
|
-
//
|
|
316
|
-
// Most frameworks offer a way to access the current
|
|
317
|
-
// request. In this example, we assume that the language tag
|
|
318
|
-
// is available in the request object.
|
|
271
|
+
import { setLanguageTag, onSetLanguageTag, type AvailableLanguageTag } from "../paraglide/runtime.js"
|
|
272
|
+
import { isServer, isClient, request, render } from "@example/framework"
|
|
273
|
+
import { detectLanguage } from "./utils.js"
|
|
274
|
+
|
|
319
275
|
if (isServer) {
|
|
320
|
-
|
|
276
|
+
// On the server the language tag needs to be resolved on a per-request basis.
|
|
277
|
+
// Pass a getter function that resolves the language from the correct request
|
|
278
|
+
|
|
279
|
+
const detectLanguage = (request: Request) : AvailableLanguageTag => {
|
|
280
|
+
//your logic ...
|
|
281
|
+
}
|
|
282
|
+
setLanguageTag(() => detectLanguage(request))
|
|
321
283
|
}
|
|
322
|
-
// On a client, the language tag could be resolved from
|
|
323
|
-
// the document's html lang tag.
|
|
324
|
-
//
|
|
325
|
-
// In addition, we also want to trigger a side-effect
|
|
326
|
-
// to request the site if the language changes.
|
|
327
|
-
else {
|
|
328
|
-
setLanguageTag(() => document.documentElement.lang)
|
|
329
284
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
285
|
+
if(isClient) {
|
|
286
|
+
// On the client, the language tag can be resolved from
|
|
287
|
+
// the document's html lang tag.
|
|
288
|
+
setLanguageTag(() => document.documentElement.lang)
|
|
333
289
|
|
|
334
|
-
//
|
|
290
|
+
// When the language changes we want to re-render the page in the new language
|
|
291
|
+
// Here we just navigate to the new route
|
|
292
|
+
//
|
|
293
|
+
// Make sure to call `onSetLanguageTag` after `setLanguageTag` to avoid an infinite loop.
|
|
335
294
|
onSetLanguageTag((newLanguageTag) => {
|
|
336
295
|
window.location.pathname = `/${newLanguageTag}${window.location.pathname}`
|
|
337
296
|
})
|
|
338
297
|
}
|
|
339
298
|
|
|
340
|
-
//
|
|
299
|
+
// Render the app once the setup is done
|
|
341
300
|
render((page) => (
|
|
342
301
|
<html lang={request.languageTag}>
|
|
343
302
|
<body>{page}</body>
|
|
@@ -347,15 +306,15 @@ render((page) => (
|
|
|
347
306
|
|
|
348
307
|
# Community
|
|
349
308
|
|
|
350
|
-
We are grateful for all the support we get from the community. Here are a few comments we've received recently.
|
|
309
|
+
We are grateful for all the support we get from the community. Here are a few comments we've received recently.
|
|
351
310
|
|
|
352
311
|
If you have any feedback / problems, please let us know on [GitHub](https://github.com/opral/inlang-paraglide-js/issues/new)
|
|
353
312
|
|
|
354
313
|
<doc-comments>
|
|
355
314
|
<doc-comment text="Just tried Paraglide JS from @inlangHQ. This is how i18n should be done! Totally new level of DX for both implementation and managing translations! Superb support for SvelteKit as well ⭐" author="Patrik Engborg" icon="mdi:twitter" data-source="https://twitter.com/patrikengborg/status/1747260930873053674"></doc-comment>
|
|
315
|
+
<doc-comment text="I was messing with various i18n frameworks and tools in combination with Astro, and i must say that Paraglide was the smoothest experience. I have migrated my website from i18next and it was a breeze. SSG and SSR worked out of the box (which was the first one for me), and overall DX is great. Thanks for your work!" author="Dally H" icon="mdi:discord" data-source="https://discord.com/channels/897438559458430986/1096039983116202034/1220796380772307004"></doc-comment>
|
|
356
316
|
<doc-comment text="The lib is great guys!" author="ktarmyshov" icon="mdi:github"></doc-comment>
|
|
357
317
|
<doc-comment text="Thank you for that huge work you have done and still doing!" author="ZerdoX-x" icon="mdi:github"></doc-comment>
|
|
358
|
-
<doc-comment text="[...] the switch between the sdk-js and paraglide has been pretty great! " author="albbus" icon="mdi:discord"></doc-comment>
|
|
359
318
|
<doc-comment text="Thanks for all the great work @Samuel Stroschein" author="Willem" icon="mdi:discord"></doc-comment>
|
|
360
319
|
</doc-comments>
|
|
361
320
|
|
|
@@ -374,9 +333,13 @@ Of course, we're not done yet! We plan on adding the following features to Parag
|
|
|
374
333
|
- Web Zurich December 2023
|
|
375
334
|
- [Svelte London January 2024](https://www.youtube.com/watch?v=eswNQiq4T2w&t=646s)
|
|
376
335
|
|
|
377
|
-
#
|
|
336
|
+
# Tooling
|
|
337
|
+
|
|
338
|
+
Paraglide JS is part of the Inlang ecosystem and integrates nicely with all the other Inlang compatible tools.
|
|
339
|
+
|
|
340
|
+
As a developer, you will love the [Sherlock IDE extension](http://localhost:4001/m/r7kp499g/app-inlang-ideExtension).
|
|
378
341
|
|
|
379
|
-
|
|
342
|
+
If you are working with translators or designers you will find these tools useful:
|
|
380
343
|
|
|
381
344
|
- [Fink](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor) - An Online UI for editing translations. Changes made in Fink are committed to a translation branch or submitted via pull request.
|
|
382
345
|
- [Parrot](https://inlang.com/m/gkrpgoir/app-parrot-figmaPlugin) - 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.
|