Skip to content

Commit b5d7227

Browse files
authored
docs(solid-start): i18n example (#5845)
docs(solid-start) i18n example
1 parent 7492e6c commit b5d7227

29 files changed

+786
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
count.txt
7+
.env
8+
.nitro
9+
.tanstack
10+
.output
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"recommendations": ["inlang.vs-code-extension"]
3+
}
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: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# TanStack Start example
2+
3+
This example shows how to use Paraglide with TanStack Start. The source code can be found [here](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/examples/tanstack-start).
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 { tanstackStart } from "@tanstack/solid-start/plugin/vite";
18+
import react from '@vitejs/plugin-react'
19+
+import { paraglideVitePlugin } from "@inlang/paraglide-js";
20+
21+
export default defineConfig({
22+
plugins: [
23+
tanstackStart(),
24+
react(),
25+
+ paraglideVitePlugin({
26+
+ project: "./project.inlang",
27+
+ outdir: "./app/paraglide",
28+
+ outputStructure: "message-modules",
29+
+ cookieName: "PARAGLIDE_LOCALE",
30+
+ strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
31+
+ urlPatterns: [
32+
+ {
33+
+ pattern: "/:path(.*)?",
34+
+ localized: [
35+
+ ["en", "/en/:path(.*)?"],
36+
+ ],
37+
+ },
38+
+ ],
39+
+ }),
40+
],
41+
});
42+
```
43+
44+
3. Done :)
45+
46+
Run the app and start translating. See the [basics documentation](https://inlang.com/m/gerre34r/library-inlang-paraglideJs/basics) for information on how to use Paraglide's messages, parameters, and locale management.
47+
48+
## Rewrite URL
49+
50+
If you want to handle how the URL looks when the user changes the locale, you can rewrite the URL in the router.
51+
52+
```diff
53+
import { createRouter } from "@tanstack/solid-router";
54+
import { routeTree } from "./routeTree.gen";
55+
+import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime.js";
56+
57+
const router = createRouter({
58+
routeTree,
59+
+ rewrite: {
60+
+ input: ({ url }) => deLocalizeUrl(url),
61+
+ output: ({ url }) => localizeUrl(url),
62+
},
63+
});
64+
```
65+
66+
In `server.ts` intercept the request with the paraglideMiddleware.
67+
68+
```ts
69+
import { paraglideMiddleware } from './paraglide/server.js'
70+
import handler from '@tanstack/solid-start/server-entry'
71+
72+
export default {
73+
fetch(req: Request): Promise<Response> {
74+
return paraglideMiddleware(req, ({ request }) => handler.fetch(request))
75+
},
76+
}
77+
```
78+
79+
In `__root.tsx` add change the html lang attribute to the current locale.
80+
81+
```tsx
82+
import { getLocale } from '../paraglide/runtime.js'
83+
84+
function RootDocument({ children }: { children: React.ReactNode }) {
85+
return (
86+
<html lang={getLocale()}>
87+
<head>
88+
<HeadContent />
89+
</head>
90+
<body>
91+
{children}
92+
<Scripts />
93+
</body>
94+
</html>
95+
)
96+
}
97+
```
98+
99+
## Offline redirect
100+
101+
If you have an application that needs to work offline, you will need to handle the redirect in the client like this.
102+
103+
```ts
104+
import { shouldRedirect } from "../paraglide/runtime";
105+
106+
export const Route = createRootRoute({
107+
beforeLoad: async () => {
108+
const decision = await shouldRedirect({ url: window.location.href });
109+
110+
if (decision.redirectUrl) {
111+
throw redirect({ href: decision.redirectUrl.href });
112+
}
113+
},
114+
...
115+
});
116+
```
117+
118+
## Typesafe translated pathnames
119+
120+
If you don't want to miss any translated path, you can create a `createTranslatedPathnames` function and pass it to the vite plugin.
121+
122+
```ts
123+
import { Locale } from '@/paraglide/runtime'
124+
import { FileRoutesByTo } from '../routeTree.gen'
125+
126+
type RoutePath = keyof FileRoutesByTo
127+
128+
const excludedPaths = ['admin', 'docs', 'api'] as const
129+
130+
type PublicRoutePath = Exclude<
131+
RoutePath,
132+
`${string}${(typeof excludedPaths)[number]}${string}`
133+
>
134+
135+
type TranslatedPathname = {
136+
pattern: string
137+
localized: Array<[Locale, string]>
138+
}
139+
140+
function toUrlPattern(path: string) {
141+
return (
142+
path
143+
// catch-all
144+
.replace(/\/\$$/, '/:path(.*)?')
145+
// optional parameters: {-$param}
146+
.replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?')
147+
// named parameters: $param
148+
.replace(/\$([a-zA-Z0-9_]+)/g, ':$1')
149+
// remove trailing slash
150+
.replace(/\/+$/, '')
151+
)
152+
}
153+
154+
function createTranslatedPathnames(
155+
input: Record<PublicRoutePath, Record<Locale, string>>,
156+
): TranslatedPathname[] {
157+
return Object.entries(input).map(([pattern, locales]) => ({
158+
pattern: toUrlPattern(pattern),
159+
localized: Object.entries(locales).map(
160+
([locale, path]) =>
161+
[locale as Locale, `/${locale}${toUrlPattern(path)}`] satisfies [
162+
Locale,
163+
string,
164+
],
165+
),
166+
}))
167+
}
168+
169+
export const translatedPathnames = createTranslatedPathnames({
170+
'/': {
171+
en: '/',
172+
de: '/',
173+
},
174+
'/about': {
175+
en: '/about',
176+
de: '/ueber',
177+
},
178+
})
179+
```
180+
181+
And import into the Paraglide Vite plguin.
182+
183+
# Prerender routes
184+
185+
You can use use the `localizeHref` function to map the routes to localized versions and import into the pages option in the TanStack Start plugin. For this to work you will need to compile paraglide before the build with the CLI.
186+
187+
```ts
188+
import { localizeHref } from './paraglide/runtime'
189+
190+
export const prerenderRoutes = ['/', '/about'].map((path) => ({
191+
path: localizeHref(path),
192+
prerender: {
193+
enabled: true,
194+
},
195+
}))
196+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://inlang.com/schema/inlang-message-format",
3+
"example_message": "Guten Tag {username}",
4+
"server_message": "Server Nachricht {emoji}",
5+
"about_message": "Über uns",
6+
"home_page": "Startseite",
7+
"about_page": "Über uns"
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"$schema": "https://inlang.com/schema/inlang-message-format",
3+
"example_message": "Hello world {username}",
4+
"server_message": "Server message {emoji}",
5+
"about_message": "About message",
6+
"home_page": "Home page",
7+
"about_page": "About page"
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "tanstack-solid-start-i18n-paraglide",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite dev --port 3000",
7+
"start": "node .output/server/index.mjs",
8+
"build": "vite build",
9+
"serve": "vite preview"
10+
},
11+
"dependencies": {
12+
"@tanstack/solid-devtools": "^0.7.0",
13+
"@tanstack/solid-router": "^1.135.2",
14+
"@tanstack/solid-router-devtools": "^1.135.2",
15+
"@tanstack/solid-start": "^1.135.2",
16+
"solid-js": "^1.9.10"
17+
},
18+
"devDependencies": {
19+
"@types/node": "^22.18.6",
20+
"vite-plugin-solid": "^2.11.10",
21+
"typescript": "^5.9.2",
22+
"vite": "^7.1.7",
23+
"vite-tsconfig-paths": "^5.1.4",
24+
"@tailwindcss/vite": "^4.1.13",
25+
"tailwindcss": "^4.1.13",
26+
"@inlang/paraglide-js": "2.4.0"
27+
}
28+
}
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+
UoZ15Q8qSGIbImRS3Y
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"$schema": "https://inlang.com/schema/project-settings",
3+
"baseLocale": "en",
4+
"locales": ["en", "de"],
5+
"modules": [
6+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
7+
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
8+
],
9+
"plugin.inlang.messageFormat": {
10+
"pathPattern": "./messages/{locale}.json"
11+
}
12+
}

0 commit comments

Comments
 (0)