Skip to content

feat: add Simplified Chinese (zh-CN) language support#78

Open
Leck88 wants to merge 4 commits into
Open-Dev-Society:mainfrom
Leck88:zh-i18n
Open

feat: add Simplified Chinese (zh-CN) language support#78
Leck88 wants to merge 4 commits into
Open-Dev-Society:mainfrom
Leck88:zh-i18n

Conversation

@Leck88

@Leck88 Leck88 commented May 15, 2026

Copy link
Copy Markdown

Summary

Add Simplified Chinese (zh-CN) i18n support with cookie-based locale switching.

Changes

  • Cookie-based locale detection (default: en, supports zh-CN)
  • LocaleProvider + useDictionary/useLocale hooks
  • LanguageSwitcher (Globe icon) in header
  • i18n for: NavItems, Footer, Watchlist, Alerts, About, Auth pages
  • New files: i18n/en.ts, i18n/zh-CN.ts, components/LocaleProvider.tsx, components/LanguageSwitcher.tsx, hooks/useDictionary.ts, hooks/useLocale.ts

How to test

  1. Click globe icon in header to switch between EN/中文
  2. Preference is saved in cookie
  3. All nav, footer, watchlist, alerts text should translate

Summary by CodeRabbit

  • New Features

    • Multi-language support (English + Simplified Chinese) with locale-aware pages and provider.
    • Language switcher that persists preference and updates the UI.
    • UI text (navigation, footer, search, table headings, buttons) now uses localized strings.
  • Bug Fixes / Improvements

    • App now degrades gracefully when DB/auth is unavailable.
    • Middleware surfaces resolved locale in responses for authorized requests.

Review Change Stack

@vercel

vercel Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Someone is attempting to deploy a commit to the ravixalgorithm's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 15, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds English and Chinese dictionaries and a getDictionary registry, a client LocaleContext/LocaleProvider with hooks, server RootLayout locale bootstrapping, client LanguageSwitcher/Nav/Footer localization, middleware x-locale header, graceful DB/auth startup paths, constants update, and dependency/npmrc changes.

Changes

i18n core & provider

Layer / File(s) Summary
Dictionaries registry and accessor
i18n/index.ts, i18n/en.ts, i18n/zh-CN.ts
Exports dictionaries (keys: en, zh-CN), derives Locale union, sets defaultLocale and localeNames, and adds getDictionary(locale) with fallback to defaultLocale; provides en and zhCN dictionary exports and Dictionary type.
LocaleContext and provider implementation
components/LocaleProvider.tsx, hooks/useDictionary.ts, hooks/useLocale.ts
Creates LocaleContextType and exported LocaleContext; implements LocaleProvider that manages locale and currentDictionary, refreshes dictionary via getDictionary(locale) on locale change, writes NEXT_LOCALE cookie on setLocale, and exposes hooks for components.
Server layout locale bootstrap
app/layout.tsx
Makes RootLayout async, reads NEXT_LOCALE cookie, validates against supported locales, loads dictionary via getDictionary, sets <html lang={locale}>, and wraps children with LocaleProvider (initial locale + dictionary).

Client UI localization

Layer / File(s) Summary
Language switcher UI and routing
components/LanguageSwitcher.tsx
Adds a client LanguageSwitcher that rewrites/inserts locale path segments, uses startTransition + router.push, and sets NEXT_LOCALE cookie (path /, one-year max age).
Nav and Footer dictionary wiring
components/NavItems.tsx, components/Footer.tsx
NavItems and Footer consume useDictionary() for labels (nav entries, search label, donate text, footer sections/links/copyright). Footer converted to a client component.

Middleware

Layer / File(s) Summary
Resolve NEXT_LOCALE and set response header
middleware/index.ts
Adds allowed locales and defaultLocale, reads/validates NEXT_LOCALE cookie, and sets x-locale header on NextResponse.next() for authorized requests.

DB and auth startup safety

Layer / File(s) Summary
Database connection behavior change
database/mongoose.ts
Switches dns import style; connectToDatabase() logs a warning and returns null when MONGODB_URI is missing instead of throwing.
better-auth graceful initialization
lib/better-auth/auth.ts
Adds authInitFailed flag and createMockAuth fallback; getAuth short-circuits on prior failure, wraps initialization in try/catch, logs warnings, and returns mock auth when DB init fails; env defaults for secret/baseURL added.

Constants and dependencies

Layer / File(s) Summary
Watchlist header keys
lib/constants.ts
Replaces exported WATCHLIST_TABLE_HEADER labels with WATCHLIST_TABLE_HEADER_KEYS i18n key identifiers for dictionary-based headers.
Bump inngest dependency & npm registry
package.json, .npmrc
Updates inngest from ^3.47.0 to ^4.4.0 and adds .npmrc registry entry https://registry.npmjs.org/.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (UI)
  participant LangSwitch as LanguageSwitcher
  participant Router as Next.js Router
  participant Provider as LocaleProvider
  participant Cookie as NEXT_LOCALE cookie

  User->>LangSwitch: select locale
  LangSwitch->>Router: push new pathname (with locale segment)
  LangSwitch->>Cookie: set NEXT_LOCALE (path=/, max-age=1y)
  Router->>Provider: render with new locale (via RootLayout or client state)
  Provider->>Provider: getDictionary(newLocale) and update dictionary
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰
I hop through keys and language doors,
I stash your locale in cookie stores.
When words change, I fetch the tune,
A dictionary for sun or moon.
Hooray — translations bloom soon.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the primary change: adding Simplified Chinese language support. It is specific, concise, and directly reflects the main objective of introducing zh-CN i18n support with locale switching.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/constants.ts (1)

