Repository navigation
feat: useI18n - #7883
feat: useI18n#7883
Conversation
| <el-button native-type="submit" type="primary" class="w-full" :loading="isSubmitting">{{ t('auth.forgotPassword.actions.submit') }}</el-button> | ||
| </el-form> | ||
| </LoginLayout> | ||
| </template> |
There was a problem hiding this comment.
Code Review
Overall this is a solid i18n refactor. Below are the issues I found, grouped by severity.
π΄ Potential Bugs / Correctness
1. el-form rules switched from reactive to computed β validate reactivity
Switching forgotPasswordRules from reactive(...) to computed(() => ({...})) means a new object identity is created whenever any t() dependency changes (e.g. locale switch). Element Plus copies rules at init; combined with :validate-on-rule-change="false" the form will not auto-revalidate. Your manual watch(locale, ...) handles that case, which is good β but verify:
- The watch fires only on
locale, yet the rules also depend on any message change (rare, acceptable). - If a field's value has never been blurred/validated, switching language won't reveal localized errors until re-blur β expected behavior, fine.
2. Validator closure captures stale t
validateConfirmPassword uses t(...) directly, not the computed rules. That's fine because it runs at validation time and reads the current t. β
No bug, just noting it doesn't need to be inside the computed.
3. validateField return handling
if (field.prop) void form.validateField(field.prop).catch(() => undefined)form.fieldsis an internal-ish array in Element Plus; iterating it is supported but slightly fragile across versions. Acceptable.void expr.catch(...)β thevoidis redundant since.catch()returns a Promise you're already discarding. Minor.
4. Watch could cause focus loss / flicker
Re-validating all errored fields synchronously on locale change may cause visual churn if many fields error. Usually fine for a small form.
π‘ Minor Issues
5. Redundant useScope: 'global'
useI18n({ useScope: 'global' }) is the default when no useScope given, but explicit is fine if intentional for clarity.
6. Inconsistent translation keys
emailRequired/emailInvalidβauth.forgotPassword.validation.*βpasswordRequiredβauth.credentials.validation.passwordRequiredβ οΈ (different namespace β acceptable if shared, but ensure it exists in the locale files; otherwise falls back to the key string).- Others use
auth.forgotPassword...β the mixed namespace is worth documenting or aligning.
7. min-w-35 vs w-35
Changed w-35 β min-w-35 to accommodate longer localized text ("ιζ°ει (60s)" vs "Resend (60s)"). π Good call, but confirm min-w-35 is a valid Tailwind class in your config (arbitrary numeric spacing requires Tailwind v3.4+ min-w-* spacing scale support, or a custom config entry).
8. Placeholder accessibility
Placeholders are now translated β good. But ensure aria-label or visible <label> exists elsewhere; placeholders alone are not accessible labels.
9. autocomplete unchanged
Email/verification code inputs don't set autocomplete="one-time-code" for the code input. Consider adding it for OTP UX on mobile.
π’ Suggestions
10. Extract inline validator or memoize
No action needed; validateConfirmPassword reading live t is correct.
11. Consider flush: 'post' justification
flush: 'post' waits until DOM updates β correct here so form.fields reflect rendered state. Add a comment if not already present (you added comments elsewhere).
12. Type safety for _rule
(_rule: unknown, ...) β Element Plus types this as InternalRuleItem. Using unknown forwards-compat safe but loses hints; acceptable.
13. Untranslated UI remnant
Check the whole file for leftover hard-coded Chinese strings beyond this diff (e.g., error handlers, catch blocks, aria-labels). The diff only translates happy-path messages.
14. Test coverage
Add a test that switches locale while an error is shown and asserts the message updates β this is the riskiest new behavior.
Summary
No blocking bugs. Main risks: (a) rules-object identity change + relying on manual revalidation, (b) cross-namespace translation key auth.credentials.validation.passwordRequired must exist. Everything else is stylistic or minor UX polish.
feat: useI18n