Compare commits

...

177 Commits

Author SHA1 Message Date
Innei b3e330b089 feat: integrate VirtualList component across multiple features 2025-12-26 19:53:09 +08:00
Innei 36ea258fec feat: translate AI model descriptions to English (#10989)
Translate all AI model and model provider descriptions from Chinese to English for better international accessibility and consistency.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-26 15:21:59 +08:00
canisminor1990 8d2eb1ca2e style: replace all checkbox 2025-12-26 15:20:12 +08:00
Shinji-Li 50aa304317 🐛 fix: slove the model select null problem (#10988)
fix: slove the model select null problem
2025-12-26 14:46:12 +08:00
canisminor1990 fddff0e962 style: update Group Avatar 2025-12-26 14:31:57 +08:00
Innei 50bca49e7d refactor(i18n): move UI locale files from TypeScript to JSON format (#10985)
* refactor(i18n): move UI locale files from TypeScript to JSON format

- Move UI locale translations from src/locales/ui/*.ts to locales/{locale}/ui.json
- Add src/locales/default/ui.ts for default (en-US) translations
- Update getUILocaleAndResources.ts to load from JSON files
- Add ui.json for all 18 supported locales (ar, bg-BG, de-DE, en-US, es-ES, fa-IR, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-BR, ru-RU, tr-TR, vi-VN, zh-CN, zh-TW)

This change unifies the locale file format, using JSON for all translations
instead of mixing TS and JSON formats.

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

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

* fix: throw error when UI locale resources and fallback both fail

Instead of returning an empty object which could cause silent failures
in string lookups, throw an error when both the primary locale and
en-US fallback fail to load.

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

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

* refactor(i18n): remove component-level texts props and unused locale keys

- Remove texts props from all @lobehub/ui components (EmojiPicker, Form.SubmitFooter, Hotkey, ColorSwatches)
- Remove unused 'custom' and 'presets' keys from color.json files (only used for ColorSwatches texts prop)
- Components now use @lobehub/ui's built-in translations via ConfigProvider resources

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

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

* refactor(i18n): remove unused locale keys from default locale files

- Remove EmojiPicker.* keys from components.ts (only used for texts prop)
- Remove submitFooter.* keys from setting.ts (only used for texts prop)
- Remove custom and presets keys from color.ts (only used for ColorSwatches texts prop)
- Update getUILocaleAndResources tests to reflect new behavior

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

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

* refactor(i18n): enhance getUILocaleAndResources with fallback logic

* style: format code and remove unused imports

- Remove unused useTranslation import from EmojiPicker
- Format code with prettier

🤖 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-26 14:13:46 +08:00
Innei ce469967de 🐛 fix(translation): add fallback for all English locale variants (#10984)
When using English locale variants (e.g., en-GB, en-AU), the translation system should fall back to the default English namespace instead of trying to load non-existent locale files.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-26 12:37:50 +08:00
Rene Wang 972809deed lint: Warp id conversion logic 2025-12-26 12:29:10 +08:00
YuTengjing 5acd5c0a2f chore: revert type only lint 2025-12-26 12:01:32 +08:00
YuTengjing 4f2a6833b2 🐛 fix(image-generation): update chargeBeforeGenerate to return ChargeResult and include configForDatabase in parameters 2025-12-26 12:01:32 +08:00
Rene Wang a784b73685 feat: Export to markdown 2025-12-26 11:55:04 +08:00
Rene Wang 1b61f0c978 feat: Update translation 2025-12-26 11:37:58 +08:00
Shinji-Li 0b2b0963d4 🐛 fix: when use agentbuilder the topic id should use new & clear topic… (#10983)
* feat: when use agentbuilder the topic id should use new & clear topicid in unmount

* feat: when click chat button,should clear topicid first
2025-12-26 11:34:31 +08:00
Arvin Xu 7f69cb1e54 💄 style: improve page document tool inspector UI (#10977) 2025-12-26 08:51:08 +08:00
Neko 15bc6bcfbb 🐛 fix(userMemories): use date & time for building context (#10978) 2025-12-26 03:40:17 +08:00
Neko 196cfce115 tests(memory-user-memory): add tests (#10980) 2025-12-26 03:40:08 +08:00
Neko c2bcf73f9d 🐛 fix(memory-user-memory): should pre-process date & time (#10979) 2025-12-26 03:39:59 +08:00
canisminor1990 4f592ce100 style: update i18n 2025-12-26 00:09:41 +08:00
canisminor1990 4f71117bac style: update todo list style 2025-12-26 00:09:41 +08:00
Rene Wang 41e59f733b opti: Better strings 2025-12-25 23:58:30 +08:00
Arvin Xu 576ccd678c 💄 style: support tool streaming and title custom render (#10976)
* support custom inspector

* support local-system inspector

* add streaming feature

* merge
2025-12-25 23:52:57 +08:00
Rene Wang 84350b3ffc feat: Import from PDF 2025-12-25 23:23:47 +08:00
Innei e87bee6dd5 chore: update lint to use type imports (#10970)
* chore: update lint to use type imports

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

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

* revert

* chore: add workspaces and overrides to package.json

* refactor: clean up imports in lobe-web-browsing executor

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 22:28:19 +08:00
Rene Wang 7f6bca71e7 fix: Page title missing 2025-12-25 22:22:10 +08:00
Rene Wang 13349406d5 fix: Cannot load more 2025-12-25 22:12:20 +08:00
YuTengjing 51ddc7cb18 refactor: replace logging library with console.error in tRPC tools handler 2025-12-25 22:00:50 +08:00
YuTengjing 41c0b3bab3 refactor: expose lobehub models 2025-12-25 21:48:30 +08:00
Innei 221bd6e5af chore: update i18n translations for multiple locales (#10973)
Update translations for ar, bg-BG, de-DE, es-ES, fa-IR, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-BR, ru-RU, tr-TR, vi-VN, zh-TW locales.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 21:28:18 +08:00
canisminor1990 3a59cf33e9 style: update agent back style 2025-12-25 21:24:27 +08:00
YuTengjing 92ca00eb85 refactor: remove some unused business code 2025-12-25 21:19:19 +08:00
YuTengjing 12fb04b88d refactor: move src/config/modelProviders to model-bank 2025-12-25 21:02:19 +08:00
YuTengjing d2a8b9ce02 refactor: remove lobehub configuration from LLM settings 2025-12-25 20:38:36 +08:00
YuTengjing d2cf3d1c33 fix: lint errors 2025-12-25 20:33:09 +08:00
canisminor1990 c004973b23 style: update token tag 2025-12-25 20:28:20 +08:00
YuTengjing 180ebfdf70 feat: Integrate bcryptjs for password verification in BetterAuth
- Added bcryptjs as a dependency for handling password verification.
- Updated the defineConfig function to support bcrypt password hashes migrated from Clerk.
- Implemented a new password verification method that checks for bcrypt hashes and falls back to BetterAuth's default verification.
2025-12-25 19:44:36 +08:00
YuTengjing 2e7076a9fd feat: Add turbopack configuration support to CustomNextConfig
- Introduced a new optional property `turbopack` in the CustomNextConfig interface.
- Updated the defineConfig function to merge turbopack settings from the provided config.
2025-12-25 19:26:11 +08:00
YuTengjing d86f9831ca refactor: extract common next config 2025-12-25 18:04:59 +08:00
Innei 89f89c7f83 fix(i18n): Translate plugin.ts locale to English (#10972)
Translate all plugin-related UI strings from Chinese to English following the microcopy guidelines:
- Use "Skill" as the standard term (not tool/plugin)
- Consistent terminology: Agent, Group, Library, Page, Memory, Workspace
- Clear, actionable language with concise phrasing
- Natural product-native English (avoid translationese)
- Preserved all placeholders for interpolation

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 18:01:21 +08:00
Innei 0e89ce508a feat: Add i18n UI locales and improve tool types (#10964)
*  feat: Add i18n UI locales and improve tool types

- Add multiple UI locale files (ar, bg-BG, de-DE, es-ES, fa-IR, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pl-PL, pt-BR, ru-RU, tr-TR, vi-VN, zh-TW)
- Add getUILocaleAndResources utility with tests
- Update tool-related type definitions
- Use type-only imports for better tree-shaking

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

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

* chore: update

* test: update siteName to use BRANDING_NAME and streamline translation mocks

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-25 17:37:35 +08:00
Shinji-Li c11d802d26 feat: add like action in community detail (#10971)
feat: add like action in community detail
2025-12-25 17:22:14 +08:00
canisminor1990 8630f61d61 style: update community style 2025-12-25 17:01:57 +08:00
canisminor1990 7803fc52c2 style: update community style 2025-12-25 17:01:56 +08:00
Shinji-Li 60eba456ed feat: support files upload in chat input (#10967)
* feat: add a custom drag upload way

* feat: add agent bulilder & page builder & group chat support upload files

* feat: use upload fileitem to show detail

* feat: support preview in chatinput files

* feat: add useUploadFiles hook to replace the repeat logic code
2025-12-25 16:56:21 +08:00
YuTengjing 9f1c79e9a7 Tj/refactor/businessify-3 (#10961) 2025-12-25 16:31:56 +08:00
Arvin Xu 15410d1a10 ♻️ refactor: clean page editor (#10966)
refactor and clean
2025-12-25 16:07:38 +08:00
Innei 568235c311 🐛 fix: Fix desktop test cases and refactor translations (#10956)
* 🐛 fix: fix desktop test cases and refactor translations

- Import translations from default locale instead of hardcoding
- Fix macOS menu test expectations to match actual translations
- Update I18nManager test to match implementation (fallbackLng: 'en')
- Support {{appName}} interpolation in test mocks

* 🐛 fix: add missing buildAndSetAppMenu calls in tests
2025-12-25 14:57:35 +08:00
Neko Ayaka 81d3e74aed feat(userMemories): added /api/dev/memory-user-memory/benchmark-locomo with feature flag gate, and webhook auth 2025-12-25 14:54:10 +08:00
Neko Ayaka 29c70b7b40 fix(memory-user-memory): incorrect format exported from LoCoMo 2025-12-25 14:54:10 +08:00
Neko Ayaka 3dfb18b3e2 refactor(userMemories): make CEPx4 + Ix1 parallel 2025-12-25 14:54:10 +08:00
CanisMinor c5fe456aec 🔨 chore: update compoents version (#10957)
chore: update deps
2025-12-25 12:52:31 +08:00
Innei b3520a2205 🐛 fix: Fix desktop test cases and refactor translations (#10955)
* 🐛 fix: fix desktop test cases and refactor translations

- Import translations from default locale instead of hardcoding
- Fix macOS menu test expectations to match actual translations
- Update I18nManager test to match implementation (fallbackLng: 'en')
- Support {{appName}} interpolation in test mocks

* 🐛 fix: add missing buildAndSetAppMenu calls in tests
2025-12-25 12:29:28 +08:00
Rene Wang 256309a6e4 fix: Type error 2025-12-25 11:47:39 +08:00
Arvin Xu 61b30310bc 🐛 fix: page agent editor (#10953)
* refactor page agent

* refactor page agent system prompt

* support inject page context in the agent runtime

* fix initial context injection

* support diff all toolbar
2025-12-25 11:38:15 +08:00
Rene Wang d43acc8e24 fix: Editor 2025-12-25 10:44:26 +08:00
Rene Wang f2dd3894c6 lint: Create consts for URLs 2025-12-25 10:30:00 +08:00
René Wang bda2d76fdf feat: Import from notion (#10948) 2025-12-24 23:16:57 +08:00
Shinji-Li 78ca5ebed5 🐛 fix: slove the mutate not work problem (#10947)
fix: slove the mutate not work problem
2025-12-24 22:42:50 +08:00
YuTengjing 0e49d11621 fix: maxDuration must use literal 2025-12-24 21:13:51 +08:00
Shinji-Li de949d19ad 🐛 fix add lost portal locals files (#10943)
fix: add lost portal locals files
2025-12-24 20:58:57 +08:00
Shinji-Li c224951340 feat: add always show tools render in createPlan & createDoc tools (#10937)
* feat: add always show tools render in createPlan & createDoc tools

* feat: add document protral can modify & jump to pages to modify it

* feat: add a warpper into portal render
2025-12-24 20:50:12 +08:00
Innei 1a4f4564f0 feat(desktop): macOS About menu should navigate to Settings About tab (#10942)
Changed the macOS app menu's "About" action from using the default Electron
about dialog to navigating to the Settings page's About tab.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-24 20:49:57 +08:00
Innei dc870c7635 ♻️ refactor: rename browser identifier from 'chat' to 'app' (#10940)
Rename the main browser identifier from 'chat' to 'app' to better represent its purpose as the main application window. Also update the initial path from '/agent' to '/' for the root route.

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-24 20:43:11 +08:00
Innei e5f3a58056 ♻️ refactor: flatten i18n keys and extract hardcoded strings in desktop (#10939)
- Flatten all nested i18n objects to dot notation format (e.g. 'dialog.about.title')
- Add en-* locale fallback to use default TypeScript files
- Extract hardcoded Chinese strings in menu files to i18n keys
- Update 17 locale JSON files with flattened structure

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

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-24 20:29:19 +08:00
YuTengjing 187b5ab4b2 fix: remove useless config variable 2025-12-24 19:20:01 +08:00
YuTengjing bb39de4a24 chore: fix proxy.ts (#10938) 2025-12-24 17:58:16 +08:00
Innei d692a37e28 ♻️ refactor: i18n formatting optimization (#10929)
* ♻️ refactor: i18n formatting optimization

*  feat(i18n): update localization strings for clarity and consistency across chat, discover, and settings components

*  feat(i18n): update Chinese localization strings for improved clarity and consistency across various components, including chat, onboarding, and settings

* 🗑️ chore(i18n): remove outdated localization files for multiple languages to streamline the project and improve maintainability

*  feat(i18n): enhance localization loading logic to improve language handling and streamline imports for default and normalized locales

* 🐛 fix(i18n): restore English i18n keys that were incorrectly changed to Japanese characters

*  chore(i18n): Adjust Latin language locales for terminology consistency (#10933)

* This comprehensive update ensures all Latin language locales (de-DE, fr-FR, es-ES, it-IT, pt-BR, nl-NL, pl-PL) follow the microcopy style guide's terminology requirements.

**Total: 557 changes across 7 Latin locales**

1. **"Plugin" → "Skill"**
   - Fixed terminology inconsistency across all Latin languages
   - UI elements now consistently use "Skill" instead of localized equivalents
   - Includes both singular and plural forms: `plugin/Skill`, `plugins/Skills`

2. **"LobeChat" → "LobeHub"**
   - Updated brand name references to current branding

3. **"Agent" Terminology Consistency**
   - French: Fixed inconsistent "Assistant" → "Agent" usage in UI elements
   - Ensured consistent terminology across all languages

- **de-DE (German)**: 267 changes
- **fr-FR (French)**: 94 changes (including 7 Agent→Assistant fixes)
- **es-ES (Spanish)**: 39 changes
- **it-IT (Italian)**: 59 changes (including 18 plugin→skill fixes)
- **pt-BR (Portuguese)**: 58 changes
- **nl-NL (Dutch)**: 62 changes
- **pl-PL (Polish)**: 28 changes

- All 37 locale JSON files for each language (259 total files)
- Includes: auth.json, chat.json, common.json, discover.json, plugin.json, setting.json, etc.

1. **Fixed Terminology**: Following microcopy guide's fixed terminology rules
2. **Brand Consistency**: Changed all brand references to "LobeHub"
3. **Natural Localization**: Maintained natural language patterns while ensuring consistency
4. **User Experience**: Improved consistency across all Latin language interfaces

Two utility scripts for future locale maintenance:
- `scripts/adjust-latin-locales.py` - For common.json specific adjustments
- `scripts/adjust-latin-locales-full.py` - For comprehensive adjustments across all files

- All changes maintain backward compatibility
- No breaking changes to functionality
- JSON files validated and remain syntactically correct
- Changes reviewed against English base for consistency

---------

Co-authored-by: canisminor1990 <i@canisminor.cc>

*  feat(i18n): update welcome and group activity localization strings for improved clarity and consistency

*  chore(i18n): add ESLint directives to welcome localization file for improved code quality

* 🐛 fix(i18n): add missing footer translation keys for discover page

*  feat(i18n): restore footer translation keys for discover page

---------

Co-authored-by: canisminor1990 <i@canisminor.cc>
2025-12-24 17:54:42 +08:00
YuTengjing ca16409b39 🔨 chore: project structure businessify (#10930) 2025-12-24 17:52:22 +08:00
Rene Wang d0616ccebb feat: Use our own viewer 2025-12-24 17:44:38 +08:00
Rene Wang b9648deafe fix: Image preview 2025-12-24 17:44:31 +08:00
Rene Wang 7ee27c1531 fix: Restore placeholder 2025-12-24 17:44:24 +08:00
canisminor1990 89597a85bf style: update community footer and modal 2025-12-24 17:07:10 +08:00
Shinji-Li be4c17d4cc feat: buildin some tools should save into docs (#10935)
* feat: change the GTD & document protrol should show editor

* feat: when crawl website should save it into doc
2025-12-24 16:52:15 +08:00
canisminor1990 0f5ba3a6cd style: fix tool auto expand 2025-12-24 15:53:39 +08:00
canisminor1990 b65ffdcc15 style: fix some style issues 2025-12-24 15:38:35 +08:00
canisminor1990 2e37b65663 style: fix some style issues 2025-12-24 14:09:17 +08:00
Arvin Xu 1bb19027b3 test: fix some tests failed (#10927)
* fix tests

* fix tests

* fix tests

* improve title size

* fix tests

* fix messages

* fix messages
2025-12-24 13:47:06 +08:00
Neko c7c7d6f3c8 feat(memory-user-memory): support to extract memories from LoCoMo dataset (#10925) 2025-12-24 12:56:52 +08:00
Neko 9ac3ce7741 feat(memory-user-memory): support to load in memory, and extract from in-memory memory sources (#10924) 2025-12-24 12:56:52 +08:00
Neko a5dd785dca feat(memory-user-memory): added LoCoMo dataset loader & converter & exporter (#10923) 2025-12-24 12:56:52 +08:00
Neko 03342a76e3 ♻️ refactor(userMemories): added benchmark_locomo as source unify use the of source type (#10922)
refactor(userMemories): added benchmark_locomo as source unify use the of source type
2025-12-24 12:56:52 +08:00
Neko a6be1a7f75 refactor(userMemories): should use MemorySourceType (#10921) 2025-12-24 12:55:13 +08:00
Arvin Xu fbd0b666f0 🐛 fix: fix identity memory not working (#10916)
* update memory prompts

* fix memory issue

* update i18n

* update prompts and injector

* fix memory query issue

* remove fetchedAt

* fix identity memory issues

* fix lint

* fix topic messages query issues

* fix lint
2025-12-24 12:55:13 +08:00
CanisMinor 024aeb2e4e 💄 style: Update i18n microcopy (#10905)
* chore: update i18n

* chore: update i18n

* chore: update i18n

* chore: update i18n

* chore: update i18n

* chore: update i18n

* chore: update i18n

* chore: update i18n translations and placeholders across multiple components

Signed-off-by: Innei <tukon479@gmail.com>

* chore: update i18n translations for consistency in terminology across chat, onboarding, and settings components

Signed-off-by: Innei <tukon479@gmail.com>

* chore: update i18n translations to replace 'assistant' with 'agent' and ensure consistency across all components

Signed-off-by: Innei <tukon479@gmail.com>

* chore: update model descriptions in locales for clarity and accuracy

Signed-off-by: Innei <tukon479@gmail.com>

* feat: extract hard code string

Signed-off-by: Innei <tukon479@gmail.com>

* feat: enhance Chinese localization with new proxy and sync settings, update dialog messages for version checks and OAuth authorization

Signed-off-by: Innei <tukon479@gmail.com>

* chore: flatten

* chore: standardize localization keys by flattening nested structures across multiple languages

Signed-off-by: Innei <tukon479@gmail.com>

* chore: refine i18n documentation by consolidating key naming conventions and workflow guidelines for translation management

Signed-off-by: Innei <tukon479@gmail.com>

* chore: update i18n

* feat: add chat title localization for improved user experience in Chinese

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Innei <tukon479@gmail.com>
2025-12-24 12:55:12 +08:00
René Wang 1f3531f8f5 feat: Better CMDK (#10915)
* lint: Remove unused console.log

* lint: Clean up console.log

* lint: Clean up console.log

* lint: Clean up console.log

* fix: Page creaetion

* feat: Add more CMDK commands

* feat: Create team in the CMDK

* feat: Context aware commands

* feat: Ask AI menu

* feat: SHow agent list in CMDK

* feat: Lobe AI

* feat: Adjust text

* feat: Add email entry
2025-12-24 12:55:11 +08:00
Arvin Xu e05375f796 feat: support notebook tool (#10902)
* add notebook builtin tool

* document init workflow

* gtd support plan mode

* add notebook tools
2025-12-24 12:55:09 +08:00
Shinji-Li c6a6e246d8 feat: community support like and follow (#10913)
* feat: add user follow and like agent/mcp

* feat: update market sdk& api call back
2025-12-24 12:54:47 +08:00
Innei 1a99f3f37e ️ perf(tooltip): group tooltip to optimize tooltip performance (#10906)
 perf: integrate TooltipGroup component across various UI components

- Added TooltipGroup to enhance tooltip management in Header, ProviderList, ModelList, UserAgentCard, and LikeButton components.
- Updated imports to include TooltipGroup in relevant files for consistent tooltip behavior.
- Refactored existing tooltip implementations to utilize TooltipGroup for better organization and performance.

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:47 +08:00
Innei a34c1113eb 🐛 fix: remove openapi pkg patch file (#10910)
🔧 chore: remove deprecated patch for @swagger-api/apidom-reference from package.json and delete associated patch file

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:47 +08:00
Innei 2558b47822 🐛 fix(desktop): add safe top edge for message container (#10908)
fix(desktop): add safe top edge for message container

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:47 +08:00
Neko 4e65f11ab5 refactor(memory-user-memory,userMemories): split chat topic related operations into dedicated pipelines sub-route (#10907) 2025-12-24 12:54:46 +08:00
Shinji-Li 3183189cc2 feat: add home page create group builder button (#10904)
feat: add group builder inhome page use sender
2025-12-24 12:54:46 +08:00
Innei 83fa92268d ️perf: reduce back to home render time (#10890)
*  feat: update DesktopHome layout and routing

* Upgraded @lobehub/ui to version 3.4.2.
* Enhanced DesktopHome layout with conditional rendering of PageTitle based on route.
* Refactored home layout to manage visibility and activation state.
* Updated desktop router configuration to streamline home page handling.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: simplify layout visibility handling in home component

* Removed pointerEvents and visibility styles based on route condition.
* Streamlined layout rendering logic for improved performance.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Innei ca373f643e 🔨 chore: update patch file to try fix build error (#10900)
🔧 chore: update apidom-reference patch and clean up binary parser code

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Innei 6d7dce798f 🐛 fix: bump charts 3.0.4 to fix import es path (#10898)
🔧 chore: update @lobehub/charts dependency to version 3.0.4 in package.json

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Innei e22fd2761c 🔨 chore: bump @lobehub/charts (#10897)
chore: update @lobehub/charts dependency to version 3.0.2 in package.json

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Innei e51225baa8 test: fix desktop test case (#10894)
test(logger): enhance logger tests with mocked environment variables

* Added mock for getDesktopEnv to simulate various NODE_ENV and DEBUG_VERBOSE states.
* Updated logger tests to utilize the mocked environment for consistent behavior across different log levels.
* Ensured that logger methods correctly handle production and development environments.

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Shinji-Li b3fbffe428 🐛 fix: slove swr mutate not work in Cache Provider (#10895)
fix: slove swr mutate not work in Cache Provider
2025-12-24 12:54:46 +08:00
Innei 95c6840162 fix(import): fix lobehub ui es import path (#10893)
chore: update package dependencies and import paths

* Updated @lobehub/ui from version 3.4.2 to 3.4.4 in package.json.
* Adjusted import paths for components from '@lobehub/ui/es/' to include '.mjs' extension where necessary.
* Refactored imports for motion library to use 'motion/react-m' instead of 'motion/react'.
* Cleaned up import statements in various components for consistency.

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:46 +08:00
Shinji-Li 613a404bf5 feat: topic message swr cache (#10886)
feat: add topic message swr cache
2025-12-24 12:54:46 +08:00
canisminor1990 d9de7a547e style: fix some style issues 2025-12-24 12:54:46 +08:00
René Wang ba6a5475bc feat: Remove docs_ prefix from URL (#10888)
* feat: Remove page filter

* feat: Replace medium with youtube

* feat: Remove `docs_` prefix from URL

* fix: TS error
2025-12-24 12:54:46 +08:00
Innei c29c02bb23 🐛 fix(desktop): prevent window resize when onboarding (#10887)
 feat: add window resizing and sizing functionality

* Implemented IPC methods for setting window size and resizability.
* Updated Browser and BrowserManager classes to handle new window settings.
* Integrated window settings in DesktopOnboarding component.
* Added new types for window size and resizability in electron-client-ipc.

Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:45 +08:00
canisminor1990 1b0b49cc1a style: fix some style issues 2025-12-24 12:54:45 +08:00
Shinji-Li bc3f3e2a07 feat: support swr local cache (#10884)
* feat: add localstorage cache in swr provider

* feat: add use fetch topic into cache

* feat: add homepage recents api cache

* feat: add group chat initial cache

* docs: update the hint
2025-12-24 12:54:45 +08:00
Arvin Xu 0c5a41f896 feat: support export and import topic JSON (#10885)
* support export topic json

*  feat: support import and export topic data

* update config
2025-12-24 12:54:45 +08:00
YuTengjing c927d5ec86 chore: sync some changes from cloud (#10882) 2025-12-24 12:54:45 +08:00
René Wang c1be517fd6 feat: Improve CMDK (#10877)
* fix: Search more of a speific topic

* refac: Warp CommandItem

* fix: Type error

* fix: AddButton cannot expand

* style: Back button position

* refac: Use context instead of hook

* style: Add hint

* fix: Add missing translation

* lint: Remove unused varibles
2025-12-24 12:54:44 +08:00
canisminor1990 49b97df50c style: update AgentCouncil actions 2025-12-24 12:54:44 +08:00
Shinji-Li 5a79cb9116 🐛 fix: slove when first call thread, not show ai chat message (#10878)
fix: slove when first call thread, not show ai chat message
2025-12-24 12:54:44 +08:00
canisminor1990 a9cda5b46e style: fix antd modal padding 2025-12-24 12:54:44 +08:00
canisminor1990 45630015e2 style: update AgentCouncil style 2025-12-24 12:54:44 +08:00
canisminor1990 33e00b5a77 style: fix some antd v6 style issues 2025-12-24 12:54:44 +08:00
Innei 86dd27b0e1 chore: update references from react-layout-kit to @lobehub/ui for Flexbox and Center components in documentation and rules
Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:44 +08:00
YuTengjing 3c8973b9ba fix: improve tooltip hover behavior in ModelSelect component 2025-12-24 12:54:43 +08:00
canisminor1990 cedcbae038 style: remove react layout kit 2025-12-24 12:54:43 +08:00
canisminor1990 36327a7432 style: remove some memo 2025-12-24 12:54:43 +08:00
arvinxx 7dd30ebb98 🐛 fix: fix thread not working issue 2025-12-24 12:54:43 +08:00
arvinxx c632b22d97 fix agent session group not working 2025-12-24 12:54:43 +08:00
canisminor1990 53e8088f74 style: update tool style 2025-12-24 12:54:43 +08:00
canisminor1990 79274f6dee style: update tools style 2025-12-24 12:54:43 +08:00
Innei 672bcf7740 feat: wrap ConversationArea and ModelSwitchPanel in TooltipGroup for enhanced UI
Signed-off-by: Innei <tukon479@gmail.com>
2025-12-24 12:54:42 +08:00
arvinxx 4f98c1199d fix home send message 2025-12-24 12:54:42 +08:00
canisminor1990 511d6acef5 chore: update antd v6 2025-12-24 12:54:42 +08:00
arvinxx 2e6fd07c19 🌐 style: update i18n 2025-12-24 12:54:42 +08:00
arvinxx 728ce7344d 🚨 chore: fix lint 2025-12-24 12:54:42 +08:00
Shinji-Li 0a39a71245 🔧 chore: update some code 2025-12-24 12:54:42 +08:00
René Wang d2bd8a6d84 feat: support CMD K 2025-12-24 12:54:41 +08:00
arvinxx 685a6cd5a5 feat: server implement 2025-12-24 12:54:41 +08:00
YuTengjing 34d059ffae ♻️ refactor: refactor implement 2025-12-24 12:54:41 +08:00
Innei ac9363784f feat: desktop feature 2025-12-24 12:54:41 +08:00
arvinxx d5ce1442b3 feat: user memory 2025-12-24 12:54:41 +08:00
Shinji-Li ede0ed6d37 feat: agent builder 2025-12-24 12:54:41 +08:00
canisminor1990 83e689f342 💄 style: refactor UI in features 2025-12-24 12:54:40 +08:00
arvinxx 9c46c6ed89 feat: implement server data feature 2025-12-24 12:54:40 +08:00
canisminor1990 e44a82bc14 🌐 chore: add i18n 2025-12-24 12:54:40 +08:00
Innei 849ee3daa3 ♻️ refactor: refactor with electron 2025-12-24 12:54:40 +08:00
canisminor1990 1693fc5666 💄 style: update ui 2025-12-24 12:54:40 +08:00
arvinxx 96c1379e9c 🔧 chore: update config 2025-12-24 12:54:40 +08:00
arvinxx d735e2c810 feat: agent builder and group builder 2025-12-24 12:54:39 +08:00
arvinxx 4ddb491a74 ♻️ refactor: clean code 2025-12-24 12:54:39 +08:00
arvinxx 81d33a6c97 feat: onboarding ui 2025-12-24 12:54:39 +08:00
arvinxx ad14222371 💄 style: rebranding chat ui 2025-12-24 12:54:39 +08:00
Shinji-Li e3c945423f feat: agent builder 2025-12-24 12:54:39 +08:00
arvinxx 91bbbf5cb0 ♻️ refactor: refactor service 2025-12-24 12:54:39 +08:00
arvinxx 78d07c0504 feat: app ui page 2025-12-24 12:54:39 +08:00
arvinxx e3fa62e73a ♻️ refactor: refactor hooks 2025-12-24 12:54:39 +08:00
arvinxx 1b32d3a95d tests: refactor tests 2025-12-24 12:54:38 +08:00
Neko 49ffcb5c06 feat: user memory 2025-12-24 12:54:38 +08:00
arvinxx 6bf4546c92 ♻️ refactor: tools ui 2025-12-24 12:54:38 +08:00
arvinxx 9786d6462a feat: file search feature 2025-12-24 12:54:38 +08:00
arvinxx 9e47c33e9f feat: add db and schema feature 2025-12-24 12:54:38 +08:00
Neko fdae83ca2d feat: add memory implement 2025-12-24 12:54:38 +08:00
Innei 6ff8efacb3 🔧 chore: clean code 2025-12-24 12:54:38 +08:00
arvinxx 1940914e8b feat: code-interpreter tool 2025-12-24 12:54:38 +08:00
Shinji-Li c931909eda feat: code-interpreter tool 2025-12-24 12:54:38 +08:00
Shinji-Li baa29c882b feat: code-interpreter tool 2025-12-24 12:54:37 +08:00
canisminor1990 13ca81bafa feat: rebranding total UI of app 2025-12-24 12:54:37 +08:00
canisminor1990 436d9e5e8d ♻️ refactor: refactor ui and layout 2025-12-24 12:54:37 +08:00
Innei ffd7d23d5c ♻️ refactor: clean desktop relative code 2025-12-24 12:54:37 +08:00
René Wang 492d3ccbf6 feat: page and knowledge base 2025-12-24 12:54:37 +08:00
YuTengjing 5e59388317 feat: user onboarding 2025-12-24 12:54:37 +08:00
arvinxx c305889ac4 feat: add user memory 2025-12-24 12:54:37 +08:00
Innei 1848d279d9 ♻️ refactor: refactor with es-toolkit 2025-12-24 12:54:36 +08:00
Innei a69221f4f8 ♻️ refactor: refactor local-system 2025-12-24 12:54:36 +08:00
Shinji-Li f638b97517 feat: implement agent builder 2025-12-24 12:54:36 +08:00
arvinxx 2255a7cc51 feat: implement builtin agents packages 2025-12-24 12:54:36 +08:00
Neko 7f94ef1478 feat: implement memories package 2025-12-24 12:54:36 +08:00
Innei 27f101f51e ♻️ refactor: refactor implement for desktop 2025-12-24 12:54:36 +08:00
arvinxx 26e73cc438 ♻️ refactor: add builtin tools 2025-12-24 12:54:36 +08:00
arvinxx 2da0691d4e 🔧 chore: update basic config 2025-12-24 12:54:35 +08:00
Innei 10e048c9c5 feat: refactor desktop implement with brand new 2.0 2025-12-24 12:54:35 +08:00
lobehubbot b5720434e4 📝 docs(bot): Auto sync agents & plugin to readme 2025-12-23 11:12:01 +00:00
semantic-release-bot cec3754c48 🔖 chore(release): v2.0.0-next.176 [skip ci]
## [Version&nbsp;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>
2025-12-23 11:10:42 +00:00
Arvin Xu 9be0893dba 👷 build: improve document db schema (#10892)
* add document db schema update

* update migration sql

* update migration sql
2025-12-23 18:54:48 +08:00
Rdmclin2 8c42a934b3 feat: mobile native better auth support (#10871)
* feat: mobile native better auth support

* chore: add android assetlinks

* chore: add android assetlinks

* chore: add expo fingerpoint

* chore: add relation

* chore: add android origin hash

* chore: update passkey table

* chore: optimize version

* chore: remove as any

* fix: sql not exits problem

* fix: passkey statement

* fix:  passkey origin null

* chore: remove strict peer dependencies

* fix: test case

* chore: remove local passkey origin
2025-12-23 15:19:42 +08:00
lobehubbot cf02912965 📝 docs(bot): Auto sync agents & plugin to readme 2025-12-21 13:54:52 +00:00
semantic-release-bot af96f577ec 🔖 chore(release): v2.0.0-next.175 [skip ci]
## [Version&nbsp;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>
2025-12-21 13:53:37 +00:00
5054 changed files with 362599 additions and 272999 deletions
+48 -144
View File
@@ -7,173 +7,77 @@ alwaysApply: false
## Key Points
- 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
- 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)
## Directory Structure
## Key Naming Convention
```plaintext
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
**Flat keys with dot notation** (not nested objects):
```typescript
// Example: src/locales/default/common.ts
// ✅ Correct
export default {
// ... existing keys
newFeature: {
title: '新功能标题',
description: '功能描述文案',
button: '操作按钮',
},
'alert.cloud.action': '立即体验',
'clientDB.error.desc': '数据库初始化遇到问题',
'sync.actions.sync': '立即同步',
'sync.status.ready': '已连接',
};
// ❌ Avoid: Nested objects
export default {
alert: { cloud: { action: '...' } },
};
```
Step 2: If creating a new namespace, export it in src/locales/default/index.ts
**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
```typescript
import newNamespace from './newNamespace';
// ❌ Conflict: clientDB.solve exists as both leaf and parent
'clientDB.solve': '自助解决',
'clientDB.solve.backup.title': '数据备份',
const resources = {
// ... existing namespaces
newNamespace,
} as const;
// ✅ Solution: Use different suffixes
'clientDB.solve.action': '自助解决',
'clientDB.solve.backup.title': '数据备份',
```
### 2. Translation Process
## Workflow
Development mode:
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)
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
## Usage
```tsx
import { useTranslation } from 'react-i18next';
const MyComponent = () => {
const { t } = useTranslation('common');
return (
<div>
<h1>{t('newFeature.title')}</h1>
<p>{t('newFeature.description')}</p>
<button>{t('newFeature.button')}</button>
</div>
);
};
```
### Usage with Parameters
```tsx
const { t } = useTranslation('common');
<p>{t('welcome.message', { name: 'John' })}</p>;
// Corresponding language file:
// welcome: { message: 'Welcome {{name}}!' }
```
### Multiple Namespaces
```tsx
// Basic
t('newFeature.title')
// With parameters
t('alert.cloud.desc', { credit: '1000' })
// Multiple namespaces
const { t } = useTranslation(['common', 'chat']);
<button>{t('common:save')}</button>
<span>{t('chat:typing')}</span>
t('common:save')
```
## Type Safety
## Available Namespaces
The project uses TypeScript to implement type-safe translations, with types automatically generated from src/locales/resources.ts:
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
```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
**Most used:** `common` (shared UI), `chat` (chat features), `setting` (settings)
+146
View File
@@ -0,0 +1,146 @@
---
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
@@ -0,0 +1,152 @@
---
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.
+12 -9
View File
@@ -1,11 +1,12 @@
---
description: react flex layout package `react-layout-kit` usage
globs:
description: flex layout components from `@lobehub/ui` usage
globs:
alwaysApply: false
---
# React Layout Kit 使用指南
react-layout-kit 是一个功能丰富的 React flex 布局组件库,在 lobe-chat 项目中被广泛使用。以下是重点组件的使用方法:
# Flexbox 布局组件使用指南
`@lobehub/ui` 提供了 `Flexbox` 和 `Center` 组件用于创建弹性布局。以下是重点组件的使用方法:
## Flexbox 组件
@@ -14,7 +15,7 @@ Flexbox 是最常用的布局组件,用于创建弹性布局,类似于 CSS
### 基本用法
```jsx
import { Flexbox } from 'react-layout-kit';
import { Flexbox } from '@lobehub/ui';
// 默认垂直布局
<Flexbox>
@@ -58,14 +59,14 @@ import { Flexbox } from 'react-layout-kit';
>
<SidebarContent />
</Flexbox>
{/* 中间内容区 */}
<Flexbox flex={1} style={{ height: '100%' }}>
{/* 主要内容 */}
<Flexbox flex={1} padding={24} style={{ overflowY: 'auto' }}>
<MainContent />
</Flexbox>
{/* 底部区域 */}
<Flexbox
style={{
@@ -86,9 +87,11 @@ Center 是对 Flexbox 的封装,使子元素水平和垂直居中。
### 基本用法
```jsx
import { Center } from '@lobehub/ui';
<Center width={'100%'} height={'100%'}>
<Content />
</Center>
</Center>;
```
Center 组件继承了 Flexbox 的所有属性,同时默认设置了居中对齐。主要用于快速创建居中布局。
@@ -116,4 +119,4 @@ Center 组件继承了 Flexbox 的所有属性,同时默认设置了居中对
- 嵌套 Flexbox 创建复杂布局
- 设置 overflow: 'auto' 使内容可滚动
- 使用 horizontal 创建水平布局,默认为垂直布局
- 与 antd-style 的 useTheme hook 配合使用创建主题响应式的布局
- 与 antd-style 的 useTheme hook 配合使用创建主题响应式的布局
-1
View File
@@ -23,7 +23,6 @@ logo emoji: 🤯
- `@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
+4 -2
View File
@@ -7,7 +7,7 @@ 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 react-layout-kit for flex and centered layouts
- 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
@@ -15,7 +15,7 @@ alwaysApply: false
- 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.js` to see all available components and their props
- Read `node_modules/@lobehub/ui/es/index.mjs` to see all available components and their props
- General
- ActionIcon
@@ -69,7 +69,9 @@ alwaysApply: false
- Drawer
- Modal
- Layout
- Center
- DraggablePanel
- Flexbox
- Footer
- Grid
- Header
+1
View File
@@ -1,5 +1,6 @@
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
@@ -0,0 +1,30 @@
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 }}
@@ -0,0 +1,27 @@
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 }}
@@ -0,0 +1,85 @@
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
@@ -0,0 +1,341 @@
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
+18 -31
View File
@@ -29,16 +29,12 @@ jobs:
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
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
@@ -103,16 +99,11 @@ jobs:
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Setup Node & pnpm
uses: ./.github/actions/setup-node-pnpm
with:
node-version: 24.11.1
package-manager-cache: false
package-manager-cache: 'false'
# node-linker=hoisted 模式将可以确保 asar 压缩可用
- name: Install dependencies
@@ -132,11 +123,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 }}
@@ -156,10 +147,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 盘
@@ -172,10 +163,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 }}
@@ -229,16 +220,12 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v5
- name: Setup Node.js
uses: actions/setup-node@v6
- name: Setup Node & Bun
uses: ./.github/actions/setup-node-bun
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 typecheck
run: pnpm type-check
working-directory: apps/desktop
- name: Test Desktop Client
+2 -3
View File
@@ -113,7 +113,6 @@ CLAUDE.local.md
*.ppt*
*.doc*
*.xls*
e2e/reports
out
out
i18n-unused-keys-report.json
+3 -3
View File
@@ -1,14 +1,14 @@
const { defineConfig } = require('@lobehub/i18n-cli');
module.exports = defineConfig({
entry: 'locales/zh-CN',
entryLocale: 'zh-CN',
entry: 'locales/en-US',
entryLocale: 'en-US',
output: 'locales',
outputLocales: [
'ar',
'bg-BG',
'zh-CN',
'zh-TW',
'en-US',
'ru-RU',
'ja-JP',
'ko-KR',
+1 -1
View File
@@ -87,7 +87,7 @@ All following rules are saved under `.cursor/rules/` directory:
- `react.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
- `packages/react-layout-kit.mdc` Usage guide for Flexbox and Center components from @lobehub/ui
### State Management
+42
View File
@@ -2,6 +2,48 @@
# 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>
+1 -1
View File
@@ -17,7 +17,7 @@ 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 example: tj/feat/feature-name
- git branch name format template: <type>/<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
+15
View File
@@ -107,6 +107,19 @@ 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
@@ -115,6 +128,8 @@ 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
+1 -1
View File
@@ -16,7 +16,7 @@ read @.cursor/rules/project-structure.mdc
- use rebase for git pull
- git commit message should prefix with gitmoji
- git branch name format example: tj/feat/feature-name
- git branch name format template: <type>/<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
+1 -1
View File
@@ -8,7 +8,7 @@ module.exports = defineConfig({
'ar',
'bg-BG',
'zh-TW',
'en-US',
'en',
'ru-RU',
'ja-JP',
'ko-KR',
+16
View File
@@ -4,3 +4,19 @@ 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
@@ -0,0 +1,62 @@
# 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
@@ -0,0 +1 @@
module.exports = require('@lobehub/lint').prettier;
+1
View File
@@ -0,0 +1 @@
module.exports = require('@lobehub/lint').remarklint;
+39
View File
@@ -0,0 +1,39 @@
# 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
@@ -0,0 +1,9 @@
const config = require('@lobehub/lint').stylelint;
module.exports = {
...config,
rules: {
'selector-id-pattern': null,
...config.rules,
},
};
+5 -5
View File
@@ -32,7 +32,7 @@ pnpm install-isolated
pnpm electron:dev
# Type checking
pnpm typecheck
pnpm type-check
# 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 typecheck # TypeScript validation
pnpm lint # ESLint checking
pnpm format # Prettier formatting
pnpm type-check # TypeScript validation
# 3. Testing
pnpm test # Run Vitest tests
@@ -313,7 +313,7 @@ tests/ # Integration tests
```bash
pnpm test # Run all tests
pnpm test:watch # Watch mode
pnpm typecheck # Type validation
pnpm type-check # Type validation
```
### Test Coverage
+5 -5
View File
@@ -32,7 +32,7 @@ pnpm install-isolated
pnpm electron:dev
# 类型检查
pnpm typecheck
pnpm type-check
# 运行测试
pnpm test
@@ -66,9 +66,9 @@ cp .env.desktop .env
pnpm electron:dev # 启动热重载开发服务器
# 2. 代码质量
pnpm lint # ESLint 检查
pnpm format # Prettier 格式化
pnpm typecheck # TypeScript 验证
pnpm lint # ESLint 检查
pnpm format # Prettier 格式化
pnpm type-check # TypeScript 验证
# 3. 测试
pnpm test # 运行 Vitest 测试
@@ -302,7 +302,7 @@ tests/ # 集成测试
```bash
pnpm test # 运行所有测试
pnpm test:watch # 监视模式
pnpm typecheck # 类型验证
pnpm type-check # 类型验证
```
### 测试覆盖
+37 -1
View File
@@ -17,6 +17,10 @@ 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
@@ -54,7 +58,7 @@ const config = {
*/
afterPack: async (context) => {
// Only process macOS builds
if (context.electronPlatformName !== 'darwin') {
if (!['darwin', 'mas'].includes(context.electronPlatformName)) {
return;
}
@@ -68,6 +72,36 @@ 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);
@@ -106,6 +140,8 @@ const config = {
files: [
'dist',
'resources',
// Ensure Next export assets are packaged
'dist/next/**/*',
'!resources/locales',
'!dist/next/docs',
'!dist/next/packages',
+25 -8
View File
@@ -11,21 +11,30 @@
"author": "LobeHub",
"main": "./dist/main/index.js",
"scripts": {
"build": "npm run typecheck && electron-vite build",
"build": "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": "eslint --cache ",
"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",
"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": {
@@ -33,7 +42,8 @@
"electron-window-state": "^5.0.3",
"fetch-socks": "^1.3.2",
"get-port-please": "^3.2.0",
"pdfjs-dist": "4.10.38"
"pdfjs-dist": "4.10.38",
"superjson": "^2.2.6"
},
"devDependencies": {
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
@@ -41,15 +51,17 @@
"@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",
"async-retry": "^1.3.3",
"consola": "^3.4.2",
@@ -57,10 +69,13 @@
"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",
@@ -69,17 +84,19 @@
"https-proxy-agent": "^7.0.6",
"i18next": "^25.7.2",
"just-diff": "^6.0.2",
"lodash": "^4.17.21",
"lodash-es": "^4.17.21",
"prettier": "^3.7.4",
"remark-cli": "^12.0.1",
"resolve": "^1.22.11",
"semver": "^7.7.3",
"set-cookie-parser": "^2.7.2",
"stylelint": "^15.11.0",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"undici": "^7.16.0",
"uuid": "^13.0.0",
"vite": "^7.2.7",
"vitest": "^3.2.4"
"vitest": "^3.2.4",
"zod": "^3.25.76"
},
"pnpm": {
"onlyBuiltDependencies": [
@@ -87,4 +104,4 @@
"electron-builder"
]
}
}
}
+1
View File
@@ -2,4 +2,5 @@ packages:
- '../../packages/electron-server-ipc'
- '../../packages/electron-client-ipc'
- '../../packages/file-loaders'
- '../../packages/desktop-bridge'
- '.'
+25 -31
View File
@@ -1,32 +1,26 @@
{
"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": "تحذير"
}
}
"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": "تحذير"
}
+22 -30
View File
@@ -1,31 +1,23 @@
{
"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": "تخطي هذا الإصدار"
}
}
"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": "تخطي هذا الإصدار"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "تكبير"
}
}
"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": "تكبير"
}
@@ -1,32 +1,26 @@
{
"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": "Предупреждение"
}
}
"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": "Предупреждение"
}
@@ -1,31 +1,23 @@
{
"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": "Пропусни тази версия"
}
}
"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": "Пропусни тази версия"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "Мащаб"
}
}
"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": "Мащаб"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +0,0 @@
{
"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"
}
}
@@ -1,31 +0,0 @@
{
"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"
}
}
@@ -1,71 +0,0 @@
{
"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,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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": "هشدار"
}
}
"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": "هشدار"
}
@@ -1,31 +1,23 @@
{
"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": "این نسخه را نادیده بگیرید"
}
}
"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": "این نسخه را نادیده بگیرید"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "زوم"
}
}
"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": "زوم"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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": "警告"
}
}
"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": "警告"
}
@@ -1,31 +1,23 @@
{
"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": "このバージョンをスキップ"
}
}
"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": "このバージョンをスキップ"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "ズーム"
}
}
"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": "ズーム"
}
@@ -1,32 +1,26 @@
{
"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": "경고"
}
}
"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": "경고"
}
@@ -1,31 +1,23 @@
{
"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": "이 버전 건너뛰기"
}
}
"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": "이 버전 건너뛰기"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "줌"
}
}
"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": "줌"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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ę"
}
}
"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ę"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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": "Предупреждение"
}
}
"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": "Предупреждение"
}
@@ -1,31 +1,23 @@
{
"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": "Пропустить эту версию"
}
}
"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": "Пропустить эту версию"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "Масштаб"
}
}
"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": "Масштаб"
}
@@ -1,32 +1,26 @@
{
"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ı"
}
}
"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ı"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,26 @@
{
"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"
}
}
"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"
}
@@ -1,31 +1,23 @@
{
"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"
}
}
"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"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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"
}
}
"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"
}
@@ -1,32 +1,92 @@
{
"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": "警告"
}
}
"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": "自托管实例"
}
@@ -1,31 +1,44 @@
{
"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": "跳过此版本"
}
}
"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": "等待授权连接"
}
+61 -70
View File
@@ -1,71 +1,62 @@
{
"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": "缩放"
}
}
"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": "缩放"
}
@@ -1,32 +1,26 @@
{
"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": "警告"
}
}
"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": "警告"
}
@@ -1,31 +1,23 @@
{
"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": "跳過此版本"
}
}
"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": "跳過此版本"
}
+52 -70
View File
@@ -1,71 +1,53 @@
{
"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": "縮放"
}
}
"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": "縮放"
}
+2 -2
View File
@@ -1,7 +1,7 @@
import { consola } from 'consola';
import { colors } from 'consola/utils';
import { unset } from 'es-toolkit/compat';
import { diff } from 'just-diff';
import { unset } from 'lodash';
import { existsSync } from 'node:fs';
import {
@@ -34,7 +34,7 @@ export const genDiff = () => {
continue;
}
const clearLocals = [];
const clearLocals: string[] = [];
for (const locale of [i18nConfig.entryLocale, ...i18nConfig.outputLocales]) {
const localeFilepath = outputLocaleJsonFilepath(locale, `${ns}.json`);
+7 -7
View File
@@ -1,18 +1,18 @@
import type { BrowserWindowOpts } from './core/browser/Browser';
export const BrowsersIdentifiers = {
chat: 'chat',
app: 'app',
devtools: 'devtools',
};
export const appBrowsers = {
chat: {
app: {
autoHideMenuBar: true,
height: 800,
identifier: 'chat',
identifier: 'app',
keepAlive: true,
minWidth: 400,
path: '/chat',
path: '/',
showOnInit: true,
titleBarStyle: 'hidden',
vibrancy: 'under-window',
@@ -25,7 +25,7 @@ export const appBrowsers = {
identifier: 'devtools',
maximizable: false,
minWidth: 400,
parentIdentifier: 'chat',
parentIdentifier: 'app',
path: '/desktop/devtools',
titleBarStyle: 'hiddenInset',
vibrancy: 'under-window',
@@ -72,11 +72,11 @@ export const windowTemplates = {
allowMultipleInstances: true,
autoHideMenuBar: true,
baseIdentifier: 'chatSingle',
basePath: '/chat',
basePath: '/agent',
height: 600,
keepAlive: false, // Multi-instance windows don't need to stay alive
minWidth: 400,
parentIdentifier: 'chat',
parentIdentifier: 'app',
titleBarStyle: 'hidden',
vibrancy: 'under-window',
width: 900,
+7 -5
View File
@@ -1,4 +1,5 @@
import { app } from 'electron';
import { pathExistsSync } from 'fs-extra';
import { join } from 'node:path';
export const mainDir = join(__dirname);
@@ -11,7 +12,12 @@ export const buildDir = join(mainDir, '../../build');
const appPath = app.getAppPath();
export const nextStandaloneDir = join(appPath, 'dist', 'next');
const nextExportOutDir = join(appPath, 'dist', 'next', 'out');
const nextExportDefaultDir = join(appPath, 'dist', 'next');
export const nextExportDir = pathExistsSync(nextExportOutDir)
? nextExportOutDir
: nextExportDefaultDir;
export const userDataDir = app.getPath('userData');
@@ -19,10 +25,6 @@ export const appStorageDir = join(userDataDir, 'lobehub-storage');
// ------ Application storage directory ---- //
// db schema hash
export const DB_SCHEMA_HASH_FILENAME = 'lobehub-local-db-schema-hash';
// pglite database dir
export const LOCAL_DATABASE_DIR = 'lobehub-local-db';
// 本地存储文件(模拟 S3
export const FILE_STORAGE_DIR = 'file-storage';
// Plugin 安装目录
+3 -1
View File
@@ -1,9 +1,11 @@
import { dev, linux, macOS, windows } from 'electron-is';
import os from 'node:os';
import { getDesktopEnv } from '@/env';
export const isDev = dev();
export const OFFICIAL_CLOUD_SERVER = process.env.OFFICIAL_CLOUD_SERVER || 'https://lobechat.com';
export const OFFICIAL_CLOUD_SERVER = getDesktopEnv().OFFICIAL_CLOUD_SERVER;
export const isMac = macOS();
export const isWindows = windows();
+1
View File
@@ -0,0 +1 @@
export const ELECTRON_BE_PROTOCOL_SCHEME = 'lobe-backend';
+1 -1
View File
@@ -25,7 +25,7 @@ export const defaultProxySettings: NetworkProxySettings = {
* 存储默认值
*/
export const STORE_DEFAULTS: ElectronMainStore = {
dataSyncConfig: { storageMode: 'local' },
dataSyncConfig: { storageMode: 'cloud' },
encryptedTokens: {},
locale: 'auto',
networkProxy: defaultProxySettings,
+1 -1
View File
@@ -563,7 +563,7 @@ export default class AuthCtr extends ControllerModule {
// Hash codeVerifier using SHA-256
const encoder = new TextEncoder();
const data = encoder.encode(codeVerifier);
const digest = await crypto.subtle.digest('SHA-256', data);
const digest = await crypto.subtle.digest('SHA-256', data as unknown as NodeJS.BufferSource);
// Convert hash result to base64url encoding
const challenge = Buffer.from(digest)
@@ -1,4 +1,9 @@
import { InterceptRouteParams, OpenSettingsWindowOptions } from '@lobechat/electron-client-ipc';
import type {
InterceptRouteParams,
OpenSettingsWindowOptions,
WindowResizableParams,
WindowSizeParams,
} from '@lobechat/electron-client-ipc';
import { findMatchingRoute } from '~common/routes';
import { AppBrowsersIdentifiers, WindowTemplateIdentifiers } from '@/appBrowsers';
@@ -25,25 +30,20 @@ export default class BrowserWindowsCtr extends ControllerModule {
console.log('[BrowserWindowsCtr] Received request to open settings', normalizedOptions);
try {
const query = new URLSearchParams();
if (normalizedOptions.searchParams) {
Object.entries(normalizedOptions.searchParams).forEach(([key, value]) => {
if (value !== undefined) query.set(key, value);
});
}
let fullPath: string;
const tab = normalizedOptions.tab;
if (tab && tab !== 'common' && !query.has('active')) {
query.set('active', tab);
// If direct path is provided, use it directly
if (normalizedOptions.path) {
fullPath = normalizedOptions.path;
} else {
// Legacy support for tab and searchParams
const tab = normalizedOptions.tab;
fullPath = tab ? `/settings/${tab}` : '/settings/common';
}
const queryString = query.toString();
const subPath = tab && !queryString ? `/${tab}` : '';
const fullPath = `/settings${subPath}${queryString ? `?${queryString}` : ''}`;
const mainWindow = this.app.browserManager.getMainWindow();
await mainWindow.loadUrl(fullPath);
mainWindow.show();
mainWindow.broadcast('navigate', { path: fullPath });
return { success: true };
} catch (error) {
@@ -73,6 +73,20 @@ export default class BrowserWindowsCtr extends ControllerModule {
});
}
@IpcMethod()
setWindowSize(params: WindowSizeParams) {
this.withSenderIdentifier((identifier) => {
this.app.browserManager.setWindowSize(identifier, params);
});
}
@IpcMethod()
setWindowResizable(params: WindowResizableParams) {
this.withSenderIdentifier((identifier) => {
this.app.browserManager.setWindowResizable(identifier, params.resizable);
});
}
/**
* Handle route interception requests
* Responsible for handling route interception requests from the renderer process
+579
View File
@@ -0,0 +1,579 @@
import { exec } from 'node:child_process';
import { createHash, randomUUID } from 'node:crypto';
import path from 'node:path';
import { promisify } from 'node:util';
import superjson from 'superjson';
import FileService from '@/services/fileSrv';
import { createLogger } from '@/utils/logger';
import { MCPClient } from '../libs/mcp/client';
import type { MCPClientParams, ToolCallContent, ToolCallResult } from '../libs/mcp/types';
import { ControllerModule, IpcMethod } from './index';
const execPromise = promisify(exec);
const logger = createLogger('controllers:McpCtr');
/**
* Desktop-only copy of `@lobechat/types`'s `CheckMcpInstallResult`.
*
* We intentionally keep it local to avoid pulling the web app's path-alias
* expectations (e.g. `@/config/*`) into the desktop `tsgo` typecheck.
*/
interface CheckMcpInstallResult {
allDependenciesMet?: boolean;
allOptions?: Array<{
allDependenciesMet?: boolean;
connection?: {
args?: string[];
command?: string;
installationMethod: string;
packageName?: string;
repositoryUrl?: string;
};
isRecommended?: boolean;
packageInstalled?: boolean;
systemDependencies?: Array<{
error?: string;
installed: boolean;
meetRequirement: boolean;
name: string;
version?: string;
}>;
}>;
configSchema?: any;
connection?: {
args?: string[];
command?: string;
type: 'stdio' | 'http';
url?: string;
};
error?: string;
isRecommended?: boolean;
needsConfig?: boolean;
packageInstalled?: boolean;
platform: string;
success: boolean;
systemDependencies?: Array<{
error?: string;
installed: boolean;
meetRequirement: boolean;
name: string;
version?: string;
}>;
}
interface CustomPluginMetadata {
avatar?: string;
description?: string;
name?: string;
}
interface GetStdioMcpServerManifestInput {
args?: string[];
command: string;
env?: Record<string, string>;
metadata?: CustomPluginMetadata;
name: string;
type?: 'stdio';
}
interface GetStreamableMcpServerManifestInput {
auth?: {
accessToken?: string;
token?: string;
type: 'none' | 'bearer' | 'oauth2';
};
headers?: Record<string, string>;
identifier: string;
metadata?: CustomPluginMetadata;
url: string;
}
interface CallToolInput {
args: any;
env: any;
params: GetStdioMcpServerManifestInput;
toolName: string;
}
interface SuperJSONSerialized<T = unknown> {
json: T;
meta?: any;
}
const isSuperJSONSerialized = (value: unknown): value is SuperJSONSerialized => {
if (!value || typeof value !== 'object') return false;
return 'json' in value;
};
const deserializePayload = <T>(payload: unknown): T => {
// Keep backward compatibility for older renderer builds that might not serialize yet
if (isSuperJSONSerialized(payload)) return superjson.deserialize(payload as any) as T;
return payload as T;
};
const serializePayload = <T>(payload: T): SuperJSONSerialized =>
superjson.serialize(payload) as any;
const safeParseToRecord = (value: unknown): Record<string, unknown> => {
if (value && typeof value === 'object' && !Array.isArray(value))
return value as Record<string, unknown>;
if (typeof value === 'string') {
try {
const parsed = JSON.parse(value) as unknown;
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
return parsed as Record<string, unknown>;
} catch {
// ignore
}
}
return {};
};
const getFileExtensionFromMimeType = (mimeType: string, fallback: string) => {
const [, ext] = mimeType.split('/');
return ext || fallback;
};
const todayShard = () => new Date().toISOString().split('T')[0];
const toMarkdown = async (
blocks: ToolCallContent[] | null | undefined,
getHTTPURL: (key: string) => Promise<string>,
) => {
if (!blocks) return '';
const parts = await Promise.all(
blocks.map(async (item) => {
switch (item.type) {
case 'text': {
return item.text;
}
case 'image': {
const url = await getHTTPURL(item.data);
return `![](${url})`;
}
case 'audio': {
const url = await getHTTPURL(item.data);
return `<resource type="${item.type}" url="${url}" />`;
}
case 'resource': {
return `<resource type="${item.type}">${JSON.stringify(item.resource)}</resource>}`;
}
default: {
return '';
}
}
}),
);
return parts.filter(Boolean).join('\n\n');
};
/**
* MCP Controller (Desktop Main Process)
* Implements the same routes as `src/server/routers/desktop/mcp.ts`, but via IPC.
*/
export default class McpCtr extends ControllerModule {
static override readonly groupName = 'mcp';
private get fileService() {
return this.app.getService(FileService);
}
private async createClient(params: MCPClientParams) {
const client = new MCPClient(params);
await client.initialize();
return client;
}
private async processContentBlocks(blocks: ToolCallContent[]): Promise<ToolCallContent[]> {
return Promise.all(
blocks.map(async (block) => {
if (block.type !== 'image' && block.type !== 'audio') return block;
const ext = getFileExtensionFromMimeType(
block.mimeType,
block.type === 'image' ? 'png' : 'mp3',
);
const base64 = block.data;
const buffer = Buffer.from(base64, 'base64');
const hash = createHash('sha256').update(buffer).digest('hex');
const id = randomUUID();
const filePath = path.posix.join('mcp', `${block.type}s`, todayShard(), `${id}.${ext}`);
const { metadata } = await this.fileService.uploadFile({
content: base64,
filename: `${id}.${ext}`,
hash,
path: filePath,
type: block.mimeType,
});
return { ...block, data: metadata.path };
}),
);
}
@IpcMethod()
async getStdioMcpServerManifest(payload: SuperJSONSerialized<GetStdioMcpServerManifestInput>) {
const input = deserializePayload<GetStdioMcpServerManifestInput>(payload);
const params: MCPClientParams = {
args: input.args || [],
command: input.command,
env: input.env,
name: input.name,
type: 'stdio',
};
const client = await this.createClient(params);
try {
const manifest = await client.listManifests();
const identifier = input.name;
const tools = manifest.tools || [];
return serializePayload({
api: tools.map((item) => ({
description: item.description,
name: item.name,
parameters: item.inputSchema as any,
})),
identifier,
meta: {
avatar: input.metadata?.avatar || 'MCP_AVATAR',
description:
input.metadata?.description ||
`${identifier} MCP server has ` +
Object.entries(manifest)
.filter(([key]) => ['tools', 'prompts', 'resources'].includes(key))
.map(([key, item]) => `${(item as Array<any>)?.length} ${key}`)
.join(','),
title: input.metadata?.name || identifier,
},
...manifest,
mcpParams: params,
type: 'mcp' as any,
});
} finally {
await client.disconnect();
}
}
@IpcMethod()
async getStreamableMcpServerManifest(
payload: SuperJSONSerialized<GetStreamableMcpServerManifestInput>,
) {
const input = deserializePayload<GetStreamableMcpServerManifestInput>(payload);
const params: MCPClientParams = {
auth: input.auth,
headers: input.headers,
name: input.identifier,
type: 'http',
url: input.url,
};
const client = await this.createClient(params);
try {
const tools = await client.listTools();
const identifier = input.identifier;
return serializePayload({
api: tools.map((item) => ({
description: item.description,
name: item.name,
parameters: item.inputSchema as any,
})),
identifier,
mcpParams: params,
meta: {
avatar: input.metadata?.avatar || 'MCP_AVATAR',
description:
input.metadata?.description ||
`${identifier} MCP server has ${tools.length} tools, like "${tools[0]?.name}"`,
title: identifier,
},
type: 'mcp' as any,
});
} finally {
await client.disconnect();
}
}
@IpcMethod()
async callTool(payload: SuperJSONSerialized<CallToolInput>) {
const input = deserializePayload<CallToolInput>(payload);
const params: MCPClientParams = {
args: input.params.args || [],
command: input.params.command,
env: input.env,
name: input.params.name,
type: 'stdio',
};
const client = await this.createClient(params);
try {
const args = safeParseToRecord(input.args);
const raw = (await client.callTool(input.toolName, args)) as ToolCallResult;
const processed = raw.isError ? raw.content : await this.processContentBlocks(raw.content);
const content = await toMarkdown(processed, (key) => this.fileService.getFileHTTPURL(key));
return serializePayload({
content,
state: { ...raw, content: processed },
success: true,
});
} catch (error) {
logger.error('callTool failed:', error);
throw error;
} finally {
await client.disconnect();
}
}
// ---------- MCP Install Check (local system) ----------
private getInstallInstructions(installInstructions: any) {
if (!installInstructions) return undefined;
let current: string | undefined;
switch (process.platform) {
case 'darwin': {
current = installInstructions.macos;
break;
}
case 'linux': {
current = installInstructions.linux_debian || installInstructions.linux;
break;
}
case 'win32': {
current = installInstructions.windows;
break;
}
}
return { current, manual: installInstructions.manual };
}
private async checkSystemDependency(dependency: any) {
try {
const checkCommand = dependency.checkCommand || `${dependency.name} --version`;
const { stdout, stderr } = await execPromise(checkCommand);
if (stderr && !stdout) {
return {
error: stderr,
installInstructions: this.getInstallInstructions(dependency.installInstructions),
installed: false,
meetRequirement: false,
name: dependency.name,
requiredVersion: dependency.requiredVersion,
};
}
const output = String(stdout || '').trim();
let version = output;
if (dependency.versionParsingRequired) {
const versionMatch = output.match(/[Vv]?(\d+(\.\d+)*)/);
if (versionMatch) version = versionMatch[0];
}
let meetRequirement = true;
if (dependency.requiredVersion) {
const currentVersion = String(version).replace(/^[Vv]/, '');
const currentNum = Number.parseFloat(currentVersion);
const requirementMatch = String(dependency.requiredVersion).match(/([<=>]+)?(\d+(\.\d+)*)/);
if (requirementMatch) {
const [, operator = '=', requiredVersion] = requirementMatch;
const requiredNum = Number.parseFloat(requiredVersion);
switch (operator) {
case '>=': {
meetRequirement = currentNum >= requiredNum;
break;
}
case '>': {
meetRequirement = currentNum > requiredNum;
break;
}
case '<=': {
meetRequirement = currentNum <= requiredNum;
break;
}
case '<': {
meetRequirement = currentNum < requiredNum;
break;
}
default: {
meetRequirement = currentNum === requiredNum;
break;
}
}
}
}
return {
installInstructions: this.getInstallInstructions(dependency.installInstructions),
installed: true,
meetRequirement,
name: dependency.name,
requiredVersion: dependency.requiredVersion,
version,
};
} catch (error) {
return {
error: error instanceof Error ? error.message : 'Unknown error',
installInstructions: this.getInstallInstructions(dependency.installInstructions),
installed: false,
meetRequirement: false,
name: dependency.name,
requiredVersion: dependency.requiredVersion,
};
}
}
private async checkPackageInstalled(installationMethod: string, details: any) {
if (installationMethod === 'npm') {
const packageName = details?.packageName;
if (!packageName) return { installed: false };
try {
const { stdout } = await execPromise(`npm list -g ${packageName} --depth=0`);
if (!stdout.includes('(empty)') && stdout.includes(packageName)) return { installed: true };
} catch {
// ignore
}
try {
await execPromise(`npx -y ${packageName} --version`);
return { installed: true };
} catch (error) {
return {
error: error instanceof Error ? error.message : 'Unknown error',
installed: false,
};
}
}
if (installationMethod === 'python') {
const packageName = details?.packageName;
if (!packageName) return { installed: false };
const pythonCommand = details?.pythonCommand || 'python';
try {
const command = `${pythonCommand} -m pip list | grep -i "${packageName}"`;
const { stdout } = await execPromise(command);
if (stdout.trim() && stdout.toLowerCase().includes(String(packageName).toLowerCase())) {
return { installed: true };
}
} catch {
// ignore
}
try {
const importCommand = `${pythonCommand} -c "import ${String(packageName).replace('-', '_')}; print('Package installed')"`;
const { stdout } = await execPromise(importCommand);
if (stdout.includes('Package installed')) return { installed: true };
} catch {
// ignore
}
return { installed: false };
}
// manual or unknown
return { installed: false };
}
private async checkDeployOption(option: any) {
const systemDependenciesResults = [];
if (Array.isArray(option.systemDependencies) && option.systemDependencies.length > 0) {
for (const dep of option.systemDependencies) {
systemDependenciesResults.push(await this.checkSystemDependency(dep));
}
}
const packageResult = await this.checkPackageInstalled(
option.installationMethod,
option.installationDetails,
);
const packageInstalled = Boolean((packageResult as any).installed);
const allDependenciesMet = systemDependenciesResults.every((dep: any) => dep.meetRequirement);
const configSchema = option.connection?.configSchema;
const needsConfig = Boolean(
configSchema &&
((Array.isArray(configSchema.required) && configSchema.required.length > 0) ||
(configSchema.properties &&
Object.values(configSchema.properties).some((prop: any) => prop.required === true))),
);
const connection = option.connection?.url
? { ...option.connection, type: 'http' }
: { ...option.connection, type: 'stdio' };
return {
allDependenciesMet,
configSchema,
connection,
isRecommended: option.isRecommended,
needsConfig,
packageInstalled,
systemDependencies: systemDependenciesResults,
};
}
@IpcMethod()
async validMcpServerInstallable(
payload: SuperJSONSerialized<{
deploymentOptions: any[];
}>,
) {
const input = deserializePayload<{ deploymentOptions: any[] }>(payload);
try {
const options = input.deploymentOptions || [];
const results = [];
for (const option of options) {
results.push(await this.checkDeployOption(option));
}
const recommendedResult = results.find((r: any) => r.isRecommended && r.allDependenciesMet);
const firstInstallableResult = results.find((r: any) => r.allDependenciesMet);
const bestResult = recommendedResult || firstInstallableResult || results[0];
const checkResult: CheckMcpInstallResult = {
...(bestResult || {}),
allOptions: results as any,
platform: process.platform,
success: true,
};
if (bestResult?.needsConfig) {
checkResult.needsConfig = true;
checkResult.configSchema = bestResult.configSchema;
}
return serializePayload(checkResult);
} catch (error) {
return serializePayload({
error:
error instanceof Error
? error.message
: 'Unknown error when checking MCP plugin installation status',
platform: process.platform,
success: false,
});
}
}
}
@@ -138,7 +138,7 @@ export default class McpInstallController extends ControllerModule {
// 通过应用实例广播到前端
if (this.app?.browserManager) {
this.app.browserManager.broadcastToWindow('chat', 'mcpInstallRequest', installRequest);
this.app.browserManager.broadcastToWindow('app', 'mcpInstallRequest', installRequest);
logger.debug(`🔧 [McpInstall] Install request broadcasted successfully`);
return true;
} else {
@@ -1,6 +1,5 @@
import { NetworkProxySettings } from '@lobechat/electron-client-ipc';
import { merge } from 'lodash';
import { isEqual } from 'lodash-es';
import { isEqual, merge } from 'es-toolkit/compat';
import { defaultProxySettings } from '@/const/store';
import { createLogger } from '@/utils/logger';
@@ -2,9 +2,10 @@ import {
DesktopNotificationResult,
ShowDesktopNotificationParams,
} from '@lobechat/electron-client-ipc';
import { Notification, app } from 'electron';
import { Notification, app, systemPreferences } from 'electron';
import { macOS, windows } from 'electron-is';
import { getIpcContext } from '@/utils/ipc';
import { createLogger } from '@/utils/logger';
import { ControllerModule, IpcMethod } from './index';
@@ -13,6 +14,54 @@ const logger = createLogger('controllers:NotificationCtr');
export default class NotificationCtr extends ControllerModule {
static override readonly groupName = 'notification';
@IpcMethod()
async getNotificationPermissionStatus(): Promise<string> {
if (!Notification.isSupported()) return 'denied';
// Keep a stable status string for renderer-side UI mapping.
// Screen3 expects macOS to return 'authorized' when granted.
if (!macOS()) return 'authorized';
// Electron 38 no longer exposes `systemPreferences.getNotificationSettings()` in types,
// and some runtimes don't provide it at all. Use the renderer's Notification.permission
// as a reliable fallback.
const context = getIpcContext();
const sender = context?.sender;
if (!sender) return 'notDetermined';
const permission = await sender.executeJavaScript('Notification.permission', true);
return permission === 'granted' ? 'authorized' : 'denied';
}
@IpcMethod()
async requestNotificationPermission(): Promise<void> {
logger.debug('Requesting notification permission by sending a test notification');
if (!Notification.isSupported()) {
logger.warn('System does not support desktop notifications');
return;
}
// On macOS, ask permission via Web Notification API first when possible.
// This helps keep `Notification.permission` in sync for subsequent status checks.
if (macOS()) {
try {
const mainWindow = this.app.browserManager.getMainWindow().browserWindow;
await mainWindow.webContents.executeJavaScript('Notification.requestPermission()', true);
} catch (error) {
logger.debug(
'Notification.requestPermission() failed or is unavailable, continuing with test notification',
error,
);
}
}
const notification = new Notification({
body: 'LobeHub can now send you notifications.',
title: 'Notification Permission',
});
notification.show();
}
/**
* Set up desktop notifications after the application is ready
*/
@@ -45,6 +45,24 @@ export default class RemoteServerConfigCtr extends ControllerModule {
*/
private readonly encryptedTokensKey = 'encryptedTokens';
/**
* Normalize legacy config that used local storageMode.
* Local mode has been removed; fall back to cloud.
*/
private normalizeConfig = (config: DataSyncConfig): DataSyncConfig => {
if (config.storageMode !== 'local') return config;
const nextConfig: DataSyncConfig = {
...config,
remoteServerUrl: config.remoteServerUrl || OFFICIAL_CLOUD_SERVER,
storageMode: 'cloud',
};
this.app.storeManager.set('dataSyncConfig', nextConfig);
return nextConfig;
};
/**
* Get remote server configuration
*/
@@ -54,12 +72,13 @@ export default class RemoteServerConfigCtr extends ControllerModule {
const { storeManager } = this.app;
const config: DataSyncConfig = storeManager.get('dataSyncConfig');
const normalized = this.normalizeConfig(config);
logger.debug(
`Remote server config: active=${config.active}, storageMode=${config.storageMode}, url=${config.remoteServerUrl}`,
`Remote server config: active=${normalized.active}, storageMode=${normalized.storageMode}, url=${normalized.remoteServerUrl}`,
);
return config;
return normalized;
}
/**
@@ -73,8 +92,9 @@ export default class RemoteServerConfigCtr extends ControllerModule {
const { storeManager } = this.app;
const prev: DataSyncConfig = storeManager.get('dataSyncConfig');
// Save configuration
storeManager.set('dataSyncConfig', { ...prev, ...config });
// Save configuration with legacy local storage fallback
const merged = this.normalizeConfig({ ...prev, ...config });
storeManager.set('dataSyncConfig', merged);
return true;
}
@@ -88,7 +108,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
const { storeManager } = this.app;
// Clear instance configuration
storeManager.set('dataSyncConfig', { storageMode: 'local' });
storeManager.set('dataSyncConfig', { active: false, storageMode: 'cloud' });
// Clear tokens (if any)
await this.clearTokens();
@@ -468,7 +488,7 @@ export default class RemoteServerConfigCtr extends ControllerModule {
}
async getRemoteServerUrl(config?: DataSyncConfig) {
const dataConfig = config ? config : await this.getRemoteServerConfig();
const dataConfig = this.normalizeConfig(config ? config : await this.getRemoteServerConfig());
return dataConfig.storageMode === 'cloud' ? OFFICIAL_CLOUD_SERVER : dataConfig.remoteServerUrl;
}
@@ -1,8 +1,4 @@
import {
ProxyTRPCRequestParams,
ProxyTRPCRequestResult,
ProxyTRPCStreamRequestParams,
} from '@lobechat/electron-client-ipc';
import { ProxyTRPCStreamRequestParams } from '@lobechat/electron-client-ipc';
import { IpcMainEvent, WebContents, ipcMain } from 'electron';
import { HttpProxyAgent } from 'http-proxy-agent';
import { HttpsProxyAgent } from 'https-proxy-agent';
@@ -15,7 +11,7 @@ import { defaultProxySettings } from '@/const/store';
import { createLogger } from '@/utils/logger';
import RemoteServerConfigCtr from './RemoteServerConfigCtr';
import { ControllerModule, IpcMethod } from './index';
import { ControllerModule } from './index';
// Create logger
const logger = createLogger('controllers:RemoteServerSyncCtr');
@@ -174,129 +170,12 @@ export default class RemoteServerSyncCtr extends ControllerModule {
});
if (requestBody) {
clientReq.write(Buffer.from(requestBody));
clientReq.write(Buffer.from(requestBody as string));
}
clientReq.end();
}
/**
* Helper function to perform the actual request forwarding to the remote server.
* Accepts arguments from IPC and returns response details.
*/
private async forwardRequest(args: {
accessToken: string | null;
body?: string | ArrayBuffer;
headers: Record<string, string>;
method: string;
remoteServerUrl: string;
urlPath: string; // Pass the base URL
}): Promise<{
// Node headers type
body: Buffer;
headers: Record<string, string | string[] | undefined>;
status: number;
statusText: string; // Return body as Buffer
}> {
const {
urlPath,
method,
headers: originalHeaders,
body: requestBody,
accessToken,
remoteServerUrl,
} = args;
const pathname = new URL(urlPath, remoteServerUrl).pathname; // Extract pathname from URL
const logPrefix = `[ForwardRequest ${method} ${pathname}]`; // Add prefix for easier correlation
if (!accessToken) {
logger.error(`${logPrefix} No access token provided`); // Enhanced log
return {
body: Buffer.from(''),
headers: {},
status: 401,
statusText: 'Authentication required, missing token',
};
}
// 1. Determine target URL and prepare request options
const targetUrl = new URL(urlPath, remoteServerUrl); // Combine base URL and path
const { requestOptions, requester } = this.createRequester({
accessToken,
headers: originalHeaders,
method,
url: targetUrl,
});
// 2. Make the request and capture response
return new Promise((resolve) => {
const clientReq = requester.request(requestOptions, (clientRes: IncomingMessage) => {
const chunks: Buffer[] = [];
clientRes.on('data', (chunk) => {
chunks.push(chunk);
});
clientRes.on('end', () => {
const responseBody = Buffer.concat(chunks);
resolve({
// These are IncomingHttpHeaders
body: responseBody,
headers: clientRes.headers,
status: clientRes.statusCode || 500,
statusText: clientRes.statusMessage || 'Unknown Status',
});
});
clientRes.on('error', (error) => {
// Error during response streaming
logger.error(
`${logPrefix} Error reading response stream from ${targetUrl.toString()}:`,
error,
); // Enhanced log
// Rejecting might be better, but we need to resolve the outer promise for proxyTRPCRequest
resolve({
body: Buffer.from(`Error reading response stream: ${error.message}`),
headers: {},
status: 502,
// Bad Gateway
statusText: 'Error reading response stream',
});
});
});
clientReq.on('error', (error) => {
logger.error(`${logPrefix} Error forwarding request to ${targetUrl.toString()}:`, error); // Enhanced log
// Reject or resolve with error status for the outer promise
resolve({
body: Buffer.from(`Error forwarding request: ${error.message}`),
headers: {},
status: 502,
// Bad Gateway
statusText: 'Error forwarding request',
});
});
// 3. Send request body if present
if (requestBody) {
if (typeof requestBody === 'string') {
clientReq.write(requestBody, 'utf8'); // Specify encoding for strings
} else if (requestBody instanceof ArrayBuffer) {
clientReq.write(Buffer.from(requestBody)); // Convert ArrayBuffer to Buffer
} else {
// Should not happen based on type, but handle defensively
logger.warn(`${logPrefix} Unsupported request body type received:`, typeof requestBody); // Enhanced log
}
}
clientReq.end(); // Finalize the request
});
}
private createRequester({
headers,
accessToken,
@@ -341,144 +220,4 @@ export default class RemoteServerSyncCtr extends ControllerModule {
const requester = url.protocol === 'https:' ? https : http;
return { requestOptions, requester };
}
/**
* Handles the 'proxy-trpc-request' IPC call from the renderer process.
* This method should be invoked by the ipcMain.handle setup in your main process entry point.
*/
@IpcMethod()
public async proxyTRPCRequest(args: ProxyTRPCRequestParams): Promise<ProxyTRPCRequestResult> {
logger.debug('Received proxyTRPCRequest IPC call:', {
headers: args.headers,
method: args.method,
urlPath: args.urlPath, // Log headers too for context
});
const url = new URL(args.urlPath, 'http://a.b');
const logPrefix = `[ProxyTRPC ${args.method} ${url.pathname}]`; // Prefix for this specific request
try {
const config = await this.remoteServerConfigCtr.getRemoteServerConfig();
if (!config.active || (config.storageMode === 'selfHost' && !config.remoteServerUrl)) {
logger.warn(
`${logPrefix} Remote server sync not active or configured. Rejecting proxy request.`,
); // Enhanced log
return {
body: Buffer.from('Remote server sync not active or configured').buffer,
headers: {},
status: 503,
// Service Unavailable
statusText: 'Remote server sync not active or configured', // Return ArrayBuffer
};
}
const remoteServerUrl = await this.remoteServerConfigCtr.getRemoteServerUrl();
// Get initial token
let token = await this.remoteServerConfigCtr.getAccessToken();
logger.debug(
`${logPrefix} Initial token check: ${token ? 'Token exists' : 'No token found'}`,
); // Added log
logger.info(`${logPrefix} Attempting to forward request...`); // Added log
let response = await this.forwardRequest({ ...args, accessToken: token, remoteServerUrl });
// Handle 401: Refresh token and retry if necessary
if (response.status === 401) {
logger.info(`${logPrefix} Received 401 from forwarded request. Attempting token refresh.`); // Enhanced log
const refreshed = await this.refreshTokenIfNeeded(logPrefix); // Pass prefix for context
if (refreshed) {
const newToken = await this.remoteServerConfigCtr.getAccessToken();
if (newToken) {
logger.info(`${logPrefix} Token refreshed successfully, retrying the request.`); // Enhanced log
response = await this.forwardRequest({
...args,
accessToken: newToken,
remoteServerUrl,
});
} else {
logger.error(
`${logPrefix} Token refresh reported success, but failed to retrieve new token. Keeping original 401 response.`,
); // Enhanced log
// Keep the original 401 response
}
} else {
logger.error(`${logPrefix} Token refresh failed. Keeping original 401 response.`); // Enhanced log
// Keep the original 401 response
}
}
// Convert headers and body to format defined in IPC event
const responseHeaders: Record<string, string> = {};
for (const [key, value] of Object.entries(response.headers)) {
if (value !== undefined) {
responseHeaders[key.toLowerCase()] = Array.isArray(value) ? value.join(', ') : value;
}
}
// Return the final response, ensuring body is serializable (string or ArrayBuffer)
const responseBody = response.body; // Buffer
// IMPORTANT: Check IPC limits. Large bodies might fail. Consider chunking if needed.
// Convert Buffer to ArrayBuffer for IPC
const finalBody = responseBody.buffer.slice(
responseBody.byteOffset,
responseBody.byteOffset + responseBody.byteLength,
);
logger.debug(`${logPrefix} Forwarding successful. Status: ${response.status}`); // Added log
return {
body: finalBody as ArrayBuffer,
headers: responseHeaders,
status: response.status,
statusText: response.statusText, // Return ArrayBuffer
};
} catch (error) {
logger.error(`${logPrefix} Unhandled error processing proxyTRPCRequest:`, error); // Enhanced log
// Ensure a serializable error response is returned
return {
body: Buffer.from(
`Internal Server Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
).buffer,
headers: {},
status: 500,
statusText: 'Internal Server Error during proxy', // Return ArrayBuffer
};
}
}
/**
* Attempts to refresh the access token by calling the RemoteServerConfigCtr.
* @returns Whether token refresh was successful
*/
private async refreshTokenIfNeeded(callerLogPrefix: string = '[RefreshToken]'): Promise<boolean> {
// Added prefix parameter
const logPrefix = `${callerLogPrefix} [RefreshTrigger]`; // Updated prefix
logger.debug(`${logPrefix} Entered refreshTokenIfNeeded.`);
try {
logger.info(`${logPrefix} Triggering refreshAccessToken in RemoteServerConfigCtr.`);
const result = await this.remoteServerConfigCtr.refreshAccessToken();
if (result.success) {
logger.info(`${logPrefix} refreshAccessToken call completed successfully.`);
return true;
} else {
logger.error(`${logPrefix} refreshAccessToken call failed: ${result.error}`);
return false;
}
} catch (error) {
logger.error(`${logPrefix} Exception occurred while calling refreshAccessToken:`, error);
return false;
}
}
/**
* Clean up resources - No protocol handler to unregister anymore
*/
destroy() {
logger.info('Destroying RemoteServerSyncCtr');
// Nothing specific to clean up here regarding request handling now
}
}

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