Skip to content

refactor: migrate account pages to client i18n - #7515

Open
c121914yu wants to merge 17 commits into
labring:mainfrom
c121914yu:codex/fix-doc-static-assets
Open

refactor: migrate account pages to client i18n#7515
c121914yu wants to merge 17 commits into
labring:mainfrom
c121914yu:codex/fix-doc-static-assets

Conversation

@c121914yu

@c121914yu c121914yu commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Migrate the account and /price flows to a stable client-side i18n architecture, while removing the obsolete promotion feature and making language persistence and request propagation resilient when browser storage is restricted.

What changed

  • Migrated the account and price page flows to the shared client-only app shell and centralized client i18n initialization.
  • Added cached, on-demand namespace loading with explicit English fallback resources, load-error handling, and a client error state instead of rendering incomplete translations.
  • Added atomic language switching: resources are loaded before committing the new language preference, and failures restore the previous language state.
  • Hardened browser language persistence:
    • Cookie is the primary store when available, with a 400-day expiry and / path.
    • Falls back to localStorage, then in-memory state when browser storage is unavailable or blocked.
    • Request headers use localStorage → memory → navigator.language.
    • Added the x-fastgpt-language header for requests when the preference is not available through a Cookie.
    • Backend locale resolution is limited to Cookie → x-fastgpt-language → en.
  • Updated shared translations and namespace resources for account, price, API key, discount coupon, and related flows.
  • Removed the obsolete promotion activity, schema, API types, frontend configuration, and unused promotion assets.
  • Removed redundant modal fallback behavior and duplicate client initialization, and qualified permission labels that were ambiguous across namespaces.
  • Updated the pro submodule to the promotion-cleanup commit.
  • Added dedicated Web tests and coverage reporting to both GitHub Actions and Forgejo workflows.

Why

The account and pricing routes previously depended on mixed SSR/client translation behavior and local fallbacks. That made route transitions, language switching, and restricted-cookie or restricted-storage environments prone to stale or incomplete translations. The new flow centralizes resource readiness and language state, propagates the effective client language to the backend, and keeps the server fallback deterministic.

Verification

  • pnpm --filter=@fastgpt/web test — 5 files, 29 tests passed.
  • pnpm --filter=@fastgpt/app exec vitest run -c vitest.config.ts test/web/common/api/request.test.ts — 26 tests passed.
  • pnpm --filter=@fastgpt/service exec vitest run -c vitest.config.ts test/common/middle/i18n.test.ts — 4 tests passed.
  • pnpm --filter=@fastgpt/app typecheck passed.
  • Prettier, ESLint, and git diff --check passed for the changed files.

CI notes

The PR has separate Web test coverage jobs in the GitHub and Forgejo workflows. At the time of this update, the existing PR checks were still running for the test and build pipelines; detect-changes, detect_changes, and test-web had already passed.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 25.17% 2261 / 8981
🔵 Statements 25.17% 2379 / 9451
🔵 Functions 21.19% 462 / 2180
🔵 Branches 20.25% 1033 / 5100
File CoverageNo changed files found.
Generated in workflow #2256 for commit 792941a by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

Admin Preview Image Ready!

ghcr.io/labring/fastgpt-pr:admin_792941ab46db8d5169e5900b5fded30d4f100739

🕒 Time: 2026-08-14 10:38:47 (UTC+8)

@c121914yu
c121914yu marked this pull request as ready for review August 13, 2026 15:12
Copilot AI lite review requested due to automatic review settings August 13, 2026 15:12
@c121914yu
c121914yu force-pushed the codex/fix-doc-static-assets branch from 1139d32 to 4ab0d50 Compare August 13, 2026 15:13

Copilot AI 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.

Pull request overview

This PR migrates the account and pricing experiences toward client-only rendering with on-demand, cached i18n namespace loading, centralizing the client i18n boot flow in @fastgpt/web and removing the legacy promotion entrypoints.

