Skip to content

refactor(i18n): migrate from react-i18next to next-intl and consolidate dictionary files#16

Closed
fishman wants to merge 172 commits into
dynamia-ai:mainfrom
fishman:rebuild
Closed

refactor(i18n): migrate from react-i18next to next-intl and consolidate dictionary files#16
fishman wants to merge 172 commits into
dynamia-ai:mainfrom
fishman:rebuild

Conversation

@fishman

@fishman fishman commented May 27, 2026

Copy link
Copy Markdown
Contributor
  • Move translation JSON files from src/i18n/locales/ to top-level dictionary/ directory
  • Replace react-i18next with next-intl across all components and pages
  • Add new site metadata, SEO, blogUI, and Site sections to dictionary files
  • Remove duplicated zh/ route pages in favor of locale-based routing via next-intl middleware
  • Update next.config.mjsnext.config.ts and switch to next-intl plugin
  • Add new UI components (LanguageSwitcher, ModeToggle, shadcn primitives)
  • Remove deprecated I18nProvider, ThemeProvider, and unused API routes
  • Update package.json: swap i18next/react-i18next for next-intl, upgrade Next.js to 15.5, add shadcn dependencies
  • Adjust header navigation labels and logo paths to use i18n dictionary
  • Refactor structured data helpers to be locale-aware with schema-dts
  • Add sitemap.ts, robots.txt, and Google site verification file

@vercel

vercel Bot commented May 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
website Ready Ready Preview, Comment Jun 4, 2026 10:25am

@coderabbitai

coderabbitai Bot commented May 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 163 files, which is 13 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f906a9b5-98f4-439b-b51e-7bab6b13de1a

📥 Commits

Reviewing files that changed from the base of the PR and between 0bfd6ef and 290e66c.

