-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
examples: add intlayer i18n example #6039
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds a new React example demonstrating Intlayer-powered i18n with locale-aware TanStack Router routes, locale-resolving server adapters, localized components/hooks, Vite/TypeScript configuration, and a generated route tree for locale-prefixed routing. Changes
sequenceDiagram
participant Browser
participant Router as TanStack Router
participant RouteComp as RouteComponent
participant Intlayer as IntlayerProvider
participant Server
participant Store as LocalStorage
Browser->>Router: Navigate to /{locale}/path
Router->>RouteComp: mount with params.locale
RouteComp->>Intlayer: Initialize provider(locale)
RouteComp->>Store: read persisted locale (optional)
Router->>Server: preloader / getData request (headers, cookies)
Server->>Intlayer: call getLocaleCore(adapters)
Server-->>Router: return localized messages/data
RouteComp->>Router: render localized UI (Header, LocaleSwitcher, Outlet)
Browser->>RouteComp: user clicks locale switch
RouteComp->>Store: setLocaleInStorage(newLocale)
RouteComp->>Router: navigate to localized path (LocalizedLink / useLocalizedNavigate)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45–60 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
2f6ad4d to
8344da4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
🧹 Nitpick comments (9)
examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx (1)
1-21: Hook correctly syncs<html>attributes with the active localeThe effect wiring and dependency on
localelook good and should behave correctly in a browser-only context.If you expect this hook to ever run in non-DOM environments (e.g. some tests or exotic runtimes), you might optionally wrap the effect body with a
typeof document !== 'undefined'check, but it’s not strictly necessary for typical Start/React usage.examples/react/start-i18n-intlayer/tsconfig.json (1)
1-36: Strict TS config looks good; minor include nitThis config hits the strictness goals (strict mode, unused checks, bundler resolution, paths) and should work well for the example.
One tiny consistency nit: the
includearray lists"vite.config.js", but the file in this example isvite.config.ts. It’s harmless because"**/*.ts"already picks it up, but you could either change that entry to"vite.config.ts"or drop it entirely for clarity.examples/react/start-i18n-intlayer/src/utils/getLocale.ts (1)
1-29: Locale resolution wiring looks correct; simplify the async wrapperThe adapters for
getAllHeaders,getCookie, andgetHeaderare consistent with the Start server helpers. ThegetAllHeaderscallback must be async per the intlayer API, which your code correctly implements.You can drop the redundant outer async/await for a cleaner signature:
-export const getLocale = async () => - await getLocaleCore({ +export const getLocale = () => + getLocaleCore({ // Fallback using Accept-Language negotiation getAllHeaders: async () => { const headers = getRequestHeaders() const result: Record<string, string> = {} // Convert the TypedHeaders into a plain Record<string, string> for (const [key, value] of headers.entries()) { result[key] = value } return result }, // Get the cookie from the request (default: 'INTLAYER_LOCALE') getCookie: (name) => { const cookieString = getRequestHeader('cookie') return getCookie(name, cookieString) }, // Get the header from the request (default: 'x-intlayer-locale') getHeader: (name) => getRequestHeader(name), })Both forms return a
Promise, but the simplified version is more idiomatic.examples/react/start-i18n-intlayer/src/components/Header.tsx (2)
5-17: Remove unnecessary React Fragment wrapper.The Fragment (
<>...</>) is redundant since the component returns only a single<header>element.return ( - <> - <header className="p-4 flex items-center bg-gray-800 text-white shadow-lg"> - <h1 className="ml-4 text-xl font-semibold"> - <LocalizedLink to="/"> - <img - src="/tanstack-word-logo-white.svg" - alt="TanStack Logo" - className="h-10" - /> - </LocalizedLink> - </h1> - </header> - </> + <header className="p-4 flex items-center bg-gray-800 text-white shadow-lg"> + <h1 className="ml-4 text-xl font-semibold"> + <LocalizedLink to="/"> + <img + src="/tanstack-word-logo-white.svg" + alt="TanStack Logo" + className="h-10" + /> + </LocalizedLink> + </h1> + </header> )
7-15: Consider semantic HTML:<h1>with only an image.Using an
<h1>that contains only an image (no visible text) may affect accessibility and SEO. Screen readers will announce "TanStack Logo" from the alt text, which works, but consider whether adding visually-hidden text (e.g., "TanStack Start") would better convey the page heading.examples/react/start-i18n-intlayer/intlayer.config.ts (1)
14-19: AI configuration included in example.The AI configuration with OpenAI API key is included. For an example project, this is fine, but ensure the README documents that
OPENAI_API_KEYmust be set if AI features are used, or consider making this section optional/commented out by default since it's not core to the i18n demonstration.examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
29-31: Minor typo: extra space in function call.There's an extra space before the closing parenthesis on line 30.
- params={{ locale: getPrefix(localeEl ).localePrefix }} + params={{ locale: getPrefix(localeEl).localePrefix }}examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts (1)
12-27: Move type definitions outside the hook.Defining types inside the hook body is non-idiomatic. While TypeScript erases types at runtime, it's cleaner to define them at module scope for reusability and readability.
+type StripLocalePrefix<T extends string> = T extends + | `/${typeof LOCALE_ROUTE}` + | `/${typeof LOCALE_ROUTE}/` + ? "/" + : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}` + ? `/${Rest}` + : never; + +type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>; + +interface LocalizedNavigate { + (to: LocalizedTo): ReturnType<typeof useNavigate>; + (opts: { to: LocalizedTo } & Record<string, unknown>): ReturnType<typeof useNavigate>; +} + export const useLocalizedNavigate = () => { const navigate = useNavigate(); const { locale } = useLocale(); - type StripLocalePrefix<T extends string> = T extends - | `/${typeof LOCALE_ROUTE}` - | `/${typeof LOCALE_ROUTE}/` - ? "/" - : T extends `/${typeof LOCALE_ROUTE}/${infer Rest}` - ? `/${Rest}` - : never; - - type LocalizedTo = StripLocalePrefix<FileRouteTypes["to"]>; - - interface LocalizedNavigate { - (to: LocalizedTo): ReturnType<typeof navigate>; - ( - opts: { to: LocalizedTo } & Record<string, unknown>, - ): ReturnType<typeof navigate>; - } - const localizedNavigate: LocalizedNavigate = (args: any) => {examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx (1)
35-38: SimplifyqueryFnwrapper.The arrow function wrapper around
getData()is unnecessary sincegetDatais already callable and returns a Promise.const { data, isPending } = useQuery({ - queryFn: () => getData(), + queryFn: getData, queryKey: ['app-message', locale], });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
examples/react/start-i18n-intlayer/public/favicon.icois excluded by!**/*.icoexamples/react/start-i18n-intlayer/public/tanstack-circle-logo.pngis excluded by!**/*.pngexamples/react/start-i18n-intlayer/public/tanstack-word-logo-white.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
examples/react/start-i18n-intlayer/.gitignore(1 hunks)examples/react/start-i18n-intlayer/intlayer.config.ts(1 hunks)examples/react/start-i18n-intlayer/package.json(1 hunks)examples/react/start-i18n-intlayer/src/components/Header.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/localized-link.tsx(1 hunks)examples/react/start-i18n-intlayer/src/content/index.content.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts(1 hunks)examples/react/start-i18n-intlayer/src/routeTree.gen.ts(1 hunks)examples/react/start-i18n-intlayer/src/router.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/__root.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx(1 hunks)examples/react/start-i18n-intlayer/src/styles.css(1 hunks)examples/react/start-i18n-intlayer/src/utils/getLocale.ts(1 hunks)examples/react/start-i18n-intlayer/tsconfig.json(1 hunks)examples/react/start-i18n-intlayer/vite.config.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.tsexamples/react/start-i18n-intlayer/src/components/Header.tsxexamples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsxexamples/react/start-i18n-intlayer/src/router.tsxexamples/react/start-i18n-intlayer/vite.config.tsexamples/react/start-i18n-intlayer/src/content/index.content.tsxexamples/react/start-i18n-intlayer/intlayer.config.tsexamples/react/start-i18n-intlayer/src/utils/getLocale.tsexamples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/routes/__root.tsxexamples/react/start-i18n-intlayer/src/components/locale-switcher.tsxexamples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.tsexamples/react/start-i18n-intlayer/src/components/Header.tsxexamples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsxexamples/react/start-i18n-intlayer/src/router.tsxexamples/react/start-i18n-intlayer/vite.config.tsexamples/react/start-i18n-intlayer/src/content/index.content.tsxexamples/react/start-i18n-intlayer/intlayer.config.tsexamples/react/start-i18n-intlayer/src/utils/getLocale.tsexamples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/routes/__root.tsxexamples/react/start-i18n-intlayer/src/components/locale-switcher.tsxexamples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Use workspace protocol
workspace:*for internal dependencies in package.json files
Files:
examples/react/start-i18n-intlayer/package.json
🧠 Learnings (6)
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
examples/react/start-i18n-intlayer/src/router.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
examples/react/start-i18n-intlayer/src/router.tsxexamples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/routes/__root.tsxexamples/react/start-i18n-intlayer/tsconfig.json
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
examples/react/start-i18n-intlayer/package.jsonexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/tsconfig.json
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/routes/__root.tsx
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript strict mode with extensive type safety for all code
Applied to files:
examples/react/start-i18n-intlayer/tsconfig.json
🧬 Code graph analysis (7)
examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts (2)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
LOCALE_ROUTE(6-6)examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
FileRouteTypes(40-47)
examples/react/start-i18n-intlayer/src/components/Header.tsx (1)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
LocalizedLink(32-45)
examples/react/start-i18n-intlayer/src/utils/getLocale.ts (1)
packages/start-server-core/src/request-response.ts (3)
getRequestHeaders(77-80)getRequestHeader(82-84)getCookie(226-228)
examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx (2)
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx (1)
Route(15-17)examples/react/start-i18n-intlayer/src/utils/getLocale.ts (1)
getLocale(7-29)
examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
examples/react/start-i18n-intlayer/src/router.tsx (1)
getRouter(7-15)
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx (4)
examples/react/start-i18n-intlayer/src/routes/__root.tsx (1)
Route(5-28)examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx (1)
Route(9-19)examples/react/start-i18n-intlayer/src/components/Header.tsx (1)
Header(3-19)examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
LocaleSwitcher(12-51)
examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (2)
LocalizedLink(32-45)To(13-13)
🔇 Additional comments (15)
examples/react/start-i18n-intlayer/.gitignore (1)
1-15: Git ignore patterns look appropriate for this exampleThe ignore list covers the expected build artifacts, framework caches, and Intlayer-specific files; nothing here seems problematic.
examples/react/start-i18n-intlayer/src/content/index.content.tsx (1)
1-41: Typed dictionary shape and translations look solidThe
HomePageContentinterface matches thecontentstructure, and usingsatisfies Dictionary<HomePageContent>gives nice compile-time guarantees. Translations are consistently provided foren,es, andfr.examples/react/start-i18n-intlayer/vite.config.ts (1)
1-23: Vite plugin setup and ordering look correct
intlayerProxyrunning beforenitro, followed by tsconfig paths, Tailwind, TanStack Start, React, andintlayeris a sensible order and aligns with the comments and tooling expectations.examples/react/start-i18n-intlayer/src/styles.css (1)
1-10: Base Tailwind + typography styling is appropriateThe Tailwind import and minimal body reset/font stack are a good fit for this example and shouldn’t interfere with Tailwind’s utilities.
examples/react/start-i18n-intlayer/src/routes/__root.tsx (1)
5-28: Route configuration looks good.The root route setup with head metadata (charset, viewport, title) and stylesheet link is correctly structured for TanStack Start.
examples/react/start-i18n-intlayer/intlayer.config.ts (1)
4-47: Configuration structure is well-organized.The Intlayer configuration properly defines locales, routing mode, and build settings. The use of the
Localesenum ensures type safety.examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts (1)
1-19: Well-structured i18n content definition.The locale switcher content follows Intlayer's dictionary pattern correctly. Good use of
satisfies Dictionaryfor type safety andinsert()for the interpolated placeholder.examples/react/start-i18n-intlayer/src/router.tsx (1)
7-15: The suggestion to add an explicit return type is well-intentioned for TypeScript strict mode compliance, but the proposed implementation is incorrect. TheRoutertype is not exported from@tanstack/react-routerfor direct import, and the return type signatureRouter<typeof routeTreeImpl>is invalid.Per TanStack Router's documentation, type safety is achieved through declaration merging with the
Registerinterface, not through explicit return type annotations on the factory function. The current implementation is acceptable and follows TanStack Router's recommended patterns.Likely an incorrect or invalid review comment.
examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
12-50: Well-structured locale switcher component.The component properly handles accessibility with
aria-current,aria-label,lang, anddirattributes. The use ofgetPathWithoutLocaleto preserve the current path during locale switches is a good pattern.examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx (2)
23-40: Rendering<html>in a nested route is unconventional.This route component renders the full HTML document structure (
<html>,<head>,<body>). Typically, this would be handled in__root.tsxor ashellComponent. Verify this is intentional for TanStack Start's routing model with locale prefixes.
19-24:useLocale()requiresIntlayerProvidercontext to function correctly.The web search confirms that
useLocale()reads React context established byIntlayerProviderand must be called within a component tree wrapped by the provider. IfuseLocale()is indeed called beforeIntlayerProviderwraps the component tree (as suggested by the line numbers), the hook will fail to access the locale context.Verify that either: (1) a parent component or layout provides
IntlayerProviderat a higher level, (2) this is a server component using a server-side variant with explicit locale, or (3) the component structure needs adjustment to ensureuseLocale()is called only afterIntlayerProviderinitialization.examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
6-30: Good type-level utilities for locale handling.The
RemoveLocaleParam,CollapseDoubleSlashes, and helper types provide strong compile-time guarantees for locale-aware routing. The recursive type transformations are well-constructed.examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx (2)
31-47: Clean demonstration of client and server i18n.The component effectively shows both patterns:
useIntlayerfor client-side translations andgetDataserver function for server-rendered content. The query key includeslocaleensuring proper cache invalidation on locale changes.
11-13: No changes needed —getIntlayeris designed to handle undefinedlocaleparameter.The
intlayerMiddlewareautomatically detects the locale and providesgetIntlayerwith a default parameter. When the optional{-$locale}segment is absent andlocaleis undefined,getIntlayer('app', locale)correctly uses the middleware-detected locale instead. Adding a fallback likelocale ?? 'en'bypasses this intelligent detection and could override the user's actual locale preference.Likely an incorrect or invalid review comment.
examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
1-99: Auto-generated file — no review required.This file is automatically generated by TanStack Router and should not be manually modified. The file correctly includes the appropriate disable comments (
eslint-disable,@ts-nocheck) and documentation header. Based on learnings,routeTree.gen.tsfiles are excluded from review in TanStack Router repositories.
examples/react/start-i18n-intlayer/src/components/localized-link.tsx
Outdated
Show resolved
Hide resolved
examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts
Outdated
Show resolved
Hide resolved
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx
Outdated
Show resolved
Hide resolved
8344da4 to
8ecbf82
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
49-49: Handle undefinedtoprop gracefully.The
toprop is optional (line 24), but concatenation here produces"/{-$locale}undefined"whenprops.toisundefined.- to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps['to']} + to={`/${LOCALE_ROUTE}${props.to ?? ''}` as LinkComponentProps['to']}Alternatively, make
torequired inLocalizedLinkPropsif navigation without a destination isn't valid.
🧹 Nitpick comments (3)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
45-48: Consider tightening the params type guard.
typeof null === 'object'in JavaScript. Whileprops.paramsis unlikely to benullgiven TanStack Router's types, a stricter check is more defensive:params={{ locale: getPrefix(locale).localePrefix, - ...(typeof props.params === 'object' ? props.params : {}), + ...(props.params && typeof props.params === 'object' ? props.params : {}), }}examples/react/start-i18n-intlayer/src/content/index.content.tsx (1)
3-10: Consider exportingHomePageContentfor stronger cross-module typingIf other parts of the example (hooks, components, tests) need to refer to this content shape, making the interface exported (e.g.,
export interface HomePageContent) would avoid duplicating field names and keep refactors type-safe across modules.examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx (1)
18-23: Extract a singleresolvedLocaleto avoid duplication.You compute
locale ?? defaultLocaletwice; extracting it once improves readability and keeps things in sync if the fallback logic ever changes.function RouteComponent() { - const { locale } = Route.useParams() - const { defaultLocale } = useLocale() - const [queryClient] = useState(() => new QueryClient()) + const { locale } = Route.useParams() + const { defaultLocale } = useLocale() + const resolvedLocale = locale ?? defaultLocale + const [queryClient] = useState(() => new QueryClient()) return ( - <html lang={locale ?? defaultLocale}> + <html lang={resolvedLocale}> @@ - <IntlayerProvider locale={locale ?? defaultLocale}> + <IntlayerProvider locale={resolvedLocale}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
examples/react/start-i18n-intlayer/public/favicon.icois excluded by!**/*.icoexamples/react/start-i18n-intlayer/public/tanstack-circle-logo.pngis excluded by!**/*.pngexamples/react/start-i18n-intlayer/public/tanstack-word-logo-white.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
examples/react/start-i18n-intlayer/.gitignore(1 hunks)examples/react/start-i18n-intlayer/intlayer.config.ts(1 hunks)examples/react/start-i18n-intlayer/package.json(1 hunks)examples/react/start-i18n-intlayer/src/components/Header.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/localized-link.tsx(1 hunks)examples/react/start-i18n-intlayer/src/content/index.content.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts(1 hunks)examples/react/start-i18n-intlayer/src/routeTree.gen.ts(1 hunks)examples/react/start-i18n-intlayer/src/router.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/__root.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx(1 hunks)examples/react/start-i18n-intlayer/src/styles.css(1 hunks)examples/react/start-i18n-intlayer/src/utils/getLocale.ts(1 hunks)examples/react/start-i18n-intlayer/tsconfig.json(1 hunks)examples/react/start-i18n-intlayer/vite.config.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
- examples/react/start-i18n-intlayer/.gitignore
- examples/react/start-i18n-intlayer/src/styles.css
- examples/react/start-i18n-intlayer/package.json
- examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx
- examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx
- examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx
- examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts
- examples/react/start-i18n-intlayer/src/router.tsx
- examples/react/start-i18n-intlayer/intlayer.config.ts
- examples/react/start-i18n-intlayer/src/components/Header.tsx
- examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts
- examples/react/start-i18n-intlayer/src/routes/__root.tsx
- examples/react/start-i18n-intlayer/vite.config.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/utils/getLocale.tsexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/content/index.content.tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/utils/getLocale.tsexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/content/index.content.tsx
🧠 Learnings (6)
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/*.{ts,tsx} : Use TypeScript strict mode with extensive type safety for all code
Applied to files:
examples/react/start-i18n-intlayer/tsconfig.json
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
examples/react/start-i18n-intlayer/tsconfig.jsonexamples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
🧬 Code graph analysis (2)
examples/react/start-i18n-intlayer/src/utils/getLocale.ts (1)
packages/start-server-core/src/request-response.ts (3)
getRequestHeaders(77-80)getRequestHeader(82-84)getCookie(226-228)
examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
examples/react/start-i18n-intlayer/src/router.tsx (1)
getRouter(7-15)
🔇 Additional comments (7)
examples/react/start-i18n-intlayer/tsconfig.json (1)
1-36: Well-configured TypeScript setup for modern Vite + Intlayer integration.The tsconfig.json is comprehensive and follows current best practices:
- Strict mode is enabled across the board, aligning with the learning requirement for extensive type safety.
- Module resolution, target, and JSX settings are appropriate for a modern Vite-based React app.
- Inclusion of
.intlayer/types/**/*properly integrates Intlayer's generated type definitions.- The
@/*path alias for./src/*provides clean imports throughout the codebase.- All configuration files (eslint.config.ts, prettier.config.js, vite.config.js) are included for type checking.
Please confirm that
eslint.config.tsincludes TanStack Router ESLint plugin rules as per coding guidelines.examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
1-99: Skip detailed review for generated route treeThis
routeTree.gen.tsfile is clearly marked as auto-generated and, per project learnings, route tree generator outputs (likerouteTree.gen.ts) should not be manually edited or reviewed for logic, typing, or lint/style. I’m intentionally skipping further review here and assuming the generator is the source of truth.examples/react/start-i18n-intlayer/src/components/localized-link.tsx (2)
1-7: LGTM!Imports are well-organized with type-only imports separated, and
LOCALE_ROUTEcorrectly usesas constfor literal type inference.
9-37: Well-designed type utilities.The recursive type helpers (
CollapseDoubleSlashes,RemoveAll,RemoveLocaleFromString) correctly handle compile-time path normalization. The explicit type parameter naming (TVal,TString,THead,TTail) improves readability.examples/react/start-i18n-intlayer/src/content/index.content.tsx (1)
12-39: Dictionary structure andsatisfiesusage look solidThe
appContentshape matches theDictionary<HomePageContent>contract, and usingsatisfiesretains literal types while enforcing the interface, which fits strict TypeScript usage for this i18n example.examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx (1)
20-35: Per-instanceQueryClientsetup looks good for SSR.Creating the client via
useState(() => new QueryClient())inside the route component avoids module-scope cache sharing while keeping a stable client per app instance, and wrapping<Outlet />with the provider is appropriate here. This structure is solid for an example.If you later adopt the framework’s built-in QueryClient wiring elsewhere, just double-check you’re not unintentionally nesting multiple providers for the same tree.
examples/react/start-i18n-intlayer/src/utils/getLocale.ts (1)
22-26: No issues found. ThecookieStringpassed to intlayer'sgetCookieon line 25 can beundefined, but intlayer'sgetCookiefunction signature isgetCookie(name: string, cookieString?: string), where the second parameter is optional. Whenundefined, the function gracefully falls back todocument.cookieand returns either the cookie value ornull. The adapter implementation is correct.
8ecbf82 to
2340653
Compare
2340653 to
d800788
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (1)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (1)
23-25: Guard optionaltoand tightenparamsmerge to avoid edge‑case runtime issues.Two small robustness points:
tois optional inLocalizedLinkProps, but currently interpolated directly:to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps['to']}If
props.tois ever omitted, this becomes"/{-$locale}undefined". Either maketorequired or treatundefinedas an empty string so the base locale route is used.
- The
paramsmerge usestypeof props.params === 'object', which also matchesnull. Spreadingnullwould throw if it ever slipped through, even if the current types don’t allow it.A minimal defensive change that keeps the current API:
- params={{ - locale: getPrefix(locale).localePrefix, - ...(typeof props.params === 'object' ? props.params : {}), - }} - to={`/${LOCALE_ROUTE}${props.to}` as LinkComponentProps['to']} + params={{ + locale: getPrefix(locale).localePrefix, + ...(props.params && typeof props.params === 'object' + ? props.params + : {}), + }} + to={`/${LOCALE_ROUTE}${props.to ?? ''}` as LinkComponentProps['to']}This keeps the example simple, avoids accidentally serializing
"undefined"into the path, and hardens the params spread without changing the public surface.Also applies to: 45-49
🧹 Nitpick comments (1)
examples/react/start-i18n-intlayer/package.json (1)
20-40: Consider pinning Intlayer package versions for reproducibility.The
intlayer,react-intlayer,vite-intlayer, andintlayer-editorpackages use"latest"versions, which can cause non-deterministic installs and CI variability. For a stable example, consider pinning these to specific versions (e.g.,intlayer@^0.6.0or similar). This improves reproducibility and makes dependency updates explicit.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (4)
examples/react/start-i18n-intlayer/public/favicon.icois excluded by!**/*.icoexamples/react/start-i18n-intlayer/public/tanstack-circle-logo.pngis excluded by!**/*.pngexamples/react/start-i18n-intlayer/public/tanstack-word-logo-white.svgis excluded by!**/*.svgpnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
examples/react/start-i18n-intlayer/.gitignore(1 hunks)examples/react/start-i18n-intlayer/intlayer.config.ts(1 hunks)examples/react/start-i18n-intlayer/package.json(1 hunks)examples/react/start-i18n-intlayer/src/components/Header.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts(1 hunks)examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx(1 hunks)examples/react/start-i18n-intlayer/src/components/localized-link.tsx(1 hunks)examples/react/start-i18n-intlayer/src/content/index.content.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx(1 hunks)examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts(1 hunks)examples/react/start-i18n-intlayer/src/routeTree.gen.ts(1 hunks)examples/react/start-i18n-intlayer/src/router.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/__root.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx(1 hunks)examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx(1 hunks)examples/react/start-i18n-intlayer/src/styles.css(1 hunks)examples/react/start-i18n-intlayer/src/utils/getLocale.ts(1 hunks)examples/react/start-i18n-intlayer/tsconfig.json(1 hunks)examples/react/start-i18n-intlayer/vite.config.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- examples/react/start-i18n-intlayer/tsconfig.json
🚧 Files skipped from review as they are similar to previous changes (12)
- examples/react/start-i18n-intlayer/.gitignore
- examples/react/start-i18n-intlayer/src/router.tsx
- examples/react/start-i18n-intlayer/src/utils/getLocale.ts
- examples/react/start-i18n-intlayer/src/hooks/useI18nHTMLAttributes.tsx
- examples/react/start-i18n-intlayer/src/routes/{-$locale}/index.tsx
- examples/react/start-i18n-intlayer/src/routes/{-$locale}/route.tsx
- examples/react/start-i18n-intlayer/src/routes/__root.tsx
- examples/react/start-i18n-intlayer/src/hooks/useLocalizedNavigate.ts
- examples/react/start-i18n-intlayer/src/components/Header.tsx
- examples/react/start-i18n-intlayer/vite.config.ts
- examples/react/start-i18n-intlayer/intlayer.config.ts
- examples/react/start-i18n-intlayer/src/components/locale-switcher.content.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
examples/react/start-i18n-intlayer/src/components/locale-switcher.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/content/index.content.tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
examples/react/start-i18n-intlayer/src/components/locale-switcher.tsxexamples/react/start-i18n-intlayer/src/routeTree.gen.tsexamples/react/start-i18n-intlayer/src/components/localized-link.tsxexamples/react/start-i18n-intlayer/src/content/index.content.tsx
**/package.json
📄 CodeRabbit inference engine (AGENTS.md)
Use workspace protocol
workspace:*for internal dependencies in package.json files
Files:
examples/react/start-i18n-intlayer/package.json
🧠 Learnings (6)
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/package.json : Use workspace protocol `workspace:*` for internal dependencies in package.json files
Applied to files:
examples/react/start-i18n-intlayer/package.json
📚 Learning: 2025-11-02T16:16:24.898Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Applied to files:
examples/react/start-i18n-intlayer/package.jsonexamples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
📚 Learning: 2025-12-06T15:03:07.210Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.210Z
Learning: Use file-based routing in `src/routes/` directories or code-based routing with route definitions
Applied to files:
examples/react/start-i18n-intlayer/src/routeTree.gen.ts
🧬 Code graph analysis (2)
examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
examples/react/start-i18n-intlayer/src/components/localized-link.tsx (2)
LocalizedLink(39-52)To(15-15)
examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
examples/react/start-i18n-intlayer/src/router.tsx (1)
getRouter(7-15)
🔇 Additional comments (5)
examples/react/start-i18n-intlayer/src/routeTree.gen.ts (1)
1-99: Autogenerated route tree – skipping detailed reviewThis file is clearly marked as auto-generated by TanStack Router and long-term repo guidance says
routeTree.gen.tsfiles should not be manually edited or reviewed. I’m treating this as generator output and won’t suggest any changes here.Based on learnings, this file is intentionally excluded from manual review.
examples/react/start-i18n-intlayer/src/styles.css (1)
1-10: LGTM! The Tailwind setup is clean and standard, with an appropriate system font stack and font-smoothing properties for cross-platform text rendering.examples/react/start-i18n-intlayer/package.json (1)
14-27: TanStack dependencies correctly use workspace protocol. ✓All internal TanStack packages (
@tanstack/react-devtools,@tanstack/react-router,@tanstack/react-start,@tanstack/router-plugin) correctly referenceworkspace:*, ensuring the example resolves to the monorepo packages.examples/react/start-i18n-intlayer/src/content/index.content.tsx (1)
1-41: Idiomatic Intlayer dictionary; types and structure look solid
HomePageContentmatches thecontentshape exactly, andsatisfies Dictionary<HomePageContent>gives good strict-mode safety without wideningappContent’s type.- Use of
tfor each localized string is consistent and keeps all user-facing text centralized in this content file.No changes needed from my side here.
If you haven’t already, double‑check that wherever you call
useIntlayeror equivalent, you’re using the'app'key so this dictionary is actually wired into the example.examples/react/start-i18n-intlayer/src/components/locale-switcher.tsx (1)
14-52: Locale switcher wiring looks correct and accessible.Nice composition of
useLocation,getPathWithoutLocale, andLocalizedLink: the per‑localeparamsoverride correctly target the new locale,aria-current="page"and the localizedaria-labelare set appropriately, anddir/langare derived from the locale. No changes needed from a routing or strict‑TS perspective here.
This PR includes an example showing how to internationalize a TanStack Start / Router app using Intlayer
It includes i18n for:
Summary by CodeRabbit
New Features
Chores
✏️ Tip: You can customize this high-level summary in your review settings.