1-6: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove NAV_ITEMS constant—it is unused.

The NAV_ITEMS export in lib/constants.ts is no longer referenced anywhere in the codebase. Since NavItems.tsx now builds navigation from dict.nav instead, this constant can be safely deleted to reduce clutter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/constants.ts` around lines 1 - 6, Remove the unused exported constant
NAV_ITEMS from the file (delete the NAV_ITEMS declaration/export), and verify
there are no remaining imports or references to NAV_ITEMS elsewhere in the
codebase (e.g., any files that might still import NAV_ITEMS); if any are found,
remove those imports/usages or update them to use dict.nav instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/layout.tsx`:
- Around line 25-26: Replace the duplicated locale definitions in app/layout.tsx
by importing the centralized constants from the i18n module: remove the local
const locales and const defaultLocale and instead import the exported symbols
(e.g., locales and defaultLocale or locales and derive default from i18n) from
i18n/index.ts (the file that defines dictionaries and exports locales), then use
those imported names in layout.tsx (referencing the existing locales and
defaultLocale identifiers in your layout component).

In `@components/LanguageSwitcher.tsx`:
- Around line 36-49: Replace the hardcoded SelectItem entries with a dynamic map
over your i18n config: import supportedLocales and localeNames from
i18n/index.ts, then inside the SelectContent iterate supportedLocales to render
a SelectItem for each locale using the locale string for the value and
localeNames[locale] (or a fallback) for the display text; keep existing
props/handlers (locale, handleLocaleChange, isPending,
SelectTrigger/SelectValue) and preserve the current className/styling on
SelectItem and SelectContent.
- Around line 21-33: The handler handleLocaleChange currently hardcodes locales,
manually mutates cookies, and does fragile path segment logic; replace this by
importing and calling setLocale from LocaleProvider (which updates state and
persists NEXT_LOCALE) and use supportedLocales from i18n to detect/validate
current locale in the path, then compute the new pathname robustly (handling
empty paths/trailing slashes) and call router.push with the updated path; remove
the direct document.cookie write and the hardcoded 'en'/'zh-CN' checks so locale
logic is centralized in setLocale/supportedLocales.

In `@components/LocaleProvider.tsx`:
- Line 35: The NEXT_LOCALE cookie assignment in LocaleProvider (document.cookie
in components/LocaleProvider.tsx) is missing a SameSite attribute; update the
cookie string in the locale setter (where document.cookie =
`NEXT_LOCALE=${newLocale}...`) to include a SameSite attribute (e.g., append
`;SameSite=Lax`) and, if you need cross-site usage, use `SameSite=None;Secure`
instead to ensure the cookie is sent securely.

In `@middleware/index.ts`:
- Around line 5-6: The locales array and defaultLocale constant are duplicated
here; remove the local definitions of locales and defaultLocale and import them
from the centralized i18n module (exported from i18n/index.ts), then update any
references in this file to use the imported symbols (locales, defaultLocale) so
the middleware reuses the single source of truth.

---

Outside diff comments:
In `@lib/constants.ts`:
- Around line 1-6: Remove the unused exported constant NAV_ITEMS from the file
(delete the NAV_ITEMS declaration/export), and verify there are no remaining
imports or references to NAV_ITEMS elsewhere in the codebase (e.g., any files
that might still import NAV_ITEMS); if any are found, remove those
imports/usages or update them to use dict.nav instead.
🪄 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: 7e7ef71d-70c7-4ef7-9214-9c54df163e14

📥 Commits

Reviewing files that changed from the base of the PR and between e068027 and 912bbdc.

📒 Files selected for processing (12)
  • app/layout.tsx
  • components/Footer.tsx
  • components/LanguageSwitcher.tsx
  • components/LocaleProvider.tsx
  • components/NavItems.tsx
  • hooks/useDictionary.ts
  • hooks/useLocale.ts
  • i18n/en.ts
  • i18n/index.ts
  • i18n/zh-CN.ts
  • lib/constants.ts
  • middleware/index.ts

Comment thread app/layout.tsx
Comment on lines +25 to +26
const locales: Locale[] = ['en', 'zh-CN'];
const defaultLocale: Locale = 'en';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Eliminate duplication: import locale constants from i18n module.

The locales array and defaultLocale are duplicated from i18n/index.ts. This violates DRY and creates a maintenance risk where the two definitions could diverge.

♻️ Proposed refactor to use centralized constants
-const locales: Locale[] = ['en', 'zh-CN'];
-const defaultLocale: Locale = 'en';
+import { defaultLocale } from '@/i18n';
+
+const locales: Locale[] = ['en', 'zh-CN']; // Note: consider exporting this from i18n/index.ts as well

Or better yet, if you export locales from i18n/index.ts:

-const locales: Locale[] = ['en', 'zh-CN'];
-const defaultLocale: Locale = 'en';
+import { defaultLocale } from '@/i18n';
+import type { Locale } from '@/i18n';
+
+// Derive locales from dictionaries keys
+const locales = Object.keys(dictionaries) as Locale[];

However, the cleanest approach is to export a locales array from i18n/index.ts:

In i18n/index.ts:

export const locales = Object.keys(dictionaries) as Locale[];

Then in layout.tsx:

