i18n: Phrases for login page (#81478)

* i18n markup for login components

* Add serviceName to translation

* Fix typo

* Reset from main

* Extract

* Fix extract
This commit is contained in:
Tobias Skarhed 2024-02-07 16:37:42 +01:00 committed by GitHub
parent 843c477899
commit 00d69bc8e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 69 additions and 21 deletions

View File

@ -5,6 +5,7 @@ import { useForm } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors'; import { selectors } from '@grafana/e2e-selectors';
import { Button, Input, Field, useStyles2 } from '@grafana/ui'; import { Button, Input, Field, useStyles2 } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { PasswordField } from '../PasswordField/PasswordField'; import { PasswordField } from '../PasswordField/PasswordField';
@ -31,9 +32,13 @@ export const LoginForm = ({ children, onSubmit, isLoggingIn, passwordHint, login
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<form onSubmit={handleSubmit(onSubmit)}> <form onSubmit={handleSubmit(onSubmit)}>
<Field label="Email or username" invalid={!!errors.user} error={errors.user?.message}> <Field
label={t('login.form.username-label', 'Email or username')}
invalid={!!errors.user}
error={errors.user?.message}
>
<Input <Input
{...register('user', { required: 'Email or username is required' })} {...register('user', { required: t('login.form.username-required', 'Email or username is required') })}
id={usernameId} id={usernameId}
autoFocus autoFocus
autoCapitalize="none" autoCapitalize="none"
@ -41,9 +46,13 @@ export const LoginForm = ({ children, onSubmit, isLoggingIn, passwordHint, login
data-testid={selectors.pages.Login.username} data-testid={selectors.pages.Login.username}
/> />
</Field> </Field>
<Field label="Password" invalid={!!errors.password} error={errors.password?.message}> <Field
label={t('login.form.password-label', 'Password')}
invalid={!!errors.password}
error={errors.password?.message}
>
<PasswordField <PasswordField
{...register('password', { required: 'Password is required' })} {...register('password', { required: t('login.form.password-required', 'Password is required') })}
id={passwordId} id={passwordId}
autoComplete="current-password" autoComplete="current-password"
placeholder={passwordHint} placeholder={passwordHint}
@ -55,7 +64,7 @@ export const LoginForm = ({ children, onSubmit, isLoggingIn, passwordHint, login
className={styles.submitButton} className={styles.submitButton}
disabled={isLoggingIn} disabled={isLoggingIn}
> >
{isLoggingIn ? 'Logging in...' : 'Log in'} {isLoggingIn ? t('login.form.submit-loading-label', 'Logging in...') : t('login.form.submit-label', 'Log in')}
</Button> </Button>
{children} {children}
</form> </form>

View File

@ -7,7 +7,7 @@ import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime'; import { config } from '@grafana/runtime';
import { Alert, HorizontalGroup, LinkButton, useStyles2 } from '@grafana/ui'; import { Alert, HorizontalGroup, LinkButton, useStyles2 } from '@grafana/ui';
import { Branding } from 'app/core/components/Branding/Branding'; import { Branding } from 'app/core/components/Branding/Branding';
import { t } from 'app/core/internationalization'; import { t, Trans } from 'app/core/internationalization';
import { ChangePassword } from '../ForgottenPassword/ChangePassword'; import { ChangePassword } from '../ForgottenPassword/ChangePassword';
@ -54,7 +54,7 @@ export const LoginPage = () => {
fill="text" fill="text"
href={`${config.appSubUrl}/user/password/send-reset-email`} href={`${config.appSubUrl}/user/password/send-reset-email`}
> >
Forgot your password? <Trans i18nKey="login.forgot-password">Forgot your password?</Trans>
</LinkButton> </LinkButton>
)} )}
</HorizontalGroup> </HorizontalGroup>

View File

@ -5,6 +5,7 @@ import React from 'react';
import { GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data'; import { GrafanaTheme2, DEFAULT_SAML_NAME } from '@grafana/data';
import { Icon, IconName, LinkButton, useStyles2, useTheme2, VerticalGroup } from '@grafana/ui'; import { Icon, IconName, LinkButton, useStyles2, useTheme2, VerticalGroup } from '@grafana/ui';
import config from 'app/core/config'; import config from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export interface LoginService { export interface LoginService {
bgColor: string; bgColor: string;
@ -150,7 +151,9 @@ export const LoginServiceButtons = () => {
return ( return (
<VerticalGroup> <VerticalGroup>
<LoginDivider /> <LoginDivider />
{Object.entries(enabledServices).map(([key, service]) => ( {Object.entries(enabledServices).map(([key, service]) => {
const serviceName = service.name;
return (
<LinkButton <LinkButton
key={key} key={key}
className={getButtonStyleFor(service, styles, theme)} className={getButtonStyleFor(service, styles, theme)}
@ -159,9 +162,10 @@ export const LoginServiceButtons = () => {
fullWidth fullWidth
> >
<Icon className={styles.buttonIcon} name={service.icon} /> <Icon className={styles.buttonIcon} name={service.icon} />
Sign in with {service.name} <Trans i18nKey="login.services.sing-in-with-prefix">Sign in with {{ serviceName }}</Trans>
</LinkButton> </LinkButton>
))} );
})}
</VerticalGroup> </VerticalGroup>
); );
} }

View File

@ -3,6 +3,7 @@ import React from 'react';
import { LinkButton, VerticalGroup } from '@grafana/ui'; import { LinkButton, VerticalGroup } from '@grafana/ui';
import { getConfig } from 'app/core/config'; import { getConfig } from 'app/core/config';
import { Trans } from 'app/core/internationalization';
export const UserSignup = () => { export const UserSignup = () => {
const href = getConfig().verifyEmailEnabled ? `${getConfig().appSubUrl}/verify` : `${getConfig().appSubUrl}/signup`; const href = getConfig().verifyEmailEnabled ? `${getConfig().appSubUrl}/verify` : `${getConfig().appSubUrl}/signup`;
@ -10,7 +11,9 @@ export const UserSignup = () => {
return ( return (
<VerticalGroup> <VerticalGroup>
<div className={paddingTop}>New to Grafana?</div> <div className={paddingTop}>
<Trans i18nKey="login.signup.new-to-question">New to Grafana?</Trans>
</div>
<LinkButton <LinkButton
className={css({ className={css({
width: '100%', width: '100%',
@ -20,7 +23,7 @@ export const UserSignup = () => {
variant="secondary" variant="secondary"
fill="outline" fill="outline"
> >
Sign up <Trans i18nKey="login.signup.button-label">Sign up</Trans>
</LinkButton> </LinkButton>
</VerticalGroup> </VerticalGroup>
); );

View File

@ -673,6 +673,22 @@
"invalid-user-or-password": "Invalid username or password", "invalid-user-or-password": "Invalid username or password",
"title": "Login failed", "title": "Login failed",
"unknown": "Unknown error occurred" "unknown": "Unknown error occurred"
},
"forgot-password": "Forgot your password?",
"form": {
"password-label": "Password",
"password-required": "Password is required",
"submit-label": "Log in",
"submit-loading-label": "Logging in...",
"username-label": "Email or username",
"username-required": "Email or username is required"
},
"services": {
"sing-in-with-prefix": "Sign in with {{serviceName}}"
},
"signup": {
"button-label": "Sign up",
"new-to-question": "New to Grafana?"
} }
}, },
"nav": { "nav": {

View File

@ -673,6 +673,22 @@
"invalid-user-or-password": "Ĩʼnväľįđ ūşęřʼnämę őř päşşŵőřđ", "invalid-user-or-password": "Ĩʼnväľįđ ūşęřʼnämę őř päşşŵőřđ",
"title": "Ŀőģįʼn ƒäįľęđ", "title": "Ŀőģįʼn ƒäįľęđ",
"unknown": "Ůʼnĸʼnőŵʼn ęřřőř őččūřřęđ" "unknown": "Ůʼnĸʼnőŵʼn ęřřőř őččūřřęđ"
},
"forgot-password": "Főřģőŧ yőūř päşşŵőřđ?",
"form": {
"password-label": "Päşşŵőřđ",
"password-required": "Päşşŵőřđ įş řęqūįřęđ",
"submit-label": "Ŀőģ įʼn",
"submit-loading-label": "Ŀőģģįʼnģ įʼn...",
"username-label": "Ēmäįľ őř ūşęřʼnämę",
"username-required": "Ēmäįľ őř ūşęřʼnämę įş řęqūįřęđ"
},
"services": {
"sing-in-with-prefix": "Ŝįģʼn įʼn ŵįŧĥ {{serviceName}}"
},
"signup": {
"button-label": "Ŝįģʼn ūp",
"new-to-question": "Ńęŵ ŧő Ğřäƒäʼnä?"
} }
}, },
"nav": { "nav": {