Pfadparameter (Path Params)

Pfadparameter werden verwendet, um ein einzelnes Segment (den Text bis zum nächsten /) abzugleichen und dessen Wert als **benannten** Variablennamen zurückzugeben. Sie werden definiert, indem ein Dollarzeichen $-Präfix im Pfad verwendet wird, gefolgt von dem Schlüsselnamen, dem der Wert zugewiesen werden soll. Die folgenden sind gültige Pfadparameterpfade

  • $postId
  • $name
  • $teamId
  • about/$name
  • team/$teamId
  • blog/$postId

Da Pfadparameterrouten nur bis zum nächsten / abgeglichen werden, können untergeordnete Routen erstellt werden, um die Hierarchie weiter auszudrücken

Erstellen wir eine Post-Routendatei, die einen Pfadparameter verwendet, um die Post-ID abzugleichen

  • posts.$postId.tsx
tsx
import { createFileRoute } from '@tanstack/solid-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    return fetchPost(params.postId)
  },
})
import { createFileRoute } from '@tanstack/solid-router'

export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    return fetchPost(params.postId)
  },
})

Pfadparameter können von untergeordneten Routen verwendet werden

Sobald ein Pfadparameter analysiert wurde, steht er allen untergeordneten Routen zur Verfügung. Das bedeutet, dass, wenn wir eine untergeordnete Route zu unserer postRoute definieren, wir die postId-Variable aus der URL in der Route des Kindes verwenden können!

Pfadparameter in Loadern

Pfadparameter werden als params-Objekt an den Loader übergeben. Die Schlüssel dieses Objekts sind die Namen der Pfadparameter und die Werte sind die Werte, die aus dem tatsächlichen URL-Pfad analysiert wurden. Wenn wir beispielsweise die URL /blog/123 besuchen würden, wäre das params-Objekt { postId: '123' }

tsx
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    return fetchPost(params.postId)
  },
})
export const Route = createFileRoute('/posts/$postId')({
  loader: async ({ params }) => {
    return fetchPost(params.postId)
  },
})

Das params-Objekt wird auch an die beforeLoad-Option übergeben

tsx
export const Route = createFileRoute('/posts/$postId')({
  beforeLoad: async ({ params }) => {
    // do something with params.postId
  },
})
export const Route = createFileRoute('/posts/$postId')({
  beforeLoad: async ({ params }) => {
    // do something with params.postId
  },
})

Pfadparameter in Komponenten

Wenn wir unserer postRoute eine Komponente hinzufügen, können wir die postId-Variable aus der URL abrufen, indem wir den useParams-Hook der Route verwenden

tsx
export const Route = createFileRoute('/posts/$postId')({
  component: PostComponent,
})

function PostComponent() {
  const params = Route.useParams()
  return <div>Post {params.postId()}</div>
}
export const Route = createFileRoute('/posts/$postId')({
  component: PostComponent,
})

function PostComponent() {
  const params = Route.useParams()
  return <div>Post {params.postId()}</div>
}

🧠 Schneller Tipp: Wenn Ihre Komponente code-split ist, können Sie die Funktion getRouteApi verwenden, um zu vermeiden, dass Sie die Route-Konfiguration importieren müssen, um Zugriff auf den typisierten useParams()-Hook zu erhalten.

Pfadparameter außerhalb von Routen

Sie können auch den global exportierten useParams-Hook verwenden, um auf alle analysierten Pfadparameter von jeder Komponente in Ihrer App zuzugreifen. Sie müssen die Option strict: false an useParams übergeben, was darauf hinweist, dass Sie von einem mehrdeutigen Ort auf die Parameter zugreifen möchten

tsx
function PostComponent() {
  const { postId } = useParams({ strict: false })
  return <div>Post {params.postId()}</div>
}
function PostComponent() {
  const { postId } = useParams({ strict: false })
  return <div>Post {params.postId()}</div>
}

Beim Navigieren zu einer Route mit Pfadparametern verlangt TypeScript, dass Sie die Parameter entweder als Objekt oder als Funktion, die ein Objekt von Parametern zurückgibt, übergeben.

Sehen wir uns an, wie ein Objektstil aussieht

tsx
function Component() {
  return (
    <Link to="/blog/$postId" params={{ postId: '123' }}>
      Post 123
    </Link>
  )
}
function Component() {
  return (
    <Link to="/blog/$postId" params={{ postId: '123' }}>
      Post 123
    </Link>
  )
}

