chore: restructure project and add i18n support

- Reorganize project structure with new electron and shared directories
- Add comprehensive i18n support with Chinese, English, and Japanese locales
- Update build configurations and TypeScript paths for new structure
- Add various UI components including chat interface and task management
- Include Windows release binaries and localization files
- Update dependencies and fix import paths throughout the codebase
This commit is contained in:
duanshuwen
2026-04-06 14:39:06 +08:00
parent e76b034d50
commit 6615d11dd6
311 changed files with 823682 additions and 4460 deletions

23
src/i18n/constants.ts Normal file
View File

@@ -0,0 +1,23 @@
export const SUPPORTED_LANGUAGE_CODES = ['en', 'zh', 'ja'] as const;
export type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
export const SUPPORTED_LANGUAGES = [
{ code: 'en', label: 'English' },
{ code: 'zh', label: '中文' },
{ code: 'ja', label: '日本語' },
] as const;
// 命名空间定义
export const NAMESPACES = [
'common',
'conversation',
'setting',
'menu',
'login',
'dashboard',
'task',
'rate',
'knowledge',
'component',
] as const;
export type Namespace = (typeof NAMESPACES)[number];

106
src/i18n/index.ts Normal file
View File

@@ -0,0 +1,106 @@
import { createI18n, type I18n, type I18nOptions } from 'vue-i18n';
import { SUPPORTED_LANGUAGE_CODES, SUPPORTED_LANGUAGES, NAMESPACES, type LanguageCode } from './constants';
import { resolveSupportedLanguage, detectSystemLanguage } from './resolver';
// 使用 import.meta.glob 动态加载所有语言文件
// 文件路径模式:./locales/{语言}/{命名空间}.json
const modules = import.meta.glob('./locales/*/*.json', { eager: true });
// 构建 vue-i18n 格式的资源对象:{ [locale]: { [namespace]: messages } }
function buildResources() {
const resources: Record<string, Record<string, any>> = {};
// 初始化每种语言的空对象
SUPPORTED_LANGUAGE_CODES.forEach(lang => {
resources[lang] = {};
});
// 遍历所有模块,按语言和命名空间组织
for (const [path, module] of Object.entries(modules)) {
// 路径示例:'./locales/en/common.json'
const match = path.match(/\.\/locales\/([a-z]{2})\/([a-z]+)\.json$/);
if (!match) continue;
const [, lang, namespace] = match;
if (!SUPPORTED_LANGUAGE_CODES.includes(lang as LanguageCode) || !NAMESPACES.includes(namespace as any)) {
continue;
}
// @ts-expect-error: module 可能是 Module 类型
const messages = (module as any).default || module;
resources[lang][namespace] = messages;
}
return resources;
}
// 获取持久化的语言设置(稍后由 Pinia store 提供)
function getPersistedLanguage(): LanguageCode | null {
try {
const saved = localStorage.getItem('diona-language');
return saved && SUPPORTED_LANGUAGE_CODES.includes(saved as LanguageCode) ? saved as LanguageCode : null;
} catch {
return null;
}
}
// 确定初始语言:持久化设置 > 系统语言 > 默认中文
function determineInitialLocale(): LanguageCode {
const persisted = getPersistedLanguage();
if (persisted) return persisted;
const systemLang = detectSystemLanguage();
return systemLang;
}
async function createI18nInstance() {
const resources = buildResources();
const initialLocale = determineInitialLocale();
const options: I18nOptions = {
legacy: false,
locale: initialLocale,
fallbackLocale: 'zh',
messages: resources, // 使用构建的资源对象
availableLocales: SUPPORTED_LANGUAGE_CODES,
fallbackFormat: true,
datetimeFormats: {},
numberFormats: {},
};
const i18n = createI18n(options);
return i18n;
}
// 创建 i18n 实例
export const i18n = await createI18nInstance();
// 兼容性 API
export async function setLanguage(lang: LanguageCode, _i18n?: I18n) {
const __i18n = _i18n ?? i18n;
if (__i18n.mode === 'legacy') {
__i18n.global.locale = lang;
return;
}
(__i18n.global.locale as unknown as { value: LanguageCode }).value = lang;
// 持久化到 localStorage稍后由 Pinia store 处理)
try {
localStorage.setItem('diona-language', lang);
} catch {}
}
export function getLanguage() {
if (i18n.mode === 'legacy') {
return i18n.global.locale;
}
return (i18n.global.locale as unknown as { value: LanguageCode }).value;
}
// 导出类型和常量
export type { LanguageCode };
export { SUPPORTED_LANGUAGE_CODES, SUPPORTED_LANGUAGES, NAMESPACES };
export default i18n;

