feat(auth): Add linkComponent/labels props to auth forms, i18n support, widescreen layout#990
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Add translated auth section (login, register, forgotPassword) to ja, ko, de, fr, es, pt, ru, and ar locale files, positioned before the errors section to match en.ts and zh.ts structure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…h i18n to all locales, improve console auth pages with widescreen layout Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…upport Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds router-aware auth page links and i18n-ready auth form copy, and introduces a shared widescreen auth layout for the console.
Changes:
- Add
linkComponentsupport to auth forms so navigation works correctly under React Routerbasename(e.g./console). - Add
labelsoverride objects to auth forms and wire console auth pages touseObjectTranslation()with newauth.*locale keys. - Introduce
AuthPageLayoutsplit-panel layout and apply it to console auth pages.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/i18n/src/locales/en.ts | Adds auth.login/register/forgotPassword.* translation keys (source language). |
| packages/i18n/src/locales/zh.ts | Adds Chinese auth translations including {{email}} placeholder usage. |
| packages/i18n/src/locales/ja.ts | Adds Japanese auth translations. |
| packages/i18n/src/locales/ko.ts | Adds Korean auth translations. |
| packages/i18n/src/locales/de.ts | Adds German auth translations. |
| packages/i18n/src/locales/fr.ts | Adds French auth translations. |
| packages/i18n/src/locales/es.ts | Adds Spanish auth translations. |
| packages/i18n/src/locales/pt.ts | Adds Portuguese auth translations. |
| packages/i18n/src/locales/ru.ts | Adds Russian auth translations. |
| packages/i18n/src/locales/ar.ts | Adds Arabic auth translations. |
| packages/auth/src/types.ts | Introduces AuthLinkComponentProps for custom link rendering. |
| packages/auth/src/index.ts | Exports new label types and AuthLinkComponentProps from @object-ui/auth. |
| packages/auth/src/LoginForm.tsx | Adds linkComponent + labels props and replaces hardcoded strings with label defaults. |
| packages/auth/src/RegisterForm.tsx | Adds linkComponent + labels props and replaces hardcoded strings with label defaults. |
| packages/auth/src/ForgotPasswordForm.tsx | Adds linkComponent + labels props and updates success message rendering. |
| packages/auth/src/tests/LoginForm.test.tsx | Tests custom linkComponent usage and label overrides. |
| packages/auth/src/tests/RegisterForm.test.tsx | Tests custom linkComponent usage and label overrides. |
| packages/auth/src/tests/ForgotPasswordForm.test.tsx | Tests custom linkComponent usage and label overrides. |
| apps/console/src/components/AuthPageLayout.tsx | Adds shared split-panel auth layout for widescreen. |
| apps/console/src/pages/LoginPage.tsx | Uses AuthPageLayout, passes router Link wrapper + i18n labels into LoginForm. |
| apps/console/src/pages/RegisterPage.tsx | Uses AuthPageLayout, passes router Link wrapper + i18n labels into RegisterForm. |
| apps/console/src/pages/ForgotPasswordPage.tsx | Uses AuthPageLayout, passes router Link wrapper + i18n labels into ForgotPasswordForm. |
| const successMsg = l.successDescription.includes('{{email}}') | ||
| ? l.successDescription.replace('{{email}}', email) | ||
| : `${l.successDescription} ${email}`; |
There was a problem hiding this comment.
In the submitted state, successDescription is treated as a string template and then conditionally appended with the email. This can produce duplicated email (if callers pass an already-interpolated string) and only replaces the first {{email}} occurrence. Consider making this deterministic by always replacing all occurrences of the placeholder (e.g. global replace), and avoid the fallback append that can duplicate content—either require {{email}} in the template or render the email separately in JSX.
| const successMsg = l.successDescription.includes('{{email}}') | |
| ? l.successDescription.replace('{{email}}', email) | |
| : `${l.successDescription} ${email}`; | |
| const successMsg = l.successDescription.replace(/{{email}}/g, email); |
| <span className="text-2xl font-bold">ObjectStack</span> | ||
| </div> | ||
| <h2 className="text-3xl font-bold leading-tight"> | ||
| Build powerful business applications, faster. | ||
| </h2> | ||
| <p className="text-lg opacity-90"> | ||
| The universal platform for enterprise data management, workflows, and analytics. | ||
| </p> |
There was a problem hiding this comment.
AuthPageLayout introduces new user-facing strings (tagline/description) that are not wired to the console i18n system, so auth pages are still partially non-translatable. Consider passing these strings in as props from the pages (using useObjectTranslation()), or adding auth.layout.* keys to the locale files and translating here.
| > | ||
| <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" /> | ||
| </svg> | ||
| <span className="text-2xl font-bold">ObjectStack</span> | ||
| </div> | ||
| <h2 className="text-3xl font-bold leading-tight"> | ||
| Build powerful business applications, faster. | ||
| </h2> |
There was a problem hiding this comment.
The branding panel uses an unlabelled SVG and a semantic <h2> that appears before the form’s <h1> in DOM order. For accessibility, mark decorative SVGs as aria-hidden (or provide an accessible name), and avoid heading-level jumps by using non-heading elements for marketing copy (or ensure a logical heading order).
| > | |
| <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" /> | |
| </svg> | |
| <span className="text-2xl font-bold">ObjectStack</span> | |
| </div> | |
| <h2 className="text-3xl font-bold leading-tight"> | |
| Build powerful business applications, faster. | |
| </h2> | |
| aria-hidden="true" | |
| focusable="false" | |
| > | |
| <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" /> | |
| </svg> | |
| <span className="text-2xl font-bold">ObjectStack</span> | |
| </div> | |
| <p className="text-3xl font-bold leading-tight"> | |
| Build powerful business applications, faster. | |
| </p> |
| const RouterLink = ({ href, className, children }: AuthLinkComponentProps) => ( | ||
| <Link to={href} className={className}>{children}</Link> | ||
| ); |
There was a problem hiding this comment.
RouterLink is duplicated across LoginPage/RegisterPage/ForgotPasswordPage with identical implementation. To reduce maintenance overhead, consider extracting a shared link wrapper (e.g. apps/console/src/components/RouterLink.tsx) and reusing it across auth pages.
| const successMsg = l.successDescription.includes('{{email}}') | ||
| ? l.successDescription.replace('{{email}}', email) | ||
| : `${l.successDescription} ${email}`; |
There was a problem hiding this comment.
The new successDescription interpolation logic ({{email}} replacement / fallback append) isn’t covered by tests. Consider extending the existing “shows success message after submission” test to assert that the rendered success message includes the submitted email and handles the {{email}} placeholder as expected.
Auth page links (Sign up, Forgot password, Sign in) use raw
<a>tags that ignore React Router'sbasename, so deploying under/consoleprefix produces broken links. All form text is hardcoded English with no i18n path. Widescreen layout is a bare centered 350px form.linkComponentprop — fixes prefix routingAuth forms accept an optional
linkComponentprop (React.ComponentType<AuthLinkComponentProps>) defaulting to<a>. Console pages now pass a React Router<Link>wrapper, which respectsBrowserRouter basenameautomatically:labelsprop — i18n supportEach form accepts a partial
labelsobject to override all user-facing strings. Console pages wire this touseObjectTranslation():i18n locale additions
auth.login.*,auth.register.*,auth.forgotPassword.*keys to all 10 locale files (en, zh, ja, ko, de, fr, es, pt, ru, ar)successDescriptionuses{{email}}placeholder for proper sentence structure across languagesWidescreen layout
AuthPageLayoutcomponent: split-panel design (branding left / form right onlg+, full-width form on mobile)sm:w-[350px]→sm:w-[380px]Exports
AuthLinkComponentProps,LoginFormLabels,RegisterFormLabels,ForgotPasswordFormLabelsexported from@object-ui/authOriginal prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.