Changes:

  • Add generated dynamic JSON resource loaders + Vitest coverage in packages/web/i18n, with repo scripts to generate/check the generated file.
  • Route selected account/price pages through a client-only app shell and replace many next-i18next usages with useClientTranslation.
  • Remove the account promotion page/config and adjust i18n namespace naming (apikey, discount_coupon, price).

Reviewed changes

Copilot reviewed 145 out of 145 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
scripts/generate-i18n-resource-loaders.mjs Generates typed i18n loader map
scripts/check-i18n-resource-loaders.mjs CI-friendly loader up-to-date check
projects/marketplace/src/web/common/i18n/utils.ts Drops SSR deviceSize from translations props
projects/app/test/web/support/user/useUserStore.test.ts Reorders user fixture fields
projects/app/src/web/support/activity/promotion/api.ts Removes promotion API client
projects/app/src/web/context/ClientOnlyAppShell.tsx Client-only shell with i18n gates
projects/app/src/web/context/ClientBootLoading.tsx Client boot loading UI
projects/app/src/web/context/AppShell.tsx Extracts app shell from _app
projects/app/src/web/common/i18n/utils.ts Drops SSR deviceSize from translations props
projects/app/src/pages/price/index.tsx Client-only i18n migration for price page
projects/app/src/pages/app/detail/index.tsx Updates SSR namespaces list
projects/app/src/pages/account/usage/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/thirdParty/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/team/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/setting.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/promotion.tsx Deletes promotion page
projects/app/src/pages/account/model/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/inform.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/info/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/customDomain/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/bill/index.tsx Removes SSR props; client i18n hook
projects/app/src/pages/account/apikey.tsx Removes SSR props; relies on table i18n
projects/app/src/pages/_app.tsx Route-split client-only shell + client i18n config
projects/app/src/pageComponents/price/utils.ts Move price strings into price ns
projects/app/src/pageComponents/price/Standard.tsx Move price strings into price ns
projects/app/src/pageComponents/price/Points.tsx Move price strings into price ns
projects/app/src/pageComponents/price/FAQ.tsx Move price strings into price ns
projects/app/src/pageComponents/price/ExtraPlan.tsx Move price strings into price ns
projects/app/src/pageComponents/app/detail/Publish/index.tsx Disable SSR for API tab module
projects/app/src/pageComponents/account/usage/UsageTable.tsx Use client i18n; swap recharge modal wrapper
projects/app/src/pageComponents/account/usage/UsageRechargeModal.tsx Lazy wrapper around recharge modal
projects/app/src/pageComponents/account/usage/UsageDetail.tsx Use client i18n hook
projects/app/src/pageComponents/account/usage/DashboardChart.tsx Use client i18n hook
projects/app/src/pageComponents/account/usage/Dashboard.tsx Use client i18n hook + recharge wrapper
projects/app/src/pageComponents/account/thirdParty/WorkflowVariableModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/thirdParty/OpenAIAccountModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/TeamSelector.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/TransferOwnershipModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/PermissionManage/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/OrgManage/OrgMoveModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/OrgManage/OrgMemberManageModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/OrgManage/OrgInfoModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/OrgManage/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/MemberTable.tsx Use client i18n hook; modal sizing
projects/app/src/pageComponents/account/team/Invite/InviteModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/Invite/HandleInviteModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/Invite/CreateInvitationModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/GroupManage/index.tsx Use client i18n hook; formatting tweak
projects/app/src/pageComponents/account/team/GroupManage/GroupTransferOwnerModal.tsx Use client i18n hook; simplify pagination hook
projects/app/src/pageComponents/account/team/GroupManage/GroupManageMember.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/GroupManage/GroupInfoModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/EnterpriseAuth/useEnterpriseAuthFormFlow.ts Use client i18n hook
projects/app/src/pageComponents/account/team/EnterpriseAuth/index.tsx Use client i18n hook; type TFunction
projects/app/src/pageComponents/account/team/EnterpriseAuth/ContactBusinessModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/EditInfoModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/team/context.tsx Use client i18n hook; trim imports
projects/app/src/pageComponents/account/team/Audit/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/NotificationDetailsModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/ModelDashboard/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/ModelDashboard/DataTableComponent.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/ModelConfigTable.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/Log/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/Channel/ModelTest.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/Channel/index.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/Channel/EditChannelModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/model/AddModelBox.tsx Use client i18n hook
projects/app/src/pageComponents/account/info/UpdatePswModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/info/standardDetailModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/info/RedeemCouponModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/info/DiscountCouponsModal.tsx Use client i18n hook; move keys to new ns
projects/app/src/pageComponents/account/info/ConversionModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/customDomain/domainVerifyModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/customDomain/createModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/bill/InvoiceTable.tsx Use client i18n hook
projects/app/src/pageComponents/account/bill/InvoiceHeaderForm.tsx Use client i18n hook
projects/app/src/pageComponents/account/bill/BillTable.tsx Use client i18n hook
projects/app/src/pageComponents/account/bill/BillDetailModal.tsx Use client i18n hook; new coupon keys
projects/app/src/pageComponents/account/bill/ApplyInvoiceModal.tsx Use client i18n hook
projects/app/src/pageComponents/account/AccountContainer.tsx Remove promotion tab + use client i18n
projects/app/src/global/support/api/userRes.ts Remove unused import
projects/app/src/components/support/wallet/StandardPlanContentList.tsx Use client i18n hook; minor formatting
projects/app/src/components/support/wallet/QRCodePayModal.tsx Use client i18n hook; cast dynamic keys
projects/app/src/components/support/wallet/NotSufficientModal/index.tsx Use client i18n hook
projects/app/src/components/support/permission/ResumeInheritText/index.tsx Use client i18n hook
projects/app/src/components/support/permission/Radio/index.tsx Use client i18n hook
projects/app/src/components/support/permission/PermissionTags/index.tsx Use client i18n hook
projects/app/src/components/support/permission/MemberManager/RoleTags.tsx Use client i18n hook
projects/app/src/components/support/permission/MemberManager/RoleSelect.tsx Use client i18n hook
projects/app/src/components/support/permission/MemberManager/MemberModal.tsx Use client i18n hook
projects/app/src/components/support/permission/MemberManager/MemberListCard.tsx Use client i18n hook
projects/app/src/components/support/permission/MemberManager/context.tsx Use client i18n hook
projects/app/src/components/support/permission/IconText/index.tsx Use client i18n hook
projects/app/src/components/support/permission/DefaultPerList/index.tsx Use client i18n hook
projects/app/src/components/support/permission/ConfigPerModal/index.tsx Use client i18n hook
projects/app/src/components/support/permission/ChangeOwnerModal/index.tsx Use client i18n hook
projects/app/src/components/support/apikey/TagMultiSelect.tsx Move keys to apikey ns
projects/app/src/components/support/apikey/TagManageModal.tsx Move keys to apikey ns
projects/app/src/components/support/apikey/Table.tsx Move keys to apikey ns
projects/app/src/components/Layout/navbarPhone.tsx Removes promotion nav route
projects/app/src/components/Layout/navbar.tsx Removes promotion nav route
projects/app/src/components/core/ai/ModelTable/index.tsx Use client i18n hook
projects/app/src/components/CommunityModal/index.tsx Use client i18n hook
packages/web/vitest.config.ts Adds Vitest config for @fastgpt/web
packages/web/test/i18n/resourceLoaders.test.ts Tests generated loaders + status tracking
packages/web/test/i18n/dynamicImportBackend.test.ts Tests retry + typed errors
packages/web/package.json Adds @fastgpt/web test script
packages/web/i18n/zh-Hant/price.json Adds price namespace translations
packages/web/i18n/zh-Hant/discount_coupon.json Adds discount_coupon translations
packages/web/i18n/zh-Hant/apikey.json Adds/updates apikey translations
packages/web/i18n/zh-Hant/account.json Removes promotion label
packages/web/i18n/zh-Hant/account_usage.json Adds new usage keys
packages/web/i18n/zh-Hant/account_team.json Adds new audit keys
packages/web/i18n/zh-Hant/account_promotion.json Removes promotion namespace file
packages/web/i18n/zh-Hant/account_info.json Moves coupon-related keys out
packages/web/i18n/zh-CN/price.json Adds price namespace translations
packages/web/i18n/zh-CN/discount_coupon.json Adds discount_coupon translations
packages/web/i18n/zh-CN/apikey.json Adds/updates apikey translations
packages/web/i18n/zh-CN/account.json Removes promotion label
packages/web/i18n/zh-CN/account_promotion.json Removes promotion namespace file
packages/web/i18n/zh-CN/account_info.json Moves coupon-related keys out
packages/web/i18n/useClientTranslation.ts New client i18n translation hook
packages/web/i18n/resourceLoaders.ts Resource loader status + error tracking
packages/web/i18n/resourceLoaders.generated.ts Generated loader map
packages/web/i18n/i18next.ts Updates namespace typings + adds new namespaces
packages/web/i18n/en/price.json Adds price namespace translations
packages/web/i18n/en/discount_coupon.json Adds discount_coupon translations
packages/web/i18n/en/apikey.json Adds/updates apikey translations
packages/web/i18n/en/account.json Removes promotion label
packages/web/i18n/en/account_promotion.json Removes promotion namespace file
packages/web/i18n/en/account_info.json Moves coupon-related keys out
packages/web/i18n/dynamicImportBackend.ts Backend reading via dynamic imports + retry
packages/web/i18n/constants.ts Updates namespace list
packages/web/i18n/ClientI18nLoadError.ts Typed error for client i18n failures
packages/web/i18n/ClientI18nGate.tsx Gate for initial language/common load
packages/web/i18n/ClientI18nErrorFallback.tsx Minimal fallback UI for i18n load failures
packages/web/i18n/ClientI18nBoundary.tsx Suspense + error boundary wrapper
packages/web/i18n/clientConfig.ts next-i18next config for client backend
packages/web/hooks/useSafeTranslation.ts Refactors safe translation wrapper
packages/web/context/useSystem.tsx Centralizes system size readiness
packages/service/support/activity/promotion/schema.ts Removes outdated comment
packages/global/support/activity/type.ts Trims inline comments
packages/global/common/system/types/index.ts Removes promotion FE config flag
package.json Adds i18n loader scripts + web tests
document/middleware.ts Adjusts matcher for favicon path variants
document/app/[lang]/layout.tsx notFound() for unsupported doc locales

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 14 to 20
const ns = key.split(':')[0];
if (!I18N_NAMESPACES_MAP[ns as any]) {
return key;
}

