From cc101012d99bf3a8e320d3bde9964514b4f65814 Mon Sep 17 00:00:00 2001 From: 619dev <86543624+619dev@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:17:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84i18n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/GroupCallOverlay.tsx | 45 ++++++++++++---------- client/src/hooks/useGroupCall.ts | 14 ++++--- client/src/i18n/locales/de.ts | 5 +++ client/src/i18n/locales/en.ts | 25 ++++++++++++ client/src/i18n/locales/es.ts | 5 +++ client/src/i18n/locales/fr.ts | 5 +++ client/src/i18n/locales/ja.ts | 6 +++ client/src/i18n/locales/ko.ts | 5 +++ client/src/i18n/locales/ru.ts | 5 +++ client/src/i18n/locales/zh.ts | 25 ++++++++++++ 10 files changed, 114 insertions(+), 26 deletions(-) diff --git a/client/src/components/GroupCallOverlay.tsx b/client/src/components/GroupCallOverlay.tsx index fad3397..72f6c6c 100644 --- a/client/src/components/GroupCallOverlay.tsx +++ b/client/src/components/GroupCallOverlay.tsx @@ -2,26 +2,28 @@ import { useEffect, useRef, useState } from 'react' import { CameraOff, ChevronLeft, LayoutGrid, Mic, MicOff, PhoneIncoming, PhoneOff, Presentation, Users, Video } from 'lucide-react' import { formatDuration, useGroupCallContext } from '../contexts/GroupCallContext' import { useStore } from '../store' +import { useI18n } from '../hooks/useI18n' export default function GroupCallOverlay() { const gc = useGroupCallContext() + const { t } = useI18n() const groups = useStore(s => s.groups) const [showPeople, setShowPeople] = useState(false) if (gc.status === 'idle') return gc.error ? : null const group = groups.find(g => g.id === gc.groupId) const participants = Array.from(gc.peers.values()) - const title = gc.groupName || group?.name || '群视频会议' + const title = gc.groupName || group?.name || t(gc.isVideo ? 'meeting.video_title' : 'meeting.voice_title') if (gc.status === 'ringing') return (

{title}

-

{gc.inviterName} 邀请你加入{gc.isVideo ? '视频' : '语音'}会议

+

{gc.inviterName} {t('meeting.invites_you')} {t(gc.isVideo ? 'meeting.video' : 'meeting.voice')}

- - + +
@@ -30,12 +32,12 @@ export default function GroupCallOverlay() { return (
- +
{title}
- {gc.status === 'connecting' ? '正在进入会议…' : `${formatDuration(gc.duration)} · ${participants.length + 1}/${gc.maxParticipants} 人`} - {gc.meetingMode === 'lecture' && ' · 讲课模式'} + {gc.status === 'connecting' ? t('meeting.joining') : `${formatDuration(gc.duration)} · ${participants.length + 1}/${gc.maxParticipants} ${t('meeting.people_unit')}`} + {gc.meetingMode === 'lecture' && ` · ${t('meeting.lecture_mode')}`}
@@ -49,24 +51,25 @@ export default function GroupCallOverlay() {
- + {gc.isMuted ? : } - {gc.isVideo && + {gc.isVideo && {gc.isCameraOff ? : } - {gc.isHost && } - {gc.isHost && } + {gc.isHost && gc.setMeetingMode(gc.meetingMode === 'lecture' ? 'discussion' : 'lecture')}>} - +
) } function VideoStage({ gc, participants }: { gc: ReturnType; participants: any[] }) { + const { t } = useI18n() const user = useStore(s => s.user) - const tiles = [{ peerId: user?.id || 'local', nickname: `${user?.nickname || '我'}(我)`, stream: gc.localStream, + const tiles = [{ peerId: user?.id || 'local', nickname: `${user?.nickname || t('meeting.me')} (${t('meeting.me')})`, stream: gc.localStream, isMuted: gc.isMuted, isCameraOff: gc.isCameraOff, isHost: gc.isHost }, ...participants] const visible = gc.meetingMode === 'lecture' ? [...tiles].sort((a, b) => Number(b.isHost) - Number(a.isHost)).slice(0, 6) @@ -76,33 +79,35 @@ function VideoStage({ gc, participants }: { gc: ReturnType {visible.map(p => )} - {tiles.length > visible.length &&
另有 {tiles.length - visible.length} 人
} + {tiles.length > visible.length &&
{t('meeting.more_people')} {tiles.length - visible.length}
} ) } function ParticipantTile({ participant: p }: { participant: any }) { + const { t } = useI18n() const ref = useRef(null) useEffect(() => { if (ref.current) ref.current.srcObject = p.stream }, [p.stream]) const hasVideo = p.stream?.getVideoTracks().some((t: MediaStreamTrack) => t.enabled && t.readyState === 'live') && !p.isCameraOff return (
-
) } function PeoplePanel({ gc, participants }: { gc: ReturnType; participants: any[] }) { + const { t } = useI18n() const user = useStore(s => s.user) return } @@ -119,7 +124,7 @@ function Control({ label, children, onClick, active, danger, disabled }: any) { } function RoundButton({ label, color, onClick, children }: any) { return } -function MeetingError({ message, onClose }: { message: string; onClose: () => void }) { return
{message}
} +function MeetingError({ message, onClose }: { message: string; onClose: () => void }) { const { t } = useI18n(); return
{message}
} const shellStyle: React.CSSProperties = { position: 'fixed', inset: 0, zIndex: 10000, display: 'flex', flexDirection: 'column', background: '#0b1017', color: '#fff' } const headerStyle: React.CSSProperties = { minHeight: 58, padding: 'calc(8px + env(safe-area-inset-top)) 12px 8px', display: 'flex', alignItems: 'center', gap: 10, background: '#111720', borderBottom: '1px solid #2b3442' } diff --git a/client/src/hooks/useGroupCall.ts b/client/src/hooks/useGroupCall.ts index 7ba4367..802228b 100644 --- a/client/src/hooks/useGroupCall.ts +++ b/client/src/hooks/useGroupCall.ts @@ -7,6 +7,7 @@ import { import { post } from '../api/http' import { onWs, sendWs } from '../api/socket' import { playCallRingtone, showBrowserNotification, stopRingtone } from '../utils/notification' +import { useI18n } from './useI18n' export type GroupCallStatus = 'idle' | 'ringing' | 'connecting' | 'connected' export type MeetingMode = 'discussion' | 'lecture' @@ -30,6 +31,7 @@ const decoder = new TextDecoder() const encoder = new TextEncoder() export function useGroupCall(userId: string | undefined) { + const { t } = useI18n() const [status, setStatus] = useState('idle') const [callId, setCallId] = useState(null) const [groupId, setGroupId] = useState(null) @@ -172,9 +174,9 @@ export function useGroupCall(userId: string | undefined) { sendWs({ type: 'group_call_invite', group_id: gid, call_id: cid, is_video: video }) } catch (e) { cleanup() - setError(e instanceof Error ? e.message : '无法连接会议服务器') + setError(e instanceof Error ? e.message : t('meeting.connection_failed')) } - }, [cleanup, connectMeeting]) + }, [cleanup, connectMeeting, t]) const acceptGroupCall = useCallback(async () => { if (!groupIdRef.current || !callIdRef.current) return @@ -184,9 +186,9 @@ export function useGroupCall(userId: string | undefined) { sendWs({ type: 'group_call_join', group_id: groupIdRef.current, call_id: callIdRef.current }) } catch (e) { cleanup() - setError(e instanceof Error ? e.message : '无法连接会议服务器') + setError(e instanceof Error ? e.message : t('meeting.connection_failed')) } - }, [cleanup, connectMeeting]) + }, [cleanup, connectMeeting, t]) const leaveGroupCall = useCallback(() => { if (groupIdRef.current && callIdRef.current) sendWs({ type: 'group_call_leave', group_id: groupIdRef.current, call_id: callIdRef.current }) @@ -223,10 +225,10 @@ export function useGroupCall(userId: string | undefined) { setCallId(data.call_id); setGroupId(data.group_id); setIsVideo(!!data.is_video) setInviterName(data.from_nickname || data.from || ''); setInviterAvatar(data.from_avatar || '') setGroupName(data.group_name || ''); setStatus('ringing'); playCallRingtone() - showBrowserNotification('PaperPhonePlus', data.is_video ? '群视频会议' : '群语音会议', () => window.focus()) + showBrowserNotification('PaperPhonePlus', t(data.is_video ? 'meeting.video_title' : 'meeting.voice_title'), () => window.focus()) }) return off - }, [userId]) + }, [t, userId]) useEffect(() => () => cleanup(), [cleanup]) diff --git a/client/src/i18n/locales/de.ts b/client/src/i18n/locales/de.ts index 6d63f87..c78408e 100644 --- a/client/src/i18n/locales/de.ts +++ b/client/src/i18n/locales/de.ts @@ -132,4 +132,9 @@ export const de: Record = { 'profile.delete_confirm': 'Konto löschen', 'profile.delete_enter_password': 'Passwort zur Bestätigung eingeben', 'profile.delete_need_password': 'Bitte geben Sie Ihr Passwort ein', + 'chat.ws_disconnected': 'Verbindung unterbrochen, Wiederverbindung...', 'group.name_hint': 'Gruppennamen eingeben', 'profile.push_blocked': 'Benachrichtigungen sind blockiert. Bitte aktivieren Sie sie in den Browsereinstellungen.', 'profile.push_failed': 'Benachrichtigungen konnten nicht aktiviert werden. Details finden Sie in der Konsole.', 'call.connecting': 'Verbindung wird hergestellt...', + 'terms.title': 'Nutzungsbedingungen', 'terms.agree_prefix': 'Ich habe die folgenden Bedingungen gelesen und stimme ihnen zu:', 'terms.agree_link': 'Nutzungsbedingungen', 'terms.must_agree': 'Sie müssen den Nutzungsbedingungen zustimmen, um fortzufahren', 'terms.hero_title': 'Nutzungsbedingungen', 'terms.hero_subtitle': 'Bitte lesen Sie diese Bedingungen sorgfältig, bevor Sie PaperPhonePlus verwenden', + 'report.title': 'Inhalt melden', 'report.reason': 'Grund der Meldung', 'report.reason_offensive': 'Anstößiger oder unangemessener Inhalt', 'report.reason_spam': 'Spam oder Werbung', 'report.reason_harassment': 'Belästigung oder Mobbing', 'report.reason_violence': 'Gewalt oder Drohungen', 'report.reason_misinformation': 'Falschinformationen', 'report.reason_other': 'Sonstiges', 'report.detail_placeholder': 'Weitere Details (optional)', 'report.submit': 'Meldung absenden', 'report.success': 'Meldung übermittelt. Wir prüfen sie innerhalb von 24 Stunden.', 'report.failed': 'Meldung konnte nicht gesendet werden. Bitte versuchen Sie es erneut.', 'report.report_post': 'Beitrag melden', 'report.report_message': 'Nachricht melden', 'report.report_user': 'Benutzer melden', + 'block.user': 'Benutzer blockieren', 'block.confirm_title': 'Diesen Benutzer blockieren?', 'block.confirm_desc': 'Blockierte Benutzer können Ihnen keine Nachrichten senden. Ihre Inhalte werden aus Ihrem Feed entfernt. Sie können die Blockierung später aufheben.', 'block.success': 'Benutzer erfolgreich blockiert', 'block.failed': 'Benutzer konnte nicht blockiert werden', 'unblock.user': 'Benutzer entsperren', 'unblock.success': 'Benutzer entsperrt', 'unblock.failed': 'Benutzer konnte nicht entsperrt werden', + 'meeting.video_title': 'Gruppen-Videokonferenz', 'meeting.voice_title': 'Gruppen-Audiokonferenz', 'meeting.video': 'Videokonferenz', 'meeting.voice': 'Audiokonferenz', 'meeting.invites_you': 'lädt Sie ein zu einer', 'meeting.reject': 'Ablehnen', 'meeting.join': 'Beitreten', 'meeting.leave': 'Konferenz verlassen', 'meeting.joining': 'Konferenz wird betreten…', 'meeting.people_unit': 'Personen', 'meeting.lecture_mode': 'Vortragsmodus', 'meeting.discussion_mode': 'Freie Diskussion', 'meeting.mute': 'Stummschalten', 'meeting.unmute': 'Stummschaltung aufheben', 'meeting.start_video': 'Video starten', 'meeting.stop_video': 'Video beenden', 'meeting.mute_all': 'Alle stummschalten', 'meeting.me': 'Ich', 'meeting.more_people': 'Weitere Teilnehmer:', 'meeting.host': 'Moderator', 'meeting.participants': 'Teilnehmer', 'meeting.close': 'Schließen', 'meeting.connection_failed': 'Verbindung zum Konferenzserver nicht möglich', } diff --git a/client/src/i18n/locales/en.ts b/client/src/i18n/locales/en.ts index 11b3f6c..9d9e957 100644 --- a/client/src/i18n/locales/en.ts +++ b/client/src/i18n/locales/en.ts @@ -436,4 +436,29 @@ export const en: Record = { 'unblock.user': 'Unblock User', 'unblock.success': 'User unblocked', 'unblock.failed': 'Failed to unblock user', + + // Video meeting + 'meeting.video_title': 'Group Video Meeting', + 'meeting.voice_title': 'Group Voice Meeting', + 'meeting.video': 'video meeting', + 'meeting.voice': 'voice meeting', + 'meeting.invites_you': 'invites you to join a', + 'meeting.reject': 'Reject', + 'meeting.join': 'Join', + 'meeting.leave': 'Leave', + 'meeting.joining': 'Joining meeting…', + 'meeting.people_unit': 'people', + 'meeting.lecture_mode': 'Lecture mode', + 'meeting.discussion_mode': 'Open discussion', + 'meeting.mute': 'Mute', + 'meeting.unmute': 'Unmute', + 'meeting.start_video': 'Start video', + 'meeting.stop_video': 'Stop video', + 'meeting.mute_all': 'Mute all', + 'meeting.me': 'Me', + 'meeting.more_people': 'More participants:', + 'meeting.host': 'Host', + 'meeting.participants': 'Participants', + 'meeting.close': 'Close', + 'meeting.connection_failed': 'Unable to connect to the meeting server', } diff --git a/client/src/i18n/locales/es.ts b/client/src/i18n/locales/es.ts index 1500b2b..5fbe703 100644 --- a/client/src/i18n/locales/es.ts +++ b/client/src/i18n/locales/es.ts @@ -132,4 +132,9 @@ export const es: Record = { 'profile.delete_confirm': 'Eliminar cuenta', 'profile.delete_enter_password': 'Ingresa tu contraseña para confirmar', 'profile.delete_need_password': 'Por favor ingresa tu contraseña', + 'chat.ws_disconnected': 'Conexión perdida, reconectando...', 'group.name_hint': 'Ingresa el nombre del grupo', 'profile.push_blocked': 'Las notificaciones están bloqueadas. Actívalas en la configuración del navegador.', 'profile.push_failed': 'No se pudieron activar las notificaciones. Consulta la consola para más detalles.', 'call.connecting': 'Conectando...', + 'terms.title': 'Términos de uso', 'terms.agree_prefix': 'He leído y acepto los', 'terms.agree_link': 'Términos de uso', 'terms.must_agree': 'Debes aceptar los Términos de uso para continuar', 'terms.hero_title': 'Términos de uso', 'terms.hero_subtitle': 'Lee atentamente estos términos antes de usar PaperPhonePlus', + 'report.title': 'Reportar contenido', 'report.reason': 'Motivo del reporte', 'report.reason_offensive': 'Contenido ofensivo o inapropiado', 'report.reason_spam': 'Spam o publicidad', 'report.reason_harassment': 'Acoso o intimidación', 'report.reason_violence': 'Violencia o amenazas', 'report.reason_misinformation': 'Información falsa', 'report.reason_other': 'Otro', 'report.detail_placeholder': 'Detalles adicionales (opcional)', 'report.submit': 'Enviar reporte', 'report.success': 'Reporte enviado. Lo revisaremos en un plazo de 24 horas.', 'report.failed': 'No se pudo enviar el reporte. Inténtalo de nuevo.', 'report.report_post': 'Reportar publicación', 'report.report_message': 'Reportar mensaje', 'report.report_user': 'Reportar usuario', + 'block.user': 'Bloquear usuario', 'block.confirm_title': '¿Bloquear a este usuario?', 'block.confirm_desc': 'Los usuarios bloqueados no podrán enviarte mensajes. Su contenido se eliminará de tu feed. Podrás desbloquearlos más tarde.', 'block.success': 'Usuario bloqueado', 'block.failed': 'No se pudo bloquear al usuario', 'unblock.user': 'Desbloquear usuario', 'unblock.success': 'Usuario desbloqueado', 'unblock.failed': 'No se pudo desbloquear al usuario', + 'meeting.video_title': 'Videoconferencia grupal', 'meeting.voice_title': 'Conferencia de voz grupal', 'meeting.video': 'videoconferencia', 'meeting.voice': 'conferencia de voz', 'meeting.invites_you': 'te invita a una', 'meeting.reject': 'Rechazar', 'meeting.join': 'Unirse', 'meeting.leave': 'Salir de la reunión', 'meeting.joining': 'Entrando a la reunión…', 'meeting.people_unit': 'personas', 'meeting.lecture_mode': 'Modo presentación', 'meeting.discussion_mode': 'Debate libre', 'meeting.mute': 'Silenciar', 'meeting.unmute': 'Activar micrófono', 'meeting.start_video': 'Iniciar vídeo', 'meeting.stop_video': 'Detener vídeo', 'meeting.mute_all': 'Silenciar a todos', 'meeting.me': 'Yo', 'meeting.more_people': 'Más participantes:', 'meeting.host': 'Anfitrión', 'meeting.participants': 'Participantes', 'meeting.close': 'Cerrar', 'meeting.connection_failed': 'No se puede conectar al servidor de reuniones', } diff --git a/client/src/i18n/locales/fr.ts b/client/src/i18n/locales/fr.ts index fc916a1..4e73136 100644 --- a/client/src/i18n/locales/fr.ts +++ b/client/src/i18n/locales/fr.ts @@ -132,4 +132,9 @@ export const fr: Record = { 'profile.delete_confirm': 'Supprimer le compte', 'profile.delete_enter_password': 'Entrez votre mot de passe pour confirmer', 'profile.delete_need_password': 'Veuillez entrer votre mot de passe', + 'chat.ws_disconnected': 'Connexion perdue, reconnexion...', 'group.name_hint': 'Saisissez le nom du groupe', 'profile.push_blocked': 'Les notifications sont bloquées. Activez-les dans les paramètres du navigateur.', 'profile.push_failed': 'Impossible d\'activer les notifications. Consultez la console pour plus de détails.', 'call.connecting': 'Connexion...', + 'terms.title': 'Conditions d\'utilisation', 'terms.agree_prefix': 'J\'ai lu et j\'accepte les', 'terms.agree_link': 'Conditions d\'utilisation', 'terms.must_agree': 'Vous devez accepter les conditions d\'utilisation pour continuer', 'terms.hero_title': 'Conditions d\'utilisation', 'terms.hero_subtitle': 'Veuillez lire attentivement ces conditions avant d\'utiliser PaperPhonePlus', + 'report.title': 'Signaler le contenu', 'report.reason': 'Motif du signalement', 'report.reason_offensive': 'Contenu offensant ou inapproprié', 'report.reason_spam': 'Spam ou publicité', 'report.reason_harassment': 'Harcèlement ou intimidation', 'report.reason_violence': 'Violence ou menaces', 'report.reason_misinformation': 'Désinformation', 'report.reason_other': 'Autre', 'report.detail_placeholder': 'Détails supplémentaires (facultatif)', 'report.submit': 'Envoyer le signalement', 'report.success': 'Signalement envoyé. Nous l\'examinerons sous 24 heures.', 'report.failed': 'Échec de l\'envoi du signalement. Veuillez réessayer.', 'report.report_post': 'Signaler la publication', 'report.report_message': 'Signaler le message', 'report.report_user': 'Signaler l\'utilisateur', + 'block.user': 'Bloquer l\'utilisateur', 'block.confirm_title': 'Bloquer cet utilisateur ?', 'block.confirm_desc': 'Les utilisateurs bloqués ne peuvent plus vous envoyer de messages. Leur contenu sera retiré de votre fil. Vous pourrez les débloquer plus tard.', 'block.success': 'Utilisateur bloqué', 'block.failed': 'Échec du blocage de l\'utilisateur', 'unblock.user': 'Débloquer l\'utilisateur', 'unblock.success': 'Utilisateur débloqué', 'unblock.failed': 'Échec du déblocage de l\'utilisateur', + 'meeting.video_title': 'Visioconférence de groupe', 'meeting.voice_title': 'Conférence audio de groupe', 'meeting.video': 'visioconférence', 'meeting.voice': 'conférence audio', 'meeting.invites_you': 'vous invite à une', 'meeting.reject': 'Refuser', 'meeting.join': 'Rejoindre', 'meeting.leave': 'Quitter la réunion', 'meeting.joining': 'Connexion à la réunion…', 'meeting.people_unit': 'personnes', 'meeting.lecture_mode': 'Mode présentation', 'meeting.discussion_mode': 'Discussion libre', 'meeting.mute': 'Couper le micro', 'meeting.unmute': 'Réactiver le micro', 'meeting.start_video': 'Activer la vidéo', 'meeting.stop_video': 'Désactiver la vidéo', 'meeting.mute_all': 'Couper tous les micros', 'meeting.me': 'Moi', 'meeting.more_people': 'Autres participants :', 'meeting.host': 'Animateur', 'meeting.participants': 'Participants', 'meeting.close': 'Fermer', 'meeting.connection_failed': 'Impossible de se connecter au serveur de réunion', } diff --git a/client/src/i18n/locales/ja.ts b/client/src/i18n/locales/ja.ts index 9b49fa2..e37308a 100644 --- a/client/src/i18n/locales/ja.ts +++ b/client/src/i18n/locales/ja.ts @@ -129,4 +129,10 @@ export const ja: Record = { 'profile.delete_confirm': 'アカウントを削除', 'profile.delete_enter_password': 'パスワードを入力して確認', 'profile.delete_need_password': 'パスワードを入力してください', + 'chat.ws_disconnected': '接続が切断されました。再接続中...', 'group.name_hint': 'グループ名を入力', + 'profile.push_blocked': '通知がブロックされています。ブラウザの設定で有効にしてください。', 'profile.push_failed': '通知を有効にできませんでした。詳細はコンソールを確認してください。', 'call.connecting': '接続中...', + 'terms.title': '利用規約', 'terms.agree_prefix': '以下を読み、同意します:', 'terms.agree_link': '利用規約', 'terms.must_agree': '続行するには利用規約への同意が必要です', 'terms.hero_title': '利用規約', 'terms.hero_subtitle': 'PaperPhonePlusを利用する前に、この規約をよくお読みください', + 'report.title': 'コンテンツを通報', 'report.reason': '通報理由', 'report.reason_offensive': '攻撃的または不適切なコンテンツ', 'report.reason_spam': 'スパムまたは広告', 'report.reason_harassment': '嫌がらせまたはいじめ', 'report.reason_violence': '暴力または脅迫', 'report.reason_misinformation': '誤情報', 'report.reason_other': 'その他', 'report.detail_placeholder': '追加詳細(任意)', 'report.submit': '通報を送信', 'report.success': '通報を送信しました。24時間以内に確認します。', 'report.failed': '通報の送信に失敗しました。もう一度お試しください。', 'report.report_post': '投稿を通報', 'report.report_message': 'メッセージを通報', 'report.report_user': 'ユーザーを通報', + 'block.user': 'ユーザーをブロック', 'block.confirm_title': 'このユーザーをブロックしますか?', 'block.confirm_desc': 'ブロックしたユーザーはあなたにメッセージを送信できず、そのコンテンツはフィードから削除されます。後で解除できます。', 'block.success': 'ユーザーをブロックしました', 'block.failed': 'ユーザーのブロックに失敗しました', 'unblock.user': 'ブロックを解除', 'unblock.success': 'ブロックを解除しました', 'unblock.failed': 'ブロック解除に失敗しました', + 'meeting.video_title': 'グループビデオ会議', 'meeting.voice_title': 'グループ音声会議', 'meeting.video': 'ビデオ会議', 'meeting.voice': '音声会議', 'meeting.invites_you': 'があなたを招待しています:', 'meeting.reject': '拒否', 'meeting.join': '参加', 'meeting.leave': '会議を退出', 'meeting.joining': '会議に参加中…', 'meeting.people_unit': '人', 'meeting.lecture_mode': '講義モード', 'meeting.discussion_mode': '自由討論', 'meeting.mute': 'ミュート', 'meeting.unmute': 'ミュート解除', 'meeting.start_video': 'ビデオを開始', 'meeting.stop_video': 'ビデオを停止', 'meeting.mute_all': '全員をミュート', 'meeting.me': '自分', 'meeting.more_people': 'その他の参加者:', 'meeting.host': 'ホスト', 'meeting.participants': '参加者', 'meeting.close': '閉じる', 'meeting.connection_failed': '会議サーバーに接続できません', } diff --git a/client/src/i18n/locales/ko.ts b/client/src/i18n/locales/ko.ts index bdb7196..8e3b988 100644 --- a/client/src/i18n/locales/ko.ts +++ b/client/src/i18n/locales/ko.ts @@ -130,4 +130,9 @@ export const ko: Record = { 'profile.delete_confirm': '계정 삭제', 'profile.delete_enter_password': '비밀번호를 입력하여 확인', 'profile.delete_need_password': '비밀번호를 입력해 주세요', + 'chat.ws_disconnected': '연결이 끊어져 다시 연결 중...', 'group.name_hint': '그룹 이름 입력', 'profile.push_blocked': '알림이 차단되었습니다. 브라우저 설정에서 활성화하세요.', 'profile.push_failed': '알림을 활성화하지 못했습니다. 자세한 내용은 콘솔을 확인하세요.', 'call.connecting': '연결 중...', + 'terms.title': '이용약관', 'terms.agree_prefix': '다음을 읽고 동의합니다:', 'terms.agree_link': '이용약관', 'terms.must_agree': '계속하려면 이용약관에 동의해야 합니다', 'terms.hero_title': '이용약관', 'terms.hero_subtitle': 'PaperPhonePlus를 사용하기 전에 약관을 자세히 읽어 주세요', + 'report.title': '콘텐츠 신고', 'report.reason': '신고 사유', 'report.reason_offensive': '모욕적이거나 부적절한 콘텐츠', 'report.reason_spam': '스팸 또는 광고', 'report.reason_harassment': '괴롭힘 또는 따돌림', 'report.reason_violence': '폭력 또는 위협', 'report.reason_misinformation': '허위 정보', 'report.reason_other': '기타', 'report.detail_placeholder': '추가 세부 사항(선택)', 'report.submit': '신고 제출', 'report.success': '신고가 제출되었습니다. 24시간 이내에 검토하겠습니다.', 'report.failed': '신고를 제출하지 못했습니다. 다시 시도하세요.', 'report.report_post': '게시물 신고', 'report.report_message': '메시지 신고', 'report.report_user': '사용자 신고', + 'block.user': '사용자 차단', 'block.confirm_title': '이 사용자를 차단할까요?', 'block.confirm_desc': '차단된 사용자는 메시지를 보낼 수 없고 피드에서 해당 콘텐츠가 제거됩니다. 나중에 차단을 해제할 수 있습니다.', 'block.success': '사용자를 차단했습니다', 'block.failed': '사용자 차단에 실패했습니다', 'unblock.user': '사용자 차단 해제', 'unblock.success': '차단을 해제했습니다', 'unblock.failed': '차단 해제에 실패했습니다', + 'meeting.video_title': '그룹 화상 회의', 'meeting.voice_title': '그룹 음성 회의', 'meeting.video': '화상 회의', 'meeting.voice': '음성 회의', 'meeting.invites_you': '님이 당신을 초대했습니다:', 'meeting.reject': '거절', 'meeting.join': '참가', 'meeting.leave': '회의 나가기', 'meeting.joining': '회의 참가 중…', 'meeting.people_unit': '명', 'meeting.lecture_mode': '강의 모드', 'meeting.discussion_mode': '자유 토론', 'meeting.mute': '음소거', 'meeting.unmute': '음소거 해제', 'meeting.start_video': '비디오 시작', 'meeting.stop_video': '비디오 중지', 'meeting.mute_all': '전체 음소거', 'meeting.me': '나', 'meeting.more_people': '추가 참가자:', 'meeting.host': '호스트', 'meeting.participants': '참가자', 'meeting.close': '닫기', 'meeting.connection_failed': '회의 서버에 연결할 수 없습니다', } diff --git a/client/src/i18n/locales/ru.ts b/client/src/i18n/locales/ru.ts index def0086..3f970b6 100644 --- a/client/src/i18n/locales/ru.ts +++ b/client/src/i18n/locales/ru.ts @@ -132,4 +132,9 @@ export const ru: Record = { 'profile.delete_confirm': 'Удалить аккаунт', 'profile.delete_enter_password': 'Введите пароль для подтверждения', 'profile.delete_need_password': 'Пожалуйста, введите пароль', + 'chat.ws_disconnected': 'Соединение потеряно, переподключение...', 'group.name_hint': 'Введите название группы', 'profile.push_blocked': 'Уведомления заблокированы. Разрешите их в настройках браузера.', 'profile.push_failed': 'Не удалось включить уведомления. Подробности доступны в консоли.', 'call.connecting': 'Подключение...', + 'terms.title': 'Условия использования', 'terms.agree_prefix': 'Я прочитал(-а) и принимаю', 'terms.agree_link': 'Условия использования', 'terms.must_agree': 'Для продолжения необходимо принять Условия использования', 'terms.hero_title': 'Условия использования', 'terms.hero_subtitle': 'Внимательно прочитайте эти условия перед использованием PaperPhonePlus', + 'report.title': 'Пожаловаться на контент', 'report.reason': 'Причина жалобы', 'report.reason_offensive': 'Оскорбительный или неприемлемый контент', 'report.reason_spam': 'Спам или реклама', 'report.reason_harassment': 'Преследование или травля', 'report.reason_violence': 'Насилие или угрозы', 'report.reason_misinformation': 'Недостоверная информация', 'report.reason_other': 'Другое', 'report.detail_placeholder': 'Дополнительные сведения (необязательно)', 'report.submit': 'Отправить жалобу', 'report.success': 'Жалоба отправлена. Мы рассмотрим её в течение 24 часов.', 'report.failed': 'Не удалось отправить жалобу. Повторите попытку.', 'report.report_post': 'Пожаловаться на публикацию', 'report.report_message': 'Пожаловаться на сообщение', 'report.report_user': 'Пожаловаться на пользователя', + 'block.user': 'Заблокировать пользователя', 'block.confirm_title': 'Заблокировать этого пользователя?', 'block.confirm_desc': 'Заблокированные пользователи не смогут отправлять вам сообщения. Их контент будет удалён из вашей ленты. Позже блокировку можно снять.', 'block.success': 'Пользователь заблокирован', 'block.failed': 'Не удалось заблокировать пользователя', 'unblock.user': 'Разблокировать пользователя', 'unblock.success': 'Пользователь разблокирован', 'unblock.failed': 'Не удалось разблокировать пользователя', + 'meeting.video_title': 'Групповая видеоконференция', 'meeting.voice_title': 'Групповая аудиоконференция', 'meeting.video': 'видеоконференцию', 'meeting.voice': 'аудиоконференцию', 'meeting.invites_you': 'приглашает вас на', 'meeting.reject': 'Отклонить', 'meeting.join': 'Присоединиться', 'meeting.leave': 'Покинуть конференцию', 'meeting.joining': 'Подключение к конференции…', 'meeting.people_unit': 'участников', 'meeting.lecture_mode': 'Режим лекции', 'meeting.discussion_mode': 'Свободное обсуждение', 'meeting.mute': 'Выключить микрофон', 'meeting.unmute': 'Включить микрофон', 'meeting.start_video': 'Включить видео', 'meeting.stop_video': 'Выключить видео', 'meeting.mute_all': 'Выключить микрофоны всем', 'meeting.me': 'Я', 'meeting.more_people': 'Другие участники:', 'meeting.host': 'Ведущий', 'meeting.participants': 'Участники', 'meeting.close': 'Закрыть', 'meeting.connection_failed': 'Не удалось подключиться к серверу конференций', } diff --git a/client/src/i18n/locales/zh.ts b/client/src/i18n/locales/zh.ts index fb46e57..190ec7d 100644 --- a/client/src/i18n/locales/zh.ts +++ b/client/src/i18n/locales/zh.ts @@ -450,4 +450,29 @@ export const zh: Record = { 'unblock.user': '取消拉黑', 'unblock.success': '已取消拉黑', 'unblock.failed': '取消拉黑失败', + + // 视频会议 + 'meeting.video_title': '群视频会议', + 'meeting.voice_title': '群语音会议', + 'meeting.video': '视频会议', + 'meeting.voice': '语音会议', + 'meeting.invites_you': '邀请你加入', + 'meeting.reject': '拒绝', + 'meeting.join': '加入', + 'meeting.leave': '离开会议', + 'meeting.joining': '正在进入会议…', + 'meeting.people_unit': '人', + 'meeting.lecture_mode': '讲课模式', + 'meeting.discussion_mode': '自由讨论', + 'meeting.mute': '静音', + 'meeting.unmute': '解除静音', + 'meeting.start_video': '开启视频', + 'meeting.stop_video': '关闭视频', + 'meeting.mute_all': '全员静音', + 'meeting.me': '我', + 'meeting.more_people': '其他参会者:', + 'meeting.host': '主席', + 'meeting.participants': '参会者', + 'meeting.close': '关闭', + 'meeting.connection_failed': '无法连接会议服务器', }