@tanstack/react-router 1.145.7 → 1.145.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/llms/rules/guide.js
CHANGED
|
@@ -2495,6 +2495,253 @@ const router = createRouter({ routeTree, history: memoryHistory })
|
|
|
2495
2495
|
|
|
2496
2496
|
Refer to the [SSR Guide](./ssr.md#server-history) for usage on the server for server-side rendering.
|
|
2497
2497
|
|
|
2498
|
+
# Internationalization (i18n)
|
|
2499
|
+
|
|
2500
|
+
TanStack Router provides flexible and highly customizable primitives that can be composed to support common internationalization (i18n) routing patterns, such as **optional path parameters**, **route rewriting**, and **type-safe params**. This enables clean, SEO-friendly URLs, flexible locale handling, and seamless integration with i18n libraries.
|
|
2501
|
+
|
|
2502
|
+
This guide covers:
|
|
2503
|
+
|
|
2504
|
+
- Prefix-based and optional-locale routing
|
|
2505
|
+
- Advanced routing patterns for i18n
|
|
2506
|
+
- Language navigation and switching
|
|
2507
|
+
- SEO considerations
|
|
2508
|
+
- Type safety
|
|
2509
|
+
- Integration patterns with i18n libraries (Paraglide)
|
|
2510
|
+
|
|
2511
|
+
---
|
|
2512
|
+
|
|
2513
|
+
## i18n with Optional Path Parameters
|
|
2514
|
+
|
|
2515
|
+
This pattern relies exclusively on TanStack Router features. It is suitable when:
|
|
2516
|
+
|
|
2517
|
+
- You want full control over translations
|
|
2518
|
+
- You already manage translations manually
|
|
2519
|
+
- You do not need automatic locale detection
|
|
2520
|
+
|
|
2521
|
+
Optional path parameters are ideal for implementing locale-aware routing without duplicating routes.
|
|
2522
|
+
|
|
2523
|
+
\`\`\`ts
|
|
2524
|
+
;/{-$locale}/abotu
|
|
2525
|
+
\`\`\`
|
|
2526
|
+
|
|
2527
|
+
This single route matches:
|
|
2528
|
+
|
|
2529
|
+
- \`/about\` (default locale)
|
|
2530
|
+
- \`/en/about\`
|
|
2531
|
+
- \`/fr/about\`
|
|
2532
|
+
- \`/es/about\`
|
|
2533
|
+
|
|
2534
|
+
### Prefix-based i18n
|
|
2535
|
+
|
|
2536
|
+
\`\`\`tsx
|
|
2537
|
+
// Route: /{-$locale}/about
|
|
2538
|
+
export const Route = createFileRoute('/{-$locale}/about')({
|
|
2539
|
+
component: AboutComponent,
|
|
2540
|
+
})
|
|
2541
|
+
|
|
2542
|
+
function AboutComponent() {
|
|
2543
|
+
const { locale } = Route.useParams()
|
|
2544
|
+
const currentLocale = locale || 'en'
|
|
2545
|
+
|
|
2546
|
+
const content = {
|
|
2547
|
+
en: { title: 'About Us' },
|
|
2548
|
+
fr: { title: 'À Propos' },
|
|
2549
|
+
es: { title: 'Acerca de' },
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
return <h1>{content[currentLocale].title}</h1>
|
|
2553
|
+
}
|
|
2554
|
+
\`\`\`
|
|
2555
|
+
|
|
2556
|
+
### Complex Routing Patterns
|
|
2557
|
+
|
|
2558
|
+
\`\`\`tsx
|
|
2559
|
+
// Route: /{-$locale}/blog/{-$category}/$slug
|
|
2560
|
+
export const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({
|
|
2561
|
+
beforeLoad: ({ params }) => {
|
|
2562
|
+
const locale = params.locale || 'en'
|
|
2563
|
+
const validLocales = ['en', 'fr', 'es', 'de']
|
|
2564
|
+
|
|
2565
|
+
if (params.locale && !validLocales.includes(params.locale)) {
|
|
2566
|
+
throw new Error('Invalid locale')
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
return { locale }
|
|
2570
|
+
},
|
|
2571
|
+
})
|
|
2572
|
+
\`\`\`
|
|
2573
|
+
|
|
2574
|
+
### Language Switching
|
|
2575
|
+
|
|
2576
|
+
\`\`\`tsx
|
|
2577
|
+
<Link
|
|
2578
|
+
to="/{-$locale}/blog/{-$category}/$slug"
|
|
2579
|
+
params={(prev) => ({
|
|
2580
|
+
...prev,
|
|
2581
|
+
locale: prev.locale === 'en' ? undefined : 'fr',
|
|
2582
|
+
})}
|
|
2583
|
+
>
|
|
2584
|
+
Français
|
|
2585
|
+
</Link>
|
|
2586
|
+
\`\`\`
|
|
2587
|
+
|
|
2588
|
+
### Type-safe Locales
|
|
2589
|
+
|
|
2590
|
+
\`\`\`ts
|
|
2591
|
+
type Locale = 'en' | 'fr' | 'es' | 'de'
|
|
2592
|
+
|
|
2593
|
+
function isLocale(value?: string): value is Locale {
|
|
2594
|
+
return ['en', 'fr', 'es', 'de'].includes(value as Locale)
|
|
2595
|
+
}
|
|
2596
|
+
\`\`\`
|
|
2597
|
+
|
|
2598
|
+
---
|
|
2599
|
+
|
|
2600
|
+
## i18n Library Integration Patterns
|
|
2601
|
+
|
|
2602
|
+
TanStack Router is **library-agnostic**. You can integrate any i18n solution by mapping locale state to routing behavior.
|
|
2603
|
+
|
|
2604
|
+
Below is a recommended pattern using **Paraglide**.
|
|
2605
|
+
|
|
2606
|
+
---
|
|
2607
|
+
|
|
2608
|
+
## Client-side i18n with a Library (TanStack Router)
|
|
2609
|
+
|
|
2610
|
+
This pattern combines TanStack Router with a client-side i18n library. It is suitable when:
|
|
2611
|
+
|
|
2612
|
+
- You want type-safe translations
|
|
2613
|
+
- You want localized URLs
|
|
2614
|
+
- You do not need server-side rendering
|
|
2615
|
+
|
|
2616
|
+
### TanStack Router + Paraglide (Client-only)
|
|
2617
|
+
|
|
2618
|
+
Paraglide provides type-safe translations, locale detection, and URL localization that pair naturally with TanStack Router.
|
|
2619
|
+
|
|
2620
|
+
**GitHub example:**
|
|
2621
|
+
[https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide](https://github.com/TanStack/router/tree/main/examples/react/i18n-paraglide)
|
|
2622
|
+
|
|
2623
|
+
### Project Setup
|
|
2624
|
+
|
|
2625
|
+
\`\`\`bash
|
|
2626
|
+
npx @inlang/paraglide-js@latest init
|
|
2627
|
+
\`\`\`
|
|
2628
|
+
|
|
2629
|
+
\`\`\`ts
|
|
2630
|
+
import { paraglideVitePlugin } from '@inlang/paraglide-js'
|
|
2631
|
+
|
|
2632
|
+
paraglideVitePlugin({
|
|
2633
|
+
project: './project.inlang',
|
|
2634
|
+
outdir: './app/paraglide',
|
|
2635
|
+
})
|
|
2636
|
+
\`\`\`
|
|
2637
|
+
|
|
2638
|
+
### URL Localization via Router Rewrite
|
|
2639
|
+
|
|
2640
|
+
\`\`\`ts
|
|
2641
|
+
import { deLocalizeUrl, localizeUrl } from './paraglide/runtime'
|
|
2642
|
+
|
|
2643
|
+
const router = createRouter({
|
|
2644
|
+
routeTree,
|
|
2645
|
+
rewrite: {
|
|
2646
|
+
input: ({ url }) => deLocalizeUrl(url),
|
|
2647
|
+
output: ({ url }) => localizeUrl(url),
|
|
2648
|
+
},
|
|
2649
|
+
})
|
|
2650
|
+
\`\`\`
|
|
2651
|
+
|
|
2652
|
+
---
|
|
2653
|
+
|
|
2654
|
+
## Server-side i18n (TanStack Start)
|
|
2655
|
+
|
|
2656
|
+
This pattern integrates i18n at the routing and server layers. It is suitable when:
|
|
2657
|
+
|
|
2658
|
+
- You use TanStack Start
|
|
2659
|
+
- You need SSR or streaming
|
|
2660
|
+
- You want locale-aware redirects and metadata
|
|
2661
|
+
|
|
2662
|
+
### TanStack Start + Paraglide
|
|
2663
|
+
|
|
2664
|
+
**GitHub example:**
|
|
2665
|
+
[https://github.com/TanStack/router/tree/main/examples/react/start-i18n-paraglide](https://github.com/TanStack/router/tree/main/examples/react/start-i18n-paraglide)
|
|
2666
|
+
|
|
2667
|
+
### Server Middleware (SSR)
|
|
2668
|
+
|
|
2669
|
+
\`\`\`ts
|
|
2670
|
+
import { paraglideMiddleware } from './paraglide/server'
|
|
2671
|
+
|
|
2672
|
+
export default {
|
|
2673
|
+
fetch(req: Request) {
|
|
2674
|
+
return paraglideMiddleware(req, () => handler.fetch(req))
|
|
2675
|
+
},
|
|
2676
|
+
}
|
|
2677
|
+
\`\`\`
|
|
2678
|
+
|
|
2679
|
+
### HTML Language Attribute
|
|
2680
|
+
|
|
2681
|
+
\`\`\`tsx
|
|
2682
|
+
import { getLocale } from '../paraglide/runtime'
|
|
2683
|
+
;<html lang={getLocale()} />
|
|
2684
|
+
\`\`\`
|
|
2685
|
+
|
|
2686
|
+
---
|
|
2687
|
+
|
|
2688
|
+
## Offline-safe Redirects
|
|
2689
|
+
|
|
2690
|
+
For offline or client-only environments:
|
|
2691
|
+
|
|
2692
|
+
\`\`\`ts
|
|
2693
|
+
import { shouldRedirect } from '../paraglide/runtime'
|
|
2694
|
+
|
|
2695
|
+
beforeLoad: async () => {
|
|
2696
|
+
const decision = await shouldRedirect({ url: window.location.href })
|
|
2697
|
+
if (decision.redirectUrl) {
|
|
2698
|
+
throw redirect({ href: decision.redirectUrl.href })
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
\`\`\`
|
|
2702
|
+
|
|
2703
|
+
---
|
|
2704
|
+
|
|
2705
|
+
## Type-safe Translated Pathnames
|
|
2706
|
+
|
|
2707
|
+
To ensure every route has translations, you can derive translated pathnames directly from the TanStack Router route tree.
|
|
2708
|
+
|
|
2709
|
+
\`\`\`ts
|
|
2710
|
+
import { FileRoutesByTo } from '../routeTree.gen'
|
|
2711
|
+
import { Locale } from '@/paraglide/runtime'
|
|
2712
|
+
\`\`\`
|
|
2713
|
+
|
|
2714
|
+
This guarantees:
|
|
2715
|
+
|
|
2716
|
+
- No missing translations
|
|
2717
|
+
- Full type safety
|
|
2718
|
+
- Compiler feedback for routing mistakes
|
|
2719
|
+
|
|
2720
|
+
---
|
|
2721
|
+
|
|
2722
|
+
## Prerendering Localized Routes
|
|
2723
|
+
|
|
2724
|
+
\`\`\`ts
|
|
2725
|
+
import { localizeHref } from './paraglide/runtime'
|
|
2726
|
+
|
|
2727
|
+
export const prerenderRoutes = ['/', '/about'].map((path) => ({
|
|
2728
|
+
path: localizeHref(path),
|
|
2729
|
+
prerender: { enabled: true },
|
|
2730
|
+
}))
|
|
2731
|
+
\`\`\`
|
|
2732
|
+
|
|
2733
|
+
---
|
|
2734
|
+
|
|
2735
|
+
## Additional i18n Integration Patterns
|
|
2736
|
+
|
|
2737
|
+
### Intlayer (TanStack Start integration)
|
|
2738
|
+
|
|
2739
|
+
[https://intlayer.org/doc/environment/tanstack-start](https://intlayer.org/doc/environment/tanstack-start)
|
|
2740
|
+
|
|
2741
|
+
### use-intl (TanStack Start integration)
|
|
2742
|
+
|
|
2743
|
+
[https://nikuscs.com/blog/13-tanstackstart-i18n/](https://nikuscs.com/blog/13-tanstackstart-i18n/)
|
|
2744
|
+
|
|
2498
2745
|
# Link Options
|
|
2499
2746
|
|
|
2500
2747
|
You may want to reuse options that are intended to be passed to \`Link\`, \`redirect\` or \`navigate\`. In which case you may decide an object literal is a good way to represent options passed to \`Link\`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
|
-
"version": "1.145.
|
|
3
|
+
"version": "1.145.11",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"tiny-invariant": "^1.3.3",
|
|
81
81
|
"tiny-warning": "^1.0.3",
|
|
82
82
|
"@tanstack/history": "1.145.7",
|
|
83
|
-
"@tanstack/router-core": "1.145.
|
|
83
|
+
"@tanstack/router-core": "1.145.11"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
86
|
"@testing-library/jest-dom": "^6.6.3",
|