Skip to content

Commit 9b958aa

Browse files
Add internationalization (i18n) support and update UI components
- Introduced a new .cursorrules file outlining i18n best practices for React components, including guidelines for text handling and translation key organization. - Updated CheckboxInput.scss to enhance checkbox styling. - Added new translation keys for sign-in titles and subtitles in English, Spanish, and French. - Enhanced SignInPage and SignInForm components with i18n support, ensuring no hardcoded text is present. - Improved SignInPage.scss for better layout and visual consistency. - Established a structured approach for managing translations across the application.
1 parent 0642095 commit 9b958aa

File tree

14 files changed

+379
-94
lines changed

14 files changed

+379
-94
lines changed

.cursorrules

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Cursor Rules
2+
3+
## Always Use i18n for Text in React Files
4+
5+
Always use the internationalization (i18n) system for any text displayed to users in React components.
6+
7+
```typescript
8+
// ❌ AVOID hardcoded text
9+
<label>Email</label>
10+
<span>Don't have an account?</span>
11+
<button>Log in</button>
12+
13+
// ✅ PREFERRED - Use t() function from react-i18next
14+
<label>{t('label.email', { ns: 'auth' })}</label>
15+
<span>{t('no-account', { ns: 'auth' })}</span>
16+
<button>{t('signin', { ns: 'auth' })}</button>
17+
```
18+
19+
### Translation Key Guidelines:
20+
- Use namespaces to organize translations (e.g., { ns: 'auth' })
21+
- Use hierarchical keys with dots for organization (e.g., 'label.email')
22+
- Ensure all keys are defined in the appropriate translation files
23+
24+
### Common Namespaces:
25+
- 'common' - app-wide common labels and messages
26+
- 'auth' - authentication related texts
27+
- 'errors' - error messages
28+
- 'validation' - form validation messages
29+
30+
This rule ensures our application supports multiple languages and facilitates future translations.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
11
ion-checkbox.ls-checkbox-input {
22
width: 100%;
3+
--checkbox-label-justify-content: flex-start;
4+
--checkbox-label-padding-start: 0.5rem;
5+
6+
&::part(container) {
7+
order: -1;
8+
}
39
}

frontend/src/common/utils/i18n/resources/en/auth.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
"verification-code": "Verification Code"
2828
},
2929
"signin": "Sign In",
30+
"signin.title": "Log in",
31+
"signin.subtitle": "Login to access MedReport AI",
3032
"signup": "Sign Up",
3133
"signout": "Sign Out",
3234
"loading": "Loading...",

frontend/src/common/utils/i18n/resources/en/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
{
2+
"app": {
3+
"name": "MEDReport AI"
4+
},
25
"confirm-prompt": "Are you sure?",
36
"created": "created",
47
"deleted": "deleted",

frontend/src/common/utils/i18n/resources/es/auth.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@
1414
"remember-me": "Acuérdate de mí",
1515
"username": "Nombre de usuario"
1616
},
17-
"signin": "Iniciar sesión"
17+
"signin": "Iniciar sesión",
18+
"signin.title": "Iniciar sesión",
19+
"signin.subtitle": "Iniciar sesión para acceder a MEDReport AI"
1820
}

frontend/src/common/utils/i18n/resources/es/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,8 @@
7575
"chat": {
7676
"title": "Asistente IA"
7777
}
78+
},
79+
"app": {
80+
"name": "MEDReport AI"
7881
}
7982
}

frontend/src/common/utils/i18n/resources/fr/auth.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
"part2": "données JSONPlaceholder",
88
"part3": "Essayez un nom d'utilisateur comme ",
99
"part4": " ou ",
10-
"part5": "Vous pouvez utiliser nimporte quelle valeur comme mot de passe."
10+
"part5": "Vous pouvez utiliser n'importe quelle valeur comme mot de passe."
1111
},
1212
"label": {
1313
"password": "Mot de passe",
1414
"remember-me": "Souviens-toi de moi",
1515
"username": "Nom d'utilisateur"
1616
},
17-
"signin": "Se connecter"
17+
"signin": "Se connecter",
18+
"signin.title": "Se connecter",
19+
"signin.subtitle": "Connectez-vous pour accéder à MEDReport AI"
1820
}

