Files
Life-OS/public/i18n.js
T

47 lines
16 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Life OS internationalisation: one locale catalogue, no DOM text rewriting. */
(() => {
const en = {
app: { today: 'TODAY', timeline: 'TIMELINE', museum: 'MUSEUM', insights: 'INSIGHTS', profile: 'PROFILE', tasks: 'TASKS', calendar: 'CALENDAR', system: 'SYSTEM' },
common: { save: 'SAVE', cancel: 'CANCEL', edit: 'EDIT', delete: 'DELETE', close: 'Close', open: 'Open', minimize: 'Minimize', maximize: 'Maximize', restore: 'Restore window', energy: 'ENERGY', days: 'DAYS', never: 'NEVER' },
today: { prompt: 'How was your day?', placeholder: 'Write something about today...', archive: 'ARCHIVE TODAY', update: 'UPDATE MEMORY', archiveDate: 'SAVE MEMORY', updateDate: 'UPDATE MEMORY', backToToday: 'Back to today', weather: "TODAY'S WEATHER", energy: 'ENERGY LEVEL', film: 'DAILY PROMPT', archiving: 'ARCHIVING MEMORY...', archived: 'MEMORY ARCHIVED' },
weather: { clear: 'Clear', light: 'Light', cloudy: 'Cloudy', rain: 'Rain', storm: 'Storm' },
timeline: { eyebrow: 'MEMORY ARCHIVE', heading: '{count} OF {total} MEMORIES', search: 'Search memories', searchPlaceholder: 'Search notes, tags, places, tasks…', filterTag: 'Filter by tag', allTags: 'ALL TAGS', noMatches: 'No memories match these filters.', favorite: 'FAVORITE', emptyTitle: 'No memories yet.', emptyBody: 'Open Today when you are ready to keep one.', detail: 'MEMORY DETAIL', untitled: 'Untitled memory', noNote: 'No written note.', editing: 'EDITING AS TODAY — SAVE TO UPDATE', preserved: 'FAVORITED', addMuseum: 'ADD TO MUSEUM', confirmDelete: 'CONFIRM DELETE', remove: 'Remove this memory?', irreversible: 'This cannot be undone.', deleteMemory: 'DELETE MEMORY', removed: 'MEMORY REMOVED', added: 'MEMORY FAVORITED', unpreserved: 'REMOVED FROM FAVORITES' },
memory: { tags: 'TAGS', tagsPlaceholder: 'Separate tags with commas', place: 'PLACE / SCENE (OPTIONAL)', placePlaceholder: 'Where or what was the setting?', linkTask: 'RELATED TASK (OPTIONAL)', noTask: 'NO RELATED TASK', relatedTask: 'Related task', favorite: 'ADD TO FAVORITES', edit: 'EDIT MEMORY DETAILS', note: 'NOTE', title: 'TITLE (OPTIONAL)', titlePlaceholder: 'Give this memory a title' },
museum: { eyebrow: 'MUSEUM', title: 'Preserved moments', subtitle: 'Worth keeping for the long view.', empty: 'A museum begins with one preserved moment.', preserved: 'STATUS: PRESERVED' },
insights: { eyebrow: 'LAST 30 DAYS', title: 'Insights, quietly.', weather: 'WEATHER', average: 'AVERAGE ENERGY', active: 'MOST ACTIVE DAY', current: 'CURRENT STREAK', longest: 'Longest streak: {count} days', noEntries: 'No entries yet' },
profile: { eyebrow: 'SYSTEM PROFILE', online: 'LIFE OS ONLINE', daysOnline: 'DAYS ONLINE', memories: 'MEMORIES', museumItems: 'MUSEUM ITEMS', streak: 'CURRENT STREAK', longest: 'LONGEST STREAK', commonWeather: 'COMMON WEATHER', personal: 'PERSONAL SYSTEM', name: 'Display Name', birthday: 'Birthday (optional)', start: 'Life OS Start Date', motto: 'Personal Motto', save: 'SAVE PROFILE', saved: 'PROFILE SAVED', average: 'AVERAGE ENERGY {value} / 5' },
system: { eyebrow: 'SYSTEM SETTINGS', title: 'System, local and yours.', appearance: 'APPEARANCE', language: 'LANGUAGE', browserLanguage: 'BROWSER LANGUAGE', detectedZh: 'Detected: Chinese', detectedEn: 'Detected: English', auto: 'AUTO', data: 'DATA', storage: 'STORAGE', dataStorage: 'DATA STORAGE', export: 'EXPORT DATA', import: 'IMPORT DATA', reset: 'RESET LIFE OS', local: 'Local Storage', stored: 'Your data is stored locally in this browser.', backups: 'Create regular backups to prevent data loss.', lastBackup: 'LAST BACKUP · {value}', recommended: 'BACKUP RECOMMENDED', version: 'VERSION', theme: { dark: 'DARK', light: 'LIGHT', auto: 'AUTO' } },
dialog: { backup: 'LIFE OS BACKUP', ready: 'Ready to restore', exported: 'Exported: {date}', memories: 'Memories: {count}', museumItems: 'Museum Items: {count}', goals: 'Goals: {count}', tasks: 'Tasks: {count}', merge: 'MERGE', replaceAll: 'REPLACE ALL DATA', final: 'FINAL CONFIRMATION', replaceQuestion: 'Replace all Life OS data?', replaceWarning: 'This will replace all current Life OS data.', replace: 'REPLACE DATA', resetQuestion: 'Reset all local data?', resetWarning: 'Export a backup first if you want to keep it.', resetData: 'RESET DATA' },
feedback: { backup: 'BACKUP CREATED', invalid: 'INVALID BACKUP FILE', restored: 'SYSTEM RESTORED', restoring: 'RESTORING SYSTEM...', minimized: 'MINIMIZED — TAP THE APP ICON TO RESTORE', languageZh: 'Language set to Chinese', languageEn: 'Language set to English', followingZh: 'Following browser language: Chinese', followingEn: 'Following browser language: English' },
addon: { draftRestored: 'DRAFT RESTORED', searchTitle: 'SEARCH MEMORY ARCHIVE', searchPlaceholder: 'Search titles, notes, moods…', searchHint: 'ESC to close · click a result to open it', untitled: 'Untitled memory', noResults: 'No memories found.', syncPaused: 'CLOUD SYNC PAUSED — CHANGES STAY ON THIS DEVICE', syncReady: 'CLOUD SYNC READY', migrateQuestion: 'Move this browser’s Life OS to the cloud?', migrateBody: 'Your existing local records will become the first synced copy for this ChatGPT account.', migrate: 'MIGRATE & SYNC', fresh: 'START FRESH', migrated: 'LOCAL LIFE OS MIGRATED', cloudRestored: 'CLOUD LIFE OS RESTORED', cloudUnavailable: 'CLOUD STORAGE UNAVAILABLE — LOCAL MODE ACTIVE' },
calendar: { eyebrow: 'MEMORIES & MILESTONES', month: 'MONTH', day: 'DAY', today: 'TODAY', mon: 'MON', tue: 'TUE', wed: 'WED', thu: 'THU', fri: 'FRI', sat: 'SAT', sun: 'SUN', previous: 'Previous month', next: 'Next month', previousDay: 'Previous day', nextDay: 'Next day', dayAtGlance: 'THAT DAY', memory: 'MEMORY', task: 'TASK', goal: 'GOAL', items: 'items', taskDue: 'TASK DUE', taskDone: 'TASK COMPLETED', goalCreated: 'GOAL CREATED', goalTarget: 'GOAL TARGET DATE', goalDone: 'GOAL COMPLETED', emptyDay: 'No memories or milestones recorded for this day.', openToday: 'Write a memory', writeMemory: 'Add memory', openTasks: 'Open tasks' },
tasks: { eyebrow: 'GOALS & TASKS', title: 'Make room for what matters.', subtitle: 'A small, steady plan for today and the days ahead.', addGoal: 'NEW GOAL', addTask: 'ADD TASK', taskPlaceholder: 'What needs doing?', goalPlaceholder: 'What do you want to move toward?', goalDescription: 'A note about this goal (optional)', finishedGoals: 'COMPLETED GOALS', goalComplete: 'COMPLETE GOAL', goalReopen: 'REOPEN GOAL', all: 'ALL', today: 'TODAY', upcoming: 'UPCOMING', done: 'DONE', activeGoals: 'ACTIVE GOALS', noGoals: 'Start with one goal worth moving toward.', noTasks: 'Nothing on this list yet.', due: 'DUE {date}', noDate: 'NO DUE DATE', priority: { low: 'LOW', normal: 'NORMAL', high: 'HIGH' }, goal: 'GOAL', anyGoal: 'NO GOAL', save: 'SAVE', cancel: 'CANCEL', complete: 'MARK COMPLETE', reopen: 'REOPEN', delete: 'DELETE', goalTitle: 'New goal', taskTitle: 'New task', goalCreated: 'GOAL CREATED', taskAdded: 'TASK ADDED', taskRemoved: 'TASK REMOVED', goalRemoved: 'GOAL REMOVED', confirmGoalDelete: 'Delete this goal?', confirmGoalDeleteBody: 'Tasks linked to it will be kept without a goal.', target: 'TARGET DATE', completed: 'COMPLETED', progress: '{done} OF {total} DONE', desktopShow: 'SHOW COUNTDOWN', desktopHide: 'HIDE COUNTDOWN', countdown: 'GOAL COUNTDOWN', daysLeft: '{count} days left', todayTarget: 'Target is today', daysOverdue: '{count} days overdue', pinOnCreate: 'Show countdown on desktop', todayHeading: 'Focus for today', openCount: '{count} OPEN TASKS', overdue: 'OVERDUE' }
};
const zh = {
app: { today: '今日', timeline: '时间线', museum: '人生博物馆', insights: '洞察', profile: '个人资料', tasks: '目标与待办', calendar: '日历', system: '系统' },
common: { save: '保存', cancel: '取消', edit: '编辑', delete: '删除', close: '关闭', open: '打开', minimize: '最小化', maximize: '最大化', restore: '恢复窗口', energy: '能量', days: '天', never: '从未' },
today: { prompt: '今天过得怎么样?', placeholder: '写下今天的片段…', archive: '归档今日', update: '更新记忆', archiveDate: '保存记忆', updateDate: '更新记忆', backToToday: '返回今天', weather: '今日天气', energy: '能量等级', film: '今日灵感', archiving: '正在归档…', archived: '记忆已归档' },
weather: { clear: '晴朗', light: '微光', cloudy: '多云', rain: '雨天', storm: '风暴' },
timeline: { eyebrow: '记忆档案', heading: '{count} / {total} 条记忆', search: '搜索记忆', searchPlaceholder: '搜索记录、标签、地点或待办…', filterTag: '按标签筛选', allTags: '全部标签', noMatches: '没有符合筛选条件的记忆。', favorite: '已收藏', emptyTitle: '还没有记忆。', emptyBody: '准备好记录时,打开“今日”。', detail: '记忆详情', untitled: '当天记录', noNote: '尚未写下记录。', editing: '正在以今日记录编辑 — 保存即可更新', preserved: '已收藏', addMuseum: '加入收藏', confirmDelete: '确认删除', remove: '删除这条记忆?', irreversible: '此操作无法撤销。', deleteMemory: '删除记忆', removed: '记忆已删除', added: '记忆已收藏', unpreserved: '已取消收藏' },
memory: { tags: '标签', tagsPlaceholder: '多个标签请用逗号分隔', place: '地点 / 场景(选填)', placePlaceholder: '在哪里,或当时是什么场景?', linkTask: '关联待办(选填)', noTask: '不关联待办', relatedTask: '关联待办', favorite: '加入收藏', edit: '编辑记忆详情', note: '记录内容', title: '标题(选填)', titlePlaceholder: '为这条记忆取个标题' },
museum: { eyebrow: '人生博物馆', title: '被珍藏的瞬间', subtitle: '值得留给漫长回望的片段。', empty: '从一份被珍藏的记忆开始。', preserved: '状态:已珍藏' },
insights: { eyebrow: '最近 30 天', title: '安静地看见时间。', weather: '天气', average: '平均能量', active: '最活跃日', current: '当前连续记录', longest: '最长连续记录:{count} 天', noEntries: '暂无记录' },
profile: { eyebrow: '系统档案', online: 'LIFE OS 在线', daysOnline: '系统运行天数', memories: '记忆', museumItems: '博物馆藏品', streak: '当前连续记录', longest: '最长连续记录', commonWeather: '常见天气', personal: '个人系统', name: '显示名称', birthday: '生日(选填)', start: 'Life OS 启动日期', motto: '个人格言', save: '保存资料', saved: '资料已保存', average: '平均能量 {value} / 5' },
system: { eyebrow: '系统设置', title: '你的个人系统。', appearance: '外观', language: '语言', browserLanguage: '浏览器语言', detectedZh: '当前识别:中文', detectedEn: '当前识别:英语', auto: '跟随浏览器', data: '数据', storage: '存储', dataStorage: '数据存储', export: '导出数据', import: '导入数据', reset: '重置 Life OS', local: '本地存储', stored: '你的数据仅存储在此浏览器中。', backups: '定期备份,让记忆一直在。', lastBackup: '上次备份 · {value}', recommended: '建议备份', version: '版本', theme: { dark: '深色', light: '浅色', auto: '跟随系统' } },
dialog: { backup: 'Life OS 备份', ready: '准备恢复', exported: '导出时间:{date}', memories: '记忆:{count}', museumItems: '博物馆藏品:{count}', goals: '目标:{count}', tasks: '待办:{count}', merge: '合并', replaceAll: '替换全部数据', final: '最终确认', replaceQuestion: '替换全部 Life OS 数据?', replaceWarning: '这将覆盖当前所有 Life OS 数据。', replace: '替换数据', resetQuestion: '重置所有本地数据?', resetWarning: '如需保留数据,请先导出备份。', resetData: '重置数据' },
feedback: { backup: '备份已创建', invalid: '无效备份文件', restored: '系统已恢复', restoring: '正在恢复系统…', minimized: '已最小化 — 点击任务栏图标即可恢复', languageZh: '语言已切换为中文', languageEn: 'Language set to English', followingZh: '已跟随浏览器语言:中文', followingEn: 'Following browser language: English' },
addon: { draftRestored: '草稿已恢复', searchTitle: '搜索记忆档案', searchPlaceholder: '搜索标题、记录或天气…', searchHint: '按 Esc 关闭 · 点击结果即可打开', untitled: '未命名记忆', noResults: '没有找到记忆。', syncPaused: '云端同步暂停——更改仍保留在此设备', syncReady: '云端同步已就绪', migrateQuestion: '将此浏览器的 Life OS 迁移到云端?', migrateBody: '现有本地记录将成为这个 ChatGPT 账号的第一份云端同步数据。', migrate: '迁移并同步', fresh: '从空白开始', migrated: '本地 Life OS 已迁移', cloudRestored: '云端 Life OS 已恢复', cloudUnavailable: '云端存储暂不可用——已使用本地模式' },
calendar: { eyebrow: '记忆与生活节点', month: '月', day: '日', today: '今天', mon: '一', tue: '二', wed: '三', thu: '四', fri: '五', sat: '六', sun: '日', previous: '上个月', next: '下个月', previousDay: '前一天', nextDay: '后一天', dayAtGlance: '这一天', memory: '记忆', task: '待办', goal: '目标', items: '项', taskDue: '待办截止', taskDone: '完成待办', goalCreated: '创建目标', goalTarget: '目标日期', goalDone: '完成目标', emptyDay: '这一天还没有记忆或目标节点。', openToday: '写下一段记忆', writeMemory: '新增记忆', openTasks: '打开待办' },
tasks: { eyebrow: '目标与待办', title: '把心力留给重要的事。', subtitle: '为今天和接下来的日子,排一个轻量、踏实的计划。', addGoal: '新建目标', addTask: '添加待办', taskPlaceholder: '接下来要做什么?', goalPlaceholder: '你想朝什么方向前进?', goalDescription: '关于这个目标的备注(选填)', finishedGoals: '已完成的目标', goalComplete: '完成目标', goalReopen: '重新开启目标', all: '全部', today: '今天', upcoming: '即将开始', done: '已完成', activeGoals: '进行中的目标', noGoals: '从一个值得继续靠近的目标开始。', noTasks: '这里暂时没有待办。', due: '截止 {date}', noDate: '无截止日期', priority: { low: '低', normal: '普通', high: '高' }, goal: '目标', anyGoal: '不关联目标', save: '保存', cancel: '取消', goalTitle: '新建目标', taskTitle: '新建待办', goalCreated: '目标已创建', taskAdded: '待办已添加', taskRemoved: '待办已删除', goalRemoved: '目标已删除', confirmGoalDelete: '删除这个目标?', confirmGoalDeleteBody: '关联的待办会保留,但不再关联此目标。', target: '目标日期', completed: '已完成', complete: '标记完成', reopen: '重新打开', delete: '删除', progress: '已完成 {done} / {total}', desktopShow: '显示倒计时', desktopHide: '隐藏倒计时', countdown: '目标倒计时', daysLeft: '还有 {count} 天', todayTarget: '目标就在今天', daysOverdue: '已过期 {count} 天', pinOnCreate: '在桌面显示倒计时', todayHeading: '今天要推进的事', openCount: '还有 {count} 项待办', overdue: '已逾期' }
};
const get = (object, key) => key.split('.').reduce((value, part) => value?.[part], object);
function currentLocale() { return typeof window.lang === 'function' ? window.lang() : 'en'; }
function t(key, values = {}) {
const dictionary = currentLocale() === 'zh' ? zh : en;
const fallback = get(en, key) || key;
return String(get(dictionary, key) ?? fallback).replace(/\{(\w+)\}/g, (_, name) => values[name] ?? `{${name}}`);
}
function date(value, options) { return new Intl.DateTimeFormat(currentLocale() === 'zh' ? 'zh-CN' : 'en-US', options).format(new Date(value)); }
window.LifeI18n = { t, date, dictionaries: { en, zh } };
})();