⛔ Files ignored due to path filters (137)
  • package-lock.json is excluded by !**/package-lock.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • public/creators-of-hami.svg is excluded by !**/*.svg
  • public/dynamia-logo-white.svg is excluded by !**/*.svg
  • public/dynamia-logo-zh-white.svg is excluded by !**/*.svg
  • public/dynamia-logo-zh.svg is excluded by !**/*.svg
  • public/dynamia-logo.svg is excluded by !**/*.svg
  • public/favicon.ico is excluded by !**/*.ico
  • public/icons/chart-line.svg is excluded by !**/*.svg
  • public/images/blog/blog-cover-background.jpg is excluded by !**/*.jpg
  • public/images/blog/blog-cover-background.png is excluded by !**/*.png
  • public/images/blog/dynamia-and-hami-at-kubecon-eu-2026/hami-booth.png is excluded by !**/*.png
  • public/images/blog/dynamia-and-hami-at-kubecon-eu-2026/kubecon-eu-2026.png is excluded by !**/*.png
  • public/images/blog/dynamia-copu-2026-04-14/group-photo.jpg is excluded by !**/*.jpg
  • public/images/blog/dynamia-copu-2026-04-14/hami-architecture.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/dra-request-flow.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/ecosystem-overview.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f1.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f2.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f3.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f4.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f5.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/f6.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/heterogeneous-gpu-ecosystem.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/keyword-cloud.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/kueue-hami-integration.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/leader-election-architecture.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/meetup-beijing.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/meetup-shanghai.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/mock-device-plugin-workflow.png is excluded by !**/*.png
  • public/images/blog/hami-2.8-deep-dive/roadmap-v2.8-to-v2.9.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/ascend-config.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/ascend-soft-partition-flow.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/ascend-soft-partition-steps.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/ascend-usage.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/cover.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/hami-core-optimization.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/hami-dra-deploy.png is excluded by !**/*.png
  • public/images/blog/hami-2.9-webinar-recap/join-community.jpg is excluded by !**/*.jpg
  • public/images/blog/hami-2025-recap/ecosystem.png is excluded by !**/*.png
  • public/images/blog/hami-2025-recap/hami-2025.png is excluded by !**/*.png
  • public/images/blog/hami-2025-recap/kubecon-eu-2026.png is excluded by !**/*.png
  • public/images/blog/hami-meetup-shenzhen-recap/shenzhen-meetup-qrcode.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/image-1.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/image-2.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/image-3.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/image.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/qa-session.jpg is excluded by !**/*.jpg
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/slide_02.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/slide_04.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/slide_05.png is excluded by !**/*.png
  • public/images/blog/hami-sf-tech-gpu-pooling-chenjunchao/speaker-portrait.jpg is excluded by !**/*.jpg
  • public/images/blog/hami-v29-deep-dive/dra-device-plugin-comparison-en.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/dra-device-plugin-comparison.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/hami-dra-flow-en.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/hami-dra-flow.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/hami-webui.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/livestream-qr-code.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/webhook-quota-en.png is excluded by !**/*.png
  • public/images/blog/hami-v29-deep-dive/webhook-quota.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/ascend-910c-partitioning.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/dra-api-challenges.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/hami-dra-lightweight.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/heterogeneous-compute-mainstream.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/kai-scheduler-isolation.png is excluded by !**/*.png
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/qa-session.jpg is excluded by !**/*.jpg
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/speaker-portrait.jpg is excluded by !**/*.jpg
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/volcano-vgpu-upgrade.png is excluded by !**/*.png
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/architecture-diagram-en.svg is excluded by !**/*.svg
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/architecture-diagram-zh.svg is excluded by !**/*.svg
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/ke.png is excluded by !**/*.png
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/solution-diagram-en.svg is excluded by !**/*.svg
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/solution-diagram-zh.svg is excluded by !**/*.svg
  • public/images/blog/keith-chan-ai-infrastructure-cloud-native/cncf-survey-66-percent.png is excluded by !**/*.png
  • public/images/blog/keith-chan-ai-infrastructure-cloud-native/hami-cncf-case-studies.png is excluded by !**/*.png
  • public/images/blog/keith-chan-ai-infrastructure-cloud-native/keith-chan-portrait.jpg is excluded by !**/*.jpg
  • public/images/blog/keith-chan-ai-infrastructure-cloud-native/keith-chan-speaking.jpg is excluded by !**/*.jpg
  • public/images/blog/keith-chan-ai-infrastructure-cloud-native/kubecon-shanghai-2026.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/booth-crowd.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/cncf-toc-redhat-vllm.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/cto-maintainer-summit.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/indian-contributors.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/k8s-gpu-control-plane.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/keynote-hosts.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/keynote-live-demo.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/keynote-stage.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/landscape-mention.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/limengxuan-hami-talk.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/limengxuan-reza-demo.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/reza-ai-native-summit.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/reza-panel-discussion.png is excluded by !**/*.png
  • public/images/blog/kubecon-eu-2026-hami-recap/tag-workshop.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/team-photo.jpg is excluded by !**/*.jpg
  • public/images/blog/kubecon-eu-2026-hami-recap/zhangxiao-gpu-sharing.png is excluded by !**/*.png
  • public/images/blog/nio-hami-gpu-sharing/resource-management-chart.png is excluded by !**/*.png
  • public/images/blog/opencsg-dynamia-partnership/f1.png is excluded by !**/*.png
  • public/images/blog/opencsg-dynamia-partnership/f2.png is excluded by !**/*.png
  • public/images/blog/opencsg-dynamia-partnership/f3.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/architecture-overview.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/community-contribution.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/jiahaojie.jpg is excluded by !**/*.jpg
  • public/images/blog/sangfor-ai-computing-gateway/scheduling-topology.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/smart-routing.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/vgpu-splitting.png is excluded by !**/*.png
  • public/images/blog/sangfor-ai-computing-gateway/volcano-hami-scheduling.png is excluded by !**/*.png
  • public/images/blog/snow-corp-cncf-case-study/architecture-overview.png is excluded by !**/*.png
  • public/images/blog/snow-corp-cncf-case-study/cost-savings-chart.png is excluded by !**/*.png
  • public/images/blog/snow-corp-cncf-case-study/ghibli-filter-traffic.png is excluded by !**/*.png
  • public/images/blog/snow-corp-cncf-case-study/keda-autoscaling-arch.png is excluded by !**/*.png
  • public/images/blog/snow-corp-cncf-case-study/train-to-inference-flow.png is excluded by !**/*.png
  • public/images/case-studies/icons/beike.png is excluded by !**/*.png
  • public/images/case-studies/icons/daocloud.svg is excluded by !**/*.svg
  • public/images/case-studies/icons/nio.svg is excluded by !**/*.svg
  • public/images/case-studies/icons/prep-logo.svg is excluded by !**/*.svg
  • public/images/case-studies/icons/sf-tech.svg is excluded by !**/*.svg
  • public/images/case-studies/icons/snow-corp.jpg is excluded by !**/*.jpg
  • public/images/cnai.svg is excluded by !**/*.svg
  • public/images/cncf.svg is excluded by !**/*.svg
  • public/images/enterprise-install/hami-ai-platform/create-workload-en.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/create-workload-zh.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-detail-en-2.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-detail-en.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-detail-zh-2.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-detail-zh.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-list-en.png is excluded by !**/*.png
  • public/images/enterprise-install/hami-ai-platform/workload-list-zh.png is excluded by !**/*.png
  • public/images/features/feature2.png is excluded by !**/*.png
  • public/images/features/feature2.svg is excluded by !**/*.svg
  • public/images/features/feature5.svg is excluded by !**/*.svg
  • public/images/koordinator.png is excluded by !**/*.png
  • public/images/products/hami-ai-platform.png is excluded by !**/*.png
  • public/images/qrcode.jpg is excluded by !**/*.jpg
  • public/images/solutions/icons/prep-logo.svg is excluded by !**/*.svg
  • public/images/videos/default-cover-en.png is excluded by !**/*.png
  • public/images/videos/default-cover.png is excluded by !**/*.png
  • public/logos/opencsg.svg is excluded by !**/*.svg
  • public/sf-tech.svg is excluded by !**/*.svg