Und hier ist, wie ein Funktionsstil aussieht

tsx
function Component() {
  return (
    <Link to="/blog/$postId" params={(prev) => ({ ...prev, postId: '123' })}>
      Post 123
    </Link>
  )
}
function Component() {
  return (
    <Link to="/blog/$postId" params={(prev) => ({ ...prev, postId: '123' })}>
      Post 123
    </Link>
  )
}

Beachten Sie, dass der Funktionsstil nützlich ist, wenn Sie Parameter beibehalten müssen, die sich bereits in der URL für andere Routen befinden. Dies liegt daran, dass der Funktionsstil die aktuellen Parameter als Argument erhält, sodass Sie sie nach Bedarf ändern und das endgültige Parameterobjekt zurückgeben können.

Präfixe und Suffixe für Pfadparameter

Sie können auch **Präfixe** und **Suffixe** mit Pfadparametern verwenden, um komplexere Routingmuster zu erstellen. Dies ermöglicht es Ihnen, bestimmte URL-Strukturen abzugleichen und gleichzeitig die dynamischen Segmente zu erfassen.

Bei Verwendung von Präfixen oder Suffixen können Sie diese definieren, indem Sie den Pfadparameter in geschweifte Klammern {} einschließen und das Präfix oder Suffix vor oder nach dem Variablennamen platzieren.

Definition von Präfixen

Präfixe werden definiert, indem der Präfixtext außerhalb der geschweiften Klammern vor dem Variablennamen platziert wird. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit post- gefolgt von einer Post-ID beginnt, können Sie sie wie folgt definieren

tsx
// src/routes/posts/post-{$postId}.tsx
export const Route = createFileRoute('/posts/post-{$postId}')({
  component: PostComponent,
})

function PostComponent() {
  const params = Route.useParams()
  // postId will be the value after 'post-'
  return <div>Post ID: {params.postId()}</div>
}
// src/routes/posts/post-{$postId}.tsx
export const Route = createFileRoute('/posts/post-{$postId}')({
  component: PostComponent,
})

function PostComponent() {
  const params = Route.useParams()
  // postId will be the value after 'post-'
  return <div>Post ID: {params.postId()}</div>
}

Sie können sogar Präfixe mit Wildcard-Routen kombinieren, um komplexere Muster zu erstellen

tsx
// src/routes/on-disk/storage-{$}
export const Route = createFileRoute('/on-disk/storage-{$postId}/$')({
  component: StorageComponent,
})

function StorageComponent() {
  const params = Route.useParams()
  // _splat, will be value after 'storage-'
  // i.e. my-drive/documents/foo.txt
  return <div>Storage Location: /{params._splat()}</div>
}
// src/routes/on-disk/storage-{$}
export const Route = createFileRoute('/on-disk/storage-{$postId}/$')({
  component: StorageComponent,
})

function StorageComponent() {
  const params = Route.useParams()
  // _splat, will be value after 'storage-'
  // i.e. my-drive/documents/foo.txt
  return <div>Storage Location: /{params._splat()}</div>
}

Definition von Suffixen

Suffixe werden definiert, indem der Suffixtext außerhalb der geschweiften Klammern nach dem Variablennamen platziert wird. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit txt endet, können Sie sie wie folgt definieren

tsx
// src/routes/files/{$fileName}txt
export const Route = createFileRoute('/files/{$fileName}.txt')({
  component: FileComponent,
})

function FileComponent() {
  const params = Route.useParams()
  // fileName will be the value before 'txt'
  return <div>File Name: {params.userId()}</div>
}
// src/routes/files/{$fileName}txt
export const Route = createFileRoute('/files/{$fileName}.txt')({
  component: FileComponent,
})

function FileComponent() {
  const params = Route.useParams()
  // fileName will be the value before 'txt'
  return <div>File Name: {params.userId()}</div>
}

Sie können auch Suffixe mit Wildcards kombinieren, um komplexere Routingmuster zu erstellen

tsx
// src/routes/files/{$}[.]txt
export const Route = createFileRoute('/files/{$fileName}[.]txt')({
  component: FileComponent,
})