-const locales: Locale[] = ['en', 'zh-CN'];
-const defaultLocale: Locale = 'en';
+import { defaultLocale, dictionaries } from '@/i18n';
+import type { Locale } from '@/i18n';
+
+const locales = Object.keys(dictionaries) as Locale[];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/layout.tsx` around lines 25 - 26, Replace the duplicated locale
definitions in app/layout.tsx by importing the centralized constants from the
i18n module: remove the local const locales and const defaultLocale and instead
import the exported symbols (e.g., locales and defaultLocale or locales and
derive default from i18n) from i18n/index.ts (the file that defines dictionaries
and exports locales), then use those imported names in layout.tsx (referencing
the existing locales and defaultLocale identifiers in your layout component).

Comment on lines +21 to +33
const handleLocaleChange = (newLocale: string) => {
startTransition(() => {
const segments = pathname.split('/');
// Remove existing locale segment if present
if (segments[1] === 'en' || segments[1] === 'zh-CN') {
segments[1] = newLocale;
} else {
segments.splice(1, 0, newLocale);
}
router.push(segments.join('/'));
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
});
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Refactor to use setLocale from LocaleProvider and eliminate hardcoded locale values.

This implementation has several maintainability concerns:

  1. Hardcoded locale values (line 25): The explicit checks for 'en' and 'zh-CN' duplicate the locale configuration that should be centralized in i18n/index.ts. When new locales are added, this code must be manually updated.

  2. Manual cookie manipulation (line 31): According to the review context, LocaleProvider already exports a setLocale function that "updates both state and persists the NEXT_LOCALE cookie with one-year max age." Manually setting the cookie here bypasses that contract and creates two separate cookie-setting paths.

  3. Fragile path manipulation (lines 23-30): The logic assumes segments[1] is always safe to access and replace, but doesn't handle edge cases like empty paths, trailing slashes, or already-localized nested routes.

♻️ Recommended refactoring approach

Import setLocale from the LocaleProvider context and supportedLocales from i18n configuration:

+import { useContext } from 'react';
+import { LocaleContext } from '@/components/LocaleProvider';
+import { supportedLocales } from '@/i18n';

Then simplify the handler to delegate locale persistence and path logic:

+const { setLocale } = useContext(LocaleContext);
+
 const handleLocaleChange = (newLocale: string) => {
   startTransition(() => {
+    setLocale(newLocale);
     const segments = pathname.split('/');
-    // Remove existing locale segment if present
-    if (segments[1] === 'en' || segments[1] === 'zh-CN') {
+    if (supportedLocales.includes(segments[1] as any)) {
       segments[1] = newLocale;
     } else {
       segments.splice(1, 0, newLocale);
     }
     router.push(segments.join('/'));
-    document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
   });
 };

This ensures a single source of truth for supported locales and consistent cookie handling.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleLocaleChange = (newLocale: string) => {
startTransition(() => {
const segments = pathname.split('/');
// Remove existing locale segment if present
if (segments[1] === 'en' || segments[1] === 'zh-CN') {
segments[1] = newLocale;
} else {
segments.splice(1, 0, newLocale);
}
router.push(segments.join('/'));
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
});
};
import { useContext } from 'react';
import { LocaleContext } from '@/components/LocaleProvider';
import { supportedLocales } from '@/i18n';
// Add this line in the component before the handleLocaleChange function:
const { setLocale } = useContext(LocaleContext);
const handleLocaleChange = (newLocale: string) => {
startTransition(() => {
setLocale(newLocale);
const segments = pathname.split('/');
if (supportedLocales.includes(segments[1] as any)) {
segments[1] = newLocale;
} else {
segments.splice(1, 0, newLocale);
}
router.push(segments.join('/'));
});
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/LanguageSwitcher.tsx` around lines 21 - 33, The handler
handleLocaleChange currently hardcodes locales, manually mutates cookies, and
does fragile path segment logic; replace this by importing and calling setLocale
from LocaleProvider (which updates state and persists NEXT_LOCALE) and use
supportedLocales from i18n to detect/validate current locale in the path, then
compute the new pathname robustly (handling empty paths/trailing slashes) and
call router.push with the updated path; remove the direct document.cookie write
and the hardcoded 'en'/'zh-CN' checks so locale logic is centralized in
setLocale/supportedLocales.

Comment on lines +36 to +49
<Select value={locale} onValueChange={handleLocaleChange} disabled={isPending}>
<SelectTrigger className="w-[130px] h-9 bg-gray-700 border-gray-600 text-gray-300 hover:bg-gray-600 hover:text-white">
<Globe className="h-4 w-4 mr-2" />
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent className="bg-gray-800 border-gray-700 text-gray-200">
<SelectItem value="en" className="hover:bg-gray-700 focus:bg-gray-700">
English
</SelectItem>
<SelectItem value="zh-CN" className="hover:bg-gray-700 focus:bg-gray-700">
简体中文
</SelectItem>
</SelectContent>
</Select>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Render locale options dynamically from i18n configuration.

The SelectItem elements hardcode both locale values ("en", "zh-CN") and display labels ("English", "简体中文"). According to the review context, i18n/index.ts exports both supportedLocales and human-readable localeNames. Hardcoding these values creates a maintenance burden when adding new locales.

♻️ Proposed fix to render options dynamically

Import the i18n configuration:

+import { supportedLocales, localeNames } from '@/i18n';

Replace the hardcoded SelectItem list with a mapped array:

 <SelectContent className="bg-gray-800 border-gray-700 text-gray-200">