📒 Files selected for processing (163)
  • .gitignore
  • .markdownlint.json
  • AGENTS.md
  • COLOR_SYSTEM.md
  • Makefile
  • components.json
  • dictionary/de.json
  • dictionary/en.json
  • dictionary/zh.json
  • eslint.config.mjs
  • global.d.ts
  • next-env.d.ts
  • next-sitemap.config.js
  • next.config.mjs
  • next.config.ts
  • package.json
  • public/images/blog/boardware-hami-gpu-virtualization/agent-rl-hami-deployment.webp
  • public/images/blog/boardware-hami-gpu-virtualization/gpu-pain-points.webp
  • public/images/blog/boardware-hami-gpu-virtualization/k8s-hami-architecture.webp
  • public/images/blog/boardware-hami-gpu-virtualization/multi-scenario-workload.webp
  • public/images/blog/boardware-hami-gpu-virtualization/speaker-photo.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/cmb-choose-hami.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/gpu-partition-comparison.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/speaker-suxi.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/summary.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/super-node-adapter-1.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/super-node-adapter-2.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/super-node-results.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/super-node-value.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/topology-3layer.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/topology-scheduling-algo.webp
  • public/images/blog/cmb-hami-heterogeneous-computing/vnpu-core-arch.webp
  • public/images/blog/enflame-k8s-cloud-native-practice/gpu-operator-architecture.webp
  • public/images/blog/enflame-k8s-cloud-native-practice/inference-gateway-stack.webp
  • public/images/blog/enflame-k8s-cloud-native-practice/speaker-mada.webp
  • public/images/blog/hami-meetup-shenzhen-recap/shenzhen-meetup-group-photo.webp
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/qa-session.webp
  • public/images/blog/hami-v29-dra-ecosystem-limengxuan/speaker-portrait.webp
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/solution-diagram-en.drawio
  • public/images/blog/ke-holdings-ml-infrastructure-scaling/solution-diagram-zh.drawio
  • public/images/blog/snow-corp-cncf-case-study/snowcorp.webp
  • public/robots.txt
  • public/scripts/collect-hami-license-info.sh
  • scripts/validate-attachments.mjs
  • scripts/validate-enterprise.mjs
  • src/app/.well-known/agent-skills/agent-discovery/SKILL.md/route.ts
  • src/app/.well-known/agent-skills/index.json/route.ts
  • src/app/.well-known/api-catalog/route.ts
  • src/app/.well-known/jwks.json/route.ts
  • src/app/.well-known/mcp/server-card.json/route.ts
  • src/app/.well-known/oauth-authorization-server/route.ts
  • src/app/.well-known/oauth-protected-resource/route.ts
  • src/app/.well-known/openid-configuration/route.ts
  • src/app/[locale]/[...rest]/page.tsx
  • src/app/[locale]/apply-trial/page.tsx
  • src/app/[locale]/attachments/[slug]/page.tsx
  • src/app/[locale]/blog/BlogListClient.tsx
  • src/app/[locale]/blog/[slug]/BlogPostClient.tsx
  • src/app/[locale]/blog/[slug]/page.tsx
  • src/app/[locale]/blog/layout.tsx
  • src/app/[locale]/blog/page.tsx
  • src/app/[locale]/case-studies/[slug]/page.tsx
  • src/app/[locale]/case-studies/page.tsx
  • src/app/[locale]/company/layout.tsx
  • src/app/[locale]/company/page.tsx
  • src/app/[locale]/cookies-policy/page.tsx
  • src/app/[locale]/faq/page.tsx
  • src/app/[locale]/layout.tsx
  • src/app/[locale]/not-found.tsx
  • src/app/[locale]/page.tsx
  • src/app/[locale]/pricing/layout.tsx
  • src/app/[locale]/pricing/page.tsx
  • src/app/[locale]/privacy-policy/page.tsx
  • src/app/[locale]/products/[productId]/install/page.tsx
  • src/app/[locale]/products/[productId]/page.tsx
  • src/app/[locale]/products/layout.tsx
  • src/app/[locale]/products/page.tsx
  • src/app/[locale]/resources/layout.tsx
  • src/app/[locale]/resources/page.tsx
  • src/app/[locale]/solutions/page.tsx
  • src/app/[locale]/tools/hami-metrics-explorer/page.tsx
  • src/app/[locale]/tools/page.tsx
  • src/app/[locale]/videos/page.tsx
  • src/app/[locale]/what-is-hami/page.tsx
  • src/app/api/contact/route.ts
  • src/app/api/enterprise-install/[productId]/route.ts
  • src/app/blog/[slug]/page.tsx
  • src/app/blog/layout.tsx
  • src/app/blog/page.tsx
  • src/app/company/layout.tsx
  • src/app/error.tsx
  • src/app/globals.css
  • src/app/layout.tsx
  • src/app/pricing/layout.tsx
  • src/app/products/kantaloupe/page.tsx
  • src/app/products/layout.tsx
  • src/app/products/page.tsx
  • src/app/request-demo/page.tsx
  • src/app/resources/layout.tsx
  • src/app/robots.txt
  • src/app/sitemap.ts
  • src/app/solutions/layout.tsx
  • src/app/zh/apply-trial/page.tsx
  • src/app/zh/blog/[slug]/page.tsx
  • src/app/zh/blog/case-prep-edu-hami/page.tsx
  • src/app/zh/blog/case-sf-technology-effective-gpu/page.tsx
  • src/app/zh/blog/case-telecom-gpu/page.tsx
  • src/app/zh/blog/page.tsx
  • src/app/zh/company/page.tsx
  • src/app/zh/cookies-policy/page.tsx
  • src/app/zh/layout.tsx
  • src/app/zh/page.tsx
  • src/app/zh/pricing/page.tsx
  • src/app/zh/privacy-policy/page.tsx
  • src/app/zh/products/kantaloupe/page.tsx
  • src/app/zh/products/page.tsx
  • src/app/zh/request-demo/page.tsx
  • src/app/zh/resources/page.tsx
  • src/app/zh/solutions/page.tsx
  • src/app/zh/what-is-hami/page.tsx
  • src/components/BlogAIShareSection.tsx
  • src/components/BlogShareButtons.tsx
  • src/components/Breadcrumb.tsx
  • src/components/ConsentAwareAnalytics.tsx
  • src/components/CookieConsentManager.tsx
  • src/components/DynamicBlogCover.tsx
  • src/components/FeatureComparisonTable.tsx
  • src/components/FormSuccessMessage.tsx
  • src/components/HubSpotForm.tsx
  • src/components/I18nProvider.tsx
  • src/components/LanguageSwitcher.tsx
  • src/components/ModeToggle.tsx
  • src/components/OptimizedImage.tsx
  • src/components/SEOHead.tsx
  • src/components/Search.tsx
  • src/components/StructuredData.tsx
  • src/components/TableOfContents.tsx
  • src/components/agent/WebMCPProvider.tsx
  • src/components/attachments/AttachmentDocClient.tsx
  • src/components/case-studies/CaseDaoCloud.tsx
  • src/components/case-studies/CaseKeHoldings.tsx
  • src/components/case-studies/CaseNio.tsx
  • src/components/case-studies/CasePrepEduHami.tsx
  • src/components/case-studies/CaseSfTechnologyEffectiveGpu.tsx
  • src/components/case-studies/CaseSnowCorp.tsx
  • src/components/case-studies/CaseStudiesList.tsx
  • src/components/case-studies/CaseTelecomGpu.tsx
  • src/components/enterprise/ArtifactList.tsx
  • src/components/enterprise/ArtifactRow.tsx
  • src/components/enterprise/ComingSoonCard.tsx
  • src/components/enterprise/ConsentLabel.tsx
  • src/components/enterprise/CopyableCommand.tsx
  • src/components/enterprise/DownloadDeliveryTabs.tsx
  • src/components/enterprise/DownloadGateModal.tsx
  • src/components/enterprise/EnterpriseDetailClient.tsx
  • src/components/enterprise/EnterpriseListClient.tsx
  • src/components/enterprise/HamiOriginBanner.tsx
  • src/components/enterprise/InstallDocClient.tsx
  • src/components/enterprise/ProductCard.tsx
  • src/components/enterprise/ProductHero.tsx
  • src/components/enterprise/ProductScope.tsx
  • src/components/enterprise/TrustBlock.tsx
  • src/components/enterprise/VersionSelector.tsx

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

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

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request performs a major refactoring to migrate the internationalization framework from react-i18next to next-intl with localized routing, upgrades Next.js to 15.5.18, and integrates Shadcn UI components. The review feedback highlights several critical issues that must be addressed before merging: the deletion of the /api/contact route breaks form submissions on multiple pages; several links use single quotes instead of backticks, resulting in broken literal string interpolations; missing translation message providers in layout.tsx and error.tsx will cause runtime crashes; and the refactored middleware removes essential security headers. Additionally, the configuration in next.config.ts contains an invalid qualities property, and some minor cleanup is needed for duplicate paragraphs and unused components.


