- 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.
+ 即时模式会在录制过程中同步上传,因此停止录制时分享链接已准备就绪。
@@ -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 图标,选择标签页、窗口、屏幕或摄像头,然后开始录制。
@@ -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.
+ 视频会在录制过程中传输到云端,无需导出,结束后也不用等待。
@@ -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() {