-  <SelectItem value="en" className="hover:bg-gray-700 focus:bg-gray-700">
-    English
-  </SelectItem>
-  <SelectItem value="zh-CN" className="hover:bg-gray-700 focus:bg-gray-700">
-    简体中文
-  </SelectItem>
+  {supportedLocales.map((loc) => (
+    <SelectItem key={loc} value={loc} className="hover:bg-gray-700 focus:bg-gray-700">
+      {localeNames[loc]}
+    </SelectItem>
+  ))}
 </SelectContent>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Select value={locale} onValueChange={handleLocaleChange} disabled={isPending}>
<SelectTrigger className="w-[130px] h-9 bg-gray-700 border-gray-600 text-gray-300 hover:bg-gray-600 hover:text-white">
<Globe className="h-4 w-4 mr-2" />
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent className="bg-gray-800 border-gray-700 text-gray-200">
<SelectItem value="en" className="hover:bg-gray-700 focus:bg-gray-700">
English
</SelectItem>
<SelectItem value="zh-CN" className="hover:bg-gray-700 focus:bg-gray-700">
简体中文
</SelectItem>
</SelectContent>
</Select>
import { supportedLocales, localeNames } from '@/i18n';
// ... other imports and component code ...
<Select value={locale} onValueChange={handleLocaleChange} disabled={isPending}>
<SelectTrigger className="w-[130px] h-9 bg-gray-700 border-gray-600 text-gray-300 hover:bg-gray-600 hover:text-white">
<Globe className="h-4 w-4 mr-2" />
<SelectValue placeholder="Language" />
</SelectTrigger>
<SelectContent className="bg-gray-800 border-gray-700 text-gray-200">
{supportedLocales.map((loc) => (
<SelectItem key={loc} value={loc} className="hover:bg-gray-700 focus:bg-gray-700">
{localeNames[loc]}
</SelectItem>
))}
</SelectContent>
</Select>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/LanguageSwitcher.tsx` around lines 36 - 49, Replace the hardcoded
SelectItem entries with a dynamic map over your i18n config: import
supportedLocales and localeNames from i18n/index.ts, then inside the
SelectContent iterate supportedLocales to render a SelectItem for each locale
using the locale string for the value and localeNames[locale] (or a fallback)
for the display text; keep existing props/handlers (locale, handleLocaleChange,
isPending, SelectTrigger/SelectValue) and preserve the current className/styling
on SelectItem and SelectContent.


const changeLocale = (newLocale: Locale) => {
setLocale(newLocale);
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add SameSite attribute to cookie for security.

The NEXT_LOCALE cookie should include a SameSite attribute to protect against CSRF attacks. Consider adding at minimum SameSite=Lax.

🔒 Proposed fix to add SameSite attribute
-        document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
+        document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000;SameSite=Lax`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000`;
document.cookie = `NEXT_LOCALE=${newLocale};path=/;max-age=31536000;SameSite=Lax`;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/LocaleProvider.tsx` at line 35, The NEXT_LOCALE cookie assignment
in LocaleProvider (document.cookie in components/LocaleProvider.tsx) is missing
a SameSite attribute; update the cookie string in the locale setter (where
document.cookie = `NEXT_LOCALE=${newLocale}...`) to include a SameSite attribute
(e.g., append `;SameSite=Lax`) and, if you need cross-site usage, use
`SameSite=None;Secure` instead to ensure the cookie is sent securely.

Comment thread middleware/index.ts
Comment on lines +5 to +6
const locales: Locale[] = ['en', 'zh-CN'];
const defaultLocale: Locale = 'en';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Eliminate duplication: import locale constants from i18n module.

The locales array and defaultLocale are duplicated from i18n/index.ts. This is the same duplication issue as in app/layout.tsx and violates DRY. Three copies of these constants now exist across the codebase.

♻️ Proposed refactor to use centralized constants
+import { defaultLocale, dictionaries } from '@/i18n';
 import type { Locale } from '@/i18n';
 
-const locales: Locale[] = ['en', 'zh-CN'];
-const defaultLocale: Locale = 'en';
+const locales = Object.keys(dictionaries) as Locale[];