// Send to API route using Resend

const response = await fetch('/api/contact', {

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.

critical

The /api/contact API route was deleted in this PR, but this page still attempts to POST form submissions to /api/contact. This will cause all pricing inquiries to fail with a 404 Not Found error. Please restore the API route or migrate this form to HubSpotForm.

formData.append('_template', 'box');

// Send to API route using Resend
const response = await fetch('/api/contact', {

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.

critical

The /api/contact API route (src/app/api/contact/route.ts) was deleted in this pull request. However, this page (along with PricingPage.tsx and RequestDemoPage.tsx) still attempts to POST form submissions to /api/contact.

With the API route deleted, all form submissions on the website will fail with a 404 Not Found error. Please restore the /api/contact route or update the forms to use the newly added HubSpotForm component if that was the intended migration.

Comment thread src/app/[locale]/layout.tsx
Comment thread src/app/[locale]/layout.tsx
Comment thread src/app/error.tsx
Comment on lines +12 to +27
export default function Error({
params,
error,
reset,
}: {
params: Promise<{ locale: string }>;
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error);
}, [error]);
const { locale } = use(params);
setRequestLocale(locale);
const t = useTranslations("error");

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.

critical

Critical Issues with error.tsx:

  1. params is undefined: Next.js error.js components do not receive params as a prop. Therefore, params will be undefined at runtime, and calling use(params) on line 25 will throw a TypeError, crashing the error page itself.
  2. Missing NextIntlClientProvider: Since this file is located at src/app/error.tsx (outside the [locale] directory), it is not wrapped by the RootLayout which provides the NextIntlClientProvider. As a result, calling useTranslations("error") will throw an error because the translation context is missing.

Solution:

Move this file to src/app/[locale]/error.tsx so it is wrapped by the localized layout. Once moved inside [locale], you can remove the params prop and setRequestLocale call entirely, and use useLocale() or let next-intl handle the context automatically.

"use client";

import { ServerCrash } from "lucide-react";
import { useEffect } from "react";

import { Button } from "@/components/ui/button";

import { Link } from "@/i18n/navigation";
import { useTranslations } from "next-intl";

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string };
  reset: () => void;
}) {
  useEffect(() => {
    console.error(error);
  }, [error]);

  const t = useTranslations("error");

  return (
    <div className="flex flex-col items-center justify-center min-h-[70vh] px-4 text-center">
      <div className="flex items-center justify-center w-20 h-20 mb-6 rounded-full bg-red-100">
        <ServerCrash className="w-10 h-10 text-red-600" />
      </div>
      <h1 className="mb-2 text-3xl font-bold tracking-tight text-gray-900 sm:text-4xl">
        {t("title")}
      </h1>
      <p className="mb-8 text-lg text-gray-600">{t("sorry")}</p>
      <div className="flex flex-col gap-4 sm:flex-row">
        <Button onClick={() => reset()} variant="default">
          {t("tryAgain")}
        </Button>
        <Button variant="outline" asChild>
          <Link href="/">{t("returnHome")}</Link>
        </Button>
      </div>
    </div>
  );
}

