Forráskód Böngészése

feat(i18n): 添加国际化支持和错误码定义

- 新增英文语言文件 en.ts 包含完整的多语言键值对
- 新增中文语言文件 zh-CN.ts 提供中文本地化内容
- 创建 i18n 全局配置和语言切换功能模块
- 实现语言工具函数支持浏览器语言自动检测
- 定义前后端翻译映射表处理中英文数据转换
- 集成 Vue I18n 国际化框架支持动态语言切换
panqiuyao 2 napja
szülő
commit
7230868d03

+ 614 - 0
frontend/src/locales/en.ts

@@ -0,0 +1,614 @@
+export default {
+  // 通用
+  common: {
+    confirm: 'Confirm',
+    cancel: 'Cancel',
+    save: 'Save',
+    delete: 'Delete',
+    deleteAll: 'Delete All',
+    startGenerate: 'Start Generate',
+    edit: 'Edit',
+    copy: 'Copy',
+    add: 'Add',
+    search: 'Search',
+    reset: 'Reset',
+    loading: 'Loading...',
+    success: 'Success',
+    failed: 'Failed',
+    warning: 'Warning',
+    error: 'Error',
+    tips: 'Tips',
+    yes: 'Yes',
+    no: 'No',
+    enabled: 'Enabled',
+    disabled: 'Disabled',
+    all: 'All',
+    none: 'None',
+    operate: 'Operation',
+    status: 'Status',
+    version: 'Version',
+    download: 'Download',
+    selected: 'Selected',
+    of: 'of',
+    close: 'Close',
+    yesGetIt: 'Got It',
+    refresh: 'Refresh',
+    sort: 'Sort',
+    saveSort: 'Save Sort',
+    cancelSort: 'Cancel Sort',
+    newRow: 'Add Row',
+    reInit: 'Reinitialize',
+    rename: 'Rename Config',
+    copyConfig: 'Copy Config',
+    init: 'Initialize',
+    upload: 'Upload',
+    export: 'Export',
+    import: 'Import',
+    preview: 'Preview',
+    submit: 'Submit',
+    back: 'Back',
+    next: 'Next',
+    previous: 'Previous',
+    finish: 'Finish',
+    step: 'Step',
+    confirmDelete: 'Are you sure you want to delete this step?',
+    sortModeTip: 'Sort mode: drag rows to reorder, then click "Save Sort"',
+    dragSortTip: 'Drag rows to sort, then click "Save Sort"',
+    switchToConfig: 'Switch to Execution Config',
+    photo: 'Photo',
+    noPhoto: 'No Photo',
+    calibrationPos: 'Calibration Position',
+    newStep: 'Add Step',
+    editStep: 'Edit Step',
+    copySuffix: '_Copy',
+    renameConfig: 'Rename Config',
+    copyConfigTitle: 'Copy Config',
+    inputConfigName: 'Please enter config name',
+    inputName: 'Please enter name',
+    nickname: 'Nickname',
+    notLoggedIn: 'Not logged in',
+  },
+
+  // 验证消息
+  validation: {
+    pleaseInput: 'Please enter',
+    pleaseSelect: 'Please select',
+    required: 'This field is required',
+    invalidFormat: 'Invalid format',
+    inputPassword: 'Please enter password',
+    inputUsername: 'Please enter username',
+    inputPhone: 'Please enter phone number',
+    inputCode: 'Please enter verification code',
+    inputGoodsArtNo: 'Please scan or enter goods number in step 1 on the left!',
+    invalidPhone: 'Please enter a valid phone number',
+    selectMainImageSize: 'Please select main image size!',
+    inputValidSize: 'Please enter a valid value between 1 and 3000',
+    paddingRange: '800 image custom padding must be between 0 and 500',
+    sharpenRange: 'Image sharpen must be between 1 and 5',
+    selectMaskMode: 'Please select a valid shadow processing mode',
+    opacityRange: 'Opacity must be between 0.5 and 1',
+    brightnessRange: 'Brightness must be between 200 and 255',
+    selectFlip: 'Please select whether to flip 800 image',
+  },
+
+  // 成功/失败消息
+  message: {
+    saveSuccess: 'Saved successfully',
+    deleteSuccess: 'Deleted successfully',
+    resetSuccess: 'Reset successfully',
+    renameSuccess: 'Renamed successfully',
+    sortSuccess: 'Sorted successfully',
+    configSwitchSuccess: 'Config switched successfully',
+    configSwitchFailed: 'Config switch failed',
+    loginFailed: 'Login failed, please retry',
+    switchOrgFailed: 'Failed to switch organization, please retry',
+    noOrg: 'No organization found for current user',
+    openPreviewWarn: 'You have a live preview popup open. Please close the edit popup first, then close this window.',
+    sortCanceled: 'Sort canceled',
+    openDirFailed: 'Failed to get app directory appPath',
+    openDirError: 'Failed to open directory',
+    importImageFailed: 'Failed to import images',
+    deleteAllGoodsSuccess: 'All goods deleted successfully',
+    deleteAllGoodsFailed: 'Failed to delete all goods',
+    deleteGoodsSuccess: 'Goods deleted successfully',
+    selectGoodsFirst: 'Please select goods to generate',
+    confirmDeleteGoods: 'Are you sure you want to delete shooting data for goods: {goods}?',
+    confirmDeleteAll: 'Are you sure you want to delete all shooting data?',
+    confirmDeleteHistory: 'Are you sure you want to delete current history?',
+    confirmReTakeGoods: 'This will delete shooting data for goods: {goods}. Continue?',
+    confirmReTakeSingle: 'This will delete this data. Continue?',
+    reTakePrompt: 'This will delete this data. Continue?',
+    reTakeGoodsPrompt: 'This will delete shooting data for goods: {goods}. Continue?',
+    reTakeConfirmTitle: 'Confirm',
+    reTakeAlertTitle: 'Notice',
+    reTakeAlertMsg: 'View reset. After placing the shoes, click the button to start retake.',
+    reTakeAlertBtn: 'Start Retake',
+    startReTake: 'Start Retake',
+    reTakeComplete: 'Single photo complete',
+    photoComplete: 'All photos complete',
+    cannotReadConfig: 'Cannot read shooting config for this product. Please delete and reshoot.',
+    shootingInProgress: 'Shooting in progress, please wait',
+    notShooting: 'Please shoot a product first.',
+    alreadyStopped: 'Shooting already finished, no need to stop.',
+    remoteControlTip: 'Please scan or enter goods number in step 1 on the left!',
+    bluetoothScanTip: 'Goods {no} acquired. Press left or right button on remote to start shooting.',
+    confirmDeleteSelectedGoods: 'Are you sure you want to delete shooting data for the selected {count} goods?',
+  },
+
+  // 路由/页面标题
+  router: {
+    home: 'Home',
+    setting: 'Settings',
+    photoCheck: 'Lens Correction',
+    photoShot: 'Shoot Product',
+    photoProcess: 'Process Images',
+    photoDetail: 'Main Image & Detail Generation',
+    photoSeniorDetail: 'Detail Advanced Config',
+    photoExpired: 'Account Expired',
+    remoteControl: 'Remote Control',
+    developer: 'Device Setup',
+    developerTabSetting: 'Settings',
+    developerTabMCU: 'MCU Config',
+    developerTabRS485: 'RS485 Debug',
+    ota: 'Version Update',
+  },
+
+  // 登录页
+  login: {
+    title: 'Welcome!',
+    subtitle: 'Sign in to Zhihuiying System',
+    accountTab: 'Account Login',
+    codeTab: 'SMS Login',
+    getCode: 'Get Code',
+    countdown: 's to resend',
+    loginBtn: 'Login',
+    selectCompany: 'Select Company Identity',
+    selectCompanyTip: 'You have accounts in the following companies. Which one would you like to access?',
+    confirm: 'Confirm',
+    switchOrg: 'Failed to switch organization, please retry',
+  },
+
+  // 首页
+  home: {
+    title: 'Home',
+    appTitle: 'Zhihuiying AI Camera',
+    shootAndProcess: 'Shoot & Process',
+    processOnly: 'Process Only',
+    versionAnnouncement: 'Version Announcement',
+    noAnnouncement: 'No announcements yet',
+    loadingProgram: 'Program starting...',
+    loadingSync: 'Syncing config...',
+    loadingGeneral: 'Loading...',
+    waitSync: 'Waiting for config sync',
+    openResource: 'Click home title',
+  },
+
+  // 头部导航
+  header: {
+    setting: 'Settings',
+    remoteSimulator: 'Remote Simulator',
+    deviceSetup: 'Device Setup',
+    currentVersion: 'Version: {version}',
+    userManual: 'User Manual',
+    logout: 'Logout',
+    softwareDownload: 'Downloading software',
+    versionDetail: 'Version Details',
+  },
+
+  // 遥控器
+  remoteControl: {
+    title: 'Remote Simulator',
+    leftFoot: 'Left',
+    rightFoot: 'Right',
+    takePhoto: 'Photo',
+    ledOn: 'LED On',
+    ledOff: 'LED Off',
+    stop: 'Stop',
+    leftConfig: 'Left Config',
+    rightConfig: 'Right Config',
+    photoConfig: 'Photo Config',
+    pointLabel: 'Point {point}',
+    connected: 'Connected',
+    notConnected: 'Not Connected',
+    switchToPoint: 'Switched to Point {point}',
+    shootingInProgress: 'Shooting in progress, please wait',
+  },
+
+  // 拍摄检查
+  photoCheck: {
+    title: 'Lens Correction',
+    tipNormal: 'Place shoes on the turntable (note left/right). Shoes should face the camera with the center axis aligned with the infrared. If lighting is insufficient, turn on ambient light and turn off flash.',
+    tipSetting: 'Place shoes on the turntable (note left/right). Shoes should face the camera with the center axis aligned with the infrared. If lighting is insufficient, turn on ambient light and turn off flash.',
+    clickFocus: 'Tap to Focus',
+    testImageDesc: 'Test image for checking lens calibration',
+    takePhotoCheck: 'Take Photo Check',
+    retakeCheck: 'Retake Check',
+    confirmNext: 'Confirm and Next',
+  },
+
+  // 拍摄商品
+  photoShot: {
+    title: 'Shoot Product',
+    step1: 'Step 1: Enter Goods Number',
+    inputGoodsPlaceholder: 'Enter goods number',
+    autoGet: 'Auto Get',
+    scanTip: 'Scan product QR code with remote',
+    step2: 'Step 2: Start Shooting (press left/right on remote)',
+    remoteTip: 'Left/right buttons start shooting. Center button unlocks custom image after 5 main images.',
+    searchPlaceholder: 'Search goods number',
+    noData: 'No data yet. Please shoot first.',
+    loading: 'Loading data, please wait...',
+    imageCount: 'images',
+    advancedGenerate: 'Advanced Generate',
+    retake: 'Retake',
+    leftFootProgram: 'Execute Left Foot Program',
+    rightFootProgram: 'Execute Right Foot Program',
+    goodsSuccess: 'Goods {goods} acquired. Press left or right button on remote to start shooting.',
+    startShooting: 'Starting shooting...',
+    shootingInProgress: 'Shooting in progress, please wait',
+    alreadyStopped: 'Shooting already finished, no need to stop.',
+    notShooting: 'Please shoot a product first.',
+    goodsNoSuccess: 'Goods {goods} acquired. Press left or right button on remote to start shooting.',
+  },
+
+  // 处理图像
+  photoProcess: {
+    title: 'Process Images',
+    searchPlaceholder: 'Search goods number',
+    noData: 'No data, please shoot first',
+    loading: 'Loading data, please wait...',
+    imageCount: 'images',
+    advancedGenerate: 'Advanced Generate',
+    retake: 'Retake',
+    delete: 'Delete',
+  },
+
+  // 主图与详情生成
+  photoDetail: {
+    sceneGenerate: 'Scene Generation',
+    modelGenerate: 'Model Generation',
+    detailGenerate: 'Detail Generation',
+    customTemplate: 'Add Custom Template',
+    templateDeveloping: 'Feature developing',
+    templateCustom: 'Detail Template Custom',
+    whiteBgExport: 'Batch White Background Export',
+    productAlbum: 'Product Album Generation',
+    tipTitle: 'Tip',
+  },
+
+  // 设置页
+  setting: {
+    title: 'Settings',
+    basicConfig: 'Basic Config',
+    cameraConfig: 'Camera Config',
+    otherConfig: 'Other Settings',
+    leftRightConfig: 'Left/Right Foot Program Config',
+    mainImageSize: 'Main Image Size:',
+    customSize: 'Custom Size:',
+    inputSizeTip: 'Enter a size value between 1-3000',
+    imageFormat: 'Image Format:',
+    imageSharpen: 'Image Sharpen:',
+    sharpenTip: 'Value 1-5, 1 means no processing',
+    shadowMode: 'Shadow Mode:',
+    shadowDefault: 'Default',
+    shadowCustom: 'Custom',
+    opacity: 'Opacity:',
+    inputOpacityTip: 'Enter a value between 0.5-1',
+    brightnessRange: 'Brightness Range:',
+    inputBrightnessTip: 'Enter a value between 200-255',
+    customPadding800: '800 Image Custom Padding:',
+    inputPaddingTip: 'Enter an integer between 0-500',
+    flip800: 'Flip 800 Image:',
+    color800: '800 Image Color Config:',
+    productType: 'Product Type:',
+    defaultCutout: 'Default Cutout Mode:',
+    deviceSpeed: 'Device Speed:',
+    speedFast: 'Fast',
+    speedMedium: 'Medium',
+    speedSlow: 'Slow',
+  },
+
+  // OTA/版本更新
+  ota: {
+    currentVersion: 'Current Version:',
+    status: 'Status:',
+    latest: 'You are on the latest version',
+    newVersion: 'New version available',
+    downloadUpdate: 'Download Update',
+    changelog: 'Changelog:',
+    historyVersions: 'Version History',
+    versionNumber: 'Version',
+    releaseDate: 'Release Date',
+    description: 'Description',
+    operation: 'Operation',
+    versionDetail: 'Version Details',
+    downloading: 'Downloading',
+    downloadFailed: 'Download failed',
+    noDetail: 'No details available',
+  },
+
+  // 过期页
+  expired: {
+    title: 'Enterprise Account Expired',
+    expiredMsg: 'Your enterprise account has expired and cannot continue using the system.',
+    contactAdmin: 'Contact Admin',
+    contactMsg: 'Please contact administrator via:\n\nPhone: 400-xxx-xxxx\nEmail: admin@company.com\n\nOr scan QR code below to add support WeChat',
+    relogin: 'Relogin',
+    gotIt: 'Got It',
+    logoutFailed: 'Logout failed, please retry',
+  },
+
+  // 开发者页
+  developer: {
+    title: 'Device Setup',
+    tabSetting: 'Settings',
+    tabMCU: 'MCU Config',
+    tabRS485: 'RS485 Debug',
+    cameraSetting: 'Camera Settings',
+    turntableSetting: 'Turntable Settings',
+    flipServo: 'Flip Servo',
+    cameraHeight: 'Camera Height (mm):',
+    cameraAngle: 'Camera Angle (deg):',
+    angleOffset: 'Angle Offset (deg):',
+    frontBackOffset: 'Front/Back Offset:',
+    middlePos: 'Middle Position:',
+    highPos: 'High Position:',
+    riseSpeed: 'Rise Speed:',
+    fallSpeed: 'Fall Speed:',
+    setValue: 'Set',
+    minMaxTip: 'Min {min}, max {max}',
+    valueRangeTip: '{name} value must be between {min} and {max}',
+    deviceInit: 'Device Init',
+    readOffset: 'Read Offset & Run',
+    allSet: 'Set All',
+    readConfig: 'Read Config',
+    setConfig: 'Set Config',
+    setSuccess: 'Set Successfully',
+    setFailed: 'Set Failed',
+    readFirst: 'Please get device parameters first',
+    sendCmd: 'Send',
+  },
+
+  // 菜单项
+  menu: {
+    setting: 'Settings',
+    generateDir: 'Generated Images',
+    switchMode: 'Switch Mode',
+    history: 'History',
+    modelImage: 'Model Image',
+    sceneImage: 'Scene Image',
+    generateVideo: 'Generate Video',
+  },
+
+  // 模板相关
+  tpl: {
+    addCanvas: 'Add Canvas',
+    editCanvas: 'Edit Canvas',
+    normalCanvas: 'Normal canvas, editable content',
+    modelCanvas: 'Model placeholder, replaced during generation',
+    sceneCanvas: 'Scene placeholder, replaced during generation',
+    modeDefault: 'Default mode, one canvas per goods number',
+    modeSingle: 'One canvas per goods number, containing images of different angles',
+    modeMultiple: 'Multiple goods numbers per canvas, containing images of same angle',
+    editing: 'Editing',
+    switchCanvas: 'Switch Canvas',
+    layerImage: 'Image',
+    layerText: 'Text',
+    layerGroup: 'Group',
+    layerDynamic: 'Dynamic',
+    layerShow: 'Show',
+    layerHide: 'Hide',
+  },
+
+  // 商品字段
+  goods: {
+    color: 'Color',
+    goodsArtNo: 'Goods No.',
+    designConcept: 'Design Concept',
+    title: 'Title',
+    styleNo: 'Style No.',
+  },
+
+  // 状态
+  status: {
+    processing: 'Processing',
+    completed: 'Completed',
+    failed: 'Failed',
+    pending: 'Pending',
+    connected: 'Connected',
+    disconnected: 'Disconnected',
+    allFailed: 'All goods generation failed',
+  },
+
+  // 相机配置
+  cameraConfig: {
+    bindCamera: 'Bind Camera:',
+    selectCamera: 'Select Camera',
+    refresh: 'Refresh',
+    photoISO: 'Photo ISO:',
+    previewISO: 'Preview ISO:',
+    select: 'Select',
+    pointLabel: 'Point {point}',
+    connected: 'Camera Connected',
+    notConnected: 'Camera Disconnected',
+    notSet: 'Camera Not Set',
+    isoMustPositive: '{name} must be greater than 0',
+    selectISO: 'Please select {name}',
+    cameraConnected: 'Camera connection status updated',
+    noCameraList: 'No camera list found',
+    refreshFailed: 'Refresh failed, please retry',
+  },
+
+  // 充值
+  recharge: {
+    remainingCoins: 'Remaining Coins:',
+    recharge: 'Recharge',
+    rechargeTitle: 'Recharge Coins',
+    coinTip: '(Video generation requires separate coin payment)',
+    loading: 'Loading, please wait...',
+  },
+
+  // 详情页
+  photoDetail2: {
+    selectTemplate: 'Select Detail Template',
+    mainImageLogo: 'Main Image Logo',
+    clickOrDragUpload: 'Click or drag to upload',
+    supportPngJpg: 'PNG, JPG formats supported',
+    logoFileNotExist: 'Logo file not found or failed to load. Please re-upload.',
+    reupload: 'Re-upload',
+    preview: 'Preview',
+    dataPrep: 'Detail Data Preparation',
+    excelUpload: 'Excel Upload',
+    systemIntegration: 'System Integration',
+    clickSelectFile: 'Click to select file',
+    fileSelected: 'File Selected',
+    downloadExcelTemplate: 'Download General Product Data Template',
+    forNonCustomDetail: 'For non-custom detail page product data',
+    oneKeyPublish: 'One-Click Publish',
+    domesticEcommerce: 'Domestic Platforms:',
+    crossBorderEcommerce: 'Cross-border Platforms:',
+    startGenerate: 'Start Generate',
+    processingProgress: 'Processing Progress',
+    openFolder: 'Open Folder',
+    viewDetails: 'View',
+    edit: 'Edit',
+    delete: 'Delete',
+    downloadExcelTemplate2: 'Download Excel Template',
+    selectTemplateFirst: 'Please select Detail Generation first, then select a template',
+    templateRequires: 'This template requires {count} standard angle images: {order}. Please ensure high image quality and clean background.',
+    pleaseSelectService: 'Please select service content',
+    pleaseSelectMaleFemaleModel: 'Please select both male and female models',
+    pleaseSelectMaleModel: 'Please select male model',
+    pleaseSelectFemaleModel: 'Please select female model',
+    pleaseSetScenePrompt: 'Please set scene prompt',
+    pleaseUploadGoodsData: 'Please upload product data',
+    logoLoadError: 'Logo failed to load or file deleted. Please re-upload.',
+    processing: 'Processing, please wait',
+    allGenerateSuccess: 'All generated successfully',
+    partGenerateFailed: 'Some goods failed to generate',
+    allGenerateFailed: 'All goods generation failed',
+    logoPreview: 'Logo Preview',
+    sceneGenerate: 'Scene Generation',
+    modelGenerate: 'Model Generation',
+    detailGenerate: 'Detail Generation',
+    addCustomTemplate: 'Add Custom Template',
+    detailTemplateCustom: 'Detail Template Custom',
+    functionDeveloping: 'Feature developing',
+    whiteBgExport: 'White Background Export',
+    productAlbum: 'Product Album',
+    whiteBgExportStarted: 'White background export tool launched',
+    productAlbumStarted: 'Product album tool launched',
+    deleteTemplateConfirm: 'Are you sure you want to delete custom template "{name}"?',
+    deleteSuccess: 'Deleted successfully',
+    deleteFailed: 'Delete failed',
+    goodsNo: 'Goods No.',
+  },
+
+  // 高级配置
+  seniorDetail: {
+    title: 'Main Image & Detail Advanced Config',
+    cutoutAndGoodsGenerate: 'Image Cutout & Goods Image Generation',
+    cutoutTip1: 'Please confirm the image sequence from shooting, ensuring all images follow the same order.',
+    cutoutTip2: 'Separate with Chinese/English commas.',
+    cutoutTip3: 'Do not rename images, otherwise detail pages cannot be generated.',
+    cutoutTip4: 'Available image names: Top View, Side View, Heel View, Sole, Insole',
+    goodsFolder: 'Goods Folder:',
+    selectGoodsFolder: 'Select goods folder',
+    selectTargetFolder: 'Select Target Folder',
+    selectGoodsParentFolder: 'Select parent folder of goods',
+    cutoutMode: 'Cutout Mode:',
+    normalMode: 'Normal Mode',
+    refinedCutout: 'Refined Cutout',
+    detailAdvancedConfig: 'Detail Advanced Config',
+    imageOrder: 'Image Order:',
+    inputImageOrder: 'Enter image order',
+    imageOrderExplain: 'Explain',
+    sameStyleCheck: 'Same Style Check:',
+    sameStyleMustComplete: 'Same style goods must have complete numbers',
+    specifyPageModify: 'Specify Page Modification:',
+    inputSpecifyPage: 'Enter page to modify separately, example: 4:1 (template number: first image)',
+    specifyPageExplain: 'Explain',
+    saveConfig: 'Save Config',
+    startProcess: 'Start Process',
+    allProcessComplete: 'All processing complete',
+    openDir: 'Open Directory',
+  },
+
+  // 加载弹窗
+  loadingDialog: {
+    processing: 'Processing, please wait...',
+    processComplete: 'Done. Click to open output folder',
+  },
+
+  // 编辑行
+  editRow: {
+    title: 'Parameter Value Edit',
+    actionNameChangeTip: 'Changing action name may cause custom template generation to fail!',
+    actionName: 'Action Name',
+    shotPoint: 'Shot Point',
+    selectPoint: 'Select Point',
+    pointLabel: 'Point {point}',
+    takePhoto: 'Take Photo',
+    photo: 'Photo',
+    noPhoto: 'No Photo',
+    cameraHeight: 'Camera Height (mm)',
+    cameraAngle: 'Camera Angle',
+    turntablePosition: 'Turntable Position',
+    turntableAngle: 'Turntable Angle',
+    shoeFlip: 'Shoe Flip',
+    flip: 'Flip',
+    noFlip: 'No Flip',
+    testFlip: 'Test Flip',
+    ledSwitch: 'LED Switch',
+    off: 'Off',
+    on: 'On',
+    focusCount: 'Focus Count',
+    preDelay: 'Pre-Shot Delay (s)',
+    postDelay: 'Post-Shot Delay (s)',
+    minMaxTip: 'Min {min}, max {max}',
+    cancel: 'Cancel',
+    run: 'Run',
+    saveClose: 'Save & Close',
+    pleaseInputActionName: 'Please enter action name',
+    pleaseSelectPoint: 'Please select shot point',
+    saveSuccess: 'Saved successfully',
+  },
+
+  // 硬件检测
+  hardwareCheck: {
+    title: 'Hardware Check',
+    checkingHardware: 'Initializing hardware check......',
+    hardwareCheckComplete: 'Hardware check complete',
+    hardwareCheckFailed: 'Hardware check initialization failed',
+    selfCheck: 'Self Check',
+    checkTip1: 'Check if fill light power and connectors are properly connected.',
+    checkTip2: 'Check if the infrared device is displaying normally.',
+    reCheck: 'Recheck',
+    viewDeviceStatus: 'View Device Status',
+    checkSuccessContinue: 'Check successful, continue!',
+    deviceStatus: 'Device Status',
+    cancel: 'Cancel',
+    refresh: 'Refresh',
+    getStatusFailed: 'Failed to get device status',
+    getStatusTimeout: 'Device status request timeout',
+    statusNotInit: 'Not Initialized',
+    statusMoving: 'Moving',
+    statusStopped: 'Stopped',
+    statusOffline: 'Offline',
+    statusBlocked: 'Blocked',
+    statusUnknown: 'Unknown',
+    cameraHeightStatus: 'Camera Height Status',
+    cameraAngleStatus: 'Camera Angle Status',
+    turntableStatus: 'Turntable Status',
+    turntableMoveStatus: 'Turntable Position Status',
+    flipBoardStatus: 'Flip Board Status',
+  },
+
+  // 拍摄页面底部
+  shot: {
+    clickToStartCamera: 'Tap screen to start camera',
+    initHardware: 'Initializing camera hardware......',
+    progress: 'Checking up to',
+  },
+
+}

