From d761ed2b805e8da410e00252ad542bd24bc0df85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E5=AD=A6=E4=B9=A0=E5=B0=8F=E8=83=BD?= =?UTF-8?q?=E6=89=8B?= Date: Thu, 16 Jul 2026 01:03:06 +0800 Subject: [PATCH] feat: add Simplified Chinese localization --- apps/chrome-extension/camera-permission.html | 4 +- apps/chrome-extension/camera-preview.html | 4 +- apps/chrome-extension/e2e/overlay-ui.spec.ts | 4 +- apps/chrome-extension/how-it-works.html | 37 +- apps/chrome-extension/offscreen.html | 4 +- apps/chrome-extension/options.html | 4 +- apps/chrome-extension/popup-window.html | 4 +- apps/chrome-extension/popup.html | 4 +- apps/chrome-extension/public/manifest.json | 6 +- .../src/background/service-worker.ts | 49 +-- .../src/content/confirm-overlay.tsx | 16 +- .../src/content/countdown-overlay.tsx | 4 +- .../src/content/drawing-overlay.tsx | 34 +- apps/chrome-extension/src/content/overlay.tsx | 44 +- .../src/content/recording-bar.tsx | 26 +- .../src/offscreen/recorder.ts | 26 +- apps/chrome-extension/src/options/main.tsx | 87 ++-- .../src/permission/camera-permission.tsx | 42 +- .../src/popup/components/camera-selector.tsx | 19 +- .../src/popup/components/cog-icon.tsx | 2 +- .../src/popup/components/dashboard-button.tsx | 2 +- .../components/device-select-overlay.tsx | 2 +- .../popup/components/how-it-works-button.tsx | 2 +- .../popup/components/microphone-selector.tsx | 19 +- .../src/popup/components/recorder-header.tsx | 10 +- .../src/popup/components/recording-bar.tsx | 12 +- .../src/popup/components/recording-button.tsx | 6 +- .../components/recording-mode-selector.tsx | 18 +- .../src/popup/components/settings-button.tsx | 2 +- .../src/popup/components/sign-in-view.tsx | 14 +- .../popup/components/system-audio-toggle.tsx | 8 +- apps/chrome-extension/src/popup/main.tsx | 10 +- .../src/preview/camera-preview.tsx | 21 +- apps/chrome-extension/src/shared/api.ts | 12 +- apps/chrome-extension/src/shared/devices.ts | 4 +- apps/chrome-extension/src/shared/page-nav.ts | 12 +- apps/chrome-extension/src/shared/runtime.ts | 2 +- apps/chrome-extension/src/uploading/main.ts | 50 +-- apps/chrome-extension/uploading.html | 17 +- apps/chrome-extension/welcome.html | 30 +- apps/desktop/src-tauri/src/captions.rs | 12 +- apps/desktop/src-tauri/src/export.rs | 8 +- apps/desktop/src-tauri/src/lib.rs | 100 ++--- apps/desktop/src-tauri/src/notifications.rs | 38 +- apps/desktop/src-tauri/src/recording.rs | 44 +- .../src-tauri/src/screenshot_editor.rs | 4 +- apps/desktop/src-tauri/src/tray.rs | 68 +-- apps/desktop/src-tauri/src/windows.rs | 26 +- .../src/components/CameraPreviewChrome.tsx | 6 +- apps/desktop/src/components/Cropper.tsx | 6 +- apps/desktop/src/components/Mode.tsx | 17 +- apps/desktop/src/components/ModeSelect.tsx | 12 +- apps/desktop/src/components/RecoveryToast.tsx | 19 +- apps/desktop/src/components/SignInButton.tsx | 2 +- .../src/components/callback.template.ts | 6 +- .../desktop/src/components/selection-hint.tsx | 2 +- apps/desktop/src/entry-server.tsx | 2 +- .../(window-chrome)/new-main/CameraSelect.tsx | 14 +- .../new-main/ChangeLogButton.tsx | 2 +- .../new-main/DeviceSelectOverlay.tsx | 8 +- .../new-main/MicrophoneSelect.tsx | 6 +- .../new-main/ModeInfoPanel.tsx | 18 +- .../(window-chrome)/new-main/SystemAudio.tsx | 8 +- .../(window-chrome)/new-main/TargetCard.tsx | 46 +- .../new-main/TargetMenuGrid.tsx | 20 +- .../new-main/TargetSelectInfoPill.tsx | 6 +- .../routes/(window-chrome)/new-main/index.tsx | 134 +++--- .../src/routes/(window-chrome)/onboarding.tsx | 218 +++++----- .../src/routes/(window-chrome)/settings.tsx | 70 ++- .../(window-chrome)/settings/Setting.tsx | 2 +- .../(window-chrome)/settings/automations.tsx | 285 ++++++------ .../(window-chrome)/settings/changelog.tsx | 8 +- .../routes/(window-chrome)/settings/cli.tsx | 56 ++- .../(window-chrome)/settings/experimental.tsx | 14 +- .../(window-chrome)/settings/feedback.tsx | 41 +- .../(window-chrome)/settings/general.tsx | 296 ++++++------- .../(window-chrome)/settings/hotkeys.tsx | 34 +- .../settings/integrations/config-header.tsx | 2 +- .../integrations/google-drive-config.tsx | 63 ++- .../settings/integrations/index.tsx | 16 +- .../settings/integrations/s3-config.tsx | 62 ++- .../(window-chrome)/settings/license.tsx | 48 +-- .../(window-chrome)/settings/recordings.tsx | 60 ++- .../(window-chrome)/settings/screenshots.tsx | 38 +- .../settings/transcription.tsx | 27 +- .../src/routes/(window-chrome)/update.tsx | 21 +- .../src/routes/(window-chrome)/upgrade.tsx | 81 ++-- apps/desktop/src/routes/camera.tsx | 8 +- apps/desktop/src/routes/capture-area.tsx | 10 +- apps/desktop/src/routes/debug.tsx | 34 +- .../src/routes/editor/AspectRatioSelect.tsx | 6 +- .../src/routes/editor/AudioLibrary.tsx | 26 +- .../src/routes/editor/BrandColorsDropdown.tsx | 2 +- .../routes/editor/CanvasElementsOverlay.tsx | 12 +- .../routes/editor/CaptionsRegenerateBadge.tsx | 12 +- .../desktop/src/routes/editor/CaptionsTab.tsx | 196 ++++----- .../src/routes/editor/ClipsSidebar.tsx | 66 ++- .../src/routes/editor/ConfigSidebar.tsx | 408 +++++++++--------- apps/desktop/src/routes/editor/Editor.tsx | 62 ++- .../src/routes/editor/EditorErrorScreen.tsx | 25 +- apps/desktop/src/routes/editor/ExportPage.tsx | 178 ++++---- .../desktop/src/routes/editor/FrameButton.tsx | 32 +- .../src/routes/editor/GradientEditor.tsx | 12 +- apps/desktop/src/routes/editor/Header.tsx | 17 +- .../src/routes/editor/ImportProgress.tsx | 26 +- .../desktop/src/routes/editor/KeyboardTab.tsx | 65 ++- .../routes/editor/OrganizationDropdown.tsx | 50 ++- .../src/routes/editor/PerformanceOverlay.tsx | 22 +- apps/desktop/src/routes/editor/Player.tsx | 30 +- .../src/routes/editor/PresetsDropdown.tsx | 22 +- .../src/routes/editor/ShadowSettings.tsx | 8 +- .../desktop/src/routes/editor/ShareButton.tsx | 32 +- .../desktop/src/routes/editor/TextOverlay.tsx | 4 +- .../src/routes/editor/Timeline/AudioTrack.tsx | 12 +- .../routes/editor/Timeline/CaptionsTrack.tsx | 6 +- .../src/routes/editor/Timeline/ClipTrack.tsx | 2 +- .../routes/editor/Timeline/KeyboardTrack.tsx | 4 +- .../src/routes/editor/Timeline/MaskTrack.tsx | 6 +- .../src/routes/editor/Timeline/SceneTrack.tsx | 14 +- .../src/routes/editor/Timeline/TextTrack.tsx | 6 +- .../routes/editor/Timeline/TrackManager.tsx | 26 +- .../src/routes/editor/Timeline/ZoomTrack.tsx | 14 +- .../src/routes/editor/Timeline/index.tsx | 52 ++- .../src/routes/editor/TranscriptPage.tsx | 20 +- apps/desktop/src/routes/editor/captions.ts | 10 +- apps/desktop/src/routes/editor/context.ts | 2 +- apps/desktop/src/routes/editor/text-style.tsx | 50 +-- apps/desktop/src/routes/editor/ui.tsx | 6 +- .../src/routes/in-progress-recording.tsx | 85 ++-- apps/desktop/src/routes/mode-select.tsx | 8 +- .../desktop/src/routes/recordings-overlay.tsx | 66 ++- .../screenshot-editor/AnnotationConfig.tsx | 25 +- .../screenshot-editor/AnnotationLayer.tsx | 2 +- .../screenshot-editor/AnnotationTools.tsx | 14 +- .../src/routes/screenshot-editor/Editor.tsx | 12 +- .../src/routes/screenshot-editor/Header.tsx | 26 +- .../routes/screenshot-editor/LayersPanel.tsx | 20 +- .../src/routes/screenshot-editor/Preview.tsx | 10 +- .../src/routes/screenshot-editor/context.tsx | 2 +- .../popovers/AnnotationPopover.tsx | 18 +- .../popovers/AspectRatioSelect.tsx | 6 +- .../popovers/BackgroundSettingsPopover.tsx | 33 +- .../popovers/BorderPopover.tsx | 13 +- .../popovers/PaddingPopover.tsx | 4 +- .../popovers/RoundingPopover.tsx | 10 +- .../popovers/ShadowPopover.tsx | 4 +- .../popovers/ShadowSettings.tsx | 8 +- .../screenshot-editor/screenshotExport.ts | 14 +- .../src/routes/screenshot-editor/ui.tsx | 6 +- .../screenshot-editor/useScreenshotExport.ts | 29 +- .../src/routes/target-select-overlay.tsx | 69 ++- apps/desktop/src/routes/teleprompter.tsx | 32 +- apps/desktop/src/store/captions.ts | 22 +- apps/desktop/src/utils/auth.ts | 4 +- apps/desktop/src/utils/automations.ts | 54 +-- apps/desktop/src/utils/createPresets.ts | 2 +- apps/desktop/src/utils/export.ts | 2 +- apps/desktop/src/utils/frame-worker.ts | 4 +- apps/desktop/src/utils/general-settings.ts | 2 +- apps/desktop/src/utils/importMedia.ts | 15 +- .../src/utils/organization-branding.ts | 2 +- apps/desktop/src/utils/recording.ts | 20 +- apps/desktop/src/utils/teleprompter.ts | 2 +- apps/desktop/src/utils/web-api.ts | 2 +- .../__tests__/unit/developer-actions.test.ts | 52 ++- .../__tests__/unit/platform-downloads.test.ts | 4 +- .../__tests__/unit/save-video-edits.test.ts | 12 +- .../unit/upload-progress-playback.test.ts | 12 +- .../unit/video-speed-controller-page.test.ts | 2 +- apps/web/actions/collections/password.ts | 10 +- apps/web/actions/developers/add-domain.ts | 8 +- apps/web/actions/developers/create-app.ts | 4 +- apps/web/actions/developers/delete-app.ts | 4 +- apps/web/actions/developers/delete-video.ts | 4 +- .../web/actions/developers/regenerate-keys.ts | 4 +- apps/web/actions/developers/remove-domain.ts | 4 +- apps/web/actions/developers/update-app.ts | 6 +- .../actions/developers/update-auto-topup.ts | 10 +- apps/web/actions/send-download-link.ts | 8 +- apps/web/actions/videos/password.ts | 18 +- apps/web/actions/videos/save-edits.ts | 36 +- .../docs/_components/DocsBreadcrumbs.tsx | 2 +- .../(docs)/docs/_components/DocsHeader.tsx | 8 +- .../docs/_components/DocsMobileMenu.tsx | 8 +- .../(docs)/docs/_components/DocsSearch.tsx | 16 +- apps/web/app/(org)/auth-email.ts | 8 +- .../_components/AnimatedIcons/Refer.tsx | 2 +- .../_components/CollectionShareControl.tsx | 16 +- .../_components/CollectionShareDialog.tsx | 68 +-- .../dashboard/_components/Navbar/CapAIBox.tsx | 4 +- .../_components/Navbar/CapAIDialog.tsx | 21 +- .../_components/Navbar/DashboardSearch.tsx | 107 +++-- .../dashboard/_components/Navbar/Desktop.tsx | 4 +- .../dashboard/_components/Navbar/Items.tsx | 44 +- .../_components/Navbar/MemberAvatars.tsx | 2 +- .../dashboard/_components/Navbar/Mobile.tsx | 2 +- .../_components/Navbar/SpaceDialog.tsx | 108 +++-- .../_components/Navbar/SpacesList.tsx | 40 +- .../dashboard/_components/Navbar/Top.tsx | 65 ++- .../dashboard/_components/Navbar/server.ts | 12 +- .../_components/Notifications/Filter.ts | 10 +- .../Notifications/NotificationFooter.tsx | 4 +- .../Notifications/NotificationHeader.tsx | 8 +- .../_components/Notifications/index.tsx | 10 +- .../_components/PublicCollectionField.tsx | 9 +- .../components/AnalyticsDashboard.tsx | 34 +- .../analytics/components/ChartArea.tsx | 18 +- .../dashboard/analytics/components/Header.tsx | 30 +- .../analytics/components/OtherStats.tsx | 53 ++- .../analytics/components/StatsChart.tsx | 10 +- .../analytics/components/TableCard.tsx | 10 +- .../analytics/components/VideoComponents.tsx | 2 +- .../analytics/components/VideoFilters.tsx | 2 +- .../analytics/components/VideosPicker.tsx | 4 +- apps/web/app/(org)/dashboard/caps/Caps.tsx | 40 +- .../caps/components/CapCard/CapCard.tsx | 64 +-- .../components/CapCard/CapCardAnalytics.tsx | 8 +- .../components/CapCard/CapCardContent.tsx | 25 +- .../caps/components/EmptyCapState.tsx | 12 +- .../dashboard/caps/components/Folder.tsx | 32 +- .../caps/components/FoldersDropdown.tsx | 8 +- .../caps/components/ImportLoomButton.tsx | 20 +- .../caps/components/NewFolderDialog.tsx | 20 +- .../caps/components/PasswordDialog.tsx | 12 +- .../caps/components/SelectedCapsBar.tsx | 16 +- .../caps/components/SettingsDialog.tsx | 51 ++- .../caps/components/SharingDialog.tsx | 101 ++--- .../caps/components/UploadCapButton.tsx | 2 +- .../caps/components/UploadPlaceholderCard.tsx | 12 +- .../CameraPreviewWindow.tsx | 8 +- .../web-recorder-dialog/CameraSelector.tsx | 12 +- .../web-recorder-dialog/HowItWorksButton.tsx | 2 +- .../web-recorder-dialog/HowItWorksPanel.tsx | 19 +- .../InProgressRecordingBar.tsx | 68 ++- .../MicrophoneSelector.tsx | 14 +- .../web-recorder-dialog/RecordingButton.tsx | 4 +- .../RecordingModeSelector.tsx | 21 +- .../web-recorder-dialog/SettingsButton.tsx | 2 +- .../web-recorder-dialog/SettingsPanel.tsx | 13 +- .../web-recorder-dialog/SystemAudioToggle.tsx | 8 +- .../web-recorder-dialog/useWebRecorder.ts | 102 ++--- .../web-recorder-dialog-header.tsx | 6 +- .../web-recorder-dialog.tsx | 24 +- apps/web/app/(org)/dashboard/caps/page.tsx | 2 +- .../dashboard/caps/record/RecordVideoPage.tsx | 34 +- .../app/(org)/dashboard/caps/record/page.tsx | 2 +- .../developers/_components/ApiKeyDisplay.tsx | 4 +- .../developers/_components/AppCard.tsx | 6 +- .../_components/CreateAppDialog.tsx | 30 +- .../_components/CreditTransactionTable.tsx | 24 +- .../_components/DeveloperSidebarContent.tsx | 14 +- .../developers/_components/DomainRow.tsx | 5 +- .../_components/EnvironmentBadge.tsx | 2 +- .../developers/apps/AppsListClient.tsx | 10 +- .../apps/[appId]/api-keys/ApiKeysClient.tsx | 30 +- .../developers/apps/[appId]/api-keys/page.tsx | 2 +- .../apps/[appId]/domains/DomainsClient.tsx | 22 +- .../developers/apps/[appId]/domains/page.tsx | 2 +- .../developers/apps/[appId]/layout.tsx | 2 +- .../[appId]/settings/AppSettingsClient.tsx | 37 +- .../developers/apps/[appId]/settings/page.tsx | 2 +- .../apps/[appId]/videos/VideosClient.tsx | 29 +- .../developers/apps/[appId]/videos/page.tsx | 2 +- .../(org)/dashboard/developers/apps/page.tsx | 2 +- .../developers/credits/CreditsClient.tsx | 36 +- .../dashboard/developers/credits/page.tsx | 2 +- .../app/(org)/dashboard/developers/layout.tsx | 2 +- .../developers/usage/UsageClient.tsx | 18 +- .../(org)/dashboard/developers/usage/page.tsx | 2 +- .../folder/[id]/components/BreadcrumbItem.tsx | 4 +- .../[id]/components/ClientMyCapsLink.tsx | 10 +- .../[id]/components/FolderVideosSection.tsx | 30 +- .../[id]/components/NewSubfolderButton.tsx | 2 +- .../[id]/components/SubfolderDialog.tsx | 20 +- .../app/(org)/dashboard/folder/[id]/page.tsx | 4 +- .../app/(org)/dashboard/import/ImportPage.tsx | 10 +- .../dashboard/import/file/ImportFilePage.tsx | 20 +- .../app/(org)/dashboard/import/file/page.tsx | 2 +- .../(org)/dashboard/import/import-media.ts | 24 +- .../dashboard/import/loom/ImportLoomPage.tsx | 186 ++++---- .../app/(org)/dashboard/import/loom/page.tsx | 2 +- apps/web/app/(org)/dashboard/import/page.tsx | 2 +- apps/web/app/(org)/dashboard/refer/page.tsx | 6 +- .../dashboard/settings/account/Settings.tsx | 76 ++-- .../account/components/ProfileImage.tsx | 10 +- .../(org)/dashboard/settings/account/page.tsx | 2 +- .../dashboard/settings/account/server.ts | 9 +- .../notifications/NotificationsSettings.tsx | 25 +- .../dashboard/settings/notifications/page.tsx | 2 +- .../organization/_components/SettingsNav.tsx | 8 +- .../settings/organization/billing/page.tsx | 6 +- .../components/AccessEmailDomain.tsx | 22 +- .../components/BillingSummaryCard.tsx | 32 +- .../components/CapSettingsCard.tsx | 77 ++-- .../organization/components/CustomDomain.tsx | 28 +- .../CustomDomainDialog/CustomDomainDialog.tsx | 42 +- .../CustomDomainDialog/DomainStep.tsx | 4 +- .../CustomDomainDialog/SubscribeContent.tsx | 4 +- .../CustomDomainDialog/SuccessStep.tsx | 6 +- .../CustomDomainDialog/VerifyStep.tsx | 64 ++- .../organization/components/DeleteOrg.tsx | 8 +- .../components/DeleteOrgDialog.tsx | 18 +- .../organization/components/InviteDialog.tsx | 42 +- .../organization/components/MembersCard.tsx | 89 ++-- .../organization/components/OrgName.tsx | 11 +- .../components/OrganizationDetailsCard.tsx | 5 +- .../components/OrganizationIcon.tsx | 16 +- .../components/SeatManagementCard.tsx | 40 +- .../components/ShareableLinkIcon.tsx | 28 +- .../organization/integrations/page.tsx | 2 +- .../integrations/storage-integrations.tsx | 116 ++--- .../settings/organization/layout.tsx | 6 +- .../dashboard/settings/organization/page.tsx | 2 +- .../organization/preferences/page.tsx | 2 +- .../dashboard/spaces/[spaceId]/SharedCaps.tsx | 18 +- .../dashboard/spaces/[spaceId]/actions.ts | 32 +- .../components/AddVideosDialogBase.tsx | 55 +-- .../components/EmptySharedCapState.tsx | 10 +- .../[spaceId]/components/MemberSelect.tsx | 14 +- .../[spaceId]/components/MembersDialog.tsx | 6 +- .../[spaceId]/components/MembersIndicator.tsx | 28 +- .../components/OrganizationIndicator.tsx | 12 +- .../spaces/[spaceId]/components/VideoCard.tsx | 13 +- .../folder/[folderId]/AddVideosButton.tsx | 2 +- .../[spaceId]/folder/[folderId]/page.tsx | 6 +- .../(org)/dashboard/spaces/[spaceId]/page.tsx | 2 +- .../(org)/dashboard/spaces/browse/page.tsx | 44 +- apps/web/app/(org)/login/form.tsx | 52 ++- apps/web/app/(org)/login/page.tsx | 2 +- .../app/(org)/onboarding/components/Base.tsx | 2 +- .../(org)/onboarding/components/Bottom.tsx | 6 +- .../components/CustomDomainPage.tsx | 11 +- .../onboarding/components/DownloadPage.tsx | 14 +- .../onboarding/components/InviteTeamPage.tsx | 54 +-- .../components/OrganizationSetupPage.tsx | 23 +- .../(org)/onboarding/components/Stepper.tsx | 23 +- .../onboarding/components/WelcomePage.tsx | 14 +- apps/web/app/(org)/signup/form.tsx | 53 +-- apps/web/app/(org)/signup/page.tsx | 2 +- apps/web/app/(org)/verify-otp/form.tsx | 37 +- apps/web/app/(org)/verify-otp/page.tsx | 2 +- apps/web/app/(site)/DesktopNavLinks.tsx | 56 +-- apps/web/app/(site)/Footer.tsx | 108 +++-- apps/web/app/(site)/download/page.tsx | 2 +- .../web/app/(site)/download/versions/page.tsx | 28 +- apps/web/app/(site)/features/FeaturesPage.tsx | 194 ++++----- .../features/instant-mode/InstantModePage.tsx | 246 +++++------ .../app/(site)/features/instant-mode/page.tsx | 16 +- apps/web/app/(site)/features/page.tsx | 4 +- .../features/studio-mode/StudioModePage.tsx | 245 +++++------ .../app/(site)/features/studio-mode/page.tsx | 16 +- apps/web/app/(site)/tools/PageContent.tsx | 14 +- apps/web/app/(site)/tools/convert/page.tsx | 28 +- .../app/(site)/tools/loom-downloader/page.tsx | 99 +++-- .../tools/video-speed-controller/page.tsx | 114 +++-- .../app/c/[id]/CollectionPasswordOverlay.tsx | 9 +- apps/web/app/c/[id]/page.tsx | 46 +- apps/web/app/c/error.tsx | 6 +- .../[videoId]/_components/EmbedVideo.tsx | 4 +- .../[videoId]/_components/PasswordOverlay.tsx | 11 +- apps/web/app/embed/[videoId]/page.tsx | 24 +- apps/web/app/layout.tsx | 10 +- apps/web/app/not-found.tsx | 6 +- .../s/[videoId]/_components/AuthOverlay.tsx | 33 +- .../[videoId]/_components/CapVideoPlayer.tsx | 26 +- .../[videoId]/_components/HLSVideoPlayer.tsx | 18 +- .../app/s/[videoId]/_components/OtpForm.tsx | 22 +- .../[videoId]/_components/PasswordOverlay.tsx | 11 +- .../_components/PendingRecordingShare.tsx | 6 +- .../[videoId]/_components/ProgressCircle.tsx | 22 +- .../_components/RecordingInProgress.tsx | 11 +- .../s/[videoId]/_components/ShareHeader.tsx | 51 ++- .../s/[videoId]/_components/ShareVideo.tsx | 12 +- .../app/s/[videoId]/_components/Sidebar.tsx | 6 +- .../[videoId]/_components/SummaryChapters.tsx | 6 +- .../app/s/[videoId]/_components/Toolbar.tsx | 20 +- .../_components/VideoDownloadMenu.tsx | 20 +- .../_components/tabs/Activity/Comment.tsx | 10 +- .../tabs/Activity/CommentInput.tsx | 6 +- .../_components/tabs/Activity/Comments.tsx | 6 +- .../_components/tabs/Activity/EmptyState.tsx | 6 +- .../_components/tabs/Activity/utils.ts | 16 +- .../s/[videoId]/_components/tabs/Settings.tsx | 12 +- .../s/[videoId]/_components/tabs/Summary.tsx | 35 +- .../[videoId]/_components/tabs/Transcript.tsx | 72 ++-- .../_components/video/media-player.tsx | 12 +- .../app/s/[videoId]/edit/EditVideoClient.tsx | 57 ++- apps/web/app/s/[videoId]/page.tsx | 41 +- apps/web/components/ChromeExtensionButton.tsx | 2 +- apps/web/components/FileInput.tsx | 16 +- apps/web/components/UpgradeModal.tsx | 64 +-- apps/web/components/UsageButton.tsx | 4 +- apps/web/components/forms/NewOrganization.tsx | 10 +- apps/web/components/forms/server.ts | 12 +- apps/web/components/pages/DownloadPage.tsx | 2 +- apps/web/components/pages/FaqPage.tsx | 37 +- .../components/pages/HomePage/Features.tsx | 2 +- apps/web/components/pages/HomePage/Header.tsx | 25 +- .../pages/HomePage/HomePageSchema.tsx | 26 +- .../pages/HomePage/InstantModeDetail.tsx | 97 ++--- .../pages/HomePage/Pricing/CommercialCard.tsx | 32 +- .../pages/HomePage/Pricing/EnterpriseCard.tsx | 30 +- .../pages/HomePage/Pricing/ProCard.tsx | 37 +- .../pages/HomePage/RecordingModePicker.tsx | 21 +- .../pages/HomePage/RecordingModes.tsx | 2 +- .../pages/HomePage/ScreenshotModeDetail.tsx | 60 ++- .../pages/HomePage/StudioModeDetail.tsx | 68 ++- .../pages/HomePage/Testimonials.tsx | 2 +- apps/web/components/pages/PricingPage.tsx | 4 +- .../components/pages/StudentDiscountPage.tsx | 4 +- apps/web/components/pages/SupportPage.tsx | 44 +- .../pages/_components/ComparePlans.tsx | 97 +++-- .../pages/_components/UpgradeToPro.tsx | 2 +- apps/web/components/tools/LoomDownloader.tsx | 101 ++--- .../components/tools/MediaFormatConverter.tsx | 134 +++--- apps/web/components/tools/SpeedController.tsx | 55 ++- apps/web/components/tools/TrimmingTool.tsx | 97 ++--- apps/web/components/tools/content.ts | 265 +++++------- apps/web/components/ui/MobileMenu.tsx | 36 +- apps/web/data/homepage-copy.ts | 237 +++++----- apps/web/lib/permissions/roles.ts | 11 +- apps/web/lib/public-collection-settings.ts | 20 +- apps/web/utils/platform.tsx | 28 +- .../recorder-core/src/recorder-constants.ts | 4 +- packages/ui/src/components/Dialog.tsx | 2 +- packages/ui/src/components/Pagination.tsx | 12 +- 426 files changed, 5686 insertions(+), 6479 deletions(-) diff --git a/apps/chrome-extension/camera-permission.html b/apps/chrome-extension/camera-permission.html index 5451ff7bf26..d79c651602d 100644 --- a/apps/chrome-extension/camera-permission.html +++ b/apps/chrome-extension/camera-permission.html @@ -1,9 +1,9 @@ - + - Camera access - Cap + 摄像头权限 - Cap diff --git a/apps/chrome-extension/camera-preview.html b/apps/chrome-extension/camera-preview.html index ca9d94312f6..826c580577a 100644 --- a/apps/chrome-extension/camera-preview.html +++ b/apps/chrome-extension/camera-preview.html @@ -1,9 +1,9 @@ - + - Cap Camera Preview + Cap 摄像头预览 diff --git a/apps/chrome-extension/e2e/overlay-ui.spec.ts b/apps/chrome-extension/e2e/overlay-ui.spec.ts index dc4a287ee86..e6ea13702ea 100644 --- a/apps/chrome-extension/e2e/overlay-ui.spec.ts +++ b/apps/chrome-extension/e2e/overlay-ui.spec.ts @@ -347,7 +347,7 @@ test("clicking X in the panel closes the panel and the camera preview", async () const panelFrame = frameWithUrl(targetPage, "popup.html"); if (!panelFrame) throw new Error("panel frame missing"); await panelFrame - .locator('button[aria-label="Close Cap and hide all recorder UI"]') + .locator('button[aria-label="关闭 Cap 并隐藏所有录制界面"]') .click(); // The panel and the camera preview should both tear down. @@ -419,7 +419,7 @@ test("a failed recording start reopens the panel with the error", async () => { .toBe(true); const panelFrame = frameWithUrl(targetPage, "popup.html"); if (!panelFrame) throw new Error("panel frame missing"); - await expect(panelFrame.getByText("Recording failed.")).toBeVisible({ + await expect(panelFrame.getByText("录制失败。")).toBeVisible({ timeout: 10_000, }); await targetPage.screenshot({ diff --git a/apps/chrome-extension/how-it-works.html b/apps/chrome-extension/how-it-works.html index 3734907d4d1..3cfba0f84e1 100644 --- a/apps/chrome-extension/how-it-works.html +++ b/apps/chrome-extension/how-it-works.html @@ -1,9 +1,9 @@ - + - How it works - Cap + 使用说明 - Cap
@@ -81,10 +81,9 @@ > -

How Cap works

+

Cap 如何工作

- Instant Mode uploads while you record, so your share link is ready the - moment you stop. + 即时模式会在录制过程中同步上传,因此停止录制时分享链接已准备就绪。

  1. @@ -92,10 +91,9 @@

    How Cap works

    - Step 1 + 第 1 步

    - Click the Cap icon, pick a tab, window, screen or camera, and press - start. + 点击 Cap 图标,选择标签页、窗口、屏幕或摄像头,然后开始录制。

  2. @@ -110,10 +108,9 @@

    How Cap works

    d="M 18 29 L 24 23 L 30 29" > - Step 2 + 第 2 步

    - Your video streams to the cloud while you record. No exports, no - waiting at the end. + 视频会在录制过程中传输到云端,无需导出,结束后也不用等待。

  3. @@ -128,36 +125,32 @@

    How Cap works

    > - Step 3 + 第 3 步

    - Stop the recording and the share link is live instantly. Paste it - anywhere. + 停止录制后,分享链接会立即生效,可粘贴到任意位置。

-

Good to know

+

实用提示

  • - Drag the camera preview anywhere on the page, resize it, or pop it - out with Picture in Picture. + 可将摄像头预览拖到页面任意位置、调整大小,或使用画中画单独显示。
  • - Pause and resume from the floating recording bar without losing - your take. + 可通过悬浮录制栏暂停和继续,不会丢失已录内容。
  • - Click the Cap icon in your toolbar while recording to stop and jump - straight to your video. + 录制时点击工具栏中的 Cap 图标,即可停止并直接打开视频。

- Click the Cap icon in your toolbar whenever you're ready to record. + 准备好后,随时点击工具栏中的 Cap 图标开始录制。

diff --git a/apps/chrome-extension/offscreen.html b/apps/chrome-extension/offscreen.html index 07811d502c2..a7821aeee06 100644 --- a/apps/chrome-extension/offscreen.html +++ b/apps/chrome-extension/offscreen.html @@ -1,9 +1,9 @@ - + - Cap Recorder Offscreen + Cap 后台录制器 diff --git a/apps/chrome-extension/options.html b/apps/chrome-extension/options.html index 583f37990f5..39056f29e95 100644 --- a/apps/chrome-extension/options.html +++ b/apps/chrome-extension/options.html @@ -1,9 +1,9 @@ - + - Options - Cap + 设置 - Cap
diff --git a/apps/chrome-extension/popup-window.html b/apps/chrome-extension/popup-window.html index 9573af9a38b..fa4a80d84ba 100644 --- a/apps/chrome-extension/popup-window.html +++ b/apps/chrome-extension/popup-window.html @@ -1,9 +1,9 @@ - + - Cap Recorder + Cap 录制器
diff --git a/apps/chrome-extension/popup.html b/apps/chrome-extension/popup.html index 9573af9a38b..fa4a80d84ba 100644 --- a/apps/chrome-extension/popup.html +++ b/apps/chrome-extension/popup.html @@ -1,9 +1,9 @@ - + - Cap Recorder + Cap 录制器
diff --git a/apps/chrome-extension/public/manifest.json b/apps/chrome-extension/public/manifest.json index eeb058f457c..b8369c1cbae 100644 --- a/apps/chrome-extension/public/manifest.json +++ b/apps/chrome-extension/public/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 3, - "name": "Cap - Screen Recorder & Screen Capture", + "name": "Cap - 屏幕录制与截图", "short_name": "Cap", - "description": "Free, open source screen recorder. Capture your screen, tab, camera & mic in Chrome and share a video link the moment you stop.", + "description": "免费开源的屏幕录制工具。在 Chrome 中录制屏幕、标签页、摄像头和麦克风,停止录制后即可分享视频链接。", "version": "1.0.2", "homepage_url": "https://cap.so", "minimum_chrome_version": "116", @@ -13,7 +13,7 @@ "128": "icons/icon-128.png" }, "action": { - "default_title": "Record your screen with Cap", + "default_title": "使用 Cap 录制屏幕", "default_icon": { "16": "icons/icon-16.png", "32": "icons/icon-32.png", diff --git a/apps/chrome-extension/src/background/service-worker.ts b/apps/chrome-extension/src/background/service-worker.ts index 43eccb06c54..43ef67e41fe 100644 --- a/apps/chrome-extension/src/background/service-worker.ts +++ b/apps/chrome-extension/src/background/service-worker.ts @@ -146,9 +146,7 @@ const createTab = (url: string) => new Promise((resolve, reject) => { chrome.tabs.create({ url, active: true }, (tab) => { if (chrome.runtime.lastError) { - reject( - new Error(chrome.runtime.lastError.message ?? "Failed to open tab"), - ); + reject(new Error(chrome.runtime.lastError.message ?? "打开标签页失败")); return; } resolve(tab); @@ -160,9 +158,7 @@ const updateTab = (tabId: number, url: string) => chrome.tabs.update(tabId, { url, active: true }, (tab) => { if (chrome.runtime.lastError || !tab) { reject( - new Error( - chrome.runtime.lastError?.message ?? "Failed to update tab", - ), + new Error(chrome.runtime.lastError?.message ?? "更新标签页失败"), ); return; } @@ -219,7 +215,7 @@ const createOffscreenDocument = () => { url: OFFSCREEN_URL, reasons: ["USER_MEDIA", "DISPLAY_MEDIA", "BLOBS", "AUDIO_PLAYBACK"], - justification: "Record and upload Cap videos from an extension page.", + justification: "从扩展页面录制并上传 Cap 视频。", }, () => { const error = chrome.runtime.lastError; @@ -228,7 +224,7 @@ const createOffscreenDocument = () => return; } - const message = error.message ?? "Failed to create offscreen document"; + const message = error.message ?? "创建后台录制文档失败"; if (message.toLowerCase().includes("single offscreen document")) { resolve(); return; @@ -267,7 +263,7 @@ const sendOffscreenRuntimeMessage = (message: OffscreenRequest) => new Promise((resolve, reject) => { chrome.runtime.sendMessage(message, (response) => { if (chrome.runtime.lastError) { - reject(new Error(chrome.runtime.lastError.message ?? "Message failed")); + reject(new Error(chrome.runtime.lastError.message ?? "消息发送失败")); return; } resolve(response as OffscreenResponse); @@ -312,11 +308,7 @@ const getTabStreamId = (tabId: number) => new Promise((resolve, reject) => { chrome.tabCapture.getMediaStreamId({ targetTabId: tabId }, (streamId) => { if (chrome.runtime.lastError) { - reject( - new Error( - chrome.runtime.lastError.message ?? "Failed to capture tab", - ), - ); + reject(new Error(chrome.runtime.lastError.message ?? "录制标签页失败")); return; } resolve(streamId); @@ -596,9 +588,7 @@ const updateActionForStatus = (nextStatus: RecordingStatus) => { // The recorder renders inside the page, so the action never opens a popup. setActionPopup(""), setActionBadgeText(isCapturing ? "REC" : ""), - setActionTitle( - isCapturing ? "Stop Cap recording" : "Record your screen with Cap", - ), + setActionTitle(isCapturing ? "停止 Cap 录制" : "使用 Cap 录制屏幕"), ]).then(() => undefined); }; @@ -849,7 +839,7 @@ const waitForWebcamPreviewReady = (tabId: number) => { previewReadyWaiters, tabId, START_PREVIEW_READY_TIMEOUT_MS, - "Camera preview did not become ready before recording started.", + "开始录制前摄像头预览未准备就绪。", ); }; @@ -1133,7 +1123,7 @@ const loadSignedInState = async () => { const requireSignedInState = async () => { const state = await loadSignedInState(); if (!state.auth || !state.bootstrap) { - throw new Error("Sign in to Cap first"); + throw new Error("请先登录 Cap"); } return state as { settings: ExtensionSettings; @@ -1230,7 +1220,7 @@ const startRecording = async (mode: RecordingMode) => { await saveSettings(recordingSettings); } if (mode === "camera" && !recordingSettings.webcam.deviceId) { - throw new Error("Select a camera before recording."); + throw new Error("请先选择摄像头再开始录制。"); } if (isWebcamPreviewEnabled(recordingSettings)) { await saveWebcamPreviewDismissed(false); @@ -1249,7 +1239,7 @@ const startRecording = async (mode: RecordingMode) => { return { ok: false, canceled: true, - error: "Recording canceled", + error: "录制已取消", } satisfies OffscreenResponse; } } @@ -1396,10 +1386,7 @@ const launchWebAuthFlow = (url: string) => (responseUrl) => { if (chrome.runtime.lastError || !responseUrl) { reject( - new Error( - chrome.runtime.lastError?.message ?? - "The sign-in window was closed", - ), + new Error(chrome.runtime.lastError?.message ?? "登录窗口已关闭"), ); return; } @@ -1492,7 +1479,7 @@ const handlePreviewError = async ( settleTabWaiters( previewReadyWaiters, tabId, - new Error("Camera preview did not become ready."), + new Error("摄像头预览未准备就绪。"), ); const fallbackTabId = @@ -1552,7 +1539,7 @@ const handleRequest = async ( const status = error instanceof ApiRequestError ? error.status : null; if (status === null || status >= 500) { throw new Error( - "Could not reach Cap to revoke this sign-in. Check your connection and try again.", + "无法连接 Cap 以撤销本次登录,请检查网络连接后重试。", ); } } @@ -1741,7 +1728,7 @@ const handleRequest = async ( // excluded so a web-accessible page embedded by a hostile site cannot // authorise itself. if (!isWebPageSender(sender)) { - return { ok: false, error: "Unauthorized" }; + return { ok: false, error: "未授权" }; } await registerOverlayToken(message.token); return { ok: true }; @@ -1757,7 +1744,7 @@ const handleRequest = async ( message.sessionId, ); if (!allowed) { - return { ok: false, error: "Camera preview is not authorized." }; + return { ok: false, error: "摄像头预览未获授权。" }; } const response = await sendOffscreen({ target: "offscreen", @@ -1789,7 +1776,7 @@ const handleRequest = async ( tabId === undefined || !(await isCameraPreviewEventAllowed(sender, message.token)) ) { - return { ok: false, error: "Unauthorized" }; + return { ok: false, error: "未授权" }; } chrome.tabs.sendMessage( tabId, @@ -1840,7 +1827,7 @@ const handleRequest = async ( return { ok: true }; } - return { ok: false, error: "Unknown request" }; + return { ok: false, error: "未知请求" }; }; chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => { diff --git a/apps/chrome-extension/src/content/confirm-overlay.tsx b/apps/chrome-extension/src/content/confirm-overlay.tsx index 08eb8da28dd..314c21c4cee 100644 --- a/apps/chrome-extension/src/content/confirm-overlay.tsx +++ b/apps/chrome-extension/src/content/confirm-overlay.tsx @@ -14,14 +14,12 @@ const COPY: Record< { title: string; message: string } > = { "no-mic": { - title: "Record without a microphone?", - message: - "No microphone is selected, so this recording won't capture your voice.", + title: "不使用麦克风录制?", + message: "尚未选择麦克风,本次录制将无法采集你的声音。", }, "no-sound": { - title: "No sound from your microphone", - message: - "We're not detecting any audio from the selected microphone. It may be muted or unplugged.", + title: "麦克风没有声音", + message: "未检测到所选麦克风的声音,它可能已静音或未连接。", }, }; @@ -98,7 +96,7 @@ export function ConfirmOverlay() { diff --git a/apps/chrome-extension/src/content/countdown-overlay.tsx b/apps/chrome-extension/src/content/countdown-overlay.tsx index 11cd3bb5180..2bcea6dde06 100644 --- a/apps/chrome-extension/src/content/countdown-overlay.tsx +++ b/apps/chrome-extension/src/content/countdown-overlay.tsx @@ -128,7 +128,7 @@ export function CountdownOverlay() { onPointerDown={(event) => event.stopPropagation()} > - {`Recording starts in ${value}`} + {`将在 ${value} 秒后开始录制`}
- Press Esc to cancel + 按 Esc 取消 ); } diff --git a/apps/chrome-extension/src/content/drawing-overlay.tsx b/apps/chrome-extension/src/content/drawing-overlay.tsx index aac1bae30ae..e5791706d59 100644 --- a/apps/chrome-extension/src/content/drawing-overlay.tsx +++ b/apps/chrome-extension/src/content/drawing-overlay.tsx @@ -10,19 +10,19 @@ import { // A bright, presentation-friendly palette: the warm/cool brights read well on // light pages and white covers dark slides. Red is the default ink. const DRAW_COLORS = [ - { name: "Red", value: "#ef4444" }, - { name: "Yellow", value: "#facc15" }, - { name: "Green", value: "#22c55e" }, - { name: "Blue", value: "#3b82f6" }, - { name: "White", value: "#ffffff" }, + { name: "红色", value: "#ef4444" }, + { name: "黄色", value: "#facc15" }, + { name: "绿色", value: "#22c55e" }, + { name: "蓝色", value: "#3b82f6" }, + { name: "白色", value: "#ffffff" }, ] as const; // Stroke width in CSS pixels paired with the diameter of the dot shown in the // toolbar, so the picker previews roughly what the brush draws. const BRUSH_SIZES = [ - { name: "Small", value: 4, dot: 6 }, - { name: "Medium", value: 9, dot: 10 }, - { name: "Large", value: 16, dot: 15 }, + { name: "细", value: 4, dot: 6 }, + { name: "中", value: 9, dot: 10 }, + { name: "粗", value: 16, dot: 15 }, ] as const; const DEFAULT_COLOR = DRAW_COLORS[0].value; @@ -259,7 +259,7 @@ export function DrawingOverlay({ active, onClose }: DrawingOverlayProps) {
{DRAW_COLORS.map((swatch) => ( @@ -290,7 +290,7 @@ export function DrawingOverlay({ active, onClose }: DrawingOverlayProps) { )} aria-label={brush.name} aria-pressed={size === brush.value} - title={`${brush.name} brush`} + title={`${brush.name}画笔`} onClick={() => setSize(brush.value)} > @@ -322,8 +322,8 @@ export function DrawingOverlay({ active, onClose }: DrawingOverlayProps) {