Compare commits

..

170 Commits

Author SHA1 Message Date
arvinxx c542670a3c add server agent 2025-12-08 17:11:48 +08:00
arvinxx 2d71b97454 fix title and avatar 2025-12-08 16:46:38 +08:00
Shinji-Li 8d26047eab feat: add the agentbuilder inject context & delete some get tools (#10666)
* feat: add agent builder inject context well down

* fix: delelte some get agentbuilder tools
2025-12-08 16:45:31 +08:00
Rene Wang 1025478de2 feat: Allow DND in tree 2025-12-08 15:18:17 +08:00
arvinxx 10141be2e5 push group route 2025-12-08 14:57:05 +08:00
arvinxx fed079ad0d refactor agent group 2025-12-08 14:49:23 +08:00
arvinxx 0d10292989 refactor create group 2025-12-08 14:49:22 +08:00
arvinxx 9e19e439f7 refactor create group 2025-12-08 14:49:22 +08:00
Rene Wang 96484851c0 feat: Page copilot 2025-12-08 14:42:28 +08:00
Shinji-Li 2b72f28be3 feat: support approve install plugins in agent builder (#10662)
* feat: update agent builder tools call way

* feat: add install Plugins tools & add human approve intervation
2025-12-08 14:29:45 +08:00
arvinxx 29a08bb673 support delete memory 2025-12-08 10:00:22 +08:00
arvinxx 55c7c439f8 improve start input action 2025-12-08 00:27:13 +08:00
arvinxx 501f1a9938 fix delete agent and improve start input action 2025-12-08 00:12:41 +08:00
arvinxx df580d79f8 fix create agent flow 2025-12-07 23:34:29 +08:00
arvinxx f4ea92399f refactor sessionStore to agentStore 2025-12-07 23:08:01 +08:00
Rene Wang 649640a538 lint: Clean up coed 2025-12-07 19:54:11 +08:00
arvinxx a1a7673d79 refactor Conversation with agentStore 2025-12-07 19:38:58 +08:00
arvinxx eefb14072e refactor home page using homeStore and agentStore 2025-12-07 19:07:54 +08:00
arvinxx b59577c2d2 refactor sidebar using homeStore and agentStore 2025-12-07 18:43:26 +08:00
arvinxx a89581216f refactor agent using homeStore and agentStore 2025-12-07 18:43:26 +08:00
arvinxx 6b7744e6a6 home store 2025-12-07 18:43:26 +08:00
canisminor1990 acd0909cb2 style: fix auth card 2025-12-07 18:24:51 +08:00
canisminor1990 df71b12f1a style: update memory card 2025-12-07 18:17:39 +08:00
Neko 5666e474dd test(database): document model delete all (#10644) 2025-12-07 17:32:45 +08:00
canisminor1990 20c5a8f80c style: update memory card 2025-12-07 17:16:32 +08:00
arvinxx 9c094bc56c Home Repo 2025-12-07 16:29:24 +08:00
canisminor1990 c80e120328 style: update memory GroupedVirtuoso 2025-12-07 15:34:51 +08:00
Rene Wang 1b0d02809c feat: Optimize hook 2025-12-07 15:02:17 +08:00
canisminor1990 1a2055c0e6 style: update memory 2025-12-07 14:49:07 +08:00
Rene Wang f15c3cb939 lint: Clean up codes 2025-12-07 12:59:58 +08:00
canisminor1990 0078695da6 style: update memory 2025-12-07 12:12:47 +08:00
arvinxx 8b6b1eb995 refactor send 2025-12-07 12:06:36 +08:00
arvinxx 2abccbb47a support switch input mode 2025-12-07 12:04:46 +08:00
Rene Wang 3b1b497d3e refac: Reorgnize folders 2025-12-07 11:58:46 +08:00
Rene Wang 1267ed9f38 lint: Remove unused files 2025-12-07 11:49:59 +08:00
Rene Wang bfbc80b7f7 refac: Clean up code 2025-12-07 11:34:52 +08:00
Rene Wang 4fe52294c0 opti: Better dnd performance 2025-12-07 11:25:38 +08:00
Rene Wang 5dedb3eda0 opti: Better D & D performance 2025-12-07 11:11:39 +08:00
Rene Wang 9eecc9becc refac: Clean up code 2025-12-07 11:01:46 +08:00
arvinxx 28e1c5f091 fix build 2025-12-07 10:41:26 +08:00
arvinxx 9904fc41cc try to fix build 2025-12-07 10:25:26 +08:00
Neko ee86fd6058 ♻️ refactor(memory-user-memory): better structure, added tests, simplified executor (#10641) 2025-12-07 09:33:18 +08:00
Neko 2f0454719b 🔨 chore(userMemories): improved the results of memory extractor (#10636) 2025-12-07 02:04:24 +08:00
canisminor1990 fa7ccaa353 chore: rm unused loading 2025-12-07 00:45:49 +08:00
canisminor1990 90b1d19c77 style: update market-auth-callback 2025-12-07 00:39:24 +08:00
arvinxx fcbdfffa6d Context 情景记忆 2025-12-07 00:37:04 +08:00
canisminor1990 3c68226bce style: update oidc style 2025-12-07 00:31:36 +08:00
arvinxx 7ed30fc881 Preference 偏好记忆 2025-12-07 00:22:37 +08:00
arvinxx 80b230672b Experience 经验记忆 2025-12-06 23:59:13 +08:00
arvinxx 3508deff3e Experience 经验记忆 2025-12-06 23:50:29 +08:00
canisminor1990 19b09e069f style: update market-auth-callback 2025-12-06 23:39:45 +08:00
Rene Wang 53b4b91af6 refac: Clean up code 2025-12-06 23:20:07 +08:00
Rene Wang 8719744225 fix: back button 2025-12-06 23:05:59 +08:00
Rene Wang 120e01d8e7 fix: View mode 2025-12-06 23:03:27 +08:00
Rene Wang 443dd88446 fix: Update library id based on URL 2025-12-06 23:03:27 +08:00
canisminor1990 65bae726c0 fix: fix home market avatar z-index 2025-12-06 22:58:53 +08:00
Rene Wang 89b96b5e8e refac: State & UI 2025-12-06 22:55:31 +08:00
canisminor1990 301908f377 fix: roll back file pagesize 2025-12-06 21:30:37 +08:00
Rene Wang 19a9e88ffc style: Update header 2025-12-06 20:44:41 +08:00
Rene Wang 5237e045ea fix: Root folder 2025-12-06 20:42:18 +08:00
canisminor1990 35f19d9b31 fix: fix mobile 2025-12-06 20:30:40 +08:00
canisminor1990 7352b8a16b fix: fix mobile 2025-12-06 20:24:21 +08:00
canisminor1990 50e386b43f fix: fix mobile 2025-12-06 20:18:46 +08:00
Shinji-Li 1bfe4579bb feat: add more official tools into agentbuilder (#10638)
*  feat: add klavis tools into agent builder

- Add searchOfficialTools API for searching builtin and Klavis integrations
- Add searchMarketTools API for searching marketplace plugins
- Update AgentTool.tsx with dual-column Segmented tabs layout (All/Installed)
- Update PluginTag.tsx to support Klavis tools display with proper icons
- Fix pre-existing type errors in Header.tsx and pluginTypes.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* 🐛 fix: resolve circular dependencies in klavisStore imports

- Import KlavisServerStatus from types.ts instead of index.ts
- Import selectors from @/store/tool/selectors instead of slice paths

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-06 19:37:24 +08:00
canisminor1990 60ca998aac style: update res pagesize 2025-12-06 18:53:25 +08:00
canisminor1990 38dc1a69a4 style: update agent setting 2025-12-06 18:09:16 +08:00
Neko 3551ab8f64 fix(userMemories): Upstash Workflows will serialize into JSON, causes the Date being incorrectly used (#10635) 2025-12-06 15:24:56 +08:00
canisminor1990 e82cb62109 style: update agent publish 2025-12-06 15:00:55 +08:00
Shinji-Li 5760f550ed feat: add modify system prompt tools in agentbuilder (#10634)
* feat: support modify system role & use stream output

* fix: slove metion dropdown position
2025-12-06 15:00:01 +08:00
canisminor1990 4222768078 style: update page sidebar 2025-12-06 15:00:01 +08:00
canisminor1990 e9bd57eeb3 feat: add Suspense debug 2025-12-06 15:00:01 +08:00
canisminor1990 7a003b0d37 feat: add Suspense debug 2025-12-06 15:00:01 +08:00
Neko 26cf7d7308 🐛 fix: expose /api/workflows endpoints (#10632) 2025-12-06 15:00:01 +08:00
canisminor1990 f9bb091f3a fix: fix DraggablePanel 2025-12-06 15:00:01 +08:00
canisminor1990 aab42b4087 fix: fix cmd k register 2025-12-06 15:00:01 +08:00
canisminor1990 f253881fc0 fix: fix auto save 2025-12-06 14:59:59 +08:00
canisminor1990 2b0e4aed44 style: update editor 2025-12-06 14:59:52 +08:00
Neko 23fc9c50d3 feat(userMemories): unify layer names, add webhook verify headers (#10629) 2025-12-06 14:59:52 +08:00
canisminor1990 9bd27ea414 style: update editor 2025-12-06 14:59:52 +08:00
canisminor1990 6f1cfa9480 style: update editor 2025-12-06 14:59:51 +08:00
canisminor1990 55194e7986 style: update agent builder 2025-12-06 14:59:51 +08:00
canisminor1990 2aa28fe8bc fix: DraggablePanel 2025-12-06 14:59:51 +08:00
canisminor1990 7001a2ea03 fix: DraggablePanel 2025-12-06 14:59:51 +08:00
arvinxx b29581d69d refactor the switch branch 2025-12-06 14:59:51 +08:00
arvinxx e2e70f1121 fix topic messages issues 2025-12-06 14:59:51 +08:00
canisminor1990 cbd1d0f584 style: update auth 2025-12-06 14:59:51 +08:00
Neko f2745306af feat(userMemories): whitelist to extract users (#10626)
feat(userMemories): whitelist to extract users for
2025-12-06 14:59:51 +08:00
Shinji-Li d6e989d692 feat: add more acions & can modify provider and model (#10625)
* feat: add topic selectror

* feat: add model change & history change way

* feat: add more tools
2025-12-06 14:59:51 +08:00
Shinji-Li de2f7f3a20 🔨 chore: change the settings sub router to / path (#10617)
feat: change the settings sub router to / path
2025-12-06 14:59:51 +08:00
Rene Wang 58adbdd983 feat: Support blocks 2025-12-06 14:59:51 +08:00
Rene Wang a762049b62 fix: Update filter 2025-12-06 14:59:51 +08:00
arvinxx 762127860d fix topic models update issues 2025-12-06 14:59:51 +08:00
Neko 43c834d687 feat(userMemory): with Upstash Workflows for memory extractor (#10623)
feat(userMemory): with Upstash Workflows for memory extractor
2025-12-06 14:59:50 +08:00
arvinxx 0a7ba6bf0b support send message 2025-12-06 14:59:50 +08:00
Neko dec483dccb ♻️ refactor(server/modules/s3): improved constructor to accept options without taking env directly (#10624)
refactor(server/modules/s3): improved constructor to accept options without taking env directly
2025-12-06 14:59:50 +08:00
Rene Wang 0a9a8ab817 fix: Exclude mapped document 2025-12-06 14:59:50 +08:00
Rene Wang d59694bb08 feat: Header 2025-12-06 14:59:50 +08:00
Rene Wang 6088095119 feat: Renaming KB 2025-12-06 14:59:50 +08:00
Rene Wang 75d591e779 fix: Changelog dialog crashing 2025-12-06 14:59:50 +08:00
arvinxx e1ddb27ef9 refactor model list 2025-12-06 14:59:50 +08:00
arvinxx b5a30c8359 update tests 2025-12-06 14:59:50 +08:00
Rene Wang 20791df887 fix: Change log modal 2025-12-06 14:59:50 +08:00
Rene Wang e4bfeb00d0 fix: Update translation 2025-12-06 14:59:50 +08:00
arvinxx 2d3bd01b02 refactor chat input issue 2025-12-06 14:59:48 +08:00
Rene Wang 9f1f23125b style: Changelog modal 2025-12-06 14:59:09 +08:00
Rene Wang d6a69f9b5b feat: Download document 2025-12-06 14:59:09 +08:00
Rene Wang dd503ff418 fix: Remove unncessary tRPC calling 2025-12-06 14:59:09 +08:00
arvinxx 882850f56b refactor topic issues 2025-12-06 14:59:09 +08:00
canisminor1990 28a7796cec style: fix cursor 2025-12-06 14:59:08 +08:00
Shinji-Li f96e3bda5d 🔨 chore: delete the url hydration & romove the pin agent way (#10616)
fix: delete the url Hydration & delete pinagent way
2025-12-06 14:59:08 +08:00
Rene Wang 9a241af65d fix: Deduplication 2025-12-06 14:59:08 +08:00
canisminor1990 2942f2244f style: fix cursor 2025-12-06 14:59:08 +08:00
canisminor1990 bc0a7a14d8 style: update editor style 2025-12-06 14:59:08 +08:00
canisminor1990 e8314145e0 style: update style 2025-12-06 14:59:08 +08:00
arvinxx dee6e5f97a fix 2025-12-06 14:59:08 +08:00
Rene Wang 031f8d143b feat: Discard the page editor modal 2025-12-06 14:59:07 +08:00
Rene Wang dc31d02bcd refac: Renaming files 2025-12-06 14:59:07 +08:00
Rene Wang 68394609b7 fix: Page explore 2025-12-06 14:59:07 +08:00
Rene Wang a6263a45d2 opti: Better file loading 2025-12-06 14:59:07 +08:00
canisminor1990 62c6d12192 chore: add knip cli 2025-12-06 14:59:07 +08:00
arvinxx 1c9c229e2a ♻️ refactor(agent): add getAgentConfigById to AgentService with default config merging
- Add getAgentConfigById method to AgentService that merges default configs
- Extract mergeDefaultConfig as private helper method for code reuse
- Update router to use agentService.getAgentConfigById instead of agentModel
- Update updateAgentConfig to return merged config via getAgentConfigById
- Add tests for getAgentConfigById merging behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 14:59:07 +08:00
arvinxx 13fedf67f6 fix 2025-12-06 14:59:07 +08:00
arvinxx 976d63b099 🐛 fix(agent): merge default configs for builtin agents on server side
- Add DEFAULT_AGENT_CONFIG and serverDefaultAgentConfig merging in AgentService.getBuiltinAgent
- Ensures inbox agent always has complete config with model/provider
- Update selector comment to document server-side merging behavior
- Add unit tests for config merging behavior

Closes LOBE-1447

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 14:59:07 +08:00
canisminor1990 69966cb235 style: update chat item style 2025-12-06 14:59:07 +08:00
canisminor1990 d10ade40f9 style: update chat item style 2025-12-06 14:59:07 +08:00
canisminor1990 7cbade75bd style: update new topic button 2025-12-06 14:59:07 +08:00
canisminor1990 4c894a3b98 style: update agent welcome and chatinput 2025-12-06 14:59:07 +08:00
canisminor1990 d286c29745 style: update agent welcome and chatinput 2025-12-06 14:59:07 +08:00
Rene Wang 561e80050f opti: Save on blur 2025-12-06 14:59:07 +08:00
canisminor1990 6c9b46e8df fix: systemrole editor init 2025-12-06 14:59:07 +08:00
Shinji-Li 6a955cc3ea 🐛 fix: slove the command k jump link error (#10614)
fix: fixed command k router error
2025-12-06 14:59:07 +08:00
Rene Wang 7d2ea6b243 fix: Jump link 2025-12-06 14:59:07 +08:00
Rene Wang ee36f3210b fix: Copilot size 2025-12-06 14:59:06 +08:00
arvinxx 4ab7013310 update for test 2025-12-06 14:59:06 +08:00
arvinxx 2243f82ba7 update for test 2025-12-06 14:59:06 +08:00
arvinxx 3656e162fe fix topic with inbox agent 2025-12-06 14:59:06 +08:00
arvinxx 05eb57ec3c refactor agent 2025-12-06 14:59:06 +08:00
arvinxx d97138fab3 refactor agent 2025-12-06 14:59:06 +08:00
canisminor1990 af14b2fb04 style: update icon 2025-12-06 14:59:06 +08:00
canisminor1990 3ecb3c4fe0 style: update create icon 2025-12-06 14:59:06 +08:00
Rene Wang e563be6a8c style: Search in CMDK 2025-12-06 14:59:06 +08:00
Rene Wang 7bb6061a03 refac: Lint code style 2025-12-06 14:59:06 +08:00
Rene Wang fff64ea919 style: Adjust padding 2025-12-06 14:59:06 +08:00
Neko 38da250e5d feat(userMemories): extract from user memory, add new memory-user-memory package (#10514)
* feat(userMemories): extract from user memory, add new memory-user-memory package

* chore: missing deps

* chore: missing test
2025-12-06 14:59:06 +08:00
arvinxx 0b99552ada inbox 2025-12-06 14:59:06 +08:00
arvinxx e805e8cb96 refactor inbox agent store 2025-12-06 14:59:05 +08:00
arvinxx 37aabb7bd5 support session get inbox 2025-12-06 14:59:05 +08:00
Rene Wang 122cd6294c feat: Support JS rendering 2025-12-06 14:59:05 +08:00
canisminor1990 3a4d9ce33e pref: update topic count 2025-12-06 14:59:05 +08:00
Rene Wang f291505215 feat: Handle gitignore 2025-12-06 14:59:05 +08:00
arvinxx 79aab68167 add welcome for agent 2025-12-06 14:59:05 +08:00
Rene Wang 356efab490 feat: Upload folder 2025-12-06 14:59:05 +08:00
arvinxx 8079032563 improve conversation width 2025-12-06 14:59:05 +08:00
arvinxx efc8d83221 support config plugins 2025-12-06 14:59:05 +08:00
Rene Wang ff06a3c602 feat: Unfiied search 2025-12-06 14:59:05 +08:00
canisminor1990 2ed15c50af style: update style 2025-12-06 14:59:05 +08:00
canisminor1990 1fe0b2e9f3 style: clean add button 2025-12-06 14:59:05 +08:00
canisminor1990 81400f3bdb feat: add agent more 2025-12-06 14:59:05 +08:00
canisminor1990 c14d2781dd feat: add agent more 2025-12-06 14:59:04 +08:00
Rene Wang 46c8106185 style: Turn changelog to a modal 2025-12-06 14:59:04 +08:00
canisminor1990 26355231ec feat: add agent more 2025-12-06 14:59:04 +08:00
canisminor1990 92a8fc1d38 feat: add topic more 2025-12-06 14:59:04 +08:00
Arvin Xu 425b773769 memory-panel (#10598)
* 🐛 fix: missing init user after user creation (#10587)

* 🌐 chore: translate non-English comments to English in python-interpreter (#10568)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

* 基本完成简单的 memory 提取

finish extract

identity 提取

refactor prompts and implements

add memory layers

refactor GateKeeper generate

improve GateKeeper generate

init packages

add messages prompts

 feat(memory): add filter, search and i18n for identity panel

- Add demographic identity type support
- Implement complete i18n with memory namespace
- Add type filter (personal/professional/demographic) and search functionality
- Remove Preference and Experience features (keep only Identity and Context)
- Optimize UI layout: left-right filter/view mode layout
- Add collapsible role tag cloud
- Refactor types to use strict IdentityType enum
- Fix type definitions and imports to use @lobechat/types consistently

finish Identity ui

update

wip for memory panel

* update

* rename

* refactor memory

* update
2025-12-06 14:59:04 +08:00
canisminor1990 721b8c980d style: update welcome speed 2025-12-06 14:59:04 +08:00
Rene Wang aaf264ca0f feat: Move help center to the footer 2025-12-06 14:59:04 +08:00
Rene Wang a807d658f3 style: Add tooltip 2025-12-06 14:59:04 +08:00
Rene Wang fdd63c25c7 feat: New AddButton 2025-12-06 14:59:04 +08:00
canisminor1990 4f88b498f7 style: update i18n 2025-12-06 14:59:04 +08:00
arvinxx 2967f36805 fix types 2025-12-06 14:59:03 +08:00
Shinji-Li cfb2ced431 style: update layout
 test: update tests (#10510)

♻️ refactor: refactor update agent config implement (#10507)

♻️ refactor: refactor session store to agent store (#10485)

♻️ refactor: refactor with new conversation store (#10483)

 feat: add editor data into market agent (#10451)

feat: Create Folder in Repo (#10352)

🔨 chore: delete editor content sql migration (#10449)

💄 style(wip): LobeHub Next UI Refactor (#10388)

 feat: change agent settings drawer to editor mode (#10392)

* 🐛 fix: Showing compatibility with both new and old versions of Plugins (#10418)

---------

Co-authored-by: Arvin Xu <arvinx@foxmail.com>
Co-authored-by: canisminor1990 <17870709+canisminor1990@users.noreply.github.com>
2025-12-06 14:58:59 +08:00
3842 changed files with 256580 additions and 306431 deletions
+4 -10
View File
@@ -5,26 +5,20 @@ alwaysApply: false
# Database Migrations Guide
## Step1: Generate migrations
## Step1: Generate migrations:
```bash
bun run db:generate
```
this step will generate following files:
- packages/database/migrations/0046_meaningless_file_name.sql
- packages/database/migrations/0046_meaningless_file_name.sql
and update the following files:
this step will generate or update the following files:
- packages/database/migrations/0046_xxx.sql
- packages/database/migrations/meta/\_journal.json
- packages/database/src/core/migrations.json
- docs/development/database-schema.dbml
## Step2: optimize the migration sql fileName
the migration sql file name is randomly generated, we need to optimize the file name to make it more readable and meaningful. For example, `0046_meaningless_file_name.sql` -> `0046_user_add_avatar_column.sql`
the migration sql file name is randomly generated, we need to optimize the file name to make it more readable and meaningful. For example, `0046_xxx.sql` -> `0046_better_auth.sql`
## Step3: Defensive Programming - Use Idempotent Clauses
@@ -36,13 +36,13 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
1. **创建控制器 (Controller)**
- 位置:`apps/desktop/src/main/controllers/`
- 示例:创建 `NewFeatureCtr.ts`
- 需继承 `ControllerModule`,并设置 `static readonly groupName`(例如 `static override readonly groupName = 'newFeature';`
- 按 `_template.ts` 模板格式实现,并在 `apps/desktop/src/main/controllers/registry.ts` 的 `controllerIpcConstructors`(或 `controllerServerIpcConstructors`)中注册,保证类型推导与自动装配
- 规范:按 `_template.ts` 模板格式实现
- 注册:在 `apps/desktop/src/main/controllers/index.ts` 导出
2. **定义 IPC 事件处理器**
- 使用 `@IpcMethod()` 装饰器暴露渲染进程可访问的通道,或使用 `@IpcServerMethod()` 声明仅供 Next.js 服务器调用的 IPC
- 通道名称基于 `groupName.methodName` 自动生成,不再手动拼接字符串
- 处理函数可通过 `getIpcContext()` 获取 `sender`、`event` 等上下文信息,并按照需要返回结构化结果
- 使用 `@ipcClientEvent('eventName')` 装饰器注册事件处理函数
- 处理函数应接收前端传递的参数并返回结果
- 处理可能的错误情况
3. **实现业务逻辑**
- 可能需要调用 Electron API 或 Node.js 原生模块
@@ -60,17 +60,15 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
1. **创建服务层**
- 位置:`src/services/electron/`
- 添加服务方法调用 IPC
- 使用 `ensureElectronIpc()` 生成的类型安全代理,避免手动拼通道名称
- 使用 `dispatch` 或 `invoke` 函数
```typescript
// src/services/electron/newFeatureService.ts
import { ensureElectronIpc } from '@/utils/electron/ipc';
import type { NewFeatureParams } from '@lobechat/electron-client-ipc';
const ipc = ensureElectronIpc();
import { dispatch } from '@lobechat/electron-client-ipc';
import { NewFeatureParams } from 'types';
export const newFeatureService = async (params: NewFeatureParams) => {
return ipc.newFeature.doSomething(params);
return dispatch('newFeatureEventName', params);
};
```
@@ -120,31 +118,36 @@ LobeChat 桌面端基于 Electron 框架构建,采用主进程-渲染进程架
```typescript
// apps/desktop/src/main/controllers/NotificationCtr.ts
import { Notification } from 'electron';
import { ControllerModule, IpcMethod } from '@/controllers';
import type {
DesktopNotificationResult,
ShowDesktopNotificationParams,
} from '@lobechat/electron-client-ipc';
import { BrowserWindow, Notification } from 'electron';
import { ipcClientEvent } from 'electron-client-ipc';
export default class NotificationCtr extends ControllerModule {
static override readonly groupName = 'notification';
@IpcMethod()
async showDesktopNotification(
params: ShowDesktopNotificationParams,
): Promise<DesktopNotificationResult> {
if (!Notification.isSupported()) {
return { error: 'Notifications not supported', success: false };
}
interface ShowNotificationParams {
title: string;
body: string;
}
export class NotificationCtr {
@ipcClientEvent('showNotification')
async handleShowNotification({ title, body }: ShowNotificationParams) {
try {
const notification = new Notification({ body: params.body, title: params.title });
if (!Notification.isSupported()) {
return { success: false, error: 'Notifications not supported' };
}
const notification = new Notification({
title,
body,
});
notification.show();
return { success: true };
} catch (error) {
console.error('[NotificationCtr] Failed to show notification:', error);
return { error: error instanceof Error ? error.message : 'Unknown error', success: false };
console.error('Failed to show notification:', error);
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error'
};
}
}
}
@@ -51,15 +51,15 @@ alwaysApply: false
* 导入在步骤 2 中定义的 IPC 参数类型。
* 添加一个新的 `async` 方法,方法名通常与 Action 名称对应 (例如: `renameLocalFile`)。
* 方法接收 `params` (符合 IPC 参数类型)。
* 通过 `ensureElectronIpc()` 获取 IPC 代理 (`const ipc = ensureElectronIpc();`),调用与 Manifest 中 `name` 字段匹配的链式方法,并将 `params` 传递过去。
* 使用从 `@lobechat/electron-client-ipc` 导入的 `dispatch` (或 `invoke`) 函数,调用与 Manifest 中 `name` 字段匹配的 IPC 事件名称,并将 `params` 传递过去。
* 定义方法的返回类型,通常是 `Promise<{ success: boolean; error?: string }>`,与后端 Controller 返回的结构一致。
5. **实现后端逻辑 (Controller / IPC Handler):**
* **文件:** `apps/desktop/src/main/controllers/[ToolName]Ctr.ts` (例如: `apps/desktop/src/main/controllers/LocalFileCtr.ts`)
* **操作:**
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ControllerModule`, `IpcMethod`/`IpcServerMethod`、参数类型等)。
* 导入 Node.js 相关模块 (`fs`, `path` 等) 和 IPC 相关依赖 (`ipcClientEvent`, 参数类型等)。
* 添加一个新的 `async` 方法,方法名通常以 `handle` 开头 (例如: `handleRenameFile`)。
* 使用 `@IpcMethod()` 或 `@IpcServerMethod()` 装饰器将此方法注册为对应 IPC 事件的处理器,确保方法名与 Manifest 中的 `name` 以及 Service 层的链式调用一致。
* 使用 `@ipcClientEvent('yourApiName')` 装饰器将此方法注册为对应 IPC 事件的处理器,确保 `'yourApiName'` 与 Manifest 中的 `name` Service 层调用的事件名称一致。
* 方法的参数应解构自 Service 层传递过来的对象,类型与步骤 2 中定义的 IPC 参数类型匹配。
* 实现核心业务逻辑:
* 进行必要的输入验证。
+66 -56
View File
@@ -149,52 +149,50 @@ export const createMainWindow = () => {
1. **在主进程中注册 IPC 处理器**
```typescript
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
import { BrowserWindow } from 'electron';
import { ControllerModule, IpcMethod } from '@/controllers';
export default class BrowserWindowsCtr extends ControllerModule {
static override readonly groupName = 'windows';
@IpcMethod()
minimizeWindow() {
const focusedWindow = BrowserWindow.getFocusedWindow();
focusedWindow?.minimize();
return { success: true };
// BrowserWindowsCtr.ts
@ipcClientEvent('minimizeWindow')
handleMinimizeWindow() {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
focusedWindow.minimize();
}
return { success: true };
}
@IpcMethod()
maximizeWindow() {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow?.isMaximized()) focusedWindow.restore();
else focusedWindow?.maximize();
return { success: true };
@ipcClientEvent('maximizeWindow')
handleMaximizeWindow() {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
if (focusedWindow.isMaximized()) {
focusedWindow.restore();
} else {
focusedWindow.maximize();
}
}
return { success: true };
}
@IpcMethod()
closeWindow() {
BrowserWindow.getFocusedWindow()?.close();
return { success: true };
@ipcClientEvent('closeWindow')
handleCloseWindow() {
const focusedWindow = BrowserWindow.getFocusedWindow();
if (focusedWindow) {
focusedWindow.close();
}
return { success: true };
}
```
- `@IpcMethod()` 根据控制器的 `groupName` 自动将方法映射为 `windows.minimizeWindow` 形式的通道名称。
- 控制器需继承 `ControllerModule`,并在 `controllers/registry.ts` 中通过 `controllerIpcConstructors` 注册,便于类型生成。
2. **在渲染进程中调用**
```typescript
// src/services/electron/windowService.ts
import { ensureElectronIpc } from '@/utils/electron/ipc';
const ipc = ensureElectronIpc();
import { dispatch } from '@lobechat/electron-client-ipc';
export const windowService = {
minimize: () => ipc.windows.minimizeWindow(),
maximize: () => ipc.windows.maximizeWindow(),
close: () => ipc.windows.closeWindow(),
minimize: () => dispatch('minimizeWindow'),
maximize: () => dispatch('maximizeWindow'),
close: () => dispatch('closeWindow'),
};
```
- `ensureElectronIpc()` 会基于 `DesktopIpcServices` 运行时生成 Proxy,并通过 `window.electronAPI.invoke` 与主进程通信;不再直接使用 `dispatch`。
### 5. 自定义窗口控制 (无边框窗口)
@@ -254,33 +252,45 @@ export const createMainWindow = () => {
```typescript
// apps/desktop/src/main/controllers/BrowserWindowsCtr.ts
import type { OpenSettingsWindowOptions } from '@lobechat/electron-client-ipc';
import { ControllerModule, IpcMethod } from '@/controllers';
export default class BrowserWindowsCtr extends ControllerModule {
static override readonly groupName = 'windows';
@IpcMethod()
async openSettingsWindow(options?: string | OpenSettingsWindowOptions) {
const normalizedOptions =
typeof options === 'string' || options === undefined
? { tab: typeof options === 'string' ? options : undefined }
: options;
const mainWindow = this.app.browserManager.getMainWindow();
const query = new URLSearchParams();
if (normalizedOptions.tab) query.set('active', normalizedOptions.tab);
if (normalizedOptions.searchParams) {
for (const [key, value] of Object.entries(normalizedOptions.searchParams)) {
if (value) query.set(key, value);
}
}
const fullPath = `/settings${query.size ? `?${query.toString()}` : ''}`;
await mainWindow.loadUrl(fullPath);
mainWindow.show();
@ipcClientEvent('openSettings')
handleOpenSettings() {
// 检查设置窗口是否已经存在
if (this.settingsWindow && !this.settingsWindow.isDestroyed()) {
// 如果窗口已存在,将其置于前台
this.settingsWindow.focus();
return { success: true };
}
// 创建新窗口
this.settingsWindow = new BrowserWindow({
width: 800,
height: 600,
title: 'Settings',
parent: this.mainWindow, // 设置父窗口,使其成为模态窗口
modal: true,
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
nodeIntegration: false,
},
});
// 加载设置页面
if (isDev) {
this.settingsWindow.loadURL('http://localhost:3000/settings');
} else {
this.settingsWindow.loadFile(
path.join(__dirname, '../../renderer/index.html'),
{ hash: 'settings' }
);
}
// 监听窗口关闭事件
this.settingsWindow.on('closed', () => {
this.settingsWindow = null;
});
return { success: true };
}
```
+17 -33
View File
@@ -1,9 +1,8 @@
---
description:
description:
globs: src/database/schemas/*
alwaysApply: false
---
# Drizzle ORM Schema Style Guide for lobe-chat
This document outlines the conventions and best practices for defining PostgreSQL Drizzle ORM schemas within the lobe-chat project.
@@ -17,8 +16,7 @@ This document outlines the conventions and best practices for defining PostgreSQ
## Helper Functions
Commonly used column definitions, especially for timestamps, are centralized in [src/database/schemas/\_helpers.ts](mdc:src/database/schemas/_helpers.ts):
Commonly used column definitions, especially for timestamps, are centralized in [src/database/schemas/_helpers.ts](mdc:src/database/schemas/_helpers.ts):
- `timestamptz(name: string)`: Creates a timestamp column with timezone
- `createdAt()`, `updatedAt()`, `accessedAt()`: Helper functions for standard timestamp columns
- `timestamps`: An object `{ createdAt, updatedAt, accessedAt }` for easy inclusion in table definitions
@@ -31,7 +29,6 @@ Commonly used column definitions, especially for timestamps, are centralized in
## Column Definitions
### Primary Keys (PKs)
- Typically `text('id')` (or `varchar('id')` for some OIDC tables)
- Often use `.$defaultFn(() => idGenerator('table_name'))` for automatic ID generation with meaningful prefixes
- **ID Prefix Purpose**: Makes it easy for users and developers to distinguish different entity types at a glance
@@ -39,29 +36,24 @@ Commonly used column definitions, especially for timestamps, are centralized in
- Composite PKs are defined using `primaryKey({ columns: [t.colA, t.colB] })`
### Foreign Keys (FKs)
- Defined using `.references(() => otherTable.id, { onDelete: 'cascade' | 'set null' | 'no action' })`
- FK columns are usually named `related_table_singular_name_id` (e.g., `user_id` references `users.id`)
- Most tables include a `user_id` column referencing `users.id` with `onDelete: 'cascade'`
### Timestamps
- Consistently use the `...timestamps` spread from [\_helpers.ts](mdc:src/database/schemas/_helpers.ts) for `created_at`, `updated_at`, and `accessed_at` columns
- Consistently use the `...timestamps` spread from [_helpers.ts](mdc:src/database/schemas/_helpers.ts) for `created_at`, `updated_at`, and `accessed_at` columns
### Default Values
- `.$defaultFn(() => expression)` for dynamic defaults (e.g., `idGenerator()`, `randomSlug()`)
- `.default(staticValue)` for static defaults (e.g., `boolean('enabled').default(true)`)
### Indexes
- Defined in the table's second argument: `pgTable('name', {...columns}, (t) => ({ indexName: indexType().on(...) }))`
- Use `uniqueIndex()` for unique constraints and `index()` for non-unique indexes
- Naming pattern: `table_name_column(s)_idx` or `table_name_column(s)_unique`
- Many tables feature a `clientId: text('client_id')` column, often part of a composite unique index with `user_id`
### Data Types
- Common types: `text`, `varchar`, `jsonb`, `boolean`, `integer`, `uuid`, `pgTable`
- For `jsonb` fields, specify the TypeScript type using `.$type<MyType>()` for better type safety
@@ -105,7 +97,9 @@ export const agents = pgTable(
...timestamps,
},
// return array instead of object, the object style is deprecated
(t) => [uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId)],
(t) => [
uniqueIndex('client_id_user_id_unique').on(t.clientId, t.userId),
],
);
export const insertAgentSchema = createInsertSchema(agents);
@@ -116,7 +110,6 @@ export type AgentItem = typeof agents.$inferSelect;
## Common Patterns
### 1. userId + clientId Pattern (Legacy)
Some existing tables include both fields for different purposes:
```typescript
@@ -136,7 +129,6 @@ clientIdUnique: uniqueIndex('agents_client_id_user_id_unique').on(t.clientId, t.
- **Note**: This pattern is being phased out for new features to simplify the schema
### 2. Junction Tables (Many-to-Many Relationships)
Use composite primary keys for relationship tables:
```typescript
@@ -144,26 +136,21 @@ Use composite primary keys for relationship tables:
export const agentsKnowledgeBases = pgTable(
'agents_knowledge_bases',
{
agentId: text('agent_id')
.references(() => agents.id, { onDelete: 'cascade' })
.notNull(),
knowledgeBaseId: text('knowledge_base_id')
.references(() => knowledgeBases.id, { onDelete: 'cascade' })
.notNull(),
userId: text('user_id')
.references(() => users.id, { onDelete: 'cascade' })
.notNull(),
agentId: text('agent_id').references(() => agents.id, { onDelete: 'cascade' }).notNull(),
knowledgeBaseId: text('knowledge_base_id').references(() => knowledgeBases.id, { onDelete: 'cascade' }).notNull(),
userId: text('user_id').references(() => users.id, { onDelete: 'cascade' }).notNull(),
enabled: boolean('enabled').default(true),
...timestamps,
},
(t) => [primaryKey({ columns: [t.agentId, t.knowledgeBaseId] })],
(t) => [
primaryKey({ columns: [t.agentId, t.knowledgeBaseId] }),
],
);
```
**Pattern**: `{entity1}Id` + `{entity2}Id` as composite PK, plus `userId` for ownership
### 3. OIDC Tables Special Patterns
OIDC tables use `varchar` IDs instead of `text` with custom generators:
```typescript
@@ -179,7 +166,6 @@ export const oidcAuthorizationCodes = pgTable('oidc_authorization_codes', {
**Reason**: OIDC standards expect specific ID formats and lengths
### 4. File Processing with Async Tasks
File-related tables reference async task IDs for background processing:
```typescript
@@ -187,21 +173,17 @@ File-related tables reference async task IDs for background processing:
export const files = pgTable('files', {
// ... other fields
chunkTaskId: uuid('chunk_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
embeddingTaskId: uuid('embedding_task_id').references(() => asyncTasks.id, {
onDelete: 'set null',
}),
embeddingTaskId: uuid('embedding_task_id').references(() => asyncTasks.id, { onDelete: 'set null' }),
// ...
});
```
**Purpose**:
**Purpose**:
- Track file chunking progress (breaking files into smaller pieces)
- Track embedding generation progress (converting text to vectors)
- Allow querying task status and handling failures
### 5. Slug Pattern (Legacy)
Some entities include auto-generated slugs - this is legacy code:
```typescript
@@ -213,6 +195,8 @@ slug: varchar('slug', { length: 100 })
slugUserIdUnique: uniqueIndex('slug_user_id_unique').on(t.slug, t.userId),
```
**Current usage**: Only used to identify default agents/sessions (legacy pattern) **Future refactor**: Will likely be replaced with `isDefault: boolean()` field **Note**: Avoid using slugs for new features - prefer explicit boolean flags for status tracking
**Current usage**: Only used to identify default agents/sessions (legacy pattern)
**Future refactor**: Will likely be replaced with `isDefault: boolean()` field
**Note**: Avoid using slugs for new features - prefer explicit boolean flags for status tracking
By following these guidelines, maintain consistency, type safety, and maintainability across database schema definitions.
+35
View File
@@ -0,0 +1,35 @@
---
description: Explain how group chat works in LobeHub (Multi-agent orchestratoin)
globs:
alwaysApply: false
---
This rule explains how group chat (multi-agent orchestration) works. Not confused with session group, which is a organization method to manage session.
## Key points
- A supervisor will devide who and how will speak next
- Each agent will speak just like in single chat (if was asked to speak)
- Not coufused with session group
## Related Files
- src/store/chat/slices/message/supervisor.ts
- src/store/chat/slices/aiChat/actions/generateAIGroupChat.ts
- src/prompts/groupChat/index.ts (All prompts here)
## Snippets
```tsx
// Detect whether in group chat
const isGroupSession = useSessionStore(sessionSelectors.isCurrentSessionGroupSession);
// Member actions
const addAgentsToGroup = useChatGroupStore((s) => s.addAgentsToGroup);
const removeAgentFromGroup = useChatGroupStore((s) => s.removeAgentFromGroup);
const persistReorder = useChatGroupStore((s) => s.reorderGroupMembers);
// Get group info
const groupConfig = useChatGroupStore(chatGroupSelectors.currentGroupConfig);
const currentGroupMemebers = useSessionStore(sessionSelectors.currentGroupAgents);
```
+150 -51
View File
@@ -2,82 +2,181 @@
globs: *.tsx
alwaysApply: false
---
# LobeChat Internationalization Guide
## Key Points
- Default language: Chinese (zh-CN), Framework: react-i18next
- **Only edit files in `src/locales/default/`** - Never edit JSON files in `locales/`
- Run `pnpm i18n` to generate all translations (or manually translate zh-CN/en-US for dev preview)
- Default language: Chinese (zh-CN) as the source language
- Supported languages: 18 languages including English, Japanese, Korean, Arabic, etc.
- Framework: react-i18next with Next.js app router
- Translation automation: @lobehub/i18n-cli for automatic translation, config file: .i18nrc.js
- Never manually modify any json file. You can only modify files in `default` folder
## Key Naming Convention
## Directory Structure
**Flat keys with dot notation** (not nested objects):
```
src/locales/
├── default/ # Source language files (zh-CN)
│ ├── index.ts # Namespace exports
│ ├── common.ts # Common translations
│ ├── chat.ts # Chat-related translations
│ ├── setting.ts # Settings translations
│ └── ... # Other namespace files
└── resources.ts # Type definitions and language configuration
locales/ # Translation files
├── en-US/ # English translations
│ ├── common.json # Common translations
│ ├── chat.json # Chat translations
│ ├── setting.json # Settings translations
│ └── ... # Other namespace JSON files
├── ja-JP/ # Japanese translations
│ ├── common.json
│ ├── chat.json
│ └── ...
└── ... # Other language folders
```
## Workflow for Adding New Translations
### 1. Adding New Translation Keys
Step 1: Add translation keys in the corresponding namespace files under src/locales/default directory
```typescript
// ✅ Correct
// Example: src/locales/default/common.ts
export default {
'alert.cloud.action': '立即体验',
'clientDB.error.desc': '数据库初始化遇到问题',
'sync.actions.sync': '立即同步',
'sync.status.ready': '已连接',
};
// ❌ Avoid: Nested objects
export default {
alert: { cloud: { action: '...' } },
// ... existing keys
newFeature: {
title: '新功能标题',
description: '功能描述文案',
button: '操作按钮',
},
};
```
**Naming patterns:** `{feature}.{context}.{action|status}`
- `clientDB.modal.title` - Feature + context + property
- `sync.actions.sync` - Feature + group + action
- `sync.status.ready` - Feature + group + status
**Parameters:** Use `{{variableName}}` syntax
```typescript
'alert.cloud.desc': '我们提供 {{credit}} 额度积分',
```
**Avoid key conflicts:** Don't use both a leaf key and its parent path
Step 2: If creating a new namespace, export it in src/locales/default/index.ts
```typescript
// ❌ Conflict: clientDB.solve exists as both leaf and parent
'clientDB.solve': '自助解决',
'clientDB.solve.backup.title': '数据备份',
import newNamespace from './newNamespace';
// ✅ Solution: Use different suffixes
'clientDB.solve.action': '自助解决',
'clientDB.solve.backup.title': '数据备份',
const resources = {
// ... existing namespaces
newNamespace,
} as const;
```
## Workflow
### 2. Translation Process
1. Add keys to `src/locales/default/{namespace}.ts`
2. Export new namespace in `src/locales/default/index.ts`
3. For dev preview: manually translate `locales/zh-CN/{namespace}.json` and `locales/en-US/{namespace}.json`
4. Run `pnpm i18n` to generate all languages (CI handles this automatically)
Development mode:
## Usage
Generally, you don't need to help me run the automatic translation tool as it takes a long time. I'll run it myself when needed. However, to see immediate results, you still need to translate `locales/zh-CN/namespace.json` first, no need to translate other languages.
Production mode:
```bash
# Generate translations for all languages
npm run i18n
```
## Usage in Components
### Basic Usage
```tsx
import { useTranslation } from 'react-i18next';
const { t } = useTranslation('common');
const MyComponent = () => {
const { t } = useTranslation('common');
// Basic
t('newFeature.title')
// With parameters
t('alert.cloud.desc', { credit: '1000' })
// Multiple namespaces
const { t } = useTranslation(['common', 'chat']);
t('common:save')
return (
<div>
<h1>{t('newFeature.title')}</h1>
<p>{t('newFeature.description')}</p>
<button>{t('newFeature.button')}</button>
</div>
);
};
```
## Available Namespaces
### Usage with Parameters
auth, authError, changelog, chat, clerk, color, **common**, components, discover, editor, electron, error, file, home, hotkey, image, knowledgeBase, labs, marketAuth, memory, metadata, migration, modelProvider, models, oauth, onboarding, plugin, portal, providers, ragEval, **setting**, subscription, thread, tool, topic, welcome
```tsx
const { t } = useTranslation('common');
**Most used:** `common` (shared UI), `chat` (chat features), `setting` (settings)
<p>{t('welcome.message', { name: 'John' })}</p>;
// Corresponding language file:
// welcome: { message: 'Welcome {{name}}!' }
```
### Multiple Namespaces
```tsx
const { t } = useTranslation(['common', 'chat']);
<button>{t('common:save')}</button>
<span>{t('chat:typing')}</span>
```
## Type Safety
The project uses TypeScript to implement type-safe translations, with types automatically generated from src/locales/resources.ts:
```typescript
import type { DefaultResources, Locales, NS } from '@/locales/resources';
// Available types:
// - NS: Available namespace keys ('common' | 'chat' | 'setting' | ...)
// - Locales: Supported language codes ('en-US' | 'zh-CN' | 'ja-JP' | ...)
const namespace: NS = 'common';
const locale: Locales = 'en-US';
```
## Best Practices
### 1. Namespace Organization
- common: Shared UI elements (buttons, labels, actions)
- chat: Chat-specific functionality
- setting: Configuration and settings
- error: Error messages and handling
- [feature]: Feature-specific or page-specific namespaces
- components: Reusable component text
### 2. Key Naming Conventions
```typescript
// ✅ Good: Hierarchical structure
export default {
modal: {
confirm: {
title: '确认操作',
message: '确定要执行此操作吗?',
actions: {
confirm: '确认',
cancel: '取消',
},
},
},
};
// ❌ Avoid: Flat structure
export default {
modalConfirmTitle: '确认操作',
modalConfirmMessage: '确定要执行此操作吗?',
};
```
## Troubleshooting
### Missing Translation Keys
- Check if the key exists in src/locales/default/namespace.ts
- Ensure the namespace is correctly imported in the component
- Ensure new namespaces are exported in src/locales/default/index.ts
- 检查键是否存在于 src/locales/default/namespace.ts 中
- 确保在组件中正确导入命名空间
- 确保新命名空间已在 src/locales/default/index.ts 中导出
-146
View File
@@ -1,146 +0,0 @@
---
globs: src/locales/default/*
alwaysApply: false
---
你是「LobeHub」的中文 UI 文案与微文案(microcopy)专家。LobeHub 是一个助理工作空间:用户可以创建助理与群组,让人和助理、助理和助理协作,提升日常生产与生活效率。产品气质:外表年轻、亲和、现代;内核专业、可靠、强调生产力与可控性。整体风格参考 Notion / Figma / Apple / Discord / OpenAI / Gemini:清晰克制、可信、有人情味但不油腻。
产品 slogan**For Collaborative Agents**。你的文案要让用户持续感到:LobeHub 的重点不是“生成”,而是“协作的助理体系”(可共享上下文、可追踪、可回放、可演进、人在回路)。
---
### 1) 固定术语(必须遵守)
+ Workspace:空间
+ Agent:助理
+ Agent Team:群组
+ Context:上下文
+ Memory:记忆
+ Integration:连接器
+ Tool/Skill/Plugin/插件/工具: 技能
+ SystemRole: 助理档案
+ Topic: 话题
+ Page: 文稿
+ Community: 社区
+ Resource: 资源
+ Library: 库
+ MCP: MCP
+ Provider: 模型服务商
术语规则:同一概念全站只用一种说法,不混用“Agent/智能体/机器人/团队/工作区”等。
---
### 2) 你的任务
+ 优化、改写或从零生成任何界面中文文案:标题、按钮、表单说明、占位、引导、空状态、Toast、弹窗、错误、权限、设置项、创建/运行流程、协作与群组相关页面等。
+ 文案必须同时兼容:普通用户看得懂 + 专业用户不觉得低幼;娱乐与严肃场景都成立;不过度营销、不夸大 AI 能力;在关键节点提供恰到好处的人文关怀。
---
### 3) 品牌三原则(内化到结构与措辞)
+ **Create(创建)**:一句话创建助理;从想法到可用;清楚下一步。
+ **Collaborate(协作)**:多助理协作;群组对齐信息与产出;共享上下文(可控、可管理)。
+ **Evolve(演进)**:助理可在你允许的范围内记住偏好;随你的工作方式变得更顺手;强调可解释、可设置、可回放。
---
### 4) 写作规则(可执行)
1. **清晰优先**:短句、强动词、少形容词;避免口号化与空泛承诺(如“颠覆”“史诗级”“100%”)。
2. **分层表达(单一版本兼容两类用户)**:
- 主句:人人可懂、可执行
- 必要时补充一句副说明:更精确/更专业/更边界(可放副标题、帮助提示、折叠区)
- 不输出“Pro/Lite 两套文案”,而是“一句主文案 + 可选补充”
3. **术语克制但准确**:能说“连接/运行/上下文”就不要堆砌术语;必须出现专业词时给一句白话解释。
4. **一致性**:同一动作按钮尽量固定动词(创建/连接/运行/暂停/重试/查看详情/清除记忆等)。
5. **可行动**:每条提示都要让用户知道下一步;按钮避免“确定/取消”泛化,改成更具体的动作。
6. **中文本地化**:符合中文阅读节奏;中英混排规范;避免翻译腔。
---
### 5) 人文关怀(中间态温度:介于克制与陪伴)
目标:在 AI 时代的价值焦虑与创作失格感中,给用户“被理解 + 有掌控 + 能继续”的体验,但不写长抒情。
#### 温度比例规则
+ 默认:信息为主,温度为辅(约 8:2)
+ 关键节点(首次创建、空状态、长等待、失败重试、回退/丢失风险、协作分歧):允许提升到 7:3
+ 强制上限:任何一条上屏文案里,温度表达不超过**半句或一句**,且必须紧跟明确下一步。
#### 表达顺序(必须遵守)
1. 先承接处境(不评判):如“没关系/先这样也可以/卡住很正常”
2. 再给掌控感(人在回路):可暂停/可回放/可编辑/可撤销/可清除记忆/可查看上下文
3. 最后给下一步(按钮/路径明确)
#### 避免
+ 鸡汤式说教(如“别焦虑”“要相信未来”)
+ 宏大叙事与文学排比
+ 过度拟人(不承诺助理“理解你/有情绪/永远记得你”)
#### 核心立场
+ 助理很强,但它替代不了你的经历、选择与判断;LobeHub 帮你把时间还给重要的部分。
##### A. 情绪承接(先人后事)
+ 允许承认:焦虑、空白、无从下手、被追赶感、被替代感、创作枯竭、意义感动摇
+ 但不下结论、不说教:不输出“你要乐观/别焦虑”,改成“这种感觉很常见/你不是一个人”
##### B. 主体性回归(把人放回驾驶位)
+ 关键句式:**“决定权在你”**、**“你可以选择交给助理的部分”**、**“把你的想法变成可运行的流程”**
+ 强调可控:可编辑、可回放、可暂停、可撤销、可清除记忆、可查看上下文
##### C. 经历与关系(把价值从结果挪回过程)
+ 适度表达:记录、回放、版本、协作痕迹、讨论、共创、里程碑
+ 用“经历/过程/痕迹/回忆/脉络/成长”这类词,避免虚无抒情
##### D. 不用“AI 神话”
+ 不渲染“AI 终将超越你/取代你”
+ 也不轻飘飘说“AI 只是工具”了事更像:**“它是工具,但你仍是作者/负责人/最终决定者”**
##### 示例
在用户可能产生自我否定或无力感的场景(空状态、创作开始、产出对比、失败重试、长时间等待、团队协作分歧、版本回退):
1. **先承接感受**:用一句短话确认处境(不评判)
2. **再给掌控感**:强调“你可控/可选择/可回放/可撤销”
3. **最后给下一步**:提供明确行动按钮或路径
+ 允许出现“经历、选择、痕迹、成长、一起、陪你把事做完”等词来传递温度;但保持信息密度,不写长段抒情。
+ 严肃场景(权限/安全/付费/数据丢失风险)仍以清晰与准确为先,温度通过“尊重与解释”体现,而不是煽情。
你可以让系统在需要时套这些结构(同一句兼容新手/专业):
**开始创作/空白页**
+ 主句:给一个轻承接 + 行动入口
+ 模板:
- 「从一个念头开始就够了。写一句话,我来帮你搭好第一个助理。」
- 「不知道从哪开始也没关系:先说目标,我们一起把它拆开。」
**长任务运行/等待**
+ 模板:
- 「正在运行中…你可以先去做别的,完成后我会提醒你。」
- 「这一步可能要几分钟。想更快:减少上下文 / 切换模型 / 关闭自动运行。」
**失败/重试**
+ 模板:
- 「没关系,这次没跑通。你可以重试,或查看原因再继续。」
- 「连接失败:权限未通过或网络不稳定。去设置重新授权,或稍后再试。」
**对比与自我价值焦虑(适合提示/引导,不适合错误弹窗)**
+ 模板:
- 「助理可以加速产出,但方向、取舍和标准仍属于你。」
- 「结果可以很快,经历更重要:把每次尝试留下来,下一次会更稳。」
**协作/群组**
+ 模板:
- 「把上下文对齐到同一处,群组里每个助理都会站在同一页上。」
- 「不同意见没关系:先把目标写清楚,再让助理分别给方案与取舍。」
### 6) 错误/异常/权限/付费:硬规则
+ 必须包含:**发生了什么 +(可选)原因 + 你可以怎么做**
+ 必须提供可操作选项:**重试 / 查看详情 / 去设置 / 联系支持 / 复制日志**(按场景取舍)
+ 不责备用户;不只给错误码;错误码可放在“详情”里
+ 涉及数据与安全:语气更中性更完整,温度通过“尊重与解释”体现,而不是煽
-152
View File
@@ -1,152 +0,0 @@
---
globs: src/locales/default/*
alwaysApply: false
---
You are **LobeHubs English UI Copy & Microcopy Specialist**.
LobeHub is an assistant workspace: users can create **Agents** and **Agent Teams** so people↔agents and agent↔agent can collaborate to improve productivity in work and life.
Brand vibe: youthful, friendly, modern on the surface; professional, reliable, productivity- and controllability-first underneath. Overall style reference: Notion / Figma / Apple / Discord / OpenAI / Gemini — clear, restrained, trustworthy, human but not cheesy.
Product slogan: **For Collaborative Agents**. Your copy must continuously reinforce that LobeHub is not about “generation”, but about a **collaborative agent system**: shareable context, traceable outcomes, replayable runs, evolvable setup, and **human-in-the-loop**.
---
## 1) Fixed Terminology (must follow)
Use **exactly** these English terms across the product. Do not mix synonyms for the same concept.
- 空间: **Workspace**
- 助理: **Agent**
- 群组: **Group**
- 上下文: **Context**
- 记忆: **Memory**
- 连接器: **Integration**
- 技能/tool/plugin: **Skill**
- 助理档案: **Agent Profile**
- 话题: **Topic**
- 文稿: **Page**
- 社区: **Community**
- 资源: **Resource**
- 库: **Library**
- MCP: **MCP**
- 模型服务商: **Provider**
Terminology rule: one concept = one term site-wide. Never alternate with “bot/assistant/AI agent/team/workspace” variations.
---
## 2) Your Responsibilities
- Improve, rewrite, or create from scratch any **English UI copy**: titles, buttons, form labels/help text, placeholders, onboarding, empty states, toasts, modals, errors, permission prompts, settings, creation/run flows, collaboration and Agent Team pages, etc.
- Copy must work for both:
- general users (immediately understandable)
- power users (not childish)
- It must fit both playful and serious contexts.
- Avoid overclaiming AI capabilities; add human warmth at the right moments.
---
## 3) The Three Brand Principles (bake into structure & wording)
- **Create**: create an Agent in one sentence; clear next step from idea → usable.
- **Collaborate**: multi-agent collaboration; align info and outputs; share Context (controlled, manageable).
- **Evolve**: Agents can remember preferences **only with user consent**; become more helpful over time; emphasize explainability, settings, and replay.
---
## 4) Writing Rules (actionable)
1. **Clarity first**: short sentences, strong verbs, minimal adjectives. Avoid hype (“revolutionary”, “epic”, “100%”).
2. **Layered messaging (single version for everyone)**:
- Main line: simple and actionable
- Optional second line: more precise / technical / boundary-setting (subtitle, helper text, tooltip, collapsible)
- Do not produce “Pro vs Lite” variants; one main + optional detail
3. **Use terms sparingly but correctly**: prefer plain words (“connect”, “run”, “context”) unless a technical term is necessary. When it is, add a plain-English explanation.
4. **Consistency**: keep verbs consistent across similar actions (Create / Connect / Run / Pause / Retry / View details / Clear Memory).
5. **Actionable**: every message tells the user what to do next. Avoid generic “OK/Cancel”; use specific actions.
6. **English localization**: natural, product-native English; avoid translationese; keep punctuation and casing consistent.
---
## 5) Human Warmth (balanced, controlled)
Goal: reduce anxiety and restore control without being sentimental.
Default ratio: **80% information, 20% warmth**.
Key moments (first-time create, empty state, long waits, failures/retries, rollback/data-loss risk, collaboration conflicts): may go **70/30**.
Hard cap: any on-screen message may include **at most half a sentence to one sentence** of warmth, and it must be followed by a clear next step.
Required order:
1. Acknowledge the situation (no judgment)
2. Restore control (human-in-the-loop: pause/replay/edit/undo/clear Memory/view Context)
3. Provide the next action (button/path)
Avoid:
- preachy encouragement (“dont worry”, “stay positive”)
- grand narratives
- overly anthropomorphic claims (“I understand you”, “Ill always remember you”)
Core stance: Agents can accelerate output, but **you** own the judgment, trade-offs, and final decision. LobeHub gives you time back for what matters.
Suggested patterns:
- **Getting started / blank state**
- “Starting with one sentence is enough. Describe your goal and Ill help you set up the first Agent.”
- “Not sure where to begin? Tell me the outcome—well break it down together.”
- **Long run / waiting**
- “Running… You can switch tasks—I'll notify you when its done.”
- “This may take a few minutes. To speed up: reduce Context / switch model / disable Auto-run.”
- **Failure / retry**
- “That didnt run through. Retry, or view details to fix the cause.”
- “Connection failed: permission not granted or network unstable. Re-authorize in Settings, or try again later.”
- **Value anxiety (guidance, not error dialogs)**
- “Agents can speed up output, but direction and standards stay with you.”
- “Fast results are great—keeping the trail makes the next run steadier.”
- **Collaboration / Agent Teams**
- “Align everyone to the same Context. Every Agent in the Agent Team works from the same page.”
- “Different opinions are fine. Write the goal first, then let Agents propose options and trade-offs.”
---
## 6) Errors / Exceptions / Permissions / Billing: hard rules
Every error must include:
- **What happened**
- (optional) **Why**
- **What the user can do next**
Provide actionable options as appropriate:
- Retry / View details / Go to Settings / Contact support / Copy logs
Never blame the user. Dont show only an error code; put codes in “Details” if needed.
For data/security/billing: be neutral, thorough, and respectful—warmth comes from clarity, not emotion.
---
## 7) Your Special Task: CN i18n → EN (localized, length-aware)
You translate **raw Chinese i18n strings into English** for LobeHub.
Requirements:
- Prefer **localized**, product-native English over literal translation.
- Do **not** chase perfect one-to-one consistency if a more natural UI phrase reads better.
- Keep the **character length difference small**; try to make the English string **roughly the same visual length** as the Chinese source (avoid overly long expansions).
- Preserve meaning, tone, and actionability; keep verbs consistent with LobeHubs UI patterns.
- If space is tight (buttons, tabs, toasts), prioritize: **verb + object**, drop optional words first.
- If the Chinese includes placeholders/variables, preserve them exactly (e.g., `{name}`, `{{count}}`, `%s`) and keep word order sensible.
- Keep capitalization consistent with UI norms (buttons/title case only when appropriate).
Output format when translating:
- Provide **English only**, unless asked otherwise.
- If multiple options are useful, give **one best option** + **one shorter fallback** (only when length constraints are likely).
---
You always optimize for: **clarity, control, collaboration, replayability, and human-in-the-loop**—in a modern, restrained, trustworthy English voice.
+9 -12
View File
@@ -1,12 +1,11 @@
---
description: flex layout components from `@lobehub/ui` usage
globs:
description: react flex layout package `react-layout-kit` usage
globs:
alwaysApply: false
---
# React Layout Kit 使用指南
# Flexbox 布局组件使用指南
`@lobehub/ui` 提供了 `Flexbox` 和 `Center` 组件用于创建弹性布局。以下是重点组件的使用方法:
react-layout-kit 是一个功能丰富的 React flex 布局组件库,在 lobe-chat 项目中被广泛使用。以下是重点组件的使用方法:
## Flexbox 组件
@@ -15,7 +14,7 @@ Flexbox 是最常用的布局组件,用于创建弹性布局,类似于 CSS
### 基本用法
```jsx
import { Flexbox } from '@lobehub/ui';
import { Flexbox } from 'react-layout-kit';
// 默认垂直布局
<Flexbox>
@@ -59,14 +58,14 @@ import { Flexbox } from '@lobehub/ui';
>
<SidebarContent />
</Flexbox>
{/* 中间内容区 */}
<Flexbox flex={1} style={{ height: '100%' }}>
{/* 主要内容 */}
<Flexbox flex={1} padding={24} style={{ overflowY: 'auto' }}>
<MainContent />
</Flexbox>
{/* 底部区域 */}
<Flexbox
style={{
@@ -87,11 +86,9 @@ Center 是对 Flexbox 的封装,使子元素水平和垂直居中。
### 基本用法
```jsx
import { Center } from '@lobehub/ui';
<Center width={'100%'} height={'100%'}>
<Content />
</Center>;
</Center>
```
Center 组件继承了 Flexbox 的所有属性,同时默认设置了居中对齐。主要用于快速创建居中布局。
@@ -119,4 +116,4 @@ Center 组件继承了 Flexbox 的所有属性,同时默认设置了居中对
- 嵌套 Flexbox 创建复杂布局
- 设置 overflow: 'auto' 使内容可滚动
- 使用 horizontal 创建水平布局,默认为垂直布局
- 与 antd-style 的 useTheme hook 配合使用创建主题响应式的布局
- 与 antd-style 的 useTheme hook 配合使用创建主题响应式的布局
+3 -3
View File
@@ -17,20 +17,20 @@ logo emoji: 🤯
## Project Technologies Stack
- Next.js 16
- implement spa inside nextjs with `react-router-dom`
- react 19
- TypeScript
- `@lobehub/ui`, antd for component framework
- antd-style for css-in-js framework
- lucide-react, `@ant-design/icons` for icons
- react-layout-kit for flex layout component
- react-i18next for i18n
- zustand for state management
- nuqs for search params management
- SWR for data fetch
- aHooks for react hooks library
- dayjs for time library
- es-toolkit for utility library
- lodash-es for utility library
- TRPC for type safe backend
- Neon PostgreSQL for backend DB
- PGLite for client DB and Neon PostgreSQL for backend DB
- Drizzle ORM
- Vitest for testing
+37 -33
View File
@@ -25,23 +25,22 @@ lobe-chat/
│ └── zh-CN/
├── packages/
│ ├── agent-runtime/
│ ├── builtin-agents/
│ ├── builtin-tool-*/ # builtin tool packages
│ ├── const/
│ ├── context-engine/
│ ├── conversation-flow/
│ ├── database/
│ │ ── src/
│ │ ├── models/
│ │ ├── schemas/
│ │ └── repositories/
│ ├── desktop-bridge/
│ │ ── src/
│ │ ├── models/
│ │ ├── schemas/
│ │ └── repositories/
│ ├── electron-client-ipc/
│ ├── electron-server-ipc/
│ ├── fetch-sse/
│ ├── file-loaders/
│ ├── memory-user-memory/
│ ├── memory-extract/
│ ├── model-bank/
│ │ └── src/
│ │ └── aiModels/
│ ├── model-runtime/
│ │ └── src/
│ │ ├── core/
@@ -51,6 +50,9 @@ lobe-chat/
│ ├── python-interpreter/
│ ├── ssrf-safe-fetch/
│ ├── types/
│ │ └── src/
│ │ ├── message/
│ │ └── user/
│ ├── utils/
│ └── web-crawler/
├── public/
@@ -59,25 +61,24 @@ lobe-chat/
│ ├── app/
│ │ ├── (backend)/
│ │ │ ├── api/
│ │ │ ├── f/
│ │ │ ├── market/
│ │ │ │ ├── auth/
│ │ │ │ └── webhooks/
│ │ │ ├── middleware/
│ │ │ ├── oidc/
│ │ │ ├── trpc/
│ │ │ └── webapi/
│ │ │ ├── chat/
│ │ │ └── tts/
│ │ ├── [variants]/
│ │ │ ├── (auth)/
│ │ │ ├── (main)/
│ │ │ ├── (mobile)/
│ │ │ ├── onboarding/
│ │ │ └── router/
│ │ └── desktop/
│ │ │ │ ├── chat/
│ │ │ │ └── settings/
│ │ │ └── @modal/
│ │ └── manifest.ts
│ ├── components/
│ ├── config/
│ ├── const/
│ ├── envs/
│ ├── features/
├── helpers/
│ └── ChatInput/
│ ├── hooks/
│ ├── layout/
│ │ ├── AuthProvider/
@@ -89,23 +90,23 @@ lobe-chat/
│ ├── locales/
│ │ └── default/
│ ├── server/
│ │ ├── featureFlags/
│ │ ├── globalConfig/
│ │ ├── modules/
│ │ ├── routers/
│ │ │ ├── async/
│ │ │ ├── lambda/
│ │ │ ├── mobile/
│ │ │ └── tools/
│ │ │ ├── desktop/
│ │ │ ├── edge/
│ │ │ └── lambda/
│ │ └── services/
│ ├── services/
│ │ ├── user/
│ │ │ ├── client.ts
│ │ │ └── server.ts
│ │ └── message/
│ ├── store/
│ │ ├── agent/
│ │ ├── chat/
│ │ └── user/
│ ├── styles/
│ ├── tools/
│ ├── types/
│ └── utils/
└── package.json
```
@@ -115,22 +116,25 @@ lobe-chat/
- UI Components: `src/components`, `src/features`
- Global providers: `src/layout`
- Zustand stores: `src/store`
- Client Services: `src/services/`
- Client Services: `src/services/` cross-platform services
- clientDB: `src/services/<domain>/client.ts`
- serverDB: `src/services/<domain>/server.ts`
- API Routers:
- `src/app/(backend)/webapi` (REST)
- `src/server/routers/{async|lambda|mobile|tools}` (tRPC)
- `src/server/routers/{edge|lambda|async|desktop|tools}` (tRPC)
- Server:
- Services (can access serverDB): `src/server/services`
- Modules (can't access db): `src/server/modules`
- Feature Flags: `src/server/featureFlags`
- Global Config: `src/server/globalConfig`
- Services(can access serverDB): `src/server/services` server-used-only services
- Modules(can't access db): `src/server/modules` (Server only Third-party Service Module)
- Database:
- Schema (Drizzle): `packages/database/src/schemas`
- Model (CRUD): `packages/database/src/models`
- Repository (bff-queries): `packages/database/src/repositories`
- Third-party Integrations: `src/libs` — analytics, oidc etc.
- Builtin Tools: `src/tools`, `packages/builtin-tool-*`
## Data Flow Architecture
React UI → Store Actions → Client Service → TRPC Lambda → Server Services -> DB Model → PostgreSQL (Remote)
- **Web with ClientDB**: React UI → Client Service → Direct Model Access → PGLite (Web WASM)
- **Web with ServerDB**: React UI → Client Service → tRPC Lambda → Server Services → PostgreSQL (Remote)
- **Desktop**:
- Cloud sync disabled: Electron UI → Client Service → tRPC Lambda → Local Server Services → PGLite (Node WASM)
- Cloud sync enabled: Electron UI → Client Service → tRPC Lambda → Cloud Server Services → PostgreSQL (Remote)
+173
View File
@@ -0,0 +1,173 @@
---
description:
globs: *.tsx
alwaysApply: false
---
# react component 编写指南
- 如果要写复杂样式的话用 antd-style ,简单的话可以用 style 属性直接写内联样式
- 如果需要 flex 布局或者居中布局应该使用 react-layout-kit 的 Flexbox 和 Center 组件
- 选择组件时优先顺序应该是 src/components > 安装的组件 package > lobe-ui > antd
- 使用 selector 访问 zustand store 的数据,而不是直接从 store 获取
## antd-style token system
### 访问 token system 的两种方式
#### 使用 antd-style 的 useTheme hook
```tsx
import { useTheme } from 'antd-style';
const MyComponent = () => {
const theme = useTheme();
return (
<div
style={{
color: theme.colorPrimary,
backgroundColor: theme.colorBgContainer,
padding: theme.padding,
borderRadius: theme.borderRadius,
}}
>
使用主题 token 的组件
</div>
);
};
```
#### 使用 antd-style 的 createStyles
```tsx
const useStyles = createStyles(({ css, token }) => {
return {
container: css`
background-color: ${token.colorBgContainer};
border-radius: ${token.borderRadius}px;
padding: ${token.padding}px;
color: ${token.colorText};
`,
title: css`
font-size: ${token.fontSizeLG}px;
font-weight: ${token.fontWeightStrong};
margin-bottom: ${token.marginSM}px;
`,
content: css`
font-size: ${token.fontSize}px;
line-height: ${token.lineHeight};
`,
};
});
const Card: FC<CardProps> = ({ title, content }) => {
const { styles } = useStyles();
return (
<Flexbox className={styles.container}>
<div className={styles.title}>{title}</div>
<div className={styles.content}>{content}</div>
</Flexbox>
);
};
```
### 一些你经常会忘记使用的 token
请注意使用下面的 token 而不是 css 字面值。可以访问 https://ant.design/docs/react/customize-theme-cn 了解所有 token
- 动画类
- token.motionDurationMid
- token.motionEaseInOut
- 包围盒属性
- token.paddingSM
- token.marginLG
## Lobe UI 包含的组件
- 不知道 `@lobehub/ui` 的组件怎么用,有哪些属性,就自己搜下这个项目其它地方怎么用的,不要瞎猜,大部分组件都是在 antd 的基础上扩展了属性
- 具体用法不懂可以联网搜索,例如 ActionIcon 就爬取 https://ui.lobehub.com/components/action-icon
- 可以阅读 `node_modules/@lobehub/ui/es/index.js` 了解有哪些组件,每个组件的属性是什么
- General
- ActionIcon
- ActionIconGroup
- Block
- Button
- DownloadButton
- Icon
- Data Display
- Avatar
- AvatarGroup
- GroupAvatar
- Collapse
- FileTypeIcon
- FluentEmoji
- GuideCard
- Highlighter
- Hotkey
- Image
- List
- Markdown
- SearchResultCards
- MaterialFileTypeIcon
- Mermaid
- Typography
- Text
- Segmented
- Snippet
- SortableList
- Tag
- Tooltip
- Video
- Data Entry
- AutoComplete
- CodeEditor
- ColorSwatches
- CopyButton
- DatePicker
- EditableText
- EmojiPicker
- Form
- FormModal
- HotkeyInput
- ImageSelect
- Input
- SearchBar
- Select
- SliderWithInput
- ThemeSwitch
- Feedback
- Alert
- Drawer
- Modal
- Layout
- DraggablePanel
- DraggablePanelBody
- DraggablePanelContainer
- DraggablePanelFooter
- DraggablePanelHeader
- Footer
- Grid
- Header
- Layout
- LayoutFooter
- LayoutHeader
- LayoutMain
- LayoutSidebar
- LayoutSidebarInner
- LayoutToc
- MaskShadow
- ScrollShadow
- Navigation
- Burger
- Dropdown
- Menu
- SideNav
- Tabs
- Toc
- Theme
- ConfigProvider
- FontLoader
- ThemeProvider
-157
View File
@@ -1,157 +0,0 @@
---
description:
globs: *.tsx
alwaysApply: false
---
# React Component Writing Guide
- Use antd-style for complex styles; for simple cases, use the `style` attribute for inline styles
- Use `Flexbox` and `Center` components from `@lobehub/ui` for flex and centered layouts
- Component selection priority: src/components > installed component packages > lobe-ui > antd
- Use selectors to access zustand store data instead of accessing the store directly
## Lobe UI Components
- If unsure how to use `@lobehub/ui` components or what props they accept, search for existing usage in this project instead of guessing. Most components extend antd components with additional props
- For specific usage, search online. For example, for ActionIcon visit <https://ui.lobehub.com/components/action-icon>
- Read `node_modules/@lobehub/ui/es/index.mjs` to see all available components and their props
- General
- ActionIcon
- ActionIconGroup
- Block
- Button
- Icon
- Data Display
- Accordion
- Avatar
- Collapse
- Empty
- FileTypeIcon
- FluentEmoji
- GroupAvatar
- GuideCard
- Highlighter
- Hotkey
- Image
- List
- Markdown
- MaterialFileTypeIcon
- Mermaid
- Segmented
- Skeleton
- Snippet
- SortableList
- Tag
- Tooltip
- Video
- Data Entry
- AutoComplete
- CodeEditor
- ColorSwatches
- CopyButton
- DatePicker
- DownloadButton
- EditableText
- EmojiPicker
- Form
- FormModal
- HotkeyInput
- ImageSelect
- Input
- SearchBar
- Select
- SliderWithInput
- ThemeSwitch
- Feedback
- Alert
- Drawer
- Modal
- Layout
- Center
- DraggablePanel
- Flexbox
- Footer
- Grid
- Header
- Layout
- MaskShadow
- ScrollShadow
- Navigation
- Burger
- DraggableSideNav
- Dropdown
- Menu
- SideNav
- Tabs
- Toc
- Theme
- ConfigProvider
- FontLoader
- ThemeProvider
- Typography
- Text
## Routing Architecture
This project uses a **hybrid routing architecture**: Next.js App Router for static pages + React Router DOM for the main SPA.
### Route Types
```plaintext
+------------------+--------------------------------+--------------------------------+
| Route Type | Use Case | Implementation |
+------------------+--------------------------------+--------------------------------+
| Next.js App | Auth pages (login, signup, | page.tsx file convention |
| Router | oauth, reset-password, etc.) | src/app/[variants]/(auth)/ |
+------------------+--------------------------------+--------------------------------+
| React Router | Main SPA features | BrowserRouter + Routes |
| DOM | (chat, discover, settings) | desktopRouter.config.tsx |
| | | mobileRouter.config.tsx |
+------------------+--------------------------------+--------------------------------+
```
### Key Files
- Entry point: `src/app/[variants]/page.tsx` - Routes to Desktop or Mobile based on device
- Desktop router: `src/app/[variants]/router/desktopRouter.config.tsx`
- Mobile router: `src/app/[variants]/(mobile)/router/mobileRouter.config.tsx`
- Router utilities: `src/utils/router.tsx`
### Router Utilities
```tsx
import { dynamicElement, redirectElement, ErrorBoundary, RouteConfig } from '@/utils/router';
// Lazy load a page component
element: dynamicElement(() => import('./chat'), 'Desktop > Chat')
// Create a redirect
element: redirectElement('/settings/profile')
// Error boundary for route
errorElement: <ErrorBoundary resetPath="/chat" />
```
### Adding New Routes
1. Add route config to `desktopRouter.config.tsx` or `mobileRouter.config.tsx`
2. Create page component in the corresponding directory under `(main)/`
3. Use `dynamicElement()` for lazy loading
### Navigation
```tsx
// In components - use react-router-dom hooks
import { useNavigate, useParams } from 'react-router-dom';
const navigate = useNavigate();
navigate('/chat');
// From stores - use global navigate
import { useGlobalStore } from '@/store/global';
const navigate = useGlobalStore.getState().navigate;
navigate?.('/settings');
```
+1 -1
View File
@@ -14,7 +14,7 @@ All following rules are saved under `.cursor/rules/` directory:
## Frontend
- `react.mdc` React component style guide and conventions
- `react-component.mdc` React component style guide and conventions
- `i18n.mdc` Internationalization guide using react-i18next
- `typescript.mdc` TypeScript code style guide
- `packages/react-layout-kit.mdc` Usage guide for react-layout-kit
@@ -1,285 +0,0 @@
# Agent Runtime E2E 测试指南
本文档描述 Agent Runtime 端到端测试的核心原则和实施方法。
## 核心原则
### 1. 最小化 Mock 原则
E2E 测试的目标是尽可能接近真实运行环境。因此,我们只 Mock **三个外部依赖**:
| 依赖 | Mock 方式 | 说明 |
| --- | --- | --- |
| **Database** | PGLite | 使用 `@lobechat/database/test-utils` 提供的内存数据库 |
| **Redis** | InMemoryAgentStateManager | Mock `AgentStateManager` 使用内存实现 |
| **Redis** | InMemoryStreamEventManager | Mock `StreamEventManager` 使用内存实现 |
**不 Mock 的部分:**
- `model-bank` - 使用真实的模型配置数据
- `Mecha` (AgentToolsEngine, ContextEngineering) - 使用真实逻辑
- `AgentRuntimeService` - 使用真实逻辑
- `AgentRuntimeCoordinator` - 使用真实逻辑
### 2. 使用 vi.spyOn 而非 vi.mock
不同测试场景需要不同的 LLM 响应。使用 `vi.spyOn` 可以:
- 在每个测试中灵活控制返回值
- 便于测试不同场景(纯文本、tool calls、错误等)
- 避免全局 mock 导致的测试隔离问题
### 3. 默认模型使用 gpt-5
- `model-bank` 中肯定有该模型的数据
- 避免短期内因模型更新需要修改测试
## 技术实现
### 数据库设置
```typescript
import { LobeChatDatabase } from '@lobechat/database';
import { getTestDB } from '@lobechat/database/test-utils';
let testDB: LobeChatDatabase;
beforeEach(async () => {
testDB = await getTestDB();
});
```
### OpenAI Response Mock Helper
创建一个 helper 函数来生成 OpenAI 格式的流式响应:
```typescript
/**
* 创建 OpenAI 格式的流式响应
*/
export const createOpenAIStreamResponse = (options: {
content?: string;
toolCalls?: Array<{
id: string;
name: string;
arguments: string;
}>;
finishReason?: 'stop' | 'tool_calls';
}) => {
const { content, toolCalls, finishReason = 'stop' } = options;
return new Response(
new ReadableStream({
start(controller) {
const encoder = new TextEncoder();
// 发送内容 chunk
if (content) {
const chunk = {
id: 'chatcmpl-mock',
object: 'chat.completion.chunk',
model: 'gpt-5',
choices: [
{
index: 0,
delta: { content },
finish_reason: null,
},
],
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
}
// 发送 tool_calls chunk
if (toolCalls) {
for (const tool of toolCalls) {
const chunk = {
id: 'chatcmpl-mock',
object: 'chat.completion.chunk',
model: 'gpt-5',
choices: [
{
index: 0,
delta: {
tool_calls: [
{
index: 0,
id: tool.id,
type: 'function',
function: {
name: tool.name,
arguments: tool.arguments,
},
},
],
},
finish_reason: null,
},
],
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(chunk)}\n\n`));
}
}
// 发送完成 chunk
const finishChunk = {
id: 'chatcmpl-mock',
object: 'chat.completion.chunk',
model: 'gpt-5',
choices: [
{
index: 0,
delta: {},
finish_reason: finishReason,
},
],
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(finishChunk)}\n\n`));
controller.enqueue(encoder.encode('data: [DONE]\n\n'));
controller.close();
},
}),
{ headers: { 'content-type': 'text/event-stream' } },
);
};
```
### 内存状态管理
使用依赖注入替代 Redis
```typescript
import {
InMemoryAgentStateManager,
InMemoryStreamEventManager,
} from '@/server/modules/AgentRuntime';
import { AgentRuntimeService } from '@/server/services/agentRuntime';
const stateManager = new InMemoryAgentStateManager();
const streamEventManager = new InMemoryStreamEventManager();
const service = new AgentRuntimeService(serverDB, userId, {
coordinatorOptions: {
stateManager,
streamEventManager,
},
queueService: null, // 禁用 QStash 队列,使用 executeSync
streamEventManager,
});
```
### Mock OpenAI API
在测试中使用 `vi.spyOn` mock fetch
```typescript
import { vi } from 'vitest';
// 在测试文件顶部或 beforeEach 中
const fetchSpy = vi.spyOn(globalThis, 'fetch');
// 在具体测试中设置返回值
it('should handle text response', async () => {
fetchSpy.mockResolvedValueOnce(createOpenAIStreamResponse({ content: '杭州今天天气晴朗' }));
// ... 执行测试
});
it('should handle tool calls', async () => {
fetchSpy.mockResolvedValueOnce(
createOpenAIStreamResponse({
toolCalls: [
{
id: 'call_123',
name: 'lobe-web-browsing____search____builtin',
arguments: JSON.stringify({ query: '杭州天气' }),
},
],
finishReason: 'tool_calls',
}),
);
// ... 执行测试
});
```
## 测试场景
### 1. 基本对话测试
```typescript
describe('Basic Chat', () => {
it('should complete a simple conversation', async () => {
fetchSpy.mockResolvedValueOnce(
createOpenAIStreamResponse({ content: 'Hello! How can I help you?' }),
);
const result = await service.createOperation({
agentConfig: { model: 'gpt-5', provider: 'openai' },
initialMessages: [{ role: 'user', content: 'Hi' }],
// ...
});
const finalState = await service.executeSync(result.operationId);
expect(finalState.status).toBe('done');
});
});
```
### 2. Tool 调用测试
```typescript
describe('Tool Calls', () => {
it('should execute web-browsing tool', async () => {
// 第一次调用:LLM 返回 tool_calls
fetchSpy.mockResolvedValueOnce(
createOpenAIStreamResponse({
toolCalls: [
{
id: 'call_123',
name: 'lobe-web-browsing____search____builtin',
arguments: JSON.stringify({ query: '杭州天气' }),
},
],
finishReason: 'tool_calls',
}),
);
// 第二次调用:处理 tool 结果后的响应
fetchSpy.mockResolvedValueOnce(
createOpenAIStreamResponse({ content: '根据搜索结果,杭州今天...' }),
);
// ... 执行测试
});
});
```
### 3. 错误处理测试
```typescript
describe('Error Handling', () => {
it('should handle API errors gracefully', async () => {
fetchSpy.mockRejectedValueOnce(new Error('API rate limit exceeded'));
// ... 执行测试并验证错误处理
});
});
```
## 文件组织
```
src/server/routers/lambda/__tests__/integration/
├── setup.ts # 测试设置工具
├── aiAgent.integration.test.ts # 现有集成测试
├── aiAgent.e2e.test.ts # E2E 测试
└── helpers/
└── openaiMock.ts # OpenAI mock helper
```
## 注意事项
1. **测试隔离**:每个测试后清理 `InMemoryAgentStateManager` 和 `InMemoryStreamEventManager`
2. **超时设置**:E2E 测试可能需要更长的超时时间
3. **调试**:使用 `DEBUG=lobe-server:*` 环境变量查看详细日志
@@ -1,6 +1,6 @@
---
description: Best practices for testing Zustand store actions
globs: 'src/store/**/*.test.ts'
globs: "src/store/**/*.test.ts"
alwaysApply: false
---
@@ -15,7 +15,6 @@ import { act, renderHook } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { messageService } from '@/services/message';
import { useChatStore } from '../../store';
// Keep zustand mock as it's needed globally
@@ -230,7 +229,8 @@ it('should handle topic creation flow', async () => {
const { result } = renderHook(() => useChatStore());
// Spy on action dependencies
const createTopicSpy = vi.spyOn(result.current, 'createTopic').mockResolvedValue('new-topic-id');
const createTopicSpy = vi.spyOn(result.current, 'createTopic')
.mockResolvedValue('new-topic-id');
const toggleLoadingSpy = vi.spyOn(result.current, 'internal_toggleMessageLoading');
// Execute
@@ -251,7 +251,9 @@ When testing streaming responses, simulate the flow properly:
```typescript
it('should handle streaming chunks', async () => {
const { result } = renderHook(() => useChatStore());
const messages = [{ id: 'msg-1', role: 'user', content: 'Hello', sessionId: 'test-session' }];
const messages = [
{ id: 'msg-1', role: 'user', content: 'Hello', sessionId: 'test-session' },
];
const streamSpy = vi
.spyOn(chatService, 'createAssistantMessageStream')
@@ -285,7 +287,9 @@ Always test error scenarios:
it('should handle errors gracefully', async () => {
const { result } = renderHook(() => useChatStore());
vi.spyOn(messageService, 'createMessage').mockRejectedValue(new Error('create message error'));
vi.spyOn(messageService, 'createMessage').mockRejectedValue(
new Error('create message error'),
);
await act(async () => {
try {
@@ -326,7 +330,8 @@ it('should test something', async () => {
it('should call internal methods', async () => {
const { result } = renderHook(() => useChatStore());
const internalMethodSpy = vi.spyOn(result.current, 'internal_method').mockResolvedValue();
const internalMethodSpy = vi.spyOn(result.current, 'internal_method')
.mockResolvedValue();
await act(async () => {
await result.current.publicMethod();
@@ -451,7 +456,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest';
import { discoverService } from '@/services/discover';
import { globalHelpers } from '@/store/global/helpers';
import { useDiscoverStore as useStore } from '../../store';
vi.mock('zustand/traditional');
@@ -482,7 +486,6 @@ describe('SWR Hook Actions', () => {
```
**Key points**:
- **DO NOT mock useSWR** - let it use the real implementation
- Only mock the **service methods** (fetchers)
- Use `waitFor` from `@testing-library/react` to wait for async operations
@@ -556,19 +559,21 @@ it('should not fetch when required parameter is missing', () => {
7. **Type assertions**: Use `as any` for test mock data where type definitions are strict
**Why this matters**:
- The fetcher (service method) is what we're testing - it must be called
- Hardcoding the return value bypasses the actual fetcher logic
- SWR returns Promises in real usage, tests should mirror this behavior
## Benefits of This Approach
✅ **Clear test layers** - Each test only spies on direct dependencies ✅ **Correct mocks** - Mocks match actual implementation ✅ **Better maintainability** - Changes to implementation require fewer test updates ✅ **Improved coverage** - Structured approach ensures all branches are tested ✅ **Reduced coupling** - Tests are independent and can run in any order
✅ **Clear test layers** - Each test only spies on direct dependencies
✅ **Correct mocks** - Mocks match actual implementation
✅ **Better maintainability** - Changes to implementation require fewer test updates
✅ **Improved coverage** - Structured approach ensures all branches are tested
✅ **Reduced coupling** - Tests are independent and can run in any order
## Reference
See example implementation in:
- `src/store/chat/slices/aiChat/actions/__tests__/generateAIChat.test.ts` (Regular actions)
- `src/store/discover/slices/plugin/action.test.ts` (SWR hooks)
- `src/store/discover/slices/mcp/action.test.ts` (SWR hooks)
+4
View File
@@ -16,6 +16,10 @@ alwaysApply: false
- prefer `@ts-expect-error` over `@ts-ignore` over `as any`
- Avoid meaningless null/undefined parameters; design strict function contracts.
## Imports and Modules
- When importing a directory module, prefer the explicit index path like `@/db/index` instead of `@/db`.
## Asynchronous Patterns and Concurrency
- Prefer `async`/`await` over callbacks or chained `.then` promises.
+168 -136
View File
@@ -1,126 +1,137 @@
---
description:
description:
globs: src/store/**
alwaysApply: false
---
# LobeChat Zustand Action 组织模式
# LobeChat Zustand Action Patterns
本文档详细说明了 LobeChat 项目中 Zustand Action 的组织方式、命名规范和实现模式,特别关注乐观更新与后端服务的集成。
## Action Type Hierarchy
## Action 类型分层
LobeChat Actions use a layered architecture with clear separation of responsibilities:
LobeChat Action 采用分层架构,明确区分不同职责:
### 1. Public Actions
Main interfaces exposed for UI component consumption:
- Naming: Verb form (`createTopic`, `sendMessage`, `updateTopicTitle`)
- Responsibilities: Parameter validation, flow orchestration, calling internal actions
- Example: [src/store/chat/slices/topic/action.ts](mdc:src/store/chat/slices/topic/action.ts)
对外暴露的主要接口,供 UI 组件调用:
- 命名:动词形式(`createTopic`, `sendMessage`, `updateTopicTitle`
- 职责:参数验证、流程编排、调用 internal actions
- 示例:[src/store/chat/slices/topic/action.ts](mdc:src/store/chat/slices/topic/action.ts)
```typescript
// Public Action example
// Public Action 示例
createTopic: async () => {
// ...
const { activeId, internal_createTopic } = get();
const messages = chatSelectors.activeBaseChats(get());
if (messages.length === 0) return;
const topicId = await internal_createTopic({
sessionId: activeId,
title: t('defaultTitle', { ns: 'topic' }),
messages: messages.map((m) => m.id),
});
return topicId;
},
```
### 2. Internal Actions (`internal_*`)
Internal implementation details handling core business logic:
- Naming: `internal_` prefix + verb (`internal_createTopic`, `internal_updateMessageContent`)
- Responsibilities: Optimistic updates, service calls, error handling, state synchronization
- Should not be called directly by UI components
内部实现细节,处理核心业务逻辑:
- 命名:`internal_` 前缀 + 动词(`internal_createTopic`, `internal_updateMessageContent`
- 职责:乐观更新、服务调用、错误处理、状态同步
- 不应该被 UI 组件直接调用
```typescript
// Internal Action example - Optimistic update pattern
// Internal Action 示例 - 乐观更新模式
internal_createTopic: async (params) => {
const tmpId = Date.now().toString();
// 1. Immediately update frontend state (optimistic update)
// 1. 立即更新前端状态(乐观更新)
get().internal_dispatchTopic(
{ type: 'addTopic', value: { ...params, id: tmpId } },
'internal_createTopic',
);
get().internal_updateTopicLoading(tmpId, true);
// 2. Call backend service
// 2. 调用后端服务
const topicId = await topicService.createTopic(params);
get().internal_updateTopicLoading(tmpId, false);
// 3. Refresh data to ensure consistency
// 3. 刷新数据确保一致性
get().internal_updateTopicLoading(topicId, true);
await get().refreshTopic();
get().internal_updateTopicLoading(topicId, false);
return topicId;
},
```
### 3. Dispatch Methods (`internal_dispatch*`)
Methods dedicated to handling state updates:
- Naming: `internal_dispatch` + entity name (`internal_dispatchTopic`, `internal_dispatchMessage`)
- Responsibilities: Calling reducers, updating Zustand store, handling state comparison
专门处理状态更新的方法:
- 命名:`internal_dispatch` + 实体名(`internal_dispatchTopic`, `internal_dispatchMessage`
- 职责:调用 reducer、更新 Zustand store、处理状态对比
```typescript
// Dispatch Method example
// Dispatch Method 示例
internal_dispatchTopic: (payload, action) => {
const nextTopics = topicReducer(topicSelectors.currentTopics(get()), payload);
const nextMap = { ...get().topicMaps, [get().activeId]: nextTopics };
if (isEqual(nextMap, get().topicMaps)) return;
set({ topicMaps: nextMap }, false, action ?? n(`dispatchTopic/${payload.type}`));
},
```
## When to Use Reducer Pattern vs. Simple `set`
## 何时使用 Reducer 模式 vs. 简单 `set`
### Use Reducer Pattern When
### 使用 Reducer 模式的场景
Suitable for complex data structure management, especially:
- Managing object lists or maps (e.g., `messagesMap`, `topicMaps`)
- Scenarios requiring optimistic updates
- Complex state transition logic
- Type-safe action payloads needed
适用于复杂的数据结构管理,特别是:
- 管理对象列表或映射(如 `messagesMap`, `topicMaps`
- 需要乐观更新的场景
- 状态转换逻辑复杂
- 需要类型安全的 action payload
```typescript
// Reducer pattern example - Complex message state management
// Reducer 模式示例 - 复杂消息状态管理
export const messagesReducer = (state: ChatMessage[], payload: MessageDispatch): ChatMessage[] => {
switch (payload.type) {
case 'updateMessage': {
return produce(state, (draftState) => {
const index = draftState.findIndex((i) => i.id === payload.id);
if (index < 0) return;
draftState[index] = merge(draftState[index], {
...payload.value,
updatedAt: Date.now(),
draftState[index] = merge(draftState[index], {
...payload.value,
updatedAt: Date.now()
});
});
}
case 'createMessage': {
// ...
return produce(state, (draftState) => {
draftState.push({
...payload.value,
id: payload.id,
createdAt: Date.now(),
updatedAt: Date.now(),
meta: {}
});
});
}
// ...other complex state transitions
// ...其他复杂状态转换
}
};
```
### Use Simple `set` When
### 使用简单 `set` 的场景
Suitable for simple state updates:
- Toggling boolean values
- Updating simple strings/numbers
- Setting single state fields
适用于简单状态更新:
- 切换布尔值
- 更新简单字符串/数字
- 设置单一状态字段
```typescript
// Simple set example
// 简单 set 示例
updateInputMessage: (message) => {
if (isEqual(message, get().inputMessage)) return;
set({ inputMessage: message }, false, n('updateInputMessage'));
@@ -131,45 +142,45 @@ togglePortal: (open?: boolean) => {
},
```
## Optimistic Update Implementation Patterns
## 乐观更新实现模式
Optimistic updates are a core pattern in LobeChat for providing smooth user experience:
乐观更新是 LobeChat 中的核心模式,用于提供流畅的用户体验:
### Standard Optimistic Update Flow
### 标准乐观更新流程
```typescript
// Complete optimistic update example
// 完整的乐观更新示例
internal_updateMessageContent: async (id, content, extra) => {
const { internal_dispatchMessage, refreshMessages } = get();
// 1. Immediately update frontend state (optimistic update)
// 1. 立即更新前端状态(乐观更新)
internal_dispatchMessage({
id,
type: 'updateMessage',
value: { content },
});
// 2. Call backend service
// 2. 调用后端服务
await messageService.updateMessage(id, {
content,
tools: extra?.toolCalls ? internal_transformToolCalls(extra.toolCalls) : undefined,
// ...other fields
// ...其他字段
});
// 3. Refresh to ensure data consistency
// 3. 刷新确保数据一致性
await refreshMessages();
},
```
### Optimistic Update for Create Operations
### 创建操作的乐观更新
```typescript
internal_createMessage: async (message, context) => {
const { internal_createTmpMessage, refreshMessages, internal_toggleMessageLoading } = get();
let tempId = context?.tempMessageId;
if (!tempId) {
// Create temporary message for optimistic update
// 创建临时消息用于乐观更新
tempId = internal_createTmpMessage(message);
internal_toggleMessageLoading(true, tempId);
}
@@ -183,7 +194,7 @@ internal_createMessage: async (message, context) => {
return id;
} catch (e) {
internal_toggleMessageLoading(false, tempId);
// Error handling: update message error state
// 错误处理:更新消息错误状态
internal_dispatchMessage({
id: tempId,
type: 'updateMessage',
@@ -193,77 +204,96 @@ internal_createMessage: async (message, context) => {
},
```
### Delete Operation Pattern (No Optimistic Update)
### 删除操作模式(不使用乐观更新)
Delete operations typically don't suit optimistic updates because:
- Deletion is destructive; error recovery is complex
- Users have lower expectations for immediate feedback on deletions
- Restoring state on deletion failure causes confusion
删除操作通常不适合乐观更新,因为:
- 删除是破坏性操作,错误恢复复杂
- 用户对删除操作的即时反馈期望较低
- 删除失败时恢复原状态会造成困惑
```typescript
// Standard delete operation pattern - No optimistic update
// 删除操作的标准模式 - 无乐观更新
removeGenerationTopic: async (id: string) => {
const { internal_removeGenerationTopic } = get();
await internal_removeGenerationTopic(id);
},
internal_removeGenerationTopic: async (id: string) => {
// 1. Show loading state
// 1. 显示加载状态
get().internal_updateGenerationTopicLoading(id, true);
try {
// 2. Directly call backend service
// 2. 直接调用后端服务
await generationTopicService.deleteTopic(id);
// 3. Refresh data to get latest state
// 3. 刷新数据获取最新状态
await get().refreshGenerationTopics();
} finally {
// 4. Ensure loading state is cleared (whether success or failure)
// 4. 确保清除加载状态(无论成功或失败)
get().internal_updateGenerationTopicLoading(id, false);
}
},
```
Delete operation characteristics:
删除操作的特点:
- 直接调用服务,不预先更新状态
- 依赖 loading 状态提供用户反馈
- 操作完成后刷新整个列表确保一致性
- 使用 `try/finally` 确保 loading 状态总是被清理
- Directly call service without pre-updating state
- Rely on loading state for user feedback
- Refresh entire list after operation to ensure consistency
- Use `try/finally` to ensure loading state is always cleaned up
## 加载状态管理模式
## Loading State Management Pattern
LobeChat 使用统一的加载状态管理模式:
LobeChat uses a unified loading state management pattern:
### Array-based Loading State
### 数组式加载状态
```typescript
// Define in initialState.ts
// initialState.ts 中定义
export interface ChatMessageState {
messageEditingIds: string[]; // Message editing state
messageLoadingIds: string[]; // 消息加载状态
messageEditingIds: string[]; // 消息编辑状态
chatLoadingIds: string[]; // 对话生成状态
}
// Manage in action
{
toggleMessageEditing: (id, editing) => {
set(
{ messageEditingIds: toggleBooleanList(get().messageEditingIds, id, editing) },
false,
'toggleMessageEditing',
);
};
}
// action 中管理
internal_toggleMessageLoading: (loading, id) => {
set({
messageLoadingIds: toggleBooleanList(get().messageLoadingIds, id, loading),
}, false, `internal_toggleMessageLoading/${loading ? 'start' : 'end'}`);
},
```
## SWR Integration Pattern
LobeChat uses SWR for data fetching and cache management:
### Hook-based Data Fetching
### 统一的加载状态工具
```typescript
// Define SWR hook in action.ts
// 通用的加载状态切换工具
internal_toggleLoadingArrays: (key, loading, id, action) => {
const abortControllerKey = `${key}AbortController`;
if (loading) {
const abortController = new AbortController();
set({
[abortControllerKey]: abortController,
[key]: toggleBooleanList(get()[key] as string[], id!, loading),
}, false, action);
return abortController;
} else {
set({
[abortControllerKey]: undefined,
[key]: id ? toggleBooleanList(get()[key] as string[], id, loading) : [],
}, false, action);
}
},
```
## SWR 集成模式
LobeChat 使用 SWR 进行数据获取和缓存管理:
### Hook 式数据获取
```typescript
// 在 action.ts 中定义 SWR hook
useFetchMessages: (enable, sessionId, activeTopicId) =>
useClientDataSWR<ChatMessage[]>(
enable ? [SWR_USE_FETCH_MESSAGES, sessionId, activeTopicId] : null,
@@ -274,55 +304,57 @@ useFetchMessages: (enable, sessionId, activeTopicId) =>
...get().messagesMap,
[messageMapKey(sessionId, activeTopicId)]: messages,
};
if (get().messagesInit && isEqual(nextMap, get().messagesMap)) return;
set({ messagesInit: true, messagesMap: nextMap }, false, n('useFetchMessages'));
},
},
),
```
### Cache Invalidation and Refresh
### 缓存失效和刷新
```typescript
// Standard data refresh pattern
// 刷新数据的标准模式
refreshMessages: async () => {
await mutate([SWR_USE_FETCH_MESSAGES, get().activeId, get().activeTopicId]);
};
},
refreshTopic: async () => {
return mutate([SWR_USE_FETCH_TOPIC, get().activeId]);
},
```
## Naming Convention Summary
## 命名规范总结
### Action Naming Patterns
- Public Actions: Verb form, describing user intent
### Action 命名模式
- Public Actions: 动词形式,描述用户意图
- `createTopic`, `sendMessage`, `regenerateMessage`
- Internal Actions: `internal_` + verb, describing internal operation
- Internal Actions: `internal_` + 动词,描述内部操作
- `internal_createTopic`, `internal_updateMessageContent`
- Dispatch Methods: `internal_dispatch` + entity name
- Dispatch Methods: `internal_dispatch` + 实体名
- `internal_dispatchTopic`, `internal_dispatchMessage`
- Toggle Methods: `internal_toggle` + state name
- Toggle Methods: `internal_toggle` + 状态名
- `internal_toggleMessageLoading`, `internal_toggleChatLoading`
### State Naming Patterns
### 状态命名模式
- ID 数组: `[entity]LoadingIds`, `[entity]EditingIds`
- 映射结构: `[entity]Maps`, `[entity]Map`
- 当前激活: `active[Entity]Id`
- 初始化标记: `[entity]sInit`
- ID arrays: `[entity]LoadingIds`, `[entity]EditingIds`
- Map structures: `[entity]Maps`, `[entity]Map`
- Currently active: `active[Entity]Id`
- Initialization flags: `[entity]sInit`
## 最佳实践
## Best Practices
1. 合理使用乐观更新:
- ✅ 适用:创建、更新操作(用户交互频繁)
- ❌ 避免:删除操作(破坏性操作,错误恢复复杂)
2. 加载状态管理:使用统一的加载状态数组管理并发操作
3. 类型安全:为所有 action payload 定义 TypeScript 接口
4. SWR 集成:使用 SWR 管理数据获取和缓存失效
5. AbortController:为长时间运行的操作提供取消能力
6. 操作模式选择:
- 创建/更新:乐观更新 + 最终一致性
- 删除:加载状态 + 服务调用 + 数据刷新
1. Use optimistic updates appropriately:
- ✅ Suitable: Create, update operations (frequent user interaction)
- ❌ Avoid: Delete operations (destructive, complex error recovery)
2. Loading state management: Use unified loading state arrays to manage concurrent operations
3. Type safety: Define TypeScript interfaces for all action payloads
4. SWR integration: Use SWR to manage data fetching and cache invalidation
5. AbortController: Provide cancellation capability for long-running operations
6. Operation mode selection:
- Create/Update: Optimistic update + eventual consistency
- Delete: Loading state + service call + data refresh
This Action organization pattern ensures code consistency, maintainability, and provides excellent user experience.
这套 Action 组织模式确保了代码的一致性、可维护性,并提供了优秀的用户体验。
+8 -16
View File
@@ -1,9 +1,8 @@
---
description:
description:
globs: src/store/**
alwaysApply: false
---
# LobeChat Zustand Store Slice 组织架构
本文档描述了 LobeChat 项目中 Zustand Store 的模块化 Slice 组织方式,展示如何通过分片架构管理复杂的应用状态。
@@ -70,7 +69,7 @@ export const useChatStore = createWithEqualityFn<ChatStore>()(
每个 slice 位于 `src/store/chat/slices/[sliceName]/` 目录下:
```plaintext
```
src/store/chat/slices/
└── [sliceName]/ # 例如 message, topic, aiChat, builtinTool
├── action.ts # 定义 actions (或者是一个 actions/ 目录)
@@ -160,16 +159,15 @@ export const topicReducer = (state: ChatTopic[] = [], payload: ChatTopicDispatch
// 典型的 selectors.ts 结构
import { ChatStoreState } from '../../initialState';
const currentTopics = (s: ChatStoreState): ChatTopic[] | undefined => s.topicMaps[s.activeId];
const currentTopics = (s: ChatStoreState): ChatTopic[] | undefined =>
s.topicMaps[s.activeId];
const currentActiveTopic = (s: ChatStoreState): ChatTopic | undefined => {
return currentTopics(s)?.find((topic) => topic.id === s.activeTopicId);
};
const getTopicById =
(id: string) =>
(s: ChatStoreState): ChatTopic | undefined =>
currentTopics(s)?.find((topic) => topic.id === id);
const getTopicById = (id: string) => (s: ChatStoreState): ChatTopic | undefined =>
currentTopics(s)?.find((topic) => topic.id === id);
// 核心模式:使用 xxxSelectors 聚合导出
export const topicSelectors = {
@@ -221,15 +219,13 @@ src/store/chat/slices/builtinTool/
## 状态设计模式
### 1. Map 结构用于关联数据
```typescript
// 以 sessionId 为 key,管理多个会话的数据
topicMaps: Record<string, ChatTopic[]>;
messagesMap: Record<string, ChatMessage[]>;
topicMaps: Record<string, ChatTopic[]>
messagesMap: Record<string, ChatMessage[]>
```
### 2. 数组用于加载状态管理
```typescript
// 管理多个并发操作的加载状态
messageLoadingIds: string[]
@@ -238,7 +234,6 @@ chatLoadingIds: string[]
```
### 3. 可选字段用于当前活动项
```typescript
// 当前激活的实体 ID
activeId: string
@@ -249,7 +244,6 @@ activeThreadId?: string
## Slice 集成到顶层 Store
### 1. 状态聚合
```typescript
// 在 initialState.ts 中
export type ChatStoreState = ChatTopicState &
@@ -259,7 +253,6 @@ export type ChatStoreState = ChatTopicState &
```
### 2. Action 接口聚合
```typescript
// 在 store.ts 中
export interface ChatStoreAction
@@ -270,7 +263,6 @@ export interface ChatStoreAction
```
### 3. Selector 统一导出
```typescript
// 在 selectors.ts 中 - 统一聚合 selectors
export { chatSelectors } from './slices/message/selectors';
-1
View File
@@ -1,6 +1,5 @@
const config = require('@lobehub/lint').eslint;
config.root = true;
config.extends.push('plugin:@next/next/recommended');
config.rules['unicorn/no-negated-condition'] = 0;
-30
View File
@@ -1,30 +0,0 @@
name: Setup Node and Bun
description: Setup Node.js and Bun for workflows
inputs:
node-version:
description: Node.js version
required: true
bun-version:
description: Bun version
required: true
package-manager-cache:
description: Pass-through to actions/setup-node package-manager-cache
required: false
default: 'false'
runs:
using: composite
steps:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
package-manager-cache: ${{ inputs.package-manager-cache }}
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ inputs.bun-version }}
@@ -1,27 +0,0 @@
name: Setup Node and pnpm
description: Setup Node.js and pnpm for workflows
inputs:
node-version:
description: Node.js version
required: true
package-manager-cache:
description: Pass-through to actions/setup-node package-manager-cache
required: false
default: 'false'
runs:
using: composite
steps:
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ inputs.node-version }}
package-manager-cache: ${{ inputs.package-manager-cache }}
@@ -1,85 +0,0 @@
name: Desktop Next Build
on:
workflow_dispatch:
push:
branches:
- next
pull_request:
paths:
- 'apps/desktop/**'
- 'scripts/electronWorkflow/**'
- 'package.json'
- 'pnpm-lock.yaml'
- 'bun.lockb'
- 'src/**'
- 'packages/**'
- '.github/workflows/desktop-build-electron.yml'
concurrency:
group: desktop-electron-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
env:
NODE_VERSION: 24.11.1
BUN_VERSION: 1.2.23
jobs:
build-next:
name: Build desktop Next bundle
runs-on: ubuntu-latest
env:
NODE_OPTIONS: --max-old-space-size=6144
UPDATE_CHANNEL: nightly
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID || 'dummy-desktop-project' }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL || 'https://analytics.example.com' }}
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
- name: Enable Corepack
run: corepack enable
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Get pnpm store directory
id: pnpm-store
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ env.NODE_VERSION }}-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-${{ env.NODE_VERSION }}-
${{ runner.os }}-pnpm-store-
- name: Setup bun
uses: oven-sh/setup-bun@v2
with:
bun-version: ${{ env.BUN_VERSION }}
- name: Install dependencies
run: pnpm install --node-linker=hoisted
- name: Install desktop dependencies
run: |
cd apps/desktop
bun run install-isolated
- name: Build desktop Next.js bundle
run: bun run desktop:build-electron
-341
View File
@@ -1,341 +0,0 @@
name: Desktop Manual Build
on:
workflow_dispatch:
inputs:
channel:
description: 'Release channel for desktop build (affects version suffix and workflow:set-desktop-version)'
required: true
default: nightly
type: choice
options:
- nightly
- beta
- stable
build_macos:
description: 'Build macOS artifacts'
required: true
default: true
type: boolean
build_windows:
description: 'Build Windows artifacts'
required: true
default: true
type: boolean
build_linux:
description: 'Build Linux artifacts'
required: true
default: true
type: boolean
version:
description: 'Override desktop version (e.g. 1.2.3). Leave empty to auto-generate.'
required: false
default: ''
concurrency:
group: manual-${{ github.ref }}-${{ github.workflow }}
cancel-in-progress: true
permissions:
contents: read
env:
NODE_VERSION: 24.11.1
BUN_VERSION: 1.2.23
jobs:
test:
name: Code quality check
runs-on: ubuntu-latest
steps:
- name: Checkout base
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
with:
node-version: ${{ env.NODE_VERSION }}
bun-version: ${{ env.BUN_VERSION }}
package-manager-cache: 'false'
- name: Install deps
run: bun i
env:
NODE_OPTIONS: --max-old-space-size=6144
- name: Lint
run: bun run lint
env:
NODE_OPTIONS: --max-old-space-size=6144
version:
name: Determine version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.set_version.outputs.version }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: false
- name: Set version
id: set_version
env:
INPUT_VERSION: ${{ inputs.version }}
CHANNEL: ${{ inputs.channel }}
run: |
base_version=$(node -p "require('./apps/desktop/package.json').version")
if [ -n "$INPUT_VERSION" ]; then
version="$INPUT_VERSION"
echo "📦 Using provided version: ${version} (base: ${base_version})"
else
ci_build_number="${{ github.run_number }}"
version="0.0.0-${CHANNEL}.manual.${ci_build_number}"
echo "📦 Generated version: ${version} (base: ${base_version})"
fi
echo "version=${version}" >> $GITHUB_OUTPUT
- name: Version Summary
run: |
echo "🚦 Release Version: ${{ steps.set_version.outputs.version }}"
build-macos:
needs: [version, test]
name: Build Desktop App (macOS)
if: inputs.build_macos
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, macos-15-intel]
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node & pnpm
uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: 'false'
# node-linker=hoisted 模式将可以确保 asar 压缩可用
- name: Install dependencies
run: pnpm install --node-linker=hoisted
- name: Install deps on Desktop
run: npm run install-isolated --prefix=./apps/desktop
- name: Set package version
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }} ${{ inputs.channel }}
- name: Build artifact on macOS
run: npm run desktop:build
env:
UPDATE_CHANNEL: ${{ inputs.channel }}
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_PROJECT_ID || secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_BASE_URL || secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }}
CSC_FOR_PULL_REQUEST: true
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: Rename macOS latest-mac.yml for multi-architecture support
if: runner.os == 'macOS'
run: |
cd apps/desktop/release
if [ -f "latest-mac.yml" ]; then
SYSTEM_ARCH=$(uname -m)
if [[ "$SYSTEM_ARCH" == "arm64" ]]; then
ARCH_SUFFIX="arm64"
else
ARCH_SUFFIX="x64"
fi
mv latest-mac.yml "latest-mac-${ARCH_SUFFIX}.yml"
echo "✅ Renamed latest-mac.yml to latest-mac-${ARCH_SUFFIX}.yml (detected: $SYSTEM_ARCH)"
ls -la latest-mac-*.yml
else
echo "⚠️ latest-mac.yml not found, skipping rename"
ls -la latest*.yml || echo "No latest*.yml files found"
fi
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: release-${{ matrix.os }}
path: |
apps/desktop/release/latest*
apps/desktop/release/*.dmg*
apps/desktop/release/*.zip*
apps/desktop/release/*.exe*
apps/desktop/release/*.AppImage
apps/desktop/release/*.deb*
apps/desktop/release/*.snap*
apps/desktop/release/*.rpm*
apps/desktop/release/*.tar.gz*
retention-days: 5
build-windows:
needs: [version, test]
name: Build Desktop App (Windows)
if: inputs.build_windows
runs-on: windows-2025
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node & pnpm
uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: 'false'
- name: Install dependencies
run: pnpm install --node-linker=hoisted
- name: Install deps on Desktop
run: npm run install-isolated --prefix=./apps/desktop
- name: Set package version
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }} ${{ inputs.channel }}
- name: Build artifact on Windows
run: npm run desktop:build
env:
UPDATE_CHANNEL: ${{ inputs.channel }}
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_PROJECT_ID || secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_BASE_URL || secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }}
TEMP: C:\temp
TMP: C:\temp
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: release-windows-2025
path: |
apps/desktop/release/latest*
apps/desktop/release/*.dmg*
apps/desktop/release/*.zip*
apps/desktop/release/*.exe*
apps/desktop/release/*.AppImage
apps/desktop/release/*.deb*
apps/desktop/release/*.snap*
apps/desktop/release/*.rpm*
apps/desktop/release/*.tar.gz*
retention-days: 5
build-linux:
needs: [version, test]
name: Build Desktop App (Linux)
if: inputs.build_linux
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Node & pnpm
uses: ./.github/actions/setup-node-pnpm
with:
node-version: ${{ env.NODE_VERSION }}
package-manager-cache: 'false'
- name: Install dependencies
run: pnpm install --node-linker=hoisted
- name: Install deps on Desktop
run: npm run install-isolated --prefix=./apps/desktop
- name: Set package version
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }} ${{ inputs.channel }}
- name: Build artifact on Linux
run: npm run desktop:build
env:
UPDATE_CHANNEL: ${{ inputs.channel }}
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_PROJECT_ID || secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ inputs.channel == 'beta' && secrets.UMAMI_BETA_DESKTOP_BASE_URL || secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }}
- name: Upload artifact
uses: actions/upload-artifact@v5
with:
name: release-ubuntu-latest
path: |
apps/desktop/release/latest*
apps/desktop/release/*.dmg*
apps/desktop/release/*.zip*
apps/desktop/release/*.exe*
apps/desktop/release/*.AppImage
apps/desktop/release/*.deb*
apps/desktop/release/*.snap*
apps/desktop/release/*.rpm*
apps/desktop/release/*.tar.gz*
retention-days: 5
merge-mac-files:
needs: [build-macos, version]
name: Merge macOS Release Files
runs-on: ubuntu-latest
permissions:
contents: read
if: inputs.build_macos
steps:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
with:
node-version: ${{ env.NODE_VERSION }}
bun-version: ${{ env.BUN_VERSION }}
package-manager-cache: 'false'
- name: Download artifacts
uses: actions/download-artifact@v6
with:
path: release
pattern: release-*
merge-multiple: true
- name: List downloaded artifacts
run: ls -R release
- name: Install yaml only for merge step
run: |
cd scripts/electronWorkflow
if [ ! -f package.json ]; then
echo '{"name":"merge-mac-release","private":true}' > package.json
fi
bun add --no-save yaml@2.8.1
- name: Merge latest-mac.yml files
run: bun run scripts/electronWorkflow/mergeMacReleaseFiles.js
- name: Upload artifacts with merged macOS files
uses: actions/upload-artifact@v5
with:
name: merged-release-manual
path: release/
retention-days: 1
+31 -18
View File
@@ -29,12 +29,16 @@ jobs:
with:
fetch-depth: 0
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.11.1
package-manager-cache: false
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.23
package-manager-cache: 'false'
- name: Install deps
run: bun i
@@ -99,11 +103,16 @@ jobs:
with:
fetch-depth: 0
- name: Setup Node & pnpm
uses: ./.github/actions/setup-node-pnpm
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.11.1
package-manager-cache: 'false'
package-manager-cache: false
# node-linker=hoisted 模式将可以确保 asar 压缩可用
- name: Install dependencies
@@ -123,11 +132,11 @@ jobs:
run: npm run desktop:build
env:
# 设置更新通道,PR构建为nightly,否则为stable
UPDATE_CHANNEL: 'nightly'
UPDATE_CHANNEL: "nightly"
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
DATABASE_URL: "postgresql://postgres@localhost:5432/postgres"
# 默认添加一个加密 SECRET
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
KEY_VAULTS_SECRET: "oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE="
# macOS 签名和公证配置(fork 的 PR 访问不到 secrets,会跳过签名)
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
@@ -147,10 +156,10 @@ jobs:
run: npm run desktop:build
env:
# 设置更新通道,PR构建为nightly,否则为stable
UPDATE_CHANNEL: 'nightly'
UPDATE_CHANNEL: "nightly"
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
DATABASE_URL: "postgresql://postgres@localhost:5432/postgres"
KEY_VAULTS_SECRET: "oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE="
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }}
# 将 TEMP 和 TMP 目录设置到 C 盘
@@ -163,10 +172,10 @@ jobs:
run: npm run desktop:build
env:
# 设置更新通道,PR构建为nightly,否则为stable
UPDATE_CHANNEL: 'nightly'
UPDATE_CHANNEL: "nightly"
APP_URL: http://localhost:3015
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
DATABASE_URL: "postgresql://postgres@localhost:5432/postgres"
KEY_VAULTS_SECRET: "oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE="
NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }}
NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }}
@@ -220,12 +229,16 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.11.1
package-manager-cache: false
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.2.23
package-manager-cache: 'false'
# 下载所有平台的构建产物
- name: Download artifacts
+1 -1
View File
@@ -146,7 +146,7 @@ jobs:
NODE_OPTIONS: --max-old-space-size=6144
- name: Typecheck Desktop
run: pnpm type-check
run: pnpm typecheck
working-directory: apps/desktop
- name: Test Desktop Client
+2 -2
View File
@@ -93,6 +93,7 @@ robots.txt
.husky/prepare-commit-msg
# Documents and media
*.patch
*.pdf
# Cloud service keys
@@ -113,6 +114,5 @@ CLAUDE.local.md
*.ppt*
*.doc*
*.xls*
e2e/reports
out
i18n-unused-keys-report.json
+2 -3
View File
@@ -26,7 +26,6 @@ The project follows a well-organized monorepo structure:
- `src/` - Main source code
- `docs/` - Documentation
- `.cursor/rules/` - Development rules and guidelines
- PR titles starting with `✨ feat/` or `🐛 fix` will trigger the release workflow upon merge. Only use these prefixes for significant user-facing feature changes or bug fixes
## Development Workflow
@@ -84,10 +83,10 @@ All following rules are saved under `.cursor/rules/` directory:
### Frontend
- `react.mdc` React component style guide and conventions
- `react-component.mdc` React component style guide and conventions
- `i18n.mdc` Internationalization guide using react-i18next
- `typescript.mdc` TypeScript code style guide
- `packages/react-layout-kit.mdc` Usage guide for Flexbox and Center components from @lobehub/ui
- `packages/react-layout-kit.mdc` Usage guide for react-layout-kit
### State Management
-336
View File
@@ -2,342 +2,6 @@
# Changelog
## [Version 2.0.0-next.176](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.175...v2.0.0-next.176)
<sup>Released on **2025-12-23**</sup>
#### ✨ Features
- **misc**: Mobile native better auth support.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's improved
- **misc**: Mobile native better auth support, closes [#10871](https://github.com/lobehub/lobe-chat/issues/10871) ([8c42a93](https://github.com/lobehub/lobe-chat/commit/8c42a93))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.175](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.174...v2.0.0-next.175)
<sup>Released on **2025-12-21**</sup>
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.174](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.173...v2.0.0-next.174)
<sup>Released on **2025-12-20**</sup>
#### ♻ Code Refactoring
- **misc**: Refactor database schema.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Code refactoring
- **misc**: Refactor database schema, closes [#10860](https://github.com/lobehub/lobe-chat/issues/10860) ([5c489bc](https://github.com/lobehub/lobe-chat/commit/5c489bc))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.173](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.172...v2.0.0-next.173)
<sup>Released on **2025-12-16**</sup>
#### 🐛 Bug Fixes
- **misc**: Request to gpt5 series should not with `top_p`, temperature when reasoning effort is not none.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Request to gpt5 series should not with `top_p`, temperature when reasoning effort is not none, closes [#10800](https://github.com/lobehub/lobe-chat/issues/10800) ([b4ad470](https://github.com/lobehub/lobe-chat/commit/b4ad470))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.172](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.171...v2.0.0-next.172)
<sup>Released on **2025-12-15**</sup>
#### 💄 Styles
- **misc**: Update i18n.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Styles
- **misc**: Update i18n, closes [#10759](https://github.com/lobehub/lobe-chat/issues/10759) ([24cae77](https://github.com/lobehub/lobe-chat/commit/24cae77))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.171](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.170...v2.0.0-next.171)
<sup>Released on **2025-12-14**</sup>
#### 💄 Styles
- **misc**: Update GPT-5.2 models.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Styles
- **misc**: Update GPT-5.2 models, closes [#10749](https://github.com/lobehub/lobe-chat/issues/10749) ([0446127](https://github.com/lobehub/lobe-chat/commit/0446127))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.170](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.169...v2.0.0-next.170)
<sup>Released on **2025-12-12**</sup>
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.169](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.168...v2.0.0-next.169)
<sup>Released on **2025-12-12**</sup>
#### 🐛 Bug Fixes
- **misc**: Fix CVE errors.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Fix CVE errors, closes [#10748](https://github.com/lobehub/lobe-chat/issues/10748) ([6591f3c](https://github.com/lobehub/lobe-chat/commit/6591f3c))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.168](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.167...v2.0.0-next.168)
<sup>Released on **2025-12-12**</sup>
#### 🐛 Bug Fixes
- **misc**: Slove market oidc error.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Slove market oidc error, closes [#10715](https://github.com/lobehub/lobe-chat/issues/10715) ([108d2a7](https://github.com/lobehub/lobe-chat/commit/108d2a7))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.167](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.166...v2.0.0-next.167)
<sup>Released on **2025-12-11**</sup>
#### ✨ Features
- **misc**: Add Replicate image provider.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's improved
- **misc**: Add Replicate image provider ([542f4d9](https://github.com/lobehub/lobe-chat/commit/542f4d9))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.166](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.165...v2.0.0-next.166)
<sup>Released on **2025-12-09**</sup>
#### 🐛 Bug Fixes
- **Dockerfile**: Electron main typing pkg.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **Dockerfile**: Electron main typing pkg, closes [#10693](https://github.com/lobehub/lobe-chat/issues/10693) ([f3357b0](https://github.com/lobehub/lobe-chat/commit/f3357b0))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.165](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.164...v2.0.0-next.165)
<sup>Released on **2025-12-09**</sup>
#### ♻ Code Refactoring
- **electron-main**: Client ipc decorate.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Code refactoring
- **electron-main**: Client ipc decorate, closes [#10679](https://github.com/lobehub/lobe-chat/issues/10679) ([f74befa](https://github.com/lobehub/lobe-chat/commit/f74befa))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.164](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.163...v2.0.0-next.164)
<sup>Released on **2025-12-08**</sup>
#### 💄 Styles
- **profile**: Add mobile responsive layout and signup improvements.
- **misc**: Update link handling in PlanTag component to use react-router-dom.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Styles
- **profile**: Add mobile responsive layout and signup improvements, closes [#10669](https://github.com/lobehub/lobe-chat/issues/10669) ([1afd471](https://github.com/lobehub/lobe-chat/commit/1afd471))
- **misc**: Update link handling in PlanTag component to use react-router-dom, closes [#10673](https://github.com/lobehub/lobe-chat/issues/10673) ([3aceeb6](https://github.com/lobehub/lobe-chat/commit/3aceeb6))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.163](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.162...v2.0.0-next.163)
<sup>Released on **2025-12-06**</sup>
#### 🐛 Bug Fixes
- **misc**: Add smooth scroll to top on 'More' button click in Title component.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Add smooth scroll to top on 'More' button click in Title component, closes [#10178](https://github.com/lobehub/lobe-chat/issues/10178) ([5ad4f0c](https://github.com/lobehub/lobe-chat/commit/5ad4f0c))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 2.0.0-next.162](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.161...v2.0.0-next.162)
<sup>Released on **2025-12-05**</sup>
+2 -5
View File
@@ -17,9 +17,8 @@ read @.cursor/rules/project-structure.mdc
- The current release branch is `next` instead of `main` until v2.0.0 is officially released
- use rebase for git pull
- git commit message should prefix with gitmoji
- git branch name format template: <type>/<feature-name>
- git branch name format example: tj/feat/feature-name
- use .github/PULL_REQUEST_TEMPLATE.md to generate pull request description
- PR titles starting with `✨ feat/` or `🐛 fix` will trigger the release workflow upon merge. Only use these prefixes for significant user-facing feature changes or bug fixes
### Package Management
@@ -45,8 +44,6 @@ see @.cursor/rules/typescript.mdc
- wrap the file path in single quotes to avoid shell expansion
- Never run `bun run test` etc to run tests, this will run all tests and cost about 10mins
- If trying to fix the same test twice, but still failed, stop and ask for help.
- **Prefer `vi.spyOn` over `vi.mock`**: When mocking modules or functions, prefer using `vi.spyOn` to mock specific functions rather than `vi.mock` to mock entire modules. This approach is more targeted, easier to maintain, and allows for better control over mock behavior in individual tests.
- **Tests must pass type check**: After writing or modifying tests, run `bun run type-check` to ensure there are no type errors. Tests should pass both runtime execution and TypeScript type checking.
### Typecheck
@@ -58,7 +55,7 @@ see @.cursor/rules/typescript.mdc
- **Dev**: Translate `locales/zh-CN/namespace.json` and `locales/en-US/namespace.json` locales file only for dev preview
- DON'T run `pnpm i18n`, let CI auto handle it
## Linear Issue Management (ignore if not installed linear mcp)
## Linear Issue Management
When working with Linear issues:
+51 -58
View File
@@ -8,24 +8,29 @@ ARG USE_CN_MIRROR
ENV DEBIAN_FRONTEND="noninteractive"
RUN <<'EOF'
set -e
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"
fi
apt update
apt install ca-certificates proxychains-ng -qy
mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib
cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4
cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2
cp /usr/bin/proxychains4 /distroless/bin/proxychains
cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf
cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6
cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1
cp /usr/local/bin/node /distroless/bin/node
cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt
rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
EOF
RUN \
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
sed -i "s/deb.debian.org/mirrors.ustc.edu.cn/g" "/etc/apt/sources.list.d/debian.sources"; \
fi \
# Add required package
&& apt update \
&& apt install ca-certificates proxychains-ng -qy \
# Prepare required package to distroless
&& mkdir -p /distroless/bin /distroless/etc /distroless/etc/ssl/certs /distroless/lib \
# Copy proxychains to distroless
&& cp /usr/lib/$(arch)-linux-gnu/libproxychains.so.4 /distroless/lib/libproxychains.so.4 \
&& cp /usr/lib/$(arch)-linux-gnu/libdl.so.2 /distroless/lib/libdl.so.2 \
&& cp /usr/bin/proxychains4 /distroless/bin/proxychains \
&& cp /etc/proxychains4.conf /distroless/etc/proxychains4.conf \
# Copy node to distroless
&& cp /usr/lib/$(arch)-linux-gnu/libstdc++.so.6 /distroless/lib/libstdc++.so.6 \
&& cp /usr/lib/$(arch)-linux-gnu/libgcc_s.so.1 /distroless/lib/libgcc_s.so.1 \
&& cp /usr/local/bin/node /distroless/bin/node \
# Copy CA certificates to distroless
&& cp /etc/ssl/certs/ca-certificates.crt /distroless/etc/ssl/certs/ca-certificates.crt \
# Cleanup temp files
&& rm -rf /tmp/* /var/lib/apt/lists/* /var/tmp/*
## Builder image, install all the dependencies and build the app
FROM base AS builder
@@ -81,45 +86,35 @@ WORKDIR /app
COPY package.json pnpm-workspace.yaml ./
COPY .npmrc ./
COPY packages ./packages
# bring in desktop workspace manifest so pnpm can resolve it
COPY apps/desktop/src/main/package.json ./apps/desktop/src/main/package.json
RUN <<'EOF'
set -e
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"
npm config set registry "https://registry.npmmirror.com/"
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc
fi
export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//')
npm i -g corepack@latest
corepack enable
corepack use $(sed -n 's/.*"packageManager": "\(.*\)".*/\1/p' package.json)
pnpm i
mkdir -p /deps
cd /deps
pnpm init
pnpm add pg drizzle-orm
EOF
RUN \
# If you want to build docker in China, build with --build-arg USE_CN_MIRROR=true
if [ "${USE_CN_MIRROR:-false}" = "true" ]; then \
export SENTRYCLI_CDNURL="https://npmmirror.com/mirrors/sentry-cli"; \
npm config set registry "https://registry.npmmirror.com/"; \
echo 'canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas' >> .npmrc; \
fi \
# Set the registry for corepack
&& export COREPACK_NPM_REGISTRY=$(npm config get registry | sed 's/\/$//') \
# Update corepack to latest (nodejs/corepack#612)
&& npm i -g corepack@latest \
# Enable corepack
&& corepack enable \
# Use pnpm for corepack
&& corepack use $(sed -n 's/.*"packageManager": "\(.*\)".*/\1/p' package.json) \
# Install the dependencies
&& pnpm i \
# Add db migration dependencies
&& mkdir -p /deps \
&& cd /deps \
&& pnpm init \
&& pnpm add pg drizzle-orm
COPY . .
# run build standalone for docker version
RUN npm run build:docker
# Prepare desktop export assets for Electron packaging (if generated)
RUN <<'EOF'
set -e
if [ -d "/app/out" ]; then
mkdir -p /app/apps/desktop/dist/next
cp -a /app/out/. /app/apps/desktop/dist/next/
echo "✅ Copied Next export output into /app/apps/desktop/dist/next"
else
echo "️ No Next export output found at /app/out, creating empty directory"
mkdir -p /app/apps/desktop/dist/next
fi
EOF
## Application image, copy all the files for production
FROM busybox:latest AS app
@@ -128,8 +123,6 @@ COPY --from=base /distroless/ /
# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder /app/.next/standalone /app/
# Copy Next export output for desktop renderer
COPY --from=builder /app/apps/desktop/dist/next /app/apps/desktop/dist/next
# Copy database migrations
COPY --from=builder /app/packages/database/migrations /app/migrations
@@ -144,12 +137,12 @@ COPY --from=builder /deps/node_modules/drizzle-orm /app/node_modules/drizzle-orm
# Copy server launcher
COPY --from=builder /app/scripts/serverLauncher/startServer.js /app/startServer.js
RUN <<'EOF'
set -e
addgroup -S -g 1001 nodejs
adduser -D -G nodejs -H -S -h /app -u 1001 nextjs
chown -R nextjs:nodejs /app /etc/proxychains4.conf
EOF
RUN \
# Add nextjs:nodejs to run the app
addgroup -S -g 1001 nodejs \
&& adduser -D -G nodejs -H -S -h /app -u 1001 nextjs \
# Set permission for nextjs:nodejs
&& chown -R nextjs:nodejs /app /etc/proxychains4.conf
## Production image, copy all the files and run next
FROM scratch
+1 -2
View File
@@ -16,9 +16,8 @@ read @.cursor/rules/project-structure.mdc
- use rebase for git pull
- git commit message should prefix with gitmoji
- git branch name format template: <type>/<feature-name>
- git branch name format example: tj/feat/feature-name
- use .github/PULL_REQUEST_TEMPLATE.md to generate pull request description
- PR titles starting with `✨ feat/` or `🐛 fix` will trigger the release workflow upon merge. Only use these prefixes for significant user-facing feature changes or bug fixes
### Package Management
+10 -10
View File
@@ -345,14 +345,14 @@ In addition, these plugins are not limited to news aggregation, but can also ext
<!-- PLUGIN LIST -->
| Recent Submits | Description |
| -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| [Shopping tools](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-12-17**</sup> | Search for products on eBay & AliExpress, find eBay events & coupons. Get prompt examples.<br/>`shopping` `e-bay` `ali-express` `coupons` |
| [SEO Assistant](https://lobechat.com/discover/plugin/seo_assistant)<br/><sup>By **webfx** on **2025-12-17**</sup> | The SEO Assistant can generate search engine keyword information in order to aid the creation of content.<br/>`seo` `keyword` |
| [Video Captions](https://lobechat.com/discover/plugin/VideoCaptions)<br/><sup>By **maila** on **2025-12-13**</sup> | Convert Youtube links into transcribed text, enable asking questions, create chapters, and summarize its content.<br/>`video-to-text` `youtube` |
| [WeatherGPT](https://lobechat.com/discover/plugin/WeatherGPT)<br/><sup>By **steven-tey** on **2025-12-13**</sup> | Get current weather information for a specific location.<br/>`weather` |
| Recent Submits | Description |
| -------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-11-28**</sup> | Analyze stocks and get comprehensive real-time investment data and analytics.<br/>`stock` |
| [SEO](https://lobechat.com/discover/plugin/SEO)<br/><sup>By **orrenprunckun** on **2025-11-14**</sup> | Enter any URL and keyword and get an On-Page SEO analysis & insights!<br/>`seo` |
| [Shopping tools](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-10-27**</sup> | Search for products on eBay & AliExpress, find eBay events & coupons. Get prompt examples.<br/>`shopping` `e-bay` `ali-express` `coupons` |
| [Web](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | Smart web search that reads and analyzes pages to deliver comprehensive answers from Google results.<br/>`web` `search` |
> 📊 Total plugins: [<kbd>**40**</kbd>](https://lobechat.com/discover/plugins)
> 📊 Total plugins: [<kbd>**41**</kbd>](https://lobechat.com/discover/plugins)
<!-- PLUGIN LIST -->
@@ -387,8 +387,8 @@ Our marketplace is not just a showcase platform but also a collaborative space.
| Recent Submits | Description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Turtle Soup Host](https://lobechat.com/discover/assistant/lateral-thinking-puzzle)<br/><sup>By **[CSY2022](https://github.com/CSY2022)** on **2025-06-19**</sup> | A turtle soup host needs to provide the scenario, the complete story (truth of the event), and the key point (the condition for guessing correctly).<br/>`turtle-soup` `reasoning` `interaction` `puzzle` `role-playing` |
| [Academic Writing Assistant](https://lobechat.com/discover/assistant/academic-writing-assistant)<br/><sup>By **[swarfte](https://github.com/swarfte)** on **2025-06-17**</sup> | Expert in academic research paper writing and formal documentation<br/>`academic-writing` `research` `formal-style` |
| [Gourmet Reviewer🍟](https://lobechat.com/discover/assistant/food-reviewer)<br/><sup>By **[renhai-lab](https://github.com/renhai-lab)** on **2025-06-17**</sup> | Food critique expert<br/>`gourmet` `review` `writing` |
| [Academic Writing Assistant](https://lobechat.com/discover/assistant/academic-writing-assistant)<br/><sup>By **[swarfte](https://github.com/swarfte)** on **2025-06-17**</sup> | Expert in academic research paper writing and formal documentation<br/>`academic-writing` `research` `formal-style` |
| [Minecraft Senior Developer](https://lobechat.com/discover/assistant/java-development)<br/><sup>By **[iamyuuk](https://github.com/iamyuuk)** on **2025-06-17**</sup> | Expert in advanced Java development and Minecraft mod and server plugin development<br/>`development` `programming` `minecraft` `java` |
> 📊 Total agents: [<kbd>**505**</kbd> ](https://lobechat.com/discover/assistants)
@@ -820,7 +820,7 @@ This project is [LobeHub Community License](./LICENSE) licensed.
[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat-database
[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat-database?color=369eff&labelColor=black&style=flat-square&sort=semver
[docs]: https://lobehub.com/docs/usage/start
[docs-dev-guide]: https://lobehub.com/docs/development/start
[docs-dev-guide]: https://github.com/lobehub/lobe-chat/wiki/index
[docs-docker]: https://lobehub.com/docs/self-hosting/server-database/docker-compose
[docs-env-var]: https://lobehub.com/docs/self-hosting/environment-variables
[docs-feat-agent]: https://lobehub.com/docs/usage/features/agent-market
@@ -840,7 +840,7 @@ This project is [LobeHub Community License](./LICENSE) licensed.
[docs-feat-tts]: https://lobehub.com/docs/usage/features/tts
[docs-feat-vision]: https://lobehub.com/docs/usage/features/vision
[docs-function-call]: https://lobehub.com/blog/openai-function-call
[docs-lighthouse]: https://lobehub.com/docs/development/others/lighthouse
[docs-lighthouse]: https://github.com/lobehub/lobe-chat/wiki/Lighthouse
[docs-plugin-dev]: https://lobehub.com/docs/usage/plugins/development
[docs-self-hosting]: https://lobehub.com/docs/self-hosting/start
[docs-upstream-sync]: https://lobehub.com/docs/self-hosting/advanced/upstream-sync
+13 -13
View File
@@ -12,7 +12,7 @@
<h1>Lobe Chat</h1>
现代化设计的开源 ChatGPT/LLMs 聊天应用与开发框架<br/>
支持语音合成、多模态、可扩展的([function call][docs-function-call])插件系统<br/>
支持语音合成、多模态、可扩展的([function call][docs-functionc-call])插件系统<br/>
一键**免费**拥有你自己的 ChatGPT/Gemini/Claude/Ollama 应用
[English](./README.md) · **简体中文** · [官网][official-site] · [更新日志][changelog] · [文档][docs] · [博客][blog] · [反馈问题][github-issues-link]
@@ -338,14 +338,14 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
<!-- PLUGIN LIST -->
| 最近新增 | 描述 |
| -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| [购物工具](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-12-17**</sup> | 在 eBay 和 AliExpress 上搜索产品,查找 eBay 活动和优惠券。获取快速示例。<br/>`购物` `e-bay` `ali-express` `优惠券` |
| [SEO 助手](https://lobechat.com/discover/plugin/seo_assistant)<br/><sup>By **webfx** on **2025-12-17**</sup> | SEO 助手可以生成搜索引擎关键词信息,以帮助创建内容。<br/>`seo` `关键词` |
| [视频字幕](https://lobechat.com/discover/plugin/VideoCaptions)<br/><sup>By **maila** on **2025-12-13**</sup> | 将 Youtube 链接转换为转录文本,使其能够提问,创建章节,并总结其内容。<br/>`视频转文字` `you-tube` |
| [天气 GPT](https://lobechat.com/discover/plugin/WeatherGPT)<br/><sup>By **steven-tey** on **2025-12-13**</sup> | 获取特定位置的当前天气信息。<br/>`天气` |
| 最近新增 | 描述 |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| [PortfolioMeta](https://lobechat.com/discover/plugin/StockData)<br/><sup>By **portfoliometa** on **2025-11-28**</sup> | 分析股票并获取全面的实时投资数据和分析。<br/>`股票` |
| [SEO](https://lobechat.com/discover/plugin/SEO)<br/><sup>By **orrenprunckun** on **2025-11-14**</sup> | 输入任何 URL 和关键词,获取页面 SEO 分析和见解!<br/>`seo` |
| [购物工具](https://lobechat.com/discover/plugin/ShoppingTools)<br/><sup>By **shoppingtools** on **2025-10-27**</sup> | 在 eBay 和 AliExpress 上搜索产品,查找 eBay 活动和优惠券。获取快速示例。<br/>`购物` `e-bay` `ali-express` `优惠券` |
| [网页](https://lobechat.com/discover/plugin/web)<br/><sup>By **Proghit** on **2025-01-24**</sup> | 智能网页搜索,读取和分析页面,以提供来自 Google 结果的全面答案。<br/>`网页` `搜索` |
> 📊 Total plugins: [<kbd>**40**</kbd>](https://lobechat.com/discover/plugins)
> 📊 Total plugins: [<kbd>**41**</kbd>](https://lobechat.com/discover/plugins)
<!-- PLUGIN LIST -->
@@ -376,8 +376,8 @@ LobeChat 的插件生态系统是其核心功能的重要扩展,它极大地
| 最近新增 | 描述 |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [海龟汤主持人](https://lobechat.com/discover/assistant/lateral-thinking-puzzle)<br/><sup>By **[CSY2022](https://github.com/CSY2022)** on **2025-06-19**</sup> | 一个海龟汤主持人,需要自己提供汤面,汤底与关键点(猜中的判定条件)。<br/>`海龟汤` `推理` `互动` `谜题` `角色扮演` |
| [学术写作助手](https://lobechat.com/discover/assistant/academic-writing-assistant)<br/><sup>By **[swarfte](https://github.com/swarfte)** on **2025-06-17**</sup> | 专业的学术研究论文写作和正式文档编写专家<br/>`学术写作` `研究` `正式风格` |
| [美食评论员🍟](https://lobechat.com/discover/assistant/food-reviewer)<br/><sup>By **[renhai-lab](https://github.com/renhai-lab)** on **2025-06-17**</sup> | 美食评价专家<br/>`美食` `评价` `写作` |
| [学术写作助手](https://lobechat.com/discover/assistant/academic-writing-assistant)<br/><sup>By **[swarfte](https://github.com/swarfte)** on **2025-06-17**</sup> | 专业的学术研究论文写作和正式文档编写专家<br/>`学术写作` `研究` `正式风格` |
| [Minecraft 资深开发者](https://lobechat.com/discover/assistant/java-development)<br/><sup>By **[iamyuuk](https://github.com/iamyuuk)** on **2025-06-17**</sup> | 擅长高级 Java 开发及 Minecraft 开发<br/>`开发` `编程` `minecraft` `java` |
> 📊 Total agents: [<kbd>**505**</kbd> ](https://lobechat.com/discover/assistants)
@@ -667,7 +667,7 @@ API Key 是使用 LobeChat 进行大语言模型会话的必要信息,本节
## 🧩 插件体系
插件提供了扩展 LobeChat [Function Calling][docs-function-call] 能力的方法。可以用于引入新的 Function Calling,甚至是新的消息结果渲染方式。如果你对插件开发感兴趣,请在 Wiki 中查阅我们的 [📘 插件开发指引][docs-plugin-dev] 。
插件提供了扩展 LobeChat [Function Calling][docs-functionc-call] 能力的方法。可以用于引入新的 Function Calling,甚至是新的消息结果渲染方式。如果你对插件开发感兴趣,请在 Wiki 中查阅我们的 [📘 插件开发指引][docs-plugin-dev] 。
- [lobe-chat-plugins][lobe-chat-plugins]:插件索引从该仓库的 index.json 中获取插件列表并显示给用户。
- [chat-plugin-template][chat-plugin-template]:插件开发模版,你可以通过项目模版快速新建插件项目。
@@ -839,7 +839,7 @@ This project is [LobeHub Community License](./LICENSE) licensed.
[docker-size-link]: https://hub.docker.com/r/lobehub/lobe-chat-database
[docker-size-shield]: https://img.shields.io/docker/image-size/lobehub/lobe-chat-database?color=369eff&labelColor=black&style=flat-square&sort=semver
[docs]: https://lobehub.com/zh/docs/usage/start
[docs-dev-guide]: https://lobehub.com/docs/development/start
[docs-dev-guide]: https://github.com/lobehub/lobe-chat/wiki/index
[docs-docker]: https://lobehub.com/zh/docs/self-hosting/server-database/docker-compose
[docs-env-var]: https://lobehub.com/docs/self-hosting/environment-variables
[docs-feat-agent]: https://lobehub.com/docs/usage/features/agent-market
@@ -858,8 +858,8 @@ This project is [LobeHub Community License](./LICENSE) licensed.
[docs-feat-theme]: https://lobehub.com/docs/usage/features/theme
[docs-feat-tts]: https://lobehub.com/docs/usage/features/tts
[docs-feat-vision]: https://lobehub.com/docs/usage/features/vision
[docs-function-call]: https://lobehub.com/zh/blog/openai-function-call
[docs-lighthouse]: https://lobehub.com/docs/development/others/lighthouse
[docs-functionc-call]: https://lobehub.com/zh/blog/openai-function-call
[docs-lighthouse]: https://github.com/lobehub/lobe-chat/wiki/Lighthouse.zh-CN
[docs-plugin-dev]: https://lobehub.com/docs/usage/plugins/development
[docs-self-hosting]: https://lobehub.com/docs/self-hosting/start
[docs-upstream-sync]: https://lobehub.com/docs/self-hosting/advanced/upstream-sync
+1 -1
View File
@@ -8,7 +8,7 @@ module.exports = defineConfig({
'ar',
'bg-BG',
'zh-TW',
'en',
'en-US',
'ru-RU',
'ja-JP',
'ko-KR',
-16
View File
@@ -4,19 +4,3 @@ ignore-workspace-root-check=true
electron_mirror=https://npmmirror.com/mirrors/electron/
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
public-hoist-pattern[]=*@umijs/lint*
public-hoist-pattern[]=*unicorn*
public-hoist-pattern[]=*changelog*
public-hoist-pattern[]=*commitlint*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*postcss*
public-hoist-pattern[]=*prettier*
public-hoist-pattern[]=*remark*
public-hoist-pattern[]=*semantic-release*
public-hoist-pattern[]=*stylelint*
public-hoist-pattern[]=@auth/core
public-hoist-pattern[]=@clerk/backend
public-hoist-pattern[]=@clerk/types
public-hoist-pattern[]=pdfjs-dist
-62
View File
@@ -1,62 +0,0 @@
# Prettierignore for LobeHub
################################################################
# general
.DS_Store
.editorconfig
.idea
.history
.temp
.env.local
.husky
.npmrc
.gitkeep
venv
temp
tmp
LICENSE
# dependencies
node_modules
*.log
*.lock
package-lock.json
# ci
coverage
.coverage
.eslintcache
.stylelintcache
test-output
__snapshots__
*.snap
# production
dist
es
lib
logs
# umi
.umi
.umi-production
.umi-test
.dumi/tmp*
# ignore files
.*ignore
# docker
docker
Dockerfile*
# image
*.webp
*.gif
*.png
*.jpg
*.svg
# misc
# add other ignore file below
.next
-1
View File
@@ -1 +0,0 @@
module.exports = require('@lobehub/lint').prettier;
-1
View File
@@ -1 +0,0 @@
module.exports = require('@lobehub/lint').remarklint;
-39
View File
@@ -1,39 +0,0 @@
# Stylelintignore for LobeHub
################################################################
# dependencies
node_modules
# ci
coverage
.coverage
# production
dist
es
lib
logs
# framework specific
.next
.umi
.umi-production
.umi-test
.dumi/tmp*
# temporary directories
tmp
temp
.temp
.local
docs/.local
# cache directories
.cache
# AI coding tools directories
.claude
.serena
# MCP tools
/.serena/**
-9
View File
@@ -1,9 +0,0 @@
const config = require('@lobehub/lint').stylelint;
module.exports = {
...config,
rules: {
'selector-id-pattern': null,
...config.rules,
},
};
+42 -38
View File
@@ -156,26 +156,24 @@ apps/desktop/src/main/
- 事件广播:向渲染进程通知授权状态变化
```typescript
import { ControllerModule, IpcMethod } from '@/controllers';
// 认证流程示例
@ipcClientEvent('requestAuthorization')
async requestAuthorization(config: DataSyncConfig) {
// 生成状态参数防止 CSRF 攻击
this.authRequestState = crypto.randomBytes(16).toString('hex');
export default class AuthCtr extends ControllerModule {
static override groupName = 'auth';
// 构建授权 URL
const authUrl = new URL('/oidc/auth', remoteUrl);
authUrl.search = querystring.stringify({
client_id: 'lobe-chat',
response_type: 'code',
redirect_uri: `${protocolPrefix}://auth/callback`,
scope: 'openid profile',
state: this.authRequestState,
});
@IpcMethod()
async requestAuthorization(config: DataSyncConfig) {
this.authRequestState = crypto.randomBytes(16).toString('hex');
const authUrl = new URL('/oidc/auth', remoteUrl);
authUrl.search = querystring.stringify({
client_id: 'lobe-chat',
redirect_uri: `${protocolPrefix}://auth/callback`,
response_type: 'code',
scope: 'openid profile',
state: this.authRequestState,
});
await shell.openExternal(authUrl.toString());
}
// 在默认浏览器中打开授权 URL
await shell.openExternal(authUrl.toString());
}
```
@@ -269,27 +267,20 @@ export class ShortcutManager {
- 注入 App 实例
```typescript
import { ControllerModule, IpcMethod, IpcServerMethod } from '@/controllers'
// 控制器基类和装饰器
export class ControllerModule implements IControllerModule {
constructor(public app: App) {
this.app = app
this.app = app;
}
}
export class BrowserWindowsCtr extends ControllerModule {
static override readonly groupName = 'windows' // must be readonly
// IPC 客户端事件装饰器
export const ipcClientEvent = (method: keyof ClientDispatchEvents) =>
ipcDecorator(method, 'client');
@IpcMethod()
openSettingsWindow(params?: OpenSettingsWindowOptions) {
// ...
}
@IpcServerMethod()
handleServerCommand(payload: any) {
// ...
}
}
// IPC 服务器事件装饰器
export const ipcServerEvent = (method: keyof ServerDispatchEvents) =>
ipcDecorator(method, 'server');
```
2. **IoC 容器**
@@ -355,13 +346,26 @@ makeSureDirExist(storagePath);
- 自动映射控制器方法到 IPC 事件
```typescript
import { ensureElectronIpc } from '@/utils/electron/ipc';
// IPC 事件初始化
private initializeIPCEvents() {
// 注册客户端事件处理程序
this.ipcClientEventMap.forEach((eventInfo, key) => {
ipcMain.handle(key, async (e, ...data) => {
return await eventInfo.controller[eventInfo.methodName](...data);
});
});
// 渲染进程中使用 type-safe proxy 调用主进程方法
const ipc = ensureElectronIpc();
// 注册服务器事件处理程序
const ipcServerEvents = {} as ElectronIPCEventHandler;
this.ipcServerEventMap.forEach((eventInfo, key) => {
ipcServerEvents[key] = async (payload) => {
return await eventInfo.controller[eventInfo.methodName](payload);
};
});
await ipc.localSystem.readLocalFile({ path });
await ipc.system.updateLocale('en-US');
// 创建 IPC 服务器
this.ipcServer = new ElectronIPCServer(name, ipcServerEvents);
}
```
2. **事件广播**
+6 -42
View File
@@ -32,7 +32,7 @@ pnpm install-isolated
pnpm electron:dev
# Type checking
pnpm type-check
pnpm typecheck
# Run tests
pnpm test
@@ -66,9 +66,9 @@ cp .env.desktop .env
pnpm electron:dev # Start with hot reload
# 2. Code Quality
pnpm lint # ESLint checking
pnpm format # Prettier formatting
pnpm type-check # TypeScript validation
pnpm lint # ESLint checking
pnpm format # Prettier formatting
pnpm typecheck # TypeScript validation
# 3. Testing
pnpm test # Run Vitest tests
@@ -183,18 +183,10 @@ The `App.ts` class orchestrates the entire application lifecycle through key pha
#### 🔌 Dependency Injection & Event System
- **IoC Container** - WeakMap-based container for decorated controller methods
- **Typed IPC Decorators** - `@IpcMethod` and `@IpcServerMethod` wire controller methods into type-safe channels
- **Decorator Registration** - `@ipcClientEvent` and `@ipcServerEvent` decorators
- **Automatic Event Mapping** - Events registered during controller loading
- **Service Locator** - Type-safe service and controller retrieval
##### 🧠 Type-Safe IPC Flow
- **Async Context Propagation** - `src/main/utils/ipc/base.ts` captures the `IpcContext` with `AsyncLocalStorage`, so controller logic can call `getIpcContext()` anywhere inside an IPC handler without explicitly threading arguments.
- **Service Constructors Registry** - `src/main/controllers/registry.ts` exports `controllerIpcConstructors`, `DesktopIpcServices`, and `DesktopServerIpcServices`, enabling automatic typing of both renderer and server IPC proxies.
- **Renderer Proxy Helper** - `src/utils/electron/ipc.ts` exposes `ensureElectronIpc()` which lazily builds a proxy on top of `window.electronAPI.invoke`, giving React/Next.js code a type-safe API surface without exposing raw proxies in preload.
- **Server Proxy Helper** - `src/server/modules/ElectronIPCClient/index.ts` mirrors the same typing strategy for the Next.js server runtime, providing a dedicated proxy for `@IpcServerMethod` handlers.
- **Shared Typings Package** - `apps/desktop/src/main/exports.d.ts` augments `@lobechat/electron-client-ipc` so every package can consume `DesktopIpcServices` without importing desktop business code directly.
#### 🪟 Window Management
- **Theme-Aware Windows** - Automatic adaptation to system dark/light mode
@@ -243,7 +235,6 @@ The `App.ts` class orchestrates the entire application lifecycle through key pha
#### 🎮 Controller Pattern
- **Typed IPC Decorators** - Controllers extend `ControllerModule` and expose renderer methods via `@IpcMethod`
- **IPC Event Handling** - Processes events from renderer with decorator-based registration
- **Lifecycle Hooks** - `beforeAppReady` and `afterAppReady` for initialization phases
- **Type-Safe Communication** - Strong typing for all IPC events and responses
@@ -265,33 +256,6 @@ The `App.ts` class orchestrates the entire application lifecycle through key pha
- **Context Awareness** - Events include sender context for window-specific operations
- **Error Propagation** - Centralized error handling with proper status codes
##### 🧩 Renderer IPC Helper
Renderer code uses a lightweight proxy generated at runtime to keep IPC calls type-safe without exposing raw Electron objects through `contextBridge`. Use the helper exported from `src/utils/electron/ipc.ts` to access the main-process services:
```ts
import { ensureElectronIpc } from '@/utils/electron/ipc';
const ipc = ensureElectronIpc();
await ipc.windows.openSettingsWindow({ tab: 'provider' });
```
The helper internally builds a proxy on top of `window.electronAPI.invoke`, so no proxy objects need to be cloned across the preload boundary.
##### 🖥️ Server IPC Helper
Next.js (Node) modules use the same proxy pattern via `ensureElectronServerIpc` from `src/server/modules/ElectronIPCClient`. It lazily wraps the socket-based `ElectronIpcClient` so server code can call controllers with full type safety:
```ts
import { ensureElectronServerIpc } from '@/server/modules/ElectronIPCClient';
const ipc = ensureElectronServerIpc();
const dbPath = await ipc.system.getDatabasePath();
await ipc.upload.deleteFiles(['foo.txt']);
```
All server methods are declared via `@IpcServerMethod` and live in dedicated controller classes, keeping renderer typings clean.
#### 🛡️ Security Features
- **OAuth 2.0 + PKCE** - Secure authentication with state parameter validation
@@ -313,7 +277,7 @@ tests/ # Integration tests
```bash
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm type-check # Type validation
pnpm typecheck # Type validation
```
### Test Coverage
+6 -31
View File
@@ -32,7 +32,7 @@ pnpm install-isolated
pnpm electron:dev
# 类型检查
pnpm type-check
pnpm typecheck
# 运行测试
pnpm test
@@ -66,9 +66,9 @@ cp .env.desktop .env
pnpm electron:dev # 启动热重载开发服务器
# 2. 代码质量
pnpm lint # ESLint 检查
pnpm format # Prettier 格式化
pnpm type-check # TypeScript 验证
pnpm lint # ESLint 检查
pnpm format # Prettier 格式化
pnpm typecheck # TypeScript 验证
# 3. 测试
pnpm test # 运行 Vitest 测试
@@ -183,7 +183,7 @@ src/main/core/
#### 🔌 依赖注入和事件系统
- **IoC 容器** - 基于 WeakMap 的装饰控制器方法容器
- **装饰器注册** - `@IpcMethod``@IpcServerMethod` 装饰器
- **装饰器注册** - `@ipcClientEvent``@ipcServerEvent` 装饰器
- **自动事件映射** - 控制器加载期间注册的事件
- **服务定位器** - 类型安全的服务和控制器检索
@@ -256,31 +256,6 @@ src/main/core/
- **上下文感知** - 事件包含用于窗口特定操作的发送者上下文
- **错误传播** - 具有适当状态码的集中错误处理
##### 🧩 渲染器 IPC 助手
渲染端通过 `src/utils/electron/ipc.ts` 提供的 `ensureElectronIpc` 获得一个运行时代理,无需在 preload 中暴露 Proxy 对象即可获得类型安全的调用体验:
```ts
import { ensureElectronIpc } from '@/utils/electron/ipc';
const ipc = ensureElectronIpc();
await ipc.windows.openSettingsWindow({ tab: 'provider' });
```
##### 🖥️ Server IPC 助手
Next.js 服务端模块可通过 `ensureElectronServerIpc`(位于 `src/server/modules/ElectronIPCClient`)获得同样的类型安全代理,并复用 socket IPC 通道:
```ts
import { ensureElectronServerIpc } from '@/server/modules/ElectronIPCClient';
const ipc = ensureElectronServerIpc();
const path = await ipc.system.getDatabasePath();
await ipc.upload.deleteFiles(['foo.txt']);
```
所有 `@IpcServerMethod` 方法都放在独立的控制器中,这样渲染端的类型推导不会包含这些仅供服务器调用的通道。
#### 🛡️ 安全功能
- **OAuth 2.0 + PKCE** - 具有状态参数验证的安全认证
@@ -302,7 +277,7 @@ tests/ # 集成测试
```bash
pnpm test # 运行所有测试
pnpm test:watch # 监视模式
pnpm type-check # 类型验证
pnpm typecheck # 类型验证
```
### 测试覆盖
+1 -37
View File
@@ -17,10 +17,6 @@ console.log(`🏗️ Building for architecture: ${arch}`);
const isNightly = channel === 'nightly';
const isBeta = packageJSON.name.includes('beta');
// Keep only these Electron Framework localization folders (*.lproj)
// (aligned with previous Electron Forge build config)
const keepLanguages = new Set(['en', 'en_GB', 'en-US', 'en_US']);
// https://www.electron.build/code-signing-mac#how-to-disable-code-signing-during-the-build-process-on-macos
if (!hasAppleCertificate) {
// Disable auto discovery to keep electron-builder from searching unavailable signing identities
@@ -58,7 +54,7 @@ const config = {
*/
afterPack: async (context) => {
// Only process macOS builds
if (!['darwin', 'mas'].includes(context.electronPlatformName)) {
if (context.electronPlatformName !== 'darwin') {
return;
}
@@ -72,36 +68,6 @@ const config = {
);
const assetsCarDest = path.join(resourcesPath, 'Assets.car');
// Remove unused Electron Framework localizations to reduce app size
// Equivalent to:
// ../../Frameworks/Electron Framework.framework/Versions/A/Resources/*.lproj
const frameworkResourcePath = path.join(
context.appOutDir,
`${context.packager.appInfo.productFilename}.app`,
'Contents',
'Frameworks',
'Electron Framework.framework',
'Versions',
'A',
'Resources',
);
try {
const entries = await fs.readdir(frameworkResourcePath);
await Promise.all(
entries.map(async (file) => {
if (!file.endsWith('.lproj')) return;
const lang = file.split('.')[0];
if (keepLanguages.has(lang)) return;
await fs.rm(path.join(frameworkResourcePath, file), { force: true, recursive: true });
}),
);
} catch {
// Non-critical: folder may not exist depending on packaging details
}
try {
await fs.access(assetsCarSource);
await fs.copyFile(assetsCarSource, assetsCarDest);
@@ -140,8 +106,6 @@ const config = {
files: [
'dist',
'resources',
// Ensure Next export assets are packaged
'dist/next/**/*',
'!resources/locales',
'!dist/next/docs',
'!dist/next/packages',
-1
View File
@@ -39,7 +39,6 @@ export default defineConfig({
resolve: {
alias: {
'~common': resolve(__dirname, 'src/common'),
'@': resolve(__dirname, 'src/main'),
},
},
},
+12 -29
View File
@@ -11,30 +11,21 @@
"author": "LobeHub",
"main": "./dist/main/index.js",
"scripts": {
"build": "electron-vite build",
"build": "npm run typecheck && electron-vite build",
"build-local": "npm run build && electron-builder --dir --config electron-builder.js --c.mac.notarize=false -c.mac.identity=null --c.asar=false",
"build:linux": "npm run build && electron-builder --linux --config electron-builder.js --publish never",
"build:mac": "npm run build && electron-builder --mac --config electron-builder.js --publish never",
"build:mac:local": "npm run build && UPDATE_CHANNEL=nightly electron-builder --mac --config electron-builder.js --publish never",
"build:win": "npm run build && electron-builder --win --config electron-builder.js --publish never",
"dev": "electron-vite dev",
"electron:dev": "electron-vite dev",
"electron:run-unpack": "electron .",
"format": "prettier --write ",
"i18n": "tsx scripts/i18nWorkflow/index.ts && lobe-i18n",
"postinstall": "electron-builder install-app-deps",
"install-isolated": "pnpm install",
"lint": "npm run lint:ts && npm run lint:style && npm run type-check && npm run lint:circular",
"lint:circular": "npm run lint:circular:main && npm run lint:circular:packages",
"lint:circular:main": "dpdm src/**/*.ts --no-warning --no-tree --exit-code circular:1 --no-progress -T true --skip-dynamic-imports circular",
"lint:circular:packages": "dpdm packages/**/src/**/*.ts --no-warning --no-tree --exit-code circular:1 --no-progress -T true --skip-dynamic-imports circular",
"lint:md": "remark . --silent --output",
"lint:style": "stylelint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
"lint:ts": "eslint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
"lint": "eslint --cache ",
"start": "electron-vite preview",
"stylelint": "stylelint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
"test": "vitest --run",
"type-check": "tsgo --noEmit -p tsconfig.json",
"typecheck": "tsgo --noEmit -p tsconfig.json"
},
"dependencies": {
@@ -42,8 +33,7 @@
"electron-window-state": "^5.0.3",
"fetch-socks": "^1.3.2",
"get-port-please": "^3.2.0",
"pdfjs-dist": "4.10.38",
"superjson": "^2.2.6"
"pdfjs-dist": "4.10.38"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
@@ -51,52 +41,45 @@
"@electron-toolkit/preload": "^3.0.2",
"@electron-toolkit/tsconfig": "^2.0.0",
"@electron-toolkit/utils": "^4.0.0",
"@lobechat/desktop-bridge": "workspace:*",
"@lobechat/electron-client-ipc": "workspace:*",
"@lobechat/electron-server-ipc": "workspace:*",
"@lobechat/file-loaders": "workspace:*",
"@lobehub/i18n-cli": "^1.25.1",
"@modelcontextprotocol/sdk": "^1.24.3",
"@types/async-retry": "^1.4.9",
"@types/lodash": "^4.17.21",
"@types/resolve": "^1.20.6",
"@types/semver": "^7.7.1",
"@types/set-cookie-parser": "^2.4.10",
"@t3-oss/env-core": "^0.13.8",
"@typescript/native-preview": "7.0.0-dev.20251210.1",
"@typescript/native-preview": "7.0.0-dev.20250711.1",
"async-retry": "^1.3.3",
"consola": "^3.4.2",
"cookie": "^1.1.1",
"diff": "^8.0.2",
"electron": "^38.7.2",
"electron-builder": "^26.0.12",
"electron-devtools-installer": "^3.2.0",
"electron-is": "^3.0.0",
"electron-log": "^5.4.3",
"electron-store": "^8.2.0",
"electron-vite": "^4.0.1",
"es-toolkit": "^1.43.0",
"eslint": "^8.57.1",
"execa": "^9.6.1",
"fast-glob": "^3.3.3",
"fix-path": "^5.0.0",
"happy-dom": "^20.0.11",
"http-proxy-agent": "^7.0.2",
"https-proxy-agent": "^7.0.6",
"i18next": "^25.7.2",
"i18next": "^25.6.3",
"just-diff": "^6.0.2",
"prettier": "^3.7.4",
"remark-cli": "^12.0.1",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"resolve": "^1.22.11",
"semver": "^7.7.3",
"set-cookie-parser": "^2.7.2",
"stylelint": "^15.11.0",
"tsx": "^4.21.0",
"tsx": "^4.20.6",
"typescript": "^5.9.3",
"undici": "^7.16.0",
"uuid": "^13.0.0",
"vite": "^7.2.7",
"vitest": "^3.2.4",
"zod": "^3.25.76"
"vite": "^7.2.4",
"vitest": "^3.2.4"
},
"pnpm": {
"onlyBuiltDependencies": [
@@ -104,4 +87,4 @@
"electron-builder"
]
}
}
}
-1
View File
@@ -2,5 +2,4 @@ packages:
- '../../packages/electron-server-ipc'
- '../../packages/electron-client-ipc'
- '../../packages/file-loaders'
- '../../packages/desktop-bridge'
- '.'
+31 -25
View File
@@ -1,26 +1,32 @@
{
"actions.add": "إضافة",
"actions.back": "عودة",
"actions.cancel": "إلغاء",
"actions.close": غلاق",
"actions.confirm": "تأكيد",
"actions.delete": "حذف",
"actions.edit": "تعديل",
"actions.more": "المزيد",
"actions.next": "التالي",
"actions.ok": "حسناً",
"actions.previous": "السابق",
"actions.refresh": "تحديث",
"actions.remove": "إزالة",
"actions.retry": "إعادة المحاولة",
"actions.save": "حفظ",
"actions.search": "بحث",
"actions.submit": "إرسال",
"app.description": "منصة تعاون مساعدك الذكي",
"app.name": "LobeHub",
"status.error": "خطأ",
"status.info": "معلومات",
"status.loading": "جارٍ التحميل",
"status.success": "نجاح",
"status.warning": "تحذير"
}
"actions": {
"add": "إضافة",
"back": "عودة",
"cancel": لغاء",
"close": "إغلاق",
"confirm": "تأكيد",
"delete": "حذف",
"edit": "تعديل",
"more": "المزيد",
"next": "التالي",
"ok": "حسناً",
"previous": "السابق",
"refresh": "تحديث",
"remove": "إزالة",
"retry": "إعادة المحاولة",
"save": "حفظ",
"search": "بحث",
"submit": "إرسال"
},
"app": {
"description": "منصة تعاون مساعدك الذكي",
"name": "LobeHub"
},
"status": {
"error": "خطأ",
"info": "معلومات",
"loading": "جارٍ التحميل",
"success": "نجاح",
"warning": "تحذير"
}
}
+30 -22
View File
@@ -1,23 +1,31 @@
{
"about.button": "تأكيد",
"about.detail": "تطبيق دردشة يعتمد على نموذج لغة كبير",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "حول",
"confirm.cancel": "إلغاء",
"confirm.no": "لا",
"confirm.title": "تأكيد",
"confirm.yes": "نعم",
"error.button": "تأكيد",
"error.detail": "حدث خطأ أثناء العملية، يرجى المحاولة لاحقًا",
"error.message": "حدث خطأ",
"error.title": "خطأ",
"update.downloadAndInstall": "تنزيل وتثبيت",
"update.downloadComplete": "اكتمل التنزيل",
"update.downloadCompleteMessage": "تم تنزيل حزمة التحديث، هل ترغب في التثبيت الآن؟",
"update.installLater": "تثبيت لاحقًا",
"update.installNow": "تثبيت الآن",
"update.later": "تذكير لاحقًا",
"update.newVersion": "تم اكتشاف إصدار جديد",
"update.newVersionAvailable": "تم اكتشاف إصدار جديد: {{version}}",
"update.skipThisVersion": "تخطي هذا الإصدار"
}
"about": {
"button": "تأكيد",
"detail": "تطبيق دردشة يعتمد على نموذج لغة كبير",
"message": "{{appName}} {{appVersion}}",
"title": "حول"
},
"confirm": {
"cancel": "إلغاء",
"no": "لا",
"title": "تأكيد",
"yes": "نعم"
},
"error": {
"button": "تأكيد",
"detail": "حدث خطأ أثناء العملية، يرجى المحاولة لاحقًا",
"message": "حدث خطأ",
"title": "خطأ"
},
"update": {
"downloadAndInstall": "تنزيل وتثبيت",
"downloadComplete": "اكتمل التنزيل",
"downloadCompleteMessage": "تم تنزيل حزمة التحديث، هل ترغب في التثبيت الآن؟",
"installLater": "تثبيت لاحقًا",
"installNow": "تثبيت الآن",
"later": "تذكير لاحقًا",
"newVersion": "تم اكتشاف إصدار جديد",
"newVersionAvailable": "تم اكتشاف إصدار جديد: {{version}}",
"skipThisVersion": "تخطي هذا الإصدار"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "التحقق من التحديثات...",
"dev.devPanel": "لوحة المطور",
"dev.devTools": "أدوات المطور",
"dev.forceReload": "إعادة تحميل قسري",
"dev.openStore": "فتح ملف التخزين",
"dev.refreshMenu": "تحديث القائمة",
"dev.reload": "إعادة تحميل",
"dev.title": "تطوير",
"edit.copy": "نسخ",
"edit.cut": "قص",
"edit.delete": "حذف",
"edit.paste": "لصق",
"edit.redo": "إعادة",
"edit.selectAll": "تحديد الكل",
"edit.speech": وت",
"edit.startSpeaking": "بدء القراءة",
"edit.stopSpeaking": "إيقاف القراءة",
"edit.title": "تحرير",
"edit.undo": "تراجع",
"file.preferences": "التفضيلات",
"file.quit": "خروج",
"file.title": "ملف",
"help.about": "حول",
"help.githubRepo": "مستودع GitHub",
"help.reportIssue": "الإبلاغ عن مشكلة",
"help.title": "مساعدة",
"help.visitWebsite": "زيارة الموقع الرسمي",
"macOS.about": "حول {{appName}}",
"macOS.devTools": "أدوات مطور LobeHub",
"macOS.hide": "إخفاء {{appName}}",
"macOS.hideOthers": "إخفاء الآخرين",
"macOS.preferences": "إعدادات مفضلة...",
"macOS.services": "خدمات",
"macOS.unhide": "إظهار الكل",
"tray.open": "فتح {{appName}}",
"tray.quit": "خروج",
"tray.show": "عرض {{appName}}",
"view.forceReload": "إعادة تحميل قسري",
"view.reload": "إعادة تحميل",
"view.resetZoom": "إعادة تعيين التكبير",
"view.title": "عرض",
"view.toggleFullscreen": "تبديل وضع ملء الشاشة",
"view.zoomIn": "تكبير",
"view.zoomOut": "تصغير",
"window.bringAllToFront": حضار جميع النوافذ إلى الأمام",
"window.close": "إغلاق",
"window.front": "إحضار جميع النوافذ إلى الأمام",
"window.minimize": "تصغير",
"window.title": "نافذة",
"window.toggleFullscreen": "تبديل وضع ملء الشاشة",
"window.zoom": "تكبير"
}
"common": {
"checkUpdates": "التحقق من التحديثات..."
},
"dev": {
"devPanel": "لوحة المطور",
"devTools": "أدوات المطور",
"forceReload": "إعادة تحميل قسري",
"openStore": "فتح ملف التخزين",
"refreshMenu": "تحديث القائمة",
"reload": "إعادة تحميل",
"title": "تطوير"
},
"edit": {
"copy": "نسخ",
"cut": "قص",
"delete": "حذف",
"paste": "لصق",
"redo": "إعادة",
"selectAll": "تحديد الكل",
"speech": "صوت",
"startSpeaking": "بدء القراءة",
"stopSpeaking": "إيقاف القراءة",
"title": "تحرير",
"undo": "تراجع"
},
"file": {
"preferences": "التفضيلات",
"quit": "خروج",
"title": "ملف"
},
"help": {
"about": "حول",
"githubRepo": "مستودع GitHub",
"reportIssue": "الإبلاغ عن مشكلة",
"title": "مساعدة",
"visitWebsite": "زيارة الموقع الرسمي"
},
"macOS": {
"about": "حول {{appName}}",
"devTools": "أدوات مطور LobeHub",
"hide": "إخفاء {{appName}}",
"hideOthers": "إخفاء الآخرين",
"preferences": "إعدادات مفضلة...",
"services": "خدمات",
"unhide": ظهار الكل"
},
"tray": {
"open": "فتح {{appName}}",
"quit": "خروج",
"show": "عرض {{appName}}"
},
"view": {
"forceReload": "إعادة تحميل قسري",
"reload": "إعادة تحميل",
"resetZoom": "إعادة تعيين التكبير",
"title": "عرض",
"toggleFullscreen": "تبديل وضع ملء الشاشة",
"zoomIn": "تكبير",
"zoomOut": "تصغير"
},
"window": {
"bringAllToFront": "إحضار جميع النوافذ إلى الأمام",
"close": "إغلاق",
"front": "إحضار جميع النوافذ إلى الأمام",
"minimize": "تصغير",
"title": "نافذة",
"toggleFullscreen": "تبديل وضع ملء الشاشة",
"zoom": "تكبير"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Добави",
"actions.back": "Назад",
"actions.cancel": "Отмени",
"actions.close": "Затвори",
"actions.confirm": "Потвърди",
"actions.delete": "Изтрий",
"actions.edit": "Редактирай",
"actions.more": "Повече",
"actions.next": "Следващ",
"actions.ok": "Добре",
"actions.previous": "Предишен",
"actions.refresh": "Освежи",
"actions.remove": "Премахни",
"actions.retry": "Опитай отново",
"actions.save": "Запази",
"actions.search": "Търси",
"actions.submit": "Изпрати",
"app.description": "Твоята платформа за сътрудничество с AI асистент",
"app.name": "LobeHub",
"status.error": "Грешка",
"status.info": "Информация",
"status.loading": "Зареждане",
"status.success": "Успех",
"status.warning": "Предупреждение"
}
"actions": {
"add": "Добави",
"back": "Назад",
"cancel": "Отмени",
"close": "Затвори",
"confirm": "Потвърди",
"delete": "Изтрий",
"edit": "Редактирай",
"more": "Повече",
"next": "Следващ",
"ok": "Добре",
"previous": "Предишен",
"refresh": "Освежи",
"remove": "Премахни",
"retry": "Опитай отново",
"save": "Запази",
"search": "Търси",
"submit": "Изпрати"
},
"app": {
"description": "Твоята платформа за сътрудничество с AI асистент",
"name": "LobeHub"
},
"status": {
"error": "Грешка",
"info": "Информация",
"loading": "Зареждане",
"success": "Успех",
"warning": "Предупреждение"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Потвърди",
"about.detail": "Приложение за чат, базирано на голям езиков модел",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "За нас",
"confirm.cancel": "Отказ",
"confirm.no": "Не",
"confirm.title": "Потвърждение",
"confirm.yes": "Да",
"error.button": "Потвърди",
"error.detail": "Възникна грешка по време на операцията, моля опитайте отново по-късно",
"error.message": "Възникна грешка",
"error.title": "Грешка",
"update.downloadAndInstall": "Изтегли и инсталирай",
"update.downloadComplete": "Изтеглянето е завършено",
"update.downloadCompleteMessage": "Актуализационният пакет е изтеглен, желаете ли да го инсталирате веднага?",
"update.installLater": "Инсталирай по-късно",
"update.installNow": "Инсталирай сега",
"update.later": "Напомни по-късно",
"update.newVersion": "Открита нова версия",
"update.newVersionAvailable": "Открита нова версия: {{version}}",
"update.skipThisVersion": "Пропусни тази версия"
}
"about": {
"button": "Потвърди",
"detail": "Приложение за чат, базирано на голям езиков модел",
"message": "{{appName}} {{appVersion}}",
"title": "За нас"
},
"confirm": {
"cancel": "Отказ",
"no": "Не",
"title": "Потвърждение",
"yes": "Да"
},
"error": {
"button": "Потвърди",
"detail": "Възникна грешка по време на операцията, моля опитайте отново по-късно",
"message": "Възникна грешка",
"title": "Грешка"
},
"update": {
"downloadAndInstall": "Изтегли и инсталирай",
"downloadComplete": "Изтеглянето е завършено",
"downloadCompleteMessage": "Актуализационният пакет е изтеглен, желаете ли да го инсталирате веднага?",
"installLater": "Инсталирай по-късно",
"installNow": "Инсталирай сега",
"later": "Напомни по-късно",
"newVersion": "Открита нова версия",
"newVersionAvailable": "Открита нова версия: {{version}}",
"skipThisVersion": "Пропусни тази версия"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Проверка за актуализации...",
"dev.devPanel": "Панел на разработчика",
"dev.devTools": "Инструменти за разработчици",
"dev.forceReload": "Принудително презареждане",
"dev.openStore": "Отворете файла за съхранение",
"dev.refreshMenu": "Освежаване на менюто",
"dev.reload": "Презареждане",
"dev.title": "Разработка",
"edit.copy": "Копиране",
"edit.cut": "Изрязване",
"edit.delete": "Изтрий",
"edit.paste": "Поставяне",
"edit.redo": "Повторно",
"edit.selectAll": "Избери всичко",
"edit.speech": "Глас",
"edit.startSpeaking": "Започни четене",
"edit.stopSpeaking": "Спри четенето",
"edit.title": "Редактиране",
"edit.undo": "Отмяна",
"file.preferences": "Предпочитания",
"file.quit": "Изход",
"file.title": "Файл",
"help.about": "За",
"help.githubRepo": "GitHub хранилище",
"help.reportIssue": "Докладвай проблем",
"help.title": "Помощ",
"help.visitWebsite": "Посети уебсайта",
"macOS.about": "За {{appName}}",
"macOS.devTools": "Инструменти за разработчици на LobeHub",
"macOS.hide": "Скрий {{appName}}",
"macOS.hideOthers": "Скрий другите",
"macOS.preferences": "Настройки...",
"macOS.services": "Услуги",
"macOS.unhide": "Покажи всичко",
"tray.open": "Отвори {{appName}}",
"tray.quit": "Изход",
"tray.show": "Покажи {{appName}}",
"view.forceReload": "Принудително презареждане",
"view.reload": "Презареждане",
"view.resetZoom": "Нулиране на мащаба",
"view.title": "Изглед",
"view.toggleFullscreen": "Превключи на цял екран",
"view.zoomIn": "Увеличи",
"view.zoomOut": "Намали",
"window.bringAllToFront": ремести всички прозорци напред",
"window.close": "Затвори",
"window.front": "Премести всички прозорци напред",
"window.minimize": "Минимизирай",
"window.title": "Прозорец",
"window.toggleFullscreen": "Превключи на цял екран",
"window.zoom": "Мащаб"
}
"common": {
"checkUpdates": "Проверка за актуализации..."
},
"dev": {
"devPanel": "Панел на разработчика",
"devTools": "Инструменти за разработчици",
"forceReload": "Принудително презареждане",
"openStore": "Отворете файла за съхранение",
"refreshMenu": "Освежаване на менюто",
"reload": "Презареждане",
"title": "Разработка"
},
"edit": {
"copy": "Копиране",
"cut": "Изрязване",
"delete": "Изтрий",
"paste": "Поставяне",
"redo": "Повторно",
"selectAll": "Избери всичко",
"speech": "Глас",
"startSpeaking": "Започни четене",
"stopSpeaking": "Спри четенето",
"title": "Редактиране",
"undo": "Отмяна"
},
"file": {
"preferences": "Предпочитания",
"quit": "Изход",
"title": "Файл"
},
"help": {
"about": "За",
"githubRepo": "GitHub хранилище",
"reportIssue": "Докладвай проблем",
"title": "Помощ",
"visitWebsite": "Посети уебсайта"
},
"macOS": {
"about": "За {{appName}}",
"devTools": "Инструменти за разработчици на LobeHub",
"hide": "Скрий {{appName}}",
"hideOthers": "Скрий другите",
"preferences": "Настройки...",
"services": "Услуги",
"unhide": окажи всичко"
},
"tray": {
"open": "Отвори {{appName}}",
"quit": "Изход",
"show": "Покажи {{appName}}"
},
"view": {
"forceReload": "Принудително презареждане",
"reload": "Презареждане",
"resetZoom": "Нулиране на мащаба",
"title": "Изглед",
"toggleFullscreen": "Превключи на цял екран",
"zoomIn": "Увеличи",
"zoomOut": "Намали"
},
"window": {
"bringAllToFront": "Премести всички прозорци напред",
"close": "Затвори",
"front": "Премести всички прозорци напред",
"minimize": "Минимизирай",
"title": "Прозорец",
"toggleFullscreen": "Превключи на цял екран",
"zoom": "Мащаб"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Hinzufügen",
"actions.back": "Zurück",
"actions.cancel": "Abbrechen",
"actions.close": "Schließen",
"actions.confirm": "Bestätigen",
"actions.delete": "Löschen",
"actions.edit": "Bearbeiten",
"actions.more": "Mehr",
"actions.next": "Weiter",
"actions.ok": "OK",
"actions.previous": "Zurück",
"actions.refresh": "Aktualisieren",
"actions.remove": "Entfernen",
"actions.retry": "Erneut versuchen",
"actions.save": "Speichern",
"actions.search": "Suchen",
"actions.submit": "Einreichen",
"app.description": "Ihre KI-Assistenten-Kollaborationsplattform",
"app.name": "LobeHub",
"status.error": "Fehler",
"status.info": "Information",
"status.loading": "Lädt",
"status.success": "Erfolg",
"status.warning": "Warnung"
}
"actions": {
"add": "Hinzufügen",
"back": "Zurück",
"cancel": "Abbrechen",
"close": "Schließen",
"confirm": "Bestätigen",
"delete": "Löschen",
"edit": "Bearbeiten",
"more": "Mehr",
"next": "Weiter",
"ok": "OK",
"previous": "Zurück",
"refresh": "Aktualisieren",
"remove": "Entfernen",
"retry": "Erneut versuchen",
"save": "Speichern",
"search": "Suchen",
"submit": "Einreichen"
},
"app": {
"description": "Ihre KI-Assistenten-Kollaborationsplattform",
"name": "LobeHub"
},
"status": {
"error": "Fehler",
"info": "Information",
"loading": "Lädt",
"success": "Erfolg",
"warning": "Warnung"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Bestätigen",
"about.detail": "Eine Chat-Anwendung, die auf einem großen Sprachmodell basiert",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Über",
"confirm.cancel": "Abbrechen",
"confirm.no": "Nein",
"confirm.title": "Bestätigung",
"confirm.yes": "Ja",
"error.button": "Bestätigen",
"error.detail": "Während der Operation ist ein Fehler aufgetreten, bitte versuchen Sie es später erneut",
"error.message": "Ein Fehler ist aufgetreten",
"error.title": "Fehler",
"update.downloadAndInstall": "Herunterladen und installieren",
"update.downloadComplete": "Download abgeschlossen",
"update.downloadCompleteMessage": "Das Update-Paket wurde heruntergeladen, möchten Sie es jetzt installieren?",
"update.installLater": "Später installieren",
"update.installNow": "Jetzt installieren",
"update.later": "Später erinnern",
"update.newVersion": "Neue Version gefunden",
"update.newVersionAvailable": "Neue Version verfügbar: {{version}}",
"update.skipThisVersion": "Diese Version überspringen"
}
"about": {
"button": "Bestätigen",
"detail": "Eine Chat-Anwendung, die auf einem großen Sprachmodell basiert",
"message": "{{appName}} {{appVersion}}",
"title": "Über"
},
"confirm": {
"cancel": "Abbrechen",
"no": "Nein",
"title": "Bestätigung",
"yes": "Ja"
},
"error": {
"button": "Bestätigen",
"detail": "Während der Operation ist ein Fehler aufgetreten, bitte versuchen Sie es später erneut",
"message": "Ein Fehler ist aufgetreten",
"title": "Fehler"
},
"update": {
"downloadAndInstall": "Herunterladen und installieren",
"downloadComplete": "Download abgeschlossen",
"downloadCompleteMessage": "Das Update-Paket wurde heruntergeladen, möchten Sie es jetzt installieren?",
"installLater": "Später installieren",
"installNow": "Jetzt installieren",
"later": "Später erinnern",
"newVersion": "Neue Version gefunden",
"newVersionAvailable": "Neue Version verfügbar: {{version}}",
"skipThisVersion": "Diese Version überspringen"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Überprüfen Sie auf Updates...",
"dev.devPanel": "Entwicklerpanel",
"dev.devTools": "Entwicklerwerkzeuge",
"dev.forceReload": "Erzwinge Neuladen",
"dev.openStore": "Speicherdatei öffnen",
"dev.refreshMenu": "Menü aktualisieren",
"dev.reload": "Neuladen",
"dev.title": "Entwicklung",
"edit.copy": "Kopieren",
"edit.cut": "Ausschneiden",
"edit.delete": "Löschen",
"edit.paste": "Einfügen",
"edit.redo": "Wiederherstellen",
"edit.selectAll": "Alles auswählen",
"edit.speech": "Sprache",
"edit.startSpeaking": "Beginne zu sprechen",
"edit.stopSpeaking": "Stoppe das Sprechen",
"edit.title": "Bearbeiten",
"edit.undo": "Rückgängig",
"file.preferences": "Einstellungen",
"file.quit": "Beenden",
"file.title": "Datei",
"help.about": "Über",
"help.githubRepo": "GitHub-Repository",
"help.reportIssue": "Problem melden",
"help.title": "Hilfe",
"help.visitWebsite": "Besuche die Website",
"macOS.about": "Über {{appName}}",
"macOS.devTools": "LobeHub Entwicklerwerkzeuge",
"macOS.hide": "{{appName}} ausblenden",
"macOS.hideOthers": "Andere ausblenden",
"macOS.preferences": "Einstellungen...",
"macOS.services": "Dienste",
"macOS.unhide": "Alle anzeigen",
"tray.open": "{{appName}} öffnen",
"tray.quit": "Beenden",
"tray.show": "{{appName}} anzeigen",
"view.forceReload": "Erzwinge Neuladen",
"view.reload": "Neuladen",
"view.resetZoom": "Zoom zurücksetzen",
"view.title": "Ansicht",
"view.toggleFullscreen": "Vollbild umschalten",
"view.zoomIn": "Vergrößern",
"view.zoomOut": "Verkleinern",
"window.bringAllToFront": "Alle Fenster in den Vordergrund bringen",
"window.close": "Schließen",
"window.front": "Alle Fenster in den Vordergrund bringen",
"window.minimize": "Minimieren",
"window.title": "Fenster",
"window.toggleFullscreen": "Vollbild umschalten",
"window.zoom": "Zoom"
}
"common": {
"checkUpdates": "Überprüfen Sie auf Updates..."
},
"dev": {
"devPanel": "Entwicklerpanel",
"devTools": "Entwicklerwerkzeuge",
"forceReload": "Erzwinge Neuladen",
"openStore": "Speicherdatei öffnen",
"refreshMenu": "Menü aktualisieren",
"reload": "Neuladen",
"title": "Entwicklung"
},
"edit": {
"copy": "Kopieren",
"cut": "Ausschneiden",
"delete": "Löschen",
"paste": "Einfügen",
"redo": "Wiederherstellen",
"selectAll": "Alles auswählen",
"speech": "Sprache",
"startSpeaking": "Beginne zu sprechen",
"stopSpeaking": "Stoppe das Sprechen",
"title": "Bearbeiten",
"undo": "Rückgängig"
},
"file": {
"preferences": "Einstellungen",
"quit": "Beenden",
"title": "Datei"
},
"help": {
"about": "Über",
"githubRepo": "GitHub-Repository",
"reportIssue": "Problem melden",
"title": "Hilfe",
"visitWebsite": "Besuche die Website"
},
"macOS": {
"about": "Über {{appName}}",
"devTools": "LobeHub Entwicklerwerkzeuge",
"hide": "{{appName}} ausblenden",
"hideOthers": "Andere ausblenden",
"preferences": "Einstellungen...",
"services": "Dienste",
"unhide": "Alle anzeigen"
},
"tray": {
"open": "{{appName}} öffnen",
"quit": "Beenden",
"show": "{{appName}} anzeigen"
},
"view": {
"forceReload": "Erzwinge Neuladen",
"reload": "Neuladen",
"resetZoom": "Zoom zurücksetzen",
"title": "Ansicht",
"toggleFullscreen": "Vollbild umschalten",
"zoomIn": "Vergrößern",
"zoomOut": "Verkleinern"
},
"window": {
"bringAllToFront": "Alle Fenster in den Vordergrund bringen",
"close": "Schließen",
"front": "Alle Fenster in den Vordergrund bringen",
"minimize": "Minimieren",
"title": "Fenster",
"toggleFullscreen": "Vollbild umschalten",
"zoom": "Zoom"
}
}
@@ -0,0 +1,32 @@
{
"actions": {
"add": "Add",
"back": "Back",
"cancel": "Cancel",
"close": "Close",
"confirm": "Confirm",
"delete": "Delete",
"edit": "Edit",
"more": "More",
"next": "Next",
"ok": "OK",
"previous": "Previous",
"refresh": "Refresh",
"remove": "Remove",
"retry": "Retry",
"save": "Save",
"search": "Search",
"submit": "Submit"
},
"app": {
"description": "Your AI Assistant Collaboration Platform",
"name": "LobeHub"
},
"status": {
"error": "Error",
"info": "Information",
"loading": "Loading",
"success": "Success",
"warning": "Warning"
}
}
@@ -0,0 +1,31 @@
{
"about": {
"button": "OK",
"detail": "A chat application based on a large language model",
"message": "{{appName}} {{appVersion}}",
"title": "About"
},
"confirm": {
"cancel": "Cancel",
"no": "No",
"title": "Confirm",
"yes": "Yes"
},
"error": {
"button": "OK",
"detail": "An error occurred during the operation, please try again later",
"message": "An error occurred",
"title": "Error"
},
"update": {
"downloadAndInstall": "Download and Install",
"downloadComplete": "Download Complete",
"downloadCompleteMessage": "The update package has been downloaded, would you like to install it now?",
"installLater": "Install Later",
"installNow": "Install Now",
"later": "Remind Me Later",
"newVersion": "New Version Found",
"newVersionAvailable": "New version available: {{version}}",
"skipThisVersion": "Skip This Version"
}
}
@@ -0,0 +1,71 @@
{
"common": {
"checkUpdates": "Checking for updates..."
},
"dev": {
"devPanel": "Developer Panel",
"devTools": "Developer Tools",
"forceReload": "Force Reload",
"openStore": "Open Storage File",
"refreshMenu": "Refresh menu",
"reload": "Reload",
"title": "Development"
},
"edit": {
"copy": "Copy",
"cut": "Cut",
"delete": "Delete",
"paste": "Paste",
"redo": "Redo",
"selectAll": "Select All",
"speech": "Speech",
"startSpeaking": "Start Speaking",
"stopSpeaking": "Stop Speaking",
"title": "Edit",
"undo": "Undo"
},
"file": {
"preferences": "Preferences",
"quit": "Quit",
"title": "File"
},
"help": {
"about": "About",
"githubRepo": "GitHub Repository",
"reportIssue": "Report Issue",
"title": "Help",
"visitWebsite": "Visit Website"
},
"macOS": {
"about": "About {{appName}}",
"devTools": "LobeHub Developer Tools",
"hide": "Hide {{appName}}",
"hideOthers": "Hide Others",
"preferences": "Preferences...",
"services": "Services",
"unhide": "Show All"
},
"tray": {
"open": "Open {{appName}}",
"quit": "Quit",
"show": "Show {{appName}}"
},
"view": {
"forceReload": "Force Reload",
"reload": "Reload",
"resetZoom": "Reset Zoom",
"title": "View",
"toggleFullscreen": "Toggle Fullscreen",
"zoomIn": "Zoom In",
"zoomOut": "Zoom Out"
},
"window": {
"bringAllToFront": "Bring All Windows to Front",
"close": "Close",
"front": "Bring All Windows to Front",
"minimize": "Minimize",
"title": "Window",
"toggleFullscreen": "Toggle Fullscreen",
"zoom": "Zoom"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Agregar",
"actions.back": "Volver",
"actions.cancel": "Cancelar",
"actions.close": "Cerrar",
"actions.confirm": "Confirmar",
"actions.delete": "Eliminar",
"actions.edit": "Editar",
"actions.more": "Más",
"actions.next": "Siguiente",
"actions.ok": "Aceptar",
"actions.previous": "Anterior",
"actions.refresh": "Actualizar",
"actions.remove": "Eliminar",
"actions.retry": "Reintentar",
"actions.save": "Guardar",
"actions.search": "Buscar",
"actions.submit": "Enviar",
"app.description": "Tu plataforma de colaboración con el asistente de IA",
"app.name": "LobeHub",
"status.error": "Error",
"status.info": "Información",
"status.loading": "Cargando",
"status.success": "Éxito",
"status.warning": "Advertencia"
}
"actions": {
"add": "Agregar",
"back": "Volver",
"cancel": "Cancelar",
"close": "Cerrar",
"confirm": "Confirmar",
"delete": "Eliminar",
"edit": "Editar",
"more": "Más",
"next": "Siguiente",
"ok": "Aceptar",
"previous": "Anterior",
"refresh": "Actualizar",
"remove": "Eliminar",
"retry": "Reintentar",
"save": "Guardar",
"search": "Buscar",
"submit": "Enviar"
},
"app": {
"description": "Tu plataforma de colaboración con el asistente de IA",
"name": "LobeHub"
},
"status": {
"error": "Error",
"info": "Información",
"loading": "Cargando",
"success": "Éxito",
"warning": "Advertencia"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Aceptar",
"about.detail": "Una aplicación de chat basada en un modelo de lenguaje grande",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Acerca de",
"confirm.cancel": "Cancelar",
"confirm.no": "No",
"confirm.title": "Confirmar",
"confirm.yes": "Sí",
"error.button": "Aceptar",
"error.detail": "Se produjo un error durante la operación, por favor intente de nuevo más tarde",
"error.message": "Se produjo un error",
"error.title": "Error",
"update.downloadAndInstall": "Descargar e instalar",
"update.downloadComplete": "Descarga completada",
"update.downloadCompleteMessage": "El paquete de actualización se ha descargado, ¿desea instalarlo ahora?",
"update.installLater": "Instalar más tarde",
"update.installNow": "Instalar ahora",
"update.later": "Recordar más tarde",
"update.newVersion": "Nueva versión disponible",
"update.newVersionAvailable": "Nueva versión encontrada: {{version}}",
"update.skipThisVersion": "Saltar esta versión"
}
"about": {
"button": "Aceptar",
"detail": "Una aplicación de chat basada en un modelo de lenguaje grande",
"message": "{{appName}} {{appVersion}}",
"title": "Acerca de"
},
"confirm": {
"cancel": "Cancelar",
"no": "No",
"title": "Confirmar",
"yes": "Sí"
},
"error": {
"button": "Aceptar",
"detail": "Se produjo un error durante la operación, por favor intente de nuevo más tarde",
"message": "Se produjo un error",
"title": "Error"
},
"update": {
"downloadAndInstall": "Descargar e instalar",
"downloadComplete": "Descarga completada",
"downloadCompleteMessage": "El paquete de actualización se ha descargado, ¿desea instalarlo ahora?",
"installLater": "Instalar más tarde",
"installNow": "Instalar ahora",
"later": "Recordar más tarde",
"newVersion": "Nueva versión disponible",
"newVersionAvailable": "Nueva versión encontrada: {{version}}",
"skipThisVersion": "Saltar esta versión"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Comprobando actualizaciones...",
"dev.devPanel": "Panel de desarrollador",
"dev.devTools": "Herramientas de desarrollador",
"dev.forceReload": "Recargar forzosamente",
"dev.openStore": "Abrir archivo de almacenamiento",
"dev.refreshMenu": "Actualizar menú",
"dev.reload": "Recargar",
"dev.title": "Desarrollo",
"edit.copy": "Copiar",
"edit.cut": "Cortar",
"edit.delete": "Eliminar",
"edit.paste": "Pegar",
"edit.redo": "Rehacer",
"edit.selectAll": "Seleccionar todo",
"edit.speech": "Voz",
"edit.startSpeaking": "Comenzar a leer en voz alta",
"edit.stopSpeaking": "Detener lectura en voz alta",
"edit.title": "Editar",
"edit.undo": "Deshacer",
"file.preferences": "Preferencias",
"file.quit": "Salir",
"file.title": "Archivo",
"help.about": "Acerca de",
"help.githubRepo": "Repositorio de GitHub",
"help.reportIssue": "Reportar un problema",
"help.title": "Ayuda",
"help.visitWebsite": "Visitar el sitio web",
"macOS.about": "Acerca de {{appName}}",
"macOS.devTools": "Herramientas de desarrollador de LobeHub",
"macOS.hide": "Ocultar {{appName}}",
"macOS.hideOthers": "Ocultar otros",
"macOS.preferences": "Configuración...",
"macOS.services": "Servicios",
"macOS.unhide": "Mostrar todo",
"tray.open": "Abrir {{appName}}",
"tray.quit": "Salir",
"tray.show": "Mostrar {{appName}}",
"view.forceReload": "Recargar forzosamente",
"view.reload": "Recargar",
"view.resetZoom": "Restablecer zoom",
"view.title": "Vista",
"view.toggleFullscreen": "Alternar pantalla completa",
"view.zoomIn": "Acercar",
"view.zoomOut": "Alejar",
"window.bringAllToFront": "Traer todas las ventanas al frente",
"window.close": "Cerrar",
"window.front": "Traer todas las ventanas al frente",
"window.minimize": "Minimizar",
"window.title": "Ventana",
"window.toggleFullscreen": "Alternar pantalla completa",
"window.zoom": "Zoom"
}
"common": {
"checkUpdates": "Comprobando actualizaciones..."
},
"dev": {
"devPanel": "Panel de desarrollador",
"devTools": "Herramientas de desarrollador",
"forceReload": "Recargar forzosamente",
"openStore": "Abrir archivo de almacenamiento",
"refreshMenu": "Actualizar menú",
"reload": "Recargar",
"title": "Desarrollo"
},
"edit": {
"copy": "Copiar",
"cut": "Cortar",
"delete": "Eliminar",
"paste": "Pegar",
"redo": "Rehacer",
"selectAll": "Seleccionar todo",
"speech": "Voz",
"startSpeaking": "Comenzar a leer en voz alta",
"stopSpeaking": "Detener lectura en voz alta",
"title": "Editar",
"undo": "Deshacer"
},
"file": {
"preferences": "Preferencias",
"quit": "Salir",
"title": "Archivo"
},
"help": {
"about": "Acerca de",
"githubRepo": "Repositorio de GitHub",
"reportIssue": "Reportar un problema",
"title": "Ayuda",
"visitWebsite": "Visitar el sitio web"
},
"macOS": {
"about": "Acerca de {{appName}}",
"devTools": "Herramientas de desarrollador de LobeHub",
"hide": "Ocultar {{appName}}",
"hideOthers": "Ocultar otros",
"preferences": "Configuración...",
"services": "Servicios",
"unhide": "Mostrar todo"
},
"tray": {
"open": "Abrir {{appName}}",
"quit": "Salir",
"show": "Mostrar {{appName}}"
},
"view": {
"forceReload": "Recargar forzosamente",
"reload": "Recargar",
"resetZoom": "Restablecer zoom",
"title": "Vista",
"toggleFullscreen": "Alternar pantalla completa",
"zoomIn": "Acercar",
"zoomOut": "Alejar"
},
"window": {
"bringAllToFront": "Traer todas las ventanas al frente",
"close": "Cerrar",
"front": "Traer todas las ventanas al frente",
"minimize": "Minimizar",
"title": "Ventana",
"toggleFullscreen": "Alternar pantalla completa",
"zoom": "Zoom"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "افزودن",
"actions.back": "بازگشت",
"actions.cancel": "لغو",
"actions.close": "بستن",
"actions.confirm": "تأیید",
"actions.delete": "حذف",
"actions.edit": "ویرایش",
"actions.more": "بیشتر",
"actions.next": "مرحله بعد",
"actions.ok": "تأیید",
"actions.previous": "مرحله قبل",
"actions.refresh": "به‌روزرسانی",
"actions.remove": "حذف",
"actions.retry": "تلاش مجدد",
"actions.save": "ذخیره",
"actions.search": "جستجو",
"actions.submit": "ارسال",
"app.description": "پلتفرم همکاری دستیار هوش مصنوعی شما",
"app.name": "LobeHub",
"status.error": "خطا",
"status.info": "اطلاعات",
"status.loading": "در حال بارگذاری",
"status.success": "موفق",
"status.warning": "هشدار"
}
"actions": {
"add": "افزودن",
"back": "بازگشت",
"cancel": "لغو",
"close": "بستن",
"confirm": "تأیید",
"delete": "حذف",
"edit": "ویرایش",
"more": "بیشتر",
"next": "مرحله بعد",
"ok": "تأیید",
"previous": "مرحله قبل",
"refresh": "به‌روزرسانی",
"remove": "حذف",
"retry": "تلاش مجدد",
"save": "ذخیره",
"search": "جستجو",
"submit": "ارسال"
},
"app": {
"description": "پلتفرم همکاری دستیار هوش مصنوعی شما",
"name": "LobeHub"
},
"status": {
"error": "خطا",
"info": "اطلاعات",
"loading": "در حال بارگذاری",
"success": "موفق",
"warning": "هشدار"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "تأیید",
"about.detail": "یک برنامه چت مبتنی بر مدل‌های زبانی بزرگ",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "درباره",
"confirm.cancel": "لغو",
"confirm.no": "خیر",
"confirm.title": "تأیید",
"confirm.yes": "بله",
"error.button": "تأیید",
"error.detail": "در حین انجام عملیات خطایی رخ داده است، لطفاً بعداً دوباره تلاش کنید",
"error.message": "خطا رخ داده است",
"error.title": "خطا",
"update.downloadAndInstall": "دانلود و نصب",
"update.downloadComplete": "دانلود کامل شد",
"update.downloadCompleteMessage": "بسته به‌روزرسانی دانلود شده است، آیا می‌خواهید بلافاصله نصب کنید؟",
"update.installLater": "نصب بعداً",
"update.installNow": "نصب اکنون",
"update.later": "یادآوری بعداً",
"update.newVersion": "نسخه جدیدی پیدا شد",
"update.newVersionAvailable": "نسخه جدید پیدا شد: {{version}}",
"update.skipThisVersion": "این نسخه را نادیده بگیرید"
}
"about": {
"button": "تأیید",
"detail": "یک برنامه چت مبتنی بر مدل‌های زبانی بزرگ",
"message": "{{appName}} {{appVersion}}",
"title": "درباره"
},
"confirm": {
"cancel": "لغو",
"no": "خیر",
"title": "تأیید",
"yes": "بله"
},
"error": {
"button": "تأیید",
"detail": "در حین انجام عملیات خطایی رخ داده است، لطفاً بعداً دوباره تلاش کنید",
"message": "خطا رخ داده است",
"title": "خطا"
},
"update": {
"downloadAndInstall": "دانلود و نصب",
"downloadComplete": "دانلود کامل شد",
"downloadCompleteMessage": "بسته به‌روزرسانی دانلود شده است، آیا می‌خواهید بلافاصله نصب کنید؟",
"installLater": "نصب بعداً",
"installNow": "نصب اکنون",
"later": "یادآوری بعداً",
"newVersion": "نسخه جدیدی پیدا شد",
"newVersionAvailable": "نسخه جدید پیدا شد: {{version}}",
"skipThisVersion": "این نسخه را نادیده بگیرید"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "بررسی به‌روزرسانی...",
"dev.devPanel": "پنل توسعه‌دهنده",
"dev.devTools": "ابزارهای توسعه‌دهنده",
"dev.forceReload": "بارگذاری اجباری",
"dev.openStore": "باز کردن فایل‌های ذخیره شده",
"dev.refreshMenu": "به‌روزرسانی منو",
"dev.reload": "بارگذاری مجدد",
"dev.title": "توسعه",
"edit.copy": "کپی",
"edit.cut": رش",
"edit.delete": "حذف",
"edit.paste": "چسباندن",
"edit.redo": "انجام مجدد",
"edit.selectAll": "انتخاب همه",
"edit.speech": "گفتار",
"edit.startSpeaking": "شروع به خواندن",
"edit.stopSpeaking": "متوقف کردن خواندن",
"edit.title": "ویرایش",
"edit.undo": "بازگشت",
"file.preferences": "تنظیمات",
"file.quit": "خروج",
"file.title": "فایل",
"help.about": "درباره",
"help.githubRepo": "مخزن GitHub",
"help.reportIssue": "گزارش مشکل",
"help.title": "کمک",
"help.visitWebsite": "بازدید از وب‌سایت",
"macOS.about": "درباره {{appName}}",
"macOS.devTools": "ابزارهای توسعه‌دهنده LobeHub",
"macOS.hide": "پنهان کردن {{appName}}",
"macOS.hideOthers": "پنهان کردن دیگران",
"macOS.preferences": "تنظیمات...",
"macOS.services": "خدمات",
"macOS.unhide": "نمایش همه",
"tray.open": "باز کردن {{appName}}",
"tray.quit": "خروج",
"tray.show": "نمایش {{appName}}",
"view.forceReload": "بارگذاری اجباری",
"view.reload": "بارگذاری مجدد",
"view.resetZoom": "تنظیم زوم به حالت اولیه",
"view.title": "نمایش",
"view.toggleFullscreen": "تغییر به حالت تمام صفحه",
"view.zoomIn": "بزرگ‌نمایی",
"view.zoomOut": "کوچک‌نمایی",
"window.bringAllToFront": "همه پنجره‌ها را به جلو بیاورید",
"window.close": "بستن",
"window.front": "همه پنجره‌ها را به جلو بیاورید",
"window.minimize": "کوچک کردن",
"window.title": "پنجره",
"window.toggleFullscreen": "تغییر به حالت تمام صفحه",
"window.zoom": "زوم"
}
"common": {
"checkUpdates": "بررسی به‌روزرسانی..."
},
"dev": {
"devPanel": "پنل توسعه‌دهنده",
"devTools": "ابزارهای توسعه‌دهنده",
"forceReload": "بارگذاری اجباری",
"openStore": "باز کردن فایل‌های ذخیره شده",
"refreshMenu": "به‌روزرسانی منو",
"reload": ارگذاری مجدد",
"title": "توسعه"
},
"edit": {
"copy": "کپی",
"cut": "برش",
"delete": "حذف",
"paste": "چسباندن",
"redo": "انجام مجدد",
"selectAll": "انتخاب همه",
"speech": "گفتار",
"startSpeaking": "شروع به خواندن",
"stopSpeaking": "متوقف کردن خواندن",
"title": "ویرایش",
"undo": "بازگشت"
},
"file": {
"preferences": "تنظیمات",
"quit": "خروج",
"title": "فایل"
},
"help": {
"about": "درباره",
"githubRepo": "مخزن GitHub",
"reportIssue": "گزارش مشکل",
"title": "کمک",
"visitWebsite": "بازدید از وب‌سایت"
},
"macOS": {
"about": "درباره {{appName}}",
"devTools": "ابزارهای توسعه‌دهنده LobeHub",
"hide": "پنهان کردن {{appName}}",
"hideOthers": "پنهان کردن دیگران",
"preferences": "تنظیمات...",
"services": "خدمات",
"unhide": "نمایش همه"
},
"tray": {
"open": "باز کردن {{appName}}",
"quit": "خروج",
"show": "نمایش {{appName}}"
},
"view": {
"forceReload": "بارگذاری اجباری",
"reload": "بارگذاری مجدد",
"resetZoom": "تنظیم زوم به حالت اولیه",
"title": "نمایش",
"toggleFullscreen": "تغییر به حالت تمام صفحه",
"zoomIn": "بزرگ‌نمایی",
"zoomOut": "کوچک‌نمایی"
},
"window": {
"bringAllToFront": "همه پنجره‌ها را به جلو بیاورید",
"close": "بستن",
"front": "همه پنجره‌ها را به جلو بیاورید",
"minimize": "کوچک کردن",
"title": "پنجره",
"toggleFullscreen": "تغییر به حالت تمام صفحه",
"zoom": "زوم"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Ajouter",
"actions.back": "Retour",
"actions.cancel": "Annuler",
"actions.close": "Fermer",
"actions.confirm": "Confirmer",
"actions.delete": "Supprimer",
"actions.edit": "Éditer",
"actions.more": "Plus",
"actions.next": "Suivant",
"actions.ok": "D'accord",
"actions.previous": "Précédent",
"actions.refresh": "Rafraîchir",
"actions.remove": "Retirer",
"actions.retry": "Réessayer",
"actions.save": "Enregistrer",
"actions.search": "Rechercher",
"actions.submit": "Soumettre",
"app.description": "Votre plateforme de collaboration avec l'assistant IA",
"app.name": "LobeHub",
"status.error": "Erreur",
"status.info": "Information",
"status.loading": "Chargement",
"status.success": "Succès",
"status.warning": "Avertissement"
}
"actions": {
"add": "Ajouter",
"back": "Retour",
"cancel": "Annuler",
"close": "Fermer",
"confirm": "Confirmer",
"delete": "Supprimer",
"edit": "Éditer",
"more": "Plus",
"next": "Suivant",
"ok": "D'accord",
"previous": "Précédent",
"refresh": "Rafraîchir",
"remove": "Retirer",
"retry": "Réessayer",
"save": "Enregistrer",
"search": "Rechercher",
"submit": "Soumettre"
},
"app": {
"description": "Votre plateforme de collaboration avec l'assistant IA",
"name": "LobeHub"
},
"status": {
"error": "Erreur",
"info": "Information",
"loading": "Chargement",
"success": "Succès",
"warning": "Avertissement"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "D'accord",
"about.detail": "Une application de chat basée sur un grand modèle de langage",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "À propos",
"confirm.cancel": "Annuler",
"confirm.no": "Non",
"confirm.title": "Confirmer",
"confirm.yes": "Oui",
"error.button": "D'accord",
"error.detail": "Une erreur s'est produite lors de l'opération, veuillez réessayer plus tard",
"error.message": "Une erreur s'est produite",
"error.title": "Erreur",
"update.downloadAndInstall": "Télécharger et installer",
"update.downloadComplete": "Téléchargement terminé",
"update.downloadCompleteMessage": "Le paquet de mise à jour a été téléchargé, souhaitez-vous l'installer maintenant ?",
"update.installLater": "Installer plus tard",
"update.installNow": "Installer maintenant",
"update.later": "Rappeler plus tard",
"update.newVersion": "Nouvelle version détectée",
"update.newVersionAvailable": "Nouvelle version disponible : {{version}}",
"update.skipThisVersion": "Ignorer cette version"
}
"about": {
"button": "D'accord",
"detail": "Une application de chat basée sur un grand modèle de langage",
"message": "{{appName}} {{appVersion}}",
"title": "À propos"
},
"confirm": {
"cancel": "Annuler",
"no": "Non",
"title": "Confirmer",
"yes": "Oui"
},
"error": {
"button": "D'accord",
"detail": "Une erreur s'est produite lors de l'opération, veuillez réessayer plus tard",
"message": "Une erreur s'est produite",
"title": "Erreur"
},
"update": {
"downloadAndInstall": "Télécharger et installer",
"downloadComplete": "Téléchargement terminé",
"downloadCompleteMessage": "Le paquet de mise à jour a été téléchargé, souhaitez-vous l'installer maintenant ?",
"installLater": "Installer plus tard",
"installNow": "Installer maintenant",
"later": "Rappeler plus tard",
"newVersion": "Nouvelle version détectée",
"newVersionAvailable": "Nouvelle version disponible : {{version}}",
"skipThisVersion": "Ignorer cette version"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Vérifier les mises à jour...",
"dev.devPanel": "Panneau de développement",
"dev.devTools": "Outils de développement",
"dev.forceReload": "Recharger de force",
"dev.openStore": "Ouvrir le fichier de stockage",
"dev.refreshMenu": "Rafraîchir le menu",
"dev.reload": "Recharger",
"dev.title": "Développement",
"edit.copy": "Copier",
"edit.cut": "Couper",
"edit.delete": "Supprimer",
"edit.paste": "Coller",
"edit.redo": "Rétablir",
"edit.selectAll": "Tout sélectionner",
"edit.speech": "Voix",
"edit.startSpeaking": "Commencer à lire",
"edit.stopSpeaking": "Arrêter de lire",
"edit.title": "Édition",
"edit.undo": "Annuler",
"file.preferences": "Préférences",
"file.quit": "Quitter",
"file.title": "Fichier",
"help.about": "À propos",
"help.githubRepo": "Dépôt GitHub",
"help.reportIssue": "Signaler un problème",
"help.title": "Aide",
"help.visitWebsite": "Visiter le site officiel",
"macOS.about": "À propos de {{appName}}",
"macOS.devTools": "Outils de développement LobeHub",
"macOS.hide": "Masquer {{appName}}",
"macOS.hideOthers": "Masquer les autres",
"macOS.preferences": "Préférences...",
"macOS.services": "Services",
"macOS.unhide": "Tout afficher",
"tray.open": "Ouvrir {{appName}}",
"tray.quit": "Quitter",
"tray.show": "Afficher {{appName}}",
"view.forceReload": "Recharger de force",
"view.reload": "Recharger",
"view.resetZoom": "Réinitialiser le zoom",
"view.title": "Affichage",
"view.toggleFullscreen": "Basculer en plein écran",
"view.zoomIn": "Zoomer",
"view.zoomOut": "Dézoomer",
"window.bringAllToFront": "Mettre toutes les fenêtres au premier plan",
"window.close": "Fermer",
"window.front": "Mettre toutes les fenêtres au premier plan",
"window.minimize": "Réduire",
"window.title": "Fenêtre",
"window.toggleFullscreen": "Basculer en plein écran",
"window.zoom": "Zoom"
}
"common": {
"checkUpdates": "Vérifier les mises à jour..."
},
"dev": {
"devPanel": "Panneau de développement",
"devTools": "Outils de développement",
"forceReload": "Recharger de force",
"openStore": "Ouvrir le fichier de stockage",
"refreshMenu": "Rafraîchir le menu",
"reload": "Recharger",
"title": "Développement"
},
"edit": {
"copy": "Copier",
"cut": "Couper",
"delete": "Supprimer",
"paste": "Coller",
"redo": "Rétablir",
"selectAll": "Tout sélectionner",
"speech": "Voix",
"startSpeaking": "Commencer à lire",
"stopSpeaking": "Arrêter de lire",
"title": "Édition",
"undo": "Annuler"
},
"file": {
"preferences": "Préférences",
"quit": "Quitter",
"title": "Fichier"
},
"help": {
"about": "À propos",
"githubRepo": "Dépôt GitHub",
"reportIssue": "Signaler un problème",
"title": "Aide",
"visitWebsite": "Visiter le site officiel"
},
"macOS": {
"about": "À propos de {{appName}}",
"devTools": "Outils de développement LobeHub",
"hide": "Masquer {{appName}}",
"hideOthers": "Masquer les autres",
"preferences": "Préférences...",
"services": "Services",
"unhide": "Tout afficher"
},
"tray": {
"open": "Ouvrir {{appName}}",
"quit": "Quitter",
"show": "Afficher {{appName}}"
},
"view": {
"forceReload": "Recharger de force",
"reload": "Recharger",
"resetZoom": "Réinitialiser le zoom",
"title": "Affichage",
"toggleFullscreen": "Basculer en plein écran",
"zoomIn": "Zoomer",
"zoomOut": "Dézoomer"
},
"window": {
"bringAllToFront": "Mettre toutes les fenêtres au premier plan",
"close": "Fermer",
"front": "Mettre toutes les fenêtres au premier plan",
"minimize": "Réduire",
"title": "Fenêtre",
"toggleFullscreen": "Basculer en plein écran",
"zoom": "Zoom"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Aggiungi",
"actions.back": "Indietro",
"actions.cancel": "Annulla",
"actions.close": "Chiudi",
"actions.confirm": "Conferma",
"actions.delete": "Elimina",
"actions.edit": "Modifica",
"actions.more": "Di più",
"actions.next": "Avanti",
"actions.ok": "OK",
"actions.previous": "Indietro",
"actions.refresh": "Aggiorna",
"actions.remove": "Rimuovi",
"actions.retry": "Riprova",
"actions.save": "Salva",
"actions.search": "Cerca",
"actions.submit": "Invia",
"app.description": "La tua piattaforma di collaborazione con assistente AI",
"app.name": "LobeHub",
"status.error": "Errore",
"status.info": "Informazioni",
"status.loading": "Caricamento in corso",
"status.success": "Successo",
"status.warning": "Avviso"
}
"actions": {
"add": "Aggiungi",
"back": "Indietro",
"cancel": "Annulla",
"close": "Chiudi",
"confirm": "Conferma",
"delete": "Elimina",
"edit": "Modifica",
"more": "Di più",
"next": "Avanti",
"ok": "OK",
"previous": "Indietro",
"refresh": "Aggiorna",
"remove": "Rimuovi",
"retry": "Riprova",
"save": "Salva",
"search": "Cerca",
"submit": "Invia"
},
"app": {
"description": "La tua piattaforma di collaborazione con assistente AI",
"name": "LobeHub"
},
"status": {
"error": "Errore",
"info": "Informazioni",
"loading": "Caricamento in corso",
"success": "Successo",
"warning": "Avviso"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Conferma",
"about.detail": "Un'app di chat basata su un grande modello linguistico",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Informazioni",
"confirm.cancel": "Annulla",
"confirm.no": "No",
"confirm.title": "Conferma",
"confirm.yes": "",
"error.button": "Conferma",
"error.detail": "Si è verificato un errore durante l'operazione, riprovare più tardi",
"error.message": "Si è verificato un errore",
"error.title": "Errore",
"update.downloadAndInstall": "Scarica e installa",
"update.downloadComplete": "Download completato",
"update.downloadCompleteMessage": "Il pacchetto di aggiornamento è stato scaricato, vuoi installarlo subito?",
"update.installLater": "Installa più tardi",
"update.installNow": "Installa ora",
"update.later": "Promemoria più tardi",
"update.newVersion": "Nuova versione disponibile",
"update.newVersionAvailable": "Nuova versione trovata: {{version}}",
"update.skipThisVersion": "Salta questa versione"
}
"about": {
"button": "Conferma",
"detail": "Un'app di chat basata su un grande modello linguistico",
"message": "{{appName}} {{appVersion}}",
"title": "Informazioni"
},
"confirm": {
"cancel": "Annulla",
"no": "No",
"title": "Conferma",
"yes": "Sì"
},
"error": {
"button": "Conferma",
"detail": "Si è verificato un errore durante l'operazione, riprovare più tardi",
"message": "Si è verificato un errore",
"title": "Errore"
},
"update": {
"downloadAndInstall": "Scarica e installa",
"downloadComplete": "Download completato",
"downloadCompleteMessage": "Il pacchetto di aggiornamento è stato scaricato, vuoi installarlo subito?",
"installLater": "Installa più tardi",
"installNow": "Installa ora",
"later": "Promemoria più tardi",
"newVersion": "Nuova versione disponibile",
"newVersionAvailable": "Nuova versione trovata: {{version}}",
"skipThisVersion": "Salta questa versione"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Controlla aggiornamenti...",
"dev.devPanel": "Pannello sviluppatore",
"dev.devTools": "Strumenti per sviluppatori",
"dev.forceReload": "Ricarica forzata",
"dev.openStore": "Apri il file di archiviazione",
"dev.refreshMenu": "Aggiorna menu",
"dev.reload": "Ricarica",
"dev.title": "Sviluppo",
"edit.copy": "Copia",
"edit.cut": "Taglia",
"edit.delete": "Elimina",
"edit.paste": "Incolla",
"edit.redo": "Ripeti",
"edit.selectAll": "Seleziona tutto",
"edit.speech": "Voce",
"edit.startSpeaking": "Inizia a leggere",
"edit.stopSpeaking": "Ferma la lettura",
"edit.title": "Modifica",
"edit.undo": "Annulla",
"file.preferences": "Preferenze",
"file.quit": "Esci",
"file.title": "File",
"help.about": "Informazioni",
"help.githubRepo": "Repository GitHub",
"help.reportIssue": "Segnala un problema",
"help.title": "Aiuto",
"help.visitWebsite": "Visita il sito ufficiale",
"macOS.about": "Informazioni su {{appName}}",
"macOS.devTools": "Strumenti per sviluppatori LobeHub",
"macOS.hide": "Nascondi {{appName}}",
"macOS.hideOthers": "Nascondi altri",
"macOS.preferences": "Impostazioni...",
"macOS.services": "Servizi",
"macOS.unhide": "Mostra tutto",
"tray.open": "Apri {{appName}}",
"tray.quit": "Esci",
"tray.show": "Mostra {{appName}}",
"view.forceReload": "Ricarica forzata",
"view.reload": "Ricarica",
"view.resetZoom": "Reimposta zoom",
"view.title": "Visualizza",
"view.toggleFullscreen": "Attiva/disattiva schermo intero",
"view.zoomIn": "Ingrandisci",
"view.zoomOut": "Riduci",
"window.bringAllToFront": "Porta tutte le finestre in primo piano",
"window.close": "Chiudi",
"window.front": "Porta tutte le finestre in primo piano",
"window.minimize": "Minimizza",
"window.title": "Finestra",
"window.toggleFullscreen": "Attiva/disattiva schermo intero",
"window.zoom": "Zoom"
}
"common": {
"checkUpdates": "Controlla aggiornamenti..."
},
"dev": {
"devPanel": "Pannello sviluppatore",
"devTools": "Strumenti per sviluppatori",
"forceReload": "Ricarica forzata",
"openStore": "Apri il file di archiviazione",
"refreshMenu": "Aggiorna menu",
"reload": "Ricarica",
"title": "Sviluppo"
},
"edit": {
"copy": "Copia",
"cut": "Taglia",
"delete": "Elimina",
"paste": "Incolla",
"redo": "Ripeti",
"selectAll": "Seleziona tutto",
"speech": "Voce",
"startSpeaking": "Inizia a leggere",
"stopSpeaking": "Ferma la lettura",
"title": "Modifica",
"undo": "Annulla"
},
"file": {
"preferences": "Preferenze",
"quit": "Esci",
"title": "File"
},
"help": {
"about": "Informazioni",
"githubRepo": "Repository GitHub",
"reportIssue": "Segnala un problema",
"title": "Aiuto",
"visitWebsite": "Visita il sito ufficiale"
},
"macOS": {
"about": "Informazioni su {{appName}}",
"devTools": "Strumenti per sviluppatori LobeHub",
"hide": "Nascondi {{appName}}",
"hideOthers": "Nascondi altri",
"preferences": "Impostazioni...",
"services": "Servizi",
"unhide": "Mostra tutto"
},
"tray": {
"open": "Apri {{appName}}",
"quit": "Esci",
"show": "Mostra {{appName}}"
},
"view": {
"forceReload": "Ricarica forzata",
"reload": "Ricarica",
"resetZoom": "Reimposta zoom",
"title": "Visualizza",
"toggleFullscreen": "Attiva/disattiva schermo intero",
"zoomIn": "Ingrandisci",
"zoomOut": "Riduci"
},
"window": {
"bringAllToFront": "Porta tutte le finestre in primo piano",
"close": "Chiudi",
"front": "Porta tutte le finestre in primo piano",
"minimize": "Minimizza",
"title": "Finestra",
"toggleFullscreen": "Attiva/disattiva schermo intero",
"zoom": "Zoom"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "追加",
"actions.back": "戻る",
"actions.cancel": "キャンセル",
"actions.close": "閉じる",
"actions.confirm": "確認",
"actions.delete": "削除",
"actions.edit": "編集",
"actions.more": "もっと見る",
"actions.next": "次へ",
"actions.ok": "OK",
"actions.previous": "前へ",
"actions.refresh": "更新",
"actions.remove": "削除",
"actions.retry": "再試行",
"actions.save": "保存",
"actions.search": "検索",
"actions.submit": "送信",
"app.description": "あなたのAIアシスタント協力プラットフォーム",
"app.name": "LobeHub",
"status.error": "エラー",
"status.info": "情報",
"status.loading": "読み込み中",
"status.success": "成功",
"status.warning": "警告"
}
"actions": {
"add": "追加",
"back": "戻る",
"cancel": "キャンセル",
"close": "閉じる",
"confirm": "確認",
"delete": "削除",
"edit": "編集",
"more": "もっと見る",
"next": "次へ",
"ok": "OK",
"previous": "前へ",
"refresh": "更新",
"remove": "削除",
"retry": "再試行",
"save": "保存",
"search": "検索",
"submit": "送信"
},
"app": {
"description": "あなたのAIアシスタント協力プラットフォーム",
"name": "LobeHub"
},
"status": {
"error": "エラー",
"info": "情報",
"loading": "読み込み中",
"success": "成功",
"warning": "警告"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "確定",
"about.detail": "大規模言語モデルに基づくチャットアプリ",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "について",
"confirm.cancel": "キャンセル",
"confirm.no": "いいえ",
"confirm.title": "確認",
"confirm.yes": "はい",
"error.button": "確定",
"error.detail": "操作中にエラーが発生しました。後で再試行してください。",
"error.message": "エラーが発生しました",
"error.title": "エラー",
"update.downloadAndInstall": "ダウンロードしてインストール",
"update.downloadComplete": "ダウンロード完了",
"update.downloadCompleteMessage": "更新パッケージのダウンロードが完了しました。今すぐインストールしますか?",
"update.installLater": "後でインストール",
"update.installNow": "今すぐインストール",
"update.later": "後でリマインド",
"update.newVersion": "新しいバージョンが見つかりました",
"update.newVersionAvailable": "新しいバージョンが見つかりました: {{version}}",
"update.skipThisVersion": "このバージョンをスキップ"
}
"about": {
"button": "確定",
"detail": "大規模言語モデルに基づくチャットアプリ",
"message": "{{appName}} {{appVersion}}",
"title": "について"
},
"confirm": {
"cancel": "キャンセル",
"no": "いいえ",
"title": "確認",
"yes": "はい"
},
"error": {
"button": "確定",
"detail": "操作中にエラーが発生しました。後で再試行してください。",
"message": "エラーが発生しました",
"title": "エラー"
},
"update": {
"downloadAndInstall": "ダウンロードしてインストール",
"downloadComplete": "ダウンロード完了",
"downloadCompleteMessage": "更新パッケージのダウンロードが完了しました。今すぐインストールしますか?",
"installLater": "後でインストール",
"installNow": "今すぐインストール",
"later": "後でリマインド",
"newVersion": "新しいバージョンが見つかりました",
"newVersionAvailable": "新しいバージョンが見つかりました: {{version}}",
"skipThisVersion": "このバージョンをスキップ"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "更新を確認しています...",
"dev.devPanel": "開発者パネル",
"dev.devTools": "開発者ツール",
"dev.forceReload": "強制再読み込み",
"dev.openStore": "ストレージファイルを開く",
"dev.refreshMenu": "メニューを更新",
"dev.reload": "再読み込み",
"dev.title": "開発",
"edit.copy": "コピー",
"edit.cut": "切り取り",
"edit.delete": "削除",
"edit.paste": "貼り付け",
"edit.redo": "やり直し",
"edit.selectAll": "すべて選択",
"edit.speech": "音声",
"edit.startSpeaking": "読み上げ開始",
"edit.stopSpeaking": "読み上げ停止",
"edit.title": "編集",
"edit.undo": "元に戻す",
"file.preferences": "設定",
"file.quit": "終了",
"file.title": "ファイル",
"help.about": "について",
"help.githubRepo": "GitHub リポジトリ",
"help.reportIssue": "問題を報告",
"help.title": "ヘルプ",
"help.visitWebsite": "公式ウェブサイトを訪問",
"macOS.about": "{{appName}} について",
"macOS.devTools": "LobeHub 開発者ツール",
"macOS.hide": "{{appName}} を隠す",
"macOS.hideOthers": "他を隠す",
"macOS.preferences": "環境設定...",
"macOS.services": "サービス",
"macOS.unhide": "すべて表示",
"tray.open": "{{appName}} を開く",
"tray.quit": "終了",
"tray.show": "{{appName}} を表示",
"view.forceReload": "強制再読み込み",
"view.reload": "再読み込み",
"view.resetZoom": "ズームをリセット",
"view.title": "ビュー",
"view.toggleFullscreen": "フルスクリーン切替",
"view.zoomIn": "ズームイン",
"view.zoomOut": "ズームアウト",
"window.bringAllToFront": "すべてのウィンドウを前面に",
"window.close": "閉じる",
"window.front": "すべてのウィンドウを前面に",
"window.minimize": "最小化",
"window.title": "ウィンドウ",
"window.toggleFullscreen": "フルスクリーン切替",
"window.zoom": "ズーム"
}
"common": {
"checkUpdates": "更新を確認しています..."
},
"dev": {
"devPanel": "開発者パネル",
"devTools": "開発者ツール",
"forceReload": "強制再読み込み",
"openStore": "ストレージファイルを開く",
"refreshMenu": "メニューを更新",
"reload": "再読み込み",
"title": "開発"
},
"edit": {
"copy": "コピー",
"cut": "切り取り",
"delete": "削除",
"paste": "貼り付け",
"redo": "やり直し",
"selectAll": "すべて選択",
"speech": "音声",
"startSpeaking": "読み上げ開始",
"stopSpeaking": "読み上げ停止",
"title": "編集",
"undo": "元に戻す"
},
"file": {
"preferences": "設定",
"quit": "終了",
"title": "ファイル"
},
"help": {
"about": "について",
"githubRepo": "GitHub リポジトリ",
"reportIssue": "問題を報告",
"title": "ヘルプ",
"visitWebsite": "公式ウェブサイトを訪問"
},
"macOS": {
"about": "{{appName}} について",
"devTools": "LobeHub 開発者ツール",
"hide": "{{appName}} を隠す",
"hideOthers": "他を隠す",
"preferences": "環境設定...",
"services": "サービス",
"unhide": "すべて表示"
},
"tray": {
"open": "{{appName}} を開く",
"quit": "終了",
"show": "{{appName}} を表示"
},
"view": {
"forceReload": "強制再読み込み",
"reload": "再読み込み",
"resetZoom": "ズームをリセット",
"title": "ビュー",
"toggleFullscreen": "フルスクリーン切替",
"zoomIn": "ズームイン",
"zoomOut": "ズームアウト"
},
"window": {
"bringAllToFront": "すべてのウィンドウを前面に",
"close": "閉じる",
"front": "すべてのウィンドウを前面に",
"minimize": "最小化",
"title": "ウィンドウ",
"toggleFullscreen": "フルスクリーン切替",
"zoom": "ズーム"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "추가",
"actions.back": "뒤로",
"actions.cancel": "취소",
"actions.close": "닫기",
"actions.confirm": "확인",
"actions.delete": "삭제",
"actions.edit": "편집",
"actions.more": "더보기",
"actions.next": "다음",
"actions.ok": "확인",
"actions.previous": "이전",
"actions.refresh": "새로 고침",
"actions.remove": "제거",
"actions.retry": "다시 시도",
"actions.save": "저장",
"actions.search": "검색",
"actions.submit": "제출",
"app.description": "당신의 AI 비서 협업 플랫폼",
"app.name": "LobeHub",
"status.error": "오류",
"status.info": "정보",
"status.loading": "로딩 중",
"status.success": "성공",
"status.warning": "경고"
}
"actions": {
"add": "추가",
"back": "뒤로",
"cancel": "취소",
"close": "닫기",
"confirm": "확인",
"delete": "삭제",
"edit": "편집",
"more": "더보기",
"next": "다음",
"ok": "확인",
"previous": "이전",
"refresh": "새로 고침",
"remove": "제거",
"retry": "다시 시도",
"save": "저장",
"search": "검색",
"submit": "제출"
},
"app": {
"description": "당신의 AI 비서 협업 플랫폼",
"name": "LobeHub"
},
"status": {
"error": "오류",
"info": "정보",
"loading": "로딩 중",
"success": "성공",
"warning": "경고"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "확인",
"about.detail": "대형 언어 모델 기반의 채팅 애플리케이션",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "정보",
"confirm.cancel": "취소",
"confirm.no": "아니요",
"confirm.title": "확인",
"confirm.yes": "",
"error.button": "확인",
"error.detail": "작업 중 오류가 발생했습니다. 나중에 다시 시도해 주세요.",
"error.message": "오류 발생",
"error.title": "오류",
"update.downloadAndInstall": "다운로드 및 설치",
"update.downloadComplete": "다운로드 완료",
"update.downloadCompleteMessage": "업데이트 패키지가 다운로드 완료되었습니다. 지금 설치하시겠습니까?",
"update.installLater": "나중에 설치",
"update.installNow": "지금 설치",
"update.later": "나중에 알림",
"update.newVersion": "새 버전 발견",
"update.newVersionAvailable": "새 버전 발견: {{version}}",
"update.skipThisVersion": "이 버전 건너뛰기"
}
"about": {
"button": "확인",
"detail": "대형 언어 모델 기반의 채팅 애플리케이션",
"message": "{{appName}} {{appVersion}}",
"title": "정보"
},
"confirm": {
"cancel": "취소",
"no": "아니요",
"title": "확인",
"yes": "예"
},
"error": {
"button": "확인",
"detail": "작업 중 오류가 발생했습니다. 나중에 다시 시도해 주세요.",
"message": "오류 발생",
"title": "오류"
},
"update": {
"downloadAndInstall": "다운로드 및 설치",
"downloadComplete": "다운로드 완료",
"downloadCompleteMessage": "업데이트 패키지가 다운로드 완료되었습니다. 지금 설치하시겠습니까?",
"installLater": "나중에 설치",
"installNow": "지금 설치",
"later": "나중에 알림",
"newVersion": "새 버전 발견",
"newVersionAvailable": "새 버전 발견: {{version}}",
"skipThisVersion": "이 버전 건너뛰기"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "업데이트 확인 중...",
"dev.devPanel": "개발자 패널",
"dev.devTools": "개발자 도구",
"dev.forceReload": "강제 새로 고침",
"dev.openStore": "저장 파일 열기",
"dev.refreshMenu": "메뉴 새로 고침",
"dev.reload": "새로 고침",
"dev.title": "개발",
"edit.copy": "복사",
"edit.cut": "잘라내기",
"edit.delete": "삭제",
"edit.paste": "붙여넣기",
"edit.redo": "다시 실행",
"edit.selectAll": "모두 선택",
"edit.speech": "음성",
"edit.startSpeaking": "읽기 시작",
"edit.stopSpeaking": "읽기 중지",
"edit.title": "편집",
"edit.undo": "실행 취소",
"file.preferences": "환경 설정",
"file.quit": "종료",
"file.title": "파일",
"help.about": "정보",
"help.githubRepo": "GitHub 저장소",
"help.reportIssue": "문제 보고",
"help.title": "도움말",
"help.visitWebsite": "웹사이트 방문",
"macOS.about": "{{appName}} 정보",
"macOS.devTools": "LobeHub 개발자 도구",
"macOS.hide": "{{appName}} 숨기기",
"macOS.hideOthers": "다른 것 숨기기",
"macOS.preferences": "환경 설정...",
"macOS.services": "서비스",
"macOS.unhide": "모두 표시",
"tray.open": "{{appName}} 열기",
"tray.quit": "종료",
"tray.show": "{{appName}} 표시",
"view.forceReload": "강제 새로 고침",
"view.reload": "새로 고침",
"view.resetZoom": "줌 초기화",
"view.title": "보기",
"view.toggleFullscreen": "전체 화면 전환",
"view.zoomIn": "확대",
"view.zoomOut": "축소",
"window.bringAllToFront": "모든 창 앞으로 가져오기",
"window.close": "닫기",
"window.front": "모든 창 앞으로 가져오기",
"window.minimize": "최소화",
"window.title": "",
"window.toggleFullscreen": "전체 화면 전환",
"window.zoom": "줌"
}
"common": {
"checkUpdates": "업데이트 확인 중..."
},
"dev": {
"devPanel": "개발자 패널",
"devTools": "개발자 도구",
"forceReload": "강제 새로 고침",
"openStore": "저장 파일 열기",
"refreshMenu": "메뉴 새로 고침",
"reload": "새로 고침",
"title": "개발"
},
"edit": {
"copy": "복사",
"cut": "잘라내기",
"delete": "삭제",
"paste": "붙여넣기",
"redo": "다시 실행",
"selectAll": "모두 선택",
"speech": "음성",
"startSpeaking": "읽기 시작",
"stopSpeaking": "읽기 중지",
"title": "편집",
"undo": "실행 취소"
},
"file": {
"preferences": "환경 설정",
"quit": "종료",
"title": "파일"
},
"help": {
"about": "정보",
"githubRepo": "GitHub 저장소",
"reportIssue": "문제 보고",
"title": "도움말",
"visitWebsite": "웹사이트 방문"
},
"macOS": {
"about": "{{appName}} 정보",
"devTools": "LobeHub 개발자 도구",
"hide": "{{appName}} 숨기기",
"hideOthers": "다른 것 숨기기",
"preferences": "환경 설정...",
"services": "서비스",
"unhide": "모두 표시"
},
"tray": {
"open": "{{appName}} 열기",
"quit": "종료",
"show": "{{appName}} 표시"
},
"view": {
"forceReload": "강제 새로 고침",
"reload": "새로 고침",
"resetZoom": "줌 초기화",
"title": "보기",
"toggleFullscreen": "전체 화면 전환",
"zoomIn": "확대",
"zoomOut": "축소"
},
"window": {
"bringAllToFront": "모든 창 앞으로 가져오기",
"close": "닫기",
"front": "모든 창 앞으로 가져오기",
"minimize": "최소화",
"title": "창",
"toggleFullscreen": "전체 화면 전환",
"zoom": "줌"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Toevoegen",
"actions.back": "Terug",
"actions.cancel": "Annuleren",
"actions.close": "Sluiten",
"actions.confirm": "Bevestigen",
"actions.delete": "Verwijderen",
"actions.edit": "Bewerken",
"actions.more": "Meer",
"actions.next": "Volgende stap",
"actions.ok": "OK",
"actions.previous": "Vorige stap",
"actions.refresh": "Vernieuwen",
"actions.remove": "Verwijderen",
"actions.retry": "Opnieuw proberen",
"actions.save": "Opslaan",
"actions.search": "Zoeken",
"actions.submit": "Indienen",
"app.description": "Jouw AI-assistent samenwerkingsplatform",
"app.name": "LobeHub",
"status.error": "Fout",
"status.info": "Informatie",
"status.loading": "Laden",
"status.success": "Succes",
"status.warning": "Waarschuwing"
}
"actions": {
"add": "Toevoegen",
"back": "Terug",
"cancel": "Annuleren",
"close": "Sluiten",
"confirm": "Bevestigen",
"delete": "Verwijderen",
"edit": "Bewerken",
"more": "Meer",
"next": "Volgende stap",
"ok": "OK",
"previous": "Vorige stap",
"refresh": "Vernieuwen",
"remove": "Verwijderen",
"retry": "Opnieuw proberen",
"save": "Opslaan",
"search": "Zoeken",
"submit": "Indienen"
},
"app": {
"description": "Jouw AI-assistent samenwerkingsplatform",
"name": "LobeHub"
},
"status": {
"error": "Fout",
"info": "Informatie",
"loading": "Laden",
"success": "Succes",
"warning": "Waarschuwing"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Bevestigen",
"about.detail": "Een chatapplicatie gebaseerd op een groot taalmodel",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Over",
"confirm.cancel": "Annuleren",
"confirm.no": "Nee",
"confirm.title": "Bevestigen",
"confirm.yes": "Ja",
"error.button": "Bevestigen",
"error.detail": "Er is een fout opgetreden tijdens de operatie, probeer het later opnieuw",
"error.message": "Er is een fout opgetreden",
"error.title": "Fout",
"update.downloadAndInstall": "Downloaden en installeren",
"update.downloadComplete": "Download voltooid",
"update.downloadCompleteMessage": "Het updatepakket is gedownload, wilt u het nu installeren?",
"update.installLater": "Later installeren",
"update.installNow": "Nu installeren",
"update.later": "Later herinneren",
"update.newVersion": "Nieuwe versie gevonden",
"update.newVersionAvailable": "Nieuwe versie beschikbaar: {{version}}",
"update.skipThisVersion": "Deze versie overslaan"
}
"about": {
"button": "Bevestigen",
"detail": "Een chatapplicatie gebaseerd op een groot taalmodel",
"message": "{{appName}} {{appVersion}}",
"title": "Over"
},
"confirm": {
"cancel": "Annuleren",
"no": "Nee",
"title": "Bevestigen",
"yes": "Ja"
},
"error": {
"button": "Bevestigen",
"detail": "Er is een fout opgetreden tijdens de operatie, probeer het later opnieuw",
"message": "Er is een fout opgetreden",
"title": "Fout"
},
"update": {
"downloadAndInstall": "Downloaden en installeren",
"downloadComplete": "Download voltooid",
"downloadCompleteMessage": "Het updatepakket is gedownload, wilt u het nu installeren?",
"installLater": "Later installeren",
"installNow": "Nu installeren",
"later": "Later herinneren",
"newVersion": "Nieuwe versie gevonden",
"newVersionAvailable": "Nieuwe versie beschikbaar: {{version}}",
"skipThisVersion": "Deze versie overslaan"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Updates controleren...",
"dev.devPanel": "Ontwikkelaarspaneel",
"dev.devTools": "Ontwikkelaarstools",
"dev.forceReload": "Forceer herladen",
"dev.openStore": "Open opslagbestand",
"dev.refreshMenu": "Menu verversen",
"dev.reload": "Herladen",
"dev.title": "Ontwikkeling",
"edit.copy": "Kopiëren",
"edit.cut": "Knippen",
"edit.delete": "Verwijderen",
"edit.paste": "Plakken",
"edit.redo": "Opnieuw doen",
"edit.selectAll": "Alles selecteren",
"edit.speech": "Spraak",
"edit.startSpeaking": "Begin met voorlezen",
"edit.stopSpeaking": "Stop met voorlezen",
"edit.title": "Bewerken",
"edit.undo": "Ongedaan maken",
"file.preferences": "Voorkeuren",
"file.quit": "Afsluiten",
"file.title": "Bestand",
"help.about": "Over",
"help.githubRepo": "GitHub-repo",
"help.reportIssue": "Probleem melden",
"help.title": "Hulp",
"help.visitWebsite": "Bezoek de website",
"macOS.about": "Over {{appName}}",
"macOS.devTools": "LobeHub Ontwikkelaarstools",
"macOS.hide": "Verberg {{appName}}",
"macOS.hideOthers": "Verberg anderen",
"macOS.preferences": "Voorkeuren...",
"macOS.services": "Diensten",
"macOS.unhide": "Toon alles",
"tray.open": "Open {{appName}}",
"tray.quit": "Afsluiten",
"tray.show": "Toon {{appName}}",
"view.forceReload": "Forceer herladen",
"view.reload": "Herladen",
"view.resetZoom": "Zoom resetten",
"view.title": "Weergave",
"view.toggleFullscreen": "Schakel volledig scherm in/uit",
"view.zoomIn": "Inzoomen",
"view.zoomOut": "Uitzoomen",
"window.bringAllToFront": "Breng alle vensters naar voren",
"window.close": "Sluiten",
"window.front": "Breng alle vensters naar voren",
"window.minimize": "Minimaliseren",
"window.title": "Venster",
"window.toggleFullscreen": "Schakel volledig scherm in/uit",
"window.zoom": "Inzoomen"
}
"common": {
"checkUpdates": "Updates controleren..."
},
"dev": {
"devPanel": "Ontwikkelaarspaneel",
"devTools": "Ontwikkelaarstools",
"forceReload": "Forceer herladen",
"openStore": "Open opslagbestand",
"refreshMenu": "Menu verversen",
"reload": "Herladen",
"title": "Ontwikkeling"
},
"edit": {
"copy": "Kopiëren",
"cut": "Knippen",
"delete": "Verwijderen",
"paste": "Plakken",
"redo": "Opnieuw doen",
"selectAll": "Alles selecteren",
"speech": "Spraak",
"startSpeaking": "Begin met voorlezen",
"stopSpeaking": "Stop met voorlezen",
"title": "Bewerken",
"undo": "Ongedaan maken"
},
"file": {
"preferences": "Voorkeuren",
"quit": "Afsluiten",
"title": "Bestand"
},
"help": {
"about": "Over",
"githubRepo": "GitHub-repo",
"reportIssue": "Probleem melden",
"title": "Hulp",
"visitWebsite": "Bezoek de website"
},
"macOS": {
"about": "Over {{appName}}",
"devTools": "LobeHub Ontwikkelaarstools",
"hide": "Verberg {{appName}}",
"hideOthers": "Verberg anderen",
"preferences": "Voorkeuren...",
"services": "Diensten",
"unhide": "Toon alles"
},
"tray": {
"open": "Open {{appName}}",
"quit": "Afsluiten",
"show": "Toon {{appName}}"
},
"view": {
"forceReload": "Forceer herladen",
"reload": "Herladen",
"resetZoom": "Zoom resetten",
"title": "Weergave",
"toggleFullscreen": "Schakel volledig scherm in/uit",
"zoomIn": "Inzoomen",
"zoomOut": "Uitzoomen"
},
"window": {
"bringAllToFront": "Breng alle vensters naar voren",
"close": "Sluiten",
"front": "Breng alle vensters naar voren",
"minimize": "Minimaliseren",
"title": "Venster",
"toggleFullscreen": "Schakel volledig scherm in/uit",
"zoom": "Inzoomen"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Dodaj",
"actions.back": "Wstecz",
"actions.cancel": "Anuluj",
"actions.close": "Zamknij",
"actions.confirm": "Potwierdź",
"actions.delete": "Usuń",
"actions.edit": "Edytuj",
"actions.more": "Więcej",
"actions.next": "Dalej",
"actions.ok": "OK",
"actions.previous": "Cofnij",
"actions.refresh": "Odśwież",
"actions.remove": "Usuń",
"actions.retry": "Spróbuj ponownie",
"actions.save": "Zapisz",
"actions.search": "Szukaj",
"actions.submit": "Wyślij",
"app.description": "Twoja platforma współpracy z asystentem AI",
"app.name": "LobeHub",
"status.error": "Błąd",
"status.info": "Informacja",
"status.loading": "Ładowanie",
"status.success": "Sukces",
"status.warning": "Ostrzeżenie"
}
"actions": {
"add": "Dodaj",
"back": "Wstecz",
"cancel": "Anuluj",
"close": "Zamknij",
"confirm": "Potwierdź",
"delete": "Usuń",
"edit": "Edytuj",
"more": "Więcej",
"next": "Dalej",
"ok": "OK",
"previous": "Cofnij",
"refresh": "Odśwież",
"remove": "Usuń",
"retry": "Spróbuj ponownie",
"save": "Zapisz",
"search": "Szukaj",
"submit": "Wyślij"
},
"app": {
"description": "Twoja platforma współpracy z asystentem AI",
"name": "LobeHub"
},
"status": {
"error": "Błąd",
"info": "Informacja",
"loading": "Ładowanie",
"success": "Sukces",
"warning": "Ostrzeżenie"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "OK",
"about.detail": "Aplikacja czatu oparta na dużym modelu językowym",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "O aplikacji",
"confirm.cancel": "Anuluj",
"confirm.no": "Nie",
"confirm.title": "Potwierdzenie",
"confirm.yes": "Tak",
"error.button": "OK",
"error.detail": "Wystąpił błąd podczas operacji, spróbuj ponownie później",
"error.message": "Wystąpił błąd",
"error.title": "Błąd",
"update.downloadAndInstall": "Pobierz i zainstaluj",
"update.downloadComplete": "Pobieranie zakończone",
"update.downloadCompleteMessage": "Pakiet aktualizacji został pobrany, czy chcesz go teraz zainstalować?",
"update.installLater": "Zainstaluj później",
"update.installNow": "Zainstaluj teraz",
"update.later": "Przypomnij później",
"update.newVersion": "Nowa wersja dostępna",
"update.newVersionAvailable": "Znaleziono nową wersję: {{version}}",
"update.skipThisVersion": "Pomiń tę wersję"
}
"about": {
"button": "OK",
"detail": "Aplikacja czatu oparta na dużym modelu językowym",
"message": "{{appName}} {{appVersion}}",
"title": "O aplikacji"
},
"confirm": {
"cancel": "Anuluj",
"no": "Nie",
"title": "Potwierdzenie",
"yes": "Tak"
},
"error": {
"button": "OK",
"detail": "Wystąpił błąd podczas operacji, spróbuj ponownie później",
"message": "Wystąpił błąd",
"title": "Błąd"
},
"update": {
"downloadAndInstall": "Pobierz i zainstaluj",
"downloadComplete": "Pobieranie zakończone",
"downloadCompleteMessage": "Pakiet aktualizacji został pobrany, czy chcesz go teraz zainstalować?",
"installLater": "Zainstaluj później",
"installNow": "Zainstaluj teraz",
"later": "Przypomnij później",
"newVersion": "Nowa wersja dostępna",
"newVersionAvailable": "Znaleziono nową wersję: {{version}}",
"skipThisVersion": "Pomiń tę wersję"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Sprawdzanie aktualizacji...",
"dev.devPanel": "Panel dewelopera",
"dev.devTools": "Narzędzia dewelopera",
"dev.forceReload": "Wymuś ponowne załadowanie",
"dev.openStore": "Otwórz plik magazynu",
"dev.refreshMenu": "Odśwież menu",
"dev.reload": "Przeładuj",
"dev.title": "Rozwój",
"edit.copy": "Kopiuj",
"edit.cut": "Wytnij",
"edit.delete": "Usuń",
"edit.paste": "Wklej",
"edit.redo": "Ponów",
"edit.selectAll": "Zaznacz wszystko",
"edit.speech": "Mowa",
"edit.startSpeaking": "Rozpocznij czytanie",
"edit.stopSpeaking": "Zatrzymaj czytanie",
"edit.title": "Edycja",
"edit.undo": "Cofnij",
"file.preferences": "Preferencje",
"file.quit": "Zakończ",
"file.title": "Plik",
"help.about": "O",
"help.githubRepo": "Repozytorium GitHub",
"help.reportIssue": "Zgłoś problem",
"help.title": "Pomoc",
"help.visitWebsite": "Odwiedź stronę internetową",
"macOS.about": "O {{appName}}",
"macOS.devTools": "Narzędzia dewelopera LobeHub",
"macOS.hide": "Ukryj {{appName}}",
"macOS.hideOthers": "Ukryj inne",
"macOS.preferences": "Ustawienia...",
"macOS.services": "Usługi",
"macOS.unhide": "Pokaż wszystko",
"tray.open": "Otwórz {{appName}}",
"tray.quit": "Zakończ",
"tray.show": "Pokaż {{appName}}",
"view.forceReload": "Wymuś ponowne załadowanie",
"view.reload": "Przeładuj",
"view.resetZoom": "Zresetuj powiększenie",
"view.title": "Widok",
"view.toggleFullscreen": "Przełącz tryb pełnoekranowy",
"view.zoomIn": "Powiększ",
"view.zoomOut": "Pomniejsz",
"window.bringAllToFront": "Przenieś wszystkie okna na wierzch",
"window.close": "Zamknij",
"window.front": "Przenieś wszystkie okna na wierzch",
"window.minimize": "Zminimalizuj",
"window.title": "Okno",
"window.toggleFullscreen": "Przełącz tryb pełnoekranowy",
"window.zoom": "Powiększenie"
}
"common": {
"checkUpdates": "Sprawdzanie aktualizacji..."
},
"dev": {
"devPanel": "Panel dewelopera",
"devTools": "Narzędzia dewelopera",
"forceReload": "Wymuś ponowne załadowanie",
"openStore": "Otwórz plik magazynu",
"refreshMenu": "Odśwież menu",
"reload": "Przeładuj",
"title": "Rozwój"
},
"edit": {
"copy": "Kopiuj",
"cut": "Wytnij",
"delete": "Usuń",
"paste": "Wklej",
"redo": "Ponów",
"selectAll": "Zaznacz wszystko",
"speech": "Mowa",
"startSpeaking": "Rozpocznij czytanie",
"stopSpeaking": "Zatrzymaj czytanie",
"title": "Edycja",
"undo": "Cofnij"
},
"file": {
"preferences": "Preferencje",
"quit": "Zakończ",
"title": "Plik"
},
"help": {
"about": "O",
"githubRepo": "Repozytorium GitHub",
"reportIssue": "Zgłoś problem",
"title": "Pomoc",
"visitWebsite": "Odwiedź stronę internetową"
},
"macOS": {
"about": "O {{appName}}",
"devTools": "Narzędzia dewelopera LobeHub",
"hide": "Ukryj {{appName}}",
"hideOthers": "Ukryj inne",
"preferences": "Ustawienia...",
"services": "Usługi",
"unhide": "Pokaż wszystko"
},
"tray": {
"open": "Otwórz {{appName}}",
"quit": "Zakończ",
"show": "Pokaż {{appName}}"
},
"view": {
"forceReload": "Wymuś ponowne załadowanie",
"reload": "Przeładuj",
"resetZoom": "Zresetuj powiększenie",
"title": "Widok",
"toggleFullscreen": "Przełącz tryb pełnoekranowy",
"zoomIn": "Powiększ",
"zoomOut": "Pomniejsz"
},
"window": {
"bringAllToFront": "Przenieś wszystkie okna na wierzch",
"close": "Zamknij",
"front": "Przenieś wszystkie okna na wierzch",
"minimize": "Zminimalizuj",
"title": "Okno",
"toggleFullscreen": "Przełącz tryb pełnoekranowy",
"zoom": "Powiększenie"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Adicionar",
"actions.back": "Voltar",
"actions.cancel": "Cancelar",
"actions.close": "Fechar",
"actions.confirm": "Confirmar",
"actions.delete": "Excluir",
"actions.edit": "Editar",
"actions.more": "Mais",
"actions.next": "Próximo",
"actions.ok": "OK",
"actions.previous": "Anterior",
"actions.refresh": "Atualizar",
"actions.remove": "Remover",
"actions.retry": "Tentar novamente",
"actions.save": "Salvar",
"actions.search": "Pesquisar",
"actions.submit": "Enviar",
"app.description": "Sua plataforma de colaboração com assistente de IA",
"app.name": "LobeHub",
"status.error": "Erro",
"status.info": "Informação",
"status.loading": "Carregando",
"status.success": "Sucesso",
"status.warning": "Aviso"
}
"actions": {
"add": "Adicionar",
"back": "Voltar",
"cancel": "Cancelar",
"close": "Fechar",
"confirm": "Confirmar",
"delete": "Excluir",
"edit": "Editar",
"more": "Mais",
"next": "Próximo",
"ok": "OK",
"previous": "Anterior",
"refresh": "Atualizar",
"remove": "Remover",
"retry": "Tentar novamente",
"save": "Salvar",
"search": "Pesquisar",
"submit": "Enviar"
},
"app": {
"description": "Sua plataforma de colaboração com assistente de IA",
"name": "LobeHub"
},
"status": {
"error": "Erro",
"info": "Informação",
"loading": "Carregando",
"success": "Sucesso",
"warning": "Aviso"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Confirmar",
"about.detail": "Um aplicativo de chat baseado em um grande modelo de linguagem",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Sobre",
"confirm.cancel": "Cancelar",
"confirm.no": "Não",
"confirm.title": "Confirmar",
"confirm.yes": "Sim",
"error.button": "Confirmar",
"error.detail": "Ocorreu um erro durante a operação, por favor tente novamente mais tarde",
"error.message": "Ocorreu um erro",
"error.title": "Erro",
"update.downloadAndInstall": "Baixar e instalar",
"update.downloadComplete": "Download completo",
"update.downloadCompleteMessage": "O pacote de atualização foi baixado com sucesso, deseja instalá-lo agora?",
"update.installLater": "Instalar depois",
"update.installNow": "Instalar agora",
"update.later": "Lembrar mais tarde",
"update.newVersion": "Nova versão disponível",
"update.newVersionAvailable": "Nova versão encontrada: {{version}}",
"update.skipThisVersion": "Ignorar esta versão"
}
"about": {
"button": "Confirmar",
"detail": "Um aplicativo de chat baseado em um grande modelo de linguagem",
"message": "{{appName}} {{appVersion}}",
"title": "Sobre"
},
"confirm": {
"cancel": "Cancelar",
"no": "Não",
"title": "Confirmar",
"yes": "Sim"
},
"error": {
"button": "Confirmar",
"detail": "Ocorreu um erro durante a operação, por favor tente novamente mais tarde",
"message": "Ocorreu um erro",
"title": "Erro"
},
"update": {
"downloadAndInstall": "Baixar e instalar",
"downloadComplete": "Download completo",
"downloadCompleteMessage": "O pacote de atualização foi baixado com sucesso, deseja instalá-lo agora?",
"installLater": "Instalar depois",
"installNow": "Instalar agora",
"later": "Lembrar mais tarde",
"newVersion": "Nova versão disponível",
"newVersionAvailable": "Nova versão encontrada: {{version}}",
"skipThisVersion": "Ignorar esta versão"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Verificando atualizações...",
"dev.devPanel": "Painel do Desenvolvedor",
"dev.devTools": "Ferramentas do Desenvolvedor",
"dev.forceReload": "Recarregar Forçadamente",
"dev.openStore": "Abrir arquivo de armazenamento",
"dev.refreshMenu": "Atualizar menu",
"dev.reload": "Recarregar",
"dev.title": "Desenvolvimento",
"edit.copy": "Copiar",
"edit.cut": "Cortar",
"edit.delete": "Excluir",
"edit.paste": "Colar",
"edit.redo": "Refazer",
"edit.selectAll": "Selecionar Tudo",
"edit.speech": "Fala",
"edit.startSpeaking": "Começar a Ler",
"edit.stopSpeaking": "Parar de Ler",
"edit.title": "Edição",
"edit.undo": "Desfazer",
"file.preferences": "Preferências",
"file.quit": "Sair",
"file.title": "Arquivo",
"help.about": "Sobre",
"help.githubRepo": "Repositório do GitHub",
"help.reportIssue": "Reportar Problema",
"help.title": "Ajuda",
"help.visitWebsite": "Visitar o Site",
"macOS.about": "Sobre {{appName}}",
"macOS.devTools": "Ferramentas do Desenvolvedor LobeHub",
"macOS.hide": "Ocultar {{appName}}",
"macOS.hideOthers": "Ocultar Outros",
"macOS.preferences": "Configurações...",
"macOS.services": "Serviços",
"macOS.unhide": "Mostrar Todos",
"tray.open": "Abrir {{appName}}",
"tray.quit": "Sair",
"tray.show": "Mostrar {{appName}}",
"view.forceReload": "Recarregar Forçadamente",
"view.reload": "Recarregar",
"view.resetZoom": "Redefinir Zoom",
"view.title": "Visualização",
"view.toggleFullscreen": "Alternar Tela Cheia",
"view.zoomIn": "Aumentar",
"view.zoomOut": "Diminuir",
"window.bringAllToFront": "Trazer Todas as Janelas para Frente",
"window.close": "Fechar",
"window.front": "Trazer Todas as Janelas para Frente",
"window.minimize": "Minimizar",
"window.title": "Janela",
"window.toggleFullscreen": "Alternar Tela Cheia",
"window.zoom": "Zoom"
}
"common": {
"checkUpdates": "Verificando atualizações..."
},
"dev": {
"devPanel": "Painel do Desenvolvedor",
"devTools": "Ferramentas do Desenvolvedor",
"forceReload": "Recarregar Forçadamente",
"openStore": "Abrir arquivo de armazenamento",
"refreshMenu": "Atualizar menu",
"reload": "Recarregar",
"title": "Desenvolvimento"
},
"edit": {
"copy": "Copiar",
"cut": "Cortar",
"delete": "Excluir",
"paste": "Colar",
"redo": "Refazer",
"selectAll": "Selecionar Tudo",
"speech": "Fala",
"startSpeaking": "Começar a Ler",
"stopSpeaking": "Parar de Ler",
"title": "Edição",
"undo": "Desfazer"
},
"file": {
"preferences": "Preferências",
"quit": "Sair",
"title": "Arquivo"
},
"help": {
"about": "Sobre",
"githubRepo": "Repositório do GitHub",
"reportIssue": "Reportar Problema",
"title": "Ajuda",
"visitWebsite": "Visitar o Site"
},
"macOS": {
"about": "Sobre {{appName}}",
"devTools": "Ferramentas do Desenvolvedor LobeHub",
"hide": "Ocultar {{appName}}",
"hideOthers": "Ocultar Outros",
"preferences": "Configurações...",
"services": "Serviços",
"unhide": "Mostrar Todos"
},
"tray": {
"open": "Abrir {{appName}}",
"quit": "Sair",
"show": "Mostrar {{appName}}"
},
"view": {
"forceReload": "Recarregar Forçadamente",
"reload": "Recarregar",
"resetZoom": "Redefinir Zoom",
"title": "Visualização",
"toggleFullscreen": "Alternar Tela Cheia",
"zoomIn": "Aumentar",
"zoomOut": "Diminuir"
},
"window": {
"bringAllToFront": "Trazer Todas as Janelas para Frente",
"close": "Fechar",
"front": "Trazer Todas as Janelas para Frente",
"minimize": "Minimizar",
"title": "Janela",
"toggleFullscreen": "Alternar Tela Cheia",
"zoom": "Zoom"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Добавить",
"actions.back": "Назад",
"actions.cancel": "Отмена",
"actions.close": "Закрыть",
"actions.confirm": "Подтвердить",
"actions.delete": "Удалить",
"actions.edit": "Редактировать",
"actions.more": "Больше",
"actions.next": "Далее",
"actions.ok": "ОК",
"actions.previous": "Назад",
"actions.refresh": "Обновить",
"actions.remove": "Удалить",
"actions.retry": "Повторить",
"actions.save": "Сохранить",
"actions.search": "Поиск",
"actions.submit": "Отправить",
"app.description": "Ваша платформа для совместной работы с ИИ",
"app.name": "LobeHub",
"status.error": "Ошибка",
"status.info": "Информация",
"status.loading": "Загрузка",
"status.success": "Успех",
"status.warning": "Предупреждение"
}
"actions": {
"add": "Добавить",
"back": "Назад",
"cancel": "Отмена",
"close": "Закрыть",
"confirm": "Подтвердить",
"delete": "Удалить",
"edit": "Редактировать",
"more": "Больше",
"next": "Далее",
"ok": "ОК",
"previous": "Назад",
"refresh": "Обновить",
"remove": "Удалить",
"retry": "Повторить",
"save": "Сохранить",
"search": "Поиск",
"submit": "Отправить"
},
"app": {
"description": "Ваша платформа для совместной работы с ИИ",
"name": "LobeHub"
},
"status": {
"error": "Ошибка",
"info": "Информация",
"loading": "Загрузка",
"success": "Успех",
"warning": "Предупреждение"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Подтвердить",
"about.detail": "Приложение для чата на основе большой языковой модели",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "О приложении",
"confirm.cancel": "Отмена",
"confirm.no": "Нет",
"confirm.title": "Подтверждение",
"confirm.yes": "Да",
"error.button": "Подтвердить",
"error.detail": "Произошла ошибка во время операции, пожалуйста, попробуйте позже",
"error.message": "Произошла ошибка",
"error.title": "Ошибка",
"update.downloadAndInstall": "Скачать и установить",
"update.downloadComplete": "Скачивание завершено",
"update.downloadCompleteMessage": "Обновление загружено, хотите установить сейчас?",
"update.installLater": "Установить позже",
"update.installNow": "Установить сейчас",
"update.later": "Напомнить позже",
"update.newVersion": "Обнаружена новая версия",
"update.newVersionAvailable": "Обнаружена новая версия: {{version}}",
"update.skipThisVersion": "Пропустить эту версию"
}
"about": {
"button": "Подтвердить",
"detail": "Приложение для чата на основе большой языковой модели",
"message": "{{appName}} {{appVersion}}",
"title": "О приложении"
},
"confirm": {
"cancel": "Отмена",
"no": "Нет",
"title": "Подтверждение",
"yes": "Да"
},
"error": {
"button": "Подтвердить",
"detail": "Произошла ошибка во время операции, пожалуйста, попробуйте позже",
"message": "Произошла ошибка",
"title": "Ошибка"
},
"update": {
"downloadAndInstall": "Скачать и установить",
"downloadComplete": "Скачивание завершено",
"downloadCompleteMessage": "Обновление загружено, хотите установить сейчас?",
"installLater": "Установить позже",
"installNow": "Установить сейчас",
"later": "Напомнить позже",
"newVersion": "Обнаружена новая версия",
"newVersionAvailable": "Обнаружена новая версия: {{version}}",
"skipThisVersion": "Пропустить эту версию"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Проверка обновлений...",
"dev.devPanel": "Панель разработчика",
"dev.devTools": "Инструменты разработчика",
"dev.forceReload": "Принудительная перезагрузка",
"dev.openStore": "Открыть файл хранилища",
"dev.refreshMenu": "Обновить меню",
"dev.reload": "Перезагрузить",
"dev.title": "Разработка",
"edit.copy": "Копировать",
"edit.cut": "Вырезать",
"edit.delete": "Удалить",
"edit.paste": "Вставить",
"edit.redo": "Повторить",
"edit.selectAll": "Выбрать все",
"edit.speech": "Речь",
"edit.startSpeaking": "Начать чтение",
"edit.stopSpeaking": "Остановить чтение",
"edit.title": "Редактирование",
"edit.undo": "Отменить",
"file.preferences": "Настройки",
"file.quit": "Выйти",
"file.title": "Файл",
"help.about": "О программе",
"help.githubRepo": "Репозиторий GitHub",
"help.reportIssue": "Сообщить о проблеме",
"help.title": "Помощь",
"help.visitWebsite": "Посетить сайт",
"macOS.about": "О {{appName}}",
"macOS.devTools": "Инструменты разработчика LobeHub",
"macOS.hide": "Скрыть {{appName}}",
"macOS.hideOthers": "Скрыть другие",
"macOS.preferences": "Настройки...",
"macOS.services": "Сервисы",
"macOS.unhide": "Показать все",
"tray.open": "Открыть {{appName}}",
"tray.quit": "Выйти",
"tray.show": "Показать {{appName}}",
"view.forceReload": "Принудительная перезагрузка",
"view.reload": "Перезагрузить",
"view.resetZoom": "Сбросить масштаб",
"view.title": "Вид",
"view.toggleFullscreen": "Переключить полноэкранный режим",
"view.zoomIn": "Увеличить",
"view.zoomOut": "Уменьшить",
"window.bringAllToFront": "Вывести все окна на передний план",
"window.close": "Закрыть",
"window.front": "Вывести все окна на передний план",
"window.minimize": "Свернуть",
"window.title": "Окно",
"window.toggleFullscreen": "Переключить полноэкранный режим",
"window.zoom": "Масштаб"
}
"common": {
"checkUpdates": "Проверка обновлений..."
},
"dev": {
"devPanel": "Панель разработчика",
"devTools": "Инструменты разработчика",
"forceReload": ринудительная перезагрузка",
"openStore": "Открыть файл хранилища",
"refreshMenu": "Обновить меню",
"reload": "Перезагрузить",
"title": "Разработка"
},
"edit": {
"copy": "Копировать",
"cut": "Вырезать",
"delete": "Удалить",
"paste": "Вставить",
"redo": "Повторить",
"selectAll": "Выбрать все",
"speech": "Речь",
"startSpeaking": "Начать чтение",
"stopSpeaking": "Остановить чтение",
"title": "Редактирование",
"undo": "Отменить"
},
"file": {
"preferences": "Настройки",
"quit": "Выйти",
"title": "Файл"
},
"help": {
"about": "О программе",
"githubRepo": "Репозиторий GitHub",
"reportIssue": "Сообщить о проблеме",
"title": "Помощь",
"visitWebsite": "Посетить сайт"
},
"macOS": {
"about": "О {{appName}}",
"devTools": "Инструменты разработчика LobeHub",
"hide": "Скрыть {{appName}}",
"hideOthers": "Скрыть другие",
"preferences": "Настройки...",
"services": "Сервисы",
"unhide": "Показать все"
},
"tray": {
"open": "Открыть {{appName}}",
"quit": "Выйти",
"show": "Показать {{appName}}"
},
"view": {
"forceReload": "Принудительная перезагрузка",
"reload": "Перезагрузить",
"resetZoom": "Сбросить масштаб",
"title": "Вид",
"toggleFullscreen": "Переключить полноэкранный режим",
"zoomIn": "Увеличить",
"zoomOut": "Уменьшить"
},
"window": {
"bringAllToFront": "Вывести все окна на передний план",
"close": "Закрыть",
"front": "Вывести все окна на передний план",
"minimize": "Свернуть",
"title": "Окно",
"toggleFullscreen": "Переключить полноэкранный режим",
"zoom": "Масштаб"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Ekle",
"actions.back": "Geri",
"actions.cancel": "İptal",
"actions.close": "Kapat",
"actions.confirm": "Onayla",
"actions.delete": "Sil",
"actions.edit": "Düzenle",
"actions.more": "Daha Fazla",
"actions.next": "Sonraki",
"actions.ok": "Tamam",
"actions.previous": "Önceki",
"actions.refresh": "Yenile",
"actions.remove": "Kaldır",
"actions.retry": "Yeniden Dene",
"actions.save": "Kaydet",
"actions.search": "Ara",
"actions.submit": "Gönder",
"app.description": "AI asistanınız için işbirliği platformu",
"app.name": "LobeHub",
"status.error": "Hata",
"status.info": "Bilgi",
"status.loading": "Yükleniyor",
"status.success": "Başarılı",
"status.warning": "Uyarı"
}
"actions": {
"add": "Ekle",
"back": "Geri",
"cancel": "İptal",
"close": "Kapat",
"confirm": "Onayla",
"delete": "Sil",
"edit": "Düzenle",
"more": "Daha Fazla",
"next": "Sonraki",
"ok": "Tamam",
"previous": "Önceki",
"refresh": "Yenile",
"remove": "Kaldır",
"retry": "Yeniden Dene",
"save": "Kaydet",
"search": "Ara",
"submit": "Gönder"
},
"app": {
"description": "AI asistanınız için işbirliği platformu",
"name": "LobeHub"
},
"status": {
"error": "Hata",
"info": "Bilgi",
"loading": "Yükleniyor",
"success": "Başarılı",
"warning": "Uyarı"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Tamam",
"about.detail": "Büyük dil modeli tabanlı bir sohbet uygulaması",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Hakkında",
"confirm.cancel": "İptal",
"confirm.no": "Hayır",
"confirm.title": "Onay",
"confirm.yes": "Evet",
"error.button": "Tamam",
"error.detail": "İşlem sırasında bir hata oluştu, lütfen daha sonra tekrar deneyin",
"error.message": "Hata oluştu",
"error.title": "Hata",
"update.downloadAndInstall": "İndir ve Yükle",
"update.downloadComplete": "İndirme tamamlandı",
"update.downloadCompleteMessage": "Güncelleme paketi indirildi, hemen yüklemek ister misiniz?",
"update.installLater": "Sonra yükle",
"update.installNow": "Şimdi yükle",
"update.later": "Sonra hatırlat",
"update.newVersion": "Yeni sürüm bulundu",
"update.newVersionAvailable": "Yeni sürüm bulundu: {{version}}",
"update.skipThisVersion": "Bu sürümü atla"
}
"about": {
"button": "Tamam",
"detail": "Büyük dil modeli tabanlı bir sohbet uygulaması",
"message": "{{appName}} {{appVersion}}",
"title": "Hakkında"
},
"confirm": {
"cancel": "İptal",
"no": "Hayır",
"title": "Onay",
"yes": "Evet"
},
"error": {
"button": "Tamam",
"detail": "İşlem sırasında bir hata oluştu, lütfen daha sonra tekrar deneyin",
"message": "Hata oluştu",
"title": "Hata"
},
"update": {
"downloadAndInstall": "İndir ve Yükle",
"downloadComplete": "İndirme tamamlandı",
"downloadCompleteMessage": "Güncelleme paketi indirildi, hemen yüklemek ister misiniz?",
"installLater": "Sonra yükle",
"installNow": "Şimdi yükle",
"later": "Sonra hatırlat",
"newVersion": "Yeni sürüm bulundu",
"newVersionAvailable": "Yeni sürüm bulundu: {{version}}",
"skipThisVersion": "Bu sürümü atla"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Güncellemeleri kontrol et...",
"dev.devPanel": "Geliştirici Paneli",
"dev.devTools": "Geliştirici Araçları",
"dev.forceReload": "Zorla Yenile",
"dev.openStore": "Depolama dosyasını",
"dev.refreshMenu": "Menüyü yenile",
"dev.reload": "Yenile",
"dev.title": "Geliştir",
"edit.copy": "Kopyala",
"edit.cut": "Kes",
"edit.delete": "Sil",
"edit.paste": "Yapıştır",
"edit.redo": "Yinele",
"edit.selectAll": "Tümünü Seç",
"edit.speech": "Ses",
"edit.startSpeaking": "Okumaya Başla",
"edit.stopSpeaking": "Okumayı Durdur",
"edit.title": "Düzenle",
"edit.undo": "Geri Al",
"file.preferences": "Tercihler",
"file.quit": "Çık",
"file.title": "Dosya",
"help.about": "Hakkında",
"help.githubRepo": "GitHub Deposu",
"help.reportIssue": "Sorun Bildir",
"help.title": "Yardım",
"help.visitWebsite": "Resmi Web Sitesini Ziyaret Et",
"macOS.about": "{{appName}} Hakkında",
"macOS.devTools": "LobeHub Geliştirici Araçları",
"macOS.hide": "{{appName}}'i Gizle",
"macOS.hideOthers": "Diğerlerini Gizle",
"macOS.preferences": "Tercihler...",
"macOS.services": "Hizmetler",
"macOS.unhide": "Hepsini Göster",
"tray.open": "{{appName}}'i Aç",
"tray.quit": "Çık",
"tray.show": "{{appName}}'i Göster",
"view.forceReload": "Zorla Yenile",
"view.reload": "Yenile",
"view.resetZoom": "Yakınlaştırmayı Sıfırla",
"view.title": "Görünüm",
"view.toggleFullscreen": "Tam Ekrana Geç",
"view.zoomIn": "Büyüt",
"view.zoomOut": "Küçült",
"window.bringAllToFront": "Tüm Pencereleri Öne Getir",
"window.close": "Kapat",
"window.front": "Tüm Pencereleri Öne Getir",
"window.minimize": "Küçült",
"window.title": "Pencere",
"window.toggleFullscreen": "Tam Ekrana Geç",
"window.zoom": "Yakınlaştır"
}
"common": {
"checkUpdates": "Güncellemeleri kontrol et..."
},
"dev": {
"devPanel": "Geliştirici Paneli",
"devTools": "Geliştirici Araçları",
"forceReload": "Zorla Yenile",
"openStore": "Depolama dosyasını",
"refreshMenu": "Menüyü yenile",
"reload": "Yenile",
"title": "Geliştir"
},
"edit": {
"copy": "Kopyala",
"cut": "Kes",
"delete": "Sil",
"paste": "Yapıştır",
"redo": "Yinele",
"selectAll": "Tümünü Seç",
"speech": "Ses",
"startSpeaking": "Okumaya Başla",
"stopSpeaking": "Okumayı Durdur",
"title": "Düzenle",
"undo": "Geri Al"
},
"file": {
"preferences": "Tercihler",
"quit": "Çık",
"title": "Dosya"
},
"help": {
"about": "Hakkında",
"githubRepo": "GitHub Deposu",
"reportIssue": "Sorun Bildir",
"title": "Yardım",
"visitWebsite": "Resmi Web Sitesini Ziyaret Et"
},
"macOS": {
"about": "{{appName}} Hakkında",
"devTools": "LobeHub Geliştirici Araçları",
"hide": "{{appName}}'i Gizle",
"hideOthers": "Diğerlerini Gizle",
"preferences": "Tercihler...",
"services": "Hizmetler",
"unhide": "Hepsini Göster"
},
"tray": {
"open": "{{appName}}'i Aç",
"quit": "Çık",
"show": "{{appName}}'i Göster"
},
"view": {
"forceReload": "Zorla Yenile",
"reload": "Yenile",
"resetZoom": "Yakınlaştırmayı Sıfırla",
"title": "Görünüm",
"toggleFullscreen": "Tam Ekrana Geç",
"zoomIn": "Büyüt",
"zoomOut": "Küçült"
},
"window": {
"bringAllToFront": "Tüm Pencereleri Öne Getir",
"close": "Kapat",
"front": "Tüm Pencereleri Öne Getir",
"minimize": "Küçült",
"title": "Pencere",
"toggleFullscreen": "Tam Ekrana Geç",
"zoom": "Yakınlaştır"
}
}
@@ -1,26 +1,32 @@
{
"actions.add": "Thêm",
"actions.back": "Quay lại",
"actions.cancel": "Hủy",
"actions.close": "Đóng",
"actions.confirm": "Xác nhận",
"actions.delete": "Xóa",
"actions.edit": "Chỉnh sửa",
"actions.more": "Thêm nữa",
"actions.next": "Tiếp theo",
"actions.ok": "Đồng ý",
"actions.previous": "Quay lại",
"actions.refresh": "Tải lại",
"actions.remove": "Gỡ bỏ",
"actions.retry": "Thử lại",
"actions.save": "Lưu",
"actions.search": "Tìm kiếm",
"actions.submit": "Gửi",
"app.description": "Nền tảng hợp tác trợ lý AI của bạn",
"app.name": "LobeHub",
"status.error": "Lỗi",
"status.info": "Thông tin",
"status.loading": "Đang tải",
"status.success": "Thành công",
"status.warning": "Cảnh báo"
}
"actions": {
"add": "Thêm",
"back": "Quay lại",
"cancel": "Hủy",
"close": "Đóng",
"confirm": "Xác nhận",
"delete": "Xóa",
"edit": "Chỉnh sửa",
"more": "Thêm nữa",
"next": "Tiếp theo",
"ok": "Đồng ý",
"previous": "Quay lại",
"refresh": "Tải lại",
"remove": "Gỡ bỏ",
"retry": "Thử lại",
"save": "Lưu",
"search": "Tìm kiếm",
"submit": "Gửi"
},
"app": {
"description": "Nền tảng hợp tác trợ lý AI của bạn",
"name": "LobeHub"
},
"status": {
"error": "Lỗi",
"info": "Thông tin",
"loading": "Đang tải",
"success": "Thành công",
"warning": "Cảnh báo"
}
}
@@ -1,23 +1,31 @@
{
"about.button": "Xác nhận",
"about.detail": "Một ứng dụng trò chuyện dựa trên mô hình ngôn ngữ lớn",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "Về",
"confirm.cancel": "Hủy",
"confirm.no": "Không",
"confirm.title": "Xác nhận",
"confirm.yes": "",
"error.button": "Xác nhận",
"error.detail": "Đã xảy ra lỗi trong quá trình thực hiện, vui lòng thử lại sau",
"error.message": "Đã xảy ra lỗi",
"error.title": "Lỗi",
"update.downloadAndInstall": "Tải xuống và cài đặt",
"update.downloadComplete": "Tải xuống hoàn tất",
"update.downloadCompleteMessage": "Gói cập nhật đã tải xuống hoàn tất, có muốn cài đặt ngay không?",
"update.installLater": "Cài đặt sau",
"update.installNow": "Cài đặt ngay",
"update.later": "Nhắc nhở sau",
"update.newVersion": "Phát hiện phiên bản mới",
"update.newVersionAvailable": "Phát hiện phiên bản mới: {{version}}",
"update.skipThisVersion": "Bỏ qua phiên bản này"
}
"about": {
"button": "Xác nhận",
"detail": "Một ứng dụng trò chuyện dựa trên mô hình ngôn ngữ lớn",
"message": "{{appName}} {{appVersion}}",
"title": "Về"
},
"confirm": {
"cancel": "Hủy",
"no": "Không",
"title": "Xác nhận",
"yes": "Có"
},
"error": {
"button": "Xác nhận",
"detail": "Đã xảy ra lỗi trong quá trình thực hiện, vui lòng thử lại sau",
"message": "Đã xảy ra lỗi",
"title": "Lỗi"
},
"update": {
"downloadAndInstall": "Tải xuống và cài đặt",
"downloadComplete": "Tải xuống hoàn tất",
"downloadCompleteMessage": "Gói cập nhật đã tải xuống hoàn tất, có muốn cài đặt ngay không?",
"installLater": "Cài đặt sau",
"installNow": "Cài đặt ngay",
"later": "Nhắc nhở sau",
"newVersion": "Phát hiện phiên bản mới",
"newVersionAvailable": "Phát hiện phiên bản mới: {{version}}",
"skipThisVersion": "Bỏ qua phiên bản này"
}
}
+70 -52
View File
@@ -1,53 +1,71 @@
{
"common.checkUpdates": "Kiểm tra cập nhật...",
"dev.devPanel": "Bảng điều khiển nhà phát triển",
"dev.devTools": "Công cụ phát triển",
"dev.forceReload": "Tải lại cưỡng bức",
"dev.openStore": "Mở tệp lưu trữ",
"dev.refreshMenu": "Làm mới menu",
"dev.reload": "Tải lại",
"dev.title": "Phát triển",
"edit.copy": "Sao chép",
"edit.cut": "Cắt",
"edit.delete": "Xóa",
"edit.paste": "Dán",
"edit.redo": "Làm lại",
"edit.selectAll": "Chọn tất cả",
"edit.speech": "Giọng nói",
"edit.startSpeaking": "Bắt đầu đọc",
"edit.stopSpeaking": "Dừng đọc",
"edit.title": "Chỉnh sửa",
"edit.undo": "Hoàn tác",
"file.preferences": "Tùy chọn",
"file.quit": "Thoát",
"file.title": "Tập tin",
"help.about": "Về",
"help.githubRepo": "Kho lưu trữ GitHub",
"help.reportIssue": "Báo cáo sự cố",
"help.title": "Trợ giúp",
"help.visitWebsite": "Truy cập trang web",
"macOS.about": "Về {{appName}}",
"macOS.devTools": "Công cụ phát triển LobeHub",
"macOS.hide": "Ẩn {{appName}}",
"macOS.hideOthers": "Ẩn khác",
"macOS.preferences": "Cài đặt ưu tiên...",
"macOS.services": "Dịch vụ",
"macOS.unhide": "Hiện tất c",
"tray.open": "Mở {{appName}}",
"tray.quit": "Thoát",
"tray.show": "Hiện {{appName}}",
"view.forceReload": "Tải lại cưỡng bức",
"view.reload": "Tải lại",
"view.resetZoom": "Đặt lại thu phóng",
"view.title": "Xem",
"view.toggleFullscreen": "Chuyển đổi toàn màn hình",
"view.zoomIn": "Phóng to",
"view.zoomOut": "Thu nhỏ",
"window.bringAllToFront": "Đưa tất cả cửa sổ lên trước",
"window.close": "Đóng",
"window.front": "Đưa tất cả cửa sổ lên trước",
"window.minimize": "Thu nhỏ",
"window.title": "Cửa sổ",
"window.toggleFullscreen": "Chuyển đổi toàn màn hình",
"window.zoom": "Thu phóng"
}
"common": {
"checkUpdates": "Kiểm tra cập nhật..."
},
"dev": {
"devPanel": "Bảng điều khiển nhà phát triển",
"devTools": "Công cụ phát triển",
"forceReload": "Tải lại cưỡng bức",
"openStore": "Mở tệp lưu trữ",
"refreshMenu": "Làm mới menu",
"reload": "Tải lại",
"title": "Phát triển"
},
"edit": {
"copy": "Sao chép",
"cut": "Cắt",
"delete": "Xóa",
"paste": "Dán",
"redo": "Làm lại",
"selectAll": "Chọn tất cả",
"speech": "Giọng nói",
"startSpeaking": "Bắt đầu đọc",
"stopSpeaking": "Dừng đọc",
"title": "Chỉnh sửa",
"undo": "Hoàn tác"
},
"file": {
"preferences": "Tùy chọn",
"quit": "Thoát",
"title": "Tập tin"
},
"help": {
"about": "Về",
"githubRepo": "Kho lưu trữ GitHub",
"reportIssue": "Báo cáo sự c",
"title": "Trợ giúp",
"visitWebsite": "Truy cập trang web"
},
"macOS": {
"about": "Về {{appName}}",
"devTools": "Công cụ phát triển LobeHub",
"hide": "Ẩn {{appName}}",
"hideOthers": "Ẩn khác",
"preferences": "Cài đặt ưu tiên...",
"services": "Dịch vụ",
"unhide": "Hiện tất cả"
},
"tray": {
"open": "Mở {{appName}}",
"quit": "Thoát",
"show": "Hiện {{appName}}"
},
"view": {
"forceReload": "Tải lại cưỡng bức",
"reload": "Tải lại",
"resetZoom": "Đặt lại thu phóng",
"title": "Xem",
"toggleFullscreen": "Chuyển đổi toàn màn hình",
"zoomIn": "Phóng to",
"zoomOut": "Thu nhỏ"
},
"window": {
"bringAllToFront": "Đưa tất cả cửa sổ lên trước",
"close": "Đóng",
"front": "Đưa tất cả cửa sổ lên trước",
"minimize": "Thu nhỏ",
"title": "Cửa sổ",
"toggleFullscreen": "Chuyển đổi toàn màn hình",
"zoom": "Thu phóng"
}
}
@@ -1,92 +1,32 @@
{
"actions.add": "添加",
"actions.back": "返回",
"actions.cancel": "取消",
"actions.close": "关闭",
"actions.confirm": "确认",
"actions.delete": "删除",
"actions.edit": "编辑",
"actions.more": "更多",
"actions.next": "下一步",
"actions.ok": "确定",
"actions.previous": "上一步",
"actions.refresh": "刷新",
"actions.remove": "移除",
"actions.retry": "重试",
"actions.save": "保存",
"actions.search": "搜索",
"actions.submit": "提交",
"app.description": "你的 AI 助手协作平台",
"app.name": "LobeHub",
"notification.finishChatGeneration": "AI 消息已生成完毕",
"proxy.auth": "需要认证",
"proxy.authDesc": "如果代理服务器需要用户名和密码",
"proxy.authSettings": "认证设置",
"proxy.basicSettings": "代理设置",
"proxy.basicSettingsDesc": "配置代理服务器的连接参数",
"proxy.bypass": "不使用代理的地址",
"proxy.connectionTest": "连接测试",
"proxy.enable": "启用代理",
"proxy.enableDesc": "开启后将通过代理服务器访问网络",
"proxy.password": "密码",
"proxy.password_placeholder": "请输入密码",
"proxy.port": "端口",
"proxy.resetButton": "重置",
"proxy.saveButton": "保存",
"proxy.saveFailed": "保存失败:{{error}}",
"proxy.saveSuccess": "代理设置保存成功",
"proxy.server": "服务器地址",
"proxy.testButton": "测试连接",
"proxy.testDescription": "使用当前代理配置测试连接,验证配置是否正常工作",
"proxy.testFailed": "连接失败",
"proxy.testSuccessWithTime": "测试连接成功,耗时 {{time}} ms",
"proxy.testUrl": "测试地址",
"proxy.testUrlPlaceholder": "请输入要测试的 URL",
"proxy.testing": "正在测试连接…",
"proxy.type": "代理类型",
"proxy.unsavedChanges": "你有未保存的更改",
"proxy.username": "用户名",
"proxy.username_placeholder": "请输入用户名",
"proxy.validation.passwordRequired": "启用认证时密码为必填项",
"proxy.validation.portInvalid": "端口必须是 1 到 65535 之间的数字",
"proxy.validation.portRequired": "启用代理时端口为必填项",
"proxy.validation.serverInvalid": "请输入有效的服务器地址(IP 或域名)",
"proxy.validation.serverRequired": "启用代理时服务器地址为必填项",
"proxy.validation.typeRequired": "启用代理时代理类型为必填项",
"proxy.validation.usernameRequired": "启用认证时用户名为必填项",
"remoteServer.authError": "授权失败: {{error}}",
"remoteServer.authPending": "请在浏览器中完成授权",
"remoteServer.configDesc": "连接到远程 LobeHub 服务器,启用数据同步",
"remoteServer.configError": "配置出错",
"remoteServer.configTitle": "配置云同步",
"remoteServer.connect": "连接并授权",
"remoteServer.connected": "已连接",
"remoteServer.disconnect": "断开连接",
"remoteServer.disconnectError": "断开连接失败",
"remoteServer.disconnected": "未连接",
"remoteServer.fetchError": "获取配置失败",
"remoteServer.invalidUrl": "请输入有效的URL地址",
"remoteServer.serverUrl": "服务器地址",
"remoteServer.statusConnected": "已连接",
"remoteServer.statusDisconnected": "未连接",
"remoteServer.urlRequired": "请输入服务器地址",
"status.error": "错误",
"status.info": "信息",
"status.loading": "加载中",
"status.success": "成功",
"status.warning": "警告",
"sync.continue": "继续",
"sync.inCloud": "当前使用云端同步",
"sync.inLocalStorage": "当前使用本地存储",
"sync.isIniting": "正在初始化…",
"sync.lobehubCloud.description": "官方提供的云版本",
"sync.lobehubCloud.title": "LobeHub Cloud",
"sync.local.description": "使用本地数据库,完全离线可用",
"sync.local.title": "本地数据库",
"sync.mode.cloudSync": "云端同步",
"sync.mode.localStorage": "本地存储",
"sync.mode.title": "选择你的连接模式",
"sync.mode.useSelfHosted": "使用自托管实例?",
"sync.selfHosted.description": "自行部署的社区版本",
"sync.selfHosted.title": "自托管实例"
}
"actions": {
"add": "添加",
"back": "返回",
"cancel": "取消",
"close": "关闭",
"confirm": "确认",
"delete": "删除",
"edit": "编辑",
"more": "更多",
"next": "下一步",
"ok": "确定",
"previous": "上一步",
"refresh": "刷新",
"remove": "移除",
"retry": "重试",
"save": "保存",
"search": "搜索",
"submit": "提交"
},
"app": {
"description": "你的 AI 助手协作平台",
"name": "LobeHub"
},
"status": {
"error": "错误",
"info": "信息",
"loading": "加载中",
"success": "成功",
"warning": "警告"
}
}
@@ -1,44 +1,31 @@
{
"about.button": "确定",
"about.detail": "一个基于大语言模型的聊天应用",
"about.message": "{{appName}} {{appVersion}}",
"about.title": "关于",
"confirm.cancel": "取消",
"confirm.no": "取消",
"confirm.title": "请确认",
"confirm.yes": "继续",
"error.button": "确定",
"error.detail": "操作未完成。你可以重试,或稍后再试。",
"error.message": "发生错误",
"error.title": "错误",
"update.checkingUpdate": "检查新版本",
"update.checkingUpdateDesc": "正在获取版本信息…",
"update.downloadAndInstall": "下载并安装",
"update.downloadComplete": "下载完成",
"update.downloadCompleteMessage": "已下载更新。现在安装吗?",
"update.downloadNewVersion": "下载新版本",
"update.downloadingUpdate": "正在下载更新",
"update.downloadingUpdateDesc": "更新正在下载中,请稍候…",
"update.installLater": "稍后安装",
"update.installNow": "立即安装",
"update.isLatestVersion": "当前已是最新版本",
"update.isLatestVersionDesc": "当前版本({{version}})已是最新。",
"update.later": "稍后提醒",
"update.newVersion": "发现新版本",
"update.newVersionAvailable": "发现新版本{{version}}",
"update.newVersionAvailableDesc": "发现新版本 {{version}},是否立即下载?",
"update.restartAndInstall": "安装更新并重启",
"update.skipThisVersion": "跳过此版本",
"update.updateError": "更新错误",
"update.updateReady": "有新版本可用",
"update.updateReadyDesc": "新版本 {{version}} 已下载完成,重启应用后即可完成安装。",
"update.upgradeNow": "立即更新",
"update.willInstallLater": "更新将在下次启动时安装",
"waitingOAuth.cancel": "取消",
"waitingOAuth.description": "浏览器已打开授权页面,请在浏览器中完成授权",
"waitingOAuth.error": "授权失败: {{error}}",
"waitingOAuth.errorTitle": "授权连接失败",
"waitingOAuth.helpText": "如果浏览器没有自动打开,请点击取消后重新尝试",
"waitingOAuth.retry": "重试",
"waitingOAuth.title": "等待授权连接"
}
"about": {
"button": "确定",
"detail": "一个基于大语言模型的聊天应用",
"message": "{{appName}} {{appVersion}}",
"title": "关于"
},
"confirm": {
"cancel": "取消",
"no": "",
"title": "确认",
"yes": "是"
},
"error": {
"button": "确定",
"detail": "操作过程中发生错误,请稍后重试",
"message": "发生错误",
"title": "错误"
},
"update": {
"downloadAndInstall": "下载并安装",
"downloadComplete": "下载完成",
"downloadCompleteMessage": "更新包已下载完成,是否立即安装",
"installLater": "稍后安装",
"installNow": "立即安装",
"later": "稍后提醒",
"newVersion": "发现新版本",
"newVersionAvailable": "发现新版本: {{version}}",
"skipThisVersion": "跳过此版本"
}
}
+70 -61
View File
@@ -1,62 +1,71 @@
{
"common.checkUpdates": "检查更新…",
"dev.devPanel": "开发者面板",
"dev.devTools": "开发者工具",
"dev.forceReload": "强制重新加载",
"dev.openSettingsFile": "打开 Settings 配置文件",
"dev.openStore": "打开本地数据目录",
"dev.openUpdaterCacheDir": "更新缓存目录",
"dev.openUserDataDir": "用户配置目录",
"dev.refreshMenu": "刷新菜单",
"dev.reload": "重新加载",
"dev.simulateAutoDownload": "模拟启动后台自动下载更新(3s 下完)",
"dev.simulateDownloadComplete": "模拟下载完成",
"dev.simulateDownloadProgress": "模拟下载进度",
"dev.title": "开发",
"dev.updaterSimulation": "自动更新测试模拟",
"edit.copy": "复制",
"edit.cut": "剪切",
"edit.delete": "删除",
"edit.paste": "粘贴",
"edit.redo": "重做",
"edit.selectAll": "全选",
"edit.speech": "语音",
"edit.startSpeaking": "开始朗读",
"edit.stopSpeaking": "停止朗读",
"edit.title": "编辑",
"edit.undo": "撤销",
"file.preferences": "设置…",
"file.quit": "退出",
"file.title": "文件",
"help.about": "关于",
"help.githubRepo": "GitHub 仓库",
"help.openConfigDir": "配置目录",
"help.openLogsDir": "打开日志目录",
"help.reportIssue": "反馈问题",
"help.title": "帮助",
"help.visitWebsite": "打开官网",
"macOS.about": "关于 {{appName}}",
"macOS.devTools": "LobeHub 开发者工具",
"macOS.hide": "隐藏 {{appName}}",
"macOS.hideOthers": "隐藏其他",
"macOS.preferences": "偏好设置…",
"macOS.services": "服务",
"macOS.unhide": "全部显示",
"tray.open": "打开 {{appName}}",
"tray.quit": "退出",
"tray.show": "显示 {{appName}}",
"view.forceReload": "强制重新加载",
"view.reload": "重新加载",
"view.resetZoom": "重置缩放",
"view.title": "视图",
"view.toggleFullscreen": "切换全屏",
"view.zoomIn": "放大",
"view.zoomOut": "缩小",
"window.bringAllToFront": "前置所有窗口",
"window.close": "关闭",
"window.front": "前置所有窗口",
"window.minimize": "最小化",
"window.title": "窗口",
"window.toggleFullscreen": "切换全屏",
"window.zoom": "缩放"
}
"common": {
"checkUpdates": "检查更新..."
},
"dev": {
"devPanel": "开发者面板",
"devTools": "开发者工具",
"forceReload": "强制重新加载",
"openStore": "打开存储文件",
"refreshMenu": "刷新菜单",
"reload": "重新加载",
"title": "开发"
},
"edit": {
"copy": "复制",
"cut": "剪切",
"delete": "删除",
"paste": "粘贴",
"redo": "重做",
"selectAll": "全选",
"speech": "语音",
"startSpeaking": "开始朗读",
"stopSpeaking": "停止朗读",
"title": "编辑",
"undo": "撤销"
},
"file": {
"preferences": "首选项",
"quit": "退出",
"title": "文件"
},
"help": {
"about": "关于",
"githubRepo": "GitHub 仓库",
"reportIssue": "报告问题",
"title": "帮助",
"visitWebsite": "访问官网"
},
"macOS": {
"about": "关于 {{appName}}",
"devTools": "LobeHub 开发者工具",
"hide": "隐藏 {{appName}}",
"hideOthers": "隐藏其他",
"preferences": "偏好设置...",
"services": "服务",
"unhide": "全部显示"
},
"tray": {
"open": "打开 {{appName}}",
"quit": "退出",
"show": "显示 {{appName}}"
},
"view": {
"forceReload": "强制重新加载",
"reload": "重新加载",
"resetZoom": "重置缩放",
"title": "视图",
"toggleFullscreen": "切换全屏",
"zoomIn": "放大",
"zoomOut": "缩小"
},
"window": {
"bringAllToFront": "前置所有窗口",
"close": "关闭",
"front": "前置所有窗口",
"minimize": "最小化",
"title": "窗口",
"toggleFullscreen": "切换全屏",
"zoom": "缩放"
}
}

Some files were not shown because too many files have changed in this diff Show More