Comment thread src/components/layout/Header.tsx Outdated
Comment thread src/app/[locale]/blog/[slug]/BlogPostClient.tsx Outdated
Comment on lines 61 to 63
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</p>
</div>

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.

medium

There is a hardcoded Lorem ipsum dolor sit amet... placeholder paragraph under each core feature. Please replace this with actual localized feature descriptions or remove the paragraph entirely to keep the UI clean and professional.

Comment thread src/components/pages/KantaloupeProductPage.tsx Outdated
Comment thread src/components/LocaleStructuredData.tsx Outdated
@fishman

fishman commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

@Shenhan11 @rootsongjc

fishman added 27 commits June 4, 2026 17:57
…cales

- Replace union type `'en' | 'zh'` with `string` (`locale`/`language`) in blog server, client, and rehype plugins
- Update `formatDate` to use `locale` parameter with `toLocaleDateString`
- Change image caption language detection from `=== 'zh'` to `startsWith('zh')`
- Simplify blog post metadata lookup to use `locale` directly instead of fallback logic
Centralize canonical/alternate URL generation using locale-aware utility
functions, removing duplicated inline logic from the blog post page and
the generatePageMetadata function.
Previously, Chinese locale pages had incorrect canonical and alternate hreflang links (e.g., `/zh/zh`). Now uses `localizedUrl` and `localizedAlternates` utilities to generate proper URLs.
…nctions

