From a866ecc3b31b1bd4a98c4e66a291a87d42b7efb1 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:14:45 +0800 Subject: [PATCH 1/6] feat: add e2e entry script and i18n CI check - Add scripts/e2e.ts as entry point requiring spec file selection - Rename e2e to e2e:all for running all tests - Add i18n check job to CI workflow --- .github/workflows/ci.yml | 31 ++++++++++- package.json | 3 +- scripts/e2e.ts | 117 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 scripts/e2e.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 140264683..2d1b53348 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,6 +85,31 @@ jobs: - name: Unit tests run: pnpm test + # ==================== i18n 检查 ==================== + i18n: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: ${{ env.PNPM_VERSION }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Check i18n keys + run: pnpm i18n:check + # ==================== 构建检查 ==================== build: runs-on: ubuntu-latest @@ -155,7 +180,7 @@ jobs: # ==================== 最终状态检查 ==================== checks: runs-on: ubuntu-latest - needs: [typecheck, test, build, e2e] + needs: [typecheck, test, i18n, build, e2e] if: always() steps: - name: Check results @@ -168,6 +193,10 @@ jobs: echo "Tests failed" exit 1 fi + if [[ "${{ needs.i18n.result }}" == "failure" ]]; then + echo "i18n check failed" + exit 1 + fi if [[ "${{ needs.build.result }}" == "failure" ]]; then echo "Build failed" exit 1 diff --git a/package.json b/package.json index 3d1dc3414..e2ba69fc6 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,8 @@ "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "typecheck": "tsc --build --noEmit", - "e2e": "playwright test", + "e2e": "bun scripts/e2e.ts", + "e2e:all": "playwright test", "e2e:ui": "playwright test --ui", "e2e:headed": "playwright test --headed", "e2e:update": "playwright test --update-snapshots", diff --git a/scripts/e2e.ts b/scripts/e2e.ts new file mode 100644 index 000000000..dfe1b703a --- /dev/null +++ b/scripts/e2e.ts @@ -0,0 +1,117 @@ +#!/usr/bin/env bun +/** + * E2E 测试入口脚本 + * + * 要求必须传递至少一个 spec 文件,以控制测试时间成本。 + * + * Usage: + * bun scripts/e2e.ts # 运行指定 spec(不需要 .spec.ts 后缀) + * bun scripts/e2e.ts pages guide # 运行多个 spec + * bun scripts/e2e.ts --all # 运行所有测试(等同于 pnpm e2e:all) + * + * Examples: + * bun scripts/e2e.ts pages + * bun scripts/e2e.ts wallet-create wallet-import + * bun scripts/e2e.ts i18n-boot --headed + */ + +import { readdirSync } from 'node:fs' +import { join, resolve, basename } from 'node:path' +import { execSync } from 'node:child_process' + +const ROOT = resolve(import.meta.dirname, '..') +const E2E_DIR = join(ROOT, 'e2e') + +const colors = { + reset: '\x1b[0m', + bold: '\x1b[1m', + dim: '\x1b[2m', + red: '\x1b[31m', + green: '\x1b[32m', + yellow: '\x1b[33m', + cyan: '\x1b[36m', +} + +function getAvailableSpecs(): string[] { + return readdirSync(E2E_DIR) + .filter((f) => f.endsWith('.spec.ts')) + .map((f) => f.replace('.spec.ts', '')) + .sort() +} + +function printUsage() { + const specs = getAvailableSpecs() + + console.log(` +${colors.bold}${colors.cyan}E2E 测试入口${colors.reset} + +${colors.yellow}用法:${colors.reset} + pnpm e2e [spec-name...] 运行指定 spec + pnpm e2e --all 运行所有测试 + pnpm e2e --headed 带界面运行 + pnpm e2e --ui 使用 Playwright UI 模式 + +${colors.yellow}可用的 spec 文件 (${specs.length}):${colors.reset} +${specs.map((s) => ` ${colors.dim}•${colors.reset} ${s}`).join('\n')} + +${colors.yellow}示例:${colors.reset} + pnpm e2e pages + pnpm e2e wallet-create wallet-import + pnpm e2e i18n-boot --headed + +${colors.dim}提示: 为了控制测试时间,请只运行需要的 spec 文件。 +运行全部测试请使用: pnpm e2e:all${colors.reset} +`) +} + +function main() { + const args = process.argv.slice(2) + + // 如果有 --all 参数,运行所有测试 + if (args.includes('--all')) { + const otherArgs = args.filter((a) => a !== '--all') + const cmd = ['playwright', 'test', ...otherArgs].join(' ') + console.log(`${colors.cyan}运行所有 E2E 测试...${colors.reset}\n`) + execSync(cmd, { stdio: 'inherit', cwd: ROOT }) + return + } + + // 分离 spec 名称和 playwright 参数 + const specNames: string[] = [] + const playwrightArgs: string[] = [] + + for (const arg of args) { + if (arg.startsWith('-')) { + playwrightArgs.push(arg) + } else { + specNames.push(arg) + } + } + + // 如果没有传递 spec 名称,显示用法 + if (specNames.length === 0) { + printUsage() + process.exit(1) + } + + const availableSpecs = getAvailableSpecs() + + // 验证 spec 名称 + const invalidSpecs = specNames.filter((s) => !availableSpecs.includes(s)) + if (invalidSpecs.length > 0) { + console.error( + `${colors.red}错误: 未找到以下 spec 文件:${colors.reset} ${invalidSpecs.join(', ')}`, + ) + console.error(`${colors.dim}可用的 spec: ${availableSpecs.join(', ')}${colors.reset}`) + process.exit(1) + } + + // 构建 playwright 命令 + const specFiles = specNames.map((s) => `e2e/${s}.spec.ts`) + const cmd = ['playwright', 'test', ...specFiles, ...playwrightArgs].join(' ') + + console.log(`${colors.cyan}运行 E2E 测试: ${specNames.join(', ')}${colors.reset}\n`) + execSync(cmd, { stdio: 'inherit', cwd: ROOT }) +} + +main() From 36a167dac77020251f86f82e4d3df03aba7f6f25 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:18:28 +0800 Subject: [PATCH 2/6] feat: introduce turborepo for build/test caching - Add turbo as dev dependency - Configure turbo.json with tasks: typecheck, test, i18n:check, e2e:all, build - Add packageManager field to package.json - Add turbo:* convenience scripts Performance improvement: - First run (no cache): ~35s - Cached run: ~1.5s - Speed improvement: ~23x faster for unchanged code --- package.json | 9 ++++++- pnpm-lock.yaml | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ turbo.json | 47 ++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 turbo.json diff --git a/package.json b/package.json index e2ba69fc6..3a771dcfa 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "private": true, "version": "0.1.0", "type": "module", + "packageManager": "pnpm@10.22.0", "scripts": { "dev": "vite", "dev:mock": "SERVICE_IMPL=mock vite --port 5174", @@ -36,7 +37,12 @@ "i18n:extract": "bun scripts/i18n-extract.ts", "i18n:check": "bun scripts/i18n-check.ts", "i18n:validate": "bun scripts/i18n-validate.ts", - "agent": "bun scripts/agent-readme.ts" + "agent": "bun scripts/agent-readme.ts", + "turbo:test": "turbo run test", + "turbo:typecheck": "turbo run typecheck", + "turbo:i18n": "turbo run i18n:check", + "turbo:e2e": "turbo run e2e:all", + "turbo:check": "turbo run typecheck test i18n:check" }, "dependencies": { "@base-ui/react": "^1.0.0", @@ -112,6 +118,7 @@ "shadcn": "^3.6.1", "storybook": "^10.1.4", "tailwindcss": "^4.0.0", + "turbo": "^2.7.1", "typescript": "~5.9.3", "vite": "^7.2.7", "vitepress": "^1.6.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66adca090..1bc273254 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -222,6 +222,9 @@ importers: tailwindcss: specifier: ^4.0.0 version: 4.1.17 + turbo: + specifier: ^2.7.1 + version: 2.7.1 typescript: specifier: ~5.9.3 version: 5.9.3 @@ -4188,6 +4191,40 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + turbo-darwin-64@2.7.1: + resolution: {integrity: sha512-EaA7UfYujbY9/Ku0WqPpvfctxm91h9LF7zo8vjielz+omfAPB54Si+ADmUoBczBDC6RoLgbURC3GmUW2alnjJg==} + cpu: [x64] + os: [darwin] + + turbo-darwin-arm64@2.7.1: + resolution: {integrity: sha512-/pWGSygtBugd7sKQOeMm+jKY3qN1vyB0RiHBM6bN/6qUOo2VHo8IQwBTIaSgINN4Ue6fzEU+WfePNvonSU9yXw==} + cpu: [arm64] + os: [darwin] + + turbo-linux-64@2.7.1: + resolution: {integrity: sha512-Y5H11mdhASw/dJuRFyGtTCDFX5/MPT73EKsVEiHbw5MkFc77lx3nMc5L/Q7bKEhef/vYJAsAb61QuHsB6qdP8Q==} + cpu: [x64] + os: [linux] + + turbo-linux-arm64@2.7.1: + resolution: {integrity: sha512-L/r77jD7cqIEXoyu2LGBUrTY5GJSi/XcGLsQ2nZ/fefk6x3MpljTvwsXUVG1BUkiBPc4zaKRj6yGyWMo5MbLxQ==} + cpu: [arm64] + os: [linux] + + turbo-windows-64@2.7.1: + resolution: {integrity: sha512-rkeuviXZ/1F7lCare7TNKvYtT/SH9dZR55FAMrxrFRh88b+ZKwlXEBfq5/1OctEzRUo/VLIm+s5LJMOEy+QshA==} + cpu: [x64] + os: [win32] + + turbo-windows-arm64@2.7.1: + resolution: {integrity: sha512-1rZk9htm3+iP/rWCf/h4/DFQey9sMs2TJPC4T5QQfwqAdMWsphgrxBuFqHdxczlbBCgbWNhVw0CH2bTxe1/GFg==} + cpu: [arm64] + os: [win32] + + turbo@2.7.1: + resolution: {integrity: sha512-zAj9jGc7VDvuAo/5Jbos4QTtWz9uUpkMhMKGyTjDJkx//hdL2bM31qQoJSAbU+7JyK5vb0LPzpwf6DUt3zayqg==} + hasBin: true + tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} @@ -8466,6 +8503,33 @@ snapshots: tslib@2.8.1: {} + turbo-darwin-64@2.7.1: + optional: true + + turbo-darwin-arm64@2.7.1: + optional: true + + turbo-linux-64@2.7.1: + optional: true + + turbo-linux-arm64@2.7.1: + optional: true + + turbo-windows-64@2.7.1: + optional: true + + turbo-windows-arm64@2.7.1: + optional: true + + turbo@2.7.1: + optionalDependencies: + turbo-darwin-64: 2.7.1 + turbo-darwin-arm64: 2.7.1 + turbo-linux-64: 2.7.1 + turbo-linux-arm64: 2.7.1 + turbo-windows-64: 2.7.1 + turbo-windows-arm64: 2.7.1 + tw-animate-css@1.4.0: {} type-fest@5.3.1: diff --git a/turbo.json b/turbo.json new file mode 100644 index 000000000..b20a9fab5 --- /dev/null +++ b/turbo.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://turbo.build/schema.json", + "tasks": { + "typecheck": { + "dependsOn": [], + "inputs": ["src/**/*.ts", "src/**/*.tsx", "tsconfig*.json"], + "outputs": [], + "cache": true + }, + "test": { + "dependsOn": [], + "inputs": ["src/**/*.ts", "src/**/*.tsx", "vitest.config.ts"], + "outputs": ["coverage/**"], + "cache": true + }, + "i18n:check": { + "dependsOn": [], + "inputs": ["src/**/*.ts", "src/**/*.tsx", "src/i18n/**/*.json", "scripts/i18n-check.ts"], + "outputs": [], + "cache": true + }, + "e2e:all": { + "dependsOn": [], + "inputs": ["src/**", "e2e/**", "playwright.config.ts"], + "outputs": ["e2e/report/**", "e2e/test-results/**"], + "cache": true + }, + "build": { + "dependsOn": ["typecheck"], + "inputs": ["src/**", "index.html", "vite.config.ts", "tsconfig*.json"], + "outputs": ["dist/**"], + "cache": true + }, + "build:web": { + "dependsOn": ["typecheck"], + "inputs": ["src/**", "index.html", "vite.config.ts", "tsconfig*.json"], + "outputs": ["dist-web/**"], + "cache": true + }, + "build:dweb": { + "dependsOn": ["typecheck"], + "inputs": ["src/**", "index.html", "vite.config.ts", "tsconfig*.json"], + "outputs": ["dist-dweb/**"], + "cache": true + } + } +} From 4a8304456525c5860b5022556c3a07bf743cba80 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:24:34 +0800 Subject: [PATCH 3/6] fix: remove pnpm version from CI to use packageManager field --- .github/workflows/ci.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d1b53348..e5111a560 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,6 @@ on: env: NODE_VERSION: '24' - PNPM_VERSION: '10' jobs: # ==================== 变更检测 ==================== @@ -45,8 +44,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -70,8 +67,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -95,8 +90,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -120,8 +113,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - name: Setup Node.js uses: actions/setup-node@v4 @@ -147,8 +138,6 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4 - with: - version: ${{ env.PNPM_VERSION }} - name: Setup Node.js uses: actions/setup-node@v4 From 0f8ea09363dfef91375f2292dbbc07cf22ec9c4e Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:27:32 +0800 Subject: [PATCH 4/6] fix: add bun setup to CI for i18n and e2e jobs --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5111a560..cdd26912e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -88,6 +88,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -136,6 +139,9 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + - name: Setup pnpm uses: pnpm/action-setup@v4 @@ -164,7 +170,7 @@ jobs: run: pnpm exec playwright install-deps chromium - name: E2E smoke (Mobile Chrome) - run: pnpm e2e e2e/bioforest-chains.spec.ts --project "Mobile Chrome" + run: pnpm e2e bioforest-chains --project "Mobile Chrome" # ==================== 最终状态检查 ==================== checks: From 591ace2d6ed3c78e1a1ec5ab68ace3514b36d06c Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:30:46 +0800 Subject: [PATCH 5/6] fix: improve e2e script arg parsing and add missing i18n keys --- scripts/e2e.ts | 47 +++++++++++++- src/i18n/locales/ar/onboarding.json | 5 ++ src/i18n/locales/ar/wallet.json | 89 +++++++++++++------------- src/i18n/locales/zh-TW/onboarding.json | 5 ++ src/i18n/locales/zh-TW/wallet.json | 89 +++++++++++++------------- 5 files changed, 148 insertions(+), 87 deletions(-) diff --git a/scripts/e2e.ts b/scripts/e2e.ts index dfe1b703a..6b974d3c3 100644 --- a/scripts/e2e.ts +++ b/scripts/e2e.ts @@ -77,15 +77,60 @@ function main() { } // 分离 spec 名称和 playwright 参数 + // 使用 -- 分隔符或识别带值的参数 const specNames: string[] = [] const playwrightArgs: string[] = [] - for (const arg of args) { + // 需要参数值的 playwright 选项 + const argsWithValue = new Set([ + '--project', + '-p', + '--grep', + '-g', + '--config', + '-c', + '--workers', + '-j', + '--timeout', + '--retries', + '--reporter', + '--output', + '--trace', + '--shard', + '--global-timeout', + '--browser', + ]) + + let i = 0 + let foundSeparator = false + + while (i < args.length) { + const arg = args[i] + + // -- 后面的都是 playwright 参数 + if (arg === '--') { + foundSeparator = true + i++ + continue + } + + if (foundSeparator) { + playwrightArgs.push(arg) + i++ + continue + } + if (arg.startsWith('-')) { playwrightArgs.push(arg) + // 如果是需要值的参数,把下一个参数也加入 + if (argsWithValue.has(arg) && i + 1 < args.length && !args[i + 1].startsWith('-')) { + i++ + playwrightArgs.push(args[i]) + } } else { specNames.push(arg) } + i++ } // 如果没有传递 spec 名称,显示用法 diff --git a/src/i18n/locales/ar/onboarding.json b/src/i18n/locales/ar/onboarding.json index 3665c8bee..0c9f18774 100644 --- a/src/i18n/locales/ar/onboarding.json +++ b/src/i18n/locales/ar/onboarding.json @@ -126,6 +126,11 @@ "passwordPlaceholder": "أدخل كلمة المرور", "setPassword": "تعيين كلمة المرور", "setPasswordDesc": "تُستخدم كلمة المرور لتشفير محفظتك", + "success": { + "description": "[MISSING:ar] 钱包 {{name}} 已成功导入", + "enterWallet": "[MISSING:ar] 进入钱包", + "title": "[MISSING:ar] 导入成功" + }, "title": "استيراد المحفظة", "words12": "12 كلمة", "words24": "24 كلمة" diff --git a/src/i18n/locales/ar/wallet.json b/src/i18n/locales/ar/wallet.json index 47e3e42f3..be0767c89 100644 --- a/src/i18n/locales/ar/wallet.json +++ b/src/i18n/locales/ar/wallet.json @@ -1,11 +1,7 @@ { - "add": "إضافة محفظة", - "createDesc": "Generate a new mnemonic to create wallet", - "importDesc": "Import existing wallet with mnemonic or key", - "empty": "لا توجد محافظ بعد", - "emptyHint": "انقر على الزر أعلاه لإنشاء أو استيراد محفظة", " obtainingTheAddressPassowrdIsEquivalentToOwningTheWalletAsset": "Obtaining the address password is equivalent to owning the wallet asset", "1AllWalletDataInTheOriginal_{appName}": "1. All wallet data in the original will be retained and the data will be organized. The rules are as follows:", + "add": "إضافة محفظة", "addBitcoinAddress": "Add Bitcoin address", "addToken": "Add Token", "addWallet": "Add Wallet", @@ -33,6 +29,13 @@ "balance": "Balance", "belongingChain": "Belonging chain", "bitcoinAddressSettings": "Bitcoin address settings", + "chainSelector": { + "default": "افتراضي", + "noAddresses": "لا توجد عناوين في هذه السلسلة", + "noChains": "لا توجد سلاسل متاحة", + "selectAddress": "اختر العنوان", + "selectChain": "اختر السلسلة" + }, "changeWallet": "Change Wallet", "congratulationsYouHaveSuccessfullyCreatedANewWallet": "Congratulations you have successfully created a new wallet", "contractAddress": "Contract address", @@ -40,6 +43,7 @@ "creatWallet": "Create Wallet", "create": "Create", "create/importWallet": "Create/Import Wallet", + "createDesc": "Generate a new mnemonic to create wallet", "createEntity": "Create entity", "createEntityFactory": "Create entity factory", "createImport": "[MISSING:ar] 创建 / 导入", @@ -51,8 +55,44 @@ "deleteIdentityWallet": "Delete Identity Wallet", "deleteWallet": "Delete Wallet", "destoryAsset": "Destory asset", + "detail": { + "chainAddresses": "عناوين السلاسل", + "createdAt": "أُنشئت في {{date}}", + "deleteWallet": "حذف المحفظة", + "editName": "تعديل اسم المحفظة", + "exportDeveloping": "ميزة تصدير العبارة السرية قيد التطوير", + "exportMnemonic": "تصدير العبارة السرية", + "notFound": "المحفظة غير موجودة", + "securityWarning": "يتطلب تصدير العبارة السرية التحقق من كلمة المرور. يرجى التأكد من أنك في بيئة آمنة", + "title": "تفاصيل المحفظة", + "verifyFailed": "فشل التحقق", + "verifyToDelete": "تحقق من الهوية لحذف المحفظة", + "verifyToExport": "تحقق من الهوية لتصدير العبارة السرية", + "walletDeleted": "تم حذف المحفظة" + }, "doesNotMatchAddressRule": "Does not match address rule", "edit address": "Edit Address", + "editSheet": { + "cancel": "إلغاء", + "confirmDelete": "[MISSING:ar] 确认删除", + "delete": "حذف المحفظة", + "deleteDesc": "لا يمكن التراجع عن هذا الإجراء", + "deleteTitle": "حذف المحفظة", + "deleteWarning": "⚠️ لا يمكن التراجع عن هذا الإجراء\n\nأدخل كلمة المرور لتأكيد حذف المحفظة \"{{name}}\"", + "passwordError": "كلمة المرور غير صحيحة", + "passwordPlaceholder": "[MISSING:ar] 请输入钱包密码", + "rename": "إعادة تسمية", + "renameDesc": "تغيير اسم المحفظة", + "renameTitle": "إعادة تسمية المحفظة", + "save": "حفظ", + "title": "إعدادات المحفظة", + "verifyFailed": "فشل التحقق", + "verifying": "[MISSING:ar] 验证中...", + "walletName": "اسم المحفظة", + "walletNamePlaceholder": "أدخل اسم المحفظة" + }, + "empty": "لا توجد محافظ بعد", + "emptyHint": "انقر على الزر أعلاه لإنشاء أو استيراد محفظة", "enterOrPasteTheWalletAddress": "[MISSING:ar] 输入或者粘贴钱包地址", "enterTheAddressOf_{chain}": "Enter the address of", "enterWallet": "Enter wallet", @@ -64,6 +104,7 @@ "frozenAddressesCannotBeSet": "Frozen addresses cannot be set", "genesisaddress": "Genesis Address", "ifItIsNotBackedUpTheWalletCannotBeRestoredAndAssetLossMayResult": "[MISSING:ar] 若未完成助记词备份,将无法恢复钱包,同时可能造成资产损失。", + "importDesc": "Import existing wallet with mnemonic or key", "importTheAccountWithThePrivateKey": "Import the account with the private key", "importTheWalletOfTheAddressAndThePerformTheSigningOperation": "Import the wallet of the address and then perform the signing operation", "importWallet": "Import Wallet", @@ -79,44 +120,6 @@ "title": "إدارة المحافظ", "viewDetail": "عرض التفاصيل" }, - "chainSelector": { - "default": "افتراضي", - "noChains": "لا توجد سلاسل متاحة", - "selectChain": "اختر السلسلة", - "selectAddress": "اختر العنوان", - "noAddresses": "لا توجد عناوين في هذه السلسلة" - }, - "editSheet": { - "title": "إعدادات المحفظة", - "renameTitle": "إعادة تسمية المحفظة", - "rename": "إعادة تسمية", - "renameDesc": "تغيير اسم المحفظة", - "delete": "حذف المحفظة", - "deleteDesc": "لا يمكن التراجع عن هذا الإجراء", - "walletName": "اسم المحفظة", - "walletNamePlaceholder": "أدخل اسم المحفظة", - "save": "حفظ", - "cancel": "إلغاء", - "deleteTitle": "حذف المحفظة", - "deleteWarning": "⚠️ لا يمكن التراجع عن هذا الإجراء\n\nأدخل كلمة المرور لتأكيد حذف المحفظة \"{{name}}\"", - "passwordError": "كلمة المرور غير صحيحة", - "verifyFailed": "فشل التحقق" - }, - "detail": { - "title": "تفاصيل المحفظة", - "notFound": "المحفظة غير موجودة", - "createdAt": "أُنشئت في {{date}}", - "chainAddresses": "عناوين السلاسل", - "editName": "تعديل اسم المحفظة", - "exportMnemonic": "تصدير العبارة السرية", - "deleteWallet": "حذف المحفظة", - "exportDeveloping": "ميزة تصدير العبارة السرية قيد التطوير", - "walletDeleted": "تم حذف المحفظة", - "verifyToExport": "تحقق من الهوية لتصدير العبارة السرية", - "verifyToDelete": "تحقق من الهوية لحذف المحفظة", - "verifyFailed": "فشل التحقق", - "securityWarning": "يتطلب تصدير العبارة السرية التحقق من كلمة المرور. يرجى التأكد من أنك في بيئة آمنة" - }, "manageIdentityWallet": "Manage Identity Wallet", "manageIdentityWallets": "Manage Identity Wallets", "manageWallet": "Manage Wallet", diff --git a/src/i18n/locales/zh-TW/onboarding.json b/src/i18n/locales/zh-TW/onboarding.json index fe3dfe2ad..36449dd5b 100644 --- a/src/i18n/locales/zh-TW/onboarding.json +++ b/src/i18n/locales/zh-TW/onboarding.json @@ -126,6 +126,11 @@ "passwordPlaceholder": "輸入密碼", "setPassword": "設定密碼", "setPasswordDesc": "密碼用於加密您的錢包", + "success": { + "description": "[MISSING:zh-TW] 钱包 {{name}} 已成功导入", + "enterWallet": "[MISSING:zh-TW] 进入钱包", + "title": "[MISSING:zh-TW] 导入成功" + }, "title": "匯入錢包", "words12": "12 個單詞", "words24": "24 個單詞" diff --git a/src/i18n/locales/zh-TW/wallet.json b/src/i18n/locales/zh-TW/wallet.json index b5357f0fc..2c9ec4840 100644 --- a/src/i18n/locales/zh-TW/wallet.json +++ b/src/i18n/locales/zh-TW/wallet.json @@ -1,11 +1,7 @@ { - "add": "添加錢包", - "createDesc": "生成新的助記詞創建錢包", - "importDesc": "使用助記詞或密鑰導入已有錢包", - "empty": "暫無錢包", - "emptyHint": "點擊上方按鈕創建或匯入錢包", " obtainingTheAddressPassowrdIsEquivalentToOwningTheWalletAsset": "獲得地址密碼等同於擁有錢包資產所有權", "1AllWalletDataInTheOriginal_{appName}": "1. 原 中的錢包資料將全部保留,並進行資料整理,規則如下:", + "add": "添加錢包", "addBitcoinAddress": "添加 Bitcoin 地址", "addToken": "添加幣種", "addWallet": "添加錢包", @@ -33,6 +29,13 @@ "balance": "[MISSING:zh-TW] 余额", "belongingChain": "所屬鏈", "bitcoinAddressSettings": "Bitcoin 地址設置", + "chainSelector": { + "default": "預設", + "noAddresses": "該鏈暫無地址", + "noChains": "暫無可用鏈", + "selectAddress": "選擇地址", + "selectChain": "選擇鏈" + }, "changeWallet": "切換錢包", "congratulationsYouHaveSuccessfullyCreatedANewWallet": "恭喜您已經成功添加了一個新錢包", "contractAddress": "合約地址", @@ -40,6 +43,7 @@ "creatWallet": "創建錢包", "create": "創建", "create/importWallet": "創建/導入錢包", + "createDesc": "生成新的助記詞創建錢包", "createEntity": "創建同質化資產", "createEntityFactory": "創建同質化資產模板", "createImport": "創建 / 導入", @@ -51,8 +55,44 @@ "deleteIdentityWallet": "刪除身份錢包", "deleteWallet": "刪除錢包", "destoryAsset": "銷毀資產", + "detail": { + "chainAddresses": "鏈地址", + "createdAt": "建立於 {{date}}", + "deleteWallet": "刪除錢包", + "editName": "編輯錢包名稱", + "exportDeveloping": "助記詞匯出功能開發中", + "exportMnemonic": "匯出助記詞", + "notFound": "錢包不存在", + "securityWarning": "匯出助記詞需要驗證密碼,請確保在安全環境下操作", + "title": "錢包詳情", + "verifyFailed": "驗證失敗", + "verifyToDelete": "驗證身份以刪除錢包", + "verifyToExport": "驗證身份以匯出助記詞", + "walletDeleted": "錢包已刪除" + }, "doesNotMatchAddressRule": "地址不符合格式規則", "edit address": "編輯地址", + "editSheet": { + "cancel": "取消", + "confirmDelete": "[MISSING:zh-TW] 确认删除", + "delete": "刪除錢包", + "deleteDesc": "此操作無法撤銷", + "deleteTitle": "刪除錢包", + "deleteWarning": "⚠️ 此操作無法撤銷\n\n請輸入密碼以確認刪除錢包 \"{{name}}\"", + "passwordError": "密碼錯誤", + "passwordPlaceholder": "[MISSING:zh-TW] 请输入钱包密码", + "rename": "重命名", + "renameDesc": "修改錢包名稱", + "renameTitle": "重命名錢包", + "save": "儲存", + "title": "錢包設定", + "verifyFailed": "驗證失敗", + "verifying": "[MISSING:zh-TW] 验证中...", + "walletName": "錢包名稱", + "walletNamePlaceholder": "請輸入錢包名稱" + }, + "empty": "暫無錢包", + "emptyHint": "點擊上方按鈕創建或匯入錢包", "enterOrPasteTheWalletAddress": "Enter or paste the wallet address", "enterTheAddressOf_{chain}": "請輸入 地址", "enterWallet": "進入錢包", @@ -64,6 +104,7 @@ "frozenAddressesCannotBeSet": "該地址已凍結,無法設置鏈上交易密碼", "genesisaddress": "創世地址", "ifItIsNotBackedUpTheWalletCannotBeRestoredAndAssetLossMayResult": "若未完成助記詞備份,將無法恢復錢包,同時可能造成資產損失。", + "importDesc": "使用助記詞或密鑰導入已有錢包", "importTheAccountWithThePrivateKey": "使用私鑰來導入錢包", "importTheWalletOfTheAddressAndThePerformTheSigningOperation": "請先導入關聯錢包地址,再進行簽名操作", "importWallet": "導入錢包", @@ -79,44 +120,6 @@ "title": "錢包管理", "viewDetail": "查看詳情" }, - "chainSelector": { - "default": "預設", - "noChains": "暫無可用鏈", - "selectChain": "選擇鏈", - "selectAddress": "選擇地址", - "noAddresses": "該鏈暫無地址" - }, - "editSheet": { - "title": "錢包設定", - "renameTitle": "重命名錢包", - "rename": "重命名", - "renameDesc": "修改錢包名稱", - "delete": "刪除錢包", - "deleteDesc": "此操作無法撤銷", - "walletName": "錢包名稱", - "walletNamePlaceholder": "請輸入錢包名稱", - "save": "儲存", - "cancel": "取消", - "deleteTitle": "刪除錢包", - "deleteWarning": "⚠️ 此操作無法撤銷\n\n請輸入密碼以確認刪除錢包 \"{{name}}\"", - "passwordError": "密碼錯誤", - "verifyFailed": "驗證失敗" - }, - "detail": { - "title": "錢包詳情", - "notFound": "錢包不存在", - "createdAt": "建立於 {{date}}", - "chainAddresses": "鏈地址", - "editName": "編輯錢包名稱", - "exportMnemonic": "匯出助記詞", - "deleteWallet": "刪除錢包", - "exportDeveloping": "助記詞匯出功能開發中", - "walletDeleted": "錢包已刪除", - "verifyToExport": "驗證身份以匯出助記詞", - "verifyToDelete": "驗證身份以刪除錢包", - "verifyFailed": "驗證失敗", - "securityWarning": "匯出助記詞需要驗證密碼,請確保在安全環境下操作" - }, "manageIdentityWallet": "管理身份錢包", "manageIdentityWallets": "管理身份錢包", "manageWallet": "管理錢包", From 0ace2ce693bc975d92c58943f149917f140889c1 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Mon, 22 Dec 2025 13:33:27 +0800 Subject: [PATCH 6/6] fix: use spawnSync for proper argument handling in e2e script --- scripts/e2e.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/scripts/e2e.ts b/scripts/e2e.ts index 6b974d3c3..952209618 100644 --- a/scripts/e2e.ts +++ b/scripts/e2e.ts @@ -16,8 +16,8 @@ */ import { readdirSync } from 'node:fs' -import { join, resolve, basename } from 'node:path' -import { execSync } from 'node:child_process' +import { join, resolve } from 'node:path' +import { spawnSync } from 'node:child_process' const ROOT = resolve(import.meta.dirname, '..') const E2E_DIR = join(ROOT, 'e2e') @@ -70,10 +70,12 @@ function main() { // 如果有 --all 参数,运行所有测试 if (args.includes('--all')) { const otherArgs = args.filter((a) => a !== '--all') - const cmd = ['playwright', 'test', ...otherArgs].join(' ') console.log(`${colors.cyan}运行所有 E2E 测试...${colors.reset}\n`) - execSync(cmd, { stdio: 'inherit', cwd: ROOT }) - return + const result = spawnSync('playwright', ['test', ...otherArgs], { + stdio: 'inherit', + cwd: ROOT, + }) + process.exit(result.status ?? 1) } // 分离 spec 名称和 playwright 参数 @@ -153,10 +155,13 @@ function main() { // 构建 playwright 命令 const specFiles = specNames.map((s) => `e2e/${s}.spec.ts`) - const cmd = ['playwright', 'test', ...specFiles, ...playwrightArgs].join(' ') console.log(`${colors.cyan}运行 E2E 测试: ${specNames.join(', ')}${colors.reset}\n`) - execSync(cmd, { stdio: 'inherit', cwd: ROOT }) + const result = spawnSync('playwright', ['test', ...specFiles, ...playwrightArgs], { + stdio: 'inherit', + cwd: ROOT, + }) + process.exit(result.status ?? 1) } main()