function FileComponent() {
  const params = Route.useParams()
  // _splat will be the value before '.txt'
  return <div>File Splat: {params._splat()}</div>
}
// src/routes/files/{$}[.]txt
export const Route = createFileRoute('/files/{$fileName}[.]txt')({
  component: FileComponent,
})

function FileComponent() {
  const params = Route.useParams()
  // _splat will be the value before '.txt'
  return <div>File Splat: {params._splat()}</div>
}

Kombination von Präfixen und Suffixen

Sie können sowohl Präfixe als auch Suffixe kombinieren, um sehr spezifische Routingmuster zu erstellen. Wenn Sie beispielsweise eine URL abgleichen möchten, die mit user- beginnt und mit .json endet, können Sie sie wie folgt definieren

tsx
// src/routes/users/user-{$userId}person
export const Route = createFileRoute('/users/user-{$userId}person')({
  component: UserComponent,
})

function UserComponent() {
  const params = Route.useParams()
  // userId will be the value between 'user-' and 'person'
  return <div>User ID: {params.userId()}</div>
}
// src/routes/users/user-{$userId}person
export const Route = createFileRoute('/users/user-{$userId}person')({
  component: UserComponent,
})

function UserComponent() {
  const params = Route.useParams()
  // userId will be the value between 'user-' and 'person'
  return <div>User ID: {params.userId()}</div>
}

Ähnlich wie in den vorherigen Beispielen können Sie auch Wildcards mit Präfixen und Suffixen verwenden. Seien Sie kreativ!

Optionale Pfadparameter

Optionale Pfadparameter ermöglichen es Ihnen, Routensegmente zu definieren, die in der URL vorhanden sein können oder nicht. Sie verwenden die Syntax {-$paramName} und bieten flexible Routing-Muster, bei denen bestimmte Parameter optional sind.

Definition optionaler Parameter

Optionale Pfadparameter werden mit geschweiften Klammern und einem Bindestrich-Präfix definiert: {-$paramName}

tsx
// Single optional parameter
// src/routes/posts/{-$category}.tsx
export const Route = createFileRoute('/posts/{-$category}')({
  component: PostsComponent,
})

// Multiple optional parameters
// src/routes/posts/{-$category}/{-$slug}.tsx
export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
  component: PostComponent,
})

// Mixed required and optional parameters
// src/routes/users/$id/{-$tab}.tsx
export const Route = createFileRoute('/users/$id/{-$tab}')({
  component: UserComponent,
})
// Single optional parameter
// src/routes/posts/{-$category}.tsx
export const Route = createFileRoute('/posts/{-$category}')({
  component: PostsComponent,
})

// Multiple optional parameters
// src/routes/posts/{-$category}/{-$slug}.tsx
export const Route = createFileRoute('/posts/{-$category}/{-$slug}')({
  component: PostComponent,
})

// Mixed required and optional parameters
// src/routes/users/$id/{-$tab}.tsx
export const Route = createFileRoute('/users/$id/{-$tab}')({
  component: UserComponent,
})

So funktionieren optionale Parameter

Optionale Parameter erstellen flexible URL-Muster

  • /posts/{-$category} gleicht sowohl /posts als auch /posts/tech ab
  • /posts/{-$category}/{-$slug} gleicht /posts, /posts/tech und /posts/tech/hello-world ab
  • /users/$id/{-$tab} gleicht /users/123 und /users/123/settings ab

Wenn ein optionaler Parameter in der URL nicht vorhanden ist, ist sein Wert in Ihren Routen-Handlern und Komponenten undefined.

Zugriff auf optionale Parameter

Optionale Parameter funktionieren in Ihren Komponenten genauso wie reguläre Parameter, aber ihre Werte können undefined sein

tsx
function PostsComponent() {
  const { category } = Route.useParams()

  return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>
}
function PostsComponent() {
  const { category } = Route.useParams()

  return <div>{category ? `Posts in ${category}` : 'All Posts'}</div>
}

Optionale Parameter in Loadern

Optionale Parameter sind in Loadern verfügbar und können undefined sein

tsx
export const Route = createFileRoute('/posts/{-$category}')({
  loader: async ({ params }) => {
    // params.category might be undefined
    return fetchPosts({ category: params.category })
  },
})
export const Route = createFileRoute('/posts/{-$category}')({
  loader: async ({ params }) => {
    // params.category might be undefined
    return fetchPosts({ category: params.category })
  },
})