+ 29 - 0
frontend/src/locales/index.ts

@@ -0,0 +1,29 @@
+import { createI18n } from 'vue-i18n'
+import zhCN from './zh-CN'
+import en from './en'
+import { getLanguage } from '@/utils/language'
+
+const i18n = createI18n({
+  legacy: false,
+  locale: getLanguage(),
+  fallbackLocale: 'zh-CN',
+  messages: {
+    'zh-CN': zhCN,
+    en
+  },
+  // 支持模板中直接使用 $tc 进行复数处理
+  numberFormats: {},
+  datetimeFormats: {},
+})
+
+export default i18n
+
+// 切换语言
+export function switchLanguage(lang: 'zh-CN' | 'en') {
+  ;(i18n.global.locale as any).value = lang
+  import('@/utils/language').then(({ setLanguage }) => {
+    setLanguage(lang)
+  })
+}
+
+export type { SupportedLocale } from '@/utils/language'

+ 84 - 0
frontend/src/locales/mappings.ts

@@ -0,0 +1,84 @@
+// 前后端中文数据翻译映射表
+// 前端内部用的中文 key(如 action='执行左脚程序')在前端硬编码
+// 后端返回的中文数据(如 status='处理完成')在后端保持不变,前端做翻译映射
+
+export const actionNameMap: Record<string, { zh: string; en: string }> = {
+  '执行左脚程序': { zh: '执行左脚程序', en: 'Execute Left Foot Program' },
+  '执行右脚程序': { zh: '执行右脚程序', en: 'Execute Right Foot Program' },
+  '历史记录':    { zh: '历史记录',    en: 'History' },
+  '模特图':      { zh: '模特图',      en: 'Model Image' },
+  '场景图':      { zh: '场景图',      en: 'Scene Image' },
+  '生成视频':    { zh: '生成视频',    en: 'Generate Video' },
+  '高级生成':    { zh: '高级生成',    en: 'Advanced Generation' },
+  '侧视':        { zh: '侧视',        en: 'Side View' },
+  '测试':        { zh: '测试',        en: 'Test' },
+}
+
+export const stepStatusMap: Record<string, { zh: string; en: string; cls: string }> = {
+  '处理完成': { zh: '处理完成', en: 'Completed', cls: 'completed' },
+  '正在处理': { zh: '正在处理', en: 'Processing', cls: 'processing' },
+  '处理失败': { zh: '处理失败', en: 'Failed', cls: 'failed' },
+  '等待处理': { zh: '等待处理', en: 'Pending', cls: 'waiting' },
+}
+
+export const templateStatusMap: Record<string, { zh: string; en: string }> = {
+  '启用': { zh: '启用', en: 'Enabled' },
+  '禁用': { zh: '禁用', en: 'Disabled' },
+}
+
+export const cameraStatusMap: Record<string, { zh: string; en: string; type: string }> = {
+  'connected':    { zh: '已连接相机', en: 'Camera Connected', type: 'success' },
+  'disconnected': { zh: '未连接相机', en: 'Camera Disconnected', type: 'danger' },
+}
+
+export const modelGenderMap: Record<string, { zh: string; en: string }> = {
+  '女性': { zh: '女性', en: 'Female' },
+  '男性': { zh: '男性', en: 'Male' },
+}
+
+// 画布类型映射
+export const canvasTypeMap: Record<string, { zh: string; en: string }> = {
+  '普通画布,可编辑内容': { zh: '普通画布,可编辑内容', en: 'Normal canvas, editable content' },
+  '模特图占位,用于前台/后端生成时替换': { zh: '模特图占位,用于前台/后端生成时替换', en: 'Model image placeholder, replaced when generating' },
+  '场景图占位,用于前台/后端生成时替换': { zh: '场景图占位,用于前台/后端生成时替换', en: 'Scene image placeholder, replaced when generating' },
+}
+
+// 货号画布模式映射
+export const multiGoodsModeMap: Record<string, { zh: string; en: string }> = {
+  '': { zh: '默认模式,画布对应单个货号', en: 'Default mode, canvas corresponds to single goods art no' },
+  'single': { zh: '一个画布对应一个货号,画布中包含该货号不同角度的图片', en: 'One canvas per goods, contains different angles' },
+  'multiple': { zh: '画布中含有多个货号,画布中包含多个货号同一角度的图片', en: 'Canvas contains multiple goods, same angle' },
+}
+
+// 图层类型映射
+export const layerTypeMap: Record<string, { zh: string; en: string }> = {
+  '图片': { zh: '图片', en: 'Image' },
+  '文字': { zh: '文字', en: 'Text' },
+  '组合': { zh: '组合', en: 'Group' },
+}
+
+// 货号字段中文 key 映射(商品属性)
+export const goodsFieldMap: Record<string, { zh: string; en: string }> = {
+  '颜色': { zh: '颜色', en: 'Color' },
+  '货号': { zh: '货号', en: 'Goods Art No' },
+  '设计理念': { zh: '设计理念', en: 'Design Concept' },
+  '标题': { zh: '标题', en: 'Title' },
+  '款号': { zh: '款号', en: 'Style No' },
+}
+
+// 设备初始化状态
+export const deviceInitStatusMap: Record<string, { zh: string; en: string }> = {
+  '设备初始化完成': { zh: '设备初始化完成', en: 'Device Initialization Complete' },
+  '相机舵机 设置成功': { zh: '相机舵机设置成功', en: 'Camera Servo Setting Success' },
+}
+
+// 根据当前语言获取翻译后的值
+export function getTransValue<T extends Record<string, { zh: string; en: string }>>(
+  map: T,
+  key: string,
+  locale: string
+): string {
+  const entry = map[key]
+  if (!entry) return key
+  return locale === 'en' ? entry.en : entry.zh
+}

