@inlang/paraglide-js
Advanced tools
Comparing version 1.5.0 to 1.6.0
@@ -9,7 +9,7 @@ /** | ||
export declare const compilePattern: (pattern: ({ | ||
value: string; | ||
type: "Text"; | ||
value: string; | ||
} | { | ||
name: string; | ||
type: "VariableReference"; | ||
name: string; | ||
})[]) => { | ||
@@ -16,0 +16,0 @@ params: Record<string, "NonNullable<unknown>">; |
@@ -5,1 +5,5 @@ export { cli } from './cli/main.js'; | ||
export { Logger, type LoggerOptions } from './services/logger/index.js'; | ||
export type MessageIndexFunction<T extends string> = (params?: Record<string, never>, options?: { | ||
languageTag: T; | ||
}) => string; | ||
export type MessageFunction = (params?: Record<string, never>) => string; |
{ | ||
"name": "@inlang/paraglide-js", | ||
"type": "module", | ||
"version": "1.5.0", | ||
"version": "1.6.0", | ||
"license": "Apache-2.0", | ||
@@ -65,10 +65,10 @@ "publishConfig": { | ||
"vitest": "0.34.3", | ||
"@inlang/cross-sell-sherlock": "0.0.4", | ||
"@inlang/env-variables": "0.2.0", | ||
"@inlang/cross-sell-sherlock": "0.0.4", | ||
"@inlang/language-tag": "1.5.1", | ||
"@inlang/plugin-message-format": "2.1.1", | ||
"@inlang/sdk": "0.31.0", | ||
"@inlang/telemetry": "0.3.21", | ||
"@inlang/telemetry": "0.3.22", | ||
"@lix-js/client": "1.2.0", | ||
"@lix-js/fs": "1.0.0" | ||
"@lix-js/fs": "1.0.0", | ||
"@inlang/sdk": "0.32.0" | ||
}, | ||
@@ -83,2 +83,6 @@ "exports": { | ||
"types": "./dist/index.d.ts" | ||
}, | ||
"./internal/adapter-utils": { | ||
"import": "./dist/adapter-utils/index.js", | ||
"types": "./dist/adapter-utils/index.d.ts" | ||
} | ||
@@ -85,0 +89,0 @@ }, |
120
README.md
@@ -88,4 +88,30 @@ [<img src="https://cdn.jsdelivr.net/gh/opral/monorepo@latest/inlang/source-code/paraglide/paraglide-js/assets/header.png" alt="Dead Simple i18n. Typesafe, Small Footprint, Treeshsakeable Messages, IDE Integration, Framework Agnostic" width="10000000px" />](https://www.youtube.com/watch?v=-YES3CCAG90) | ||
To choose between messages at runtime create a map of messages and index into it. | ||
## Working with the Inlang Message Format | ||
Paraglide is part of the highly modular Inlang Ecosystem which supports many different Message Formats. By default, the [Inlang Message Format](https://inlang.com/m/reootnfj/plugin-inlang-messageFormat) is used. | ||
It expects messages to be in `messages/{lang}.json` relative to your repo root. | ||
```json | ||
//messages/en.json | ||
{ | ||
//the $schema key is automatically ignored | ||
"$schema": "https://inlang.com/schema/inlang-message-format", | ||
"hello_world: "Hello World!", | ||
"greeting": "Hello {name}!" | ||
} | ||
``` | ||
The `messages/{lang}.json` file contains a flat map of message IDs and their translations. You can use curly braces to insert `{parameters}` into translations | ||
**Nesting purposely isn't supported and likely won't be**. Nested messages are way harder to interact with from complementary tools like the [Sherlock IDE Extension](https://inlang.com/m/r7kp499g/app-inlang-ideExtension), the [Parrot Figma Plugin](https://inlang.com/m/gkrpgoir/app-parrot-figmaPlugin), or the [Fink Localization editor](https://inlang.com/m/tdozzpar/app-inlang-finkLocalizationEditor). Intellisense also becomes less helpful since it only shows the messages at the current level, not all messages. Additionally enforcing an organization-style side-steps organization discussions with other contributors. | ||
### Complex Formatting | ||
The Message Format is still quite young, so advanced formats like plurals, param-formatting, and markup interpolation are currently not supported but are all on our roadmap. | ||
If you need complex formatting, like plurals, dates, currency, or markup interpolation you can achieve them like so: | ||
For a message with multiple cases, aka a _select message_, you can define a message for each case & then use a Map in JS to index into it. | ||
```ts | ||
@@ -104,5 +130,42 @@ import * as m from "./paraglide/messages.js" | ||
For date & currency formatting use the `.toLocaleString` method on the `Date` or `Number`. | ||
```ts | ||
import * as m from "./paraglide/messages.js" | ||
import { languageTag } from "./paraglide/runtime.js" | ||
const todaysDate = new Date(); | ||
m.today_is_the({ | ||
date: todaysDate.toLocaleString(languageTag()) | ||
}) | ||
const price = 100; | ||
m.the_price_is({ | ||
price: price.toLocaleString(languageTag(), { | ||
style: "currency", | ||
currency: "EUR", | ||
}) | ||
}) | ||
``` | ||
You can put HTML into the messages. This is useful for links and images. | ||
```json | ||
// messages/en.json | ||
{ | ||
"you_must_agree_to_the_tos": "You must agree to the <a href='/en/tos'>Terms of Service</a>." | ||
} | ||
``` | ||
```json | ||
// messages/de.json | ||
{ | ||
you_must_agree_to_the_tos": "Sie müssen den <a href='/de/agb'>Nutzungsbedingungen</a> zustimmen." | ||
} | ||
``` | ||
There is currently no way to interpolate full-blown components into the messages. If you require components mid-message you will need to create a one-off component for that bit of text. | ||
## Setting the language | ||
You can set the [language tag](https://www.inlang.com/m/8y8sxj09/library-inlang-languageTag) by calling `setLanguageTag()`. Any subsequent calls to either `languageTag()` or a message function will use the new language tag. | ||
You can set the [language tag](https://www.inlang.com/m/8y8sxj09/library-inlang-languageTag) by calling `setLanguageTag()` with the desired language, or a getter function. Any subsequent calls to either `languageTag()` or a message function will use the new language tag. | ||
@@ -116,7 +179,7 @@ ```js | ||
setLanguageTag("en") | ||
setLanguageTag(()=>document.documentElement.lang /* en */ ) | ||
m.hello() // Hello world! | ||
``` | ||
The [language tag](https://www.inlang.com/m/8y8sxj09/library-inlang-languageTag) is global, so you need to be careful with it on the server to make sure multiple requests don't interfere with each other. | ||
The [language tag](https://www.inlang.com/m/8y8sxj09/library-inlang-languageTag) is global, so you need to be careful with it on the server to make sure multiple requests don't interfere with each other. Always use a getter-function that returns the current language tag _for the current request_. | ||
@@ -143,3 +206,3 @@ You will need to call `setLanguageTag` on both the server and the client since they run in separate processes. | ||
A few things to know about `onSetLanguageTag()`: | ||
Things to know about `onSetLanguageTag()`: | ||
@@ -167,6 +230,5 @@ - You can only register one listener. If you register a second listener it will throw an error. | ||
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 [our blog post on lazy-loading](https://inlang.com/g/mqlyfa7l/guide-lorissigrist-dontlazyload). | ||
Paraglide consciously discourages lazy-loading translations since it causes a render-fetch waterfall which seriously hurts your Web Vitals. Learn more about why lazy-loading is bad & what to do instead in [our blog post on lazy-loading](https://inlang.com/g/mqlyfa7l/guide-lorissigrist-dontlazyload). | ||
If you want to do it anyway, lazily import the language-specific message files. Be careful with this. | ||
If you want to do it anyway, lazily import the language-specific message files. | ||
@@ -211,14 +273,10 @@ ```ts | ||
// project.inlang/settings.json | ||
"plugin.inlang.messageFormat": { | ||
- "pathPattern": "./messages/{languageTag}.json" | ||
+ "pathPattern": "./i18n/{languageTag}.json" | ||
}, | ||
{ | ||
"plugin.inlang.messageFormat": { | ||
- "pathPattern": "./messages/{languageTag}.json" | ||
+ "pathPattern": "./i18n/{languageTag}.json" | ||
} | ||
} | ||
``` | ||
### Lint Rules | ||
If you're using the [Sherlock VS Code extension](https://inlang.com/m/r7kp499g/app-inlang-ideExtension) you might see warnings about certain messages. Perhaps they're duplicates, perhaps they're missing in one language. | ||
You can configure which lint-rules are active in `./project.inlang/settings.json`. Simply add or remove them from the `modules` array. | ||
# Playground | ||
@@ -236,7 +294,7 @@ | ||
ParaglideJS leverages a compiler to generate vanilla JavaScript functions from your messages. We call these "message functions". | ||
Paraglide uses a compiler to generate JS 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. | ||
Message Functions are fully typed using JSDoc. They are exported individually from the `messages.js` file making them tree-shakable. When called, they return a translated string. Message functions aren't reactive in any way, if you want a translation in another language you will need to re-call them. | ||
This avoids many edge cases associated with reactivity, lazy-loading, and namespacing that other i18n libraries have to work around. | ||
This design avoids many edge cases with reactivity, lazy-loading, and namespacing that other i18n libraries have to work around. | ||
@@ -281,12 +339,2 @@ 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. | ||
## Messages | ||
By convention, we import the compiled functions with a wildcard import. | ||
```js | ||
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 | ||
@@ -299,4 +347,6 @@ | ||
This example adapts Paraglide to a fictitious full-stack framework. | ||
Many popular frameworks already have adapters available, check out the [list of available adapters](#use-it-with-your-favorite-framework). | ||
If there isn't one for your framework, you can write your own. This example adapts Paraglide to a fictitious full-stack framework. | ||
```tsx | ||
@@ -328,3 +378,3 @@ import { | ||
// Here we just navigate to the new route | ||
// | ||
// Make sure to call `onSetLanguageTag` after `setLanguageTag` to avoid an infinite loop. | ||
@@ -351,2 +401,4 @@ onSetLanguageTag((newLanguageTag) => { | ||
- [ ] Markup Placeholders ([Join the Discussion](https://github.com/opral/monorepo/discussions/913)) | ||
- [ ] Component Interpolation | ||
- [ ] Per-Language Splitting without Lazy-Loading | ||
- [ ] Even Smaller Output | ||
@@ -361,3 +413,3 @@ | ||
# Tooling | ||
# Complementary Tooling | ||
@@ -364,0 +416,0 @@ Paraglide JS is part of the Inlang ecosystem and integrates nicely with all the other Inlang-compatible tools. |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1658044
59
48760
416