feat: workbench i18n

This commit is contained in:
JOYCEQL
2025-01-03 13:41:23 +08:00
committed by qingchen
parent fffd522b17
commit 0527c53031
13 changed files with 560 additions and 77 deletions
@@ -144,6 +144,7 @@ const Field = ({
);
return;
}
setShowPolishDialog(true);
}}
/>
</div>
@@ -3,6 +3,7 @@ import { useMemo } from "react";
import { motion } from "framer-motion";
import { Layout, Type, SpaceIcon, Palette } from "lucide-react";
import debounce from "lodash/debounce";
import { useTranslations } from "next-intl";
import {
Select,
SelectContent,
@@ -81,6 +82,19 @@ export function SidePanel() {
} = activeResume || {};
const { themeColor } = globalSettings;
const t = useTranslations('workbench.sidePanel');
const fontOptions = [
{ value: "sans", label: t('typography.font.sans') },
{ value: "serif", label: t('typography.font.serif') },
{ value: "mono", label: t('typography.font.mono') },
];
const lineHeightOptions = [
{ value: "normal", label: t('typography.lineHeight.normal') },
{ value: "relaxed", label: t('typography.lineHeight.relaxed') },
{ value: "loose", label: t('typography.lineHeight.loose') },
];
const debouncedSetColor = useMemo(
() =>
@@ -122,7 +136,7 @@ export function SidePanel() {
animate={{ x: 0, opacity: 1 }}
>
<div className="p-4 space-y-4">
<SettingCard icon={Layout} title="布局">
<SettingCard icon={Layout} title={t('layout.title')}>
<LayoutSetting
menuSections={menuSections}
activeSection={activeSection}
@@ -139,13 +153,13 @@ export function SidePanel() {
onClick={handleCreateSection}
className="flex justify-center w-full rounded-lg items-center gap-2 py-2 px-3 text-sm font-medium text-primary bg-indigo-50"
>
{t('layout.addCustomSection')}
</motion.button>
</div>
</SettingCard>
{/* 主题色设置 */}
<SettingCard icon={Palette} title="主题色">
<SettingCard icon={Palette} title={t('theme.title')}>
<div className="space-y-4">
<div className="grid grid-cols-6 gap-2">
{THEME_COLORS.map((presetTheme) => (
@@ -186,7 +200,7 @@ export function SidePanel() {
<div className="flex flex-col gap-4">
<div className="text-sm text-gray-600 dark:text-gray-400">
{t('theme.custom')}
</div>
<motion.input
type="color"
@@ -198,11 +212,11 @@ export function SidePanel() {
</SettingCard>
{/* 排版设置 */}
<SettingCard icon={Type} title="排版">
<SettingCard icon={Type} title={t('typography.title')}>
<div className="space-y-6">
{/* <div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
字体
{t('typography.font.title')}
</Label>
<Select
value={globalSettings?.fontFamily}
@@ -220,16 +234,15 @@ export function SidePanel() {
</motion.div>
<SelectContent
className={cn(
theme === "dark"
? "bg-neutral-900 border-neutral-800 text-white"
: "bg-white border-gray-200"
"dark:bg-neutral-900 dark:border-neutral-800 text-white",
"bg-white border-gray-200"
)}
>
{fontOptions.map((font) => (
<SelectItem
key={font.value}
value={font.value}
className="cursor-pointer transition-colors focus:bg-gray-100 dark:text-neutral-200 dark:hover:bg-neutral-800 dark:focus:bg-neutral-800"
className="cursor-pointer transition-colors hover:bg-gray-100 focus:bg-gray-100 dark:text-neutral-200 dark:hover:bg-neutral-800 dark:focus:bg-neutral-800"
>
{font.label}
</SelectItem>
@@ -241,7 +254,7 @@ export function SidePanel() {
{/* 行高选择 */}
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('typography.lineHeight.title')}
</Label>
<div className="flex items-center gap-4">
<Slider
@@ -261,7 +274,7 @@ export function SidePanel() {
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('typography.baseFontSize.title')}
</Label>
<Select
value={globalSettings?.baseFontSize?.toString()}
@@ -279,8 +292,8 @@ export function SidePanel() {
</motion.div>
<SelectContent
className={cn(
"dark:bg-neutral-900 dark:border-neutral-800 text-white",
"bg-white text-gray-700 border-gray-200"
"dark:bg-neutral-900 dark:border-neutral-800 dark:text-white",
"bg-white border-gray-200"
)}
>
{[12, 13, 14, 15, 16, 18, 20, 24].map((size) => (
@@ -298,7 +311,7 @@ export function SidePanel() {
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('typography.headerSize.title')}
</Label>
<Select
value={globalSettings?.headerSize?.toString()}
@@ -335,7 +348,7 @@ export function SidePanel() {
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('typography.subheaderSize.title')}
</Label>
<Select
value={globalSettings?.subheaderSize?.toString()}
@@ -373,11 +386,11 @@ export function SidePanel() {
</SettingCard>
{/* 间距设置 */}
<SettingCard icon={SpaceIcon} title="间距">
<SettingCard icon={SpaceIcon} title={t('spacing.title')}>
<div className="space-y-6">
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('spacing.pagePadding.title')}
</Label>
<div className="flex items-center gap-4">
<Slider
@@ -397,7 +410,7 @@ export function SidePanel() {
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('spacing.sectionSpacing.title')}
</Label>
<div className="flex items-center gap-4">
<Slider
@@ -417,7 +430,7 @@ export function SidePanel() {
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('spacing.paragraphSpacing.title')}
</Label>
<div className="flex items-center gap-4">
<Slider
@@ -437,10 +450,10 @@ export function SidePanel() {
</SettingCard>
{/* 模式设置 */}
<SettingCard icon={SpaceIcon} title="模式">
<SettingCard icon={SpaceIcon} title={t('mode.title')}>
<div className="space-y-2">
<Label className="text-gray-600 dark:text-neutral-300">
{t('mode.useIconMode.title')}
</Label>
<div className="flex items-center gap-4">
<Switch
@@ -2,6 +2,7 @@
import React, { useState } from "react";
import { PlusCircle, GripVertical, Trash2, Eye, EyeOff } from "lucide-react";
import { Reorder, AnimatePresence, motion } from "framer-motion";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Switch } from "@/components/ui/switch";
@@ -30,6 +31,8 @@ const CustomField: React.FC<CustomFieldProps> = ({
onUpdate,
onDelete,
}) => {
const t = useTranslations("workbench.basicPanel");
return (
<Reorder.Item
value={field}
@@ -71,7 +74,7 @@ const CustomField: React.FC<CustomFieldProps> = ({
label: value,
})
}
placeholder="标签"
placeholder={t("customFields.placeholders.label")}
className={cn(
"bg-neutral-50 dark:bg-neutral-900",
"border-neutral-200 dark:border-neutral-700",
@@ -87,7 +90,7 @@ const CustomField: React.FC<CustomFieldProps> = ({
value: value,
})
}
placeholder="值"
placeholder={t("customFields.placeholders.value")}
className={cn(
"bg-neutral-50 dark:bg-neutral-900",
"border-neutral-200 dark:border-neutral-700",
@@ -142,6 +145,7 @@ const BasicPanel: React.FC = () => {
visible: field.visible ?? true,
}));
});
const t = useTranslations("workbench.basicPanel");
const handleBasicReorder = (newOrder: BasicFieldType[]) => {
setBasicFields(newOrder);
@@ -205,6 +209,7 @@ const BasicPanel: React.FC = () => {
customFields: newOrder,
});
};
const renderBasicField = (field: BasicFieldType) => {
const selectedIcon = basic?.icons?.[field.key] || "User";
@@ -258,7 +263,7 @@ const BasicPanel: React.FC = () => {
/>
)}
<div className=" w-[80px] ml-[4px] text-sm font-medium text-neutral-700 dark:text-neutral-200">
{field.label}
{t(`basicFields.${field.key}`)}
</div>
<div className="flex-1">
<Field
@@ -310,7 +315,7 @@ const BasicPanel: React.FC = () => {
<motion.div className="space-y-6">
<motion.div className="space-y-3">
<motion.h3 className="font-medium text-neutral-900 dark:text-neutral-200 px-1">
{t("basicField")}
</motion.h3>
<AnimatePresence mode="popLayout">
<Reorder.Group
@@ -327,7 +332,7 @@ const BasicPanel: React.FC = () => {
<motion.div className="space-y-3">
<motion.h3 className="font-medium text-neutral-900 dark:text-neutral-200 px-1">
{t("customField")}
</motion.h3>
<AnimatePresence mode="popLayout">
<Reorder.Group
@@ -355,7 +360,7 @@ const BasicPanel: React.FC = () => {
>
<Button onClick={addCustomField} className="w-full mt-4">
<PlusCircle className="w-4 h-4 mr-2" />
{t("customFields.addButton")}
</Button>
</motion.div>
</motion.div>
@@ -367,7 +372,7 @@ const BasicPanel: React.FC = () => {
>
<div className="flex items-center justify-between">
<motion.h3 className="font-medium text-neutral-900 dark:text-neutral-200 px-1">
Github
{t("githubContributions")}
</motion.h3>
<Switch
@@ -13,6 +13,7 @@ import { GripVertical, Eye, EyeOff, ChevronDown, Trash2 } from "lucide-react";
import { useState, useCallback } from "react";
import Field from "../Field";
import ThemeModal from "@/components/shared/ThemeModal";
import { useTranslations } from "next-intl";
interface EducationEditorProps {
education: Education;
@@ -25,6 +26,7 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
education,
onSave,
}) => {
const t = useTranslations("workbench.educationItem");
const handleChange = (field: keyof Education, value: string) => {
onSave({
...education,
@@ -37,40 +39,40 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
<div className="grid gap-5">
<div className="grid grid-cols-2 gap-4">
<Field
label="学校名称"
label={t("labels.school")}
value={education.school}
onChange={(value) => handleChange("school", value)}
placeholder="学校名称"
placeholder={t("placeholders.school")}
required
/>
<Field
label="所在地"
label={t("labels.location")}
value={education.location || ""}
onChange={(value) => handleChange("location", value)}
placeholder="城市"
placeholder={t("placeholders.location")}
/>
</div>
<div className="grid grid-cols-2 gap-4">
<Field
label="专业"
label={t("labels.major")}
value={education.major}
onChange={(value) => handleChange("major", value)}
placeholder="专业名称"
placeholder={t("placeholders.major")}
required
/>
<Field
label="学历"
label={t("labels.degree")}
value={education.degree}
onChange={(value) => handleChange("degree", value)}
placeholder="学历"
placeholder={t("placeholders.degree")}
required
/>
</div>
<div className="grid grid-cols-2 gap-4">
<Field
label="开始时间"
label={t("labels.startDate")}
value={education.startDate}
onChange={(value) => handleChange("startDate", value)}
type="date"
@@ -78,7 +80,7 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
required
/>
<Field
label="结束时间"
label={t("labels.endDate")}
value={education.endDate}
onChange={(value) => handleChange("endDate", value)}
type="date"
@@ -88,18 +90,18 @@ const EducationEditor: React.FC<EducationEditorProps> = ({
</div>
<Field
label="GPA"
label={t("labels.gpa")}
value={education.gpa || ""}
onChange={(value) => handleChange("gpa", value)}
placeholder="选填"
placeholder={t("placeholders.gpa")}
/>
<Field
label="在校经历"
label={t("labels.description")}
value={education.description}
onChange={(value) => handleChange("description", value)}
type="editor"
placeholder="描述你的在校表现、获奖经历等..."
placeholder={t("placeholders.description")}
/>
</div>
</div>
@@ -3,20 +3,22 @@ import { cn } from "@/lib/utils";
import { useResumeStore } from "@/store/useResumeStore";
import { Reorder } from "framer-motion";
import { PlusCircle } from "lucide-react";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import EducationItem from "./EducationItem";
import { Education } from "@/types/resume";
const EducationPanel = () => {
const t = useTranslations('workbench.educationPanel');
const { activeResume, updateEducation, updateEducationBatch } =
useResumeStore();
const { education = [] } = activeResume || {};
const handleCreateProject = () => {
const newEducation: Education = {
id: crypto.randomUUID(),
school: "家里蹲大学",
major: "",
degree: "",
school: t('defaultProject.school'),
major: t('defaultProject.major'),
degree: t('defaultProject.degree'),
startDate: "2015-09-01",
endDate: "2019-06-30",
description: "",
@@ -50,10 +52,11 @@ const EducationPanel = () => {
<Button onClick={handleCreateProject} className="w-full">
<PlusCircle className="w-4 h-4 mr-2" />
{t('addButton')}
</Button>
</Reorder.Group>
</div>
);
};
export default EducationPanel;
@@ -13,6 +13,7 @@ import Field from "../Field";
import { Experience } from "@/types/resume";
import ThemeModal from "@/components/shared/ThemeModal";
import { useResumeStore } from "@/store/useResumeStore";
import { useTranslations } from "next-intl";
interface ProjectEditorProps {
experience: Experience;
@@ -25,6 +26,8 @@ const ProjectEditor: React.FC<ProjectEditorProps> = ({
experience,
onSave,
}) => {
const t = useTranslations("workbench.experiencePanel");
const handleChange = (field: keyof Experience, value: string) => {
onSave({
...experience,
@@ -37,33 +40,33 @@ const ProjectEditor: React.FC<ProjectEditorProps> = ({
<div className="grid gap-5">
<div className="grid grid-cols-2 gap-4">
<Field
label="公司名称"
label={t("placeholders.company")}
value={experience.company}
onChange={(value) => handleChange("company", value)}
placeholder="项目名称"
placeholder={t("placeholders.company")}
required
/>
<Field
label="岗位"
label={t("placeholders.position")}
value={experience.position}
onChange={(value) => handleChange("position", value)}
placeholder="如:前端工程师"
placeholder={t("placeholders.position")}
required
/>
</div>
<Field
label="开始时间-结束时间"
label={t("placeholders.date")}
value={experience.date}
onChange={(value) => handleChange("date", value)}
placeholder="如:2023.01 - 2023.06"
placeholder={t("placeholders.date")}
required
/>
<Field
label="主要职责"
label={t("placeholders.details")}
value={experience.details}
onChange={(value) => handleChange("details", value)}
type="editor"
placeholder="简要描述项目的背景和目标..."
placeholder={t("placeholders.details")}
/>
</div>
</div>
@@ -3,21 +3,23 @@ import { cn } from "@/lib/utils";
import { Reorder } from "framer-motion";
import { PlusCircle } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useTranslations } from "next-intl";
import ExperienceItem from "./ExperienceItem";
import { Experience } from "@/types/resume";
import { useResumeStore } from "@/store/useResumeStore";
const ExperiencePanel = () => {
const t = useTranslations("workbench.experiencePanel");
const { activeResume, updateExperience, updateExperienceBatch } =
useResumeStore();
const { experience = [] } = activeResume || {};
const handleCreateProject = () => {
const newProject: Experience = {
id: crypto.randomUUID(),
company: "某科技有限公司",
position: "高级前端工程师",
date: "2020-至今",
details: "负责公司核心产品...",
company: t("defaultProject.company"),
position: t("defaultProject.position"),
date: t("defaultProject.date"),
details: t("defaultProject.details"),
visible: true,
};
updateExperience(newProject);
@@ -44,10 +46,11 @@ const ExperiencePanel = () => {
<Button onClick={handleCreateProject} className="w-full">
<PlusCircle className="w-4 h-4 mr-2" />
{t("addButton")}
</Button>
</Reorder.Group>
</div>
);
};
export default ExperiencePanel;
@@ -12,6 +12,7 @@ import { ChevronDown, Eye, EyeOff, GripVertical, Trash2 } from "lucide-react";
import { useCallback, useState } from "react";
import Field from "../Field";
import ThemeModal from "@/components/shared/ThemeModal";
import { useTranslations } from "next-intl";
interface Project {
id: string;
@@ -30,6 +31,7 @@ interface ProjectEditorProps {
}
const ProjectEditor: React.FC<ProjectEditorProps> = ({ project, onSave }) => {
const t = useTranslations("workbench.projectItem");
const handleChange = (field: keyof Project, value: string) => {
onSave({
...project,
@@ -42,33 +44,33 @@ const ProjectEditor: React.FC<ProjectEditorProps> = ({ project, onSave }) => {
<div className="grid gap-5">
<div className="grid grid-cols-2 gap-4">
<Field
label="项目名称"
label={t("labels.name")}
value={project.name}
onChange={(value) => handleChange("name", value)}
placeholder="项目名称"
placeholder={t("placeholders.name")}
required
/>
<Field
label="担任角色"
label={t("labels.role")}
value={project.role}
onChange={(value) => handleChange("role", value)}
placeholder="如:前端负责人"
placeholder={t("placeholders.role")}
required
/>
</div>
<Field
label="项目时间"
label={t("labels.date")}
value={project.date}
onChange={(value) => handleChange("date", value)}
placeholder="如:2023.01 - 2023.06"
placeholder={t("placeholders.date")}
required
/>
<Field
label="项目描述"
label={t("labels.description")}
value={project.description}
onChange={(value) => handleChange("description", value)}
type="editor"
placeholder="简要描述项目的背景和目标..."
placeholder={t("placeholders.description")}
/>
</div>
</div>
@@ -2,21 +2,23 @@ import { cn } from "@/lib/utils";
import { useResumeStore } from "@/store/useResumeStore";
import { Reorder } from "framer-motion";
import { PlusCircle } from "lucide-react";
import { useTranslations } from "next-intl";
import { Button } from "@/components/ui/button";
import ProjectItem from "./ProjectItem";
import { Project } from "@/types/resume";
const ProjectPanel = () => {
const t = useTranslations("workbench.projectPanel");
const { activeResume, updateProjects, updateProjectsBatch } =
useResumeStore();
const { projects = [] } = activeResume || {};
const handleCreateProject = () => {
const newProject: Project = {
id: crypto.randomUUID(),
name: "Project Name",
role: "Project Role",
date: "",
description: "",
name: t("defaultProject.name"),
role: t("defaultProject.role"),
date: t("defaultProject.date"),
description: t("defaultProject.description"),
visible: true,
};
updateProjects(newProject);
@@ -43,10 +45,11 @@ const ProjectPanel = () => {
<Button onClick={handleCreateProject} className="w-full">
<PlusCircle className="w-4 h-4 mr-2" />
{t("addButton")}
</Button>
</Reorder.Group>
</div>
);
};
export default ProjectPanel;
@@ -4,6 +4,7 @@ import { Download, Loader2 } from "lucide-react";
import { toast } from "sonner";
import { useResumeStore } from "@/store/useResumeStore";
import { Button } from "@/components/ui/button";
import { useTranslations } from "next-intl";
const getOptimizedStyles = () => {
const styleCache = new Map();
@@ -70,6 +71,7 @@ const PdfExport = () => {
const [isExporting, setIsExporting] = useState(false);
const { activeResume } = useResumeStore();
const { globalSettings = {}, title } = activeResume || {};
const t = useTranslations("pdfExport");
const handleExport = async () => {
const exportStartTime = performance.now();
@@ -118,10 +120,10 @@ const PdfExport = () => {
window.URL.revokeObjectURL(url);
console.log(`Total export took ${performance.now() - exportStartTime}ms`);
toast.success("PDF 导出成功!");
toast.success(t("toast.success"));
} catch (error) {
console.error("Export error:", error);
toast.error("PDF 导出失败,请重试");
toast.error(t("toast.error"));
} finally {
setIsExporting(false);
}
@@ -140,7 +142,7 @@ const PdfExport = () => {
) : (
<Download className="w-4 h-4" />
)}
<span>{isExporting ? "导出中..." : "导出 PDF"}</span>
<span>{isExporting ? t("button.exporting") : t("button.default")}</span>
</Button>
</div>
);
@@ -3,5 +3,5 @@ import { setUserLocale } from "@/i18n/db";
import { revalidatePath } from "next/cache";
export default async function updateLocale(locale: string) {
setUserLocale(locale);
revalidatePath("/app");
// revalidatePath("/app");
}
+223
View File
@@ -74,5 +74,228 @@
}
}
}
},
"pdfExport": {
"button": {
"exporting": "Exporting...",
"default": "Export PDF"
},
"toast": {
"success": "PDF exported successfully!",
"error": "PDF export failed, please try again"
}
},
"workbench": {
"sidePanel": {
"layout": {
"title": "Layout",
"addCustomSection": "Add Custom Section"
},
"theme": {
"title": "Theme Color",
"custom": "Custom"
},
"typography": {
"title": "Typography",
"font": {
"title": "Font",
"sans": "Sans-serif",
"serif": "Serif",
"mono": "Monospace"
},
"lineHeight": {
"title": "Line Height",
"normal": "Default",
"relaxed": "Relaxed",
"loose": "Loose"
},
"baseFontSize": {
"title": "Base Font Size"
},
"headerSize": {
"title": "Section Header Size"
},
"subheaderSize": {
"title": "Section Subheader Size"
}
},
"spacing": {
"title": "Spacing",
"pagePadding": {
"title": "Page Padding"
},
"sectionSpacing": {
"title": "Section Spacing"
},
"paragraphSpacing": {
"title": "Paragraph Spacing"
}
},
"mode": {
"title": "Mode",
"useIconMode": {
"title": "Compact Mode"
}
}
},
"basicPanel": {
"basicField": "Basic",
"customField": "Custom",
"customFields": {
"placeholders": {
"label": "Label",
"value": "Value"
},
"addButton": "Add Custom Field"
},
"basicFields": {
"name": "Name",
"title": "Title",
"email": "Email",
"phone": "Phone",
"website": "Website",
"location": "Location",
"birthDate": "Birth Date",
"employementStatus": "Employ"
},
"fieldVisibility": {
"show": "Show",
"hide": "Hide"
},
"githubContributions": "GitHub Contributions"
},
"experiencePanel": {
"title": "Work Experience",
"addButton": "Add Work Experience",
"defaultProject": {
"company": "Tech Company Ltd.",
"position": "Senior Frontend Engineer",
"date": "2020-Present",
"details": "Responsible for core product development..."
},
"placeholders": {
"company": "company name",
"position": "job title",
"date": "employment period",
"details": "job responsibilities and achievements"
}
},
"experienceItem": {
"labels": {
"company": "Company Name",
"position": "Position",
"date": "Employment Period",
"details": "Job Responsibilities"
},
"placeholders": {
"company": "Enter company name",
"position": "e.g., Frontend Engineer",
"date": "e.g., 2020-Present",
"details": "Describe your responsibilities and achievements in this role"
},
"buttons": {
"edit": "Edit",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete"
},
"visibility": {
"show": "Show",
"hide": "Hide"
}
},
"projectPanel": {
"title": "Project Experience",
"addButton": "Add Project",
"defaultProject": {
"name": "Personal Project",
"description": "Project Description",
"role": "Responsibilities",
"date": "2023.01 - 2023.06"
},
"placeholders": {
"name": "Project Name",
"description": "Briefly describe project background and goals",
"role": "Your role and responsibilities in the project",
"date": "Project time range",
"link": "Project link (optional)"
}
},
"projectItem": {
"labels": {
"name": "Project Name",
"role": "Project Role",
"date": "Project Period",
"description": "Project Description",
"technologies": "Tech Stack",
"link": "Project Link"
},
"placeholders": {
"name": "Enter project name",
"role": "Your role in the project",
"date": "Project time range",
"description": "Briefly describe project background and goals",
"technologies": "Technologies and tools used",
"link": "Project link (optional)"
},
"buttons": {
"edit": "Edit",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete"
},
"visibility": {
"show": "Show",
"hide": "Hide"
}
},
"educationPanel": {
"title": "Education",
"addButton": "Add Education",
"defaultProject": {
"school": "School Name",
"degree": "Degree",
"major": "Major",
"date": "2020.09 - 2024.06"
},
"placeholders": {
"school": "Enter school name",
"degree": "Select degree",
"major": "Enter major",
"date": "Enter study period"
}
},
"educationItem": {
"labels": {
"school": "School Name",
"degree": "Degree",
"major": "Major",
"date": "Study Period",
"description": "Description",
"gpa": "GPA",
"location": "Location",
"startDate": "Start Date",
"endDate": "End Date"
},
"placeholders": {
"school": "Enter school name",
"degree": "Select degree",
"major": "Enter major",
"date": "Enter study time range",
"description": "Enter school description",
"gpa": "Enter GPA",
"location": "Enter location"
},
"buttons": {
"edit": "Edit",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete"
},
"visibility": {
"show": "Show",
"hide": "Hide"
}
}
}
}
+223
View File
@@ -74,5 +74,228 @@
}
}
}
},
"pdfExport": {
"button": {
"exporting": "导出中...",
"default": "导出 PDF"
},
"toast": {
"success": "PDF 导出成功!",
"error": "PDF 导出失败,请重试"
}
},
"workbench": {
"sidePanel": {
"layout": {
"title": "布局",
"addCustomSection": "添加自定义模块"
},
"theme": {
"title": "主题色",
"custom": "自定义"
},
"typography": {
"title": "排版",
"font": {
"title": "字体",
"sans": "无衬线体",
"serif": "衬线体",
"mono": "等宽体"
},
"lineHeight": {
"title": "行高",
"normal": "默认",
"relaxed": "适中",
"loose": "宽松"
},
"baseFontSize": {
"title": "基础字号"
},
"headerSize": {
"title": "模块标题字号"
},
"subheaderSize": {
"title": "模块二级标题字号"
}
},
"spacing": {
"title": "间距",
"pagePadding": {
"title": "页边距"
},
"sectionSpacing": {
"title": "模块间距"
},
"paragraphSpacing": {
"title": "段落间距"
}
},
"mode": {
"title": "模式",
"useIconMode": {
"title": "简洁模式"
}
}
},
"basicPanel": {
"basicField": "基本信息",
"customField": "自定义字段",
"customFields": {
"placeholders": {
"label": "标签",
"value": "值"
},
"addButton": "添加自定义字段"
},
"basicFields": {
"name": "姓名",
"title": "职位",
"email": "邮箱",
"phone": "电话",
"website": "个人网站",
"location": "地址",
"birthDate": "出生日期",
"employementStatus": "求职状态"
},
"fieldVisibility": {
"show": "显示",
"hide": "隐藏"
},
"githubContributions": "GitHub 贡献"
},
"experiencePanel": {
"title": "工作经历",
"addButton": "添加工作经历",
"defaultProject": {
"company": "某科技有限公司",
"position": "高级前端工程师",
"date": "2020-至今",
"details": "负责公司核心产品..."
},
"placeholders": {
"company": "请输入公司名称",
"position": "请输入职位",
"date": "请输入工作时间",
"details": "请输入工作职责和成就"
}
},
"experienceItem": {
"labels": {
"company": "公司名称",
"position": "岗位",
"date": "工作时间",
"details": "工作职责"
},
"placeholders": {
"company": "请输入公司名称",
"position": "如:前端工程师",
"date": "如:2020-至今",
"details": "描述你在这份工作中的职责和成就"
},
"buttons": {
"edit": "编辑",
"save": "保存",
"cancel": "取消",
"delete": "删除"
},
"visibility": {
"show": "显示",
"hide": "隐藏"
}
},
"projectPanel": {
"title": "项目经历",
"addButton": "添加项目",
"defaultProject": {
"name": "个人项目",
"description": "项目描述",
"role": "负责内容",
"technologies": "技术栈",
"date": "2023.01 - 2023.06"
},
"placeholders": {
"name": "项目名称",
"description": "简要描述项目背景和目标",
"role": "你在项目中的角色和职责",
"technologies": "使用的技术和工具",
"date": "项目时间范围",
"link": "项目链接(可选)"
}
},
"projectItem": {
"labels": {
"name": "项目名称",
"role": "项目角色",
"date": "项目时间",
"description": "项目描述",
"link": "项目链接"
},
"placeholders": {
"name": "请输入项目名称",
"role": "你在项目中的角色",
"date": "项目时间范围",
"description": "简要描述项目背景和目标",
"link": "项目链接(可选)"
},
"buttons": {
"edit": "编辑",
"save": "保存",
"cancel": "取消",
"delete": "删除"
},
"visibility": {
"show": "显示",
"hide": "隐藏"
}
},
"educationPanel": {
"title": "教育背景",
"addButton": "添加教育经历",
"defaultProject": {
"school": "学校名称",
"degree": "学历",
"major": "专业",
"date": "2020.09 - 2024.06"
},
"placeholders": {
"school": "请输入学校名称",
"degree": "请选择学历",
"major": "请输入专业名称",
"date": "请输入就读时间范围"
}
},
"educationItem": {
"labels": {
"school": "学校名称",
"degree": "学历",
"major": "专业",
"date": "就读时间",
"description": "学校简介",
"gpa": "GPA",
"location": "所在地",
"startDate": "开始时间",
"endDate": "结束时间"
},
"placeholders": {
"school": "请输入学校名称",
"degree": "请选择学历",
"major": "请输入专业名称",
"date": "请输入就读时间范围",
"description": "请输入学校简介",
"gpa": "请输入GPA",
"location": "请输入所在地"
},
"buttons": {
"edit": "编辑",
"save": "保存",
"cancel": "取消",
"delete": "删除"
},
"visibility": {
"show": "显示",
"hide": "隐藏"
}
}
}
}