+ 621 - 0
frontend/src/locales/zh-CN.ts

@@ -0,0 +1,621 @@
+export default {
+  // 通用
+  common: {
+    confirm: '确认',
+    cancel: '取消',
+    save: '保存',
+    delete: '删除',
+    deleteAll: '删除所有',
+    startGenerate: '开始生成',
+    edit: '编辑',
+    copy: '复制',
+    add: '新增',
+    search: '搜索',
+    reset: '重置',
+    loading: '加载中...',
+    success: '成功',
+    failed: '失败',
+    warning: '警告',
+    error: '错误',
+    tips: '提示',
+    yes: '是',
+    no: '否',
+    enabled: '启用',
+    disabled: '禁用',
+    all: '全部',
+    none: '无',
+    operate: '操作',
+    status: '状态',
+    version: '版本',
+    download: '下载',
+    selected: '已选择',
+    of: '共',
+    close: '关闭',
+    yesGetIt: '知道了',
+    refresh: '刷新',
+    sort: '排序',
+    saveSort: '保存排序',
+    cancelSort: '取消排序',
+    newRow: '新增一行',
+    reInit: '重新初始化',
+    rename: '重命名配置',
+    copyConfig: '复制配置',
+    init: '初始化',
+    upload: '上传',
+    export: '导出',
+    import: '导入',
+    preview: '预览',
+    submit: '提交',
+    back: '返回',
+    next: '下一步',
+    previous: '上一步',
+    finish: '完成',
+    step: '步骤',
+    confirmDelete: '确定删除该步骤吗?',
+    sortModeTip: '排序模式:请拖拽行进行排序,完成后点击"保存排序"',
+    dragSortTip: '请拖拽行进行排序,完成后点击"保存排序"',
+    switchToConfig: '切换成执行配置',
+    photo: '拍照',
+    noPhoto: '不拍照',
+    calibrationPos: '校准位',
+    newStep: '新增步骤',
+    editStep: '编辑步骤',
+    copySuffix: '_副本',
+    renameConfig: '重命名配置',
+    copyConfigTitle: '复制配置',
+    inputConfigName: '请输入配置名称',
+    inputName: '请输入名称',
+    nickname: '昵称',
+    notLoggedIn: '未登录',
+  },
+
+  // 验证消息
+  validation: {
+    pleaseInput: '请输入',
+    pleaseSelect: '请选择',
+    required: '该字段为必填项',
+    invalidFormat: '格式不正确',
+    inputPassword: '请输入密码',
+    inputUsername: '请输入用户名',
+    inputPhone: '请输入手机号',
+    inputCode: '请输入验证码',
+    inputGoodsArtNo: '请在左侧第一步中,先扫描货号或者手动输入货号!',
+    invalidPhone: '请输入手机号',
+    selectMainImageSize: '请选择主图尺寸!',
+    inputValidSize: '请输入1-3000之间的有效数值',
+    paddingRange: '800图自定义边距必须在0-500之间',
+    sharpenRange: '图片锐化必须在1-5之间',
+    selectMaskMode: '请选择有效的阴影处理模式',
+    opacityRange: '透明度必须在0.5-1之间',
+    brightnessRange: '亮度范围必须在200-255之间',
+    selectFlip: '请选择800图是否翻转',
+  },
+
+  // 成功/失败消息
+  message: {
+    saveSuccess: '保存成功',
+    deleteSuccess: '删除成功',
+    resetSuccess: '重置成功',
+    renameSuccess: '重命名成功',
+    sortSuccess: '排序成功',
+    configSwitchSuccess: '配置切换成功',
+    configSwitchFailed: '配置切换失败',
+    loginFailed: '登录失败,请重试',
+    switchOrgFailed: '切换组织失败,请重试',
+    noOrg: '当前没有所属组织',
+    openPreviewWarn: '您已打开实时预览弹出框,请先取消或者保存后,关闭编辑弹出框,后再关闭此窗口',
+    sortCanceled: '已取消排序',
+    openDirFailed: '未获取到应用目录 appPath',
+    openDirError: '打开目录失败',
+    importImageFailed: '导入图片失败',
+    deleteAllGoodsSuccess: '删除所有货号成功',
+    deleteAllGoodsFailed: '删除所有货号失败',
+    deleteGoodsSuccess: '货号删除成功',
+    selectGoodsFirst: '请选择要生成的货号',
+    confirmDeleteGoods: '确定要删除货号:{goods}的拍摄数据吗?',
+    confirmDeleteAll: '确定要删除所有货号的拍摄数据吗?',
+    confirmDeleteHistory: '确定要删除当下的历史记录吗?',
+    confirmReTakeGoods: '此操作会先删除货号:{goods}的拍摄数据,需要继续吗?',
+    confirmReTakeSingle: '此操作会先删除此数据,需要继续吗?',
+    reTakePrompt: '此操作会先删除此数据,需要继续吗?',
+    reTakeGoodsPrompt: '此操作会先删除货号:{goods}的拍摄数据,需要继续吗?',
+    reTakeConfirmTitle: '提示',
+    reTakeAlertTitle: '提示',
+    reTakeAlertMsg: '已复位到该视图下,请把鞋子摆放完毕之后,点击按钮开始重拍',
+    reTakeAlertBtn: '开始重拍',
+    startReTake: '开始重拍',
+    reTakeComplete: '单张拍摄完成',
+    photoComplete: '全部拍摄完成',
+    cannotReadConfig: '无法读取到该商品拍摄配置,如需重新生成请删除该商品并重新拍摄',
+    shootingInProgress: '正在拍摄中,请稍候',
+    notShooting: '请先拍摄商品。',
+    alreadyStopped: '拍摄程序已结束,不需要单独停止!',
+    remoteControlTip: '请在左侧第一步中,先扫描货号或者手动输入货号!',
+    bluetoothScanTip: '商品货号{no}获取成功,请在遥控器上按下左或右脚按键,启动拍摄',
+    confirmDeleteSelectedGoods: '确定要删除选中的 {count} 个货号的拍摄数据吗?',
+  },
+
+  // 路由/页面标题
+  router: {
+    home: '首页',
+    setting: '设置',
+    photoCheck: '拍摄物体镜头矫正',
+    photoShot: '拍摄商品',
+    photoProcess: '处理图像',
+    photoDetail: '主图与详情生成',
+    photoSeniorDetail: '详情高级配置',
+    photoExpired: '企业账户过期',
+    remoteControl: '遥控器',
+    developer: '初始设备调频设置',
+    developerTabSetting: '设置',
+    developerTabMCU: 'MCU其他配置设置',
+    developerTabRS485: 'RS485调试发送',
+    ota: '版本更新',
+  },
+
+  // 登录页
+  login: {
+    title: '欢迎!',
+    subtitle: '登录智惠映系统',
+    accountTab: '账号密码登录',
+    codeTab: '验证码登录',
+    getCode: '获取验证码',
+    countdown: 's后重新获取',
+    loginBtn: '登录',
+    selectCompany: '请选择企业身份',
+    selectCompanyTip: '您在以下企业均有任职,请问您想代表那个企业进行访问',
+    confirm: '确认',
+    switchOrg: '切换组织失败,请重试',
+  },
+
+  // 首页
+  home: {
+    title: '首页',
+    appTitle: '智惠映AI自动拍照机',
+    shootAndProcess: '拍摄产品\n并处理图像',
+    processOnly: '仅处理图像',
+    versionAnnouncement: '版本公告',
+    noAnnouncement: '暂无详细公告内容',
+    loadingProgram: '程序启动中...',
+    loadingSync: '正在同步配置...',
+    loadingGeneral: '正在加载...',
+    waitSync: '等待配置同步完成',
+    openResource: '点击首页标题',
+  },
+
+  // 头部导航
+  header: {
+    setting: '设置',
+    remoteSimulator: '模拟遥控器',
+    deviceSetup: '初始设备调频设置',
+    currentVersion: '当前版本:{version}',
+    userManual: '使用手册',
+    logout: '退出登录',
+    softwareDownload: '软件下载中',
+    versionDetail: '版本详情',
+  },
+
+  // 遥控器
+  remoteControl: {
+    title: '遥控器模拟器',
+    leftFoot: '左脚',
+    rightFoot: '右脚',
+    takePhoto: '拍照',
+    ledOn: 'LED开',
+    ledOff: 'LED关',
+    stop: '停止',
+    leftConfig: '左脚配置',
+    rightConfig: '右脚配置',
+    photoConfig: '拍照配置',
+    pointLabel: '点位 {point}',
+    connected: '已连接',
+    notConnected: '未连接',
+    switchToPoint: '已切换到点位 {point}',
+    shootingInProgress: '拍摄程序正在运行,请稍候',
+  },
+
+  // 拍摄检查
+  photoCheck: {
+    title: '拍摄物体镜头矫正',
+    tipNormal: '请在圆盘上摆上鞋子(注意左右脚),要求鞋外侧朝向拍照机,鞋子中轴线和红外线对齐,如果光亮不够,可以打开环境光源,关闭闪光灯。',
+    tipSetting: '请在圆盘上摆上鞋子(注意左右脚),要求鞋外侧朝向拍照机,鞋子中轴线和红外线对齐,如果光亮不够,可以打开环境光源,关闭闪光灯。',
+    clickFocus: '点击对焦',
+    testImageDesc: '这是一张用于检查镜头是否合适的测试图',
+    takePhotoCheck: '拍照检查',
+    retakeCheck: '重新拍照检查',
+    confirmNext: '确认无误,下一步',
+  },
+
+  // 拍摄商品
+  photoShot: {
+    title: '拍摄商品',
+    step1: '第一步:获取商品货号',
+    inputGoodsPlaceholder: '请输入货号',
+    autoGet: '自动获取',
+    scanTip: '用遥控器扫描商品资料二维码',
+    step2: '第二步:启动拍摄(根据按遥控器左右键启动)',
+    remoteTip: '遥控左右按键可启动拍摄,中间按钮可在拍摄5张主图后解锁,用于拍摄自定义图',
+    searchPlaceholder: '搜索货号',
+    noData: '暂无数据,请先进行拍摄',
+    loading: '数据正在加载中,请稍候...',
+    imageCount: '张图片',
+    advancedGenerate: '高级生成',
+    retake: '重拍',
+    leftFootProgram: '执行左脚程序',
+    rightFootProgram: '执行右脚程序',
+    goodsSuccess: '商品货号{goods}获取成功,请在遥控器上按下左或右脚按键,启动拍摄',
+    startShooting: '开始拍摄,请稍后',
+    shootingInProgress: '拍摄程序正在运行,请稍候',
+    alreadyStopped: '拍摄程序已结束,不需要单独停止!',
+    notShooting: '请先拍摄商品。',
+    goodsNoSuccess: '商品货号{goods}获取成功,请在遥控器上按下左或右脚按键,启动拍摄',
+  },
+
+  // 处理图像
+  photoProcess: {
+    title: '处理图像',
+    searchPlaceholder: '搜索货号',
+    noData: '暂无数据,请先进行拍摄',
+    loading: '数据正在加载中,请稍候...',
+    imageCount: '张图片',
+    advancedGenerate: '高级生成',
+    retake: '重拍',
+    delete: '删除',
+  },
+
+  // 主图与详情生成
+  photoDetail: {
+    sceneGenerate: '场景图生成',
+    modelGenerate: '模特图生成',
+    detailGenerate: '详情页生成',
+    customTemplate: '新增自定义详情页模板',
+    templateDeveloping: '功能开发中',
+    templateCustom: '详情页模板自定义',
+    whiteBgExport: '白底图批量导出',
+    productAlbum: '产品图册生成',
+    tipTitle: '提示',
+  },
+
+  // 设置页
+  setting: {
+    title: '设置',
+    basicConfig: '基础配置',
+    cameraConfig: '相机配置',
+    otherConfig: '其他设置',
+    leftRightConfig: '左右脚程序设置',
+    mainImageSize: '主图尺寸:',
+    customSize: '自定义尺寸:',
+    inputSizeTip: '请输入1-3000的尺寸值',
+    imageFormat: '图片输出格式:',
+    imageSharpen: '图片锐化:',
+    sharpenTip: '数值1-5,值为1则代表不处理',
+    shadowMode: '阴影处理模式:',
+    shadowDefault: '默认模式',
+    shadowCustom: '自定义模式',
+    opacity: '透明度:',
+    inputOpacityTip: '请输入0.5-1之间的值',
+    brightnessRange: '亮度范围:',
+    inputBrightnessTip: '请输入200-255之间的值',
+    customPadding800: '800图自定义边距:',
+    inputPaddingTip: '请输入0-500的整数',
+    flip800: '800图是否翻转:',
+    color800: '800图颜色配置:',
+    productType: '产品类型:',
+    defaultCutout: '默认抠图模式:',
+    deviceSpeed: '设备运动速度:',
+    speedFast: '快',
+    speedMedium: '中',
+    speedSlow: '慢',
+  },
+
+  // OTA/版本更新
+  ota: {
+    currentVersion: '当前版本:',
+    status: '状态:',
+    latest: '您已经是最新版本',
+    newVersion: '发现新版本',
+    downloadUpdate: '下载更新',
+    changelog: '更新日志:',
+    historyVersions: '历史版本',
+    versionNumber: '版本号',
+    releaseDate: '发布日期',
+    description: '描述',
+    operation: '操作',
+    versionDetail: '版本详情',
+    downloading: '下载中',
+    downloadFailed: '下载失败',
+    noDetail: '暂无详情',
+  },
+
+  // 过期页
+  expired: {
+    title: '企业账户已过期',
+    expiredMsg: '您的企业账户已过期,无法继续使用系统功能。',
+    contactAdmin: '联系方式',
+    contactMsg: '请通过以下方式联系管理员:\n\n电话:400-xxx-xxxx\n邮箱:admin@company.com\n\n或扫描下方二维码添加客服微信',
+    relogin: '重新登录',
+    gotIt: '知道了',
+    logoutFailed: '退出登录失败,请重试',
+  },
+
+  // 菜单项
+  menu: {
+    setting: '设置',
+    generateDir: '生成图目录',
+    switchMode: '切换模式',
+    history: '历史记录',
+    modelImage: '模特图',
+    sceneImage: '场景图',
+    generateVideo: '生成视频',
+  },
+
+  // 模板相关
+  tpl: {
+    addCanvas: '新增画布',
+    editCanvas: '编辑画布',
+    normalCanvas: '普通画布,可编辑内容',
+    modelCanvas: '模特图占位,用于前台/后端生成时替换',
+    sceneCanvas: '场景图占位,用于前台/后端生成时替换',
+    modeDefault: '默认模式,画布对应单个货号',
+    modeSingle: '一个画布对应一个货号,画布中包含该货号不同角度的图片',
+    modeMultiple: '画布中含有多个货号,画布中包含多个货号同一角度的图片',
+    editing: '正在编辑',
+    switchCanvas: '切换画布',
+    layerImage: '图片',
+    layerText: '文字',
+    layerGroup: '组合',
+    layerDynamic: '动态',
+    layerShow: '显示',
+    layerHide: '隐藏',
+  },
+
+  // 商品字段
+  goods: {
+    color: '颜色',
+    goodsArtNo: '货号',
+    designConcept: '设计理念',
+    title: '标题',
+    styleNo: '款号',
+  },
+
+  // 状态
+  status: {
+    processing: '处理中',
+    completed: '已完成',
+    failed: '失败',
+    pending: '等待中',
+    connected: '已连接',
+    disconnected: '未连接',
+    allFailed: '全部货号生成失败',
+  },
+
+  // Element Plus 默认消息
+  el: {
+    confirm: '确定',
+    cancel: '取消',
+    loading: '加载中...',
+  },
+
+  // 开发者页
+  developer: {
+    title: '初始设备调频设置',
+    tabSetting: '设置',
+    tabMCU: 'MCU其他配置设置',
+    tabRS485: 'RS485调试发送',
+    cameraSetting: '相机设置',
+    turntableSetting: '转盘设置',
+    flipServo: '翻版舵机',
+    cameraHeight: '相机高度mm:',
+    cameraAngle: '相机角度(度):',
+    angleOffset: '角度偏移(度):',
+    frontBackOffset: '前后偏移:',
+    middlePos: '中位:',
+    highPos: '高位:',
+    riseSpeed: '上升速度:',
+    fallSpeed: '下降速度:',
+    setValue: '设定',
+    minMaxTip: '最小{min},最大{max}',
+    valueRangeTip: '{name}值应在{min}到{max}之间',
+    deviceInit: '设备初始化',
+    readOffset: '读取偏移量并运行',
+    allSet: '整体设定',
+    readConfig: '读取配置',
+    setConfig: '设置配置',
+    setSuccess: '设定成功',
+    setFailed: '设置失败',
+    readFirst: '请先获取设备参数',
+    sendCmd: '发送',
+  },
+
+  // 相机配置
+  cameraConfig: {
+    bindCamera: '绑定相机:',
+    selectCamera: '请选择相机',
+    refresh: '刷新',
+    photoISO: '拍照ISO:',
+    previewISO: '预览ISO:',
+    select: '请选择',
+    pointLabel: '点位 {point}',
+    connected: '已连接相机',
+    notConnected: '未连接相机',
+    notSet: '未设置相机',
+    isoMustPositive: '{name}必须大于0',
+    selectISO: '请选择{name}',
+    cameraConnected: '相机连接状态已更新',
+    noCameraList: '未获取到相机列表',
+    refreshFailed: '刷新失败,请稍后重试',
+  },
+
+  // 充值
+  recharge: {
+    remainingCoins: '剩余金币:',
+    recharge: '充值',
+    rechargeTitle: '充值金币',
+    coinTip: '(用户视频生成,需单独金币支付)',
+    loading: '加载中,请稍候...',
+  },
+
+  // 详情页
+  photoDetail2: {
+    selectTemplate: '选择详情模版',
+    mainImageLogo: '主图LOGO',
+    clickOrDragUpload: '点击或拖拽上传',
+    supportPngJpg: '支持PNG、JPG格式',
+    logoFileNotExist: 'LOGO指向的文件不存在或加载失败,请重新上传',
+    reupload: '重新上传',
+    preview: '预览',
+    dataPrep: '详情资料准备',
+    excelUpload: 'Excel上传',
+    systemIntegration: '系统对接',
+    clickSelectFile: '点击选择文件',
+    fileSelected: '已选择文件',
+    downloadExcelTemplate: '下载通用商品基础资料模版',
+    forNonCustomDetail: '用于非自定义详情页的商品基础资料模版',
+    oneKeyPublish: '一键上架平台',
+    domesticEcommerce: '国内电商平台:',
+    crossBorderEcommerce: '跨境电商平台:',
+    startGenerate: '开始生成',
+    processingProgress: '处理进度',
+    openFolder: '打开目录',
+    viewDetails: '查看详情',
+    edit: '编辑',
+    delete: '删除',
+    downloadExcelTemplate2: '下载EXECL模版',
+    selectTemplateFirst: '请先选中详情页生成,后在选择模板详情',
+    templateRequires: '该模版需提供{count}张标准视角的商品图:{order}。请确保图片清晰度高,背景干净。',
+    pleaseSelectService: '请选择服务内容',
+    pleaseSelectMaleFemaleModel: '请选择男模特和女模特',
+    pleaseSelectMaleModel: '请选择男模特',
+    pleaseSelectFemaleModel: '请选择女模特',
+    pleaseSetScenePrompt: '请设置场景提示词',
+    pleaseUploadGoodsData: '请上传商品基础资料',
+    logoLoadError: 'LOGO加载出错或文件已被删除,请重新上传',
+    processing: '正在为您处理,请稍后',
+    allGenerateSuccess: '全部生成成功',
+    partGenerateFailed: '部分货号生成失败',
+    allGenerateFailed: '全部货号生成失败',
+    logoPreview: 'LOGO预览',
+    sceneGenerate: '场景图生成',
+    modelGenerate: '模特图生成',
+    detailGenerate: '详情页生成',
+    addCustomTemplate: '新增自定义详情页模板',
+    detailTemplateCustom: '详情页模板自定义',
+    functionDeveloping: '功能开发中',
+    whiteBgExport: '白底图批量导出',
+    productAlbum: '产品图册生成',
+    whiteBgExportStarted: '白底图批量导出工具已启动',
+    productAlbumStarted: '产品图册生成工具已启动',
+    deleteTemplateConfirm: '确定要删除自定义模板「{name}」吗?',
+    deleteSuccess: '删除成功',
+    deleteFailed: '删除失败',
+    goodsNo: '货号',
+  },
+
+  // 高级配置
+  seniorDetail: {
+    title: '主图与详情高级配置',
+    cutoutAndGoodsGenerate: '图片抠图与货号图生成',
+    cutoutTip1: '请在下方确认图片拍摄过程中的顺序,确保所有拍摄的图片的顺序一致。',
+    cutoutTip2: '使用中英文语号分隔。',
+    cutoutTip3: '图片的名称不能随意修改,否则无法正常生成详情页。',
+    cutoutTip4: '现有图片名称有:俯视、侧视、后视、鞋底、内里',
+    goodsFolder: '货号文件夹:',
+    selectGoodsFolder: '请选择货号文件夹',
+    selectTargetFolder: '选择目标文件夹',
+    selectGoodsParentFolder: '选择货号的上级文件夹',
+    cutoutMode: '抠图模式:',
+    normalMode: '普通模式',
+    refinedCutout: '精细化扣图',
+    detailAdvancedConfig: '详情高级配置',
+    imageOrder: '图片顺序:',
+    inputImageOrder: '请输入图片顺序',
+    imageOrderExplain: '说明',
+    sameStyleCheck: '同款检验:',
+    sameStyleMustComplete: '同款下货号必须齐全',
+    specifyPageModify: '可指定页面独修改:',
+    inputSpecifyPage: '请输入入需要单独修改的页面,示例:4:1 (需修改模版的编号:第一张)',
+    specifyPageExplain: '说明',
+    saveConfig: '保存配置',
+    startProcess: '开始处理',
+    allProcessComplete: '全部处理完毕',
+    openDir: '打开目录',
+  },
+
+  // 加载弹窗
+  loadingDialog: {
+    processing: '正在为您处理,请稍后...',
+    processComplete: '处理完毕,点击打开最终图片目录',
+  },
+
+  // 编辑行
+  editRow: {
+    title: '参数值编辑',
+    actionNameChangeTip: '动作名称修改后,可能会导致自定义模板生成失效!',
+    actionName: '动作名称',
+    shotPoint: '拍摄点位',
+    selectPoint: '请选择点位',
+    pointLabel: '点位 {point}',
+    takePhoto: '是否拍照',
+    photo: '拍照',
+    noPhoto: '不拍照',
+    cameraHeight: '相机高度(mm)',
+    cameraAngle: '相机倾角',
+    turntablePosition: '转盘前后位置',
+    turntableAngle: '转盘角度',
+    shoeFlip: '鞋子翻转',
+    flip: '翻转',
+    noFlip: '不翻转',
+    testFlip: '测试翻转',
+    ledSwitch: 'LED灯光开关',
+    off: '关闭',
+    on: '开启',
+    focusCount: '对焦次数',
+    preDelay: '拍照前延时(秒)',
+    postDelay: '拍照后延时(秒)',
+    minMaxTip: '最小{min},最大{max}',
+    cancel: '取消',
+    run: '运行',
+    saveClose: '保存并关闭',
+    pleaseInputActionName: '请输入动作名称',
+    pleaseSelectPoint: '请选择拍摄点位',
+    saveSuccess: '保存成功',
+  },
+
+  // 硬件检测
+  hardwareCheck: {
+    title: '检测硬件',
+    checkingHardware: '正在初始化检测硬件......',
+    hardwareCheckComplete: '硬件检测完成',
+    hardwareCheckFailed: '初始化检测硬件失败',
+    selfCheck: '自我检查',
+    checkTip1: '补光灯电源和连接器是否正常连上。',
+    checkTip2: '请检查红外线器是否正常显示。',
+    reCheck: '重新监测一次',
+    viewDeviceStatus: '查看设备状态',
+    checkSuccessContinue: '检测成功,继续操作!',
+    deviceStatus: '设备运行状态',
+    cancel: '取消',
+    refresh: '刷新',
+    getStatusFailed: '获取设备状态失败',
+    getStatusTimeout: '获取设备状态超时',
+    statusNotInit: '未初始化',
+    statusMoving: '运动中',
+    statusStopped: '已停止',
+    statusOffline: '未在线',
+    statusBlocked: '堵转',
+    statusUnknown: '未知状态',
+    cameraHeightStatus: '相机高度状态',
+    cameraAngleStatus: '相机角度状态',
+    turntableStatus: '转盘状态',
+    turntableMoveStatus: '转盘前后移动状态',
+    flipBoardStatus: '翻板状态',
+  },
+
+  // 拍摄页面底部
+  shot: {
+    clickToStartCamera: '点击屏幕以启动拍照机',
+    initHardware: '正在初始化拍照硬件......',
+    progress: '共检查至',
+  },
+
+}

