Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/solid/start-i18n-paraglide/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
count.txt
.env
.nitro
.tanstack
.output
3 changes: 3 additions & 0 deletions examples/solid/start-i18n-paraglide/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": ["inlang.vs-code-extension"]
}
11 changes: 11 additions & 0 deletions examples/solid/start-i18n-paraglide/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"files.watcherExclude": {
"**/routeTree.gen.ts": true
},
"search.exclude": {
"**/routeTree.gen.ts": true
},
"files.readonlyInclude": {
"**/routeTree.gen.ts": true
}
}
196 changes: 196 additions & 0 deletions examples/solid/start-i18n-paraglide/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# TanStack Start example

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).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fix incorrect repository link.

The link points to opral/monorepo but this example is located in the TanStack/router repository. This appears to be a copy-paste error.

Apply this diff to fix the link:

-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).
+This example shows how to use Paraglide with TanStack Start.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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).
This example shows how to use Paraglide with TanStack Start.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

3-3: Link text should be descriptive

(MD059, descriptive-link-text)

🤖 Prompt for AI Agents
In examples/solid/start-i18n-paraglide/README.md around line 3, the repository
link incorrectly points to opral/monorepo; update the URL to reference the
TanStack/router repository example location instead (replace the current GitHub
URL with the correct TanStack/router tree path that contains the
start-i18n-paraglide example).


## Getting started

1. Init Paraglide JS

```bash
npx @inlang/paraglide-js@latest init
```

2. Add the vite plugin to your `vite.config.ts`:

```diff
import { defineConfig } from 'vite'
import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
import react from '@vitejs/plugin-react'
+import { paraglideVitePlugin } from "@inlang/paraglide-js";

export default defineConfig({
plugins: [
tanstackStart(),
react(),
+ paraglideVitePlugin({
+ project: "./project.inlang",
+ outdir: "./app/paraglide",
+ outputStructure: "message-modules",
+ cookieName: "PARAGLIDE_LOCALE",
+ strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
+ urlPatterns: [
+ {
+ pattern: "/:path(.*)?",
+ localized: [
+ ["en", "/en/:path(.*)?"],
+ ],
+ },
+ ],
+ }),
],
});
```
Comment on lines +15 to +42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove incorrect React imports from Solid example.

The code block shows React imports and the @vitejs/plugin-react plugin, but this is a Solid.js example. These lines should be removed as they don't apply to Solid Start.

Apply this diff to fix the configuration example:

 import { defineConfig } from 'vite'
 import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
