1. 新增TDashboard翻译类型与多语言文案 2. 完善macOS权限管理与Impeller渲染适配 3. 更新服务器部署配置与协议文件上传脚本 4. 修复翻译导入服务与根类型编译问题
1711 lines
68 KiB
Dart
1711 lines
68 KiB
Dart
/// ============================================================
|
||
/// 闲言APP — 翻译导出/导入服务
|
||
/// 创建时间: 2026-05-19
|
||
/// 更新时间: 2026-06-26
|
||
/// 作用: 将翻译数据导出为JSON/从JSON导入,支持协同翻译
|
||
/// 上次更新: importFromJson 的 return T(...) 补 dashboard: fallback.dashboard(修复 required 字段缺失编译错误)
|
||
/// ============================================================
|
||
|
||
import 'dart:convert';
|
||
|
||
import 'translations.dart';
|
||
|
||
class TranslationIOService {
|
||
static Map<String, dynamic> _tNavToMap(TNav nav) => {
|
||
'home': nav.home,
|
||
'discover': nav.discover,
|
||
'profile': nav.profile,
|
||
};
|
||
|
||
static Map<String, dynamic> _tCommonToMap(TCommon common) => {
|
||
'cancel': common.cancel,
|
||
'ok': common.ok,
|
||
'save': common.save,
|
||
'confirm': common.confirm,
|
||
'clear': common.clear,
|
||
'reset': common.reset,
|
||
'delete': common.delete,
|
||
'success': common.success,
|
||
'failed': common.failed,
|
||
'enabled': common.enabled,
|
||
'disabled': common.disabled,
|
||
'loading': common.loading,
|
||
'view': common.view,
|
||
'search': common.search,
|
||
'entriesCountUnit': common.entriesCountUnit,
|
||
'copyright': common.copyright,
|
||
};
|
||
|
||
static Map<String, dynamic> _tProfileToMap(TProfile profile) => {
|
||
'title': profile.title,
|
||
'myFavorites': profile.myFavorites,
|
||
'readingHistory': profile.readingHistory,
|
||
'darkMode': profile.darkMode,
|
||
'accountSettings': profile.accountSettings,
|
||
'dataManagement': profile.dataManagement,
|
||
'offlineMode': profile.offlineMode,
|
||
'cacheManagement': profile.cacheManagement,
|
||
'themeCustomization': profile.themeCustomization,
|
||
'desktopWidgets': profile.desktopWidgets,
|
||
'sentenceSource': profile.sentenceSource,
|
||
'aboutApp': profile.aboutApp,
|
||
'rateApp': profile.rateApp,
|
||
'debugMode': profile.debugMode,
|
||
'tapToLogin': profile.tapToLogin,
|
||
'defaultUserName': profile.defaultUserName,
|
||
'appSlogan': profile.appSlogan,
|
||
'freeTier': profile.freeTier,
|
||
'points': profile.points,
|
||
'checkin': profile.checkin,
|
||
'notes': profile.notes,
|
||
'quickActions': profile.quickActions,
|
||
'scanQr': profile.scanQr,
|
||
'nearbyTransfer': profile.nearbyTransfer,
|
||
'payment': profile.payment,
|
||
'selectScanMethod': profile.selectScanMethod,
|
||
'scanQrLogin': profile.scanQrLogin,
|
||
'scanQrCode': profile.scanQrCode,
|
||
'appStoreNotFound': profile.appStoreNotFound,
|
||
'experimentalFeature': profile.experimentalFeature,
|
||
'underReview': profile.underReview,
|
||
'changeAvatar': profile.changeAvatar,
|
||
'inputAvatarUrl': profile.inputAvatarUrl,
|
||
'selectFromAlbum': profile.selectFromAlbum,
|
||
'avatarUrlHint': profile.avatarUrlHint,
|
||
'pleaseInputUrl': profile.pleaseInputUrl,
|
||
'urlMustStartWithHttp': profile.urlMustStartWithHttp,
|
||
'urlTooLong': profile.urlTooLong,
|
||
'invalidUrlFormat': profile.invalidUrlFormat,
|
||
'avatarUnderReview': profile.avatarUnderReview,
|
||
'avatarReviewing': profile.avatarReviewing,
|
||
'avatarChangeSuccess': profile.avatarChangeSuccess,
|
||
'avatarChangeFailed': profile.avatarChangeFailed,
|
||
'success': profile.success,
|
||
'failed': profile.failed,
|
||
'ok': profile.ok,
|
||
'loading': profile.loading,
|
||
'loginToViewProfile': profile.loginToViewProfile,
|
||
'goLogin': profile.goLogin,
|
||
'consecutiveCheckin': profile.consecutiveCheckin,
|
||
'favorites': profile.favorites,
|
||
'likes': profile.likes,
|
||
'dailyCheckin': profile.dailyCheckin,
|
||
'learningCenter': profile.learningCenter,
|
||
'achievementCenter': profile.achievementCenter,
|
||
'dailyTask': profile.dailyTask,
|
||
'leaderboard': profile.leaderboard,
|
||
'dataStatistics': profile.dataStatistics,
|
||
'myNotes': profile.myNotes,
|
||
'contentCorrection': profile.contentCorrection,
|
||
'myDevices': profile.myDevices,
|
||
'tagCloud': profile.tagCloud,
|
||
'deviceRemoveCurrentTitle': profile.deviceRemoveCurrentTitle,
|
||
'deviceRemoveCurrentWarning': profile.deviceRemoveCurrentWarning,
|
||
'deviceContinueRemove': profile.deviceContinueRemove,
|
||
'deviceVerifyIdentityRemove': profile.deviceVerifyIdentityRemove,
|
||
'deviceRemoveTitle': profile.deviceRemoveTitle,
|
||
'deviceRemoveConfirm': profile.deviceRemoveConfirm,
|
||
'deviceRemoved': profile.deviceRemoved,
|
||
'deviceRemoveFailed': profile.deviceRemoveFailed,
|
||
'personalInfo': profile.personalInfo,
|
||
'username': profile.username,
|
||
'nickname': profile.nickname,
|
||
'bio': profile.bio,
|
||
'notSet': profile.notSet,
|
||
'notFilled': profile.notFilled,
|
||
'set': profile.set,
|
||
'reviewing': profile.reviewing,
|
||
'editUsername': profile.editUsername,
|
||
'editNickname': profile.editNickname,
|
||
'nearbyDiscovery': profile.nearbyDiscovery,
|
||
'nearbyDiscoveryDesc': profile.nearbyDiscoveryDesc,
|
||
'totalTasks': profile.totalTasks,
|
||
'taskClaimed': profile.taskClaimed,
|
||
'perfectDay': profile.perfectDay,
|
||
'perfectDayAllDone': profile.perfectDayAllDone,
|
||
'perfectDayReward': profile.perfectDayReward,
|
||
'perfectDayRewardDesc': profile.perfectDayRewardDesc,
|
||
'claimPerfectDayReward': profile.claimPerfectDayReward,
|
||
'rewardSuffix': profile.rewardSuffix,
|
||
'expUnit': profile.expUnit,
|
||
'scoreUnit': profile.scoreUnit,
|
||
'noTasks': profile.noTasks,
|
||
'noTasksDesc': profile.noTasksDesc,
|
||
'great': profile.great,
|
||
'loginToCheckin': profile.loginToCheckin,
|
||
'loginToCheckinDesc': profile.loginToCheckinDesc,
|
||
'viewAchievementCenter': profile.viewAchievementCenter,
|
||
'todaySigned': profile.todaySigned,
|
||
'tapToCheckin': profile.tapToCheckin,
|
||
'signed': profile.signed,
|
||
'weeklyCheckin': profile.weeklyCheckin,
|
||
'totalCheckinDays': profile.totalCheckinDays,
|
||
'checkinHistory': profile.checkinHistory,
|
||
'noCheckinRecord': profile.noCheckinRecord,
|
||
'todayLabel': profile.todayLabel,
|
||
'checkinDate': profile.checkinDate,
|
||
'status': profile.status,
|
||
'signedStatus': profile.signedStatus,
|
||
'remark': profile.remark,
|
||
'dailyCheckinTaskDone': profile.dailyCheckinTaskDone,
|
||
'makeupCheckin': profile.makeupCheckin,
|
||
'makeupCostInfo': profile.makeupCostInfo,
|
||
'makeupDate': profile.makeupDate,
|
||
'costPoints': profile.costPoints,
|
||
'currentPoints': profile.currentPoints,
|
||
'makeupInfo': profile.makeupInfo,
|
||
'makeupLimitInfo': profile.makeupLimitInfo,
|
||
'confirmMakeup': profile.confirmMakeup,
|
||
'insufficientPoints': profile.insufficientPoints,
|
||
'insufficientPointsDesc': profile.insufficientPointsDesc,
|
||
'makeupSuccess': profile.makeupSuccess,
|
||
'makeupSuccessDesc': profile.makeupSuccessDesc,
|
||
'makeupFailed': profile.makeupFailed,
|
||
'makeupFailedRetry': profile.makeupFailedRetry,
|
||
'timesUnit': profile.timesUnit,
|
||
'daysUnit': profile.daysUnit,
|
||
'accountAndData': profile.accountAndData,
|
||
'editProfile': profile.editProfile,
|
||
'edit': profile.edit,
|
||
'editBio': profile.editBio,
|
||
'save': profile.save,
|
||
'pleaseInput': profile.pleaseInput,
|
||
'modifySuccess': profile.modifySuccess,
|
||
'modifyFailed': profile.modifyFailed,
|
||
'userProfile': profile.userProfile,
|
||
'goBack': profile.goBack,
|
||
'userNotExist': profile.userNotExist,
|
||
'retry': profile.retry,
|
||
'anonymousUser': profile.anonymousUser,
|
||
'articles': profile.articles,
|
||
'follow': profile.follow,
|
||
'followed': profile.followed,
|
||
'theUser': profile.theUser,
|
||
'privateMessage': profile.privateMessage,
|
||
'gotIt': profile.gotIt,
|
||
'shareProfile': profile.shareProfile,
|
||
'blockUser': profile.blockUser,
|
||
'personalBio': profile.personalBio,
|
||
'titleLevel': profile.titleLevel,
|
||
'activeData': profile.activeData,
|
||
'beginner': profile.beginner,
|
||
'apprentice': profile.apprentice,
|
||
'skilled': profile.skilled,
|
||
'expert': profile.expert,
|
||
'master': profile.master,
|
||
'signInCount': profile.signInCount,
|
||
'noteCount': profile.noteCount,
|
||
'likeCount': profile.likeCount,
|
||
'commentCount': profile.commentCount,
|
||
'viewCount': profile.viewCount,
|
||
'readLaterCount': profile.readLaterCount,
|
||
'modifyField': profile.modifyField,
|
||
'pleaseInputField': profile.pleaseInputField,
|
||
'fieldModifySuccess': profile.fieldModifySuccess,
|
||
'fieldModifyFailed': profile.fieldModifyFailed,
|
||
'debugInfo': profile.debugInfo,
|
||
'defaultBio': profile.defaultBio,
|
||
};
|
||
|
||
static Map<String, dynamic> _tSettingsToMap(TSettings settings) => {
|
||
'generalSettings': settings.generalSettings,
|
||
'language': settings.language,
|
||
'languageSubtitle': settings.languageSubtitle,
|
||
'selectLanguage': settings.selectLanguage,
|
||
'followSystem': settings.followSystem,
|
||
'collaborativeTranslation': settings.collaborativeTranslation,
|
||
'collaborativeTranslationDesc': settings.collaborativeTranslationDesc,
|
||
'interaction': settings.interaction,
|
||
'sound': settings.sound,
|
||
'soundSubtitle': settings.soundSubtitle,
|
||
'vibration': settings.vibration,
|
||
'vibrationSubtitle': settings.vibrationSubtitle,
|
||
'soundEffect': settings.soundEffect,
|
||
'soundEffectSubtitle': settings.soundEffectSubtitle,
|
||
'pageTransitionMode': settings.pageTransitionMode,
|
||
'pageTransitionModeNavigate': settings.pageTransitionModeNavigate,
|
||
'pageTransitionModeSheet': settings.pageTransitionModeSheet,
|
||
'predictiveBack': settings.predictiveBack,
|
||
'predictiveBackSubtitle': settings.predictiveBackSubtitle,
|
||
'longPressPreview': settings.longPressPreview,
|
||
'longPressPreviewSubtitle': settings.longPressPreviewSubtitle,
|
||
'notification': settings.notification,
|
||
'pushNotification': settings.pushNotification,
|
||
'pushNotificationSubtitle': settings.pushNotificationSubtitle,
|
||
'display': settings.display,
|
||
'screenTimeout': settings.screenTimeout,
|
||
'screenTimeoutSubtitle': settings.screenTimeoutSubtitle,
|
||
'fontSize': settings.fontSize,
|
||
'fontSizeSubtitle': settings.fontSizeSubtitle,
|
||
'startupPage': settings.startupPage,
|
||
'startupPageSubtitle': settings.startupPageSubtitle,
|
||
'immersiveStatus': settings.immersiveStatus,
|
||
'immersiveStatusSubtitle': settings.immersiveStatusSubtitle,
|
||
'contentDensity': settings.contentDensity,
|
||
'contentDensitySubtitle': settings.contentDensitySubtitle,
|
||
'reduceAnimations': settings.reduceAnimations,
|
||
'reduceAnimationsSubtitle': settings.reduceAnimationsSubtitle,
|
||
'performance': settings.performance,
|
||
'smartMode': settings.smartMode,
|
||
'smartModeSubtitle': settings.smartModeSubtitle,
|
||
'preload': settings.preload,
|
||
'preloadSubtitle': settings.preloadSubtitle,
|
||
'cacheStrategy': settings.cacheStrategy,
|
||
'cacheStrategySubtitle': settings.cacheStrategySubtitle,
|
||
'imageQuality': settings.imageQuality,
|
||
'imageQualityOriginal': settings.imageQualityOriginal,
|
||
'imageQualitySaver': settings.imageQualitySaver,
|
||
'imageQualityBalanced': settings.imageQualityBalanced,
|
||
'dataSaver': settings.dataSaver,
|
||
'dataSaverSubtitle': settings.dataSaverSubtitle,
|
||
'privacyAndPermissions': settings.privacyAndPermissions,
|
||
'appLock': settings.appLock,
|
||
'appLockSubtitle': settings.appLockSubtitle,
|
||
'clipboardRead': settings.clipboardRead,
|
||
'clipboardReadSubtitle': settings.clipboardReadSubtitle,
|
||
'permissionManagement': settings.permissionManagement,
|
||
'permissionManagementSubtitle': settings.permissionManagementSubtitle,
|
||
'privacyPolicy': settings.privacyPolicy,
|
||
'privacyPolicySubtitle': settings.privacyPolicySubtitle,
|
||
'advanced': settings.advanced,
|
||
'moreSettings': settings.moreSettings,
|
||
'moreSettingsSubtitle': settings.moreSettingsSubtitle,
|
||
'autoCheckUpdate': settings.autoCheckUpdate,
|
||
'autoCheckUpdateSubtitle': settings.autoCheckUpdateSubtitle,
|
||
'syncSettings': settings.syncSettings,
|
||
'syncSettingsSubtitle': settings.syncSettingsSubtitle,
|
||
'logManagement': settings.logManagement,
|
||
'logManagementSubtitle': settings.logManagementSubtitle,
|
||
'exportImportSettings': settings.exportImportSettings,
|
||
'exportImportSettingsSubtitle': settings.exportImportSettingsSubtitle,
|
||
'dataExport': settings.dataExport,
|
||
'dataExportSubtitle': settings.dataExportSubtitle,
|
||
'clearCache': settings.clearCache,
|
||
'clearCacheSubtitle': settings.clearCacheSubtitle,
|
||
'resetSettings': settings.resetSettings,
|
||
'resetSettingsSubtitle': settings.resetSettingsSubtitle,
|
||
'youMayBeLookingFor': settings.youMayBeLookingFor,
|
||
'fontManagement': settings.fontManagement,
|
||
'clearCacheConfirm': settings.clearCacheConfirm,
|
||
'resetSettingsConfirm': settings.resetSettingsConfirm,
|
||
'exportSettings': settings.exportSettings,
|
||
'importSettings': settings.importSettings,
|
||
'importSettingsDesc': settings.importSettingsDesc,
|
||
'confirmImport': settings.confirmImport,
|
||
'importSuccess': settings.importSuccess,
|
||
'importFailed': settings.importFailed,
|
||
'pasteJson': settings.pasteJson,
|
||
'pasteJsonPlaceholder': settings.pasteJsonPlaceholder,
|
||
'vibrationStrength': settings.vibrationStrength,
|
||
'soundEffectStyle': settings.soundEffectStyle,
|
||
'screenTimeoutTitle': settings.screenTimeoutTitle,
|
||
'startupPageTitle': settings.startupPageTitle,
|
||
'pageTransitionModeTitle': settings.pageTransitionModeTitle,
|
||
'contentDensityTitle': settings.contentDensityTitle,
|
||
'cacheStrategyTitle': settings.cacheStrategyTitle,
|
||
'imageQualityTitle': settings.imageQualityTitle,
|
||
'navigateDescDetail': settings.navigateDescDetail,
|
||
'sheetDescDetail': settings.sheetDescDetail,
|
||
'standardNavigation': settings.standardNavigation,
|
||
'bottomSheet': settings.bottomSheet,
|
||
};
|
||
|
||
static Map<String, dynamic> _tNoteToMap(TNote note) => {
|
||
// 页面标题与导航
|
||
'title': note.title,
|
||
'searchNotes': note.searchNotes,
|
||
'editNote': note.editNote,
|
||
'newNote': note.newNote,
|
||
// 登录守卫
|
||
'loginRequired': note.loginRequired,
|
||
'loginToUseNotes': note.loginToUseNotes,
|
||
'goLogin': note.goLogin,
|
||
// 搜索
|
||
'searchPlaceholder': note.searchPlaceholder,
|
||
// 筛选类型
|
||
'all': note.all,
|
||
'note': note.note,
|
||
'excerpt': note.excerpt,
|
||
'checklist': note.checklist,
|
||
// 排序与分组
|
||
'sortBy': note.sortBy,
|
||
'sortByUpdateTime': note.sortByUpdateTime,
|
||
'sortByCreateTime': note.sortByCreateTime,
|
||
'sortByTitle': note.sortByTitle,
|
||
'groupBy': note.groupBy,
|
||
'groupByDate': note.groupByDate,
|
||
'groupByCategory': note.groupByCategory,
|
||
'groupByType': note.groupByType,
|
||
'groupBySource': note.groupBySource,
|
||
// 布局
|
||
'switchLayout': note.switchLayout,
|
||
'layoutList': note.layoutList,
|
||
'layoutGrid': note.layoutGrid,
|
||
'layoutTimeline': note.layoutTimeline,
|
||
// 选择模式
|
||
'selectedCount': note.selectedCount,
|
||
'selectAll': note.selectAll,
|
||
'deselectAll': note.deselectAll,
|
||
'batchSelect': note.batchSelect,
|
||
'multiSelect': note.multiSelect,
|
||
// 批量操作
|
||
'batchDelete': note.batchDelete,
|
||
'batchDeleteConfirm': note.batchDeleteConfirm,
|
||
'deletedCount': note.deletedCount,
|
||
// 拖拽排序
|
||
'dragReorder': note.dragReorder,
|
||
'dragToReorder': note.dragToReorder,
|
||
// 上下文菜单
|
||
'starFavorite': note.starFavorite,
|
||
'unfavorite': note.unfavorite,
|
||
'exportNote': note.exportNote,
|
||
'copyNote': note.copyNote,
|
||
// 菜单项
|
||
'newNoteMenu': note.newNoteMenu,
|
||
'sortMenu': note.sortMenu,
|
||
'groupMenu': note.groupMenu,
|
||
'showStarOnly': note.showStarOnly,
|
||
'showAll': note.showAll,
|
||
'statsPanel': note.statsPanel,
|
||
'reorderMenu': note.reorderMenu,
|
||
// 清空全部
|
||
'confirmClear': note.confirmClear,
|
||
'clearAllWarning': note.clearAllWarning,
|
||
'clearAll': note.clearAll,
|
||
'allCleared': note.allCleared,
|
||
// 空状态
|
||
'noNotes': note.noNotes,
|
||
'tapToStart': note.tapToStart,
|
||
// 底部
|
||
'reachedBottom': note.reachedBottom,
|
||
'notesCount': note.notesCount,
|
||
// 日期标签
|
||
'unknownDate': note.unknownDate,
|
||
'today': note.today,
|
||
'yesterday': note.yesterday,
|
||
// 分组标签
|
||
'uncategorized': note.uncategorized,
|
||
'noSource': note.noSource,
|
||
// 笔记卡片
|
||
'noTitle': note.noTitle,
|
||
// 删除
|
||
'deleteNote': note.deleteNote,
|
||
'deleteNoteConfirm': note.deleteNoteConfirm,
|
||
// 编辑页
|
||
'noteLoadFailed': note.noteLoadFailed,
|
||
'titlePlaceholder': note.titlePlaceholder,
|
||
'categoryLabel': note.categoryLabel,
|
||
'sourceLabel': note.sourceLabel,
|
||
'publicLabel': note.publicLabel,
|
||
'optionalPlaceholder': note.optionalPlaceholder,
|
||
'visibleToAll': note.visibleToAll,
|
||
'visibleToSelf': note.visibleToSelf,
|
||
'selectSourceType': note.selectSourceType,
|
||
'excerptPlaceholder': note.excerptPlaceholder,
|
||
'checklistPlaceholder': note.checklistPlaceholder,
|
||
'notePlaceholder': note.notePlaceholder,
|
||
'noPreviewContent': note.noPreviewContent,
|
||
'switchToEdit': note.switchToEdit,
|
||
'selectPreviewFont': note.selectPreviewFont,
|
||
'systemDefault': note.systemDefault,
|
||
'noTitleNote': note.noTitleNote,
|
||
'noteSaved': note.noteSaved,
|
||
'unsaved': note.unsaved,
|
||
'saved': note.saved,
|
||
'charCount': note.charCount,
|
||
// 来源类型
|
||
'sourcePoetry': note.sourcePoetry,
|
||
'sourceArticle': note.sourceArticle,
|
||
'sourceHanzi': note.sourceHanzi,
|
||
'sourceIdiom': note.sourceIdiom,
|
||
// Markdown 工具栏
|
||
'bold': note.bold,
|
||
'italic': note.italic,
|
||
'heading': note.heading,
|
||
'list': note.list,
|
||
'orderedList': note.orderedList,
|
||
'quote': note.quote,
|
||
'link': note.link,
|
||
'code': note.code,
|
||
'divider': note.divider,
|
||
// 统计面板
|
||
'noteStats': note.noteStats,
|
||
'totalNotes': note.totalNotes,
|
||
'weekNew': note.weekNew,
|
||
'totalWords': note.totalWords,
|
||
'typeDistribution': note.typeDistribution,
|
||
'categoryDistribution': note.categoryDistribution,
|
||
'noCategoryData': note.noCategoryData,
|
||
'starredNotes': note.starredNotes,
|
||
// 导出
|
||
'exportTitle': note.exportTitle,
|
||
'exportCountNote': note.exportCountNote,
|
||
'copiedToClipboard': note.copiedToClipboard,
|
||
'exportTypeLabel': note.exportTypeLabel,
|
||
'exportCategoryLabel': note.exportCategoryLabel,
|
||
'exportPublicYes': note.exportPublicYes,
|
||
'exportSourceLabel': note.exportSourceLabel,
|
||
'exportCreateTime': note.exportCreateTime,
|
||
'exportUpdateTime': note.exportUpdateTime,
|
||
'exportShareSubject': note.exportShareSubject,
|
||
// 置顶
|
||
'pinToDiscover': note.pinToDiscover,
|
||
'pinToDiscoverDesc': note.pinToDiscoverDesc,
|
||
'close': note.close,
|
||
'pinnedToDiscover': note.pinnedToDiscover,
|
||
'unpinnedFromDiscover': note.unpinnedFromDiscover,
|
||
'confirmPin': note.confirmPin,
|
||
'confirmUnpin': note.confirmUnpin,
|
||
};
|
||
|
||
static Map<String, dynamic> _tBetaToMap(TBeta beta) => {
|
||
// 页面级
|
||
'pageTitle': beta.pageTitle,
|
||
'back': beta.back,
|
||
'previewTab': beta.previewTab,
|
||
'issuesTab': beta.issuesTab,
|
||
// 对话框
|
||
'confirmClose': beta.confirmClose,
|
||
'confirmOpen': beta.confirmOpen,
|
||
'cancel': beta.cancel,
|
||
'close': beta.close,
|
||
'open': beta.open,
|
||
// 空状态/错误
|
||
'emptyFeatures': beta.emptyFeatures,
|
||
'reload': beta.reload,
|
||
'loadFailed': beta.loadFailed,
|
||
'retry': beta.retry,
|
||
// 筛选标签
|
||
'filterAll': beta.filterAll,
|
||
'filterPending': beta.filterPending,
|
||
'filterFixing': beta.filterFixing,
|
||
'filterFixed': beta.filterFixed,
|
||
// 问题列表
|
||
'emptyIssues': beta.emptyIssues,
|
||
'rolloutPercentage': beta.rolloutPercentage,
|
||
'targetGroup': beta.targetGroup,
|
||
'issueStats': beta.issueStats,
|
||
// 严重程度
|
||
'severityHigh': beta.severityHigh,
|
||
'severityMedium': beta.severityMedium,
|
||
'severityLow': beta.severityLow,
|
||
// 状态
|
||
'statusPending': beta.statusPending,
|
||
'statusFixing': beta.statusFixing,
|
||
'statusFixed': beta.statusFixed,
|
||
'statusDeveloping': beta.statusDeveloping,
|
||
'statusTesting': beta.statusTesting,
|
||
'statusPreview': beta.statusPreview,
|
||
'statusReleased': beta.statusReleased,
|
||
// 通用
|
||
'comingSoon': beta.comingSoon,
|
||
'gotIt': beta.gotIt,
|
||
};
|
||
|
||
static Map<String, dynamic> _tSubmitToMap(TSubmit submit) => {
|
||
'title': submit.title,
|
||
'contentLabel': submit.contentLabel,
|
||
'titleLabel': submit.titleLabel,
|
||
'authorLabel': submit.authorLabel,
|
||
'categoryLabel': submit.categoryLabel,
|
||
'titleHint': submit.titleHint,
|
||
'authorHint': submit.authorHint,
|
||
'contentHint': submit.contentHint,
|
||
'submit': submit.submit,
|
||
'submitting': submit.submitting,
|
||
'contentRequired': submit.contentRequired,
|
||
'contentTooShort': submit.contentTooShort,
|
||
'contentTooLong': submit.contentTooLong,
|
||
'reviewing': submit.reviewing,
|
||
'reviewDesc': submit.reviewDesc,
|
||
'historyTitle': submit.historyTitle,
|
||
'historyEmpty': submit.historyEmpty,
|
||
'statusReviewing': submit.statusReviewing,
|
||
'statusApproved': submit.statusApproved,
|
||
'statusRejected': submit.statusRejected,
|
||
'catYiyan': submit.catYiyan,
|
||
'catXinde': submit.catXinde,
|
||
'catYiju': submit.catYiju,
|
||
'catSignature': submit.catSignature,
|
||
'deleteRecord': submit.deleteRecord,
|
||
'deleteConfirm': submit.deleteConfirm,
|
||
};
|
||
|
||
static Map<String, dynamic> tToMap(T t) => {
|
||
'nav': _tNavToMap(t.nav),
|
||
'common': _tCommonToMap(t.common),
|
||
'profile': _tProfileToMap(t.profile),
|
||
'settings': _tSettingsToMap(t.settings),
|
||
'note': _tNoteToMap(t.note),
|
||
'beta': _tBetaToMap(t.beta),
|
||
'submit': _tSubmitToMap(t.submit),
|
||
'studyPlan': t.studyPlan.toMap(),
|
||
'correction': t.correction.toMap(),
|
||
'leisure': t.leisure.toMap(),
|
||
};
|
||
|
||
static String exportToJson(T t) {
|
||
final map = tToMap(t);
|
||
const encoder = JsonEncoder.withIndent(' ');
|
||
return encoder.convert(map);
|
||
}
|
||
|
||
static Map<String, dynamic> exportAllTranslations() {
|
||
final result = <String, dynamic>{};
|
||
final allTranslations = {
|
||
'zh_CN': getTranslations('zh_CN'),
|
||
'en': getTranslations('en'),
|
||
'ja': getTranslations('ja'),
|
||
'zh_TW': getTranslations('zh_TW'),
|
||
'es': getTranslations('es'),
|
||
'ar': getTranslations('ar'),
|
||
'bn': getTranslations('bn'),
|
||
};
|
||
for (final entry in allTranslations.entries) {
|
||
result[entry.key] = tToMap(entry.value);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
static String exportAllToJson() {
|
||
const encoder = JsonEncoder.withIndent(' ');
|
||
return encoder.convert(exportAllTranslations());
|
||
}
|
||
|
||
static Map<String, dynamic>? parseJson(String jsonStr) {
|
||
try {
|
||
return json.decode(jsonStr) as Map<String, dynamic>;
|
||
} catch (_) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
static bool validateTranslationJson(String jsonStr) {
|
||
final parsed = parseJson(jsonStr);
|
||
if (parsed == null) return false;
|
||
return parsed.containsKey('nav') ||
|
||
parsed.containsKey('common') ||
|
||
parsed.containsKey('profile') ||
|
||
parsed.containsKey('settings') ||
|
||
parsed.containsKey('note');
|
||
}
|
||
|
||
static Map<String, int> getCoverageReport() {
|
||
return TranslationCoverage.checkAll();
|
||
}
|
||
|
||
static int getTotalFieldCount() {
|
||
return TranslationCoverage.totalFieldCount;
|
||
}
|
||
|
||
static T? importFromJson(String jsonStr, T fallback) {
|
||
final parsed = parseJson(jsonStr);
|
||
if (parsed == null) return null;
|
||
|
||
try {
|
||
final navMap = parsed['nav'] as Map<String, dynamic>?;
|
||
final commonMap = parsed['common'] as Map<String, dynamic>?;
|
||
final homeMap = parsed['home'] as Map<String, dynamic>?;
|
||
final discoverMap = parsed['discover'] as Map<String, dynamic>?;
|
||
final profileMap = parsed['profile'] as Map<String, dynamic>?;
|
||
final settingsMap = parsed['settings'] as Map<String, dynamic>?;
|
||
final noteMap = parsed['note'] as Map<String, dynamic>?;
|
||
final betaMap = parsed['beta'] as Map<String, dynamic>?;
|
||
final submitMap = parsed['submit'] as Map<String, dynamic>?;
|
||
final studyPlanMap = parsed['studyPlan'] as Map<String, dynamic>?;
|
||
final correctionMap = parsed['correction'] as Map<String, dynamic>?;
|
||
final leisureMap = parsed['leisure'] as Map<String, dynamic>?;
|
||
|
||
final nav = _importNav(navMap, fallback.nav);
|
||
final common = _importCommon(commonMap, fallback.common);
|
||
final home = _importHome(homeMap, fallback.home);
|
||
final discover = _importDiscover(discoverMap, fallback.discover);
|
||
final profile = _importProfile(profileMap, fallback.profile);
|
||
final settings = _importSettings(settingsMap, fallback.settings);
|
||
final note = _importNote(noteMap, fallback.note);
|
||
final beta = _importBeta(betaMap, fallback.beta);
|
||
final submit = _importSubmit(submitMap, fallback.submit);
|
||
final studyPlan = TStudyPlan.fromMap(
|
||
studyPlanMap?.map((k, v) => MapEntry(k, v.toString())) ?? {},
|
||
fallback: fallback.studyPlan,
|
||
);
|
||
final correction = TCorrection.fromMap(
|
||
correctionMap?.map((k, v) => MapEntry(k, v.toString())) ?? {},
|
||
fallback: fallback.correction,
|
||
);
|
||
final leisure = TLeisure.fromMap(
|
||
leisureMap?.map((k, v) => MapEntry(k, v.toString())) ?? {},
|
||
);
|
||
|
||
return T(
|
||
nav: nav,
|
||
common: common,
|
||
home: home,
|
||
discover: discover,
|
||
profile: profile,
|
||
settings: settings,
|
||
note: note,
|
||
beta: beta,
|
||
submit: submit,
|
||
about: fallback.about,
|
||
auth: fallback.auth,
|
||
onboarding: fallback.onboarding,
|
||
progress: fallback.progress,
|
||
theme: fallback.theme,
|
||
search: fallback.search,
|
||
accountSettings: fallback.accountSettings,
|
||
dataManagement: fallback.dataManagement,
|
||
source: fallback.source,
|
||
favorites: fallback.favorites,
|
||
offline: fallback.offline,
|
||
accountInsights: fallback.accountInsights,
|
||
widget: fallback.widget,
|
||
fileTransfer: fallback.fileTransfer,
|
||
studyPlan: studyPlan,
|
||
correction: correction,
|
||
leisure: leisure,
|
||
quickCard: fallback.quickCard,
|
||
dashboard: fallback.dashboard,
|
||
);
|
||
} catch (_) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
static TNav _importNav(Map<String, dynamic>? map, TNav fallback) {
|
||
if (map == null) return fallback;
|
||
return TNav.fromMap(Map<String, String>.from(map), fallback: fallback);
|
||
}
|
||
|
||
static TCommon _importCommon(Map<String, dynamic>? map, TCommon fallback) {
|
||
if (map == null) return fallback;
|
||
return TCommon.fromMap(Map<String, String>.from(map), fallback: fallback);
|
||
}
|
||
|
||
static THome _importHome(Map<String, dynamic>? map, THome fallback) {
|
||
if (map == null) return fallback;
|
||
return THome.fromImportMap(map, fallback: fallback);
|
||
}
|
||
|
||
static TDiscover _importDiscover(
|
||
Map<String, dynamic>? map,
|
||
TDiscover fallback,
|
||
) {
|
||
if (map == null) return fallback;
|
||
final stringMap = map.map((k, v) => MapEntry(k, v as String? ?? ''));
|
||
final fallbackMap = fallback.toMap();
|
||
final merged = <String, String>{};
|
||
for (final key in {...fallbackMap.keys, ...stringMap.keys}) {
|
||
merged[key] = stringMap[key] ?? fallbackMap[key] ?? '';
|
||
}
|
||
return TDiscover.fromMap(merged);
|
||
}
|
||
|
||
static TProfile _importProfile(Map<String, dynamic>? map, TProfile fallback) {
|
||
if (map == null) return fallback;
|
||
// ---- 字段同步检查(防止新增字段遗漏) ----
|
||
_checkProfileFieldsSync(map, fallback);
|
||
return TProfile(
|
||
title: map['title'] as String? ?? fallback.title,
|
||
myFavorites: map['myFavorites'] as String? ?? fallback.myFavorites,
|
||
readingHistory:
|
||
map['readingHistory'] as String? ?? fallback.readingHistory,
|
||
darkMode: map['darkMode'] as String? ?? fallback.darkMode,
|
||
accountSettings:
|
||
map['accountSettings'] as String? ?? fallback.accountSettings,
|
||
dataManagement:
|
||
map['dataManagement'] as String? ?? fallback.dataManagement,
|
||
offlineMode: map['offlineMode'] as String? ?? fallback.offlineMode,
|
||
cacheManagement:
|
||
map['cacheManagement'] as String? ?? fallback.cacheManagement,
|
||
themeCustomization:
|
||
map['themeCustomization'] as String? ?? fallback.themeCustomization,
|
||
desktopWidgets:
|
||
map['desktopWidgets'] as String? ?? fallback.desktopWidgets,
|
||
sentenceSource:
|
||
map['sentenceSource'] as String? ?? fallback.sentenceSource,
|
||
aboutApp: map['aboutApp'] as String? ?? fallback.aboutApp,
|
||
rateApp: map['rateApp'] as String? ?? fallback.rateApp,
|
||
debugMode: map['debugMode'] as String? ?? fallback.debugMode,
|
||
tapToLogin: map['tapToLogin'] as String? ?? fallback.tapToLogin,
|
||
defaultUserName:
|
||
map['defaultUserName'] as String? ?? fallback.defaultUserName,
|
||
appSlogan: map['appSlogan'] as String? ?? fallback.appSlogan,
|
||
freeTier: map['freeTier'] as String? ?? fallback.freeTier,
|
||
points: map['points'] as String? ?? fallback.points,
|
||
checkin: map['checkin'] as String? ?? fallback.checkin,
|
||
notes: map['notes'] as String? ?? fallback.notes,
|
||
quickActions: map['quickActions'] as String? ?? fallback.quickActions,
|
||
scanQr: map['scanQr'] as String? ?? fallback.scanQr,
|
||
nearbyTransfer:
|
||
map['nearbyTransfer'] as String? ?? fallback.nearbyTransfer,
|
||
payment: map['payment'] as String? ?? fallback.payment,
|
||
selectScanMethod:
|
||
map['selectScanMethod'] as String? ?? fallback.selectScanMethod,
|
||
scanQrLogin: map['scanQrLogin'] as String? ?? fallback.scanQrLogin,
|
||
scanQrCode: map['scanQrCode'] as String? ?? fallback.scanQrCode,
|
||
appStoreNotFound:
|
||
map['appStoreNotFound'] as String? ?? fallback.appStoreNotFound,
|
||
experimentalFeature:
|
||
map['experimentalFeature'] as String? ?? fallback.experimentalFeature,
|
||
underReview: map['underReview'] as String? ?? fallback.underReview,
|
||
changeAvatar: map['changeAvatar'] as String? ?? fallback.changeAvatar,
|
||
inputAvatarUrl:
|
||
map['inputAvatarUrl'] as String? ?? fallback.inputAvatarUrl,
|
||
selectFromAlbum:
|
||
map['selectFromAlbum'] as String? ?? fallback.selectFromAlbum,
|
||
avatarUrlHint: map['avatarUrlHint'] as String? ?? fallback.avatarUrlHint,
|
||
pleaseInputUrl:
|
||
map['pleaseInputUrl'] as String? ?? fallback.pleaseInputUrl,
|
||
urlMustStartWithHttp:
|
||
map['urlMustStartWithHttp'] as String? ??
|
||
fallback.urlMustStartWithHttp,
|
||
urlTooLong: map['urlTooLong'] as String? ?? fallback.urlTooLong,
|
||
invalidUrlFormat:
|
||
map['invalidUrlFormat'] as String? ?? fallback.invalidUrlFormat,
|
||
avatarUnderReview:
|
||
map['avatarUnderReview'] as String? ?? fallback.avatarUnderReview,
|
||
avatarReviewing:
|
||
map['avatarReviewing'] as String? ?? fallback.avatarReviewing,
|
||
avatarChangeSuccess:
|
||
map['avatarChangeSuccess'] as String? ?? fallback.avatarChangeSuccess,
|
||
avatarChangeFailed:
|
||
map['avatarChangeFailed'] as String? ?? fallback.avatarChangeFailed,
|
||
success: map['success'] as String? ?? fallback.success,
|
||
failed: map['failed'] as String? ?? fallback.failed,
|
||
ok: map['ok'] as String? ?? fallback.ok,
|
||
loading: map['loading'] as String? ?? fallback.loading,
|
||
loginToViewProfile:
|
||
map['loginToViewProfile'] as String? ?? fallback.loginToViewProfile,
|
||
goLogin: map['goLogin'] as String? ?? fallback.goLogin,
|
||
consecutiveCheckin:
|
||
map['consecutiveCheckin'] as String? ?? fallback.consecutiveCheckin,
|
||
favorites: map['favorites'] as String? ?? fallback.favorites,
|
||
likes: map['likes'] as String? ?? fallback.likes,
|
||
dailyCheckin: map['dailyCheckin'] as String? ?? fallback.dailyCheckin,
|
||
learningCenter:
|
||
map['learningCenter'] as String? ?? fallback.learningCenter,
|
||
achievementCenter:
|
||
map['achievementCenter'] as String? ?? fallback.achievementCenter,
|
||
dailyTask: map['dailyTask'] as String? ?? fallback.dailyTask,
|
||
leaderboard: map['leaderboard'] as String? ?? fallback.leaderboard,
|
||
dataStatistics:
|
||
map['dataStatistics'] as String? ?? fallback.dataStatistics,
|
||
myNotes: map['myNotes'] as String? ?? fallback.myNotes,
|
||
contentCorrection:
|
||
map['contentCorrection'] as String? ?? fallback.contentCorrection,
|
||
myDevices: map['myDevices'] as String? ?? fallback.myDevices,
|
||
tagCloud: map['tagCloud'] as String? ?? fallback.tagCloud,
|
||
deviceRemoveCurrentTitle:
|
||
map['deviceRemoveCurrentTitle'] as String? ?? fallback.deviceRemoveCurrentTitle,
|
||
deviceRemoveCurrentWarning:
|
||
map['deviceRemoveCurrentWarning'] as String? ?? fallback.deviceRemoveCurrentWarning,
|
||
deviceContinueRemove:
|
||
map['deviceContinueRemove'] as String? ?? fallback.deviceContinueRemove,
|
||
deviceVerifyIdentityRemove:
|
||
map['deviceVerifyIdentityRemove'] as String? ?? fallback.deviceVerifyIdentityRemove,
|
||
deviceRemoveTitle:
|
||
map['deviceRemoveTitle'] as String? ?? fallback.deviceRemoveTitle,
|
||
deviceRemoveConfirm:
|
||
map['deviceRemoveConfirm'] as String? ?? fallback.deviceRemoveConfirm,
|
||
deviceRemoved:
|
||
map['deviceRemoved'] as String? ?? fallback.deviceRemoved,
|
||
deviceRemoveFailed:
|
||
map['deviceRemoveFailed'] as String? ?? fallback.deviceRemoveFailed,
|
||
personalInfo: map['personalInfo'] as String? ?? fallback.personalInfo,
|
||
username: map['username'] as String? ?? fallback.username,
|
||
nickname: map['nickname'] as String? ?? fallback.nickname,
|
||
bio: map['bio'] as String? ?? fallback.bio,
|
||
notSet: map['notSet'] as String? ?? fallback.notSet,
|
||
notFilled: map['notFilled'] as String? ?? fallback.notFilled,
|
||
set: map['set'] as String? ?? fallback.set,
|
||
reviewing: map['reviewing'] as String? ?? fallback.reviewing,
|
||
editUsername: map['editUsername'] as String? ?? fallback.editUsername,
|
||
editNickname: map['editNickname'] as String? ?? fallback.editNickname,
|
||
nearbyDiscovery:
|
||
map['nearbyDiscovery'] as String? ?? fallback.nearbyDiscovery,
|
||
nearbyDiscoveryDesc:
|
||
map['nearbyDiscoveryDesc'] as String? ?? fallback.nearbyDiscoveryDesc,
|
||
totalTasks: map['totalTasks'] as String? ?? fallback.totalTasks,
|
||
taskClaimed: map['taskClaimed'] as String? ?? fallback.taskClaimed,
|
||
perfectDay: map['perfectDay'] as String? ?? fallback.perfectDay,
|
||
perfectDayAllDone:
|
||
map['perfectDayAllDone'] as String? ?? fallback.perfectDayAllDone,
|
||
perfectDayReward:
|
||
map['perfectDayReward'] as String? ?? fallback.perfectDayReward,
|
||
perfectDayRewardDesc:
|
||
map['perfectDayRewardDesc'] as String? ??
|
||
fallback.perfectDayRewardDesc,
|
||
claimPerfectDayReward:
|
||
map['claimPerfectDayReward'] as String? ??
|
||
fallback.claimPerfectDayReward,
|
||
rewardSuffix: map['rewardSuffix'] as String? ?? fallback.rewardSuffix,
|
||
expUnit: map['expUnit'] as String? ?? fallback.expUnit,
|
||
scoreUnit: map['scoreUnit'] as String? ?? fallback.scoreUnit,
|
||
noTasks: map['noTasks'] as String? ?? fallback.noTasks,
|
||
noTasksDesc: map['noTasksDesc'] as String? ?? fallback.noTasksDesc,
|
||
great: map['great'] as String? ?? fallback.great,
|
||
loginToCheckin:
|
||
map['loginToCheckin'] as String? ?? fallback.loginToCheckin,
|
||
loginToCheckinDesc:
|
||
map['loginToCheckinDesc'] as String? ?? fallback.loginToCheckinDesc,
|
||
viewAchievementCenter:
|
||
map['viewAchievementCenter'] as String? ??
|
||
fallback.viewAchievementCenter,
|
||
todaySigned: map['todaySigned'] as String? ?? fallback.todaySigned,
|
||
tapToCheckin: map['tapToCheckin'] as String? ?? fallback.tapToCheckin,
|
||
signed: map['signed'] as String? ?? fallback.signed,
|
||
weeklyCheckin: map['weeklyCheckin'] as String? ?? fallback.weeklyCheckin,
|
||
totalCheckinDays:
|
||
map['totalCheckinDays'] as String? ?? fallback.totalCheckinDays,
|
||
checkinHistory:
|
||
map['checkinHistory'] as String? ?? fallback.checkinHistory,
|
||
noCheckinRecord:
|
||
map['noCheckinRecord'] as String? ?? fallback.noCheckinRecord,
|
||
todayLabel: map['todayLabel'] as String? ?? fallback.todayLabel,
|
||
checkinDate: map['checkinDate'] as String? ?? fallback.checkinDate,
|
||
status: map['status'] as String? ?? fallback.status,
|
||
signedStatus: map['signedStatus'] as String? ?? fallback.signedStatus,
|
||
remark: map['remark'] as String? ?? fallback.remark,
|
||
dailyCheckinTaskDone:
|
||
map['dailyCheckinTaskDone'] as String? ??
|
||
fallback.dailyCheckinTaskDone,
|
||
makeupCheckin: map['makeupCheckin'] as String? ?? fallback.makeupCheckin,
|
||
makeupCostInfo:
|
||
map['makeupCostInfo'] as String? ?? fallback.makeupCostInfo,
|
||
makeupDate: map['makeupDate'] as String? ?? fallback.makeupDate,
|
||
costPoints: map['costPoints'] as String? ?? fallback.costPoints,
|
||
currentPoints: map['currentPoints'] as String? ?? fallback.currentPoints,
|
||
makeupInfo: map['makeupInfo'] as String? ?? fallback.makeupInfo,
|
||
makeupLimitInfo:
|
||
map['makeupLimitInfo'] as String? ?? fallback.makeupLimitInfo,
|
||
confirmMakeup: map['confirmMakeup'] as String? ?? fallback.confirmMakeup,
|
||
insufficientPoints:
|
||
map['insufficientPoints'] as String? ?? fallback.insufficientPoints,
|
||
insufficientPointsDesc:
|
||
map['insufficientPointsDesc'] as String? ??
|
||
fallback.insufficientPointsDesc,
|
||
makeupSuccess: map['makeupSuccess'] as String? ?? fallback.makeupSuccess,
|
||
makeupSuccessDesc:
|
||
map['makeupSuccessDesc'] as String? ?? fallback.makeupSuccessDesc,
|
||
makeupFailed: map['makeupFailed'] as String? ?? fallback.makeupFailed,
|
||
makeupFailedRetry:
|
||
map['makeupFailedRetry'] as String? ?? fallback.makeupFailedRetry,
|
||
timesUnit: map['timesUnit'] as String? ?? fallback.timesUnit,
|
||
daysUnit: map['daysUnit'] as String? ?? fallback.daysUnit,
|
||
accountAndData:
|
||
map['accountAndData'] as String? ?? fallback.accountAndData,
|
||
editProfile: map['editProfile'] as String? ?? fallback.editProfile,
|
||
edit: map['edit'] as String? ?? fallback.edit,
|
||
editBio: map['editBio'] as String? ?? fallback.editBio,
|
||
save: map['save'] as String? ?? fallback.save,
|
||
pleaseInput: map['pleaseInput'] as String? ?? fallback.pleaseInput,
|
||
modifySuccess: map['modifySuccess'] as String? ?? fallback.modifySuccess,
|
||
modifyFailed: map['modifyFailed'] as String? ?? fallback.modifyFailed,
|
||
userProfile: map['userProfile'] as String? ?? fallback.userProfile,
|
||
goBack: map['goBack'] as String? ?? fallback.goBack,
|
||
userNotExist: map['userNotExist'] as String? ?? fallback.userNotExist,
|
||
retry: map['retry'] as String? ?? fallback.retry,
|
||
anonymousUser: map['anonymousUser'] as String? ?? fallback.anonymousUser,
|
||
articles: map['articles'] as String? ?? fallback.articles,
|
||
follow: map['follow'] as String? ?? fallback.follow,
|
||
followed: map['followed'] as String? ?? fallback.followed,
|
||
theUser: map['theUser'] as String? ?? fallback.theUser,
|
||
privateMessage:
|
||
map['privateMessage'] as String? ?? fallback.privateMessage,
|
||
gotIt: map['gotIt'] as String? ?? fallback.gotIt,
|
||
shareProfile: map['shareProfile'] as String? ?? fallback.shareProfile,
|
||
blockUser: map['blockUser'] as String? ?? fallback.blockUser,
|
||
personalBio: map['personalBio'] as String? ?? fallback.personalBio,
|
||
titleLevel: map['titleLevel'] as String? ?? fallback.titleLevel,
|
||
activeData: map['activeData'] as String? ?? fallback.activeData,
|
||
beginner: map['beginner'] as String? ?? fallback.beginner,
|
||
apprentice: map['apprentice'] as String? ?? fallback.apprentice,
|
||
skilled: map['skilled'] as String? ?? fallback.skilled,
|
||
expert: map['expert'] as String? ?? fallback.expert,
|
||
master: map['master'] as String? ?? fallback.master,
|
||
signInCount: map['signInCount'] as String? ?? fallback.signInCount,
|
||
noteCount: map['noteCount'] as String? ?? fallback.noteCount,
|
||
likeCount: map['likeCount'] as String? ?? fallback.likeCount,
|
||
commentCount: map['commentCount'] as String? ?? fallback.commentCount,
|
||
viewCount: map['viewCount'] as String? ?? fallback.viewCount,
|
||
readLaterCount:
|
||
map['readLaterCount'] as String? ?? fallback.readLaterCount,
|
||
modifyField: map['modifyField'] as String? ?? fallback.modifyField,
|
||
pleaseInputField:
|
||
map['pleaseInputField'] as String? ?? fallback.pleaseInputField,
|
||
fieldModifySuccess:
|
||
map['fieldModifySuccess'] as String? ?? fallback.fieldModifySuccess,
|
||
fieldModifyFailed:
|
||
map['fieldModifyFailed'] as String? ?? fallback.fieldModifyFailed,
|
||
debugInfo: map['debugInfo'] as String? ?? fallback.debugInfo,
|
||
defaultBio: map['defaultBio'] as String? ?? fallback.defaultBio,
|
||
exitSubProject:
|
||
map['exitSubProject'] as String? ?? fallback.exitSubProject,
|
||
exitApp: map['exitApp'] as String? ?? fallback.exitApp,
|
||
exitAccount: map['exitAccount'] as String? ?? fallback.exitAccount,
|
||
closeAppToDesktop:
|
||
map['closeAppToDesktop'] as String? ?? fallback.closeAppToDesktop,
|
||
closeAppKillBackground:
|
||
map['closeAppKillBackground'] as String? ??
|
||
fallback.closeAppKillBackground,
|
||
backToDesktop:
|
||
map['backToDesktop'] as String? ?? fallback.backToDesktop,
|
||
selectExitMethod:
|
||
map['selectExitMethod'] as String? ?? fallback.selectExitMethod,
|
||
);
|
||
}
|
||
|
||
static TSettings _importSettings(
|
||
Map<String, dynamic>? map,
|
||
TSettings fallback,
|
||
) {
|
||
if (map == null) return fallback;
|
||
final fallbackMap = fallback.toMap();
|
||
final merged = <String, String>{};
|
||
for (final key in fallbackMap.keys) {
|
||
final value = map[key];
|
||
if (value is String && value.isNotEmpty) {
|
||
merged[key] = value;
|
||
} else {
|
||
merged[key] = fallbackMap[key] ?? '';
|
||
}
|
||
}
|
||
return TSettings.fromMap(merged);
|
||
}
|
||
|
||
static TNote _importNote(Map<String, dynamic>? map, TNote fallback) {
|
||
if (map == null) return fallback;
|
||
// ---- 字段同步检查(防止新增字段遗漏) ----
|
||
_checkNoteFieldsSync(map, fallback);
|
||
return TNote(
|
||
// 页面标题与导航
|
||
title: map['title'] as String? ?? fallback.title,
|
||
searchNotes: map['searchNotes'] as String? ?? fallback.searchNotes,
|
||
editNote: map['editNote'] as String? ?? fallback.editNote,
|
||
newNote: map['newNote'] as String? ?? fallback.newNote,
|
||
// 登录守卫
|
||
loginRequired: map['loginRequired'] as String? ?? fallback.loginRequired,
|
||
loginToUseNotes:
|
||
map['loginToUseNotes'] as String? ?? fallback.loginToUseNotes,
|
||
goLogin: map['goLogin'] as String? ?? fallback.goLogin,
|
||
// 搜索
|
||
searchPlaceholder:
|
||
map['searchPlaceholder'] as String? ?? fallback.searchPlaceholder,
|
||
// 筛选类型
|
||
all: map['all'] as String? ?? fallback.all,
|
||
note: map['note'] as String? ?? fallback.note,
|
||
excerpt: map['excerpt'] as String? ?? fallback.excerpt,
|
||
checklist: map['checklist'] as String? ?? fallback.checklist,
|
||
// 排序与分组
|
||
sortBy: map['sortBy'] as String? ?? fallback.sortBy,
|
||
sortByUpdateTime:
|
||
map['sortByUpdateTime'] as String? ?? fallback.sortByUpdateTime,
|
||
sortByCreateTime:
|
||
map['sortByCreateTime'] as String? ?? fallback.sortByCreateTime,
|
||
sortByTitle: map['sortByTitle'] as String? ?? fallback.sortByTitle,
|
||
groupBy: map['groupBy'] as String? ?? fallback.groupBy,
|
||
groupByDate: map['groupByDate'] as String? ?? fallback.groupByDate,
|
||
groupByCategory:
|
||
map['groupByCategory'] as String? ?? fallback.groupByCategory,
|
||
groupByType: map['groupByType'] as String? ?? fallback.groupByType,
|
||
groupBySource:
|
||
map['groupBySource'] as String? ?? fallback.groupBySource,
|
||
// 布局
|
||
switchLayout:
|
||
map['switchLayout'] as String? ?? fallback.switchLayout,
|
||
layoutList: map['layoutList'] as String? ?? fallback.layoutList,
|
||
layoutGrid: map['layoutGrid'] as String? ?? fallback.layoutGrid,
|
||
layoutTimeline:
|
||
map['layoutTimeline'] as String? ?? fallback.layoutTimeline,
|
||
// 选择模式
|
||
selectedCount:
|
||
map['selectedCount'] as String? ?? fallback.selectedCount,
|
||
selectAll: map['selectAll'] as String? ?? fallback.selectAll,
|
||
deselectAll: map['deselectAll'] as String? ?? fallback.deselectAll,
|
||
batchSelect: map['batchSelect'] as String? ?? fallback.batchSelect,
|
||
multiSelect: map['multiSelect'] as String? ?? fallback.multiSelect,
|
||
// 批量操作
|
||
batchDelete: map['batchDelete'] as String? ?? fallback.batchDelete,
|
||
batchDeleteConfirm:
|
||
map['batchDeleteConfirm'] as String? ?? fallback.batchDeleteConfirm,
|
||
deletedCount: map['deletedCount'] as String? ?? fallback.deletedCount,
|
||
// 拖拽排序
|
||
dragReorder: map['dragReorder'] as String? ?? fallback.dragReorder,
|
||
dragToReorder:
|
||
map['dragToReorder'] as String? ?? fallback.dragToReorder,
|
||
// 上下文菜单
|
||
starFavorite:
|
||
map['starFavorite'] as String? ?? fallback.starFavorite,
|
||
unfavorite: map['unfavorite'] as String? ?? fallback.unfavorite,
|
||
exportNote: map['exportNote'] as String? ?? fallback.exportNote,
|
||
copyNote: map['copyNote'] as String? ?? fallback.copyNote,
|
||
// 菜单项
|
||
newNoteMenu: map['newNoteMenu'] as String? ?? fallback.newNoteMenu,
|
||
sortMenu: map['sortMenu'] as String? ?? fallback.sortMenu,
|
||
groupMenu: map['groupMenu'] as String? ?? fallback.groupMenu,
|
||
showStarOnly: map['showStarOnly'] as String? ?? fallback.showStarOnly,
|
||
showAll: map['showAll'] as String? ?? fallback.showAll,
|
||
statsPanel: map['statsPanel'] as String? ?? fallback.statsPanel,
|
||
reorderMenu: map['reorderMenu'] as String? ?? fallback.reorderMenu,
|
||
// 清空全部
|
||
confirmClear: map['confirmClear'] as String? ?? fallback.confirmClear,
|
||
clearAllWarning:
|
||
map['clearAllWarning'] as String? ?? fallback.clearAllWarning,
|
||
clearAll: map['clearAll'] as String? ?? fallback.clearAll,
|
||
allCleared: map['allCleared'] as String? ?? fallback.allCleared,
|
||
// 空状态
|
||
noNotes: map['noNotes'] as String? ?? fallback.noNotes,
|
||
tapToStart: map['tapToStart'] as String? ?? fallback.tapToStart,
|
||
// 底部
|
||
reachedBottom:
|
||
map['reachedBottom'] as String? ?? fallback.reachedBottom,
|
||
notesCount: map['notesCount'] as String? ?? fallback.notesCount,
|
||
// 日期标签
|
||
unknownDate: map['unknownDate'] as String? ?? fallback.unknownDate,
|
||
today: map['today'] as String? ?? fallback.today,
|
||
yesterday: map['yesterday'] as String? ?? fallback.yesterday,
|
||
// 分组标签
|
||
uncategorized:
|
||
map['uncategorized'] as String? ?? fallback.uncategorized,
|
||
noSource: map['noSource'] as String? ?? fallback.noSource,
|
||
// 笔记卡片
|
||
noTitle: map['noTitle'] as String? ?? fallback.noTitle,
|
||
// 删除
|
||
deleteNote: map['deleteNote'] as String? ?? fallback.deleteNote,
|
||
deleteNoteConfirm:
|
||
map['deleteNoteConfirm'] as String? ?? fallback.deleteNoteConfirm,
|
||
// 编辑页
|
||
noteLoadFailed:
|
||
map['noteLoadFailed'] as String? ?? fallback.noteLoadFailed,
|
||
titlePlaceholder:
|
||
map['titlePlaceholder'] as String? ?? fallback.titlePlaceholder,
|
||
categoryLabel:
|
||
map['categoryLabel'] as String? ?? fallback.categoryLabel,
|
||
sourceLabel: map['sourceLabel'] as String? ?? fallback.sourceLabel,
|
||
publicLabel: map['publicLabel'] as String? ?? fallback.publicLabel,
|
||
optionalPlaceholder:
|
||
map['optionalPlaceholder'] as String? ?? fallback.optionalPlaceholder,
|
||
visibleToAll:
|
||
map['visibleToAll'] as String? ?? fallback.visibleToAll,
|
||
visibleToSelf:
|
||
map['visibleToSelf'] as String? ?? fallback.visibleToSelf,
|
||
selectSourceType:
|
||
map['selectSourceType'] as String? ?? fallback.selectSourceType,
|
||
excerptPlaceholder:
|
||
map['excerptPlaceholder'] as String? ?? fallback.excerptPlaceholder,
|
||
checklistPlaceholder:
|
||
map['checklistPlaceholder'] as String? ??
|
||
fallback.checklistPlaceholder,
|
||
notePlaceholder:
|
||
map['notePlaceholder'] as String? ?? fallback.notePlaceholder,
|
||
noPreviewContent:
|
||
map['noPreviewContent'] as String? ?? fallback.noPreviewContent,
|
||
switchToEdit:
|
||
map['switchToEdit'] as String? ?? fallback.switchToEdit,
|
||
selectPreviewFont:
|
||
map['selectPreviewFont'] as String? ?? fallback.selectPreviewFont,
|
||
systemDefault:
|
||
map['systemDefault'] as String? ?? fallback.systemDefault,
|
||
noTitleNote: map['noTitleNote'] as String? ?? fallback.noTitleNote,
|
||
noteSaved: map['noteSaved'] as String? ?? fallback.noteSaved,
|
||
unsaved: map['unsaved'] as String? ?? fallback.unsaved,
|
||
saved: map['saved'] as String? ?? fallback.saved,
|
||
charCount: map['charCount'] as String? ?? fallback.charCount,
|
||
// 来源类型
|
||
sourcePoetry: map['sourcePoetry'] as String? ?? fallback.sourcePoetry,
|
||
sourceArticle:
|
||
map['sourceArticle'] as String? ?? fallback.sourceArticle,
|
||
sourceHanzi: map['sourceHanzi'] as String? ?? fallback.sourceHanzi,
|
||
sourceIdiom: map['sourceIdiom'] as String? ?? fallback.sourceIdiom,
|
||
// Markdown 工具栏
|
||
bold: map['bold'] as String? ?? fallback.bold,
|
||
italic: map['italic'] as String? ?? fallback.italic,
|
||
heading: map['heading'] as String? ?? fallback.heading,
|
||
list: map['list'] as String? ?? fallback.list,
|
||
orderedList: map['orderedList'] as String? ?? fallback.orderedList,
|
||
quote: map['quote'] as String? ?? fallback.quote,
|
||
link: map['link'] as String? ?? fallback.link,
|
||
code: map['code'] as String? ?? fallback.code,
|
||
divider: map['divider'] as String? ?? fallback.divider,
|
||
// 统计面板
|
||
noteStats: map['noteStats'] as String? ?? fallback.noteStats,
|
||
totalNotes: map['totalNotes'] as String? ?? fallback.totalNotes,
|
||
weekNew: map['weekNew'] as String? ?? fallback.weekNew,
|
||
totalWords: map['totalWords'] as String? ?? fallback.totalWords,
|
||
typeDistribution:
|
||
map['typeDistribution'] as String? ?? fallback.typeDistribution,
|
||
categoryDistribution:
|
||
map['categoryDistribution'] as String? ??
|
||
fallback.categoryDistribution,
|
||
noCategoryData:
|
||
map['noCategoryData'] as String? ?? fallback.noCategoryData,
|
||
starredNotes:
|
||
map['starredNotes'] as String? ?? fallback.starredNotes,
|
||
// 导出
|
||
exportTitle: map['exportTitle'] as String? ?? fallback.exportTitle,
|
||
exportCountNote:
|
||
map['exportCountNote'] as String? ?? fallback.exportCountNote,
|
||
copiedToClipboard:
|
||
map['copiedToClipboard'] as String? ?? fallback.copiedToClipboard,
|
||
exportTypeLabel:
|
||
map['exportTypeLabel'] as String? ?? fallback.exportTypeLabel,
|
||
exportCategoryLabel:
|
||
map['exportCategoryLabel'] as String? ?? fallback.exportCategoryLabel,
|
||
exportPublicYes:
|
||
map['exportPublicYes'] as String? ?? fallback.exportPublicYes,
|
||
exportSourceLabel:
|
||
map['exportSourceLabel'] as String? ?? fallback.exportSourceLabel,
|
||
exportCreateTime:
|
||
map['exportCreateTime'] as String? ?? fallback.exportCreateTime,
|
||
exportUpdateTime:
|
||
map['exportUpdateTime'] as String? ?? fallback.exportUpdateTime,
|
||
exportShareSubject:
|
||
map['exportShareSubject'] as String? ?? fallback.exportShareSubject,
|
||
// 置顶
|
||
pinToDiscover:
|
||
map['pinToDiscover'] as String? ?? fallback.pinToDiscover,
|
||
pinToDiscoverDesc:
|
||
map['pinToDiscoverDesc'] as String? ?? fallback.pinToDiscoverDesc,
|
||
close: map['close'] as String? ?? fallback.close,
|
||
pinnedToDiscover:
|
||
map['pinnedToDiscover'] as String? ?? fallback.pinnedToDiscover,
|
||
unpinnedFromDiscover:
|
||
map['unpinnedFromDiscover'] as String? ??
|
||
fallback.unpinnedFromDiscover,
|
||
confirmPin: map['confirmPin'] as String? ?? fallback.confirmPin,
|
||
confirmUnpin: map['confirmUnpin'] as String? ?? fallback.confirmUnpin,
|
||
);
|
||
}
|
||
|
||
/// 检查 TProfile 字段同步
|
||
///
|
||
/// 当 TProfile 新增字段但 _importProfile 未同步时,
|
||
/// 会在 debug 模式下打印警告,帮助开发者及时发现遗漏。
|
||
static void _checkProfileFieldsSync(
|
||
Map<String, dynamic> map,
|
||
TProfile? fallback,
|
||
) {
|
||
assert(() {
|
||
const expectedKeys = <String>{
|
||
'title',
|
||
'myFavorites',
|
||
'readingHistory',
|
||
'darkMode',
|
||
'accountSettings',
|
||
'dataManagement',
|
||
'offlineMode',
|
||
'cacheManagement',
|
||
'themeCustomization',
|
||
'desktopWidgets',
|
||
'sentenceSource',
|
||
'aboutApp',
|
||
'rateApp',
|
||
'debugMode',
|
||
'tapToLogin',
|
||
'defaultUserName',
|
||
'appSlogan',
|
||
'freeTier',
|
||
'points',
|
||
'checkin',
|
||
'notes',
|
||
'quickActions',
|
||
'scanQr',
|
||
'nearbyTransfer',
|
||
'payment',
|
||
'selectScanMethod',
|
||
'scanQrLogin',
|
||
'scanQrCode',
|
||
'appStoreNotFound',
|
||
'experimentalFeature',
|
||
'underReview',
|
||
'changeAvatar',
|
||
'inputAvatarUrl',
|
||
'selectFromAlbum',
|
||
'avatarUrlHint',
|
||
'pleaseInputUrl',
|
||
'urlMustStartWithHttp',
|
||
'urlTooLong',
|
||
'invalidUrlFormat',
|
||
'avatarUnderReview',
|
||
'avatarReviewing',
|
||
'avatarChangeSuccess',
|
||
'avatarChangeFailed',
|
||
'success',
|
||
'failed',
|
||
'ok',
|
||
'loading',
|
||
'loginToViewProfile',
|
||
'goLogin',
|
||
'consecutiveCheckin',
|
||
'favorites',
|
||
'likes',
|
||
'dailyCheckin',
|
||
'learningCenter',
|
||
'achievementCenter',
|
||
'dailyTask',
|
||
'leaderboard',
|
||
'dataStatistics',
|
||
'myNotes',
|
||
'contentCorrection',
|
||
'myDevices',
|
||
'tagCloud',
|
||
'deviceRemoveCurrentTitle',
|
||
'deviceRemoveCurrentWarning',
|
||
'deviceContinueRemove',
|
||
'deviceVerifyIdentityRemove',
|
||
'deviceRemoveTitle',
|
||
'deviceRemoveConfirm',
|
||
'deviceRemoved',
|
||
'deviceRemoveFailed',
|
||
'personalInfo',
|
||
'username',
|
||
'nickname',
|
||
'bio',
|
||
'notSet',
|
||
'notFilled',
|
||
'set',
|
||
'reviewing',
|
||
'editUsername',
|
||
'editNickname',
|
||
'nearbyDiscovery',
|
||
'nearbyDiscoveryDesc',
|
||
'totalTasks',
|
||
'taskClaimed',
|
||
'perfectDay',
|
||
'perfectDayAllDone',
|
||
'perfectDayReward',
|
||
'perfectDayRewardDesc',
|
||
'claimPerfectDayReward',
|
||
'rewardSuffix',
|
||
'expUnit',
|
||
'scoreUnit',
|
||
'noTasks',
|
||
'noTasksDesc',
|
||
'great',
|
||
'loginToCheckin',
|
||
'loginToCheckinDesc',
|
||
'viewAchievementCenter',
|
||
'todaySigned',
|
||
'tapToCheckin',
|
||
'signed',
|
||
'weeklyCheckin',
|
||
'totalCheckinDays',
|
||
'checkinHistory',
|
||
'noCheckinRecord',
|
||
'todayLabel',
|
||
'checkinDate',
|
||
'status',
|
||
'signedStatus',
|
||
'remark',
|
||
'dailyCheckinTaskDone',
|
||
'makeupCheckin',
|
||
'makeupCostInfo',
|
||
'makeupDate',
|
||
'costPoints',
|
||
'currentPoints',
|
||
'makeupInfo',
|
||
'makeupLimitInfo',
|
||
'confirmMakeup',
|
||
'insufficientPoints',
|
||
'insufficientPointsDesc',
|
||
'makeupSuccess',
|
||
'makeupSuccessDesc',
|
||
'makeupFailed',
|
||
'makeupFailedRetry',
|
||
'timesUnit',
|
||
'daysUnit',
|
||
};
|
||
final mapKeys = map.keys.toSet();
|
||
final missingInImport = expectedKeys.difference(mapKeys);
|
||
if (missingInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TProfile _importProfile 缺失字段: $missingInImport',
|
||
);
|
||
}
|
||
final extraInImport = mapKeys.difference(expectedKeys);
|
||
if (extraInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TProfile _importProfile 多余字段: $extraInImport',
|
||
);
|
||
}
|
||
return true; // assert 总是通过,仅打印警告
|
||
}());
|
||
}
|
||
|
||
/// 检查 TNote 字段同步
|
||
///
|
||
/// 当 TNote 新增字段但 _importNote 未同步时,
|
||
/// 会在 debug 模式下打印警告,帮助开发者及时发现遗漏。
|
||
static void _checkNoteFieldsSync(
|
||
Map<String, dynamic> map,
|
||
TNote? fallback,
|
||
) {
|
||
assert(() {
|
||
const expectedKeys = <String>{
|
||
'title',
|
||
'searchNotes',
|
||
'editNote',
|
||
'newNote',
|
||
'loginRequired',
|
||
'loginToUseNotes',
|
||
'goLogin',
|
||
'searchPlaceholder',
|
||
'all',
|
||
'note',
|
||
'excerpt',
|
||
'checklist',
|
||
'sortBy',
|
||
'sortByUpdateTime',
|
||
'sortByCreateTime',
|
||
'sortByTitle',
|
||
'groupBy',
|
||
'groupByDate',
|
||
'groupByCategory',
|
||
'groupByType',
|
||
'groupBySource',
|
||
'switchLayout',
|
||
'layoutList',
|
||
'layoutGrid',
|
||
'layoutTimeline',
|
||
'selectedCount',
|
||
'selectAll',
|
||
'deselectAll',
|
||
'batchSelect',
|
||
'multiSelect',
|
||
'batchDelete',
|
||
'batchDeleteConfirm',
|
||
'deletedCount',
|
||
'dragReorder',
|
||
'dragToReorder',
|
||
'starFavorite',
|
||
'unfavorite',
|
||
'exportNote',
|
||
'copyNote',
|
||
'newNoteMenu',
|
||
'sortMenu',
|
||
'groupMenu',
|
||
'showStarOnly',
|
||
'showAll',
|
||
'statsPanel',
|
||
'reorderMenu',
|
||
'confirmClear',
|
||
'clearAllWarning',
|
||
'clearAll',
|
||
'allCleared',
|
||
'noNotes',
|
||
'tapToStart',
|
||
'reachedBottom',
|
||
'notesCount',
|
||
'unknownDate',
|
||
'today',
|
||
'yesterday',
|
||
'uncategorized',
|
||
'noSource',
|
||
'noTitle',
|
||
'deleteNote',
|
||
'deleteNoteConfirm',
|
||
'noteLoadFailed',
|
||
'titlePlaceholder',
|
||
'categoryLabel',
|
||
'sourceLabel',
|
||
'publicLabel',
|
||
'optionalPlaceholder',
|
||
'visibleToAll',
|
||
'visibleToSelf',
|
||
'selectSourceType',
|
||
'excerptPlaceholder',
|
||
'checklistPlaceholder',
|
||
'notePlaceholder',
|
||
'noPreviewContent',
|
||
'switchToEdit',
|
||
'selectPreviewFont',
|
||
'systemDefault',
|
||
'noTitleNote',
|
||
'noteSaved',
|
||
'unsaved',
|
||
'saved',
|
||
'charCount',
|
||
'sourcePoetry',
|
||
'sourceArticle',
|
||
'sourceHanzi',
|
||
'sourceIdiom',
|
||
'bold',
|
||
'italic',
|
||
'heading',
|
||
'list',
|
||
'orderedList',
|
||
'quote',
|
||
'link',
|
||
'code',
|
||
'divider',
|
||
'noteStats',
|
||
'totalNotes',
|
||
'weekNew',
|
||
'totalWords',
|
||
'typeDistribution',
|
||
'categoryDistribution',
|
||
'noCategoryData',
|
||
'starredNotes',
|
||
'exportTitle',
|
||
'exportCountNote',
|
||
'copiedToClipboard',
|
||
'exportTypeLabel',
|
||
'exportCategoryLabel',
|
||
'exportPublicYes',
|
||
'exportSourceLabel',
|
||
'exportCreateTime',
|
||
'exportUpdateTime',
|
||
'exportShareSubject',
|
||
'pinToDiscover',
|
||
'pinToDiscoverDesc',
|
||
'close',
|
||
'pinnedToDiscover',
|
||
'unpinnedFromDiscover',
|
||
'confirmPin',
|
||
'confirmUnpin',
|
||
};
|
||
final mapKeys = map.keys.toSet();
|
||
final missingInImport = expectedKeys.difference(mapKeys);
|
||
if (missingInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TNote _importNote 缺失字段: $missingInImport',
|
||
);
|
||
}
|
||
final extraInImport = mapKeys.difference(expectedKeys);
|
||
if (extraInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TNote _importNote 多余字段: $extraInImport',
|
||
);
|
||
}
|
||
return true; // assert 总是通过,仅打印警告
|
||
}());
|
||
}
|
||
|
||
static TBeta _importBeta(Map<String, dynamic>? map, TBeta fallback) {
|
||
if (map == null) return fallback;
|
||
// ---- 字段同步检查(防止新增字段遗漏) ----
|
||
_checkBetaFieldsSync(map, fallback);
|
||
return TBeta(
|
||
// 页面级
|
||
pageTitle: map['pageTitle'] as String? ?? fallback.pageTitle,
|
||
back: map['back'] as String? ?? fallback.back,
|
||
previewTab: map['previewTab'] as String? ?? fallback.previewTab,
|
||
issuesTab: map['issuesTab'] as String? ?? fallback.issuesTab,
|
||
// 对话框
|
||
confirmClose: map['confirmClose'] as String? ?? fallback.confirmClose,
|
||
confirmOpen: map['confirmOpen'] as String? ?? fallback.confirmOpen,
|
||
cancel: map['cancel'] as String? ?? fallback.cancel,
|
||
close: map['close'] as String? ?? fallback.close,
|
||
open: map['open'] as String? ?? fallback.open,
|
||
// 空状态/错误
|
||
emptyFeatures: map['emptyFeatures'] as String? ?? fallback.emptyFeatures,
|
||
reload: map['reload'] as String? ?? fallback.reload,
|
||
loadFailed: map['loadFailed'] as String? ?? fallback.loadFailed,
|
||
retry: map['retry'] as String? ?? fallback.retry,
|
||
// 筛选标签
|
||
filterAll: map['filterAll'] as String? ?? fallback.filterAll,
|
||
filterPending: map['filterPending'] as String? ?? fallback.filterPending,
|
||
filterFixing: map['filterFixing'] as String? ?? fallback.filterFixing,
|
||
filterFixed: map['filterFixed'] as String? ?? fallback.filterFixed,
|
||
// 问题列表
|
||
emptyIssues: map['emptyIssues'] as String? ?? fallback.emptyIssues,
|
||
rolloutPercentage: map['rolloutPercentage'] as String? ?? fallback.rolloutPercentage,
|
||
targetGroup: map['targetGroup'] as String? ?? fallback.targetGroup,
|
||
issueStats: map['issueStats'] as String? ?? fallback.issueStats,
|
||
// 严重程度
|
||
severityHigh: map['severityHigh'] as String? ?? fallback.severityHigh,
|
||
severityMedium: map['severityMedium'] as String? ?? fallback.severityMedium,
|
||
severityLow: map['severityLow'] as String? ?? fallback.severityLow,
|
||
// 状态
|
||
statusPending: map['statusPending'] as String? ?? fallback.statusPending,
|
||
statusFixing: map['statusFixing'] as String? ?? fallback.statusFixing,
|
||
statusFixed: map['statusFixed'] as String? ?? fallback.statusFixed,
|
||
statusDeveloping: map['statusDeveloping'] as String? ?? fallback.statusDeveloping,
|
||
statusTesting: map['statusTesting'] as String? ?? fallback.statusTesting,
|
||
statusPreview: map['statusPreview'] as String? ?? fallback.statusPreview,
|
||
statusReleased: map['statusReleased'] as String? ?? fallback.statusReleased,
|
||
// 通用
|
||
comingSoon: map['comingSoon'] as String? ?? fallback.comingSoon,
|
||
gotIt: map['gotIt'] as String? ?? fallback.gotIt,
|
||
// 问卷
|
||
questionnaireBtn: map['questionnaireBtn'] as String? ?? fallback.questionnaireBtn,
|
||
questionnaireTitle: map['questionnaireTitle'] as String? ?? fallback.questionnaireTitle,
|
||
q1KnowGooglePlay: map['q1KnowGooglePlay'] as String? ?? fallback.q1KnowGooglePlay,
|
||
q2HasGmsDevice: map['q2HasGmsDevice'] as String? ?? fallback.q2HasGmsDevice,
|
||
q3WillingToBeta: map['q3WillingToBeta'] as String? ?? fallback.q3WillingToBeta,
|
||
q4EnterGmail: map['q4EnterGmail'] as String? ?? fallback.q4EnterGmail,
|
||
q4GmailHint: map['q4GmailHint'] as String? ?? fallback.q4GmailHint,
|
||
qYes: map['qYes'] as String? ?? fallback.qYes,
|
||
qNo: map['qNo'] as String? ?? fallback.qNo,
|
||
qSubmit: map['qSubmit'] as String? ?? fallback.qSubmit,
|
||
qNext: map['qNext'] as String? ?? fallback.qNext,
|
||
qEndTitle: map['qEndTitle'] as String? ?? fallback.qEndTitle,
|
||
qEndThanks: map['qEndThanks'] as String? ?? fallback.qEndThanks,
|
||
qEndNotQualified: map['qEndNotQualified'] as String? ?? fallback.qEndNotQualified,
|
||
qInvalidEmail: map['qInvalidEmail'] as String? ?? fallback.qInvalidEmail,
|
||
qSubmitting: map['qSubmitting'] as String? ?? fallback.qSubmitting,
|
||
qSubmitSuccess: map['qSubmitSuccess'] as String? ?? fallback.qSubmitSuccess,
|
||
qSubmitFailed: map['qSubmitFailed'] as String? ?? fallback.qSubmitFailed,
|
||
qEndThankYou: map['qEndThankYou'] as String? ?? fallback.qEndThankYou,
|
||
);
|
||
}
|
||
|
||
/// 检查 TBeta 字段同步
|
||
///
|
||
/// 当 TBeta 新增字段但 _importBeta 未同步时,
|
||
/// 会在 debug 模式下打印警告,帮助开发者及时发现遗漏。
|
||
static void _checkBetaFieldsSync(
|
||
Map<String, dynamic> map,
|
||
TBeta? fallback,
|
||
) {
|
||
assert(() {
|
||
const expectedKeys = <String>{
|
||
'pageTitle',
|
||
'back',
|
||
'previewTab',
|
||
'issuesTab',
|
||
'confirmClose',
|
||
'confirmOpen',
|
||
'cancel',
|
||
'close',
|
||
'open',
|
||
'emptyFeatures',
|
||
'reload',
|
||
'loadFailed',
|
||
'retry',
|
||
'filterAll',
|
||
'filterPending',
|
||
'filterFixing',
|
||
'filterFixed',
|
||
'emptyIssues',
|
||
'rolloutPercentage',
|
||
'targetGroup',
|
||
'issueStats',
|
||
'severityHigh',
|
||
'severityMedium',
|
||
'severityLow',
|
||
'statusPending',
|
||
'statusFixing',
|
||
'statusFixed',
|
||
'statusDeveloping',
|
||
'statusTesting',
|
||
'statusPreview',
|
||
'statusReleased',
|
||
'comingSoon',
|
||
'gotIt',
|
||
};
|
||
final mapKeys = map.keys.toSet();
|
||
final missingInImport = expectedKeys.difference(mapKeys);
|
||
if (missingInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TBeta _importBeta 缺失字段: $missingInImport',
|
||
);
|
||
}
|
||
final extraInImport = mapKeys.difference(expectedKeys);
|
||
if (extraInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TBeta _importBeta 多余字段: $extraInImport',
|
||
);
|
||
}
|
||
return true; // assert 总是通过,仅打印警告
|
||
}());
|
||
}
|
||
|
||
static TSubmit _importSubmit(Map<String, dynamic>? map, TSubmit fallback) {
|
||
if (map == null) return fallback;
|
||
// ---- 字段同步检查(防止新增字段遗漏) ----
|
||
_checkSubmitFieldsSync(map, fallback);
|
||
return TSubmit(
|
||
title: map['title'] as String? ?? fallback.title,
|
||
contentLabel: map['contentLabel'] as String? ?? fallback.contentLabel,
|
||
titleLabel: map['titleLabel'] as String? ?? fallback.titleLabel,
|
||
authorLabel: map['authorLabel'] as String? ?? fallback.authorLabel,
|
||
categoryLabel: map['categoryLabel'] as String? ?? fallback.categoryLabel,
|
||
titleHint: map['titleHint'] as String? ?? fallback.titleHint,
|
||
authorHint: map['authorHint'] as String? ?? fallback.authorHint,
|
||
contentHint: map['contentHint'] as String? ?? fallback.contentHint,
|
||
submit: map['submit'] as String? ?? fallback.submit,
|
||
submitting: map['submitting'] as String? ?? fallback.submitting,
|
||
contentRequired: map['contentRequired'] as String? ?? fallback.contentRequired,
|
||
contentTooShort: map['contentTooShort'] as String? ?? fallback.contentTooShort,
|
||
contentTooLong: map['contentTooLong'] as String? ?? fallback.contentTooLong,
|
||
reviewing: map['reviewing'] as String? ?? fallback.reviewing,
|
||
reviewDesc: map['reviewDesc'] as String? ?? fallback.reviewDesc,
|
||
historyTitle: map['historyTitle'] as String? ?? fallback.historyTitle,
|
||
historyEmpty: map['historyEmpty'] as String? ?? fallback.historyEmpty,
|
||
statusReviewing: map['statusReviewing'] as String? ?? fallback.statusReviewing,
|
||
statusApproved: map['statusApproved'] as String? ?? fallback.statusApproved,
|
||
statusRejected: map['statusRejected'] as String? ?? fallback.statusRejected,
|
||
catYiyan: map['catYiyan'] as String? ?? fallback.catYiyan,
|
||
catXinde: map['catXinde'] as String? ?? fallback.catXinde,
|
||
catYiju: map['catYiju'] as String? ?? fallback.catYiju,
|
||
catSignature: map['catSignature'] as String? ?? fallback.catSignature,
|
||
deleteRecord: map['deleteRecord'] as String? ?? fallback.deleteRecord,
|
||
deleteConfirm: map['deleteConfirm'] as String? ?? fallback.deleteConfirm,
|
||
);
|
||
}
|
||
|
||
/// 检查 TSubmit 字段同步
|
||
///
|
||
/// 当 TSubmit 新增字段但 _importSubmit 未同步时,
|
||
/// 会在 debug 模式下打印警告,帮助开发者及时发现遗漏。
|
||
static void _checkSubmitFieldsSync(
|
||
Map<String, dynamic> map,
|
||
TSubmit? fallback,
|
||
) {
|
||
assert(() {
|
||
const expectedKeys = <String>{
|
||
'title',
|
||
'contentLabel',
|
||
'titleLabel',
|
||
'authorLabel',
|
||
'categoryLabel',
|
||
'titleHint',
|
||
'authorHint',
|
||
'contentHint',
|
||
'submit',
|
||
'submitting',
|
||
'contentRequired',
|
||
'contentTooShort',
|
||
'contentTooLong',
|
||
'reviewing',
|
||
'reviewDesc',
|
||
'historyTitle',
|
||
'historyEmpty',
|
||
'statusReviewing',
|
||
'statusApproved',
|
||
'statusRejected',
|
||
'catYiyan',
|
||
'catXinde',
|
||
'catYiju',
|
||
'catSignature',
|
||
'deleteRecord',
|
||
'deleteConfirm',
|
||
};
|
||
final mapKeys = map.keys.toSet();
|
||
final missingInImport = expectedKeys.difference(mapKeys);
|
||
if (missingInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TSubmit _importSubmit 缺失字段: $missingInImport',
|
||
);
|
||
}
|
||
final extraInImport = mapKeys.difference(expectedKeys);
|
||
if (extraInImport.isNotEmpty) {
|
||
// ignore: avoid_print
|
||
print(
|
||
'⚠️ [TranslationIO] TSubmit _importSubmit 多余字段: $extraInImport',
|
||
);
|
||
}
|
||
return true; // assert 总是通过,仅打印警告
|
||
}());
|
||
}
|
||
}
|