Alternatively, export locales from i18n/index.ts and import it here.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const locales: Locale[] = ['en', 'zh-CN'];
const defaultLocale: Locale = 'en';
import { defaultLocale, dictionaries } from '@/i18n';
import type { Locale } from '@/i18n';
const locales = Object.keys(dictionaries) as Locale[];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@middleware/index.ts` around lines 5 - 6, The locales array and defaultLocale
constant are duplicated here; remove the local definitions of locales and
defaultLocale and import them from the centralized i18n module (exported from
i18n/index.ts), then update any references in this file to use the imported
symbols (locales, defaultLocale) so the middleware reuses the single source of
truth.

@Leck88 Leck88 force-pushed the zh-i18n branch 2 times, most recently from 3c99daf to 610d3de Compare May 15, 2026 05:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
database/mongoose.ts (1)

32-35: ⚖️ Poor tradeoff

Consider consistency in error-handling strategy.

The function now returns null with a warning when MONGODB_URI is missing (lines 32-34), but still throws when mongoose.connect() fails (line 48). This creates two different error-handling patterns for connection failures:

  • Missing URI → returns null (soft fail)
  • Connection failure → throws (hard fail)

This mixed approach may confuse consumers. Consider whether both cases should throw, or both should return null, depending on whether the application should fail fast or gracefully degrade when MongoDB is unavailable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/mongoose.ts` around lines 32 - 35, The code currently returns null
when MONGODB_URI is missing but throws on mongoose.connect failure; pick one
consistent strategy and implement it: either (A) make both soft-fail by changing
the mongoose.connect error path to catch the error and return null (wrap the
await mongoose.connect(...) in try/catch and return null on failure), or (B)
make both hard-fail by replacing the console.warn + return null when MONGODB_URI
is falsy with throwing a clear Error (e.g., `throw new Error("MONGODB_URI is not
set")`) so the function consistently throws; update calls that expect the
function’s result accordingly. Ensure you modify the code around the MONGODB_URI
check and the await mongoose.connect(...) call to reflect the chosen approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@database/mongoose.ts`:
- Around line 31-35: connectToDatabase should declare an explicit return type
(e.g., Promise<mongoose.Connection | null> or Promise<YourDbClientType | null>)
and consistently return that type when MONGODB_URI is missing; update the
signature of connectToDatabase to reflect Promise<... | null>. Then update every
consumer that assumes a non-null result—specifically any code that uses the
returned value to access .connection.db or uses it without a null-check—to
handle the null case: either guard with if (!db) { throw/new error/early-return
} or add proper conditional logic before accessing .connection.db; ensure call
sites that assign the result to a variable check for null before property access
and adjust types accordingly.

In `@lib/better-auth/auth.ts`:
- Around line 20-21: The code uses mongoose.connection.db (const db =
mongoose.connection; const database = db.db) without guarding that .db is
initialized; update the logic in the connectToDatabase / auth initialization to
check that mongoose.connection.db is present before using it (e.g., if
(!mongoose.connection || !mongoose.connection.db) throw or return a clear error,
or wait/retry until mongoose.connection.db is set) and ensure the adapter
receives a valid database object; reference the variables db and database and
the connectToDatabase flow when adding this defensive validation.

---

Nitpick comments:
In `@database/mongoose.ts`:
- Around line 32-35: The code currently returns null when MONGODB_URI is missing
but throws on mongoose.connect failure; pick one consistent strategy and
implement it: either (A) make both soft-fail by changing the mongoose.connect
error path to catch the error and return null (wrap the await
mongoose.connect(...) in try/catch and return null on failure), or (B) make both
hard-fail by replacing the console.warn + return null when MONGODB_URI is falsy
with throwing a clear Error (e.g., `throw new Error("MONGODB_URI is not set")`)
so the function consistently throws; update calls that expect the function’s
result accordingly. Ensure you modify the code around the MONGODB_URI check and
the await mongoose.connect(...) call to reflect the chosen approach.
🪄 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: 730f8f9e-61cb-4257-b5b6-654d4a6d0ff9

📥 Commits

Reviewing files that changed from the base of the PR and between 912bbdc and 3c99daf.

📒 Files selected for processing (14)
  • app/layout.tsx
  • components/Footer.tsx
  • components/LanguageSwitcher.tsx
  • components/LocaleProvider.tsx
  • components/NavItems.tsx
  • database/mongoose.ts
  • hooks/useDictionary.ts
  • hooks/useLocale.ts
  • i18n/en.ts
  • i18n/index.ts
  • i18n/zh-CN.ts
  • lib/better-auth/auth.ts
  • lib/constants.ts
  • middleware/index.ts
✅ Files skipped from review due to trivial changes (1)
  • i18n/zh-CN.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • hooks/useDictionary.ts
  • hooks/useLocale.ts
  • i18n/index.ts
  • components/LanguageSwitcher.tsx
  • lib/constants.ts
  • i18n/en.ts
  • app/layout.tsx
  • components/LocaleProvider.tsx
  • middleware/index.ts
  • components/Footer.tsx
  • components/NavItems.tsx

Comment thread database/mongoose.ts
Comment on lines 31 to 35
export const connectToDatabase = async () => {
if (!MONGODB_URI) {
throw new Error("MongoDB URI is missing");
console.warn("MongoDB URI is missing — skipping database connection");
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find all consumers of connectToDatabase to verify they handle null

# Search for imports and usage of connectToDatabase
rg -n "connectToDatabase" --type ts --type tsx -C 3

Repository: Open-Dev-Society/OpenStock

Length of output: 98


🏁 Script executed:

# First, let's examine the mongoose.ts file to see the actual function signature and implementation
cat -n database/mongoose.ts

Repository: Open-Dev-Society/OpenStock

Length of output: 1786


🏁 Script executed:

# Search for connectToDatabase usage with corrected file type (remove tsx)
rg -n "connectToDatabase" --type ts -C 3

Repository: Open-Dev-Society/OpenStock

Length of output: 11379


Add explicit return type and fix consumers to handle null return value.

The function signature lacks an explicit return type but can return null when MONGODB_URI is missing (line 34). This creates a type safety gap where consumers might not handle the null case, leading to potential runtime errors.

Update the function signature:

Return type fix
-export const connectToDatabase = async () => {
+export const connectToDatabase = async (): Promise<typeof mongoose | null> => {

Critical: Multiple consumers do not check for null before using the return value:

  • scripts/test-db.ts:5, lib/inngest/functions.ts:214, lib/inngest/functions.ts:278, lib/actions/watchlist.actions.ts:11, lib/actions/watchlist.actions.ts:35, lib/actions/watchlist.actions.ts:48, lib/actions/watchlist.actions.ts:60, lib/actions/alert.actions.ts:15, lib/actions/alert.actions.ts:32, lib/actions/alert.actions.ts:44, lib/actions/alert.actions.ts:57 call it without null checks
  • lib/inngest/functions.ts:302, lib/inngest/functions.ts:340, lib/actions/watchlist.actions.ts:75, lib/actions/user.actions.ts:7, lib/actions/auth.actions.ts:41 assign the result to a variable and access .connection.db without checking if the returned value is null first

Only lib/better-auth/auth.ts:16-18 correctly checks for null and throws an appropriate error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/mongoose.ts` around lines 31 - 35, connectToDatabase should declare
an explicit return type (e.g., Promise<mongoose.Connection | null> or
Promise<YourDbClientType | null>) and consistently return that type when
MONGODB_URI is missing; update the signature of connectToDatabase to reflect
Promise<... | null>. Then update every consumer that assumes a non-null
result—specifically any code that uses the returned value to access
.connection.db or uses it without a null-check—to handle the null case: either
guard with if (!db) { throw/new error/early-return } or add proper conditional
logic before accessing .connection.db; ensure call sites that assign the result
to a variable check for null before property access and adjust types
accordingly.

