Skip to content

Commit a5a269f

Browse files
committed
feat: implement internationalization across navigation and UI components
- Refactored SideNav, TopNav, OmniBar, StatusBar, and various pages to utilize the i18n hook for dynamic translations. - Updated route definitions to support localized labels for navigation items. - Enhanced user experience by replacing hardcoded strings with translation keys, ensuring consistency across the application. - Added new translation keys in both English and Japanese for improved localization support.
1 parent 2353739 commit a5a269f

File tree

16 files changed

+835
-161
lines changed

16 files changed

+835
-161
lines changed

src/components/nav/SideNav.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import React from "react";
22
import { NavLink } from "react-router-dom";
3-
import { routes } from "@/routes/registry";
3+
import { getRoutes } from "@/routes/registry";
44
import { Box, HStack, Text, VStack } from "@chakra-ui/react";
55
import { ColorModeButton } from "@/components/ui/color-mode";
6+
import { useI18n } from "@/hooks/useI18n";
67

78
export interface SideNavProps {
89
onNavigate?: () => void;
910
}
1011

1112
export function SideNav({ onNavigate }: SideNavProps = {}) {
13+
const { t } = useI18n();
14+
const routes = React.useMemo(() => getRoutes(t), [t]);
1215
return (
1316
<VStack align="stretch" p={2} gap={1} h="full">
1417
{routes.map((r) => (
@@ -30,7 +33,7 @@ export function SideNav({ onNavigate }: SideNavProps = {}) {
3033
>
3134
<HStack gap={2} align="center">
3235
<Text fontSize="sm" color="fg.muted">
33-
Theme
36+
{t("nav.theme")}
3437
</Text>
3538
<ColorModeButton />
3639
</HStack>

src/components/nav/TopNav.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import { ColorModeButton } from "@/components/ui/color-mode";
1111
import { useColorMode } from "@/components/ui/use-color-mode";
1212
import { LuMenu } from "react-icons/lu";
13+
import { useI18n } from "@/hooks/useI18n";
1314

1415
export interface TopNavProps {
1516
onOpenOmni?: () => void;
@@ -20,6 +21,7 @@ export interface TopNavProps {
2021
export function TopNav(
2122
{ onOpenOmni, onOpenMenu, showMenuButton = false }: TopNavProps,
2223
) {
24+
const { t } = useI18n();
2325
const lightLogoUrl = new URL(
2426
"../../assets/Floorp_Logo_OS_C_Light.png",
2527
import.meta.url,
@@ -54,7 +56,7 @@ export function TopNav(
5456
<HStack gap={{ base: 1, md: 1.5 }} flexShrink={0}>
5557
{showMenuButton && (
5658
<IconButton
57-
aria-label="Open menu"
59+
aria-label={t("nav.openMenu")}
5860
size="sm"
5961
variant="ghost"
6062
onClick={onOpenMenu}
@@ -86,7 +88,7 @@ export function TopNav(
8688
<Box
8789
role="button"
8890
tabIndex={0}
89-
aria-label="Open Omni Bar"
91+
aria-label={t("nav.openOmniBar")}
9092
onClick={() => onOpenOmni?.()}
9193
onKeyDown={(e) => {
9294
if (e.key === "Enter" || e.key === " ") onOpenOmni?.();
@@ -117,7 +119,7 @@ export function TopNav(
117119
h="full"
118120
>
119121
<Text fontSize="xs" whiteSpace="nowrap" lineHeight="1.5">
120-
Search or run…
122+
{t("nav.searchOrRun")}
121123
</Text>
122124
<HStack display={"flex"} align="center" gap={0.5}>
123125
<Kbd fontSize="xs"></Kbd>

src/components/omni/OmniBar.tsx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
VStack,
1212
} from "@chakra-ui/react";
1313
import { useNavigate } from "react-router-dom";
14+
import { useI18n } from "@/hooks/useI18n";
1415

1516
interface OmniBarItem {
1617
label: string;
@@ -24,30 +25,32 @@ export interface OmniBarProps {
2425
onClose: () => void;
2526
}
2627

27-
const DEFAULT_ITEMS: OmniBarItem[] = [
28+
const getDefaultItems = (t: (key: string) => string): OmniBarItem[] => [
2829
{
29-
label: "Go to Generate",
30+
label: t("omniBar.goToGenerate"),
3031
hint: "/generate",
3132
to: "/generate",
3233
kind: "navigate",
3334
},
34-
{ label: "Go to Fix", hint: "/fix", to: "/fix", kind: "navigate" },
35-
{ label: "Run Workflow", hint: "/run", to: "/run", kind: "navigate" },
36-
{ label: "Open Plugins", hint: "/plugins", to: "/plugins", kind: "navigate" },
35+
{ label: t("omniBar.goToFix"), hint: "/fix", to: "/fix", kind: "navigate" },
36+
{ label: t("omniBar.runWorkflow"), hint: "/run", to: "/run", kind: "navigate" },
37+
{ label: t("omniBar.openPlugins"), hint: "/plugins", to: "/plugins", kind: "navigate" },
3738
];
3839

3940
export function OmniBar({ isOpen, onClose }: OmniBarProps) {
41+
const { t } = useI18n();
4042
const [query, setQuery] = React.useState("");
4143
const [active, setActive] = React.useState(0);
4244
const navigate = useNavigate();
4345

4446
const items = React.useMemo(() => {
47+
const defaultItems = getDefaultItems(t);
4548
const q = query.trim().toLowerCase();
46-
if (!q) return DEFAULT_ITEMS;
47-
return DEFAULT_ITEMS.filter((i) =>
49+
if (!q) return defaultItems;
50+
return defaultItems.filter((i) =>
4851
i.label.toLowerCase().includes(q) || i.hint?.toLowerCase().includes(q)
4952
);
50-
}, [query]);
53+
}, [query, t]);
5154

5255
React.useEffect(() => {
5356
function onKey(e: KeyboardEvent) {
@@ -90,25 +93,25 @@ export function OmniBar({ isOpen, onClose }: OmniBarProps) {
9093
borderWidth="1px"
9194
>
9295
<HStack px={{ base: 2, md: 3 }} py={{ base: 1.5, md: 2 }} borderBottomWidth="1px" justify="space-between">
93-
<Text fontWeight="medium" fontSize={{ base: "sm", md: "md" }}>Omni Bar</Text>
96+
<Text fontWeight="medium" fontSize={{ base: "sm", md: "md" }}>{t("omniBar.title")}</Text>
9497
<HStack color="fg.muted" display={{ base: "none", sm: "flex" }} gap={1}>
9598
<Kbd fontSize="xs">Esc</Kbd>
96-
<Text fontSize="xs">to close</Text>
99+
<Text fontSize="xs">{t("omniBar.toClose")}</Text>
97100
</HStack>
98101
</HStack>
99102
<Box p={{ base: 2, md: 3 }}>
100103
<Input
101104
autoFocus
102105
size={{ base: "md", md: "lg" }}
103-
placeholder="Search commands, navigate, or ask…"
106+
placeholder={t("omniBar.searchPlaceholder")}
104107
onChange={(e) => {
105108
setQuery(e.target.value);
106109
setActive(0);
107110
}}
108111
/>
109112
<VStack align="stretch" gap={1} mt={3} maxH={{ base: "50vh", md: "60vh" }} overflowY="auto">
110113
{items.length === 0
111-
? <Box px={2} py={3} color="fg.muted" fontSize={{ base: "xs", md: "sm" }}>No results</Box>
114+
? <Box px={2} py={3} color="fg.muted" fontSize={{ base: "xs", md: "sm" }}>{t("omniBar.noResults")}</Box>
112115
: (
113116
items.map((it, idx) => (
114117
<Suggestion
@@ -137,12 +140,12 @@ export function OmniBar({ isOpen, onClose }: OmniBarProps) {
137140
</HStack>
138141
<HStack gap={1}>
139142
<Kbd fontSize="xs">Enter</Kbd>
140-
<Text>to run</Text>
143+
<Text>{t("omniBar.toRun")}</Text>
141144
</HStack>
142145
</HStack>
143146
<HStack justify="flex-end" mt={2}>
144147
<Button size="sm" variant="outline" onClick={onClose} minH={{ base: "36px", md: "auto" }}>
145-
Close
148+
{t("omniBar.close")}
146149
</Button>
147150
</HStack>
148151
</Box>

src/components/status/StatusBar.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import React from "react";
22
import { Badge, Box, HStack, Spacer, Text } from "@chakra-ui/react";
33
import { useVersionPing } from "@/hooks";
4+
import { useI18n } from "@/hooks/useI18n";
45

56
export function StatusBar() {
7+
const { t } = useI18n();
68
const [grpc, setGrpc] = React.useState<
79
"connected" | "connecting" | "disconnected"
810
>("connecting");
@@ -33,7 +35,7 @@ export function StatusBar() {
3335
}}
3436
>
3537
<HStack gap={2} flexShrink={0}>
36-
<Text whiteSpace="nowrap">Automotor Status</Text>
38+
<Text whiteSpace="nowrap">{t("statusBar.automotorStatus")}</Text>
3739
<Badge
3840
colorPalette={grpc === "connected"
3941
? "green"
@@ -42,7 +44,7 @@ export function StatusBar() {
4244
: "red"}
4345
fontSize={{ base: "xs", md: "sm" }}
4446
>
45-
{grpc}
47+
{t(`statusBar.${grpc}`)}
4648
</Badge>
4749
</HStack>
4850

@@ -61,7 +63,7 @@ export function StatusBar() {
6163
? (
6264
<HStack gap={2} flexShrink={0}>
6365
<Text display={{ base: "none", sm: "block" }} whiteSpace="nowrap">
64-
Version:
66+
{t("statusBar.version")}
6567
</Text>
6668
<Badge colorPalette="gray" fontSize={{ base: "xs", md: "sm" }}>
6769
{version}

0 commit comments

Comments
 (0)