Skip to content

Commit 30a2d66

Browse files
add paraglide examples
1 parent 0babe5d commit 30a2d66

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+1823
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
count.txt
7+
.env
8+
.nitro
9+
.tanstack
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
}
11+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# TanSTack Router example
2+
3+
This example shows how to use Paraglide with TanStack Router. The source code can be found [here](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/examples/tanstack-router).
4+
5+
## Getting started
6+
7+
1. Init Paraglide JS
8+
9+
```bash
10+
npx @inlang/paraglide-js@latest init
11+
```
12+
13+
2. Add the vite plugin to your `vite.config.ts`:
14+
15+
```diff
16+
import { defineConfig } from 'vite'
17+
import react from '@vitejs/plugin-react'
18+
import { tanstackRouter } from '@tanstack/router-plugin/vite'
19+
+import { paraglideVitePlugin } from "@inlang/paraglide-js";
20+
21+
export default defineConfig({
22+
plugins: [
23+
tanstackRouter({ target: 'react', autoCodeSplitting: true }),
24+
react(),
25+
+ paraglideVitePlugin({
26+
+ project: "./project.inlang",
27+
+ outdir: "./app/paraglide",
28+
+ }),
29+
],
30+
});
31+
```
32+
33+
3. Done :)
34+
35+
Run the app and start translating. See the [basics documentation](/m/gerre34r/library-inlang-paraglideJs/basics) for information on how to use Paraglide's messages, parameters, and locale management.
36+
37+
## Rewrite URL
38+
39+
If you want to handle how the URL looks when the user changes the locale, you can rewrite the URL in the router.
40+
41+
```diff
42+
import { createRouter } from "@tanstack/react-router";
43+
import { routeTree } from "./routeTree.gen";
44+
+import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime.js";
45+
46+
const router = createRouter({
47+
routeTree,
48+
+ rewrite: {
49+
+ input: ({ url }) => deLocalizeUrl(url),
50+
+ output: ({ url }) => localizeUrl(url),
51+
},
52+
});
53+
```
54+
55+
In `__root.tsx` add a `beforeLoad` hook to check if the user should be redirected and set the html `lang` attribute.
56+
57+
```ts
58+
import { shouldRedirect } from "../paraglide/runtime";
59+
60+
export const Route = createRootRoute({
61+
beforeLoad: async () => {
62+
document.documentElement.setAttribute("lang", getLocale());
63+
64+
const decision = await shouldRedirect({ url: window.location.href });
65+
66+
if (decision.redirectUrl) {
67+
throw redirect({ href: decision.redirectUrl.href });
68+
}
69+
},
70+
...
71+
});
72+
```
73+
74+
## Typesafe translated pathnames
75+
76+
If you don't want to miss any translated path, you can create a `createTranslatedPathnames` function and pass it to the vite plugin.
77+
78+
```ts
79+
import { Locale } from "@/paraglide/runtime";
80+
import { FileRoutesByTo } from "../routeTree.gen";
81+
82+
type RoutePath = keyof FileRoutesByTo;
83+
84+
const excludedPaths = ["admin", "docs", "api"] as const;
85+
86+
type PublicRoutePath = Exclude<
87+
RoutePath,
88+
`${string}${(typeof excludedPaths)[number]}${string}`
89+
>;
90+
91+
type TranslatedPathname = {
92+
pattern: string;
93+
localized: Array<[Locale, string]>;
94+
};
95+
96+
function toUrlPattern(path: string) {
97+
return (
98+
path
99+
// catch-all
100+
.replace(/\/\$$/, "/:path(.*)?")
101+
// optional parameters: {-$param}
102+
.replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ":$1?")
103+
// named parameters: $param
104+
.replace(/\$([a-zA-Z0-9_]+)/g, ":$1")
105+
// remove trailing slash
106+
.replace(/\/+$/, "")
107+
);
108+
}
109+
110+
function createTranslatedPathnames(
111+
input: Record<PublicRoutePath, Record<Locale, string>>
112+
): TranslatedPathname[] {
113+
return Object.entries(input).map(([pattern, locales]) => ({
114+
pattern: toUrlPattern(pattern),
115+
localized: Object.entries(locales).map(
116+
([locale, path]) =>
117+
[locale as Locale, `/${locale}${toUrlPattern(path)}`] satisfies [
118+
Locale,
119+
string,
120+
]
121+
),
122+
}));
123+
}
124+
125+
export const translatedPathnames = createTranslatedPathnames({
126+
"/": {
127+
en: "/",
128+
de: "/",
129+
},
130+
"/about": {
131+
en: "/about",
132+
de: "/ueber",
133+
},
134+
});
135+
```
136+
137+
And import into the Paraglide Vite plguin.
138+
139+
## Server side rendering
140+
141+
For server side rerdering, check out the [TanStack Start guide](https://inlang.com/m/gerre34r/library-inlang-paraglideJs/tanstack-start).
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!doctype html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<link rel="icon" href="/favicon.ico" />
7+
<meta name="theme-color" content="#000000" />
8+
<meta
9+
name="description"
10+
content="Web site created using create-tsrouter-app"
11+
/>
12+
<link rel="apple-touch-icon" href="/logo192.png" />
13+
<link rel="manifest" href="/manifest.json" />
14+
<title>Create TanStack App - i18n-paraglide</title>
15+
</head>
16+
<body>
17+
<div id="app"></div>
18+
<script type="module" src="/src/main.tsx"></script>
19+
</body>
20+
</html>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$schema": "https://inlang.com/schema/inlang-message-format",
3+
"example_message": "Guten Tag {username}",
4+
"hello_about": "Hallo /ueber!",
5+
"home_page": "Startseite",
6+
"about_page": "Über uns"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"$schema": "https://inlang.com/schema/inlang-message-format",
3+
"example_message": "Hello world {username}",
4+
"hello_about": "Hello /about!",
5+
"home_page": "Home page",
6+
"about_page": "About page"
7+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "tanstack-router-i18n-paraglide",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite --port 3000",
7+
"start": "vite --port 3000",
8+
"build": "vite build && tsc",
9+
"serve": "vite preview",
10+
"test": "vitest run"
11+
},
12+
"dependencies": {
13+
"@tailwindcss/vite": "^4.1.13",
14+
"@tanstack/react-router": "^1.132.2",
15+
"@tanstack/router-plugin": "^1.132.3",
16+
"react": "^19.1.1",
17+
"react-dom": "^19.1.1",
18+
"tailwindcss": "^4.1.13"
19+
},
20+
"devDependencies": {
21+
"@types/node": "^22.18.6",
22+
"@types/react": "^19.1.13",
23+
"@types/react-dom": "^19.1.9",
24+
"@vitejs/plugin-react": "^5.0.3",
25+
"typescript": "^5.9.2",
26+
"vite": "^7.1.7",
27+
"@inlang/paraglide-js": "^2.4.0"
28+
}
29+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
cache
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
72AJsIR0c0ewzkN33F
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"$schema": "https://inlang.com/schema/project-settings",
3+
"baseLocale": "en",
4+
"locales": [
5+
"en",
6+
"de"
7+
],
8+
"modules": [
9+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
10+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
11+
],
12+
"plugin.inlang.messageFormat": {
13+
"pathPattern": "./messages/{locale}.json"
14+
}
15+
}

0 commit comments

Comments
 (0)