@tanstack/react-router 1.145.7 → 1.146.0

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.
@@ -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.7",
3
+ "version": "1.146.0",
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.7"
83
+ "@tanstack/router-core": "1.146.0"
84
84
  },
85
85
  "devDependencies": {
86
86
  "@testing-library/jest-dom": "^6.6.3",