Replace manual locale-based URL generation and alternates definition across
all case-study, cookies-policy, faq, privacy-policy, videos, and what-is-hami
pages with the localizedUrl and localizedAlternates helpers from @/utils/seo.
This centralizes URL logic and reduces duplication.
- Add complete German translation dictionary (de.json)
- Register "de" as a supported locale in routing, site config, and types
- Refactor blog components to accept string locale instead of union types
- Add safe locale loading with fallback to default in i18n/request.ts
- Simplify FormSuccessMessage by removing per-locale fallbacks
- Use routing.locales in generateStaticParams for DRYness
- Remove hardcoded locale list and labels in LanguageSwitcher
- Move attachment page under [locale] directory for Next.js App Router i18n
- Use next-intl translations for "not found" fallback and metadata
- Add "attachments.notFound" translation keys for de, en, zh
- Delete redundant src/app/zh/attachments/[slug]/page.tsx
…pages

- Replace `t('...', { returnObjects: true })` with `t.raw('...')` in FeatureComparisonTable, PricingPage, and SolutionsPage
- Remove unused Kantaloupe product page and Request Demo page
- Add missing `t` to useEffect dependency array in BlogPostClient
This reverts commit 0850bd0.
…oded locale logic

Replace ad-hoc locale branching and inline dictionaries (`CHROME`, `COPY`, `PRODUCT_INTRO`, `STATUS_LABEL`, `COMPATIBILITY_LABELS`, etc.) with next-intl translation keys. This eliminates props drilling of `locale`, unifies URL generation via `localizedPath()`, and moves all product metadata (`productsData`, `productIntro`) into JSON dictionaries for the three supported locales.