Comment thread lib/better-auth/auth.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/better-auth/auth.ts`:
- Around line 22-24: The code currently sets authInitFailed = true and
permanently short-circuits to createMockAuth() (seen where authInitFailed is
read and where it is set around lines 22 and 63-66), which prevents recovery
from transient MongoDB outages; change this to a retry/cooldown strategy: when
initialization fails, do not permanently set a blocking flag—instead schedule
retries with exponential backoff (or set a timestamp/until value) and return the
mock only temporarily while a background retry attempts to re-run the real
initialization (call the same init function that previously set authInitFailed)
and clear the failure state on success; ensure both the early-return check
(authInitFailed read) and the failure path (where authInitFailed is assigned)
are updated so the code uses a time-based/backoff retry policy rather than an
irreversible boolean lockout.
- Around line 11-15: createMockAuth currently returns null which causes unsafe
null dereferences; replace it with a deterministic "unavailable" auth object
(implementing the same interface used by real auth) that provides safe,
predictable fallbacks (e.g., methods like authenticate, getUser, verifyToken
return rejected Promises or explicit errors / no-op safe values) so callers
never receive null and TypeScript type-safety is preserved; update
createMockAuth to construct and return that object instead of null and ensure
its shape matches the real auth type/signature.
- Around line 40-41: Replace the permissive fallbacks for the BetterAuth
configuration so production never uses predictable defaults: check
process.env.NODE_ENV (or equivalent environment flag) and if in production,
validate that process.env.BETTER_AUTH_SECRET and process.env.BETTER_AUTH_URL are
present and throw a clear error (including which variable is missing) instead of
using "dev-secret-change-in-production" or "http://localhost:3000"; keep the
existing fallbacks only for non-production (development/test) runs and update
the error message to reference the config keys used in the auth config object
(secret and baseURL) so callers can fix environment setup quickly.
🪄 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: 08aff3fb-c251-4e72-a9c4-c4ded1614963

📥 Commits

Reviewing files that changed from the base of the PR and between 3c99daf and 610d3de.

📒 Files selected for processing (14)
  • app/layout.tsx
  • components/Footer.tsx
  • components/LanguageSwitcher.tsx
  • components/LocaleProvider.tsx
  • components/NavItems.tsx
  • database/mongoose.ts
  • hooks/useDictionary.ts
  • hooks/useLocale.ts
  • i18n/en.ts
  • i18n/index.ts
  • i18n/zh-CN.ts
  • lib/better-auth/auth.ts
  • lib/constants.ts
  • middleware/index.ts
✅ Files skipped from review due to trivial changes (1)
  • i18n/en.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • hooks/useLocale.ts
  • hooks/useDictionary.ts
  • i18n/zh-CN.ts
  • lib/constants.ts
  • i18n/index.ts
  • database/mongoose.ts
  • middleware/index.ts
  • components/NavItems.tsx
  • components/Footer.tsx
  • app/layout.tsx
  • components/LanguageSwitcher.tsx
  • components/LocaleProvider.tsx

Comment thread lib/better-auth/auth.ts
Comment on lines +11 to +15
const createMockAuth = () => {
// Return a minimal mock so the module can load without MongoDB
// All auth operations will fail gracefully at runtime
return null as any;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

createMockAuth returns null, so fallback is not actually safe.

Line 14 (null as any) turns failures into downstream null dereferences and drops type safety.

🔧 Suggested fix (deterministic unavailable-auth object)
 const createMockAuth = () => {
-    // Return a minimal mock so the module can load without MongoDB
-    // All auth operations will fail gracefully at runtime
-    return null as any;
+    // Return a deterministic placeholder that fails with a clear error
+    return new Proxy(
+        {},
+        {
+            get() {
+                throw new Error("Auth is unavailable: MongoDB initialization failed");
+            },
+        },
+    ) as ReturnType<typeof betterAuth>;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const createMockAuth = () => {
// Return a minimal mock so the module can load without MongoDB
// All auth operations will fail gracefully at runtime
return null as any;
};
const createMockAuth = () => {
// Return a deterministic placeholder that fails with a clear error
return new Proxy(
{},
{
get() {
throw new Error("Auth is unavailable: MongoDB initialization failed");
},
},
) as ReturnType<typeof betterAuth>;
};
🧰 Tools
🪛 ESLint

[error] 14-14: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/better-auth/auth.ts` around lines 11 - 15, createMockAuth currently
returns null which causes unsafe null dereferences; replace it with a
deterministic "unavailable" auth object (implementing the same interface used by
real auth) that provides safe, predictable fallbacks (e.g., methods like
authenticate, getUser, verifyToken return rejected Promises or explicit errors /
no-op safe values) so callers never receive null and TypeScript type-safety is
preserved; update createMockAuth to construct and return that object instead of
null and ensure its shape matches the real auth type/signature.

