Repository navigation
Localize tab titles, validation and server errors; add ?lang= links (T12: IN-01, SE-01, IN-14, IN-03, IN-04, IN-11) - #222
Merged
Conversation
…nks (T12) IN-01, SE-01, IN-14, IN-03, IN-04, IN-11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…k's title (review round 1) A link opened before the account's settings load no longer saves this device's older snapshot or flips back after hydration. A page can name its tab over its route's label, so a language switch keeps the not-found title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…iew round 2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Low) The switcher now shows on pages that open before the account's settings load; writing this device's whole snapshot could overwrite newer settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in title check e2e/localization.spec.ts proves T12 in the browser with every off-origin request stubbed: titles per route and language, the empty-Attack error, the switcher on /login and 404, ?lang= and /hu, and a translated refusal, at 1280 and 375 px. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedEnable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Next included review available in 38 minutes. View limit details
Note 🎁 Summarized by CodeRabbit Free
Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
T12 from the 22 Oct 2026 QA report on prod: tab titles, form validation, error messages and language routing now follow the interface language (EN, ES, HU).
Per issue
IN-01 (Medium) + SE-01 (Low): tab titles English-only; app routes titled just "DebateLab"
/app/*,/login,/share/*) were already titled<page> · DebateLabthroughusePrivateRouteHead(landed in Fix sign-in links, the OAuth callback and per-account state (T2: AUTH-01, 18, 17, 02, 19, 06, 07, 13) #202), but they had no description. They now also get the landing description in the interface language./toolspages, 404) take their title and description from a newpageHeadsection in the catalogs.usePageHeadtranslates them and re-titles the page on a language switch. Title and description now run in their own effect, so a switch doesn't drop the page's JSON-LD or canonical link.en.jsonthroughsrc/lib/seo/head-text.ts, so the prerendered HTML and the client say the same thing.index.htmltoo), and the debate-timer (186) and motion-generator (161) descriptions were trimmed.usePageLabel).src/test/seo/page-head.test.tsx(EN matches the prerender, HU/ES after a switch, 404, app routes, length cap); browser: recipeloc-titles(see table below).IN-14 (Medium): Zod validation errors English in every language
packages/core/src/ai/schemas/{attack,generate,brainstorm,factoids,ask}.tsnow emit catalog keys (validation.caseTextRequired, …). The Generate, Attack, Brainstorm and Factoids forms translate them. English text is unchanged, soagentic/forms.e2e.tsstill matches.src/test/i18n/localized-errors.test.tsx(HU error after an empty submit, nothing before it, ES after a switch); browser: recipeloc-validation.IN-03 (Low): language switcher only on the landing page
LanguageSwitcheris now inPublicPageShell(terms, privacy, sources, share, 404) and on/login. The app shell already had it.loc-switcheron/loginand the 404 page.IN-04 (Low):
?lang=ignored;/esand/hu404?lang=hu|es|enis applied inmountAppbefore the first render waits for the language, sets<html lang>, is saved like a switcher choice, and is removed from the address.UrlLanguagehandles one reached by in-app navigation./esand/huare client routes to/?lang=…, plus onevercel.jsonredirect for full loads:{ "source": "/:lang(es|hu)", "destination": "/?lang=:lang", "statusCode": 302 }. That is the onlyvercel.jsonchange. Sitemap and hreflang are unchanged.languagecolumn, and hydration prefers it over the saved language. A later switcher choice or a sign-out cancels it (review rounds 1 and 2).src/test/i18n/url-language.test.tsx, two cases insrc/test/settings/settings-migration.test.ts, the redirect rule insrc/test/vercel-deployment-config.test.ts; browser: recipeloc-links.IN-11 (Low): server and client error strings English-only
src/lib/server-errors.tsmaps server codes to catalog keys and falls back to the server's English for unknown codes._shared/entitlements.ts: the two 500 refusals now carryusage_check_failed/access_check_failed. The names avoid "quota" because clients read any code matching/quota|billing|…|rate/as a provider failure.create-portal:code: "no_active_subscription"beside the existing English.redeem-promo: acodeon every answer, via_shared/promo-result.ts, which also maps the database function's English messages. The browser does the same mapping, so promo answers translate beforeredeem-promois redeployed.usage_check_failed/access_check_failed, and the generic "AI service error: …" wrapper are now translated.stripe.tsthrows translatedBillingErrors carrying the server's code, and Settings and the pricing dialog detect "no active subscription" by code (or the legacy English). The literal "Failed to open billing portal" fallback is nowserverErrors.portalFailed.create-checkout's existingalready_subscribed/promo_expired/promo_exhaustedcodes, are translated.localized-errors.test.tsx(code → message per language, unknown code keeps server text, legacy promo messages); edge tests updated for the new promocode; browser: recipeloc-server-error(refused promo code in Hungarian).Edge Functions to deploy (not deployed by me)
ai,ai-stream,voice(bundle_shared/entitlements.ts),create-portal,redeem-promo. All changes are additive. The current frontend works with both the old and the new versions. No migrations.Tests
New:
src/test/seo/page-head.test.tsx,src/test/i18n/localized-errors.test.tsx,src/test/i18n/url-language.test.tsx, two cases insrc/test/settings/settings-migration.test.ts, one insrc/test/vercel-deployment-config.test.ts, one insrc/test/pages/SharedPage.test.tsx. I checked the title, linked-language and switcher-cancel tests by breaking each fix once and watching them fail. Five Login/Shared page tests now wrap the page inTooltipProvider, because those pages show the switcher.New browser spec:
e2e/localization.spec.ts. It is credential-free and runs in the full e2e suite on desktop and mobile Chromium, but not in the smoke set.New maintained verify recipe:
.claude/skills/verify-debatelab/recipes/localization.spec.ts, withfeatures/localization.mdand the index entry.Verification
This is a local run of the full
npm run verify, not a CI pass, because GitHub Actions minutes are used up. Every step passed at6b5d0830, the PR head. That head mergesorigin/mainated6b1c57(#216, which changed one string per catalog) with a normal merge:npm test: 84 files, 619 tests passedtest:collaboration: 5 files, 30 tests passedtest:edge: 457 passed, 0 failedbuild(vite build, prerender of all 10 public pages, sitemap, site check, build boundaries): passtest:sw: all checks true, includinglanguageSwitchOfflineandpublicPagesKeepTheirOwnHtmltest:e2e:smoke: 47 passedThe browser evidence comes from two runs. Both are kept locally under
.verify/artifacts/, becauseghcan't attach them.e2e/localization.spec.ts. It runs on this worktree's port (18123) with a stubbed session, and every request off the origin is stubbed:/rest/v1/*returns empty tables and theaifunction returns a 403banned. It proves the client only. Evidence:.verify/artifacts/20261023T-t12-stackless/.loc-titles,loc-validation,loc-linksandloc-server-error. The fifth,loc-switcher, failed on a recipe bug: it expected the Hungarian login title to end with "DebateLab", but "Bejelentkezés a DebateLab-ba" already names the app. The assertion is fixed, and the same check passes in run 1. Evidence:.verify/artifacts/20261023T103204Z-localization/. The recipe was not rerun on mobile against the stack.document.titleper route and language, signed in. Run 1 (stub user, 375 px) and run 2 (real local user, 1280 px) recorded the same values:/app/app/generate/app/attack/app/history/app/settings/terms/privacy/toolsSigned out,
/loginin Hungarian is titled "Bejelentkezés a DebateLab-ba". That label already names the app, so it gets no suffix, the same way the English "Sign in to DebateLab" works. The landing page via/?lang=huis titled "DebateLab by Pi-Stack | MI-alapú vitafelkészülés, érvek és cáfolatok". After a language switch,/app/generateand the 404 page re-title without a reload.Screenshots, at both widths unless noted:
/app/attackin Hungarian before any submit shows no error and no red border. After an empty submit it reads "Az érv szövegének megadása kötelező", and after switching to Spanish, "El texto del argumento es obligatorio"./loginheader (EN, then HU) and on the 404 page (HU, then ES)./?lang=huopens the landing page in Hungarian and drops the?langfrom the address./eslands on/in Spanish./hulands on/in Hungarian and stays Hungarian after a reload.aifunction answers 403banned, and Attack shows "Támadás elemzés sikertelen: A fiókodat felfüggesztettük. Fordulj az ügyfélszolgálathoz." with no English.redeem-promo: an unknown promo code returns{ success: false, code: "promo_invalid", message: "Invalid or expired promo code" }, and the Hungarian toast reads "Érvénytelen vagy lejárt promóciós kód".Review rounds (fresh-context Claude subagent,
claude-opus-5-5, full diff against main)?lang=link opened while signed in raced account hydration. It could flip back, or save this device's older settings snapshot over the account's.Left open
?lang=link. This behaviour predates the PR, and changing it touches auth logic, so it is left for a follow-up.To check on the Vercel preview or staging
These need the real host or backend:
/esand/huredirect on the host is avercel.jsonrule. Locally only the client route ran.curl -sI <preview>/hushould answer 302 withLocation: /?lang=hu.view-source:of/termsshould still have the English title, plus the new 150-character landing description in/and/app.?lang=link against real settings hydration (the round 1 and 2 fixes). This is covered by unit tests against a PostgREST-like mock, not by a browser run.already_subscribed/promo_expiredcodes in a browser. These are unit-tested only; the batch rules exclude real Stripe.🤖 Generated with Claude Code