Optionale Parameter in beforeLoad

Optionale Parameter funktionieren auch in beforeLoad-Handlern

tsx
export const Route = createFileRoute('/posts/{-$category}')({
  beforeLoad: async ({ params }) => {
    if (params.category) {
      // Validate category exists
      await validateCategory(params.category)
    }
  },
})
export const Route = createFileRoute('/posts/{-$category}')({
  beforeLoad: async ({ params }) => {
    if (params.category) {
      // Validate category exists
      await validateCategory(params.category)
    }
  },
})

Fortgeschrittene Muster für optionale Parameter

Mit Präfix und Suffix

Optionale Parameter unterstützen Präfix- und Suffixmuster

tsx
// File route: /files/prefix{-$name}.txt
// Matches: /files/prefix.txt and /files/prefixdocument.txt
export const Route = createFileRoute('/files/prefix{-$name}.txt')({
  component: FileComponent,
})

function FileComponent() {
  const { name } = Route.useParams()
  return <div>File: {name || 'default'}</div>
}
// File route: /files/prefix{-$name}.txt
// Matches: /files/prefix.txt and /files/prefixdocument.txt
export const Route = createFileRoute('/files/prefix{-$name}.txt')({
  component: FileComponent,
})

function FileComponent() {
  const { name } = Route.useParams()
  return <div>File: {name || 'default'}</div>
}

Alle optionalen Parameter

Sie können Routen erstellen, bei denen alle Parameter optional sind

tsx
// Route: /{-$year}/{-$month}/{-$day}
// Matches: /, /2023, /2023/12, /2023/12/25
export const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({
  component: DateComponent,
})

function DateComponent() {
  const { year, month, day } = Route.useParams()

  if (!year) return <div>Select a year</div>
  if (!month) return <div>Year: {year}</div>
  if (!day)
    return (
      <div>
        Month: {year}/{month}
      </div>
    )

  return (
    <div>
      Date: {year}/{month}/{day}
    </div>
  )
}
// Route: /{-$year}/{-$month}/{-$day}
// Matches: /, /2023, /2023/12, /2023/12/25
export const Route = createFileRoute('/{-$year}/{-$month}/{-$day}')({
  component: DateComponent,
})

function DateComponent() {
  const { year, month, day } = Route.useParams()

  if (!year) return <div>Select a year</div>
  if (!month) return <div>Year: {year}</div>
  if (!day)
    return (
      <div>
        Month: {year}/{month}
      </div>
    )

  return (
    <div>
      Date: {year}/{month}/{day}
    </div>
  )
}

Optionale Parameter mit Wildcards

Optionale Parameter können mit Wildcards für komplexe Routingmuster kombiniert werden

tsx
// Route: /docs/{-$version}/$
// Matches: /docs/extra/path, /docs/v2/extra/path
export const Route = createFileRoute('/docs/{-$version}/$')({
  component: DocsComponent,
})

function DocsComponent() {
  const { version } = Route.useParams()
  const params = Route.useParams()

  return (
    <div>
      Version: {version || 'latest'}
      Path: {params._splat()}
    </div>
  )
}
// Route: /docs/{-$version}/$
// Matches: /docs/extra/path, /docs/v2/extra/path
export const Route = createFileRoute('/docs/{-$version}/$')({
  component: DocsComponent,
})

function DocsComponent() {
  const { version } = Route.useParams()
  const params = Route.useParams()

  return (
    <div>
      Version: {version || 'latest'}
      Path: {params._splat()}
    </div>
  )
}

Beim Navigieren zu Routen mit optionalen Parametern haben Sie eine detaillierte Kontrolle darüber, welche Parameter einbezogen werden sollen

tsx
function Navigation() {
  return (
    <div>
      {/* Navigate with optional parameter */}
      <Link to="/posts/{-$category}" params={{ category: 'tech' }}>
        Tech Posts
      </Link>

      {/* Navigate without optional parameter */}
      <Link to="/posts/{-$category}" params={{ category: undefined }}>
        All Posts
      </Link>

      {/* Navigate with multiple optional parameters */}
      <Link
        to="/posts/{-$category}/{-$slug}"
        params={{ category: 'tech', slug: 'react-tips' }}
      >
        Specific Post
      </Link>
    </div>
  )
}
function Navigation() {
  return (
    <div>
      {/* Navigate with optional parameter */}
      <Link to="/posts/{-$category}" params={{ category: 'tech' }}>
        Tech Posts
      </Link>

      {/* Navigate without optional parameter */}
      <Link to="/posts/{-$category}" params={{ category: undefined }}>
        All Posts
      </Link>

      {/* Navigate with multiple optional parameters */}
      <Link
        to="/posts/{-$category}/{-$slug}"
        params={{ category: 'tech', slug: 'react-tips' }}
      >
        Specific Post
      </Link>
    </div>
  )
}