frontend/src/common/utils/i18n/resources/fr/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,8 @@
7575
"chat": {
7676
"title": "Assistant IA"
7777
}
78+
},
79+
"app": {
80+
"name": "MEDReport AI"
7881
}
7982
}
Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,63 @@
11
.ls-signin-page {
2-
&__container {
3-
max-width: 576px;
2+
--ion-background-color: #1a233f;
3+
4+
&__background {
5+
width: 100%;
6+
height: 100%;
7+
display: flex;
8+
flex-direction: column;
9+
align-items: center;
10+
padding: 2rem 1.5rem;
11+
}
12+
13+
&__logo-container {
14+
display: flex;
15+
align-items: center;
16+
justify-content: center;
17+
margin-bottom: 2.5rem;
18+
}
19+
20+
&__logo {
21+
width: 3.5rem;
22+
height: auto;
23+
margin-right: 0.75rem;
24+
}
25+
26+
&__logo-text {
27+
color: white;
28+
font-size: 1.75rem;
29+
font-weight: 600;
30+
}
31+
32+
&__card {
33+
width: 100%;
34+
max-width: 30rem;
35+
background-color: white;
36+
border-radius: 1.5rem;
37+
padding: 2.5rem 2rem;
38+
box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
39+
}
40+
41+
&__header {
42+
margin-bottom: 2.5rem;
43+
44+
h1 {
45+
font-size: 2rem;
46+
font-weight: 600;
47+
color: #333;
48+
margin-bottom: 0.5rem;
49+
margin-top: 0;
50+
}
51+
52+
p {
53+
font-size: 1.125rem;
54+
color: #666;
55+
margin: 0;
56+
}
457
}
558

659
&__form {
7-
margin: 2rem 0;
60+
width: 100%;
61+
margin: 0;
862
}
963
}

frontend/src/pages/Auth/SignIn/SignInPage.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
import { IonContent, IonPage } from '@ionic/react';
1+
import { IonContent, IonPage, IonImg } from '@ionic/react';
22
import { useTranslation } from 'react-i18next';
33

44
import './SignInPage.scss';
55
import { PropsWithTestId } from 'common/components/types';
66
import ProgressProvider from 'common/providers/ProgressProvider';
7-
import Header from 'common/components/Header/Header';
87
import SignInForm from './components/SignInForm';
9-
import Container from 'common/components/Content/Container';
8+
import logo from 'assets/logo_ls.png';
109

1110
/**
1211
* Properties for the `SignInPage` component.
@@ -24,12 +23,22 @@ const SignInPage = ({ testid = 'page-signin' }: SignInPageProps): JSX.Element =>
2423
return (
2524
<IonPage className="ls-signin-page" data-testid={testid}>
2625
<ProgressProvider>
27-
<Header title={t('ionic-playground')} />
28-
2926
<IonContent fullscreen className="ion-padding">
30-
<Container className="ls-signin-page__container" fixed>
31-
<SignInForm className="ls-signin-page__form" />
32-
</Container>
27+
<div className="ls-signin-page__background">
28+
<div className="ls-signin-page__logo-container">
29+
<IonImg src={logo} alt="Logo" className="ls-signin-page__logo" />
30+
<span className="ls-signin-page__logo-text">{t('app.name', { ns: 'common' })}</span>
31+
</div>
32+
33+
<div className="ls-signin-page__card">
34+
<div className="ls-signin-page__header">
35+
<h1>{t('signin.title', { ns: 'auth' })}</h1>
36+
<p>{t('signin.subtitle', { ns: 'auth' })}</p>
37+
</div>
38+
39+
<SignInForm className="ls-signin-page__form" />
40+
</div>
41+
</div>
3342
</IonContent>
3443
</ProgressProvider>
3544
</IonPage>

0 commit comments

Comments
 (0)