-import react from '@vitejs/plugin-react'
 +import { paraglideVitePlugin } from "@inlang/paraglide-js";
 
 export default defineConfig({
-	plugins: [
+  plugins: [
     tanstackStart(),
-    react(),
-		paraglideVitePlugin({
-			project: "./project.inlang",
-			outdir: "./app/paraglide",
-     outputStructure: "message-modules",
-     cookieName: "PARAGLIDE_LOCALE",
-     strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
-      urlPatterns: [
-       {
-         pattern: "/:path(.*)?",
-         localized: [
-           ["en", "/en/:path(.*)?"],
-         ],
-       },
-     ],
-		}),
-	],
+    paraglideVitePlugin({
+      project: "./project.inlang",
+      outdir: "./app/paraglide",
+      outputStructure: "message-modules",
+      cookieName: "PARAGLIDE_LOCALE",
+      strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
+      urlPatterns: [
+        {
+          pattern: "/:path(.*)?",
+          localized: [
+            ["en", "/en/:path(.*)?"],
+          ],
+        },
+      ],
+    }),
+  ],
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```diff
import { defineConfig } from 'vite'
import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
import react from '@vitejs/plugin-react'
+import { paraglideVitePlugin } from "@inlang/paraglide-js";
export default defineConfig({
plugins: [
tanstackStart(),
react(),
+ paraglideVitePlugin({
+ project: "./project.inlang",
+ outdir: "./app/paraglide",
+ outputStructure: "message-modules",
+ cookieName: "PARAGLIDE_LOCALE",
+ strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
+ urlPatterns: [
+ {
+ pattern: "/:path(.*)?",
+ localized: [
+ ["en", "/en/:path(.*)?"],
+ ],
+ },
+ ],
+ }),
],
});
```
import { defineConfig } from 'vite'
import { tanstackStart } from "@tanstack/solid-start/plugin/vite";
import { paraglideVitePlugin } from "@inlang/paraglide-js";
export default defineConfig({
plugins: [
tanstackStart(),
paraglideVitePlugin({
project: "./project.inlang",
outdir: "./app/paraglide",
outputStructure: "message-modules",
cookieName: "PARAGLIDE_LOCALE",
strategy: ["url", "cookie", "preferredLanguage", "baseLocale"],
urlPatterns: [
{
pattern: "/:path(.*)?",
localized: [
["en", "/en/:path(.*)?"],
],
},
],
}),
],
});
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

22-22: Hard tabs
Column: 1

(MD010, no-hard-tabs)


25-25: Hard tabs
Column: 2

(MD010, no-hard-tabs)


26-26: Hard tabs
Column: 2

(MD010, no-hard-tabs)


27-27: Hard tabs
Column: 2

(MD010, no-hard-tabs)


39-39: Hard tabs
Column: 2

(MD010, no-hard-tabs)


40-40: Hard tabs
Column: 1

(MD010, no-hard-tabs)

🤖 Prompt for AI Agents
In examples/solid/start-i18n-paraglide/README.md around lines 15 to 42, the Vite
config sample incorrectly imports React and includes '@vitejs/plugin-react'
which does not belong in a Solid.js example; remove the line "import react from
'@vitejs/plugin-react'" and the react() entry in the plugins array, leaving
tanstackStart() and the paraglideVitePlugin({...}) configuration intact, and
ensure indentation and commas in the plugins array remain valid after removal.


3. Done :)

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.

## Rewrite URL

If you want to handle how the URL looks when the user changes the locale, you can rewrite the URL in the router.

```diff
import { createRouter } from "@tanstack/solid-router";
import { routeTree } from "./routeTree.gen";
+import { deLocalizeUrl, localizeUrl } from "./paraglide/runtime.js";

const router = createRouter({
routeTree,
+ rewrite: {
+ input: ({ url }) => deLocalizeUrl(url),
+ output: ({ url }) => localizeUrl(url),
},
});
```

In `server.ts` intercept the request with the paraglideMiddleware.

```ts
import { paraglideMiddleware } from './paraglide/server.js'
import handler from '@tanstack/solid-start/server-entry'

export default {
fetch(req: Request): Promise<Response> {
return paraglideMiddleware(req, ({ request }) => handler.fetch(request))
},
}
```

In `__root.tsx` add change the html lang attribute to the current locale.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix grammatical error.

The sentence contains a grammatical error.

Apply this diff:

-In `__root.tsx` add change the html lang attribute to the current locale.
+In `__root.tsx`, change the html lang attribute to the current locale.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
In `__root.tsx` add change the html lang attribute to the current locale.
In `__root.tsx`, change the html lang attribute to the current locale.
🤖 Prompt for AI Agents
In examples/solid/start-i18n-paraglide/README.md around line 79, the sentence
"In `__root.tsx` add change the html lang attribute to the current locale." has
a grammar mistake; update it to read "In `__root.tsx` change the html lang
attribute to the current locale." so it is clear and grammatically correct.


```tsx
import { getLocale } from '../paraglide/runtime.js'

function RootDocument({ children }: { children: React.ReactNode }) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Use Solid types instead of React types.

The code example uses React.ReactNode but this is a Solid.js example. Use appropriate Solid types.

Apply this diff:

-function RootDocument({ children }: { children: React.ReactNode }) {
+function RootDocument({ children }: { children: JSX.Element }) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function RootDocument({ children }: { children: React.ReactNode }) {
function RootDocument({ children }: { children: JSX.Element }) {
🤖 Prompt for AI Agents
examples/solid/start-i18n-paraglide/README.md around line 84: the example uses
React.ReactNode but this is a Solid.js example; replace React types with Solid
types by typing the component's children using Solid's types (e.g., import
ParentProps or JSX from 'solid-js' and use ParentProps['children'] or
JSX.Element) and update the import accordingly so the RootDocument parameter
uses a Solid-appropriate children type instead of React.ReactNode.

return (
<html lang={getLocale()}>
<head>
<HeadContent />
</head>
<body>
{children}
<Scripts />
</body>
</html>
)
}
```

## Offline redirect

If you have an application that needs to work offline, you will need to handle the redirect in the client like this.

```ts
import { shouldRedirect } from "../paraglide/runtime";

export const Route = createRootRoute({
beforeLoad: async () => {
const decision = await shouldRedirect({ url: window.location.href });

if (decision.redirectUrl) {
throw redirect({ href: decision.redirectUrl.href });
}
},
...
});
```

## Typesafe translated pathnames

If you don't want to miss any translated path, you can create a `createTranslatedPathnames` function and pass it to the vite plugin.

```ts
import { Locale } from '@/paraglide/runtime'
import { FileRoutesByTo } from '../routeTree.gen'

type RoutePath = keyof FileRoutesByTo

const excludedPaths = ['admin', 'docs', 'api'] as const

type PublicRoutePath = Exclude<
RoutePath,
`${string}${(typeof excludedPaths)[number]}${string}`
>

type TranslatedPathname = {
pattern: string
localized: Array<[Locale, string]>
}

function toUrlPattern(path: string) {
return (
path
// catch-all
.replace(/\/\$$/, '/:path(.*)?')
// optional parameters: {-$param}
.replace(/\{-\$([a-zA-Z0-9_]+)\}/g, ':$1?')
// named parameters: $param
.replace(/\$([a-zA-Z0-9_]+)/g, ':$1')
// remove trailing slash
.replace(/\/+$/, '')
)
}

function createTranslatedPathnames(
input: Record<PublicRoutePath, Record<Locale, string>>,
): TranslatedPathname[] {
return Object.entries(input).map(([pattern, locales]) => ({
pattern: toUrlPattern(pattern),
localized: Object.entries(locales).map(
([locale, path]) =>
[locale as Locale, `/${locale}${toUrlPattern(path)}`] satisfies [
Locale,
string,
],
),
}))
}

export const translatedPathnames = createTranslatedPathnames({
'/': {
en: '/',
de: '/',
},
'/about': {
en: '/about',
de: '/ueber',
},
})
```

And import into the Paraglide Vite plguin.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix incomplete sentence and typo.

The sentence is incomplete and contains a typo ("plguin" should be "plugin").

Apply this diff to complete the documentation:

-And import into the Paraglide Vite plguin.
+Then import `translatedPathnames` into the `urlPatterns` option of the Paraglide Vite plugin.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
And import into the Paraglide Vite plguin.
Then import `translatedPathnames` into the `urlPatterns` option of the Paraglide Vite plugin.
🤖 Prompt for AI Agents
In examples/solid/start-i18n-paraglide/README.md around line 181, the sentence
"And import into the Paraglide Vite plguin." is incomplete and contains a typo;
fix it by changing the line to a complete, grammatically correct sentence and
correct "plguin" to "plugin" (for example: "And import it into the Paraglide
Vite plugin.").


# Prerender routes

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.

```ts
import { localizeHref } from './paraglide/runtime'

export const prerenderRoutes = ['/', '/about'].map((path) => ({
path: localizeHref(path),
prerender: {
enabled: true,
},
}))
```
8 changes: 8 additions & 0 deletions examples/solid/start-i18n-paraglide/messages/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"example_message": "Guten Tag {username}",
"server_message": "Server Nachricht {emoji}",
"about_message": "Über uns",
"home_page": "Startseite",
"about_page": "Über uns"
}
8 changes: 8 additions & 0 deletions examples/solid/start-i18n-paraglide/messages/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"$schema": "https://inlang.com/schema/inlang-message-format",
"example_message": "Hello world {username}",
"server_message": "Server message {emoji}",
"about_message": "About message",
"home_page": "Home page",
"about_page": "About page"
}
28 changes: 28 additions & 0 deletions examples/solid/start-i18n-paraglide/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "tanstack-solid-start-i18n-paraglide",
"private": true,
"type": "module",
"scripts": {
"dev": "vite dev --port 3000",
"start": "node .output/server/index.mjs",
"build": "vite build",
"serve": "vite preview"
},
"dependencies": {
"@tanstack/solid-devtools": "^0.7.0",
"@tanstack/solid-router": "^1.135.2",
"@tanstack/solid-router-devtools": "^1.135.2",
"@tanstack/solid-start": "^1.135.2",
"solid-js": "^1.9.10"
},
Comment on lines +11 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use workspace:* protocol for internal TanStack dependencies.