143
src/i18n/locales/en.json Normal file
View File

@@ -0,0 +1,143 @@
{
"window": {
"minimize": "Minimize",
"maximize": "Maximize",
"restore": "Restore",
"close": "Close"
},
"main": {
"welcome": {
"helloMessage": "Hello, I'm Diona"
},
"conversation": {
"placeholder": "Type a message...",
"newConversation": "New Conversation",
"selectModel": "Please select model",
"createConversation": "Create Conversation",
"searchPlaceholder": "Search conversations...",
"goSettings": "Go to",
"settings": "Settings Window",
"addModel": "to add a model",
"dialog": {
"title": "Confirm Deletion",
"content": "Are you sure you want to delete this conversation?",
"content_1": "Are you sure you want to delete the selected conversations? This action cannot be undone."
},
"operations": {
"pin": "Pin Selected",
"del": "Delete Selected",
"selectAll": "Select All",
"cancel": "Cancel"
}
},
"sidebar": {
"conversations": "Conversations",
"settings": "Settings",
"help": "Help"
},
"message": {
"dialog": {
"title": "Confirm Deletion",
"messageDelete": "Are you sure you want to delete this message?",
"batchDelete": "Are you sure you want to delete the selected messages?",
"copySuccess": "Copied successfully"
},
"batchActions": {
"deleteSelected": "Delete Selected"
},
"rendering": "Thinking...",
"stoppedGeneration": "(Stopped generating)",
"sending": "Sending",
"stopGeneration": "Stop generating",
"send": "Send"
}
},
"dialog": {
"cancel": "Cancel",
"confirm": "Confirm"
},
"settings": {
"title": "Settings",
"base": "Basic Settings",
"provider": {
"modelConfig": "Model Configuration"
},
"theme": {
"label": "Theme Settings",
"dark": "Dark Theme",
"light": "Light Theme",
"system": "System Theme",
"primaryColor": "Primary Color"
},
"appearance": {
"fontSize": "Font Size",
"fontSizeOptions": {
"10": "Tiny (10px)",
"12": "Small (12px)",
"14": "Normal (14px)",
"16": "Medium (16px)",
"18": "Large (18px)",
"20": "Larger (20px)",
"24": "Extra Large (24px)"
}
},
"behavior": {
"minimizeToTray": "Minimize to tray when closed"
},
"language": {
"label": "Language"
},
"providers": {
"defaultModel": "Default Model",
"apiKey": "API Key",
"apiUrl": "API URL"
}
},
"menu": {
"conversation": {
"newConversation": "New Conversation",
"sortBy": "Sort By",
"sortByCreateTime": "Sort by Creation Time",
"sortByUpdateTime": "Sort by Update Time",
"sortByName": "Sort by Name",
"sortByModel": "Sort by Model",
"sortAscending": "Ascending",
"sortDescending": "Descending",
"pinConversation": "Pin Conversation",
"unpinConversation": "Unpin Conversation",
"renameConversation": "Rename Conversation",
"delConversation": "Delete Conversation",
"batchOperations": "Batch Operations"
},
"message": {
"copyMessage": "Copy Message",
"deleteMessage": "Delete Message",
"selectMessage": "Select Message"
}
},
"tray": {
"tooltip": "Diona Application",
"showWindow": "Show Window",
"exit": "Exit"
},
"timeAgo": {
"justNow": "Just now",
"minutes": "{count} minutes ago",
"hours": "{count} hours ago",
"days": "{count} days ago",
"months": "{count} months ago",
"years": "{count} years ago",
"weekday": {
"sun": "Sunday",
"mon": "Monday",
"tue": "Tuesday",
"wed": "Wednesday",
"thu": "Thursday",
"fri": "Friday",
"sat": "Saturday"
}
},
"app": {
"title": "Diona Application"
}
}

View File

