Internationalize auth toasts and settings validation messages - #8
pdlourenco wants to merge 2 commits into
Conversation
pdlourenco
left a comment
There was a problem hiding this comment.
Review — LGTM ✅ (most thoroughly verified of the four)
Ran the full verification myself on this branch:
- Test suite: 29/29 passing (25 existing + the 4 new ones) — reproduced locally. (First run failed in my sandbox, but that was my environment's inlang-plugin setup, not the PR — after fixing my local paraglide compile the suite is green.)
svelte-check: 0 errors across the workspace, so the signature change is consistent — and I confirmed the only production caller issrc/routes/(app)/settings/+page.svelte:42, updated in this diff.- The locale-following test is a real assertion: I checked
de.jsonand it does containsettings_error_currency_required, so thedecomparison isn't trivially passing through the English fallback. Nice that the test restores the locale in afinally. - The claimed pre-existing
.omit()-after-.refine()bug reproduces exactly:z.object({...}).refine(...).omit(...)throws.omit() cannot be used on object schemas containing refinementson this zod version. Confirmed it predates this PR and only the dead second-overload path hits it. Please do file it as its own issue so it doesn't get lost in this PR's description — the "omit before refine" fix suggestion is right.
Design points I specifically like: lazy { error: () => m.foo() } getters (correctly makes messages follow the locale at validation time — and the new test proves it), reusing the three existing settings_error_* keys instead of minting duplicates (which kills the "timzone" typo for free), and replacing raw zod enum internals with settings_error_invalid_option.
Scope expansion to the error-prefix toasts is justified — leaving the store half-hardcoded would have been worse.
Coordination notes: (1) disjoint-hunk overlap with #7 in settings-form.helper.ts and with #10 in en.json — both should merge cleanly regardless of order; (2) the 8 new keys need pt-PT values in upstream javedh-dev#240 once this lands, as the description already notes.
No changes requested.
Generated by Claude Code
Several user-facing strings bypassed Paraglide and always rendered in English: - Login, registration and profile toasts in the auth store, including the "Login failed:"/"Registration failed:"/"Update failed:" prefixes. - Settings validation messages produced by the zod schema: the required currency, the date format and timezone refinements, the UK MPG rule, and the raw "Invalid option: expected one of ..." text emitted for enum fields. The schema is now built through a factory that takes the messages module, with message getters called lazily so errors follow the locale that is active when the form is validated. The existing catalog keys are reused where they already existed; wiring settings_error_timezone_invalid also resolves the "timzone" typo that was visible to users. Adds tests covering the validation messages, including that they follow a locale change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG
The pt-PT catalog is now upstream, so the keys introduced here would otherwise fall back to English for Portuguese users. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG
2df39ae to
34e5641
Compare
pt-PT strings for reviewThe pt-PT catalog is now upstream (javedh-dev#240 merged), so I rebased this branch onto
Judgement calls worth a second opinion
Catalog stateOnly Verification after the rebase
🤖 Generated with Claude Code https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG Generated by Claude Code |
| } | ||
| return false; | ||
| } catch (err: any) { | ||
| console.error('Registration error:', err); |
There was a problem hiding this comment.
What about this string? Shouldn't it be localized as well or are we only translating UI and not console?
There was a problem hiding this comment.
Deliberate: UI only, not console. console.error('Login error:', err) and its sibling on line 93 are developer diagnostics, not user-facing text.
That matches the existing convention rather than being a decision I made for this PR — I checked: 27 console.* calls across src/ (excluding generated Paraglide output), and 0 of them are localized. The server-side logger.info/error calls follow the same rule.
Three reasons it's the right split:
- Greppability. An English console string can be matched back to source. If a pt-PT user pastes
Erro de início de sessão:into a bug report, the maintainer can't grep for it — and neither can they read it. - Catalog bloat. Every translator in every locale would translate strings no user ever reads.
- The user-facing half of the same failure already is localized — the
toast.error(...)two lines below eachconsole.error. So on a failed login the person sees Portuguese, and the developer opening DevTools sees English. That's the intended division, and both branches of this function do it.
Related gap worth knowing about (not fixed here)
The localized toast interpolates a server-supplied string:
toast.error(`${m.auth_toast_login_error_prefix()}${err.response?.data?.message || err.message}`)err.response?.data?.message comes from the API and is always English ('Invalid username or password', 'Username already exists', …). So a pt-PT user sees a half-translated toast: Falha ao iniciar sessão: Invalid username or password.
Fixing that properly means either localizing API error responses (the server would need per-request locale awareness) or mapping known server error codes to catalog keys on the client. Both are a design change well beyond this PR — worth its own issue if you want it. Flagging it so the half-English toast isn't mistaken for an oversight in this change.
Leaving both threads open for you to close, since this is an answer rather than a code change.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG
Generated by Claude Code
| } catch (err: any) { | ||
| this.user = null; | ||
| this.isLoggedIn = false; | ||
| console.error('Login error:', err); |
There was a problem hiding this comment.
See below comment on missing translation for console errors
There was a problem hiding this comment.
Answered on the line-93 thread: console diagnostics stay English by design (27 console.* calls in src/, 0 localized; server logger.* likewise), while the user-facing toast.error two lines below is localized. Same reasoning applies to this one.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG
Generated by Claude Code
pdlourenco
left a comment
There was a problem hiding this comment.
Follow-up review of the update — LGTM ✅
Re-verified after the force-push:
- Rebase is content-identical: the rebased commit's patch differs from the previously reviewed
2df39aeonly in the blob-index line — no code drift smuggled in with the rebase onto the post-javedh-dev#240dev. - New commit (pt-PT values for the 8 keys) — reviewed as European Portuguese, all approved:
- "Sessão iniciada com sucesso" / "Falha ao iniciar sessão: " — matches the catalog's "Iniciar sessão" terminology exactly;
- "Conta criada com sucesso. Inicie sessão." — matches the "Criar conta" button rather than the English "User created", which is the better localization;
- "Falha ao …: " prefixes are consistent with the existing error-prefix pattern;
- "Opção inválida" follows the "Formato inválido" convention;
- "O cálculo em MPG britânico requer a distância em milhas e o volume em litros." — consistent with the "MPG britânico (milhas por galão imperial)" label, correct AO90, natural phrasing.
- Integrity: 818/818 key parity between
en.jsonandpt-PT.json, zero placeholder mismatches (scripted check). - Suite on the new head: 36/36 passing — the 29 from before plus the date-validation tests that arrived via the rebase, all green together.
Nice touch appending the keys in the same order as en.json. Since javedh-dev#240 merged upstream and dev is synced, updating both catalogs in this PR is exactly right; the other ten locales fall back to English for these 8 keys as before.
One thing still outstanding from the previous review: the pre-existing zod .omit()-after-.refine() bug (confirmed reproducible) deserves its own issue so it isn't lost when this PR merges.
No changes requested.
Generated by Claude Code
|
Thanks — both reviews addressed. Nothing to change in the code; two items to close out. The zod
|
Fixes #4. For review before sending upstream. Branched from
dev, independent of #6 and #7.Problem
Several user-facing strings bypassed Paraglide entirely, so a pt-PT (or any non-English) user saw English text:
src/lib/stores/auth.svelte.ts) — "Login successful", "User created successfully. Please login.", "Profile updated successfully"src/lib/helper/settings-form.helper.ts) — "Currency is required", "Format not valid",Invalid timzone value.(with the user-visible typo), the UK MPG rule, and zod's rawUnit Of Lpg: Invalid option: expected one of "liter"|...Changes
Schema factory is now locale-aware.
createSettingsConfigSchematakes the messages module as its first argument (matchingcreateSettingsOptions(m, locales)), and the schema is built by abuildSettingsConfigSchema(m)factory. Message getters are passed lazily ({ error: () => m.foo() }) so errors follow the locale active at validation time, not schema-construction time — this matters because the locale can change without a full remount.Enum errors now use a shared
settings_error_invalid_optionmessage instead of leaking zod internals.Existing keys reused where they existed (
settings_error_currency_required,settings_error_date_format_invalid,settings_error_timezone_invalid) — the catalog already spelled "timezone" correctly, so wiring it up fixes the typo for free.Scope note: the issue listed only the three success toasts, but the
Login failed:/Registration failed:/Update failed:prefixes are hardcoded in the same way, so I did those too rather than leave the store half-translated.New keys (8, added to
en.jsononly)auth_toast_login_success,auth_toast_login_error_prefix,auth_toast_register_success,auth_toast_register_error_prefix,profile_toast_updated,profile_toast_error_prefix,settings_error_invalid_option,settings_error_uk_mpg_requirementsOther locales fall back to English until translated — strictly better than hardcoded, and the same pattern earlier language PRs used.
Verification
src/__tests__/settings-validation.test.ts, 4 passing) covering each localized message, that the enum error no longer containsInvalid option: expected one of, that the timezone message no longer containstimzone, and that messages follow a locale change (asserted againstde). CI already runspnpm run test.pnpm build,pnpm check(5073 files, 0 errors),pnpm lint— all clean.Pre-existing bug found while testing (not fixed here)
createSettingsConfigSchemathrows when called withoutincludeNotificationProcessingSchedule: true:zod v4 rejects
.omit()on a schema that already has.refine(). Confirmed present on unmodifieddev, so it predates this change; the only caller passes the flag, which is why nobody has hit it — the second overload is effectively dead code that would throw if used. Out of scope here; worth its own issue (fix would be to omit before refining).Follow-up for the pt-PT PR
The 8 new keys will need pt-PT values in javedh-dev#240 — happy to add them once this lands.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YXazaegVWZdeKziwMzPKPG
Generated by Claude Code