The TanStack packages should use the workspace:* protocol instead of version ranges to ensure this example always uses the latest local versions from the monorepo during development.

As per coding guidelines

Apply this diff to fix the dependency declarations:

   "dependencies": {
-    "@tanstack/solid-devtools": "^0.7.0",
-    "@tanstack/solid-router": "^1.135.2",
-    "@tanstack/solid-router-devtools": "^1.135.2",
-    "@tanstack/solid-start": "^1.135.2",
+    "@tanstack/solid-devtools": "workspace:*",
+    "@tanstack/solid-router": "workspace:*",
+    "@tanstack/solid-router-devtools": "workspace:*",
+    "@tanstack/solid-start": "workspace:*",
     "solid-js": "^1.9.10"
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"dependencies": {
"@tanstack/solid-devtools": "^0.7.0",
"@tanstack/solid-router": "^1.135.2",
"@tanstack/solid-router-devtools": "^1.135.2",
"@tanstack/solid-start": "^1.135.2",
"solid-js": "^1.9.10"
},
"dependencies": {
"@tanstack/solid-devtools": "workspace:*",
"@tanstack/solid-router": "workspace:*",
"@tanstack/solid-router-devtools": "workspace:*",
"@tanstack/solid-start": "workspace:*",
"solid-js": "^1.9.10"
},
🤖 Prompt for AI Agents
In examples/solid/start-i18n-paraglide/package.json around lines 11 to 17, the
TanStack scoped dependencies use fixed version ranges; change each @tanstack/*
entry to use the workspace:* protocol (e.g., "@tanstack/solid-devtools":
"workspace:*", "@tanstack/solid-router": "workspace:*",
"@tanstack/solid-router-devtools": "workspace:*", "@tanstack/solid-start":
"workspace:*") so the example uses local monorepo packages during development,
then save the file and run your package manager install (e.g., pnpm install or
npm install) to update lockfiles.

"devDependencies": {
"@types/node": "^22.18.6",
"vite-plugin-solid": "^2.11.10",
"typescript": "^5.9.2",
"vite": "^7.1.7",
"vite-tsconfig-paths": "^5.1.4",
"@tailwindcss/vite": "^4.1.13",
"tailwindcss": "^4.1.13",
"@inlang/paraglide-js": "2.4.0"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cache
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UoZ15Q8qSGIbImRS3Y
12 changes: 12 additions & 0 deletions examples/solid/start-i18n-paraglide/project.inlang/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://inlang.com/schema/project-settings",
"baseLocale": "en",
"locales": ["en", "de"],
"modules": [
"https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@4/dist/index.js",
"https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@2/dist/index.js"
],
"plugin.inlang.messageFormat": {
"pathPattern": "./messages/{locale}.json"
}
}
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions examples/solid/start-i18n-paraglide/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"short_name": "TanStack App",
"name": "Create TanStack App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
3 changes: 3 additions & 0 deletions examples/solid/start-i18n-paraglide/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
12 changes: 12 additions & 0 deletions examples/solid/start-i18n-paraglide/src/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading