Files
CamTalk/frontend/src/components/MicManager/index.tsx
cfy666 e95b1603c1 feat: 前端 UI 国际化,支持中/英/日三语切换
之前语言设置只影响后端 AI 行为,前端 UI 文字始终为中文。
新增轻量 i18n 模块(React Context + 翻译字典),切换语言后所有 UI 文字即时刷新。

- 新增 i18n 核心模块和 zh-CN/en-US/ja-JP 翻译文件(约 72 个 key)
- App.tsx 拆分为 App(Provider)+ AppContent(业务),确保 Hook 可访问 Context
- 所有组件通过 useI18n().t() 获取翻译文本
- errors.ts 改为接受翻译函数参数
- storage.ts saveConfig 时派发事件通知 locale 变化
2026-06-14 14:34:30 +08:00

54 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ============================================================
// MicManager — 麦克风音频采集
// 职责:获取麦克风 MediaStream供 VAD 和音频录制使用
// ============================================================
import { useCallback, useRef, useState } from "react";
import { useI18n } from "../../lib/i18n";
export function useMicrophone() {
const { t } = useI18n();
const [stream, setStream] = useState<MediaStream | null>(null);
const [error, setError] = useState<string | null>(null);
const audioContextRef = useRef<AudioContext | null>(null);
const startMic = useCallback(async () => {
try {
const mediaStream = await navigator.mediaDevices.getUserMedia({
audio: {
sampleRate: 16000,
channelCount: 1,
echoCancellation: true,
noiseSuppression: true,
},
video: false,
});
setStream(mediaStream);
setError(null);
return mediaStream;
} catch (err) {
const message = err instanceof Error ? err.message : t("error.micAccess");
setError(message);
console.error("[Mic] 获取麦克风失败:", err);
return null;
}
}, []);
const stopMic = useCallback(() => {
stream?.getTracks().forEach((track) => track.stop());
setStream(null);
audioContextRef.current?.close();
audioContextRef.current = null;
}, [stream]);
/** 获取或创建 AudioContext */
const getAudioContext = useCallback((): AudioContext => {
if (!audioContextRef.current) {
audioContextRef.current = new AudioContext({ sampleRate: 16000 });
}
return audioContextRef.current;
}, []);
return { stream, error, startMic, stopMic, getAudioContext };
}