**Why this was needed** – The old approach had a number of problems that hurt long-term maintainability:

1. **Duplication & drift** – The same English/Chinese text was defined in multiple places (e.g., status labels appeared in `ArtifactRow`, `ProductCard`, `ProductHero`). Any update required finding and changing every copy.
2. **Non-idiomatic patterns** – Hardcoded objects like `const CHROME = { en: { … }, zh: { … } }` bypass the established `next-intl` infrastructure, making it harder to add new locales or use features like interpolation, plurals, and fallbacks.
3. **Prop drilling** – `locale` was threaded through component trees (e.g., `EnterpriseDetailClient` → `DownloadDeliveryTabs` → `ArtifactList` → `ArtifactRow`), increasing cognitive load and making components less reusable.
4. **Inconsistent handling** – Some strings used `pickI18n()` (a custom helper), others used `locale === 'zh'` ternaries directly, and some were embedded in JSX with no translation path at all.

Moving everything to `next-intl` dictionaries fixes these issues by enforcing a single source of truth, improving discoverability, and simplifying the component API.

Key changes:
- Replace `pickI18n` utility and `Locale` type with `useLocale()` and indexed `I18nText` lookups
- Remove `locale` prop from all enterprise components (`ArtifactRow`, `DownloadDeliveryTabs`, `EnterpriseDetailClient`, `ProductCard`, etc.)
- Move hardcoded copy into JSON translation dictionaries (status, compatLabels, origin, scope, productsData, productIntro, codeLabels, etc.)
- Replace conditional `locale === 'zh'` URL logic with `localizedPath()` utility
- Update `enhanceCodeBlocks` to accept a `labels` object instead of a locale string
- Switch all `@/utils/seo` imports to `@/utils/i18n`
- Unify `productsData` and `productIntro` lookups via `t.raw()` for per-locale product metadata
- Add `back` key to `installDoc` translations for all three locales
- Fix i18n interpolation syntax from `{{count}}` to `{count}`
…`[slug]` route

Replace 7 individual case study page files under `src/app/[locale]/case-studies/{slug}/` with a single dynamic route `[slug]/page.tsx`. The new page uses a `CASE_STUDIES` mapping to resolve the correct component and i18n key, removing duplicated page setups, metadata generation, and imports. This follows Next.js dynamic routing patterns, adheres to the DRY principle, and simplifies adding new case studies in the future.
…ontmatter

Replace hardcoded `'en' | 'zh'` union types with `string` in attachment and enterprise-docs modules. Remove the `frontmatter.language` field from both output types and stop deriving locale from frontmatter. Use the passed-in `locale` parameter directly for markdown conversion.

Dynamically validate product IDs against `getProductIds()` instead of a static union. Install doc default locale changed from `'zh'` to `'en'`. Locale suffix regex relaxed from `\.(en|zh)$` to `\.[a-z]{2}$`. `installDocExists` now checks via `getInstallDocSlugs()` instead of enumerating known locales.
The conditional `if (!mounted)` block returned a completely different DOM tree during SSR, causing React hydration errors. Replaced it with a synchronous logo placeholder (`/dynamia-logo.svg`) for SSR and deferred locale/theme-aware logo selection to after mount. Also switched the logo source from hardcoded SVG paths to translation keys (`t('navigation.logo')` / `t('navigation.logoDark')`), enabling locale-aware branding. This ensures the component tree is identical between server and client, preventing `useId()` mismatches.
…lated link

Replace inline consent label markup with a shared `ConsentLabel` component that uses `t.rich` for i18n-safe link rendering.
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.

5 participants