fix(i18n): close shared ui gaps

This commit is contained in:
cesnimda
2026-08-29 22:52:24 +02:00
parent 3c9b22c97e
commit 6210909b62
11 changed files with 35 additions and 15 deletions
@@ -515,7 +515,7 @@ export default function AddJobModal({ open, onClose, onCreated, initialUrl }: Pr
<ListItem key={match.id} sx={{ px: 0 }}>
<ListItemText
primary={`${match.company} - ${match.jobTitle}`}
secondary={`${match.reason}${match.status}${new Date(match.dateApplied).toLocaleDateString()}`}
secondary={`${match.reason}${match.status}${new Date(match.dateApplied).toLocaleDateString(language === "nb" ? "nb-NO" : "en")}`}
/>
</ListItem>
))}
@@ -488,7 +488,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
) : null}
<Box sx={{ display: "flex", justifyContent: "space-between", gap: 1, alignItems: "flex-end", mt: 0.75 }}>
<Typography variant="caption" sx={{ color: "text.secondary" }}>
{isMe ? t("correspondenceMe") : t("correspondenceCompany")}{m.channel ? ` - ${m.channel}` : ""}{m.date ? ` - ${new Date(m.date).toLocaleString()}` : ""}
{isMe ? t("correspondenceMe") : t("correspondenceCompany")}{m.channel ? ` - ${m.channel}` : ""}{m.date ? ` - ${new Date(m.date).toLocaleString(language === "nb" ? "nb-NO" : "en")}` : ""}
</Typography>
<IconButton size="small" aria-label={t("correspondenceDeleteTitle")} onClick={() => void deleteMessage(m.id)} sx={{ color: "text.secondary" }}>
<DeleteOutlineIcon fontSize="small" />
@@ -654,7 +654,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
))}
</Box>
) : null}
{gmailStatus.lastSyncedAt ? <Chip label={t("correspondenceLastSynced", { date: new Date(gmailStatus.lastSyncedAt).toLocaleString() })} size="small" /> : null}
{gmailStatus.lastSyncedAt ? <Chip label={t("correspondenceLastSynced", { date: new Date(gmailStatus.lastSyncedAt).toLocaleString(language === "nb" ? "nb-NO" : "en") })} size="small" /> : null}
{gmailStatus.lastSyncAttemptedAt ? <Chip label={t("correspondenceSyncChecked", { date: new Date(gmailStatus.lastSyncAttemptedAt).toLocaleString(language === "nb" ? "nb-NO" : "en") })} size="small" variant="outlined" /> : null}
{gmailStatus.lastSyncStatus === "error" && gmailStatus.lastSyncError ? <Chip label={t("correspondenceSyncIssue", { error: gmailStatus.lastSyncError })} size="small" color="warning" variant="outlined" /> : null}
{linkedThreadIds.length > 0 ? (
@@ -710,7 +710,7 @@ export default function Correspondence({ jobId, jobContext }: { jobId: number; j
<ListItemButton sx={{ alignItems: "flex-start", px: 0, py: 1 }}>
<ListItemText
secondaryTypographyProps={{ component: "div" }}
primary={<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}><Typography sx={{ fontWeight: 700 }}>{message.subject || t("correspondenceNoSubject")}</Typography><Typography variant="caption" sx={{ color: "text.secondary" }}>{message.date ? new Date(message.date).toLocaleString() : ""}</Typography></Box>}
primary={<Box sx={{ display: "flex", justifyContent: "space-between", gap: 2, alignItems: "center", flexWrap: "wrap" }}><Typography sx={{ fontWeight: 700 }}>{message.subject || t("correspondenceNoSubject")}</Typography><Typography variant="caption" sx={{ color: "text.secondary" }}>{message.date ? new Date(message.date).toLocaleString(language === "nb" ? "nb-NO" : "en") : ""}</Typography></Box>}
secondary={<Box component="span" sx={{ mt: 0.5, display: "block" }}>
<Typography component="span" variant="body2" sx={{ color: "text.primary", display: "block" }}>{t("correspondenceFromLabel", { value: message.from || t("correspondenceUnknown") })}</Typography>
<Typography component="span" variant="body2" sx={{ color: "text.secondary", mt: 0.25, display: "block" }}>{message.snippet}</Typography>
@@ -654,7 +654,7 @@ export default function DashboardView() {
<Box key={series.tag}>
<Box sx={{ display: "flex", justifyContent: "space-between", mb: 0.5, gap: 1 }}>
<Typography variant="body2" sx={{ fontWeight: 800, overflowWrap: "anywhere" }}>{series.tag}</Typography>
<Typography variant="caption" sx={{ color: "text.secondary" }}>{series.counts.reduce((sum, value) => sum + value, 0)} total</Typography>
<Typography variant="caption" sx={{ color: "text.secondary" }}>{t("dashboardTotalCount", { count: series.counts.reduce((sum, value) => sum + value, 0) })}</Typography>
</Box>
<Box sx={{ display: "grid", gridTemplateColumns: `repeat(${series.counts.length}, 1fr)`, gap: 0.5 }}>
{series.counts.map((count, i) => (
+2 -2
View File
@@ -771,7 +771,7 @@ export default function JobTable({ refreshToken, pageSize, onPageSizeChange, col
<Table size="small" sx={{ minWidth: 980 }}>
<TableHead>
<TableRow>
<TableCell padding="checkbox"><Checkbox checked={selectedAllOnPage} indeterminate={selectedIds.length > 0 && !selectedAllOnPage} onChange={(e) => toggleSelectAll(e.target.checked)} /></TableCell>
<TableCell padding="checkbox"><Checkbox inputProps={{ "aria-label": t("jobTableSelectAll") }} checked={selectedAllOnPage} indeterminate={selectedIds.length > 0 && !selectedAllOnPage} onChange={(e) => toggleSelectAll(e.target.checked)} /></TableCell>
<TableCell sortDirection={sortBy === "company" ? sortDir : false}><TableSortLabel active={sortBy === "company"} direction={sortBy === "company" ? sortDir : "asc"} onClick={() => requestSort("company")}>{t("jobTableCompany")}</TableSortLabel></TableCell>
<TableCell sortDirection={sortBy === "jobTitle" ? sortDir : false}><TableSortLabel active={sortBy === "jobTitle"} direction={sortBy === "jobTitle" ? sortDir : "asc"} onClick={() => requestSort("jobTitle")}>{t("jobTableRole")}</TableSortLabel></TableCell>
<TableCell sortDirection={sortBy === "location" ? sortDir : false}><TableSortLabel active={sortBy === "location"} direction={sortBy === "location" ? sortDir : "asc"} onClick={() => requestSort("location")}>{t("jobTableLocation")}</TableSortLabel></TableCell>
@@ -809,7 +809,7 @@ export default function JobTable({ refreshToken, pageSize, onPageSizeChange, col
"&:focus-visible": { outline: "3px solid", outlineColor: "primary.main", outlineOffset: -3 },
}}
>
<TableCell padding="checkbox"><Checkbox checked={isSelected} onChange={(e) => toggleSelected(job.id, e.target.checked)} /></TableCell>
<TableCell padding="checkbox"><Checkbox inputProps={{ "aria-label": t("jobTableSelectJob", { title: job.jobTitle }) }} checked={isSelected} onChange={(e) => toggleSelected(job.id, e.target.checked)} /></TableCell>
<TableCell sx={{ minWidth: 140, fontWeight: 700 }}>{job.company?.name ?? ""}</TableCell>
<TableCell>
<Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }}>
@@ -1,6 +1,7 @@
import React, { useState } from "react";
import CloseIcon from "@mui/icons-material/Close";
import { Alert, Button, IconButton, Stack, Typography } from "@mui/material";
import { useOptionalI18n } from "../i18n/I18nProvider";
type Props = {
featureKey: string;
@@ -13,6 +14,7 @@ function storageKey(featureKey: string) {
}
export default function ProFeatureNotice({ featureKey, title, children }: Props) {
const i18n = useOptionalI18n();
const [dismissed, setDismissed] = useState(() => {
if (typeof window === "undefined") return false;
try {
@@ -38,8 +40,8 @@ export default function ProFeatureNotice({ featureKey, title, children }: Props)
severity="info"
action={(
<Stack direction="row" spacing={0.5} alignItems="center">
<Button href="/settings" size="small">View Pro</Button>
<IconButton size="small" aria-label={`Dismiss ${title}`} onClick={dismiss}>
<Button href="/settings" size="small">{i18n?.t("proFeatureView") ?? "View Pro"}</Button>
<IconButton size="small" aria-label={i18n?.t("proFeatureDismiss", { title }) ?? `Dismiss ${title}`} onClick={dismiss}>
<CloseIcon fontSize="small" />
</IconButton>
</Stack>
+4 -2
View File
@@ -1,9 +1,10 @@
import React from "react";
import { Autocomplete, Chip, TextField } from "@mui/material";
import { useI18n } from "../i18n/I18nProvider";
export default function TagsInput({
label = "Tags",
label,
value,
onChange,
}: {
@@ -11,6 +12,7 @@ export default function TagsInput({
value: string[];
onChange: (next: string[]) => void;
}) {
const { t } = useI18n();
return (
<Autocomplete
multiple
@@ -28,7 +30,7 @@ export default function TagsInput({
<Chip variant="outlined" label={option} {...getTagProps({ index })} key={option} size="small" />
))
}
renderInput={(params) => <TextField {...params} label={label} placeholder="Add a tag and press Enter" />}
renderInput={(params) => <TextField {...params} label={label ?? t("cvEditorTags")} placeholder={t("tagsInputPlaceholder")} />}
/>
);
}