Typsicherheit mit optionalen Parametern

TypeScript bietet volle Typsicherheit für optionale Parameter

tsx
function PostsComponent() {
  // TypeScript knows category might be undefined
  const { category } = Route.useParams() // category: string | undefined

  // Safe navigation
  const categoryUpper = category?.toUpperCase()

  return <div>{categoryUpper || 'All Categories'}</div>
}

// Navigation is type-safe and flexible
<Link
  to="/posts/{-$category}"
  params={{ category: 'tech' }} // ✅ Valid - string
>
  Tech Posts
</Link>

<Link
  to="/posts/{-$category}"
  params={{ category: 123 }} // ✅ Valid - number (auto-stringified)
>
  Category 123
</Link>
function PostsComponent() {
  // TypeScript knows category might be undefined
  const { category } = Route.useParams() // category: string | undefined

  // Safe navigation
  const categoryUpper = category?.toUpperCase()

  return <div>{categoryUpper || 'All Categories'}</div>
}

// Navigation is type-safe and flexible
<Link
  to="/posts/{-$category}"
  params={{ category: 'tech' }} // ✅ Valid - string
>
  Tech Posts
</Link>

<Link
  to="/posts/{-$category}"
  params={{ category: 123 }} // ✅ Valid - number (auto-stringified)
>
  Category 123
</Link>

Internationalisierung (i18n) mit optionalen Pfadparametern

Optionale Pfadparameter sind hervorragend geeignet, um Internationalisierungs- (i18n) Routingmuster zu implementieren. Sie können Präfixmuster verwenden, um mehrere Sprachen zu verwalten und gleichzeitig saubere, SEO-freundliche URLs zu erhalten.

Präfix-basierte i18n

Verwenden Sie optionale Sprachpräfixe, um URLs wie /en/about, /fr/about oder einfach /about (Standardsprache) zu unterstützen

tsx
// Route: /{-$locale}/about
export const Route = createFileRoute('/{-$locale}/about')({
  component: AboutComponent,
})

function AboutComponent() {
  const { locale } = Route.useParams()
  const currentLocale = locale || 'en' // Default to English

  const content = {
    en: { title: 'About Us', description: 'Learn more about our company.' },
    fr: {
      title: 'À Propos',
      description: 'En savoir plus sur notre entreprise.',
    },
    es: {
      title: 'Acerca de',
      description: 'Conoce más sobre nuestra empresa.',
    },
  }

  return (
    <div>
      <h1>{content[currentLocale]?.title}</h1>
      <p>{content[currentLocale]?.description}</p>
    </div>
  )
}
// Route: /{-$locale}/about
export const Route = createFileRoute('/{-$locale}/about')({
  component: AboutComponent,
})

function AboutComponent() {
  const { locale } = Route.useParams()
  const currentLocale = locale || 'en' // Default to English

  const content = {
    en: { title: 'About Us', description: 'Learn more about our company.' },
    fr: {
      title: 'À Propos',
      description: 'En savoir plus sur notre entreprise.',
    },
    es: {
      title: 'Acerca de',
      description: 'Conoce más sobre nuestra empresa.',
    },
  }

  return (
    <div>
      <h1>{content[currentLocale]?.title}</h1>
      <p>{content[currentLocale]?.description}</p>
    </div>
  )
}

Dieses Muster gleicht Folgendes ab

  • /about (Standard-Locale)
  • /en/about (explizites Englisch)
  • /fr/about (Französisch)
  • /es/about (Spanisch)

Komplexe i18n-Muster

Kombinieren Sie optionale Parameter für anspruchsvollere i18n-Routen

