mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-16 12:36:07 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c763054764 | |||
| 4ca2aceea4 | |||
| 5dfd40d586 | |||
| 76b7316ca7 | |||
| f577b2ea00 | |||
| cfaebdddbf | |||
| 6f16b9ecf3 | |||
| 2c9810e37d | |||
| 3e8c95a785 | |||
| 5720078296 | |||
| 18404f04a8 | |||
| 22b2f95794 | |||
| dca922103f | |||
| 1706dc2a50 | |||
| 9a401d40fd | |||
| ac0c15ee6e | |||
| 6e6777ab20 | |||
| b36972ce0a | |||
| 1297d0434c | |||
| 2fb4641457 | |||
| 7233bc9812 | |||
| 3e0edafe36 | |||
| 1803e7768a | |||
| 2011b3e12c | |||
| bd6d9c35a6 | |||
| cc17f3b4ca | |||
| 09dac18e78 | |||
| 24d7959c7e | |||
| 2799f4332c | |||
| 21895401db | |||
| c8b7760017 | |||
| 2d3ed3032f | |||
| 313f02e5a7 | |||
| 4f0fd0cf8c | |||
| c381081fb3 | |||
| b3c2eec633 | |||
| 459642e15d | |||
| b2c91e9efa | |||
| 80c500512a | |||
| 8b08f8048b |
@@ -0,0 +1,7 @@
|
||||
# copy this file to .env when you want to develop the desktop app or you will fail
|
||||
APP_URL=http://localhost:3015
|
||||
FEATURE_FLAGS=+pin_list
|
||||
KEY_VAULTS_SECRET=oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE=
|
||||
DATABASE_URL=postgresql://postgres@localhost:5432/postgres
|
||||
DEFAULT_AGENT_CONFIG="model=qwen2.5;provider=ollama;chatConfig.searchFCModel.provider=ollama;chatConfig.searchFCModel.model=qwen2.5"
|
||||
SYSTEM_AGENT="default=ollama/qwen2.5"
|
||||
@@ -10,6 +10,7 @@ module.exports = ({ version, prNumber, branch }) => {
|
||||
|
||||
**Version**: \`${version}\`
|
||||
**PR**: [#${prNumber}](${prLink})
|
||||
**Release Time**: \`${new Date().toISOString()}\`
|
||||
|
||||
## ⚠️ Important Notice
|
||||
|
||||
@@ -36,6 +37,7 @@ Please report any issues found in this build directly in the PR discussion.
|
||||
|
||||
**版本**: \`${version}\`
|
||||
**PR**: [#${prNumber}](${prLink})
|
||||
**发布时间**: \`${new Date().toISOString()}\`
|
||||
|
||||
## ⚠️ 重要提示
|
||||
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
name: Desktop PR Build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [synchronize, labeled, unlabeled] # PR 更新或标签变化时触发
|
||||
|
||||
# 确保同一时间只运行一个相同的 workflow,取消正在进行的旧的运行
|
||||
concurrency:
|
||||
group: ${{ github.ref }}-${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PR_TAG_PREFIX: pr- # PR 构建版本的前缀标识
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Code quality check
|
||||
# 添加 PR label 触发条件,只有添加了 Build Desktop 标签的 PR 才会触发构建
|
||||
if: contains(github.event.pull_request.labels.*.name, 'Build Desktop')
|
||||
runs-on: ubuntu-latest # 只在 ubuntu 上运行一次检查
|
||||
steps:
|
||||
- name: Checkout base
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- name: Install deps
|
||||
run: pnpm install
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
|
||||
version:
|
||||
name: Determine version
|
||||
# 与 test job 相同的触发条件
|
||||
if: contains(github.event.pull_request.labels.*.name, 'Build Desktop')
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
# 输出版本信息,供后续 job 使用
|
||||
version: ${{ steps.set_version.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
# 主要逻辑:确定构建版本号
|
||||
- name: Set version
|
||||
id: set_version
|
||||
run: |
|
||||
# 从 apps/desktop/package.json 读取基础版本号
|
||||
base_version=$(node -p "require('./apps/desktop/package.json').version")
|
||||
|
||||
# PR 构建:在基础版本号上添加 PR 信息
|
||||
pr_number="${{ github.event.pull_request.number }}"
|
||||
ci_build_number="${{ github.run_number }}" # CI 构建编号
|
||||
version="${base_version}-nightly.pr${pr_number}.${ci_build_number}"
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "📦 Release Version: ${version} (based on base version ${base_version})"
|
||||
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
|
||||
# 输出版本信息总结,方便在 GitHub Actions 界面查看
|
||||
- name: Version Summary
|
||||
run: |
|
||||
echo "🚦 Release Version: ${{ steps.set_version.outputs.version }}"
|
||||
|
||||
build:
|
||||
needs: [version, test]
|
||||
name: Build Desktop App
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 9
|
||||
|
||||
# node-linker=hoisted 模式将可以确保 asar 压缩可用
|
||||
- name: Install deps
|
||||
run: pnpm install --node-linker=hoisted
|
||||
|
||||
- name: Install deps on Desktop
|
||||
run: npm run install-isolated --prefix=./apps/desktop
|
||||
|
||||
# 设置 package.json 的版本号
|
||||
- name: Set package version
|
||||
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }} true
|
||||
|
||||
# macOS 构建处理
|
||||
- name: Build artifact on macOS
|
||||
if: runner.os == 'macOS'
|
||||
run: npm run desktop:build
|
||||
env:
|
||||
# 设置更新通道,PR构建为nightly,否则为stable
|
||||
UPDATE_CHANNEL: 'nightly'
|
||||
APP_URL: http://localhost:3015
|
||||
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
|
||||
# 默认添加一个加密 SECRET
|
||||
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
|
||||
# macOS 签名和公证配置
|
||||
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
# allow provisionally
|
||||
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 }}
|
||||
|
||||
# 非 macOS 平台构建处理
|
||||
- name: Build artifact on other platforms
|
||||
if: runner.os != 'macOS'
|
||||
run: npm run desktop:build
|
||||
env:
|
||||
# 设置更新通道,PR构建为nightly,否则为stable
|
||||
UPDATE_CHANNEL: 'nightly'
|
||||
APP_URL: http://localhost:3015
|
||||
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
|
||||
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
|
||||
|
||||
# 上传构建产物
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
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
|
||||
retention-days: 5
|
||||
|
||||
publish-pr:
|
||||
needs: [build, version]
|
||||
name: Publish PR Build
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact_path: ${{ steps.set_path.outputs.path }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 下载所有平台的构建产物
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: release
|
||||
pattern: release-*
|
||||
merge-multiple: true
|
||||
|
||||
# 列出所有构建产物
|
||||
- name: List artifacts
|
||||
run: ls -R release
|
||||
|
||||
# 生成PR发布描述
|
||||
- name: Generate PR Release Body
|
||||
id: pr_release_body
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const generateReleaseBody = require('${{ github.workspace }}/.github/scripts/pr-release-body.js');
|
||||
|
||||
const body = generateReleaseBody({
|
||||
version: "${{ needs.version.outputs.version }}",
|
||||
prNumber: "${{ github.event.pull_request.number }}",
|
||||
branch: "${{ github.head_ref }}"
|
||||
});
|
||||
|
||||
return body;
|
||||
|
||||
- name: Create Temporary Release for PR
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: PR Build v${{ needs.version.outputs.version }}
|
||||
tag_name: v${{ needs.version.outputs.version }}
|
||||
# tag_name: pr-build-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
body: ${{ steps.pr_release_body.outputs.result }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
files: |
|
||||
release/latest*
|
||||
release/*.dmg*
|
||||
release/*.zip*
|
||||
release/*.exe*
|
||||
release/*.AppImage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# 在 PR 上添加评论,包含构建信息和下载链接
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const releaseUrl = "${{ steps.create_release.outputs.url }}";
|
||||
const prCommentGenerator = require('${{ github.workspace }}/.github/scripts/pr-comment.js');
|
||||
|
||||
const result = await prCommentGenerator({
|
||||
github,
|
||||
context,
|
||||
releaseUrl,
|
||||
version: "${{ needs.version.outputs.version }}",
|
||||
tag: "v${{ needs.version.outputs.version }}"
|
||||
});
|
||||
|
||||
console.log(`评论状态: ${result.updated ? '已更新' : '已创建'}, ID: ${result.id}`);
|
||||
@@ -1,11 +1,8 @@
|
||||
name: Release Desktop
|
||||
|
||||
on:
|
||||
# uncomment when official desktop version released
|
||||
# release:
|
||||
# types: [published] # 发布 release 时触发构建
|
||||
pull_request:
|
||||
types: [synchronize, labeled, unlabeled] # PR 更新或标签变化时触发
|
||||
release:
|
||||
types: [published] # 发布 release 时触发构建
|
||||
|
||||
# 确保同一时间只运行一个相同的 workflow,取消正在进行的旧的运行
|
||||
concurrency:
|
||||
@@ -19,10 +16,6 @@ jobs:
|
||||
test:
|
||||
name: Code quality check
|
||||
# 添加 PR label 触发条件,只有添加了 Build Desktop 标签的 PR 才会触发构建
|
||||
if: |
|
||||
(github.event_name == 'pull_request' &&
|
||||
contains(github.event.pull_request.labels.*.name, 'Build Desktop')) ||
|
||||
github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest # 只在 ubuntu 上运行一次检查
|
||||
steps:
|
||||
- name: Checkout base
|
||||
@@ -38,28 +31,16 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
version: 9
|
||||
|
||||
- name: Install deps
|
||||
run: pnpm install
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
|
||||
# - name: Test
|
||||
# run: pnpm run test
|
||||
|
||||
version:
|
||||
name: Determine version
|
||||
# 与 test job 相同的触发条件
|
||||
if: |
|
||||
(github.event_name == 'pull_request' &&
|
||||
contains(github.event.pull_request.labels.*.name, 'Build Desktop')) ||
|
||||
github.event_name != 'pull_request'
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
# 输出版本信息,供后续 job 使用
|
||||
@@ -82,34 +63,12 @@ jobs:
|
||||
# 从 apps/desktop/package.json 读取基础版本号
|
||||
base_version=$(node -p "require('./apps/desktop/package.json').version")
|
||||
|
||||
if [ "${{ github.event_name }}" == "pull_request" ]; then
|
||||
# PR 构建:在基础版本号上添加 PR 信息
|
||||
branch_name="${{ github.head_ref }}"
|
||||
# 清理分支名,移除非法字符
|
||||
sanitized_branch=$(echo "${branch_name}" | sed -E 's/[^a-zA-Z0-9_.-]+/-/g')
|
||||
# 创建特殊的 PR 版本号:基础版本号-PR前缀-分支名-提交哈希
|
||||
version="${base_version}-${{ env.PR_TAG_PREFIX }}${sanitized_branch}-$(git rev-parse --short HEAD)"
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "is_pr_build=true" >> $GITHUB_OUTPUT
|
||||
echo "📦 Release Version: ${version} (based on base version ${base_version})"
|
||||
|
||||
elif [ "${{ github.event_name }}" == "release" ]; then
|
||||
# Release 事件直接使用 release tag 作为版本号,去掉可能的 v 前缀
|
||||
version="${{ github.event.release.tag_name }}"
|
||||
version="${version#v}"
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "is_pr_build=false" >> $GITHUB_OUTPUT
|
||||
echo "📦 Release Version: ${version}"
|
||||
|
||||
else
|
||||
# 其他情况(如手动触发)使用 apps/desktop/package.json 的版本号
|
||||
version="${base_version}"
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "is_pr_build=false" >> $GITHUB_OUTPUT
|
||||
echo "📦 Release Version: ${version}"
|
||||
fi
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=6144
|
||||
# Release 事件直接使用 release tag 作为版本号,去掉可能的 v 前缀
|
||||
version="${{ github.event.release.tag_name }}"
|
||||
version="${version#v}"
|
||||
echo "version=${version}" >> $GITHUB_OUTPUT
|
||||
echo "is_pr_build=false" >> $GITHUB_OUTPUT
|
||||
echo "📦 Release Version: ${version}"
|
||||
|
||||
# 输出版本信息总结,方便在 GitHub Actions 界面查看
|
||||
- name: Version Summary
|
||||
@@ -137,39 +96,46 @@ jobs:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
with:
|
||||
version: 8
|
||||
version: 9
|
||||
|
||||
# node-linker=hoisted 模式将可以确保 asar 压缩可用
|
||||
- name: Install deps
|
||||
run: pnpm install
|
||||
run: pnpm install --node-linker=hoisted
|
||||
|
||||
- name: Install deps on Desktop
|
||||
run: npm run install-isolated --prefix=./apps/desktop
|
||||
|
||||
# 设置 package.json 的版本号
|
||||
- name: Set package version
|
||||
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }}
|
||||
run: npm run workflow:set-desktop-version ${{ needs.version.outputs.version }} false
|
||||
|
||||
# macOS 构建处理
|
||||
- name: Build artifact on macOS
|
||||
if: runner.os == 'macOS'
|
||||
run: npm run desktop:build
|
||||
env:
|
||||
APP_URL: http://localhost:3010
|
||||
UPDATE_CHANNEL: 'stable'
|
||||
APP_URL: http://localhost:3015
|
||||
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
|
||||
# 默认添加一个加密 SECRET
|
||||
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
|
||||
# 公证部分将来再加回
|
||||
# CSC_LINK: ./build/developer-id-app-certs.p12
|
||||
# CSC_KEY_PASSWORD: ${{ secrets.APPLE_APP_CERTS_PASSWORD }}
|
||||
# APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
# APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
|
||||
# macOS 签名和公证配置
|
||||
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
# allow provisionally
|
||||
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 }}
|
||||
|
||||
# 非 macOS 平台构建处理
|
||||
- name: Build artifact on other platforms
|
||||
if: runner.os != 'macOS'
|
||||
run: npm run desktop:build
|
||||
env:
|
||||
APP_URL: http://localhost:3010
|
||||
# 设置更新通道,PR构建为nightly,否则为stable
|
||||
UPDATE_CHANNEL: 'stable'
|
||||
APP_URL: http://localhost:3015
|
||||
DATABASE_URL: 'postgresql://postgres@localhost:5432/postgres'
|
||||
KEY_VAULTS_SECRET: 'oLXWIiR/AKF+rWaqy9lHkrYgzpATbW3CtJp3UfkVgpE='
|
||||
|
||||
@@ -179,6 +145,7 @@ jobs:
|
||||
with:
|
||||
name: release-${{ matrix.os }}
|
||||
path: |
|
||||
apps/desktop/release/nightly*
|
||||
apps/desktop/release/latest*
|
||||
apps/desktop/release/*.dmg*
|
||||
apps/desktop/release/*.zip*
|
||||
@@ -190,8 +157,8 @@ jobs:
|
||||
run: |
|
||||
echo "🔄 Is PR Build: ${{ needs.version.outputs.is_pr_build }}"
|
||||
|
||||
# 将原本的 merge job 调整,作为所有构建产物的准备步骤
|
||||
prepare-artifacts:
|
||||
# 正式版发布 job
|
||||
publish-release:
|
||||
needs: [build, version]
|
||||
name: Prepare Artifacts
|
||||
runs-on: ubuntu-latest
|
||||
@@ -210,39 +177,13 @@ jobs:
|
||||
- name: List artifacts
|
||||
run: ls -R release
|
||||
|
||||
# 设置构建产物路径,供后续 job 使用
|
||||
- name: Set artifact path
|
||||
id: set_path
|
||||
run: echo "path=release" >> $GITHUB_OUTPUT
|
||||
|
||||
# 正式版发布 job - 只处理 release 触发的场景
|
||||
publish-release:
|
||||
# 只在 release 事件触发且不是 PR 构建时执行
|
||||
if: |
|
||||
github.event_name == 'release' &&
|
||||
needs.version.outputs.is_pr_build != 'true'
|
||||
needs: [prepare-artifacts, version]
|
||||
name: Publish Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 下载构建产物
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{ needs.prepare-artifacts.outputs.artifact_path }}
|
||||
pattern: release-*
|
||||
merge-multiple: true
|
||||
|
||||
# 将构建产物上传到现有 release
|
||||
- name: Upload to Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: ${{ github.event.release.tag_name }}
|
||||
files: |
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/nightly*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/latest*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.dmg*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.zip*
|
||||
@@ -250,82 +191,3 @@ jobs:
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.AppImage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# PR 构建的处理步骤
|
||||
publish-pr:
|
||||
if: needs.version.outputs.is_pr_build == 'true'
|
||||
needs: [prepare-artifacts, version]
|
||||
name: Publish PR Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
# 下载构建产物
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ${{ needs.prepare-artifacts.outputs.artifact_path }}
|
||||
pattern: release-*
|
||||
merge-multiple: true
|
||||
|
||||
# 生成PR发布描述
|
||||
- name: Generate PR Release Body
|
||||
id: pr_release_body
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const generateReleaseBody = require('${{ github.workspace }}/.github/scripts/pr-release-body.js');
|
||||
|
||||
const body = generateReleaseBody({
|
||||
version: "${{ needs.version.outputs.version }}",
|
||||
prNumber: "${{ github.event.pull_request.number }}",
|
||||
branch: "${{ github.head_ref }}"
|
||||
});
|
||||
|
||||
return body;
|
||||
|
||||
# 为构建产物创建一个临时发布
|
||||
- name: Create Temporary Release for PR
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
name: PR Build v${{ needs.version.outputs.version }}
|
||||
tag_name: pr-build-${{ github.event.pull_request.number }}-${{ github.sha }}
|
||||
body: ${{ steps.pr_release_body.outputs.result }}
|
||||
draft: false
|
||||
prerelease: true
|
||||
files: |
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/latest*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.dmg*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.zip*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.exe*
|
||||
${{ needs.prepare-artifacts.outputs.artifact_path }}/*.AppImage
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# 在 PR 上添加评论,包含构建信息和下载链接
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
const releaseUrl = "${{ steps.create_release.outputs.url }}";
|
||||
const prCommentGenerator = require('${{ github.workspace }}/.github/scripts/pr-comment.js');
|
||||
|
||||
const body = await prCommentGenerator({
|
||||
github,
|
||||
context,
|
||||
releaseUrl,
|
||||
version: "${{ needs.version.outputs.version }}",
|
||||
tag: "pr-build-${{ github.event.pull_request.number }}-${{ github.sha }}"
|
||||
});
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: body
|
||||
});
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
node_modules
|
||||
dist
|
||||
out
|
||||
.DS_Store
|
||||
.eslintcache
|
||||
*.log*
|
||||
standalone
|
||||
release
|
||||
@@ -0,0 +1,31 @@
|
||||
const { defineConfig } = require('@lobehub/i18n-cli');
|
||||
|
||||
module.exports = defineConfig({
|
||||
entry: 'resources/locales/zh-CN',
|
||||
entryLocale: 'zh-CN',
|
||||
output: 'resources/locales',
|
||||
outputLocales: [
|
||||
'ar',
|
||||
'bg-BG',
|
||||
'zh-TW',
|
||||
'en-US',
|
||||
'ru-RU',
|
||||
'ja-JP',
|
||||
'ko-KR',
|
||||
'fr-FR',
|
||||
'tr-TR',
|
||||
'es-ES',
|
||||
'pt-BR',
|
||||
'de-DE',
|
||||
'it-IT',
|
||||
'nl-NL',
|
||||
'pl-PL',
|
||||
'vi-VN',
|
||||
'fa-IR',
|
||||
],
|
||||
temperature: 0,
|
||||
modelName: 'gpt-4o-mini',
|
||||
experimental: {
|
||||
jsonMode: true,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
lockfile=false
|
||||
shamefully-hoist=true
|
||||
electron_mirror=https://npmmirror.com/mirrors/electron/
|
||||
electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/
|
||||
@@ -0,0 +1,47 @@
|
||||
## Menu 实现框架
|
||||
|
||||
```
|
||||
apps/desktop/src/main/
|
||||
├── core/
|
||||
│ ├── App.ts // 应用核心类
|
||||
│ ├── BrowserManager.ts // 浏览器窗口管理
|
||||
│ └── MenuManager.ts // 新增:菜单管理核心类,负责选择和协调平台实现
|
||||
├── menus/ // 新增:菜单实现目录
|
||||
│ ├── index.ts // 导出平台实现和接口
|
||||
│ ├── types.ts // 定义菜单平台接口 IMenuPlatform
|
||||
│ └── impl/ // 平台特定实现目录
|
||||
│ ├── BaseMenuPlatform.ts // 基础平台类,注入App
|
||||
│ ├── DarwinMenu.ts // macOS 充血模型实现
|
||||
│ ├── WindowsMenu.ts // Windows 充血模型实现
|
||||
│ └── LinuxMenu.ts // Linux 充血模型实现
|
||||
├── controllers/
|
||||
│ └── MenuCtr.ts // 菜单控制器,处理渲染进程调用
|
||||
```
|
||||
|
||||
## i18n
|
||||
|
||||
src/main/
|
||||
├── core/
|
||||
│ ├── I18nManager.ts //i18n 管理器
|
||||
│ └── App.ts // 应用主类,集成 i18n
|
||||
├── locales/
|
||||
│ ├── index.ts // 导出 i18n 相关功能
|
||||
│ ├── resources.ts // 资源加载逻辑
|
||||
│ └── default/ // 默认中文翻译源文件
|
||||
│ ├── index.ts // 导出所有翻译
|
||||
│ ├── menu.ts // 菜单翻译
|
||||
│ ├── dialog.ts // 对话框翻译
|
||||
│ └── common.ts // 通用翻译
|
||||
|
||||
主进程 i18n 国际化管理
|
||||
使用方式:
|
||||
|
||||
1. 直接导入 i18nManager 实例:
|
||||
import i18nManager from '@/locales';
|
||||
|
||||
2. 使用翻译函数:
|
||||
import {t} from '@/locales';
|
||||
const translated = t ('key');
|
||||
|
||||
3. 添加新翻译:
|
||||
在 locales/default/ 目录下添加翻译源文件
|
||||
@@ -0,0 +1,6 @@
|
||||
# LobeHub Desktop
|
||||
|
||||
构建路径:
|
||||
|
||||
- dist: 构建产物路径
|
||||
- release: 发布产物路径
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 161 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 221 KiB |
@@ -0,0 +1,6 @@
|
||||
provider: github
|
||||
owner: lobehub
|
||||
repo: lobe-chat
|
||||
updaterCacheDirName: electron-app-updater
|
||||
allowPrerelease: true
|
||||
channel: nightly
|
||||
@@ -0,0 +1,93 @@
|
||||
const dotenv = require('dotenv');
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const packageJSON = require('./package.json');
|
||||
|
||||
const channel = process.env.UPDATE_CHANNEL || 'stable';
|
||||
|
||||
console.log(`🚄 Build Version ${packageJSON.version}, Channel: ${channel}`);
|
||||
|
||||
const isNightly = channel === 'nightly';
|
||||
/**
|
||||
* @type {import('electron-builder').Configuration}
|
||||
* @see https://www.electron.build/configuration
|
||||
*/
|
||||
const config = {
|
||||
appId: isNightly ? 'com.lobehub.lobehub-desktop-nightly' : 'com.lobehub.lobehub-desktop',
|
||||
appImage: {
|
||||
artifactName: '${productName}-${version}.${ext}',
|
||||
},
|
||||
asar: true,
|
||||
detectUpdateChannel: true,
|
||||
directories: {
|
||||
buildResources: 'build',
|
||||
output: 'release',
|
||||
},
|
||||
dmg: {
|
||||
artifactName: '${productName}-${version}-${arch}.${ext}',
|
||||
},
|
||||
electronDownload: {
|
||||
mirror: 'https://npmmirror.com/mirrors/electron/',
|
||||
},
|
||||
files: [
|
||||
'dist',
|
||||
'resources',
|
||||
'!resources/locales',
|
||||
'!dist/next/docs',
|
||||
'!dist/next/packages',
|
||||
'!dist/next/.next/server/app/sitemap',
|
||||
'!dist/next/.next/static/media',
|
||||
],
|
||||
generateUpdatesFilesForAllChannels: true,
|
||||
linux: {
|
||||
category: 'Utility',
|
||||
maintainer: 'electronjs.org',
|
||||
target: ['AppImage', 'snap', 'deb'],
|
||||
},
|
||||
mac: {
|
||||
compression: 'maximum',
|
||||
entitlementsInherit: 'build/entitlements.mac.plist',
|
||||
extendInfo: [
|
||||
{ NSCameraUsageDescription: "Application requests access to the device's camera." },
|
||||
{ NSMicrophoneUsageDescription: "Application requests access to the device's microphone." },
|
||||
{
|
||||
NSDocumentsFolderUsageDescription:
|
||||
"Application requests access to the user's Documents folder.",
|
||||
},
|
||||
{
|
||||
NSDownloadsFolderUsageDescription:
|
||||
"Application requests access to the user's Downloads folder.",
|
||||
},
|
||||
],
|
||||
gatekeeperAssess: false,
|
||||
hardenedRuntime: true,
|
||||
notarize: true,
|
||||
target: [
|
||||
{ arch: ['x64', 'arm64'], target: 'dmg' },
|
||||
{ arch: ['x64', 'arm64'], target: 'zip' },
|
||||
],
|
||||
},
|
||||
npmRebuild: true,
|
||||
nsis: {
|
||||
artifactName: '${productName}-${version}-setup.${ext}',
|
||||
createDesktopShortcut: 'always',
|
||||
// allowToChangeInstallationDirectory: true,
|
||||
// oneClick: false,
|
||||
shortcutName: '${productName}',
|
||||
uninstallDisplayName: '${productName}',
|
||||
},
|
||||
productName: isNightly ? 'LobeHub Nightly' : 'LobeHub',
|
||||
publish: [
|
||||
{
|
||||
owner: 'lobehub',
|
||||
provider: 'github',
|
||||
repo: 'lobe-chat',
|
||||
},
|
||||
],
|
||||
win: {
|
||||
executableName: 'LobeHub',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
@@ -0,0 +1,39 @@
|
||||
import dotenv from 'dotenv';
|
||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const updateChannel = process.env.UPDATE_CHANNEL || 'stable';
|
||||
console.log(`[electron-vite.config.ts] Detected UPDATE_CHANNEL: ${updateChannel}`); // 添加日志确认
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
build: {
|
||||
outDir: 'dist/main',
|
||||
},
|
||||
// 这里是关键:在构建时进行文本替换
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
'process.env.UPDATE_CHANNEL': JSON.stringify(process.env.UPDATE_CHANNEL),
|
||||
},
|
||||
plugins: [externalizeDepsPlugin({})],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': resolve(__dirname, 'src/main'),
|
||||
'~common': resolve(__dirname, 'src/common'),
|
||||
},
|
||||
},
|
||||
},
|
||||
preload: {
|
||||
build: {
|
||||
outDir: 'dist/preload',
|
||||
},
|
||||
plugins: [externalizeDepsPlugin({})],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~common': resolve(__dirname, 'src/common'),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "lobehub-desktop-dev",
|
||||
"version": "0.0.6",
|
||||
"description": "A minimal Electron application with TypeScript",
|
||||
"homepage": "https://lobehub.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/lobehub/lobe-chat.git"
|
||||
},
|
||||
"author": "LobeHub",
|
||||
"main": "./dist/main/index.js",
|
||||
"scripts": {
|
||||
"build": "npm run typecheck && electron-vite build",
|
||||
"build-local": "npm run build && electron-builder --dir --config electron-builder.js --c.mac.notarize=false -c.mac.identity=null --c.asar=false",
|
||||
"build:linux": "npm run build && electron-builder --linux --config electron-builder.js",
|
||||
"build:mac": "npm run build && electron-builder --mac --config electron-builder.js",
|
||||
"build:win": "npm run build && electron-builder --win --config electron-builder.js",
|
||||
"electron:dev": "electron-vite dev",
|
||||
"electron:run-unpack": "electron .",
|
||||
"format": "prettier --write ",
|
||||
"i18n": "bun run scripts/i18nWorkflow/index.ts && lobe-i18n",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"install-isolated": "pnpm install",
|
||||
"lint": "eslint --cache ",
|
||||
"pg-server": "bun run scripts/pglite-server.ts",
|
||||
"start": "electron-vite preview",
|
||||
"typecheck": "tsc --noEmit -p tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electron-toolkit/utils": "^4.0.0",
|
||||
"electron-updater": "^6.6.2",
|
||||
"get-port-please": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron-toolkit/eslint-config-prettier": "^3.0.0",
|
||||
"@electron-toolkit/eslint-config-ts": "^3.0.0",
|
||||
"@electron-toolkit/preload": "^3.0.1",
|
||||
"@electron-toolkit/tsconfig": "^1.0.1",
|
||||
"@lobechat/electron-client-ipc": "workspace:*",
|
||||
"@lobechat/electron-server-ipc": "workspace:*",
|
||||
"@lobehub/i18n-cli": "^1.20.3",
|
||||
"@types/lodash": "^4.17.0",
|
||||
"@types/resolve": "^1.20.6",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/set-cookie-parser": "^2.4.10",
|
||||
"consola": "^3.1.0",
|
||||
"cookie": "^1.0.2",
|
||||
"electron": "35.1.4",
|
||||
"electron-builder": "^26.0.12",
|
||||
"electron-is": "^3.0.0",
|
||||
"electron-log": "^5.3.3",
|
||||
"electron-store": "^8.2.0",
|
||||
"electron-vite": "^3.0.0",
|
||||
"execa": "^9.5.2",
|
||||
"just-diff": "^6.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"pglite-server": "^0.1.4",
|
||||
"resolve": "^1.22.8",
|
||||
"semver": "^7.5.4",
|
||||
"set-cookie-parser": "^2.7.1",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.2.5"
|
||||
},
|
||||
"pnpm": {
|
||||
"onlyBuiltDependencies": [
|
||||
"electron"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
packages:
|
||||
- '../../packages/electron-server-ipc'
|
||||
- '../../packages/electron-client-ipc'
|
||||
- '.'
|
||||
@@ -0,0 +1,136 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>LobeHub - 连接错误</title>
|
||||
<style>
|
||||
body {
|
||||
-webkit-app-region: drag;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
color: #1f1f1f;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 添加暗色模式支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
color: #f5f5f5;
|
||||
background-color: #121212;
|
||||
}
|
||||
.error-message {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
.retry-button {
|
||||
background-color: #2a2a2a;
|
||||
color: #f5f5f5;
|
||||
border: 1px solid #3a3a3a;
|
||||
}
|
||||
.retry-button:hover {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.lobe-brand {
|
||||
width: 120px;
|
||||
height: auto;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.lobe-brand path {
|
||||
fill: currentcolor;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.error-title {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-bottom: 2rem;
|
||||
line-height: 1.5;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.retry-button {
|
||||
-webkit-app-region: no-drag;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: #f5f5f5;
|
||||
color: #1f1f1f;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.retry-button:hover {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="error-icon">⚠️</div>
|
||||
<h1 class="error-title">Connection Error</h1>
|
||||
<p class="error-message">
|
||||
Unable to connect to the application, please check your network connection or confirm if the
|
||||
development server is running.
|
||||
</p>
|
||||
|
||||
<button id="retry-button" class="retry-button">Retry</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 当按钮被点击时,通知主进程重试连接
|
||||
const retryButton = document.getElementById('retry-button');
|
||||
const errorMessage = document.querySelector('.error-message');
|
||||
|
||||
if (retryButton) {
|
||||
retryButton.addEventListener('click', () => {
|
||||
// 更新UI状态
|
||||
retryButton.disabled = true;
|
||||
retryButton.textContent = 'Retrying...';
|
||||
errorMessage.textContent = 'Attempting to reconnect to the next server, please wait...';
|
||||
|
||||
// 调用主进程的重试逻辑
|
||||
if (window.electron && window.electron.ipcRenderer) {
|
||||
window.electron.ipcRenderer.invoke('retry-connection')
|
||||
.then((result) => {
|
||||
if (result && result.success) {
|
||||
// 连接成功,无需额外操作,页面会自动导航
|
||||
} else {
|
||||
// 连接失败,重置按钮状态
|
||||
setTimeout(() => {
|
||||
retryButton.disabled = false;
|
||||
retryButton.textContent = 'Retry';
|
||||
errorMessage.textContent = 'Unable to connect to the application, please check your network connection or confirm if the development server is running.';
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "تحذير"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "تخطي هذا الإصدار"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "التحقق من التحديثات..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "لوحة المطور",
|
||||
"devTools": "أدوات المطور",
|
||||
"forceReload": "إعادة تحميل قسري",
|
||||
"openStore": "فتح ملف التخزين",
|
||||
"refreshMenu": "تحديث القائمة",
|
||||
"reload": "إعادة تحميل",
|
||||
"title": "تطوير"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "نسخ",
|
||||
"cut": "قص",
|
||||
"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": "تكبير"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "Предупреждение"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "Пропусни тази версия"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "Проверка за актуализации..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "Панел на разработчика",
|
||||
"devTools": "Инструменти за разработчици",
|
||||
"forceReload": "Принудително презареждане",
|
||||
"openStore": "Отворете файла за съхранение",
|
||||
"refreshMenu": "Освежаване на менюто",
|
||||
"reload": "Презареждане",
|
||||
"title": "Разработка"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "Копиране",
|
||||
"cut": "Изрязване",
|
||||
"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": "Мащаб"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"paste": "Einfügen",
|
||||
"redo": "Wiederherstellen",
|
||||
"selectAll": "Alles auswählen",
|
||||
"speech": "Sprache",
|
||||
"startSpeaking": "Beginne zu sprechen",
|
||||
"stopSpeaking": "Stoppe das Sprechen",
|
||||
"title": "Bearbeiten",
|
||||
"undo": "Rückgängig"
|
||||
},
|
||||
"file": {
|
||||
"preferences": "Einstellungen",
|
||||
"quit": "Beenden",
|
||||
"title": "Datei"
|
||||
},
|
||||
"help": {
|
||||
"about": "Über",
|
||||
"githubRepo": "GitHub-Repository",
|
||||
"reportIssue": "Problem melden",
|
||||
"title": "Hilfe",
|
||||
"visitWebsite": "Besuche die Website"
|
||||
},
|
||||
"macOS": {
|
||||
"about": "Über {{appName}}",
|
||||
"devTools": "LobeHub Entwicklerwerkzeuge",
|
||||
"hide": "{{appName}} ausblenden",
|
||||
"hideOthers": "Andere ausblenden",
|
||||
"preferences": "Einstellungen...",
|
||||
"services": "Dienste",
|
||||
"unhide": "Alle anzeigen"
|
||||
},
|
||||
"tray": {
|
||||
"open": "{{appName}} öffnen",
|
||||
"quit": "Beenden",
|
||||
"show": "{{appName}} anzeigen"
|
||||
},
|
||||
"view": {
|
||||
"forceReload": "Erzwinge Neuladen",
|
||||
"reload": "Neuladen",
|
||||
"resetZoom": "Zoom zurücksetzen",
|
||||
"title": "Ansicht",
|
||||
"toggleFullscreen": "Vollbild umschalten",
|
||||
"zoomIn": "Vergrößern",
|
||||
"zoomOut": "Verkleinern"
|
||||
},
|
||||
"window": {
|
||||
"bringAllToFront": "Alle Fenster in den Vordergrund bringen",
|
||||
"close": "Schließen",
|
||||
"front": "Alle Fenster in den Vordergrund bringen",
|
||||
"minimize": "Minimieren",
|
||||
"title": "Fenster",
|
||||
"toggleFullscreen": "Vollbild umschalten",
|
||||
"zoom": "Zoom"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"actions": {
|
||||
"add": "Add",
|
||||
"back": "Back",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"confirm": "Confirm",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit",
|
||||
"more": "More",
|
||||
"next": "Next",
|
||||
"ok": "OK",
|
||||
"previous": "Previous",
|
||||
"refresh": "Refresh",
|
||||
"remove": "Remove",
|
||||
"retry": "Retry",
|
||||
"save": "Save",
|
||||
"search": "Search",
|
||||
"submit": "Submit"
|
||||
},
|
||||
"app": {
|
||||
"description": "Your AI Assistant Collaboration Platform",
|
||||
"name": "LobeHub"
|
||||
},
|
||||
"status": {
|
||||
"error": "Error",
|
||||
"info": "Information",
|
||||
"loading": "Loading",
|
||||
"success": "Success",
|
||||
"warning": "Warning"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"about": {
|
||||
"button": "OK",
|
||||
"detail": "A chat application based on a large language model",
|
||||
"message": "{{appName}} {{appVersion}}",
|
||||
"title": "About"
|
||||
},
|
||||
"confirm": {
|
||||
"cancel": "Cancel",
|
||||
"no": "No",
|
||||
"title": "Confirm",
|
||||
"yes": "Yes"
|
||||
},
|
||||
"error": {
|
||||
"button": "OK",
|
||||
"detail": "An error occurred during the operation, please try again later",
|
||||
"message": "An error occurred",
|
||||
"title": "Error"
|
||||
},
|
||||
"update": {
|
||||
"downloadAndInstall": "Download and Install",
|
||||
"downloadComplete": "Download Complete",
|
||||
"downloadCompleteMessage": "The update package has been downloaded, would you like to install it now?",
|
||||
"installLater": "Install Later",
|
||||
"installNow": "Install Now",
|
||||
"later": "Remind Me Later",
|
||||
"newVersion": "New Version Found",
|
||||
"newVersionAvailable": "New version available: {{version}}",
|
||||
"skipThisVersion": "Skip This Version"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "هشدار"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "این نسخه را نادیده بگیرید"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "بررسی بهروزرسانی..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "پنل توسعهدهنده",
|
||||
"devTools": "ابزارهای توسعهدهنده",
|
||||
"forceReload": "بارگذاری اجباری",
|
||||
"openStore": "باز کردن فایلهای ذخیره شده",
|
||||
"refreshMenu": "بهروزرسانی منو",
|
||||
"reload": "بارگذاری مجدد",
|
||||
"title": "توسعه"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "کپی",
|
||||
"cut": "برش",
|
||||
"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": "زوم"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "警告"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "このバージョンをスキップ"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "更新を確認しています..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "開発者パネル",
|
||||
"devTools": "開発者ツール",
|
||||
"forceReload": "強制再読み込み",
|
||||
"openStore": "ストレージファイルを開く",
|
||||
"refreshMenu": "メニューを更新",
|
||||
"reload": "再読み込み",
|
||||
"title": "開発"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "コピー",
|
||||
"cut": "切り取り",
|
||||
"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": "ズーム"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "경고"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "이 버전 건너뛰기"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "업데이트 확인 중..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "개발자 패널",
|
||||
"devTools": "개발자 도구",
|
||||
"forceReload": "강제 새로 고침",
|
||||
"openStore": "저장 파일 열기",
|
||||
"refreshMenu": "메뉴 새로 고침",
|
||||
"reload": "새로 고침",
|
||||
"title": "개발"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "복사",
|
||||
"cut": "잘라내기",
|
||||
"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": "줌"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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ę"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "Предупреждение"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "Пропустить эту версию"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "Проверка обновлений..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "Панель разработчика",
|
||||
"devTools": "Инструменты разработчика",
|
||||
"forceReload": "Принудительная перезагрузка",
|
||||
"openStore": "Открыть файл хранилища",
|
||||
"refreshMenu": "Обновить меню",
|
||||
"reload": "Перезагрузить",
|
||||
"title": "Разработка"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "Копировать",
|
||||
"cut": "Вырезать",
|
||||
"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": "Масштаб"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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ı"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "Güncellemeleri kontrol et..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "Geliştirici Paneli",
|
||||
"devTools": "Geliştirici Araçları",
|
||||
"forceReload": "Zorla Yenile",
|
||||
"openStore": "Depolama dosyasını aç",
|
||||
"refreshMenu": "Menüyü yenile",
|
||||
"reload": "Yenile",
|
||||
"title": "Geliştir"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "Kopyala",
|
||||
"cut": "Kes",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "警告"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "跳过此版本"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "检查更新..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "开发者面板",
|
||||
"devTools": "开发者工具",
|
||||
"forceReload": "强制重新加载",
|
||||
"openStore": "打开存储文件",
|
||||
"refreshMenu": "刷新菜单",
|
||||
"reload": "重新加载",
|
||||
"title": "开发"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "复制",
|
||||
"cut": "剪切",
|
||||
"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": "缩放"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"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": "警告"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"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": "跳過此版本"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"common": {
|
||||
"checkUpdates": "檢查更新..."
|
||||
},
|
||||
"dev": {
|
||||
"devPanel": "開發者面板",
|
||||
"devTools": "開發者工具",
|
||||
"forceReload": "強制重新載入",
|
||||
"openStore": "打開儲存檔案",
|
||||
"refreshMenu": "刷新選單",
|
||||
"reload": "重新載入",
|
||||
"title": "開發"
|
||||
},
|
||||
"edit": {
|
||||
"copy": "複製",
|
||||
"cut": "剪下",
|
||||
"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": "縮放"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>LobeHub</title>
|
||||
<style>
|
||||
body {
|
||||
-webkit-app-region: drag;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family:
|
||||
-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||||
color: #1f1f1f;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 添加暗色模式支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.lobe-brand-loading {
|
||||
width: 120px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.lobe-brand-loading path {
|
||||
fill: currentcolor;
|
||||
fill-opacity: 0%;
|
||||
stroke: currentcolor;
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
stroke-width: 0.25em;
|
||||
|
||||
animation:
|
||||
draw 2s cubic-bezier(0.4, 0, 0.2, 1) infinite,
|
||||
fill 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
||||
}
|
||||
|
||||
@keyframes draw {
|
||||
0% {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
|
||||
100% {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fill {
|
||||
30% {
|
||||
fill-opacity: 5%;
|
||||
}
|
||||
|
||||
100% {
|
||||
fill-opacity: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<svg
|
||||
class="lobe-brand-loading"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
viewBox="0 0 940 320"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>LobeHub</title>
|
||||
<path
|
||||
d="M15 240.035V87.172h39.24V205.75h66.192v34.285H15zM183.731 242c-11.759 0-22.196-2.621-31.313-7.862-9.116-5.241-16.317-12.447-21.601-21.619-5.153-9.317-7.729-19.945-7.729-31.883 0-11.937 2.576-22.492 7.729-31.664 5.164-8.963 12.159-15.98 20.982-21.05l.619-.351c9.117-5.241 19.554-7.861 31.313-7.861s22.196 2.62 31.313 7.861c9.248 5.096 16.449 12.229 21.601 21.401 5.153 9.172 7.729 19.727 7.729 31.664 0 11.938-2.576 22.566-7.729 31.883-5.152 9.172-12.353 16.378-21.601 21.619-9.117 5.241-19.554 7.862-31.313 7.862zm0-32.975c4.36 0 8.191-1.092 11.494-3.275 3.436-2.184 6.144-5.387 8.126-9.609 1.982-4.367 2.973-9.536 2.973-15.505 0-5.968-.991-10.991-2.973-15.067-1.906-4.06-4.483-7.177-7.733-9.352l-.393-.257c-3.303-2.184-7.134-3.276-11.494-3.276-4.228 0-8.059 1.092-11.495 3.276-3.303 2.184-6.011 5.387-8.125 9.609-1.982 4.076-2.973 9.099-2.973 15.067 0 5.969.991 11.138 2.973 15.505 2.114 4.222 4.822 7.425 8.125 9.609 3.436 2.183 7.267 3.275 11.495 3.275zM295.508 78l-.001 54.042a34.071 34.071 0 016.541-5.781c6.474-4.367 14.269-6.551 23.385-6.551 9.777 0 18.629 2.475 26.557 7.424 7.872 4.835 14.105 11.684 18.7 20.546l.325.637c4.756 9.026 7.135 19.799 7.135 32.319 0 12.666-2.379 23.585-7.135 32.757-4.624 9.026-10.966 16.087-19.025 21.182-7.928 4.95-16.78 7.425-26.557 7.425-9.644 0-17.704-2.184-24.178-6.551-2.825-1.946-5.336-4.355-7.532-7.226l.001 11.812h-35.87V78h37.654zm21.998 74.684c-4.228 0-8.059 1.092-11.494 3.276-3.303 2.184-6.012 5.387-8.126 9.609-1.982 4.076-2.972 9.099-2.972 15.067 0 5.969.99 11.138 2.972 15.505 2.114 4.222 4.823 7.425 8.126 9.609 3.435 2.183 7.266 3.275 11.494 3.275s7.994-1.092 11.297-3.275c3.435-2.184 6.143-5.387 8.125-9.609 2.114-4.367 3.171-9.536 3.171-15.505 0-5.968-1.057-10.991-3.171-15.067-1.906-4.06-4.483-7.177-7.732-9.352l-.393-.257c-3.303-2.184-7.069-3.276-11.297-3.276zm105.335 38.653l.084.337a27.857 27.857 0 002.057 5.559c2.246 4.222 5.417 7.498 9.513 9.827 4.096 2.184 8.984 3.276 14.665 3.276 5.285 0 9.777-.801 13.477-2.403 3.579-1.632 7.1-4.025 10.564-7.182l.732-.679 19.818 22.711c-5.153 6.26-11.494 11.064-19.025 14.413-7.531 3.203-16.449 4.804-26.755 4.804-12.683 0-23.782-2.621-33.294-7.862-9.381-5.386-16.713-12.665-21.998-21.837-5.153-9.317-7.729-19.872-7.729-31.665 0-11.792 2.51-22.274 7.53-31.446 5.036-9.105 11.902-16.195 20.596-21.268l.61-.351c8.984-5.241 19.091-7.861 30.322-7.861 10.311 0 19.743 2.286 28.294 6.859l.64.347c8.72 4.659 15.656 11.574 20.809 20.746 5.153 9.172 7.729 20.309 7.729 33.411 0 1.294-.052 2.761-.156 4.4l-.042.623-.17 2.353c-.075 1.01-.151 1.973-.227 2.888h-78.044zm21.365-42.147c-4.492 0-8.456 1.092-11.891 3.276-3.303 2.184-5.879 5.314-7.729 9.39a26.04 26.04 0 00-1.117 2.79 30.164 30.164 0 00-1.121 4.499l-.058.354h43.96l-.015-.106c-.401-2.638-1.122-5.055-2.163-7.252l-.246-.503c-1.776-3.774-4.282-6.742-7.519-8.906l-.409-.266c-3.303-2.184-7.2-3.276-11.692-3.276zm111.695-62.018l-.001 57.432h53.51V87.172h39.24v152.863h-39.24v-59.617H555.9l.001 59.617h-39.24V87.172h39.24zM715.766 242c-8.72 0-16.581-1.893-23.583-5.678-6.87-3.785-12.287-9.681-16.251-17.688-3.832-8.153-5.747-18.417-5.747-30.791v-66.168h37.654v59.398c0 9.172 1.519 15.723 4.558 19.654 3.171 3.931 7.597 5.896 13.278 5.896 3.7 0 7.069-.946 10.108-2.839 3.038-1.892 5.483-4.877 7.332-8.953 1.85-4.222 2.775-9.609 2.775-16.16v-56.996h37.654v118.36h-35.871l.004-12.38c-2.642 3.197-5.682 5.868-9.12 8.012-7.002 4.222-14.599 6.333-22.791 6.333zM841.489 78l-.001 54.041a34.1 34.1 0 016.541-5.78c6.474-4.367 14.269-6.551 23.385-6.551 9.777 0 18.629 2.475 26.556 7.424 7.873 4.835 14.106 11.684 18.701 20.546l.325.637c4.756 9.026 7.134 19.799 7.134 32.319 0 12.666-2.378 23.585-7.134 32.757-4.624 9.026-10.966 16.087-19.026 21.182-7.927 4.95-16.779 7.425-26.556 7.425-9.645 0-17.704-2.184-24.178-6.551-2.825-1.946-5.336-4.354-7.531-7.224v11.81h-35.87V78h37.654zm21.998 74.684c-4.228 0-8.059 1.092-11.495 3.276-3.303 2.184-6.011 5.387-8.125 9.609-1.982 4.076-2.973 9.099-2.973 15.067 0 5.969.991 11.138 2.973 15.505 2.114 4.222 4.822 7.425 8.125 9.609 3.436 2.183 7.267 3.275 11.495 3.275 4.228 0 7.993-1.092 11.296-3.275 3.435-2.184 6.144-5.387 8.126-9.609 2.114-4.367 3.171-9.536 3.171-15.505 0-5.968-1.057-10.991-3.171-15.067-1.906-4.06-4.484-7.177-7.733-9.352l-.393-.257c-3.303-2.184-7.068-3.276-11.296-3.276z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
import { readdirSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../../.i18nrc';
|
||||
|
||||
export const root = resolve(__dirname, '../..');
|
||||
export const localesDir = resolve(root, i18nConfig.output);
|
||||
export const localeDir = (locale: string) => resolve(localesDir, locale);
|
||||
export const localeDirJsonList = (locale: string) =>
|
||||
readdirSync(localeDir(locale)).filter((name) => name.includes('.json'));
|
||||
export const srcLocalesDir = resolve(root, './src/main/locales');
|
||||
export const entryLocaleJsonFilepath = (file: string) =>
|
||||
resolve(localesDir, i18nConfig.entryLocale, file);
|
||||
export const outputLocaleJsonFilepath = (locale: string, file: string) =>
|
||||
resolve(localesDir, locale, file);
|
||||
export const srcDefaultLocales = resolve(root, srcLocalesDir, 'default');
|
||||
|
||||
export { default as i18nConfig } from '../../.i18nrc';
|
||||
@@ -0,0 +1,35 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
|
||||
import { entryLocaleJsonFilepath, i18nConfig, localeDir, srcDefaultLocales } from './const';
|
||||
import { tagWhite, writeJSON } from './utils';
|
||||
|
||||
export const genDefaultLocale = () => {
|
||||
consola.info(`默认语言为 ${i18nConfig.entryLocale}...`);
|
||||
|
||||
// 确保入口语言目录存在
|
||||
const entryLocaleDir = localeDir(i18nConfig.entryLocale);
|
||||
if (!existsSync(entryLocaleDir)) {
|
||||
mkdirSync(entryLocaleDir, { recursive: true });
|
||||
consola.info(`创建目录:${entryLocaleDir}`);
|
||||
}
|
||||
|
||||
const resources = require(srcDefaultLocales);
|
||||
const data = Object.entries(resources.default);
|
||||
consola.start(`生成默认语言 JSON 文件,发现 ${data.length} 个命名空间...`);
|
||||
|
||||
for (const [ns, value] of data) {
|
||||
const filepath = entryLocaleJsonFilepath(`${ns}.json`);
|
||||
|
||||
// 确保目录存在
|
||||
const dir = dirname(filepath);
|
||||
if (!existsSync(dir)) {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
writeJSON(filepath, value);
|
||||
consola.success(tagWhite(ns), colors.gray(filepath));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { diff } from 'just-diff';
|
||||
import { unset } from 'lodash';
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
import {
|
||||
entryLocaleJsonFilepath,
|
||||
i18nConfig,
|
||||
outputLocaleJsonFilepath,
|
||||
srcDefaultLocales,
|
||||
} from './const';
|
||||
import { readJSON, tagWhite, writeJSON } from './utils';
|
||||
|
||||
export const genDiff = () => {
|
||||
consola.start(`对比开发与生产环境中的本地化文件...`);
|
||||
|
||||
const resources = require(srcDefaultLocales);
|
||||
const data = Object.entries(resources.default);
|
||||
|
||||
for (const [ns, devJSON] of data) {
|
||||
const filepath = entryLocaleJsonFilepath(`${ns}.json`);
|
||||
if (!existsSync(filepath)) {
|
||||
consola.info(`文件不存在,跳过:${filepath}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const prodJSON = readJSON(filepath);
|
||||
|
||||
const diffResult = diff(prodJSON, devJSON as any);
|
||||
const remove = diffResult.filter((item) => item.op === 'remove');
|
||||
if (remove.length === 0) {
|
||||
consola.success(tagWhite(ns), colors.gray(filepath));
|
||||
continue;
|
||||
}
|
||||
|
||||
const clearLocals = [];
|
||||
|
||||
for (const locale of [i18nConfig.entryLocale, ...i18nConfig.outputLocales]) {
|
||||
const localeFilepath = outputLocaleJsonFilepath(locale, `${ns}.json`);
|
||||
if (!existsSync(localeFilepath)) continue;
|
||||
const localeJSON = readJSON(localeFilepath);
|
||||
|
||||
for (const item of remove) {
|
||||
unset(localeJSON, item.path);
|
||||
}
|
||||
|
||||
writeJSON(localeFilepath, localeJSON);
|
||||
clearLocals.push(locale);
|
||||
}
|
||||
|
||||
if (clearLocals.length > 0) {
|
||||
consola.info('清理了以下语言的过期项目:', clearLocals.join(', '));
|
||||
}
|
||||
consola.success(tagWhite(ns), colors.gray(filepath));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,35 @@
|
||||
import { existsSync, mkdirSync } from 'node:fs';
|
||||
|
||||
import { i18nConfig, localeDir } from './const';
|
||||
import { genDefaultLocale } from './genDefaultLocale';
|
||||
import { genDiff } from './genDiff';
|
||||
import { split } from './utils';
|
||||
|
||||
// 确保所有语言目录存在
|
||||
const ensureLocalesDirs = () => {
|
||||
[i18nConfig.entryLocale, ...i18nConfig.outputLocales].forEach((locale) => {
|
||||
const dir = localeDir(locale);
|
||||
if (!existsSync(dir)) {
|
||||
mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 运行工作流
|
||||
const run = async () => {
|
||||
// 确保目录存在
|
||||
ensureLocalesDirs();
|
||||
|
||||
// 差异分析
|
||||
split('差异分析');
|
||||
genDiff();
|
||||
|
||||
// 生成默认语言文件
|
||||
split('生成默认语言文件');
|
||||
genDefaultLocale();
|
||||
|
||||
// 生成国际化文件
|
||||
split('生成国际化文件');
|
||||
};
|
||||
|
||||
run();
|
||||
@@ -0,0 +1,54 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../../.i18nrc';
|
||||
|
||||
export const readJSON = (filePath: string) => {
|
||||
const data = readFileSync(filePath, 'utf8');
|
||||
return JSON.parse(data);
|
||||
};
|
||||
|
||||
export const writeJSON = (filePath: string, data: any) => {
|
||||
const jsonStr = JSON.stringify(data, null, 2);
|
||||
writeFileSync(filePath, jsonStr, 'utf8');
|
||||
};
|
||||
|
||||
export const genResourcesContent = (locales: string[]) => {
|
||||
let index = '';
|
||||
let indexObj = '';
|
||||
|
||||
for (const locale of locales) {
|
||||
index += `import ${locale} from "./${locale}";\n`;
|
||||
indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`;
|
||||
}
|
||||
|
||||
return `${index}
|
||||
const resources = {
|
||||
${indexObj}} as const;
|
||||
export default resources;
|
||||
export const defaultResources = ${i18nConfig.entryLocale};
|
||||
export type Resources = typeof resources;
|
||||
export type DefaultResources = typeof defaultResources;
|
||||
export type Namespaces = keyof DefaultResources;
|
||||
export type Locales = keyof Resources;
|
||||
`;
|
||||
};
|
||||
|
||||
export const genNamespaceList = (files: string[], locale: string) => {
|
||||
return files.map((file) => ({
|
||||
name: file.replace('.json', ''),
|
||||
path: resolve(i18nConfig.output, locale, file),
|
||||
}));
|
||||
};
|
||||
|
||||
export const tagBlue = (text: string) => colors.bgBlueBright(colors.black(` ${text} `));
|
||||
export const tagYellow = (text: string) => colors.bgYellowBright(colors.black(` ${text} `));
|
||||
export const tagGreen = (text: string) => colors.bgGreenBright(colors.black(` ${text} `));
|
||||
export const tagWhite = (text: string) => colors.bgWhiteBright(colors.black(` ${text} `));
|
||||
|
||||
export const split = (name: string) => {
|
||||
consola.log('');
|
||||
consola.log(colors.gray(`========================== ${name} ==============================`));
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import { PGlite } from "@electric-sql/pglite";
|
||||
import { createServer } from "pglite-server";
|
||||
|
||||
// 创建或连接到您现有的 PGlite 数据库
|
||||
const db = new PGlite("/Users/arvinxx/Library/Application Support/lobehub-desktop/lobehub-local-db");
|
||||
await db.waitReady;
|
||||
|
||||
// 创建服务器并监听端口
|
||||
const PORT = 6543;
|
||||
const pgServer = createServer(db);
|
||||
|
||||
pgServer.listen(PORT, () => {
|
||||
console.log(`PGlite 服务器已启动,监听端口 ${PORT}`);
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* 路由拦截类型,描述拦截路由和目标窗口的映射关系
|
||||
*/
|
||||
export interface RouteInterceptConfig {
|
||||
/**
|
||||
* 是否始终在新窗口中打开,即使目标窗口已经存在
|
||||
*/
|
||||
alwaysOpenNew?: boolean;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
description: string;
|
||||
|
||||
/**
|
||||
* 是否启用拦截
|
||||
*/
|
||||
enabled: boolean;
|
||||
|
||||
/**
|
||||
* 路由模式前缀,例如 '/settings'
|
||||
*/
|
||||
pathPrefix: string;
|
||||
|
||||
/**
|
||||
* 目标窗口标识符
|
||||
*/
|
||||
targetWindow: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截路由配置列表
|
||||
* 定义了所有需要特殊处理的路由
|
||||
*/
|
||||
export const interceptRoutes: RouteInterceptConfig[] = [
|
||||
{
|
||||
description: '设置页面',
|
||||
enabled: true,
|
||||
pathPrefix: '/settings',
|
||||
targetWindow: 'settings',
|
||||
},
|
||||
{
|
||||
description: '开发者工具',
|
||||
enabled: true,
|
||||
pathPrefix: '/desktop/devtools',
|
||||
targetWindow: 'devtools',
|
||||
},
|
||||
// 未来可能的其他路由
|
||||
// {
|
||||
// description: '帮助中心',
|
||||
// enabled: true,
|
||||
// pathPrefix: '/help',
|
||||
// targetWindow: 'help',
|
||||
// },
|
||||
];
|
||||
|
||||
/**
|
||||
* 通过路径查找匹配的路由拦截配置
|
||||
* @param path 需要检查的路径
|
||||
* @returns 匹配的拦截配置,如果没有匹配则返回 undefined
|
||||
*/
|
||||
export const findMatchingRoute = (path: string): RouteInterceptConfig | undefined => {
|
||||
return interceptRoutes.find((route) => route.enabled && path.startsWith(route.pathPrefix));
|
||||
};
|
||||
|
||||
/**
|
||||
* 从完整路径中提取子路径
|
||||
* @param fullPath 完整路径,如 '/settings/agent'
|
||||
* @param pathPrefix 路径前缀,如 '/settings'
|
||||
* @returns 子路径,如 'agent'
|
||||
*/
|
||||
export const extractSubPath = (fullPath: string, pathPrefix: string): string | undefined => {
|
||||
if (fullPath.length <= pathPrefix.length) return undefined;
|
||||
|
||||
// 去除前导斜杠
|
||||
const subPath = fullPath.slice(Math.max(0, pathPrefix.length + 1));
|
||||
return subPath || undefined;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { BrowserWindowOpts } from './core/Browser';
|
||||
|
||||
export const BrowsersIdentifiers = {
|
||||
chat: 'chat',
|
||||
devtools: 'devtools',
|
||||
settings: 'settings',
|
||||
};
|
||||
|
||||
export const appBrowsers = {
|
||||
chat: {
|
||||
autoHideMenuBar: true,
|
||||
height: 800,
|
||||
identifier: 'chat',
|
||||
keepAlive: true,
|
||||
minWidth: 400,
|
||||
path: '/chat',
|
||||
showOnInit: true,
|
||||
titleBarStyle: 'hidden',
|
||||
vibrancy: 'under-window',
|
||||
width: 1200,
|
||||
},
|
||||
devtools: {
|
||||
autoHideMenuBar: true,
|
||||
fullscreenable: false,
|
||||
height: 600,
|
||||
identifier: 'devtools',
|
||||
maximizable: false,
|
||||
minWidth: 400,
|
||||
path: '/desktop/devtools',
|
||||
titleBarStyle: 'hiddenInset',
|
||||
vibrancy: 'under-window',
|
||||
width: 1000,
|
||||
},
|
||||
settings: {
|
||||
autoHideMenuBar: true,
|
||||
height: 800,
|
||||
identifier: 'settings',
|
||||
keepAlive: true,
|
||||
minWidth: 600,
|
||||
path: '/settings',
|
||||
titleBarStyle: 'hidden',
|
||||
vibrancy: 'under-window',
|
||||
width: 1000,
|
||||
},
|
||||
} satisfies Record<string, BrowserWindowOpts>;
|
||||
|
||||
export type AppBrowsersIdentifiers = keyof typeof appBrowsers;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { app } from 'electron';
|
||||
import { join } from 'node:path';
|
||||
|
||||
export const mainDir = join(__dirname);
|
||||
|
||||
export const preloadDir = join(mainDir, '../preload');
|
||||
|
||||
export const resourcesDir = join(mainDir, '../../resources');
|
||||
|
||||
export const buildDir = join(mainDir, '../../build');
|
||||
|
||||
const appPath = app.getAppPath();
|
||||
|
||||
export const nextStandaloneDir = join(appPath, 'dist', 'next');
|
||||
|
||||
export const userDataDir = app.getPath('userData');
|
||||
@@ -0,0 +1 @@
|
||||
export const isDev = process.env.NODE_ENV === 'development';
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 应用设置存储相关常量
|
||||
*/
|
||||
import { DEFAULT_SHORTCUTS_CONFIG } from '@/shortcuts';
|
||||
import { ElectronMainStore } from '@/types/store';
|
||||
|
||||
/**
|
||||
* 存储名称
|
||||
*/
|
||||
export const STORE_NAME = 'lobehub-settings';
|
||||
|
||||
/**
|
||||
* 存储默认值
|
||||
*/
|
||||
export const STORE_DEFAULTS: ElectronMainStore = {
|
||||
locale: 'auto',
|
||||
shortcuts: DEFAULT_SHORTCUTS_CONFIG,
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
import { InterceptRouteParams } from '@lobechat/electron-client-ipc';
|
||||
import { extractSubPath, findMatchingRoute } from '~common/routes';
|
||||
|
||||
import { AppBrowsersIdentifiers, BrowsersIdentifiers } from '@/appBrowsers';
|
||||
|
||||
import { ControllerModule, ipcClientEvent, shortcut } from './index';
|
||||
|
||||
export default class BrowserWindowsCtr extends ControllerModule {
|
||||
@shortcut('toggleMainWindow')
|
||||
async toggleMainWindow() {
|
||||
const mainWindow = this.app.browserManager.getMainWindow();
|
||||
mainWindow.toggleVisible();
|
||||
}
|
||||
|
||||
@ipcClientEvent('openSettingsWindow')
|
||||
async openSettingsWindow(tab?: string) {
|
||||
console.log('[BrowserWindowsCtr] Received request to open settings window', tab);
|
||||
|
||||
try {
|
||||
await this.app.browserManager.showSettingsWindowWithTab(tab);
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('[BrowserWindowsCtr] Failed to open settings window:', error);
|
||||
return { error: error.message, success: false };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle route interception requests
|
||||
* Responsible for handling route interception requests from the renderer process
|
||||
*/
|
||||
@ipcClientEvent('interceptRoute')
|
||||
async interceptRoute(params: InterceptRouteParams) {
|
||||
const { path, source } = params;
|
||||
console.log(
|
||||
`[BrowserWindowsCtr] Received route interception request: ${path}, source: ${source}`,
|
||||
);
|
||||
|
||||
// Find matching route configuration
|
||||
const matchedRoute = findMatchingRoute(path);
|
||||
|
||||
// If no matching route found, return not intercepted
|
||||
if (!matchedRoute) {
|
||||
console.log(`[BrowserWindowsCtr] No matching route configuration found: ${path}`);
|
||||
return { intercepted: false, path, source };
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[BrowserWindowsCtr] Intercepted route: ${path}, target window: ${matchedRoute.targetWindow}`,
|
||||
);
|
||||
|
||||
try {
|
||||
if (matchedRoute.targetWindow === BrowsersIdentifiers.settings) {
|
||||
const subPath = extractSubPath(path, matchedRoute.pathPrefix);
|
||||
|
||||
await this.app.browserManager.showSettingsWindowWithTab(subPath);
|
||||
|
||||
return {
|
||||
intercepted: true,
|
||||
path,
|
||||
source,
|
||||
subPath,
|
||||
targetWindow: matchedRoute.targetWindow,
|
||||
};
|
||||
} else {
|
||||
await this.openTargetWindow(matchedRoute.targetWindow as AppBrowsersIdentifiers);
|
||||
|
||||
return {
|
||||
intercepted: true,
|
||||
path,
|
||||
source,
|
||||
targetWindow: matchedRoute.targetWindow,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[BrowserWindowsCtr] Error while processing route interception:', error);
|
||||
return {
|
||||
error: error.message,
|
||||
intercepted: false,
|
||||
path,
|
||||
source,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open target window and navigate to specified sub-path
|
||||
*/
|
||||
private async openTargetWindow(targetWindow: AppBrowsersIdentifiers) {
|
||||
// Ensure the window can always be created or reopened
|
||||
const browser = this.app.browserManager.retrieveByIdentifier(targetWindow);
|
||||
browser.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ControllerModule, ipcClientEvent } from './index';
|
||||
|
||||
export default class DevtoolsCtr extends ControllerModule {
|
||||
@ipcClientEvent('openDevtools')
|
||||
async openDevtools() {
|
||||
const devtoolsBrowser = this.app.browserManager.retrieveByIdentifier('devtools');
|
||||
devtoolsBrowser.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import FileService from '@/services/fileSrv';
|
||||
|
||||
import { ControllerModule, ipcClientEvent, ipcServerEvent } from './index';
|
||||
|
||||
interface UploadFileParams {
|
||||
content: ArrayBuffer;
|
||||
filename: string;
|
||||
hash: string;
|
||||
path: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export default class FileCtr extends ControllerModule {
|
||||
private get fileService() {
|
||||
return this.app.getService(FileService);
|
||||
}
|
||||
|
||||
@ipcClientEvent('createFile')
|
||||
async uploadFile(params: UploadFileParams) {
|
||||
return this.fileService.uploadFile(params);
|
||||
}
|
||||
|
||||
// ======== server event
|
||||
|
||||
@ipcServerEvent('getStaticFilePath')
|
||||
async getFileUrlById(id: string) {
|
||||
return this.fileService.getFilePath(id);
|
||||
}
|
||||
|
||||
@ipcServerEvent('deleteFiles')
|
||||
async deleteFiles(paths: string[]) {
|
||||
return this.fileService.deleteFiles(paths);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ControllerModule, ipcClientEvent } from './index';
|
||||
|
||||
export default class MenuController extends ControllerModule {
|
||||
/**
|
||||
* 刷新菜单
|
||||
*/
|
||||
@ipcClientEvent('refreshAppMenu')
|
||||
refreshAppMenu() {
|
||||
// 注意:可能需要根据具体情况决定是否允许渲染进程刷新所有菜单
|
||||
return this.app.menuManager.refreshMenus();
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示上下文菜单
|
||||
*/
|
||||
@ipcClientEvent('showContextMenu')
|
||||
showContextMenu(type: string, data?: any) {
|
||||
return this.app.menuManager.showContextMenu(type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置开发菜单可见性
|
||||
*/
|
||||
@ipcClientEvent('setDevMenuVisibility')
|
||||
setDevMenuVisibility(visible: boolean) {
|
||||
// 调用 MenuManager 的方法来重建应用菜单
|
||||
return this.app.menuManager.rebuildAppMenu({ showDevItems: visible });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { ControllerModule, ipcClientEvent } from '.';
|
||||
|
||||
export default class ShortcutController extends ControllerModule {
|
||||
/**
|
||||
* 获取所有快捷键配置
|
||||
*/
|
||||
@ipcClientEvent('getShortcutsConfig')
|
||||
getShortcutsConfig() {
|
||||
return this.app.shortcutManager.getShortcutsConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新单个快捷键配置
|
||||
*/
|
||||
@ipcClientEvent('updateShortcutConfig')
|
||||
updateShortcutConfig(id: string, accelerator: string): boolean {
|
||||
return this.app.shortcutManager.updateShortcutConfig(id, accelerator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import { app, systemPreferences } from 'electron';
|
||||
import { macOS } from 'electron-is';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
import { userDataDir } from '@/const/dir';
|
||||
|
||||
import { ControllerModule, ipcClientEvent, ipcServerEvent } from './index';
|
||||
|
||||
const DB_SCHEMA_HASH_PATH = path.join(userDataDir, 'lobehub-local-db-schema-hash');
|
||||
|
||||
export default class SystemService extends ControllerModule {
|
||||
/**
|
||||
* 检查可用性
|
||||
*/
|
||||
@ipcClientEvent('checkSystemAccessibility')
|
||||
checkAccessibilityForMacOS() {
|
||||
if (!macOS()) return;
|
||||
return systemPreferences.isTrustedAccessibilityClient(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新应用语言设置
|
||||
*/
|
||||
@ipcClientEvent('updateLocale')
|
||||
async updateLocale(locale: string) {
|
||||
// 保存语言设置
|
||||
this.app.storeManager.set('locale', locale);
|
||||
|
||||
// 更新i18n实例的语言
|
||||
await this.app.i18n.changeLanguage(locale === 'auto' ? app.getLocale() : locale);
|
||||
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
@ipcServerEvent('getDatabasePath')
|
||||
async getDatabasePath() {
|
||||
return path.join(userDataDir, 'lobehub-local-db');
|
||||
}
|
||||
|
||||
@ipcServerEvent('getDatabaseSchemaHash')
|
||||
async getDatabaseSchemaHash() {
|
||||
try {
|
||||
return readFileSync(DB_SCHEMA_HASH_PATH, 'utf8');
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ipcServerEvent('getUserDataPath')
|
||||
async getUserDataPath() {
|
||||
return userDataDir;
|
||||
}
|
||||
|
||||
@ipcServerEvent('setDatabaseSchemaHash')
|
||||
async setDatabaseSchemaHash(hash: string) {
|
||||
writeFileSync(DB_SCHEMA_HASH_PATH, hash, 'utf8');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { App } from '@/core/App';
|
||||
|
||||
import { ipcClientEvent } from './index';
|
||||
|
||||
export default class UpdaterService {
|
||||
private app: App;
|
||||
|
||||
constructor(app: App) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查更新
|
||||
*/
|
||||
@ipcClientEvent('checkUpdate')
|
||||
async checkForUpdates() {
|
||||
console.log('[UpdaterSrv] Check for updates requested');
|
||||
await this.app.updaterManager.checkForUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载更新
|
||||
*/
|
||||
@ipcClientEvent('downloadUpdate')
|
||||
async downloadUpdate() {
|
||||
console.log('[UpdaterSrv] Download update requested');
|
||||
await this.app.updaterManager.downloadUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭应用并安装更新
|
||||
*/
|
||||
@ipcClientEvent('installNow')
|
||||
quitAndInstallUpdate() {
|
||||
console.log('[UpdaterSrv] Quit and install update requested');
|
||||
this.app.updaterManager.installNow();
|
||||
}
|
||||
|
||||
/**
|
||||
* 下次启动时安装更新
|
||||
*/
|
||||
@ipcClientEvent('installLater')
|
||||
installLater() {
|
||||
console.log('[UpdaterSrv] Install later requested');
|
||||
this.app.updaterManager.installLater();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { ControllerModule, ipcClientEvent } from './index';
|
||||
|
||||
export default class DevtoolsCtr extends ControllerModule {
|
||||
@ipcClientEvent('openDevtools')
|
||||
async openDevtools() {
|
||||
const devtoolsBrowser = this.app.browserManager.retrieveByIdentifier('devtools');
|
||||
devtoolsBrowser.show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import * as fs from 'node:fs';
|
||||
import * as path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
import FileSearchService from '@/services/fileSearchSrv';
|
||||
|
||||
import { ControllerModule, ipcClientEvent } from './index';
|
||||
|
||||
const readFilePromise = promisify(fs.readFile);
|
||||
const statPromise = promisify(fs.stat);
|
||||
|
||||
// 定义一个接口来表示读取文件的返回结果
|
||||
interface ReadFileResult {
|
||||
content: string;
|
||||
createdTime: Date;
|
||||
fileType: string;
|
||||
filename: string;
|
||||
modifiedTime: Date;
|
||||
}
|
||||
|
||||
export default class FileSearchCtr extends ControllerModule {
|
||||
private get searchService() {
|
||||
return this.app.getService(FileSearchService);
|
||||
}
|
||||
|
||||
@ipcClientEvent('searchFiles')
|
||||
async searchFiles(query: string) {
|
||||
return this.searchService.search(query);
|
||||
}
|
||||
|
||||
@ipcClientEvent('readFiles')
|
||||
async readFiles(paths: string[]): Promise<ReadFileResult[]> {
|
||||
const results: ReadFileResult[] = [];
|
||||
|
||||
for (const filePath of paths) {
|
||||
try {
|
||||
// 获取文件状态信息
|
||||
const stats = await statPromise(filePath);
|
||||
|
||||
// 获取文件名
|
||||
const filename = path.basename(filePath);
|
||||
|
||||
// 获取文件扩展名
|
||||
const fileType = path.extname(filePath).toLowerCase().replace('.', '');
|
||||
|
||||
// 初始化结果对象
|
||||
const result: ReadFileResult = {
|
||||
content: '',
|
||||
createdTime: stats.birthtime,
|
||||
fileType,
|
||||
filename,
|
||||
modifiedTime: stats.mtime,
|
||||
};
|
||||
|
||||
// 判断文件是否可以以纯文本方式读取
|
||||
if (this.isTextReadableFile(fileType) && !stats.isDirectory()) {
|
||||
try {
|
||||
// 尝试读取文件内容
|
||||
result.content = await readFilePromise(filePath, 'utf8');
|
||||
} catch (error) {
|
||||
// 读取失败,设置错误信息
|
||||
result.content = `Failed to read file content: ${(error as Error).message}`;
|
||||
}
|
||||
} else if (stats.isDirectory()) {
|
||||
// 目录不能以文本方式读取
|
||||
result.content = 'This is a directory and cannot be read as plain text.';
|
||||
} else {
|
||||
// 不可读取的文件类型
|
||||
result.content = 'This file cannot be read as plain text.';
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
// 处理文件不存在或无法访问的情况
|
||||
results.push({
|
||||
content: `Error accessing file: ${(error as Error).message}`,
|
||||
createdTime: new Date(),
|
||||
fileType: 'unknown',
|
||||
filename: path.basename(filePath),
|
||||
modifiedTime: new Date(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a file can be read as text
|
||||
* @param fileType File extension
|
||||
* @returns Whether the file can be read as text
|
||||
*/
|
||||
private isTextReadableFile(fileType: string): boolean {
|
||||
// Common file types that can be read as text
|
||||
const textReadableTypes = [
|
||||
'txt',
|
||||
'md',
|
||||
'json',
|
||||
'xml',
|
||||
'html',
|
||||
'htm',
|
||||
'css',
|
||||
'scss',
|
||||
'less',
|
||||
'js',
|
||||
'ts',
|
||||
'jsx',
|
||||
'tsx',
|
||||
'vue',
|
||||
'svelte',
|
||||
'php',
|
||||
'py',
|
||||
'rb',
|
||||
'java',
|
||||
'c',
|
||||
'cpp',
|
||||
'h',
|
||||
'hpp',
|
||||
'cs',
|
||||
'go',
|
||||
'rs',
|
||||
'swift',
|
||||
'kt',
|
||||
'sh',
|
||||
'bat',
|
||||
'yml',
|
||||
'yaml',
|
||||
'toml',
|
||||
'ini',
|
||||
'cfg',
|
||||
'conf',
|
||||
'log',
|
||||
'svg',
|
||||
'csv',
|
||||
'sql',
|
||||
];
|
||||
|
||||
return textReadableTypes.includes(fileType.toLowerCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import type { ClientDispatchEvents } from '@lobechat/electron-client-ipc';
|
||||
import type { ServerDispatchEvents } from '@lobechat/electron-server-ipc';
|
||||
|
||||
import type { App } from '@/core/App';
|
||||
import { IoCContainer } from '@/core/IoCContainer';
|
||||
import { ShortcutActionType } from '@/shortcuts';
|
||||
|
||||
const ipcDecorator =
|
||||
(name: string, mode: 'client' | 'server') =>
|
||||
(target: any, methodName: string, descriptor?: any) => {
|
||||
const actions = IoCContainer.controllers.get(target.constructor) || [];
|
||||
actions.push({
|
||||
methodName,
|
||||
mode,
|
||||
name,
|
||||
});
|
||||
IoCContainer.controllers.set(target.constructor, actions);
|
||||
return descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* controller 用的 ipc client event 装饰器
|
||||
*/
|
||||
export const ipcClientEvent = (method: keyof ClientDispatchEvents) =>
|
||||
ipcDecorator(method, 'client');
|
||||
|
||||
/**
|
||||
* controller 用的 ipc server event 装饰器
|
||||
*/
|
||||
export const ipcServerEvent = (method: keyof ServerDispatchEvents) =>
|
||||
ipcDecorator(method, 'server');
|
||||
|
||||
const shortcutDecorator = (name: string) => (target: any, methodName: string, descriptor?: any) => {
|
||||
const actions = IoCContainer.shortcuts.get(target.constructor) || [];
|
||||
actions.push({ methodName, name });
|
||||
|
||||
IoCContainer.shortcuts.set(target.constructor, actions);
|
||||
|
||||
return descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* shortcut inject decorator
|
||||
*/
|
||||
export const shortcut = (method: ShortcutActionType) => shortcutDecorator(method);
|
||||
|
||||
export class ControllerModule {
|
||||
constructor(public app: App) {
|
||||
this.app = app;
|
||||
}
|
||||
}
|
||||
|
||||
export type IControlModule = typeof ControllerModule;
|
||||
@@ -0,0 +1,236 @@
|
||||
import { ElectronIPCEventHandler, ElectronIPCServer } from '@lobechat/electron-server-ipc';
|
||||
import { Session, app, ipcMain, protocol } from 'electron';
|
||||
import { macOS, windows } from 'electron-is';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { buildDir, nextStandaloneDir } from '@/const/dir';
|
||||
import { isDev } from '@/const/env';
|
||||
import { IControlModule } from '@/controllers';
|
||||
import { IServiceModule } from '@/services';
|
||||
import { createHandler } from '@/utils/next-electron-rsc';
|
||||
|
||||
import BrowserManager from './BrowserManager';
|
||||
import { I18nManager } from './I18nManager';
|
||||
import { IoCContainer } from './IoCContainer';
|
||||
import MenuManager from './MenuManager';
|
||||
import { ShortcutManager } from './ShortcutManager';
|
||||
import { StoreManager } from './StoreManager';
|
||||
import { UpdaterManager } from './UpdaterManager';
|
||||
|
||||
export type IPCEventMap = Map<string, { controller: any; methodName: string }>;
|
||||
export type ShortcutMethodMap = Map<string, () => Promise<void>>;
|
||||
|
||||
type Class<T> = new (...args: any[]) => T;
|
||||
|
||||
const importAll = (r: any) => Object.values(r).map((v: any) => v.default);
|
||||
|
||||
export class App {
|
||||
nextServerUrl = 'http://localhost:3015';
|
||||
|
||||
browserManager: BrowserManager;
|
||||
menuManager: MenuManager;
|
||||
i18n: I18nManager;
|
||||
storeManager: StoreManager;
|
||||
updaterManager: UpdaterManager;
|
||||
shortcutManager: ShortcutManager;
|
||||
|
||||
/**
|
||||
* whether app is in quiting
|
||||
*/
|
||||
isQuiting: boolean = false;
|
||||
|
||||
constructor() {
|
||||
// 初始化存储管理器
|
||||
this.storeManager = new StoreManager(this);
|
||||
|
||||
// load controllers
|
||||
const controllers: IControlModule[] = importAll(
|
||||
(import.meta as any).glob('@/controllers/*Ctr.ts', { eager: true }),
|
||||
);
|
||||
|
||||
controllers.forEach((controller) => this.addController(controller));
|
||||
|
||||
// load services
|
||||
const services: IServiceModule[] = importAll(
|
||||
(import.meta as any).glob('@/services/*Srv.ts', { eager: true }),
|
||||
);
|
||||
|
||||
services.forEach((service) => this.addService(service));
|
||||
|
||||
this.initializeIPCEvents();
|
||||
|
||||
this.i18n = new I18nManager(this);
|
||||
this.browserManager = new BrowserManager(this);
|
||||
this.menuManager = new MenuManager(this);
|
||||
this.updaterManager = new UpdaterManager(this);
|
||||
this.shortcutManager = new ShortcutManager(this);
|
||||
|
||||
// register the schema to interceptor url
|
||||
// it should register before app ready
|
||||
this.registerNextHandler();
|
||||
}
|
||||
|
||||
bootstrap = async () => {
|
||||
// make single instance
|
||||
const isSingle = app.requestSingleInstanceLock();
|
||||
if (!isSingle) app.exit(0);
|
||||
|
||||
this.initDevBranding();
|
||||
|
||||
// ==============
|
||||
await this.ipcServer.start();
|
||||
|
||||
await app.whenReady();
|
||||
|
||||
// 初始化 i18n. PS: app.getLocale() 必须在 app.whenReady() 之后调用才能拿到正确的值
|
||||
await this.i18n.init();
|
||||
this.menuManager.initialize();
|
||||
|
||||
// 初始化全局快捷键: globalShortcut 必须在 app.whenReady() 之后调用
|
||||
this.shortcutManager.initialize();
|
||||
|
||||
this.browserManager.initializeBrowsers();
|
||||
|
||||
// 初始化更新管理器
|
||||
await this.updaterManager.initialize();
|
||||
|
||||
// 添加全局应用退出状态
|
||||
this.isQuiting = false;
|
||||
|
||||
// 监听 before-quit 事件,设置退出标志
|
||||
app.on('before-quit', () => {
|
||||
this.isQuiting = true;
|
||||
// 在应用退出前注销所有快捷键
|
||||
this.shortcutManager.unregisterAll();
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (windows()) {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on('activate', this.onActivate);
|
||||
};
|
||||
|
||||
getService<T>(serviceClass: Class<T>): T {
|
||||
return this.services.get(serviceClass);
|
||||
}
|
||||
|
||||
private onActivate = () => {
|
||||
this.browserManager.showMainWindow();
|
||||
};
|
||||
|
||||
// ============= helper ============= //
|
||||
|
||||
/**
|
||||
* all controllers in app
|
||||
*/
|
||||
private controllers = new WeakMap();
|
||||
/**
|
||||
* all services in app
|
||||
*/
|
||||
private services = new WeakMap();
|
||||
|
||||
private ipcServer: ElectronIPCServer;
|
||||
/**
|
||||
* webview 层 dispatch 来的事件表
|
||||
*/
|
||||
private ipcClientEventMap: IPCEventMap = new Map();
|
||||
private ipcServerEventMap: IPCEventMap = new Map();
|
||||
shortcutMethodMap: ShortcutMethodMap = new Map();
|
||||
|
||||
/**
|
||||
* use in next router interceptor in prod browser render
|
||||
*/
|
||||
nextInterceptor: (params: { enabled?: boolean; session: Session }) => () => void;
|
||||
|
||||
private addController = (ControllerClass: IControlModule) => {
|
||||
const controller = new ControllerClass(this);
|
||||
this.controllers.set(ControllerClass, controller);
|
||||
|
||||
IoCContainer.controllers.get(ControllerClass)?.forEach((event) => {
|
||||
if (event.mode === 'client') {
|
||||
// 将 event 装饰器中的对象全部存到 ipcClientEventMap 中
|
||||
this.ipcClientEventMap.set(event.name, {
|
||||
controller,
|
||||
methodName: event.methodName,
|
||||
});
|
||||
}
|
||||
|
||||
if (event.mode === 'server') {
|
||||
// 将 event 装饰器中的对象全部存到 ipcServerEventMap 中
|
||||
this.ipcServerEventMap.set(event.name, {
|
||||
controller,
|
||||
methodName: event.methodName,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
IoCContainer.shortcuts.get(ControllerClass)?.forEach((shortcut) => {
|
||||
this.shortcutMethodMap.set(shortcut.name, async () => {
|
||||
controller[shortcut.methodName]();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
private addService = (ServiceClass: IServiceModule) => {
|
||||
const service = new ServiceClass(this);
|
||||
this.services.set(ServiceClass, service);
|
||||
};
|
||||
|
||||
private initDevBranding = () => {
|
||||
if (!isDev) return;
|
||||
|
||||
app.setName('LobeHub Dev');
|
||||
if (macOS()) {
|
||||
app.dock!.setIcon(join(buildDir, 'icon-dev.png'));
|
||||
}
|
||||
};
|
||||
|
||||
private registerNextHandler() {
|
||||
const handler = createHandler({
|
||||
debug: true,
|
||||
localhostUrl: this.nextServerUrl,
|
||||
protocol,
|
||||
standaloneDir: nextStandaloneDir,
|
||||
});
|
||||
console.log(
|
||||
`[APP] Server Debugging Enabled, ${this.nextServerUrl} will be intercepted to ${nextStandaloneDir}`,
|
||||
);
|
||||
|
||||
this.nextInterceptor = handler.createInterceptor;
|
||||
}
|
||||
|
||||
private initializeIPCEvents() {
|
||||
// 批量注册 controller 中 client event 事件 供 render 端消费
|
||||
this.ipcClientEventMap.forEach((eventInfo, key) => {
|
||||
const { controller, methodName } = eventInfo;
|
||||
|
||||
ipcMain.handle(key, async (e, ...data) => {
|
||||
try {
|
||||
return await controller[methodName](...data);
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 批量注册 controller 中的 server event 事件 供 next server 端消费
|
||||
const ipcServerEvents = {} as ElectronIPCEventHandler;
|
||||
|
||||
this.ipcServerEventMap.forEach((eventInfo, key) => {
|
||||
const { controller, methodName } = eventInfo;
|
||||
|
||||
ipcServerEvents[key] = async (payload) => {
|
||||
try {
|
||||
return await controller[methodName](payload);
|
||||
} catch (error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
this.ipcServer = new ElectronIPCServer(ipcServerEvents);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
import { MainBroadcastEventKey, MainBroadcastParams } from '@lobechat/electron-client-ipc';
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions, ipcMain } from 'electron';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { isDev } from '@/const/env';
|
||||
|
||||
import { preloadDir, resourcesDir } from '../const/dir';
|
||||
import type { App } from './App';
|
||||
|
||||
export interface BrowserWindowOpts extends BrowserWindowConstructorOptions {
|
||||
devTools?: boolean;
|
||||
height?: number;
|
||||
/**
|
||||
* URL
|
||||
*/
|
||||
identifier: string;
|
||||
keepAlive?: boolean;
|
||||
path: string;
|
||||
showOnInit?: boolean;
|
||||
title?: string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export default class Browser {
|
||||
private app: App;
|
||||
|
||||
/**
|
||||
* Internal electron window
|
||||
*/
|
||||
private _browserWindow?: BrowserWindow;
|
||||
|
||||
private stopInterceptHandler;
|
||||
/**
|
||||
* Identifier
|
||||
*/
|
||||
identifier: string;
|
||||
|
||||
/**
|
||||
* Options at creation
|
||||
*/
|
||||
options: BrowserWindowOpts;
|
||||
|
||||
/**
|
||||
* Method to expose window externally
|
||||
*/
|
||||
get browserWindow() {
|
||||
return this.retrieveOrInitialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to construct BrowserWindows object
|
||||
* @param options
|
||||
* @param application
|
||||
*/
|
||||
constructor(options: BrowserWindowOpts, application: App) {
|
||||
this.app = application;
|
||||
this.identifier = options.identifier;
|
||||
this.options = options;
|
||||
|
||||
// Initialization
|
||||
this.retrieveOrInitialize();
|
||||
}
|
||||
|
||||
loadUrl = async (path: string) => {
|
||||
const initUrl = this.app.nextServerUrl + path;
|
||||
|
||||
try {
|
||||
console.log(`[Browser] loading ${initUrl}`);
|
||||
await this._browserWindow.loadURL(initUrl);
|
||||
console.log(`[Browser] loaded ${initUrl}`);
|
||||
} catch (error) {
|
||||
console.error(`[Browser] failed to load (${initUrl}):`, error);
|
||||
|
||||
// Try to load local error page
|
||||
try {
|
||||
await this._browserWindow.loadFile(join(resourcesDir, 'error.html'));
|
||||
console.log('[APP] Error page loaded');
|
||||
|
||||
// Remove previously set retry listeners to avoid duplicates
|
||||
|
||||
// Set retry logic
|
||||
ipcMain.handle('retry-connection', async () => {
|
||||
console.log(`[APP] Attempting to reconnect ${initUrl}`);
|
||||
try {
|
||||
await this._browserWindow?.loadURL(initUrl);
|
||||
console.log('[APP] Reconnection successful');
|
||||
return { success: true };
|
||||
} catch (err) {
|
||||
console.error('[APP] Retry failed:', err);
|
||||
// Reload error page
|
||||
try {
|
||||
await this._browserWindow?.loadFile(join(resourcesDir, 'error.html'));
|
||||
} catch (loadErr) {
|
||||
console.error('[APP] Failed to load error page:', loadErr);
|
||||
}
|
||||
return { error: err.message, success: false };
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('[APP] Failed to load error page:', err);
|
||||
// If even the error page can't be loaded, at least show a simple error message
|
||||
try {
|
||||
await this._browserWindow.loadURL(
|
||||
'data:text/html,<html><body><h1>Loading Failed</h1><p>Unable to connect to server, please restart the application</p></body></html>',
|
||||
);
|
||||
} catch (finalErr) {
|
||||
console.error('[APP] Unable to display any page:', finalErr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadPlaceholder = async () => {
|
||||
// First load a local HTML loading page
|
||||
await this._browserWindow.loadFile(join(resourcesDir, 'splash.html'));
|
||||
};
|
||||
|
||||
show() {
|
||||
this.browserWindow.show();
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.browserWindow.hide();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.browserWindow.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy instance
|
||||
*/
|
||||
destroy() {
|
||||
this.stopInterceptHandler?.();
|
||||
this._browserWindow = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize
|
||||
*/
|
||||
retrieveOrInitialize() {
|
||||
// When there is this window and it has not been destroyed
|
||||
if (this._browserWindow && !this._browserWindow.isDestroyed()) {
|
||||
return this._browserWindow;
|
||||
}
|
||||
|
||||
const { path, title, width, height, devTools, showOnInit, ...res } = this.options;
|
||||
|
||||
console.log(`[Browser] create new Browser instance: ${this.identifier}`);
|
||||
const browserWindow = new BrowserWindow({
|
||||
...res,
|
||||
height,
|
||||
show: false,
|
||||
title,
|
||||
transparent: true,
|
||||
webPreferences: {
|
||||
// Context isolation environment
|
||||
// https://www.electronjs.org/docs/tutorial/context-isolation
|
||||
contextIsolation: true,
|
||||
preload: join(preloadDir, 'index.js'),
|
||||
// devTools: isDev,
|
||||
},
|
||||
width,
|
||||
});
|
||||
|
||||
this._browserWindow = browserWindow;
|
||||
|
||||
this.stopInterceptHandler = this.app.nextInterceptor({
|
||||
enabled: !isDev,
|
||||
session: browserWindow.webContents.session,
|
||||
});
|
||||
|
||||
// Windows 11 can use this new API
|
||||
if (process.platform === 'win32' && browserWindow.setBackgroundMaterial) {
|
||||
browserWindow.setBackgroundMaterial('acrylic');
|
||||
}
|
||||
|
||||
this.loadPlaceholder().then(() => {
|
||||
this.loadUrl(path).catch((e) => {
|
||||
console.error(`load url error, ${path}`, e);
|
||||
});
|
||||
});
|
||||
|
||||
// Show devtools if enabled
|
||||
if (devTools) {
|
||||
browserWindow.webContents.openDevTools();
|
||||
}
|
||||
|
||||
browserWindow.once('ready-to-show', () => {
|
||||
if (showOnInit) browserWindow?.show();
|
||||
});
|
||||
|
||||
browserWindow.on('close', (e) => {
|
||||
console.log(`[Browser] Window close event: ${this.identifier}`);
|
||||
|
||||
// If in application quitting process, allow window to be closed
|
||||
if (this.app.isQuiting) {
|
||||
// Need to clean up intercept handler
|
||||
this.stopInterceptHandler?.();
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent window from being destroyed, just hide it (if marked as keepAlive)
|
||||
if (this.options.keepAlive) {
|
||||
console.log(`[Browser] Window needs to remain active: ${this.identifier}`);
|
||||
e.preventDefault();
|
||||
browserWindow.hide();
|
||||
} else {
|
||||
// Need to clean up intercept handler
|
||||
this.stopInterceptHandler?.();
|
||||
}
|
||||
});
|
||||
|
||||
return browserWindow;
|
||||
}
|
||||
|
||||
moveToCenter() {
|
||||
this._browserWindow?.center();
|
||||
}
|
||||
|
||||
setWindowSize(boundSize: { height?: number; width?: number }) {
|
||||
const windowSize = this._browserWindow.getBounds();
|
||||
this._browserWindow?.setBounds({
|
||||
height: boundSize.height || windowSize.height,
|
||||
width: boundSize.width || windowSize.width,
|
||||
});
|
||||
}
|
||||
|
||||
broadcast = <T extends MainBroadcastEventKey>(channel: T, data?: MainBroadcastParams<T>) => {
|
||||
this._browserWindow.webContents.send(channel, data);
|
||||
};
|
||||
|
||||
toggleVisible() {
|
||||
if (this._browserWindow.isVisible() && this._browserWindow.isFocused()) {
|
||||
this._browserWindow.hide();
|
||||
} else {
|
||||
this._browserWindow.show();
|
||||
this._browserWindow.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user