fix(i18n): localize generated labels without changing saved content
This commit is contained in:
@@ -4,6 +4,7 @@ import { Box, Button, Chip, Paper, Stack, Typography } from "@mui/material";
|
||||
|
||||
import { CvTheme, getVisibleCvThemes } from "../cvBuilder";
|
||||
import { useI18n } from "../i18n/I18nProvider";
|
||||
import type { TranslationKey } from "../i18n/translations";
|
||||
import CvTemplateThumbnail from "./CvTemplateThumbnail";
|
||||
|
||||
type Props = {
|
||||
@@ -15,8 +16,20 @@ type Props = {
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
const templateLabels = new Map<string, [TranslationKey, TranslationKey, TranslationKey]>([
|
||||
["modern", ["cvTemplateModernName", "cvTemplateCategoryModern", "cvTemplateModernDescription"]],
|
||||
["minimal", ["cvTemplateMinimalName", "cvTemplateCategoryMinimal", "cvTemplateMinimalDescription"]],
|
||||
["executive", ["cvTemplateExecutiveName", "cvTemplateCategoryExecutive", "cvTemplateExecutiveDescription"]],
|
||||
["technical", ["cvTemplateTechnicalName", "cvTemplateCategoryTechnical", "cvTemplateTechnicalDescription"]],
|
||||
["ats-classic", ["cvTemplateAtsClassicName", "cvTemplateCategoryAts", "cvTemplateAtsClassicDescription"]],
|
||||
["nordic", ["cvTemplateNordicName", "cvTemplateCategoryModern", "cvTemplateNordicDescription"]],
|
||||
["elegant", ["cvTemplateElegantName", "cvTemplateCategoryCreative", "cvTemplateElegantDescription"]],
|
||||
["creative", ["cvTemplateCreativeName", "cvTemplateCategoryCreative", "cvTemplateCreativeDescription"]],
|
||||
["code", ["cvTemplateCodeName", "cvTemplateCategoryTechnical", "cvTemplateCodeDescription"]],
|
||||
]);
|
||||
|
||||
export default function CvTemplateGallery({ themes, selectedId, onSelect, previewHeight = 170, showDescriptions = true, disabled = false }: Props) {
|
||||
const { t } = useI18n();
|
||||
const { t, language } = useI18n();
|
||||
const id = useId();
|
||||
const [atsOnly, setAtsOnly] = useState(true);
|
||||
const visibleThemes = useMemo(() => getVisibleCvThemes(themes, atsOnly, selectedId), [atsOnly, selectedId, themes]);
|
||||
@@ -33,16 +46,18 @@ export default function CvTemplateGallery({ themes, selectedId, onSelect, previe
|
||||
const active = theme.id === selectedId;
|
||||
const locked = theme.available === false;
|
||||
const unavailable = locked || disabled;
|
||||
const labels = language === "nb" ? templateLabels.get(theme.id) : undefined;
|
||||
const name = labels ? t(labels[0]) : theme.name;
|
||||
return (
|
||||
<Paper key={theme.id} variant="outlined" role="button" tabIndex={unavailable ? -1 : 0} aria-label={theme.name} aria-describedby={`${id}-${theme.id}-category ${showDescriptions ? `${id}-${theme.id}-description ` : ""}${id}-${theme.id}-features`} aria-disabled={unavailable} aria-pressed={active}
|
||||
<Paper key={theme.id} variant="outlined" role="button" tabIndex={unavailable ? -1 : 0} aria-label={name} aria-describedby={`${id}-${theme.id}-category ${showDescriptions ? `${id}-${theme.id}-description ` : ""}${id}-${theme.id}-features`} aria-disabled={unavailable} aria-pressed={active}
|
||||
onClick={() => { if (!unavailable) onSelect(theme); }}
|
||||
onKeyDown={(event) => { if (!unavailable && (event.key === "Enter" || event.key === " ")) { event.preventDefault(); onSelect(theme); } }}
|
||||
sx={{ p: 1, cursor: unavailable ? "not-allowed" : "pointer", position: "relative", minWidth: 0, overflowWrap: "anywhere", borderColor: active ? "primary.main" : "divider", borderWidth: active ? 2 : 1, "&:hover": unavailable ? undefined : { borderColor: "primary.main" } }}>
|
||||
{active && <CheckCircleIcon aria-label={t("cvEditorSelectedTemplate")} color="primary" sx={{ position: "absolute", zIndex: 2, top: 6, right: 6, bgcolor: "background.paper", borderRadius: "50%" }} />}
|
||||
<Box sx={{ mb: 1 }}><CvTemplateThumbnail theme={theme} height={previewHeight} /></Box>
|
||||
<Typography variant="body2" sx={{ fontWeight: 750 }}>{theme.name}</Typography>
|
||||
<Typography id={`${id}-${theme.id}-category`} variant="caption" color="text.secondary" sx={{ display: "block" }}>{theme.category}</Typography>
|
||||
{showDescriptions && <Typography id={`${id}-${theme.id}-description`} variant="caption" color="text.secondary" sx={{ display: "block", mt: 0.25, lineHeight: 1.35 }}>{theme.description}</Typography>}
|
||||
<Typography variant="body2" sx={{ fontWeight: 750 }}>{name}</Typography>
|
||||
<Typography id={`${id}-${theme.id}-category`} variant="caption" color="text.secondary" sx={{ display: "block" }}>{labels ? t(labels[1]) : theme.category}</Typography>
|
||||
{showDescriptions && <Typography id={`${id}-${theme.id}-description`} variant="caption" color="text.secondary" sx={{ display: "block", mt: 0.25, lineHeight: 1.35 }}>{labels ? t(labels[2]) : theme.description}</Typography>}
|
||||
<Stack id={`${id}-${theme.id}-features`} direction="row" spacing={0.5} alignItems="center" flexWrap="wrap" useFlexGap sx={{ mt: 0.75 }}>
|
||||
{theme.atsFriendly && <Chip size="small" label={t("cvEditorAtsFriendly")} color="success" variant="outlined" sx={{ height: 20, fontSize: 10 }} />}
|
||||
{theme.requiresPro && <Chip size="small" label={locked ? t("cvEditorPro") : t("cvEditorProUnlocked")} color="secondary" variant="outlined" sx={{ height: 20, fontSize: 10 }} />}
|
||||
|
||||
Reference in New Issue
Block a user