tsx
// Route: /{-$locale}/blog/{-$category}/$slug
export const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({
  beforeLoad: async ({ params }) => {
    const locale = params.locale || 'en'
    const category = params.category

    // Validate locale and category
    const validLocales = ['en', 'fr', 'es', 'de']
    if (locale && !validLocales.includes(locale)) {
      throw new Error('Invalid locale')
    }

    return { locale, category }
  },
  loader: async ({ params, context }) => {
    const { locale } = context
    const { slug, category } = params

    return fetchBlogPost({ slug, category, locale })
  },
  component: BlogPostComponent,
})

function BlogPostComponent() {
  const { locale, category, slug } = Route.useParams()
  const data = Route.useLoaderData()

  return (
    <article>
      <h1>{data.title}</h1>
      <p>
        Category: {category || 'All'} | Language: {locale || 'en'}
      </p>
      <div>{data.content}</div>
    </article>
  )
}
// Route: /{-$locale}/blog/{-$category}/$slug
export const Route = createFileRoute('/{-$locale}/blog/{-$category}/$slug')({
  beforeLoad: async ({ params }) => {
    const locale = params.locale || 'en'
    const category = params.category

    // Validate locale and category
    const validLocales = ['en', 'fr', 'es', 'de']
    if (locale && !validLocales.includes(locale)) {
      throw new Error('Invalid locale')
    }

    return { locale, category }
  },
  loader: async ({ params, context }) => {
    const { locale } = context
    const { slug, category } = params

    return fetchBlogPost({ slug, category, locale })
  },
  component: BlogPostComponent,
})

function BlogPostComponent() {
  const { locale, category, slug } = Route.useParams()
  const data = Route.useLoaderData()

  return (
    <article>
      <h1>{data.title}</h1>
      <p>
        Category: {category || 'All'} | Language: {locale || 'en'}
      </p>
      <div>{data.content}</div>
    </article>
  )
}

Dies unterstützt URLs wie

  • /blog/tech/my-post (Standard-Locale, Tech-Kategorie)
  • /fr/blog/my-post (Französisch, keine Kategorie)
  • /en/blog/tech/my-post (explizites Englisch, Tech-Kategorie)
  • /es/blog/tecnologia/mi-post (Spanisch, spanische Kategorie)

Sprachnavigation

Erstellen Sie Sprachumschalter mit optionalen i18n-Parametern und Funktionsparametern

tsx
function LanguageSwitcher() {
  const currentParams = useParams({ strict: false })

  const languages = [
    { code: 'en', name: 'English' },
    { code: 'fr', name: 'Français' },
    { code: 'es', name: 'Español' },
  ]

  return (
    <div className="language-switcher">
      {languages.map(({ code, name }) => (
        <Link
          key={code}
          to="/{-$locale}/blog/{-$category}/$slug"
          params={(prev) => ({
            ...prev,
            locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs
          })}
          className={currentParams.locale === code ? 'active' : ''}
        >
          {name}
        </Link>
      ))}
    </div>
  )
}
function LanguageSwitcher() {
  const currentParams = useParams({ strict: false })

  const languages = [
    { code: 'en', name: 'English' },
    { code: 'fr', name: 'Français' },
    { code: 'es', name: 'Español' },
  ]

  return (
    <div className="language-switcher">
      {languages.map(({ code, name }) => (
        <Link
          key={code}
          to="/{-$locale}/blog/{-$category}/$slug"
          params={(prev) => ({
            ...prev,
            locale: code === 'en' ? undefined : code, // Remove 'en' for clean URLs
          })}
          className={currentParams.locale === code ? 'active' : ''}
        >
          {name}
        </Link>
      ))}
    </div>
  )
}

Sie können auch ausgefeiltere Logik für die Sprachumschaltung erstellen

tsx
function AdvancedLanguageSwitcher() {
  const currentParams = useParams({ strict: false })

  const handleLanguageChange = (newLocale: string) => {
    return (prev: any) => {
      // Preserve all existing params but update locale
      const updatedParams = { ...prev }

      if (newLocale === 'en') {
        // Remove locale for clean English URLs
        delete updatedParams.locale
      } else {
        updatedParams.locale = newLocale
      }

      return updatedParams
    }
  }

  return (
    <div className="language-switcher">
      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('fr')}
      >
        Français
      </Link>

      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('es')}
      >
        Español
      </Link>

      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('en')}
      >
        English
      </Link>
    </div>
  )
}
function AdvancedLanguageSwitcher() {
  const currentParams = useParams({ strict: false })

  const handleLanguageChange = (newLocale: string) => {
    return (prev: any) => {
      // Preserve all existing params but update locale
      const updatedParams = { ...prev }

      if (newLocale === 'en') {
        // Remove locale for clean English URLs
        delete updatedParams.locale
      } else {
        updatedParams.locale = newLocale
      }

      return updatedParams
    }
  }

  return (
    <div className="language-switcher">
      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('fr')}
      >
        Français
      </Link>

      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('es')}
      >
        Español
      </Link>

      <Link
        to="/{-$locale}/blog/{-$category}/$slug"
        params={handleLanguageChange('en')}
      >
        English
      </Link>
    </div>
  )
}