+ 36 - 0
frontend/src/utils/language.ts

@@ -0,0 +1,36 @@
+// 语言工具函数
+const LANGUAGE_KEY = 'camera_machine_language'
+
+export type SupportedLocale = 'zh-CN' | 'en'
+
+const SUPPORTED_LOCALES: SupportedLocale[] = ['zh-CN', 'en']
+
+export function getLanguage(): SupportedLocale {
+  // 1. 优先从 localStorage 读取用户偏好
+  const stored = localStorage.getItem(LANGUAGE_KEY)
+  if (stored && SUPPORTED_LOCALES.includes(stored as SupportedLocale)) {
+    return stored as SupportedLocale
+  }
+
+  // 2. 其次从浏览器语言自动检测
+  const browserLang = navigator.language || (navigator as any).userLanguage || ''
+  const shortLang = browserLang.split('-')[0]
+  if (shortLang === 'en') {
+    return 'en'
+  }
+
+  // 3. 默认中文
+  return 'zh-CN'
+}
+
+export function setLanguage(lang: SupportedLocale): void {
+  localStorage.setItem(LANGUAGE_KEY, lang)
+  document.documentElement.setAttribute('lang', lang)
+}
+
+export function getSupportedLanguages(): { value: SupportedLocale; label: string }[] {
+  return [
+    { value: 'zh-CN', label: '简体中文' },
+    { value: 'en', label: 'English' },
+  ]
+}