@inlang/paraglide-js
Advanced tools
Comparing version 1.9.1 to 1.10.0
@@ -98,5 +98,4 @@ function negotiateLanguagePreferences(accept, availableLanguageTags) { | ||
base = ""; | ||
if (!path.startsWith(base)) { | ||
if (!path.startsWith(base)) | ||
return void 0; | ||
} | ||
const pathWithoutBase = path.replace(base, ""); | ||
@@ -106,43 +105,14 @@ const maybeLang = pathWithoutBase.split("/")[1]; | ||
return void 0; | ||
for (const lang of availableLanguageTags) { | ||
if (lang.toLowerCase() === maybeLang.toLowerCase()) { | ||
return lang; | ||
} | ||
} | ||
return void 0; | ||
return availableLanguageTags.map(lower).includes(lower(maybeLang)) ? maybeLang : void 0; | ||
} | ||
const EMPTY = { type: "static", content: "", matched: false }; | ||
const lower = (s) => s.toLowerCase(); | ||
const STATIC = 0; | ||
const OPTIONAL = 1; | ||
const REST = 2; | ||
const REQUIRED = 4; | ||
const PART_TYPE = 0; | ||
const PART_CONTENT = 1; | ||
const PART_MATCHED = 2; | ||
function sort_routes(routes) { | ||
const segment_cache = /* @__PURE__ */ new Map(); | ||
function split(id) { | ||
const parts = []; | ||
let i = 0; | ||
while (i <= id.length) { | ||
const start = id.indexOf("[", i); | ||
if (start === -1) { | ||
parts.push({ type: "static", content: id.slice(i), matched: false }); | ||
break; | ||
} | ||
parts.push({ type: "static", content: id.slice(i, start), matched: false }); | ||
const type = id[start + 1] === "[" ? "optional" : id[start + 1] === "." ? "rest" : "required"; | ||
const delimiter = type === "optional" ? "]]" : "]"; | ||
const end = id.indexOf(delimiter, start); | ||
if (end === -1) { | ||
throw new Error(`Invalid route ID ${id}`); | ||
} | ||
const content = id.slice(start, i = end + delimiter.length); | ||
parts.push({ | ||
type, | ||
content, | ||
matched: content.includes("=") | ||
}); | ||
} | ||
return parts; | ||
} | ||
function get_parts(segment) { | ||
if (!segment_cache.has(segment)) { | ||
segment_cache.set(segment, split(segment)); | ||
} | ||
return segment_cache.get(segment); | ||
} | ||
const get_parts = cached(split); | ||
return routes.sort((route_a, route_b) => { | ||
@@ -153,8 +123,12 @@ var _a, _b, _c, _d, _e, _f; | ||
for (let i = 0; i < Math.max(segments_a.length, segments_b.length); i += 1) { | ||
const segment_a = segments_a[i] ?? [EMPTY]; | ||
const segment_b = segments_b[i] ?? [EMPTY]; | ||
const segment_a = segments_a[i]; | ||
const segment_b = segments_b[i]; | ||
if (!segment_a) | ||
return -1; | ||
if (!segment_b) | ||
return 1; | ||
for (let j = 0; j < Math.max(segment_a.length, segment_b.length); j += 1) { | ||
const a = segment_a[j]; | ||
const b = segment_b[j]; | ||
const dynamic = !!(j % 2); | ||
const dynamic = (a == null ? void 0 : a[PART_TYPE]) || (b == null ? void 0 : b[PART_TYPE]); | ||
if (dynamic) { | ||
@@ -165,33 +139,26 @@ if (!a) | ||
return 1; | ||
const next_a = ((_a = segment_a[j + 1]) == null ? void 0 : _a.content) || ((_c = (_b = segments_a[i + 1]) == null ? void 0 : _b[0]) == null ? void 0 : _c.content); | ||
const next_b = ((_d = segment_b[j + 1]) == null ? void 0 : _d.content) || ((_f = (_e = segments_b[i + 1]) == null ? void 0 : _e[0]) == null ? void 0 : _f.content); | ||
if (a.type === "rest" && b.type === "rest") { | ||
if (next_a && next_b) | ||
const next_a = ((_a = segment_a[j + 1]) == null ? void 0 : _a[PART_CONTENT]) || ((_c = (_b = segments_a[i + 1]) == null ? void 0 : _b[0]) == null ? void 0 : _c[PART_CONTENT]); | ||
const next_b = ((_d = segment_b[j + 1]) == null ? void 0 : _d[PART_CONTENT]) || ((_f = (_e = segments_b[i + 1]) == null ? void 0 : _e[0]) == null ? void 0 : _f[PART_CONTENT]); | ||
const both_have_next = next_a && next_b; | ||
const only_a_has_next = next_a && !next_b; | ||
const only_b_has_next = !next_a && next_b; | ||
if ((a[PART_TYPE] && b[PART_TYPE]) === REST) { | ||
if (both_have_next) | ||
continue; | ||
if (next_a) | ||
if (only_a_has_next) | ||
return -1; | ||
if (next_b) | ||
if (only_b_has_next) | ||
return 1; | ||
} | ||
if (a.type === "rest") { | ||
return next_a && !next_b ? -1 : 1; | ||
if (a[PART_TYPE] === REST) | ||
return only_a_has_next ? -1 : 1; | ||
if (b[PART_TYPE] === REST) | ||
return only_b_has_next ? 1 : -1; | ||
if (a[PART_MATCHED] !== b[PART_MATCHED]) | ||
return (-1) ** +a[PART_MATCHED]; | ||
if (a[PART_TYPE] !== b[PART_TYPE]) { | ||
return (-1) ** +(a[PART_TYPE] > b[PART_TYPE]); | ||
} | ||
if (b.type === "rest") { | ||
return next_b && !next_a ? 1 : -1; | ||
} | ||
if (a.matched !== b.matched) { | ||
return a.matched ? -1 : 1; | ||
} | ||
if (a.type !== b.type) { | ||
if (a.type === "required") | ||
return -1; | ||
if (b.type === "required") | ||
return 1; | ||
} | ||
} else if ((a == null ? void 0 : a.content) !== (b == null ? void 0 : b.content)) { | ||
if (a === EMPTY) | ||
return -1; | ||
if (b === EMPTY) | ||
return 1; | ||
return sort_static(a.content, b.content); | ||
} else if ((a == null ? void 0 : a[PART_CONTENT]) !== (b == null ? void 0 : b[PART_CONTENT])) { | ||
return sort_static(a[PART_CONTENT], b[PART_CONTENT]); | ||
} | ||
@@ -203,24 +170,37 @@ } | ||
} | ||
function split_route_id(id) { | ||
return get_route_segments( | ||
id.replace(/\[\[[^\]]+\]\](?!$)/g, "") | ||
).filter(Boolean); | ||
function cached(fn) { | ||
const cache = /* @__PURE__ */ new Map(); | ||
return (arg) => { | ||
if (!cache.has(arg)) | ||
cache.set(arg, fn(arg)); | ||
return cache.get(arg); | ||
}; | ||
} | ||
function split(id) { | ||
const parts = []; | ||
let i = 0; | ||
while (i <= id.length) { | ||
const start = id.indexOf("[", i); | ||
const entirelyStatic = start === -1; | ||
parts.push([STATIC, id.slice(i, entirelyStatic ? void 0 : start), false]); | ||
if (entirelyStatic) | ||
break; | ||
const type = id[start + 1] === "[" ? OPTIONAL : id[start + 1] === "." ? REST : REQUIRED; | ||
const endBrackets = type === OPTIONAL ? "]]" : "]"; | ||
const endBracketIdx = id.indexOf(endBrackets, start); | ||
if (endBracketIdx === -1) | ||
throw new Error(`Invalid route definition ${id}`); | ||
const content = id.slice(start, i = endBracketIdx + endBrackets.length); | ||
parts.push([type, content, content.includes("=")]); | ||
} | ||
return parts; | ||
} | ||
const split_route_id = (id) => id.replace(/\[\[[^\]]+\]\](?!$)/g, "").split("/").filter(Boolean); | ||
function sort_static(a, b) { | ||
if (a === b) | ||
return 0; | ||
let i = 0; | ||
while (a[i] || b[i]) { | ||
const char_a = a[i]; | ||
const char_b = b[i]; | ||
if (char_a !== char_b) { | ||
if (char_a === void 0) | ||
return 1; | ||
if (char_b === void 0) | ||
return -1; | ||
return char_a < char_b ? -1 : 1; | ||
} | ||
i++; | ||
} | ||
return 0; | ||
let idx = 0; | ||
while (a[idx] === b[idx]) | ||
idx++; | ||
return !a[idx] ? 1 : !b[idx] ? -1 : a[idx] < b[idx] ? -1 : 1; | ||
} | ||
@@ -310,5 +290,4 @@ const param_pattern = /^(\[)?(\.\.\.)?(\w+)(?:=(\w+))?(\])?$/; | ||
} | ||
if (param.matcher && !matchers[param.matcher]) { | ||
if (param.matcher && !matchers[param.matcher]) | ||
return void 0; | ||
} | ||
const matcher = matchers[param.matcher] ?? (() => true); | ||
@@ -365,11 +344,8 @@ if (matcher(value)) { | ||
const params = exec(match, route.params, matchers); | ||
if (!params) | ||
continue; | ||
return { params, id: pathDefinition }; | ||
if (params) | ||
return { params, id: pathDefinition }; | ||
} | ||
return void 0; | ||
} | ||
function removeTrailingSlash(path) { | ||
return path.endsWith("/") ? path.slice(0, -1) : path; | ||
} | ||
const removeTrailingSlash = (path) => path.endsWith("/") ? path.slice(0, -1) : path; | ||
const get_route_segments = (route) => route.slice(1).split("/"); | ||
@@ -376,0 +352,0 @@ function validatePathTranslations(pathTranslations, availableLanguageTags, matchers) { |
@@ -0,3 +1,3 @@ | ||
import { MessageIndexFunction } from '~/index.js'; | ||
import { PathDefinitionTranslations } from './routeDefinitions.js'; | ||
import { MessageIndexFunction } from '~/index.js'; | ||
@@ -4,0 +4,0 @@ /** |
@@ -47,10 +47,2 @@ export type PathDefinitionTranslations<T extends string = string> = { | ||
} | undefined; | ||
/** | ||
* Splits a route id into its segments, removing segments that | ||
* don't affect the path (i.e. groups). The root route is represented by `/` | ||
* and will be returned as `['']`. | ||
* @param {string} route | ||
* @returns string[] | ||
*/ | ||
export declare const get_route_segments: (route: string) => string[]; | ||
export {}; |
@@ -0,5 +1,5 @@ | ||
import { Command } from 'commander'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { Command } from 'commander'; | ||
@@ -6,0 +6,0 @@ export declare const initCommand: Command; |
@@ -0,3 +1,3 @@ | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { CliStep } from '../utils.js'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
@@ -4,0 +4,0 @@ export declare const checkForUncommittedChanges: CliStep<{ |
@@ -0,5 +1,5 @@ | ||
import { InlangProject } from '@inlang/sdk'; | ||
import { Repository } from '@lix-js/client'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { CliStep } from '../utils.js'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { InlangProject } from '@inlang/sdk'; | ||
@@ -6,0 +6,0 @@ export declare const initializeInlangProject: CliStep<{ |
@@ -0,5 +1,5 @@ | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../utils.js'; | ||
import { InlangProject } from '@inlang/sdk'; | ||
import { CliStep } from '../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
@@ -6,0 +6,0 @@ export declare const maybeAddNinja: CliStep<{ |
@@ -0,5 +1,5 @@ | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../utils.js'; | ||
import { InlangProject } from '@inlang/sdk'; | ||
import { CliStep } from '../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
@@ -6,0 +6,0 @@ export declare const maybeAddSherlock: CliStep<{ |
@@ -0,3 +1,3 @@ | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { CliStep } from '../utils.js'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
@@ -4,0 +4,0 @@ export declare const promptForOutdir: CliStep<{ |
@@ -0,4 +1,4 @@ | ||
import { InlangProject } from '@inlang/sdk'; | ||
import { CliStep } from '../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../utils.js'; | ||
import { InlangProject } from '@inlang/sdk'; | ||
@@ -5,0 +5,0 @@ export declare const runCompiler: CliStep<{ |
@@ -0,4 +1,4 @@ | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { CliStep } from '../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../utils.js'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
@@ -5,0 +5,0 @@ export declare function updatePackageJson(opt: { |
@@ -0,4 +1,4 @@ | ||
import { Repository } from '@lix-js/client'; | ||
import { CliStep } from '../utils.js'; | ||
import { Logger } from '~/services/logger/index.js'; | ||
import { CliStep } from '../utils.js'; | ||
import { Repository } from '@lix-js/client'; | ||
@@ -5,0 +5,0 @@ export declare const maybeChangeTsConfig: CliStep<{ |
@@ -0,3 +1,3 @@ | ||
import { LanguageTag, Message } from '@inlang/sdk'; | ||
import { Params } from './paramsType.js'; | ||
import { LanguageTag, Message } from '@inlang/sdk'; | ||
@@ -4,0 +4,0 @@ type Resource = { |
@@ -0,3 +1,3 @@ | ||
import { LanguageTag, Message } from '@inlang/sdk'; | ||
import { Params } from './paramsType.js'; | ||
import { LanguageTag, Message } from '@inlang/sdk'; | ||
@@ -4,0 +4,0 @@ export declare const messageIndexFunction: (args: { |
export { compile } from './compiler/compile.js'; | ||
export { writeOutput } from './services/file-handling/write-output.js'; | ||
export { Logger, type LoggerOptions } from './services/logger/index.js'; | ||
export { classifyProjectErrors } from './services/error-handling.js'; | ||
export type MessageIndexFunction<T extends string> = (params: Record<string, never>, options: { | ||
@@ -5,0 +6,0 @@ languageTag: T; |
@@ -0,3 +1,3 @@ | ||
import { PostHog } from 'posthog-node'; | ||
import { TelemetryEvents } from './events.js'; | ||
import { PostHog } from 'posthog-node'; | ||
@@ -4,0 +4,0 @@ /** |
{ | ||
"name": "@inlang/paraglide-js", | ||
"type": "module", | ||
"version": "1.9.1", | ||
"version": "1.10.0", | ||
"license": "Apache-2.0", | ||
@@ -65,9 +65,9 @@ "publishConfig": { | ||
"vitest": "0.34.3", | ||
"@inlang/cross-sell-ninja": "0.0.18", | ||
"@inlang/cross-sell-sherlock": "0.0.4", | ||
"@inlang/cross-sell-ninja": "0.0.32", | ||
"@inlang/language-tag": "1.5.1", | ||
"@inlang/sdk": "0.34.10", | ||
"@inlang/plugin-message-format": "2.2.0", | ||
"@lix-js/client": "1.4.0", | ||
"@lix-js/fs": "1.0.0" | ||
"@lix-js/client": "2.2.0", | ||
"@inlang/sdk": "0.36.0", | ||
"@lix-js/fs": "2.1.0" | ||
}, | ||
@@ -74,0 +74,0 @@ "exports": { |
201
README.md
@@ -0,1 +1,7 @@ | ||
--- | ||
title: "Getting Started" | ||
description: "Learn how to install the ParaglideJS i18n library in your project" | ||
--- | ||
[![Inlang-ecosystem compatibility badge](https://cdn.jsdelivr.net/gh/opral/monorepo@main/inlang/assets/md-badges/inlang.svg)](https://inlang.com) | ||
# Getting started | ||
@@ -20,3 +26,3 @@ | ||
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 are stored in `messages/{lang}.json` as key-value pairs. You can add parameters with curly braces. | ||
@@ -37,11 +43,10 @@ ```diff | ||
If you are using Bundler, you can use one of the [Bundler Plugins](#usage-with-a-bundler) to recompile automatically. | ||
If you are using a Bundler use one of the [Bundler Plugins](usage#usage-with-a-bundler) to recompile automatically. | ||
## Using Messages in Code | ||
After running the compiler, you can import messages with `import * as m from "./paraglide/messages"`. | ||
After running the compiler import the messages with `import * as m from "./paraglide/messages"`. By convention, a wildcard import is used. | ||
```js | ||
import * as m from "./paraglide/messages.js" | ||
import { setLanguageTag } from "./paraglide/runtime.js" | ||
@@ -52,190 +57,2 @@ m.hello() // Hello world! | ||
## 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 | ||
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! | ||
``` | ||
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()` with the desired language, or a getter function. Any subsequent calls to either `languageTag()` or a message function will use the new language tag. | ||
```js | ||
import { setLanguageTag } from "./paraglide/runtime.js" | ||
import * as m from "./paraglide/messages.js" | ||
setLanguageTag("de") | ||
m.hello() // Hallo Welt! | ||
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. Always use a getter-function that returns the current language tag _for the current request_. | ||
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](https://www.inlang.com/m/8y8sxj09/library-inlang-languageTag) changes. | ||
If you are using a [framework-specific library](#use-it-with-your-favorite-framework) this is done for you. | ||
```js | ||
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 | ||
``` | ||
Things to know about `onSetLanguageTag()`: | ||
- You can only register one listener. If you register a second listener it will throw an error. | ||
- `onSetLanguageTag` 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`. | ||
```ts | ||
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. | ||
```js | ||
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 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. | ||
```ts | ||
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 building your app. | ||
<doc-links> | ||
<doc-link title="Vite Plugin" icon="tabler:brand-vite" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-vite" description="Go to Github"></doc-link> | ||
<doc-link title="Rollup Plugin" icon="file-icons:rollup" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-rollup" description="Go to Github"></doc-link> | ||
<doc-link title="Webpack Plugin" icon="mdi:webpack" href="https://github.com/opral/monorepo/tree/main/inlang/source-code/paraglide/paraglide-webpack" description="Go to Github"></doc-link> | ||
</doc-links> | ||
## Configuration | ||
Most of the configuration is done in `./project.inlang/settings.json`, except for paraglide's output directory, which needs to be passed in when calling the compiler. | ||
### Languages | ||
You can declare which languages you support in the `languageTags` array. | ||
```json | ||
// project.inlang/settings.json | ||
{ | ||
"languageTags": ["en", "de"] | ||
} | ||
``` | ||
Create the corresponding `messages/{lang}.json` files and get translating! | ||
### Moving the Translation Files | ||
If you want your language files to be in a different location you can change the `pathPattern` of the [Inlang-Message-Format plugin](https://inlang.com/m/reootnfj/plugin-inlang-messageFormat). | ||
```diff | ||
// project.inlang/settings.json | ||
{ | ||
"plugin.inlang.messageFormat": { | ||
- "pathPattern": "./messages/{languageTag}.json" | ||
+ "pathPattern": "./i18n/{languageTag}.json" | ||
} | ||
} | ||
``` | ||
# Playground | ||
@@ -242,0 +59,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1619857
75
47871
82