Fortgeschrittene i18n mit optionalen Parametern

Organisieren Sie i18n-Routen mit optionalen Parametern für flexible Locale-Behandlung

tsx
// Route structure:
// routes/
//   {-$locale}/
//     index.tsx        // /, /en, /fr
//     about.tsx        // /about, /en/about, /fr/about
//     blog/
//       index.tsx      // /blog, /en/blog, /fr/blog
//       $slug.tsx      // /blog/post, /en/blog/post, /fr/blog/post

// routes/{-$locale}/index.tsx
export const Route = createFileRoute('/{-$locale}/')({
  component: HomeComponent,
})

function HomeComponent() {
  const { locale } = Route.useParams()
  const isRTL = ['ar', 'he', 'fa'].includes(locale || '')

  return (
    <div dir={isRTL ? 'rtl' : 'ltr'}>
      <h1>Welcome ({locale || 'en'})</h1>
      {/* Localized content */}
    </div>
  )
}

// routes/{-$locale}/about.tsx
export const Route = createFileRoute('/{-$locale}/about')({
  component: AboutComponent,
})
// Route structure:
// routes/
//   {-$locale}/
//     index.tsx        // /, /en, /fr
//     about.tsx        // /about, /en/about, /fr/about
//     blog/
//       index.tsx      // /blog, /en/blog, /fr/blog
//       $slug.tsx      // /blog/post, /en/blog/post, /fr/blog/post

// routes/{-$locale}/index.tsx
export const Route = createFileRoute('/{-$locale}/')({
  component: HomeComponent,
})

function HomeComponent() {
  const { locale } = Route.useParams()
  const isRTL = ['ar', 'he', 'fa'].includes(locale || '')

  return (
    <div dir={isRTL ? 'rtl' : 'ltr'}>
      <h1>Welcome ({locale || 'en'})</h1>
      {/* Localized content */}
    </div>
  )
}

// routes/{-$locale}/about.tsx
export const Route = createFileRoute('/{-$locale}/about')({
  component: AboutComponent,
})

SEO und kanonische URLs

Behandeln Sie SEO für i18n-Routen korrekt

tsx
export const Route = createFileRoute('/{-$locale}/products/$id')({
  component: ProductComponent,
  head: ({ params, loaderData }) => {
    const locale = params.locale || 'en'
    const product = loaderData

    return {
      title: product.title[locale] || product.title.en,
      meta: [
        {
          name: 'description',
          content: product.description[locale] || product.description.en,
        },
        {
          property: 'og:locale',
          content: locale,
        },
      ],
      links: [
        // Canonical URL (always use default locale format)
        {
          rel: 'canonical',
          href: `https://example.com/products/${params.id}`,
        },
        // Alternate language versions
        {
          rel: 'alternate',
          hreflang: 'en',
          href: `https://example.com/products/${params.id}`,
        },
        {
          rel: 'alternate',
          hreflang: 'fr',
          href: `https://example.com/fr/products/${params.id}`,
        },
        {
          rel: 'alternate',
          hreflang: 'es',
          href: `https://example.com/es/products/${params.id}`,
        },
      ],
    }
  },
})
export const Route = createFileRoute('/{-$locale}/products/$id')({
  component: ProductComponent,
  head: ({ params, loaderData }) => {
    const locale = params.locale || 'en'
    const product = loaderData

    return {
      title: product.title[locale] || product.title.en,
      meta: [
        {
          name: 'description',
          content: product.description[locale] || product.description.en,
        },
        {
          property: 'og:locale',
          content: locale,
        },
      ],
      links: [
        // Canonical URL (always use default locale format)
        {
          rel: 'canonical',
          href: `https://example.com/products/${params.id}`,
        },
        // Alternate language versions
        {
          rel: 'alternate',
          hreflang: 'en',
          href: `https://example.com/products/${params.id}`,
        },
        {
          rel: 'alternate',
          hreflang: 'fr',
          href: `https://example.com/fr/products/${params.id}`,
        },
        {
          rel: 'alternate',
          hreflang: 'es',
          href: `https://example.com/es/products/${params.id}`,
        },
      ],
    }
  },
})

