Fix localized SEO metadata from Ahrefs audit#7888
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughSEO helpers now normalize localized titles and descriptions with length-aware, grapheme-safe processing. Route metadata uses shared SEO, Open Graph, Twitter, canonical URL, legal-page, and fallback-content utilities. Tests cover localized output, truncation, routing, and sitemap behavior. ChangesSEO metadata standardization
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant proxy
participant localeAvailability
participant RouteMetadata
participant SEOHelpers
Browser->>proxy: request localized fallback-content route
proxy->>localeAvailability: resolve fallback content
localeAvailability-->>proxy: path and locale availability
proxy-->>Browser: rewrite or redirect
Browser->>RouteMetadata: request page metadata
RouteMetadata->>SEOHelpers: build title and description
SEOHelpers-->>RouteMetadata: normalized SEO values
RouteMetadata-->>Browser: metadata with alternates, Open Graph, and Twitter fields
Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 error, 2 warnings)
✅ Passed checks (22 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR improves localized SEO metadata and fallback-content routing across public web pages. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (25): Last reviewed commit: "Avoid invalid localized SEO fallbacks" | Re-trigger Greptile |
| function truncateMetadataText(value: string, maxLength: number) { | ||
| if (value.length <= maxLength) return value; | ||
|
|
||
| const candidate = value.slice(0, maxLength - 1).trimEnd(); |
There was a problem hiding this comment.
Truncation Splits Unicode Characters
slice() limits UTF-16 code units rather than complete Unicode characters. When translated metadata places an emoji or another supplementary character across the cutoff, this creates an unpaired surrogate, so the rendered title or description can contain a replacement character before the ellipsis. Truncate on grapheme boundaries before applying the punctuation and word-boundary logic.
Rule Used: Flag production user-facing text that is not fully... (source)
There was a problem hiding this comment.
Fixed in 710120a. Truncation now uses Intl.Segmenter grapheme clusters, so supplementary characters, combining sequences, and joined emoji stay intact. The regression test cuts across a joined emoji sequence.
— Claude Code
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@web/app/`[locale]/(landing)/docs/agent-integrations/oh-my-pi/page.tsx:
- Line 17: Update the oh-my-pi page title initialization to use the localized
seoTitle(locale, t("metaTitle")) helper instead of the raw t("metaTitle") value,
matching the title handling used by the other pages.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5d555339-e5bb-4f4d-a5ef-25daf87f52cd
📒 Files selected for processing (15)
web/app/[locale]/(landing)/assets/page.tsxweb/app/[locale]/(landing)/blog/cmux-history/page.tsxweb/app/[locale]/(landing)/blog/page.tsxweb/app/[locale]/(landing)/community/page.tsxweb/app/[locale]/(landing)/compare/[slug]/page.tsxweb/app/[locale]/(landing)/compare/page.tsxweb/app/[locale]/(landing)/docs/agent-integrations/oh-my-pi/page.tsxweb/app/[locale]/(legal)/eula/page.tsxweb/app/[locale]/(legal)/legal-metadata.tsweb/app/[locale]/(legal)/privacy-policy/page.tsxweb/app/[locale]/(legal)/terms-of-service/page.tsxweb/app/[locale]/layout.tsxweb/app/[locale]/pricing/page.tsxweb/i18n/seo.tsweb/tests/seo.test.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@web/tests/seo.test.ts`:
- Around line 54-61: Update the “keeps truncated descriptions above the minimum
boundary” test to measure description length with the same Intl.Segmenter
grapheme-counting approach used by the later assertions, replacing both
Array.from(description).length checks while preserving the 110–160 bounds.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: b96c7a9e-c127-471b-829e-57dbdb129ab6
📒 Files selected for processing (5)
web/app/[locale]/(landing)/blog/cmux-history/page.tsxweb/app/[locale]/(landing)/blog/page.tsxweb/app/[locale]/(landing)/docs/agent-integrations/oh-my-pi/page.tsxweb/i18n/seo.tsweb/tests/seo.test.ts
| url: alternates.canonical, | ||
| }, | ||
| twitter: twitterSummary("en", title, description), | ||
| }; |
There was a problem hiding this comment.
Legal metadata skips bounds
Low Severity
The new legalMetadata helper sets raw title strings and calls seoDescription without { minLength: 110 } or seoTitle, unlike the other pages updated in this PR. Legal titles stay well under the 30-character floor and descriptions typically remain under 110 characters after only the default 90-character padding, so Ahrefs-style bounds are not applied on EULA, Privacy, and Terms.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit abcbf95. Configure here.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@web/tests/seo.test.ts`:
- Around line 222-232: Export the production metadataSearchLength helper from
web/i18n/seo.ts, then update web/tests/seo.test.ts to import and use it instead
of the local searchWidthSegmenter, wideSearchGrapheme, and searchSnippetLength
implementations. Remove the duplicated test-local regex and weighting logic so
tests exercise the production behavior directly.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ebdc1cbc-b5d6-4c1c-92a8-39ea26074d35
📒 Files selected for processing (7)
web/app/[locale]/(landing)/docs/agent-integrations/oh-my-pi/page.tsxweb/app/[locale]/pricing/page.tsxweb/app/sitemap.tsweb/i18n/locale-availability.tsweb/i18n/seo.tsweb/proxy.tsweb/tests/seo.test.ts
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7bbfe14. Configure here.


Fixes the actionable metadata findings in the cmux Ahrefs crawl.
Validation:
bun test tests/seo.test.tsbun run typecheckbun run lintbun run buildog:urloutputNeed help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Note
Medium Risk
Changes sit on global SEO helpers, locale middleware, and canonical/hreflang behavior for high-traffic routes; regressions could affect search snippets or wrong-locale URLs, though coverage in
tests/seo.test.tsis extensive.Overview
Addresses Ahrefs audit metadata issues by replacing ad hoc
seoDescriptionusage on key routes withi18n/audited-seo.tshelpers that pick bounded, locale-aware titles and descriptions (Unicode-safe lengths, contextual fallbacks, FAQ/route prose for compare pages).seo.tsgainsseoTitle, richer description suffixes, sentence joining, and stricter candidate filtering.Landing, blog, compare, pricing, home layout, and Oh My Pi
generateMetadatanow use those helpers; several pages usetitle: { absolute: ... }, and blog/compare JSON-LD can reuse the same headline/description viaBlogSchemaoverrides. Legal pages sharelegalMetadatawith full OG/Twitter and English-only alternates without marketing padding.Pricing and
/docs/agent-integrations/oh-my-piare treated as en/ja-only fallback content: middleware negotiates locale, redirects unsupported prefixed URLs, setshreflangLinkheaders, sitemap/agent indexes list only those locales, and docs search skips untranslated locales.ContentLocaleLinkpoints nav/footer/docs links at canonical English or/ja/...hrefs as appropriate.Reviewed by Cursor Bugbot for commit 300afa6. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Fixes localized SEO metadata from the Ahrefs audit and locks down en/ja-only fallback-content routing for Pricing and Oh My Pi. Centralizes route-specific SEO copy so pages select complete, localized titles/descriptions with consistent canonical/OG/Twitter/JSON‑LD.
Bug Fixes
i18n/audited-seo.tsplusseoTitle/seoDescriptionpick contextual authored fallbacks; blog/compare JSON‑LD can reuse the exact<meta>headline/description viaBlogSchemaoverrides; unique compare‑page titles are enforced.openGraph.urlfrom the canonical and emit full Open Graph/Twitter cards in the content locale. Legal pages sharelegalMetadatafor English‑only canonicals without marketing padding.i18n/audited-seo.ts.Fallback Content & Links
NEXT_LOCALEandAccept-Language(q‑values, wildcards), rewrites bare paths to canonical English, 307s to/ja/...when preferred, 301s unsupported locale prefixes, and setsLinkhreflangforen/ja.ContentLocaleLinkemits direct English hrefs (no/en) or/ja/...when translated and is used in the header, nav, footer, docs sidebar/pager, and the Pro banner.Written for commit 300afa6. Summary will update on new commits.
Summary by CodeRabbit
minLength: 110for descriptions where applicable.