@@ -0,0 +1,37 @@
{
"window": {
"minimize": "Minimize",
"maximize": "Maximize",
"restore": "Restore",
"close": "Close"
},
"dialog": {
"cancel": "Cancel",
"confirm": "Confirm"
},
"tray": {
"tooltip": "Diona Application",
"showWindow": "Show Window",
"exit": "Exit"
},
"timeAgo": {
"justNow": "Just now",
"minutes": "{count} minutes ago",
"hours": "{count} hours ago",
"days": "{count} days ago",
"months": "{count} months ago",
"years": "{count} years ago",
"weekday": {
"sun": "Sunday",
"mon": "Monday",
"tue": "Tuesday",
"wed": "Wednesday",
"thu": "Thursday",
"fri": "Friday",
"sat": "Saturday"
}
},
"app": {
"title": "Diona Application"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,47 @@
{
"welcome": {
"helloMessage": "Hello, I'm Diona"
},
"conversation": {
"placeholder": "Type a message...",
"newConversation": "New Conversation",
"selectModel": "Please select model",
"createConversation": "Create Conversation",
"searchPlaceholder": "Search conversations...",
"goSettings": "Go to",
"settings": "Settings Window",
"addModel": "to add a model",
"dialog": {
"title": "Confirm Deletion",
"content": "Are you sure you want to delete this conversation?",
"content_1": "Are you sure you want to delete the selected conversations? This action cannot be undone."
},
"operations": {
"pin": "Pin Selected",
"del": "Delete Selected",
"selectAll": "Select All",
"cancel": "Cancel"
}
},
"sidebar": {
"conversations": "Conversations",
"settings": "Settings",
"help": "Help"
},
"message": {
"dialog": {
"title": "Confirm Deletion",
"messageDelete": "Are you sure you want to delete this message?",
"batchDelete": "Are you sure you want to delete the selected messages?",
"copySuccess": "Copied successfully"
},
"batchActions": {
"deleteSelected": "Delete Selected"
},
"rendering": "Thinking...",
"stoppedGeneration": "(Stopped generating)",
"sending": "Sending",
"stopGeneration": "Stop generating",
"send": "Send"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,20 @@
{
"title": "Login",
"subtitle": "24/7 digital employee, never closed",
"username": "Username",
"usernamePlaceholder": "Please enter username",
"password": "Password",
"passwordPlaceholder": "Please enter password",
"code": "Verification Code",
"codePlaceholder": "Please enter verification code",
"loginButton": "Login",
"rememberPassword": "Remember password",
"forgotPassword": "Forgot password?",
"agreeTerms": "I agree to the",
"termsOfUse": "Terms of Use",
"privacyPolicy": "Privacy Policy",
"and": "and",
"usernameRequired": "Please enter username",
"passwordRequired": "Please enter password",
"codeRequired": "Please enter verification code"
}

View File

@@ -0,0 +1,22 @@
{
"conversation": {
"newConversation": "New Conversation",
"sortBy": "Sort By",
"sortByCreateTime": "Sort by Creation Time",
"sortByUpdateTime": "Sort by Update Time",
"sortByName": "Sort by Name",
"sortByModel": "Sort by Model",
"sortAscending": "Ascending",
"sortDescending": "Descending",
"pinConversation": "Pin Conversation",
"unpinConversation": "Unpin Conversation",
"renameConversation": "Rename Conversation",
"delConversation": "Delete Conversation",
"batchOperations": "Batch Operations"
},
"message": {
"copyMessage": "Copy Message",
"deleteMessage": "Delete Message",
"selectMessage": "Select Message"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,37 @@
{
"title": "Settings",
"base": "Basic Settings",
"provider": {
"modelConfig": "Model Configuration"
},
"theme": {
"label": "Theme Settings",
"dark": "Dark Theme",
"light": "Light Theme",
"system": "System Theme",
"primaryColor": "Primary Color"
},
"appearance": {
"fontSize": "Font Size",
"fontSizeOptions": {
"10": "Tiny (10px)",
"12": "Small (12px)",
"14": "Normal (14px)",
"16": "Medium (16px)",
"18": "Large (18px)",
"20": "Larger (20px)",
"24": "Extra Large (24px)"
}
},
"behavior": {
"minimizeToTray": "Minimize to tray when closed"
},
"language": {
"label": "Language"
},
"providers": {
"defaultModel": "Default Model",
"apiKey": "API Key",
"apiUrl": "API URL"
}
}

View File

@@ -0,0 +1 @@
{}

1
src/i18n/locales/ja.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

143
src/i18n/locales/zh.json Normal file
View File

@@ -0,0 +1,143 @@
{
"window": {
"minimize": "最小化",
"maximize": "最大化",
"restore": "还原",
"close": "关闭"
},
"main": {
"welcome": {
"helloMessage": "你好,我是迪奥娜"
},
"conversation": {
"placeholder": "输入消息...",
"newConversation": "新对话",
"selectModel": "请选择模型",
"createConversation": "创建对话",
"searchPlaceholder": "搜索对话...",
"goSettings": "快去",
"settings": "设置窗口",
"addModel": "添加模型",
"dialog": {
"title": "确认删除",
"content": "确定要删除这个对话吗?",
"content_1": "确定要删除选中的对话吗?此操作不可撤销。"
},
"operations": {
"pin": "置顶所选",
"del": "删除所选",
"selectAll": "全选",
"cancel": "取消"
}
},
"sidebar": {
"conversations": "对话",
"settings": "设置",
"help": "帮助"
},
"message": {
"dialog": {
"title": "确认删除",
"messageDelete": "确认删除该条消息?",
"batchDelete": "确认删除选中的消息?",
"copySuccess": "复制成功"
},
"batchActions": {
"deleteSelected": "删除选中项"
},
"rendering": "思考中...",
"stoppedGeneration": "(已停止生成)",
"sending": "发送中",
"stopGeneration": "停止生成",
"send": "发送"
}
},
"dialog": {
"cancel": "取消",
"confirm": "确认"
},
"settings": {
"title": "设置",
"base": "基础设置",
"provider": {
"modelConfig": "模型配置"
},
"providers": {
"defaultModel": "默认模型",
"apiKey": "API密钥",
"apiUrl": "API地址"
},
"theme": {
"label": "主题设置",
"dark": "深色主题",
"light": "浅色主题",
"system": "跟随系统",
"primaryColor": "主题颜色"
},
"appearance": {
"fontSize": "字体大小",
"fontSizeOptions": {
"10": "极小 (10px)",
"12": "小 (12px)",
"14": "正常 (14px)",
"16": "中 (16px)",
"18": "大 (18px)",
"20": "较大 (20px)",
"24": "超大 (24px)"
}
},
"behavior": {
"minimizeToTray": "关闭时最小化到托盘"
},
"language": {
"label": "语言设置"
}
},
"menu": {
"conversation": {
"newConversation": "新建对话",
"sortBy": "排序方式",
"sortByCreateTime": "按创建时间排序",
"sortByUpdateTime": "按更新时间排序",
"sortByName": "按名称排序",
"sortByModel": "按模型排序",
"sortAscending": "递增",
"sortDescending": "递减",
"pinConversation": "置顶对话",
"unpinConversation": "取消置顶",
"renameConversation": "重命名对话",
"delConversation": "删除对话",
"batchOperations": "批量操作"
},
"message": {
"copyMessage": "复制消息",
"deleteMessage": "删除消息",
"selectMessage": "选择消息"
}
},
"tray": {
"tooltip": "迪奥娜",
"showWindow": "显示窗口",
"exit": "退出"
},
"timeAgo": {
"justNow": "刚刚",
"minutes": "{count}分钟前",
"hours": "{count}小时前",
"days": "{count}天前",
"months": "{count}个月前",
"years": "{count}年前",
"weekday": {
"sun": "星期日",
"mon": "星期一",
"tue": "星期二",
"wed": "星期三",
"thu": "星期四",
"fri": "星期五",
"sat": "星期六"
}
},
"app": {
"title": "迪奥娜"
}
}

View File

@@ -0,0 +1,37 @@
{
"window": {
"minimize": "最小化",
"maximize": "最大化",
"restore": "还原",
"close": "关闭"
},
"dialog": {
"cancel": "取消",
"confirm": "确认"
},
"tray": {
"tooltip": "迪奥娜",
"showWindow": "显示窗口",
"exit": "退出"
},
"timeAgo": {
"justNow": "刚刚",
"minutes": "{count}分钟前",
"hours": "{count}小时前",
"days": "{count}天前",
"months": "{count}个月前",
"years": "{count}年前",
"weekday": {
"sun": "星期日",
"mon": "星期一",
"tue": "星期二",
"wed": "星期三",
"thu": "星期四",
"fri": "星期五",
"sat": "星期六"
}
},
"app": {
"title": "迪奥娜"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,47 @@
{
"welcome": {
"helloMessage": "你好,我是迪奥娜"
},
"conversation": {
"placeholder": "输入消息...",
"newConversation": "新对话",
"selectModel": "请选择模型",
"createConversation": "创建对话",
"searchPlaceholder": "搜索对话...",
"goSettings": "快去",
"settings": "设置窗口",
"addModel": "添加模型",
"dialog": {
"title": "确认删除",
"content": "确定要删除这个对话吗?",
"content_1": "确定要删除选中的对话吗?此操作不可撤销。"
},
"operations": {
"pin": "置顶所选",
"del": "删除所选",
"selectAll": "全选",
"cancel": "取消"
}
},
"sidebar": {
"conversations": "对话",
"settings": "设置",
"help": "帮助"
},
"message": {
"dialog": {
"title": "确认删除",
"messageDelete": "确认删除该条消息?",
"batchDelete": "确认删除选中的消息?",
"copySuccess": "复制成功"
},
"batchActions": {
"deleteSelected": "删除选中项"
},
"rendering": "思考中...",
"stoppedGeneration": "(已停止生成)",
"sending": "发送中",
"stopGeneration": "停止生成",
"send": "发送"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,20 @@
{
"title": "登录",
"subtitle": "24小时在岗从不打烊的数字员工",
"username": "账号",
"usernamePlaceholder": "请输入账号",
"password": "密码",
"passwordPlaceholder": "请输入密码",
"code": "验证码",
"codePlaceholder": "请输入验证码",
"loginButton": "登 录",
"rememberPassword": "记住密码",
"forgotPassword": "忘记密码?",
"agreeTerms": "我已同意",
"termsOfUse": "《使用协议》",
"privacyPolicy": "《隐私协议》",
"and": "和",
"usernameRequired": "请输入账号",
"passwordRequired": "请输入密码",
"codeRequired": "请输入验证码"
}

View File

@@ -0,0 +1,22 @@
{
"conversation": {
"newConversation": "新建对话",
"sortBy": "排序方式",
"sortByCreateTime": "按创建时间排序",
"sortByUpdateTime": "按更新时间排序",
"sortByName": "按名称排序",
"sortByModel": "按模型排序",
"sortAscending": "递增",
"sortDescending": "递减",
"pinConversation": "置顶对话",
"unpinConversation": "取消置顶",
"renameConversation": "重命名对话",
"delConversation": "删除对话",
"batchOperations": "批量操作"
},
"message": {
"copyMessage": "复制消息",
"deleteMessage": "删除消息",
"selectMessage": "选择消息"
}
}

View File

@@ -0,0 +1 @@
{}

View File

@@ -0,0 +1,37 @@
{
"title": "设置",
"base": "基础设置",
"provider": {
"modelConfig": "模型配置"
},
"theme": {
"label": "主题设置",
"dark": "深色主题",
"light": "浅色主题",
"system": "跟随系统",
"primaryColor": "主题颜色"
},
"appearance": {
"fontSize": "字体大小",
"fontSizeOptions": {
"10": "极小 (10px)",
"12": "小 (12px)",
"14": "正常 (14px)",
"16": "中 (16px)",
"18": "大 (18px)",
"20": "较大 (20px)",
"24": "超大 (24px)"
}
},
"behavior": {
"minimizeToTray": "关闭时最小化到托盘"
},
"language": {
"label": "语言设置"
},
"providers": {
"defaultModel": "默认模型",
"apiKey": "API密钥",
"apiUrl": "API地址"
}
}

View File

@@ -0,0 +1 @@
{}

38
src/i18n/resolver.ts Normal file
View File

@@ -0,0 +1,38 @@
import { SUPPORTED_LANGUAGE_CODES, type LanguageCode } from './constants';
// 创建语言代码集合用于快速查找
const SUPPORTED_LANGUAGE_CODE_SET = new Set<string>(SUPPORTED_LANGUAGE_CODES);
/**
* 标准化语言代码(处理 zh-CN、zh_TW 等变体)
*/
export function normalizeLocale(locale: string | null | undefined): string {
return locale?.trim().toLowerCase().replaceAll('_', '-') ?? '';
}
/**
* 解析支持的语言代码
* @param locale 原始语言代码(如 'zh-CN', 'en-US'
* @param fallback 回退语言代码,默认为 'zh'
* @returns 支持的语言代码
*/
export function resolveSupportedLanguage(
locale: string | null | undefined,
fallback: LanguageCode = 'zh',
): LanguageCode {
const normalizedLocale = normalizeLocale(locale);
if (!normalizedLocale) return fallback;
const [baseLanguage] = normalizedLocale.split('-');
return SUPPORTED_LANGUAGE_CODE_SET.has(baseLanguage)
? (baseLanguage as LanguageCode)
: fallback;
}
/**
* 检测系统语言
*/
export function detectSystemLanguage(): LanguageCode {
if (typeof navigator === 'undefined') return 'zh';
return resolveSupportedLanguage(navigator.language);
}