i18n: BCP-47 URL locales + complete EN translations
- URL surface now matches Angular: `/ru-ru/`, `/en-us/`, `/zh-cn/`, …
(BCP-47). Bare short codes still work — the [lang]/layout auto-
promotes them with a replace navigation. Internally everything that
needs the short language (i18n file lookup, API path segment,
Accept-Language header, dictionary `title[lang]` key, Intl
formatters) reads it through the new `useLocale()` hook, which
returns both `locale` (BCP-47) and `language` (short).
- ApiClient.locale is now mutable and is updated from the [lang]
layout whenever the URL locale changes — was hard-coded to "ru" in
the root layout before, so backend responses for /en/... still came
back in Russian. Cities / airports / flight statuses now arrive in
the active language.
- All 21 empty EN translation keys filled in (AIRPLANE.*, BOARD.
PREVIOUS-FLIGHT, SCHEDULE.FILE-NAME, SEO.SCHEDULE.*, SEO.FLIGHTS-
MAP.*, SHARED.FLIGHT-TRANSFER-PLURAL-*, SHARED.WEEK_FORMAT-WRONG)
so /en-us renders without falling back to raw keys.
- Added BOARD.LOAD-FAILED-TITLE / -MESSAGE keys (RU + EN) and removed
the three hardcoded Russian error strings from the search-page
error card.
- FlightStatus now reads `FLIGHT-STATUSES.{Status}` from i18n instead
of hardcoding the Russian labels.
- FlightCard's OperatorLogo now picks the en/ru carrier-logo variant
from `useLocale().language` instead of always passing "ru" — the
Aeroflot/Rossiya logos display in the active language where
variants exist.
- registerPrimeLocales(): all 9 supported languages get a PrimeReact
`addLocale` entry at module load (RU + EN hand-curated, others built
from Intl). Calendar/AutoComplete widgets switch with the URL.
- ErrorBoundary catches outside the i18n provider, so it now ships
its own minimal localised string table keyed off the URL locale —
no more "Something went wrong" leaking on the Russian site.
- Hreflang URLs now emit BCP-47 (`/en-us/...`) while `hreflang="en"`
stays the short Google-friendly form.
- Datetime helpers accept either short or BCP-47 locale (`isRussianLocale`)
so callers can pass through whatever the route hands them.
This commit is contained in:
@@ -32,7 +32,7 @@ vi.mock("@/shared/dictionaries/index.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("@modern-js/runtime/router", () => ({
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
}));
|
||||
|
||||
vi.mock("@/i18n/provider.js", () => ({
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
import { type FC, useCallback, useEffect, useMemo, type FormEvent } from "react";
|
||||
import { Calendar } from "primereact/calendar";
|
||||
import { useParams } from "@modern-js/runtime/router";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { CityAutocomplete } from "@/ui/city-autocomplete/index.js";
|
||||
import { DayQuickPick } from "@/ui/calendar/DayQuickPick.js";
|
||||
import { useDictionaries, findCityByCoord } from "@/shared/dictionaries/index.js";
|
||||
@@ -53,8 +53,8 @@ export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
|
||||
onChange,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const { lang } = useParams<{ lang: string }>();
|
||||
const { dictionaries } = useDictionaries(lang ?? "ru");
|
||||
const { language } = useLocale();
|
||||
const { dictionaries } = useDictionaries(language);
|
||||
|
||||
const handleLocate = useCallback(async () => {
|
||||
if (!dictionaries || typeof navigator === "undefined" || !navigator.geolocation) return;
|
||||
@@ -254,7 +254,7 @@ export const FlightsMapFilter: FC<FlightsMapFilterProps> = ({
|
||||
<label htmlFor="fm-date">{t("SHARED.FLIGHT_DATE")}</label>
|
||||
<DayQuickPick
|
||||
value={value.date ? yyyymmddToDate(value.date) : null}
|
||||
locale={lang ?? "ru"}
|
||||
locale={language}
|
||||
onChange={handleDateChange}
|
||||
/>
|
||||
<Calendar
|
||||
|
||||
@@ -17,7 +17,7 @@ function buildDictionaries(raw?: IRawDictionaries): IDictionaries {
|
||||
}
|
||||
|
||||
vi.mock("@modern-js/runtime/router", () => ({
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
Link: ({ children, ...props }: { children: React.ReactNode }) => <a {...props}>{children}</a>,
|
||||
}));
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import { type FC, lazy, Suspense, useState, useEffect, useCallback, useMemo } from "react";
|
||||
import { useParams } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { PageLayout } from "@/ui/layout/PageLayout.js";
|
||||
import { PageTabs } from "@/ui/layout/PageTabs.js";
|
||||
@@ -81,14 +81,13 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
|
||||
tileUrl: tileUrlProp,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { locale, language } = useLocale();
|
||||
|
||||
const {
|
||||
dictionaries,
|
||||
loading: dictionariesLoading,
|
||||
error: dictionariesError,
|
||||
} = useDictionaries(lang);
|
||||
} = useDictionaries(language);
|
||||
|
||||
const [filterState, setFilterState] = useState<IFlightsMapFilterState>({
|
||||
connections: false,
|
||||
@@ -296,7 +295,7 @@ export const FlightsMapStartPage: FC<FlightsMapStartPageProps> = ({
|
||||
</h1>
|
||||
}
|
||||
breadcrumbs={[
|
||||
{ label: t("FLIGHTS-MAP.TITLE"), url: `/${lang}/flights-map` },
|
||||
{ label: t("FLIGHTS-MAP.TITLE"), url: `/${locale}/flights-map` },
|
||||
]}
|
||||
contentLeft={
|
||||
<FlightsMapFilter
|
||||
|
||||
@@ -116,7 +116,7 @@ vi.mock("@modern-js/runtime/router", () => ({
|
||||
<a href={to} {...props}>{children}</a>
|
||||
),
|
||||
useNavigate: () => vi.fn(),
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
useSearchParams: () => [new URLSearchParams()],
|
||||
}));
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
*/
|
||||
|
||||
import { type FC, useState, useCallback, useEffect, useRef, type FormEvent } from "react";
|
||||
import { useNavigate, useParams } from "@modern-js/runtime/router";
|
||||
import { useNavigate } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { Calendar } from "primereact/calendar";
|
||||
import { Slider, type SliderChangeEvent } from "primereact/slider";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
@@ -80,9 +81,8 @@ export const OnlineBoardFilter: FC<OnlineBoardFilterProps> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { dictionaries } = useDictionaries(lang);
|
||||
const { locale, language } = useLocale();
|
||||
const { dictionaries } = useDictionaries(language);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<AccordionTab>(initialTab ?? "route");
|
||||
|
||||
@@ -184,9 +184,9 @@ export const OnlineBoardFilter: FC<OnlineBoardFilterProps> = ({
|
||||
const num = cleaned;
|
||||
if (!num) return;
|
||||
const url = buildOnlineBoardUrl({ type: "flight", carrier, flightNumber: num, date: dateParam });
|
||||
void navigate(`/${lang}/${url}`);
|
||||
void navigate(`/${locale}/${url}`);
|
||||
},
|
||||
[flightNumber, flightDate, navigate, lang],
|
||||
[flightNumber, flightDate, navigate, locale],
|
||||
);
|
||||
|
||||
const handleRouteSubmit = useCallback(
|
||||
@@ -199,9 +199,9 @@ export const OnlineBoardFilter: FC<OnlineBoardFilterProps> = ({
|
||||
const arrCode = routeArrivalCode.trim().toUpperCase();
|
||||
if (!depCode || !arrCode) return;
|
||||
const url = buildOnlineBoardUrl({ type: "route", departure: depCode, arrival: arrCode, date: dateParam });
|
||||
void navigate(`/${lang}/${url}`);
|
||||
void navigate(`/${locale}/${url}`);
|
||||
},
|
||||
[routeDepartureCode, routeArrivalCode, routeDate, navigate, lang],
|
||||
[routeDepartureCode, routeArrivalCode, routeDate, navigate, locale],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -277,7 +277,7 @@ export const OnlineBoardFilter: FC<OnlineBoardFilterProps> = ({
|
||||
</label>
|
||||
<DayQuickPick
|
||||
value={flightDate}
|
||||
locale={lang}
|
||||
locale={language}
|
||||
onChange={setFlightDate}
|
||||
/>
|
||||
<Calendar
|
||||
@@ -371,7 +371,7 @@ export const OnlineBoardFilter: FC<OnlineBoardFilterProps> = ({
|
||||
</label>
|
||||
<DayQuickPick
|
||||
value={routeDate}
|
||||
locale={lang}
|
||||
locale={language}
|
||||
onChange={setRouteDate}
|
||||
/>
|
||||
<Calendar
|
||||
|
||||
@@ -22,7 +22,7 @@ vi.mock("@/i18n/provider.js", () => ({
|
||||
// Mock all hooks and router
|
||||
vi.mock("@modern-js/runtime/router", () => ({
|
||||
useNavigate: () => vi.fn(),
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
Link: ({ children, ...props }: Record<string, unknown>) =>
|
||||
<a {...props}>{children as React.ReactNode}</a>,
|
||||
}));
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
import type { FC } from "react";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { useNavigate, useParams } from "@modern-js/runtime/router";
|
||||
import { useNavigate } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { FlightList } from "@/ui/flights/FlightList.js";
|
||||
import { findClosestFlightId } from "../closestFlight.js";
|
||||
@@ -182,9 +183,8 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { dictionaries } = useDictionaries(lang);
|
||||
const { locale, language } = useLocale();
|
||||
const { dictionaries } = useDictionaries(language);
|
||||
|
||||
// Human-readable title/breadcrumb. Angular prefers the city name when a
|
||||
// code resolves to a city (LED → 'Санкт-Петербург'); falls back to the
|
||||
@@ -315,9 +315,9 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
date: flight.flightId.date,
|
||||
};
|
||||
const detailsUrl = buildOnlineBoardUrl(detailsParams);
|
||||
void navigate(`/${lang}/${detailsUrl}`);
|
||||
void navigate(`/${locale}/${detailsUrl}`);
|
||||
},
|
||||
[navigate, lang],
|
||||
[navigate, locale],
|
||||
);
|
||||
|
||||
// Navigation: change date via calendar
|
||||
@@ -325,9 +325,9 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
(newDate: string) => {
|
||||
const newParams = { ...params, date: newDate };
|
||||
const url = buildOnlineBoardUrl(newParams);
|
||||
void navigate(`/${lang}/${url}`);
|
||||
void navigate(`/${locale}/${url}`);
|
||||
},
|
||||
[navigate, lang, params],
|
||||
[navigate, locale, params],
|
||||
);
|
||||
|
||||
// Use live flights when connected, otherwise fetched flights
|
||||
@@ -364,7 +364,7 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
breadcrumbs={[
|
||||
// Angular stops the crumb trail at 'Онлайн-Табло'; the search
|
||||
// heading only lives in the h1 — don't repeat it.
|
||||
{ label: t("BOARD.TITLE"), url: `/${lang}/onlineboard` },
|
||||
{ label: t("BOARD.TITLE"), url: `/${locale}/onlineboard` },
|
||||
]}
|
||||
contentLeft={
|
||||
<>
|
||||
@@ -405,7 +405,7 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
availableDates={calendarDays}
|
||||
daysBefore={1}
|
||||
daysAfter={7}
|
||||
locale={lang}
|
||||
locale={language}
|
||||
onNavigate={handleDateChange}
|
||||
/>
|
||||
}
|
||||
@@ -434,17 +434,17 @@ export const OnlineBoardSearchPage: FC<OnlineBoardSearchPageProps> = ({
|
||||
<section className="frame" data-testid="search-error">
|
||||
<div className="online-board-search__error-card">
|
||||
<h3 className="online-board-search__error-title">
|
||||
Не удалось загрузить данные
|
||||
{t("BOARD.LOAD-FAILED-TITLE")}
|
||||
</h3>
|
||||
<p className="online-board-search__error-message">
|
||||
API сервер недоступен. Проверьте подключение и попробуйте снова.
|
||||
{t("BOARD.LOAD-FAILED-MESSAGE")}
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
className="online-board-search__retry-btn"
|
||||
onClick={refresh}
|
||||
>
|
||||
Повторить
|
||||
{t("SHARED.RETRY")}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -16,7 +16,7 @@ const mockNavigate = vi.fn();
|
||||
|
||||
vi.mock("@modern-js/runtime/router", () => ({
|
||||
useNavigate: () => mockNavigate,
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
Link: ({ children, to, ...props }: { children: React.ReactNode; to: string; className?: string; [k: string]: unknown }) => (
|
||||
<a href={to} {...props}>{children}</a>
|
||||
),
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
*/
|
||||
|
||||
import { type FC, useCallback, useState } from "react";
|
||||
import { useNavigate, useParams } from "@modern-js/runtime/router";
|
||||
import { useNavigate } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { PageLayout } from "@/ui/layout/PageLayout.js";
|
||||
import { PageTabs } from "@/ui/layout/PageTabs.js";
|
||||
@@ -72,8 +73,7 @@ export function buildOnlineBoardPrefillState(
|
||||
export const OnlineBoardStartPage: FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { locale } = useLocale();
|
||||
|
||||
// Read-and-clear any prefill the previous page wrote. Stored in
|
||||
// useState (with a one-shot initializer) so React strict mode's
|
||||
@@ -108,7 +108,7 @@ export const OnlineBoardStartPage: FC = () => {
|
||||
}
|
||||
: {};
|
||||
writeTransientPrefill(SCHEDULE_PREFILL_SLOT, state);
|
||||
navigate(`/${lang}/schedule`);
|
||||
navigate(`/${locale}/schedule`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ export const OnlineBoardStartPage: FC = () => {
|
||||
setPrefill(buildOnlineBoardPrefillState(request));
|
||||
setFilterKey((n) => n + 1);
|
||||
},
|
||||
[navigate, lang],
|
||||
[navigate, locale],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -56,7 +56,7 @@ function parseFlightSegments(segments: string[]): IScheduleFlightId[] {
|
||||
export default function ScheduleDetailsCatchAllRoute(): JSX.Element {
|
||||
const { t } = useTranslation();
|
||||
const routeParams = useParams<{ "*": string; lang: string }>();
|
||||
const locale = routeParams.lang ?? "ru";
|
||||
const locale = routeParams.lang ?? "ru-ru";
|
||||
const canonicalOrigin = getEnv().PROD_ORIGIN;
|
||||
|
||||
// Modern.js splat route ($.tsx) provides the remaining path via "*" param.
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
|
||||
import type { FC } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { useNavigate, useParams } from "@modern-js/runtime/router";
|
||||
import { useNavigate } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { useTranslation } from "@/i18n/provider.js";
|
||||
import { FlightList } from "@/ui/flights/FlightList.js";
|
||||
import { PageLayout } from "@/ui/layout/PageLayout.js";
|
||||
@@ -75,10 +76,9 @@ function extractSimpleFlights(flights: Array<{ routeType: string }>): ISimpleFli
|
||||
export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { locale, language } = useLocale();
|
||||
|
||||
const { dictionaries } = useDictionaries(lang);
|
||||
const { dictionaries } = useDictionaries(language);
|
||||
const outbound = params.outbound;
|
||||
const inbound = params.type === "roundtrip" ? params.inbound : undefined;
|
||||
|
||||
@@ -132,9 +132,9 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
|
||||
? { type: "roundtrip", outbound: newOutbound, inbound }
|
||||
: { type: "route", outbound: newOutbound };
|
||||
const url = buildScheduleUrl(newParams);
|
||||
void navigate(`/${lang}/${url}`);
|
||||
void navigate(`/${locale}/${url}`);
|
||||
},
|
||||
[navigate, lang, outbound, inbound],
|
||||
[navigate, locale, outbound, inbound],
|
||||
);
|
||||
|
||||
const outboundSimple = extractSimpleFlights(outboundFlights);
|
||||
@@ -163,7 +163,7 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
|
||||
</h1>
|
||||
}
|
||||
breadcrumbs={[
|
||||
{ label: t("SCHEDULE.TITLE"), url: `/${lang}/schedule` },
|
||||
{ label: t("SCHEDULE.TITLE"), url: `/${locale}/schedule` },
|
||||
{ label: routeHeading },
|
||||
]}
|
||||
contentLeft={
|
||||
@@ -183,7 +183,7 @@ export const ScheduleSearchPage: FC<ScheduleSearchPageProps> = ({ params }) => {
|
||||
availableDates={availableDates}
|
||||
daysBefore={2}
|
||||
daysAfter={30}
|
||||
locale={lang}
|
||||
locale={language}
|
||||
onNavigate={(yyyymmdd) => {
|
||||
const iso = `${yyyymmdd.slice(0, 4)}-${yyyymmdd.slice(4, 6)}-${yyyymmdd.slice(6, 8)}`;
|
||||
handleDateChange(iso);
|
||||
|
||||
@@ -16,7 +16,7 @@ const mockNavigate = vi.fn();
|
||||
|
||||
vi.mock("@modern-js/runtime/router", () => ({
|
||||
useNavigate: () => mockNavigate,
|
||||
useParams: () => ({ lang: "ru" }),
|
||||
useParams: () => ({ lang: "ru-ru" }),
|
||||
Link: ({ children, to, ...props }: { children: React.ReactNode; to: string; className?: string; [k: string]: unknown }) => (
|
||||
<a href={to} {...props}>{children}</a>
|
||||
),
|
||||
@@ -83,7 +83,7 @@ describe("ScheduleStartPage", () => {
|
||||
expect(sessionStorage.getItem("afl-prefill:schedule")).toBe(
|
||||
JSON.stringify({ departure: "SVO", arrival: "LED", withReturn: false }),
|
||||
);
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/ru/schedule");
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/ru-ru/schedule");
|
||||
});
|
||||
|
||||
it("writes prefill + navigates to onlineboard on Onlineboard-type popular click", () => {
|
||||
@@ -92,7 +92,7 @@ describe("ScheduleStartPage", () => {
|
||||
expect(sessionStorage.getItem("afl-prefill:online-board")).toBe(
|
||||
JSON.stringify({ tab: "route", departure: "LED" }),
|
||||
);
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/ru/onlineboard");
|
||||
expect(mockNavigate).toHaveBeenCalledWith("/ru-ru/onlineboard");
|
||||
});
|
||||
|
||||
it("initializes form from sessionStorage prefill", () => {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
*/
|
||||
|
||||
import { type FC, useState, useCallback, type FormEvent } from "react";
|
||||
import { useNavigate, useParams } from "@modern-js/runtime/router";
|
||||
import { useNavigate } from "@modern-js/runtime/router";
|
||||
import { useLocale } from "@/i18n/useLocale.js";
|
||||
import { Calendar } from "primereact/calendar";
|
||||
import { Slider, type SliderChangeEvent } from "primereact/slider";
|
||||
import { AutoComplete, type AutoCompleteCompleteEvent } from "primereact/autocomplete";
|
||||
@@ -66,8 +67,7 @@ export interface SchedulePrefillState {
|
||||
export const ScheduleStartPage: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const routeParams = useParams<{ lang: string }>();
|
||||
const lang = routeParams.lang ?? "ru";
|
||||
const { locale } = useLocale();
|
||||
|
||||
// One-shot read of any prefill the previous page wrote.
|
||||
const [prefill] = useState<SchedulePrefillState>(
|
||||
@@ -149,9 +149,9 @@ export const ScheduleStartPage: FC = () => {
|
||||
});
|
||||
}
|
||||
|
||||
void navigate(`/${lang}/${url}`);
|
||||
void navigate(`/${locale}/${url}`);
|
||||
},
|
||||
[departureAirport, arrivalAirport, dateFrom, dateTo, timeRange, directOnly, isRoundTrip, returnDateFrom, returnDateTo, returnTimeRange, navigate, lang],
|
||||
[departureAirport, arrivalAirport, dateFrom, dateTo, timeRange, directOnly, isRoundTrip, returnDateFrom, returnDateTo, returnTimeRange, navigate, locale],
|
||||
);
|
||||
|
||||
const handlePopularRequestClick = useCallback(
|
||||
@@ -161,7 +161,7 @@ export const ScheduleStartPage: FC = () => {
|
||||
ONLINE_BOARD_PREFILL_SLOT,
|
||||
buildOnlineBoardPrefillState(request),
|
||||
);
|
||||
navigate(`/${lang}/onlineboard`);
|
||||
navigate(`/${locale}/onlineboard`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,9 +175,9 @@ export const ScheduleStartPage: FC = () => {
|
||||
}
|
||||
: {};
|
||||
writeTransientPrefill(SCHEDULE_PREFILL_SLOT, state);
|
||||
navigate(`/${lang}/schedule`);
|
||||
navigate(`/${locale}/schedule`);
|
||||
},
|
||||
[navigate, lang],
|
||||
[navigate, locale],
|
||||
);
|
||||
|
||||
const scheduleFilter = (
|
||||
|
||||
Reference in New Issue
Block a user