Typsicherheit für i18n

Stellen Sie die Typsicherheit für Ihre i18n-Implementierungen sicher

tsx
// Define supported locales
type Locale = 'en' | 'fr' | 'es' | 'de'

// Type-safe locale validation
function validateLocale(locale: string | undefined): locale is Locale {
  return ['en', 'fr', 'es', 'de'].includes(locale as Locale)
}

export const Route = createFileRoute('/{-$locale}/shop/{-$category}')({
  beforeLoad: async ({ params }) => {
    const { locale } = params

    // Type-safe locale validation
    if (locale && !validateLocale(locale)) {
      throw redirect({
        to: '/shop/{-$category}',
        params: { category: params.category },
      })
    }

    return {
      locale: (locale as Locale) || 'en',
      isDefaultLocale: !locale || locale === 'en',
    }
  },
  component: ShopComponent,
})

function ShopComponent() {
  const { locale, category } = Route.useParams()
  const { isDefaultLocale } = Route.useRouteContext()

  // TypeScript knows locale is Locale | undefined
  // and we have validated it in beforeLoad

  return (
    <div>
      <h1>Shop {category ? `- ${category}` : ''}</h1>
      <p>Language: {locale || 'en'}</p>
      {!isDefaultLocale && (
        <Link to="/shop/{-$category}" params={{ category }}>
          View in English
        </Link>
      )}
    </div>
  )
}
// Define supported locales
type Locale = 'en' | 'fr' | 'es' | 'de'

// Type-safe locale validation
function validateLocale(locale: string | undefined): locale is Locale {
  return ['en', 'fr', 'es', 'de'].includes(locale as Locale)
}

export const Route = createFileRoute('/{-$locale}/shop/{-$category}')({
  beforeLoad: async ({ params }) => {
    const { locale } = params

    // Type-safe locale validation
    if (locale && !validateLocale(locale)) {
      throw redirect({
        to: '/shop/{-$category}',
        params: { category: params.category },
      })
    }

    return {
      locale: (locale as Locale) || 'en',
      isDefaultLocale: !locale || locale === 'en',
    }
  },
  component: ShopComponent,
})

function ShopComponent() {
  const { locale, category } = Route.useParams()
  const { isDefaultLocale } = Route.useRouteContext()

  // TypeScript knows locale is Locale | undefined
  // and we have validated it in beforeLoad

  return (
    <div>
      <h1>Shop {category ? `- ${category}` : ''}</h1>
      <p>Language: {locale || 'en'}</p>
      {!isDefaultLocale && (
        <Link to="/shop/{-$category}" params={{ category }}>
          View in English
        </Link>
      )}
    </div>
  )
}

Optionale Pfadparameter bieten eine leistungsstarke und flexible Grundlage für die Implementierung von Internationalisierung in Ihren TanStack Router-Anwendungen. Ob Sie präfixbasierte oder kombinierte Ansätze bevorzugen, Sie können saubere, SEO-freundliche URLs erstellen und gleichzeitig eine ausgezeichnete Entwicklererfahrung und Typsicherheit beibehalten.

Zugelassene Zeichen

Standardmäßig werden Pfadparameter mit encodeURIComponent kodiert. Wenn Sie andere gültige URI-Zeichen (z. B. @ oder +) zulassen möchten, können Sie dies in Ihren RouterOptions angeben.

Beispielanwendung

tsx
const router = createRouter({
  // ...
  pathParamsAllowedCharacters: ['@'],
})
const router = createRouter({
  // ...
  pathParamsAllowedCharacters: ['@'],
})

Die folgende Liste enthält die akzeptierten erlaubten Zeichen

  • ;
  • :
  • @
  • &
  • =
  • +
  • $
  • ,
Unsere Partner
Code Rabbit
Netlify
Neon
Clerk
Convex
Sentry
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.