Как создать компонент переключателя языка в TanStack Start v1

Переключайте языки, оставаясь на той же странице

Проблема

Когда пользователи переключают язык в многоязычном приложении, они ожидают остаться на той же странице и видеть тот же контент на новом языке. Плохо реализованный переключатель языка воспринимает выбор языка как переход на другую страницу, часто перенаправляя пользователей на главную страницу и полностью теряя их место. Это нарушает пользовательский поток и вызывает разочарование, особенно когда пользователи находятся в процессе выполнения задачи или просматривают конкретный контент. Задача заключается в создании переключателя, который изменяет только языковой сегмент URL, сохраняя остальную часть пути, параметры поиска и хэш.

Решение

Создайте компонент переключателя языка, который считывает текущий путь URL и создает ссылки для каждого доступного языка, заменяя языковой сегмент в пути. Извлеките текущий язык из структуры URL, затем создайте новые пути для других поддерживаемых языков, заменяя языковую часть, сохраняя при этом все остальные сегменты URL. Используйте эти пути для рендеринга ссылок, которые позволяют пользователям переключать язык, не теряя контекст текущей страницы.

Шаги

1. Определите поддерживаемые языки

Создайте файл конфигурации, который перечисляет все языки, поддерживаемые вашим приложением, и указывает язык по умолчанию.

export const locales = ["en", "fr", "es", "de"] as const;

export type Locale = (typeof locales)[number];

export const defaultLocale: Locale = "en";

Эта конфигурация служит единственным источником правды для доступных языков и будет использоваться для генерации ссылок переключателя.

2. Создайте вспомогательную функцию для извлечения текущего языка из пути

Напишите утилитарную функцию, которая анализирует путь и извлекает сегмент локали, если он присутствует.

import { defaultLocale, locales, type Locale } from "./locales";

export function getLocaleFromPathname(pathname: string): Locale {
  const segments = pathname.split("/").filter(Boolean);
  const firstSegment = segments[0];

  if (firstSegment && locales.includes(firstSegment as Locale)) {
    return firstSegment as Locale;
  }

  return defaultLocale;
}

Эта функция проверяет первый сегмент пути и возвращает его, если он соответствует поддерживаемой локали, в противном случае возвращается локаль по умолчанию.

3. Создайте помощник для построения локализованных путей

Напишите функцию, которая принимает текущий путь и целевую локаль, а затем создает новый путь с замененным сегментом локали.

import { defaultLocale, locales, type Locale } from "./locales";

export function getLocalizedPath(
  pathname: string,
  targetLocale: Locale,
): string {
  const segments = pathname.split("/").filter(Boolean);
  const firstSegment = segments[0];

  const hasLocalePrefix =
    firstSegment && locales.includes(firstSegment as Locale);

  if (hasLocalePrefix) {
    segments[0] = targetLocale;
  } else {
    segments.unshift(targetLocale);
  }

  return "/" + segments.join("/");
}

Эта функция либо заменяет существующий сегмент локали, либо добавляет целевую локаль в начало пути, гарантируя, что новый URL указывает на ту же страницу на другом языке.

4. Создайте компонент переключателя языка

Создайте компонент, который использует текущее местоположение для генерации ссылок для всех поддерживаемых языков.

import { Link } from "@tanstack/react-router";
import { useLocation } from "@tanstack/react-router";
import { locales, type Locale } from "./locales";
import { getLocaleFromPathname, getLocalizedPath } from "./locale-helpers";

export function LanguageSwitcher() {
  const location = useLocation();
  const currentLocale = getLocaleFromPathname(location.pathname);

  return (
    <nav>
      <ul>
        {locales.map((locale) => {
          const isActive = locale === currentLocale;
          const localizedPath = getLocalizedPath(location.pathname, locale);

          return (
            <li key={locale}>
              <Link
                to={localizedPath}
                search={location.search}
                hash={location.hash}
                aria-current={isActive ? "page" : undefined}
              >
                {locale.toUpperCase()}
              </Link>
            </li>
          );
        })}
      </ul>
    </nav>
  );
}

Компонент считывает текущий путь, определяет активную локаль и отображает ссылку для каждого поддерживаемого языка, сохраняя текущую структуру страницы, параметры поиска и фрагмент хэша. Пользователи могут переключать языки, оставаясь на той же логической странице.