// @ts-ignore
return originalT(key, ...args);
Comment on lines +24 to +28
const [isPc] = useMediaQuery('(min-width: 900px)', { fallback: true });
const [isSystemSizeReady, setIsSystemSizeReady] = useState(false);

useEffect(() => {
setSize(isPc ? 'pc' : 'mobile');
setIsSystemSizeReady(true);
Comment on lines +15 to +22
/**
* 在使用记录页打开充值弹窗时才加载套餐文案,避免首屏提前请求 user namespace。
*/
const UsageRechargeModalContent = (props: UsageRechargeModalProps) => {
useClientTranslation();

return <RechargeModal {...props} />;
};

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1139d32d46

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if (this.state.error === undefined) return this.props.children;
if (!isClientI18nLoadError(this.state.error)) throw this.state.error;

return <ClientI18nErrorFallback language={this.props.language} error={this.state.error} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve the previous language when a switch fails

When a user switches languages and any mounted namespace chunk fails to load, useI18nLng.onChangeLng has already persisted the target locale before awaiting changeLanguage; this boundary then replaces the page with a fallback whose only action reloads the same now-persisted failing locale. A transient chunk failure can therefore trap the user on the error screen instead of retaining the working language. Preload the target resources before persisting/switching, or roll back the i18n language and stored locale when this error is caught.

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

Build Successful - Preview fastgpt Image for this PR:

ghcr.io/labring/fastgpt-pr:fastgpt_792941ab46db8d5169e5900b5fded30d4f100739

🕒 Time: 2026-08-14 10:41:42 (UTC+8)

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants