Skip to content

Commit 76827bf

Browse files
feat(i18n): Create LanguageSelector to validate feature
1 parent 93c901a commit 76827bf

9 files changed

Lines changed: 79 additions & 3 deletions

File tree

webapp/.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,7 @@ dist-ssr
2323
*.sln
2424
*.sw?
2525

26-
METABASE_LOGIN.json
26+
METABASE_LOGIN.json
27+
28+
# Translations
29+
public/locales

webapp/.prettierrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
"^@pages/(.*)$",
3838
"^@ui",
3939
"^@ui/(.*)$",
40+
"^@shared",
41+
"^@shared/(.*)$",
4042
"[../]",
4143
"[./]"
4244
],

webapp/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ npm run dev
2525
- `npm run preview` : Démarre le serveur à partir du build pour la production (dans le dist)
2626
- `npm run check:arch` : Vérifier si les imports du projet respectent le principe de l'architecture FSD.
2727
- `npm run arch:tree` : Génère un fichier text contenant l'arborescence du projet.
28+
- `npm run translations:update`: Upload les fichiers de traductions vers public/locales, depuis lequel sont servis les fichiers de traduction

webapp/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"format": "prettier . --write",
1515
"format:check": "prettier . --check",
1616
"lint": "eslint ./src",
17-
"lint:fix": "eslint ./src --fix"
17+
"lint:fix": "eslint ./src --fix",
18+
"translations:update": "./scripts/update-translations.sh"
1819
},
1920
"dependencies": {
2021
"@radix-ui/react-dialog": "^1.1.15",
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
3+
# Copy src/shared/i18n/translations/{files} -> public/locales/{files}
4+
5+
cp -R ./src/shared/i18n/translations/ public/locales/

webapp/src/components/Header.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import logo from "@assets/logo_all4trees.png";
55

66
import { Button } from "@ui/button";
77

8+
import { useTranslation } from "@shared/i18n";
9+
10+
import { LanguageSelecor } from "./LanguageSelector";
811
import { ModeToggle } from "./ModeToggle";
912

1013
interface HeaderProps {
@@ -14,6 +17,8 @@ interface HeaderProps {
1417
}
1518

1619
export function Header({ onLogout, onLogin, isLogin }: HeaderProps) {
20+
const { t } = useTranslation("translations");
21+
1722
return (
1823
<header className="bg-background border-b border-border px-6 py-4 relative z-40">
1924
<div className="mx-auto max-w-screen-2xl px-6 py-4">
@@ -41,6 +46,8 @@ export function Header({ onLogout, onLogin, isLogin }: HeaderProps) {
4146
</Button>
4247
)}
4348
<ModeToggle />
49+
<p>{t("helloWorld")}</p>
50+
<LanguageSelecor />
4451
</div>
4552
</div>
4653
</div>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { LanguagesIcon } from "lucide-react";
2+
import type { FC } from "react";
3+
4+
import { Button } from "@ui/button";
5+
import {
6+
DropdownMenu,
7+
DropdownMenuContent,
8+
DropdownMenuItem,
9+
DropdownMenuTrigger,
10+
} from "@ui/dropdown-menu";
11+
12+
import { LANGUAGES, i18nInstance } from "@shared/i18n";
13+
14+
const LANGUAGES_CONFIGS = [
15+
{
16+
identifier: LANGUAGES.FRENCH,
17+
fullString: "Français",
18+
flag: "🇫🇷",
19+
},
20+
{
21+
identifier: LANGUAGES.ENGLISH,
22+
fullString: "English",
23+
flag: "🇬🇧",
24+
},
25+
] as const;
26+
27+
export const LanguageSelecor: FC = () => {
28+
return (
29+
<DropdownMenu>
30+
<DropdownMenuTrigger asChild>
31+
<Button
32+
variant="outline"
33+
size="icon"
34+
className="focus-visible:ring-0 focus-visible:ring-offset-0 shadow-none"
35+
>
36+
<LanguagesIcon className="h-[1.2rem] w-[1.2rem]" />
37+
<span className="sr-only">{i18nInstance.language.toUpperCase()}</span>
38+
</Button>
39+
</DropdownMenuTrigger>
40+
41+
<DropdownMenuContent
42+
className="bg-background"
43+
align="end"
44+
>
45+
{LANGUAGES_CONFIGS.map((config) => (
46+
<DropdownMenuItem
47+
onClick={() => i18nInstance.changeLanguage(config.identifier)}
48+
>
49+
{`${config.flag} - ${config.fullString}`}
50+
</DropdownMenuItem>
51+
))}
52+
</DropdownMenuContent>
53+
</DropdownMenu>
54+
);
55+
};

webapp/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"@widgets": ["./src/widgets/index.ts"],
2222
"@widgets/*": ["./src/widgets/*"],
2323
"@ui/*": ["./src/components/ui/*"],
24-
"@assets/*": ["./src/assets/*"]
24+
"@assets/*": ["./src/assets/*"],
25+
"@shared/*": ["./src/shared/*"]
2526
}
2627
}
2728
}

webapp/vite.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default defineConfig({
1717
"@assets": path.resolve(__dirname, "./src/assets"),
1818
"@pages": path.resolve(__dirname, "./src/pages"),
1919
"@ui": path.resolve(__dirname, "./src/components/ui"),
20+
"@shared": path.resolve(__dirname, "./src/shared"),
2021
},
2122
},
2223
plugins: [react(), tailwindcss()],

0 commit comments

Comments
 (0)