feat: add multi-language support (Vietnamese & English)#1
feat: add multi-language support (Vietnamese & English)#1justccuong wants to merge 3 commits intoLiusDev:mainfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds full i18n: English and Vietnamese message files, next-intl integration (plugin, middleware, routing, request loader), locale-aware RootLayout, language toggle UI, localized components, updated route matchers/CORS for API, package/script updates, and Cloudflare D1/KV id updates. Changes
Sequence DiagramsequenceDiagram
participant User
participant LT as LanguageToggle
participant Router as Router
participant Middleware as i18nMiddleware
participant Routing as RoutingConfig
participant Loader as MessageLoader
participant Layout as [locale] Layout
participant UI as UI Components
User->>LT: select language
LT->>Router: replace(pathname, { locale: newLocale })
Router->>Middleware: incoming request with locale
Middleware->>Routing: validate locale & routing rules
Routing-->>Middleware: locale resolved
Middleware->>Loader: load messages for locale
Loader-->>Layout: return messages
Layout->>UI: NextIntlClientProvider supplies messages
UI-->>User: render localized UI
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
next.config.ts (1)
16-16: Avoid hardcoding locale in root redirect to preserve middleware locale detection.Line 16 hardcodes
/vi/llms, which bypasses the i18n middleware's locale detection mechanism (Accept-Language header, stored preferences, etc.). Even thoughdefaultLocaleis set to 'vi', this hardcoded redirect forces Vietnamese regardless of user preference. Redirect to/llmsinstead and let the middleware handle locale prefix selection:Suggested change
- destination: "/vi/llms", + destination: "/llms",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@next.config.ts` at line 16, The redirect currently hardcodes a Vietnamese locale by setting destination: "/vi/llms", which bypasses Next.js i18n middleware; update the redirect configuration (the object with destination: "/vi/llms" in next.config.ts, typically returned from the redirects() export) to use destination: "/llms" so the middleware and i18n settings can apply locale prefixes dynamically instead of forcing "vi".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/app/`[locale]/layout.tsx:
- Around line 25-28: metadata currently contains a hard-coded Vietnamese
description; change it to be generated per-locale by replacing the static export
const metadata with a generateMetadata function (or add export async function
generateMetadata) that reads the resolved locale (e.g., params.locale or the
same locale resolution used in this layout) and returns a metadata object with
localized title/description strings so /en/* pages get English SEO/share text;
reference the metadata symbol and implement generateMetadata in layout.tsx to
produce the localized metadata.
In `@src/components/entity-components.tsx`:
- Around line 126-131: EntityHeader is using next/link directly for internal
routes (the block with newButtonHref && !onNew rendering Button -> Link ->
PlusIcon/label), which skips locale prefixes when routing; replace the imported
Link from 'next/link' with the app's locale-aware Link wrapper (the custom Link
component used elsewhere) so internal links are locale-prefixed; update the
import where Link is brought into src/components/entity-components.tsx and
ensure the JSX uses that wrapper (no other JSX changes required for the
newButtonHref/onNew branch or the other call site referenced).
In `@src/components/language-toggle.tsx`:
- Line 28: Replace the hardcoded screen-reader text in the LanguageToggle
component by using the i18n/messages lookup instead of the literal "Toggle
language": locate the span with className "sr-only" in
src/components/language-toggle.tsx and render the localized string
(Common.toggleLanguage) from your translation/messages provider (e.g., useIntl,
t, or the project's i18n helper used elsewhere in the component). Then add the
key "Common.toggleLanguage" with appropriate values to both messages/en.json and
messages/vi.json so the translated label is available for English and
Vietnamese.
In `@src/middleware.ts`:
- Around line 57-70: The matcher in export const config currently excludes API
routes so the CORS/preflight branch never runs; update the config.matcher array
in middleware.ts (the export const config and its matcher) to include the
'/api/:path*' pattern (in addition to existing entries like '/' and
'/(vi|en)/:path*' and the general redirect pattern) so that API requests hit the
middleware and the Access-Control-* and preflight handling code executes.
In `@wrangler.jsonc`:
- Line 46: The wrangler.jsonc is using global binding IDs ("database_id":
"72839a05-137f-4f25-baf8-71f8c127b3c1" and KV "id":
"0c06c7bedbfe492daf7acda7dcf3e7ac") which makes all environments share
production resources; update the config to scope these bindings per environment
by moving the D1 and KV binding entries from the root into environment-specific
blocks (e.g., [env.staging], [env.production], or separate
wrangler.staging.jsonc/wrangler.production.jsonc) and set environment-specific
values for the database_id and id for each environment so dev/staging do not
point at the production IDs.
---
Nitpick comments:
In `@next.config.ts`:
- Line 16: The redirect currently hardcodes a Vietnamese locale by setting
destination: "/vi/llms", which bypasses Next.js i18n middleware; update the
redirect configuration (the object with destination: "/vi/llms" in
next.config.ts, typically returned from the redirects() export) to use
destination: "/llms" so the middleware and i18n settings can apply locale
prefixes dynamically instead of forcing "vi".
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: d0925b43-e701-43b1-b598-23739e4ba748
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (25)
messages/en.jsonmessages/vi.jsonnext.config.tspackage.jsonsrc/app/[locale]/(auth)/layout.tsxsrc/app/[locale]/(auth)/login/page.tsxsrc/app/[locale]/(auth)/signup/page.tsxsrc/app/[locale]/(dashboard)/(admin)/agents/page.tsxsrc/app/[locale]/(dashboard)/(admin)/datasources/[id]/page.tsxsrc/app/[locale]/(dashboard)/(admin)/datasources/page.tsxsrc/app/[locale]/(dashboard)/(admin)/layout.tsxsrc/app/[locale]/(dashboard)/(admin)/llms/page.tsxsrc/app/[locale]/(dashboard)/layout.tsxsrc/app/[locale]/(dashboard)/playground/page.tsxsrc/app/[locale]/globals.csssrc/app/[locale]/layout.tsxsrc/app/layout.tsxsrc/components/app-header.tsxsrc/components/app-sidebar.tsxsrc/components/entity-components.tsxsrc/components/language-toggle.tsxsrc/i18n/request.tssrc/i18n/routing.tssrc/middleware.tswrangler.jsonc
💤 Files with no reviewable changes (1)
- src/app/layout.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/components/entity-components.tsx (2)
103-105: Consider using a sentinel pattern for consistency.The string comparison
newButtonLabel === "New"is fragile—if the default ever changes, this comparison silently breaks. Other components in this file use the cleanerprop || t(key)pattern. Consider aligning for consistency:♻️ Alternative using undefined sentinel
type EntityHeaderProps = { title: string description?: string - newButtonLabel?: string + newButtonLabel?: string // undefined = use translated default disabled?: boolean isCreating?: boolean } & (...) export const EntityHeader = ({ ... - newButtonLabel = "New", + newButtonLabel, ... }: EntityHeaderProps) => { const t = useTranslations("Entity") - const label = newButtonLabel === "New" ? t("new") : newButtonLabel + const label = newButtonLabel ?? t("new")Note: This would be a minor breaking change if any caller explicitly passes
undefinedexpecting"New".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/entity-components.tsx` around lines 103 - 105, Replace the fragile string comparison for label with the sentinel pattern used elsewhere: instead of checking newButtonLabel === "New", use the prop-or-default pattern with the translation (e.g., use newButtonLabel ?? t("new") or newButtonLabel || t("new") depending on whether you want to treat empty string as a value) so the default translation from useTranslations("Entity") is used when newButtonLabel is undefined; update the assignment to label to follow this pattern (refer to newButtonLabel, t, and label).
566-566: Same fragile string comparison pattern.This mirrors the pattern in
EntityHeader. Consider usingemptyMessage ?? t("noResults")with no default param for consistency with the rest of the file.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/entity-components.tsx` at line 566, Replace the fragile string comparison in the JSX expression that currently checks emptyMessage === "No results." with a nullish coalescing pattern; update the expression around emptyMessage and t("noResults") (same area shown in EntityHeader) to use emptyMessage ?? t("noResults") and remove any hard-coded default param usage so it follows the file's existing convention of relying on t("noResults") only when emptyMessage is null/undefined.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/middleware.ts`:
- Around line 33-48: When Access-Control-Allow-Origin is set dynamically
(originAllowed), add a Vary: Origin header so caches don't serve the wrong CORS
headers: in the OPTIONS branch include 'Vary': 'Origin' in the preflightHeaders
object, and after you call response.headers.set('Access-Control-Allow-Origin',
origin) ensure you also add or append 'Vary' => 'Origin' on the response.headers
(preserving any existing Vary values rather than overwriting) using the same
headers API used elsewhere in middleware.ts.
---
Nitpick comments:
In `@src/components/entity-components.tsx`:
- Around line 103-105: Replace the fragile string comparison for label with the
sentinel pattern used elsewhere: instead of checking newButtonLabel === "New",
use the prop-or-default pattern with the translation (e.g., use newButtonLabel
?? t("new") or newButtonLabel || t("new") depending on whether you want to treat
empty string as a value) so the default translation from
useTranslations("Entity") is used when newButtonLabel is undefined; update the
assignment to label to follow this pattern (refer to newButtonLabel, t, and
label).
- Line 566: Replace the fragile string comparison in the JSX expression that
currently checks emptyMessage === "No results." with a nullish coalescing
pattern; update the expression around emptyMessage and t("noResults") (same area
shown in EntityHeader) to use emptyMessage ?? t("noResults") and remove any
hard-coded default param usage so it follows the file's existing convention of
relying on t("noResults") only when emptyMessage is null/undefined.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b8eac385-93b5-4c84-8cee-23d3a8ed5294
📒 Files selected for processing (5)
messages/en.jsonmessages/vi.jsonsrc/components/entity-components.tsxsrc/components/language-toggle.tsxsrc/middleware.ts
✅ Files skipped from review due to trivial changes (2)
- messages/vi.json
- messages/en.json
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/language-toggle.tsx
Thêm nút chuyển ngôn ngữ trên Header
URL có prefix locale: /vi/... hoặc /en/...
Dịch Sidebar, Table, Pagination, các nút chung
Mặc định: Tiếng Việt
Summary by CodeRabbit
New Features
Routing & Behavior
Chores