Comment thread lib/better-auth/auth.ts
Comment on lines +22 to 24
if (authInitFailed) {
return createMockAuth();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Transient MongoDB failures permanently disable auth initialization.

Line 22 short-circuits forever once Line 65 sets authInitFailed = true, so a temporary startup outage requires a process restart to recover.

🔧 Suggested fix (retry after cooldown instead of permanent lockout)
-let authInitFailed = false;
+let lastAuthInitFailureAt = 0;
+const AUTH_RETRY_COOLDOWN_MS = 30_000;

@@
-    if (authInitFailed) {
+    if (
+        lastAuthInitFailureAt &&
+        Date.now() - lastAuthInitFailureAt < AUTH_RETRY_COOLDOWN_MS
+    ) {
         return createMockAuth();
     }

@@
-        return authInstance;
+        lastAuthInitFailureAt = 0;
+        return authInstance;
     } catch (err) {
         console.warn("[Auth] MongoDB not available, using mock auth:", err);
-        authInitFailed = true;
+        lastAuthInitFailureAt = Date.now();
         return createMockAuth();
     }

Also applies to: 63-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/better-auth/auth.ts` around lines 22 - 24, The code currently sets
authInitFailed = true and permanently short-circuits to createMockAuth() (seen
where authInitFailed is read and where it is set around lines 22 and 63-66),
which prevents recovery from transient MongoDB outages; change this to a
retry/cooldown strategy: when initialization fails, do not permanently set a
blocking flag—instead schedule retries with exponential backoff (or set a
timestamp/until value) and return the mock only temporarily while a background
retry attempts to re-run the real initialization (call the same init function
that previously set authInitFailed) and clear the failure state on success;
ensure both the early-return check (authInitFailed read) and the failure path
(where authInitFailed is assigned) are updated so the code uses a
time-based/backoff retry policy rather than an irreversible boolean lockout.

Comment thread lib/better-auth/auth.ts
Comment on lines +40 to +41
secret: process.env.BETTER_AUTH_SECRET || "dev-secret-change-in-production",
baseURL: process.env.BETTER_AUTH_URL || "http://localhost:3000",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not allow weak auth env fallbacks in production.

Line 40 falls back to a predictable secret and Line 41 to localhost. In production this can weaken session/token security and generate invalid callback/reset URLs.

🔧 Suggested fix (fail fast in production if env is missing)
+const isProd = process.env.NODE_ENV === "production";
+const authSecret = process.env.BETTER_AUTH_SECRET;
+const authBaseURL = process.env.BETTER_AUTH_URL;
+
+if (isProd && (!authSecret || !authBaseURL)) {
+    throw new Error("BETTER_AUTH_SECRET and BETTER_AUTH_URL are required in production");
+}
+
 authInstance = betterAuth({
     database: mongodbAdapter(database),
-    secret: process.env.BETTER_AUTH_SECRET || "dev-secret-change-in-production",
-    baseURL: process.env.BETTER_AUTH_URL || "http://localhost:3000",
+    secret: authSecret ?? "dev-secret-change-in-production",
+    baseURL: authBaseURL ?? "http://localhost:3000",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/better-auth/auth.ts` around lines 40 - 41, Replace the permissive
fallbacks for the BetterAuth configuration so production never uses predictable
defaults: check process.env.NODE_ENV (or equivalent environment flag) and if in
production, validate that process.env.BETTER_AUTH_SECRET and
process.env.BETTER_AUTH_URL are present and throw a clear error (including which
variable is missing) instead of using "dev-secret-change-in-production" or
"http://localhost:3000"; keep the existing fallbacks only for non-production
(development/test) runs and update the error message to reference the config
keys used in the auth config object (secret and baseURL) so callers can fix
environment setup quickly.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 (2)
lib/better-auth/auth.ts (2)

40-41: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail fast on missing auth config in production.

These fallbacks are fine for local development, but in production they weaken token/session security and can generate invalid reset/callback URLs. Keep the defaults only outside production and throw if BETTER_AUTH_SECRET or BETTER_AUTH_URL is missing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/better-auth/auth.ts` around lines 40 - 41, The current assignment of
secret and baseURL in auth.ts uses unsafe defaults (secret:
process.env.BETTER_AUTH_SECRET || "dev-secret-change-in-production", baseURL:
process.env.BETTER_AUTH_URL || "http://localhost:3000"); change this so that in
non-production (NODE_ENV !== "production") the existing defaults remain, but
when NODE_ENV === "production" the code throws a clear error if
BETTER_AUTH_SECRET or BETTER_AUTH_URL is missing; locate the secret and baseURL
configuration (the secret and baseURL fields) and replace the simple ||
fallbacks with explicit checks that throw descriptive errors in production while
keeping development defaults otherwise.

9-15: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Startup failures still collapse auth into a permanent null fallback.

Once Line 65 sets authInitFailed, every later getAuth() call short-circuits to createMockAuth(), and that mock is still null as any. A transient MongoDB outage therefore becomes a permanent auth outage until restart, with downstream null dereferences hidden by the declared return type.

Also applies to: 22-24, 63-66

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/better-auth/auth.ts` around lines 9 - 15, authInitFailed currently causes
getAuth() to always return createMockAuth() which is implemented as null,
producing permanent null fallbacks; change createMockAuth() to return a minimal
safe stub object (implementing the auth API used elsewhere) that throws clear
runtime errors instead of null, and remove/avoid making authInitFailed a
permanent short‑circuit: either only set it for the current init attempt or
remove the global short‑circuit and let getAuth()/initAuth() retry
initialization on subsequent calls so transient Mongo outages recover; update
references to authInitFailed, createMockAuth, and getAuth to use the safe stub
and retry behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/LocaleProvider.tsx`:
- Around line 25-31: LocaleProvider currently seeds state from props once, so if
parent updates initialLocale or dictionary later the provider stays stale; add
an effect that watches initialLocale and dictionary and calls
setLocale(initialLocale) and setCurrentDictionary(dictionary ||
getDictionary(initialLocale)) (or update currentDictionary via getDictionary
when only initialLocale changes) so the component syncs to prop changes; update
the existing useEffect usages (the one that calls getDictionary(locale)) to
coexist with this prop-sync effect and reference LocaleProvider, initialLocale,
dictionary, setLocale, setCurrentDictionary, and getDictionary when making the
changes.

---

Duplicate comments:
In `@lib/better-auth/auth.ts`:
- Around line 40-41: The current assignment of secret and baseURL in auth.ts
uses unsafe defaults (secret: process.env.BETTER_AUTH_SECRET ||
"dev-secret-change-in-production", baseURL: process.env.BETTER_AUTH_URL ||
"http://localhost:3000"); change this so that in non-production (NODE_ENV !==
"production") the existing defaults remain, but when NODE_ENV === "production"
the code throws a clear error if BETTER_AUTH_SECRET or BETTER_AUTH_URL is
missing; locate the secret and baseURL configuration (the secret and baseURL
fields) and replace the simple || fallbacks with explicit checks that throw
descriptive errors in production while keeping development defaults otherwise.
- Around line 9-15: authInitFailed currently causes getAuth() to always return
createMockAuth() which is implemented as null, producing permanent null
fallbacks; change createMockAuth() to return a minimal safe stub object
(implementing the auth API used elsewhere) that throws clear runtime errors
instead of null, and remove/avoid making authInitFailed a permanent
short‑circuit: either only set it for the current init attempt or remove the
global short‑circuit and let getAuth()/initAuth() retry initialization on
subsequent calls so transient Mongo outages recover; update references to
authInitFailed, createMockAuth, and getAuth to use the safe stub and retry
behavior.
🪄 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: 12445659-3b8b-4ffd-aec9-8fed57bc34c5

📥 Commits

Reviewing files that changed from the base of the PR and between 610d3de and d54232c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • app/layout.tsx
  • components/Footer.tsx
  • components/LanguageSwitcher.tsx
  • components/LocaleProvider.tsx
  • components/NavItems.tsx
  • database/mongoose.ts
  • hooks/useDictionary.ts
  • hooks/useLocale.ts
  • i18n/en.ts
  • i18n/index.ts
  • i18n/zh-CN.ts
  • lib/better-auth/auth.ts
  • lib/constants.ts
  • middleware/index.ts
  • package.json
✅ Files skipped from review due to trivial changes (3)
  • hooks/useLocale.ts
  • i18n/zh-CN.ts
  • i18n/en.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • middleware/index.ts
  • hooks/useDictionary.ts
  • lib/constants.ts
  • components/LanguageSwitcher.tsx
  • components/NavItems.tsx
  • components/Footer.tsx
  • app/layout.tsx
  • database/mongoose.ts

Comment on lines +25 to +31
export function LocaleProvider({ children, locale: initialLocale, dictionary }: LocaleProviderProps) {
const [locale, setLocale] = useState<Locale>(initialLocale);
const [currentDictionary, setCurrentDictionary] = useState<Dictionary>(dictionary);

useEffect(() => {
setCurrentDictionary(getDictionary(locale));
}, [locale]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sync provider state when locale props change after mount.

useState(initialLocale) and useState(dictionary) only read props once. If parent props change later, provider state can become stale and show the wrong language until a manual toggle.

Proposed fix
 export function LocaleProvider({ children, locale: initialLocale, dictionary }: LocaleProviderProps) {
     const [locale, setLocale] = useState<Locale>(initialLocale);
     const [currentDictionary, setCurrentDictionary] = useState<Dictionary>(dictionary);

+    useEffect(() => {
+        setLocale(initialLocale);
+        setCurrentDictionary(dictionary);
+    }, [initialLocale, dictionary]);
+
     useEffect(() => {
         setCurrentDictionary(getDictionary(locale));
     }, [locale]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/LocaleProvider.tsx` around lines 25 - 31, LocaleProvider currently
seeds state from props once, so if parent updates initialLocale or dictionary
later the provider stays stale; add an effect that watches initialLocale and
dictionary and calls setLocale(initialLocale) and
setCurrentDictionary(dictionary || getDictionary(initialLocale)) (or update
currentDictionary via getDictionary when only initialLocale changes) so the
component syncs to prop changes; update the existing useEffect usages (the one
that calls getDictionary(locale)) to coexist with this prop-sync effect and
reference LocaleProvider, initialLocale, dictionary, setLocale,
setCurrentDictionary, and getDictionary when making the changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant