From 280536e93cc668dc2e56e2c13644933036d74fc4 Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 6 Jan 2026 15:26:13 +0530 Subject: [PATCH] updated remaining pages for localization. metascreen and player components --- src/components/metadata/SeriesContent.tsx | 21 +++---- .../player/controls/PlayerControls.tsx | 6 +- .../player/modals/AudioTrackModal.tsx | 6 +- .../player/modals/EpisodeStreamsModal.tsx | 12 ++-- .../player/modals/EpisodesModal.tsx | 6 +- src/components/player/modals/ErrorModal.tsx | 10 +-- .../player/modals/ResumeOverlay.tsx | 26 ++++---- src/components/player/modals/SourcesModal.tsx | 10 +-- src/components/player/modals/SpeedModal.tsx | 6 +- .../player/modals/SubtitleModals.tsx | 62 ++++++++++--------- src/i18n/locales/en.json | 62 ++++++++++++++++++- src/i18n/locales/pt.json | 62 ++++++++++++++++++- 12 files changed, 213 insertions(+), 76 deletions(-) diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index 328db39b..3ef7042f 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -866,7 +866,6 @@ const SeriesContentComponent: React.FC = ({ styles.seasonTextButton, { marginRight: seasonButtonSpacing, - width: isTV ? 150 : isLargeTablet ? 140 : isTablet ? 130 : 110, paddingVertical: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12, paddingHorizontal: isTV ? 20 : isLargeTablet ? 18 : isTablet ? 16 : 16, borderRadius: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 @@ -885,7 +884,7 @@ const SeriesContentComponent: React.FC = ({ { color: currentTheme.colors.highEmphasis } ] ]} numberOfLines={1}> - {season === 0 ? 'Specials' : `Season ${season}`} + {season === 0 ? t('metadata.specials') : t('metadata.season_number', { number: season })} @@ -948,7 +947,7 @@ const SeriesContentComponent: React.FC = ({ ] ]} > - {season === 0 ? 'Specials' : `Season ${season}`} + {season === 0 ? t('metadata.specials') : t('metadata.season_number', { number: season })} @@ -1559,7 +1558,7 @@ const SeriesContentComponent: React.FC = ({ paddingHorizontal: horizontalPadding } ]}> - {currentSeasonEpisodes.length} {currentSeasonEpisodes.length === 1 ? 'Episode' : 'Episodes'} + {currentSeasonEpisodes.length === 1 ? t('metadata.episode_count', { count: currentSeasonEpisodes.length }) : t('metadata.episode_count_plural', { count: currentSeasonEpisodes.length })} {/* Show message when no episodes are available for selected season */} @@ -1567,10 +1566,10 @@ const SeriesContentComponent: React.FC = ({ - No episodes available for Season {selectedSeason} + {t('metadata.no_episodes_for_season', { season: selectedSeason })} - Episodes may not be released yet + {t('metadata.episodes_not_released')} )} @@ -1750,7 +1749,7 @@ const SeriesContentComponent: React.FC = ({ fontSize: isTV ? 16 : 15, fontWeight: '500', }}> - {markingAsWatched ? 'Removing...' : 'Mark as Unwatched'} + {markingAsWatched ? t('metadata.removing') : t('metadata.mark_as_unwatched')} ) : ( @@ -1777,7 +1776,7 @@ const SeriesContentComponent: React.FC = ({ fontSize: isTV ? 16 : 15, fontWeight: '600', }}> - {markingAsWatched ? 'Marking...' : 'Mark as Watched'} + {markingAsWatched ? t('metadata.marking') : t('metadata.mark_as_watched')} ) @@ -1809,7 +1808,7 @@ const SeriesContentComponent: React.FC = ({ fontWeight: '500', flex: 1, // Allow text to take up space }} numberOfLines={1}> - {markingAsWatched ? 'Removing...' : `Unmark Season ${selectedSeason}`} + {markingAsWatched ? t('metadata.removing') : t('metadata.unmark_season', { season: selectedSeason })} ) : ( @@ -1837,7 +1836,7 @@ const SeriesContentComponent: React.FC = ({ fontWeight: '500', flex: 1, }} numberOfLines={1}> - {markingAsWatched ? 'Marking...' : `Mark Season ${selectedSeason}`} + {markingAsWatched ? t('metadata.marking') : t('metadata.mark_season', { season: selectedSeason })} )} @@ -1856,7 +1855,7 @@ const SeriesContentComponent: React.FC = ({ fontSize: isTV ? 15 : 14, fontWeight: '500', }}> - Cancel + {t('common.cancel')} diff --git a/src/components/player/controls/PlayerControls.tsx b/src/components/player/controls/PlayerControls.tsx index 2a78f050..f144c6b5 100644 --- a/src/components/player/controls/PlayerControls.tsx +++ b/src/components/player/controls/PlayerControls.tsx @@ -4,6 +4,7 @@ import { Ionicons } from '@expo/vector-icons'; import Feather from 'react-native-vector-icons/Feather'; import { LinearGradient } from 'expo-linear-gradient'; import Slider from '@react-native-community/slider'; +import { useTranslation } from 'react-i18next'; import { styles } from '../utils/playerStyles'; // Updated styles import { getTrackDisplayName } from '../utils/playerUtils'; import { useTheme } from '../../../contexts/ThemeContext'; @@ -99,6 +100,7 @@ export const PlayerControls: React.FC = ({ useExoPlayer, }) => { const { currentTheme } = useTheme(); + const { t } = useTranslation(); /* Responsive Spacing */ @@ -287,7 +289,7 @@ export const PlayerControls: React.FC = ({ }} minimumValue={0} maximumValue={duration || 1} - + value={previewTime} onValueChange={(v) => setPreviewTime(v)} @@ -338,7 +340,7 @@ export const PlayerControls: React.FC = ({ {/* Show year and provider (quality chip removed) */} {year && {year}} - {streamName && via {streamName}} + {streamName && {t('player_ui.via', { name: streamName })}} {playerBackend && ( diff --git a/src/components/player/modals/AudioTrackModal.tsx b/src/components/player/modals/AudioTrackModal.tsx index e90e43f3..ec5d5e58 100644 --- a/src/components/player/modals/AudioTrackModal.tsx +++ b/src/components/player/modals/AudioTrackModal.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { View, Text, TouchableOpacity, ScrollView, useWindowDimensions, StyleSheet, Platform } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; +import { useTranslation } from 'react-i18next'; import Animated, { FadeIn, FadeOut, @@ -25,6 +26,7 @@ export const AudioTrackModal: React.FC = ({ selectedAudioTrack, selectAudioTrack, }) => { + const { t } = useTranslation(); const { width, height } = useWindowDimensions(); // Size constants matching SubtitleModal aesthetics @@ -67,7 +69,7 @@ export const AudioTrackModal: React.FC = ({ > {/* Header with shared aesthetics */} - Audio Tracks + {t('player_ui.audio_tracks')} = ({ {ksAudioTracks.length === 0 && ( - No audio tracks available + {t('player_ui.no_audio_tracks')} )} diff --git a/src/components/player/modals/EpisodeStreamsModal.tsx b/src/components/player/modals/EpisodeStreamsModal.tsx index 4017b469..68a901e4 100644 --- a/src/components/player/modals/EpisodeStreamsModal.tsx +++ b/src/components/player/modals/EpisodeStreamsModal.tsx @@ -7,6 +7,7 @@ import Animated, { SlideInRight, SlideOutRight, } from 'react-native-reanimated'; +import { useTranslation } from 'react-i18next'; import { Episode } from '../../../types/metadata'; import { Stream } from '../../../types/streams'; import { stremioService } from '../../../services/stremioService'; @@ -58,6 +59,7 @@ export const EpisodeStreamsModal: React.FC = ({ onSelectStream, metadata, }) => { + const { t } = useTranslation(); const { width } = useWindowDimensions(); const MENU_WIDTH = Math.min(width * 0.85, 400); @@ -177,7 +179,7 @@ export const EpisodeStreamsModal: React.FC = ({ - {episode?.name || 'Sources'} + {episode?.name || t('player_ui.sources')} {episode && ( @@ -195,7 +197,7 @@ export const EpisodeStreamsModal: React.FC = ({ {isLoading && sortedProviders.length === 0 && ( - Finding sources... + {t('player_ui.finding_sources')} )} @@ -237,7 +239,7 @@ export const EpisodeStreamsModal: React.FC = ({ - {stream.name || 'Unknown Source'} + {stream.name || t('player_ui.unknown_source')} @@ -258,13 +260,13 @@ export const EpisodeStreamsModal: React.FC = ({ {!isLoading && sortedProviders.length === 0 && ( - No sources found + {t('player_ui.no_sources_found')} )} {hasErrors.length > 0 && ( - Sources might be limited due to provider errors. + {t('player_ui.sources_limited')} )} diff --git a/src/components/player/modals/EpisodesModal.tsx b/src/components/player/modals/EpisodesModal.tsx index 81dba416..64dccc3a 100644 --- a/src/components/player/modals/EpisodesModal.tsx +++ b/src/components/player/modals/EpisodesModal.tsx @@ -7,6 +7,7 @@ import Animated, { SlideInRight, SlideOutRight, } from 'react-native-reanimated'; +import { useTranslation } from 'react-i18next'; import { Episode } from '../../../types/metadata'; import { EpisodeCard } from '../cards/EpisodeCard'; import { storageService } from '../../../services/storageService'; @@ -32,6 +33,7 @@ export const EpisodesModal: React.FC = ({ onSelectEpisode, tmdbEpisodeOverrides }) => { + const { t } = useTranslation(); const { width } = useWindowDimensions(); const [selectedSeason, setSelectedSeason] = useState(currentEpisode?.season || 1); const [episodeProgress, setEpisodeProgress] = useState<{ [key: string]: any }>({}); @@ -117,7 +119,7 @@ export const EpisodesModal: React.FC = ({ > - Episodes + {t('player_ui.episodes')} @@ -143,7 +145,7 @@ export const EpisodesModal: React.FC = ({ color: selectedSeason === season ? 'black' : 'white', fontWeight: selectedSeason === season ? '700' : '500' }}> - {season === 0 ? 'Specials' : `Season ${season}`} + {season === 0 ? t('player_ui.specials') : t('player_ui.season', { season })} ))} diff --git a/src/components/player/modals/ErrorModal.tsx b/src/components/player/modals/ErrorModal.tsx index a1eda32b..679f9aa7 100644 --- a/src/components/player/modals/ErrorModal.tsx +++ b/src/components/player/modals/ErrorModal.tsx @@ -2,6 +2,7 @@ import React from 'react'; import * as ExpoClipboard from 'expo-clipboard'; import { View, Text, TouchableOpacity, StyleSheet, useWindowDimensions } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; +import { useTranslation } from 'react-i18next'; import Animated, { FadeIn, FadeOut, @@ -22,6 +23,7 @@ export const ErrorModal: React.FC = ({ errorDetails, onDismiss, }) => { + const { t } = useTranslation(); const [copied, setCopied] = React.useState(false); const { width } = useWindowDimensions(); const MODAL_WIDTH = Math.min(width * 0.8, 400); @@ -79,7 +81,7 @@ export const ErrorModal: React.FC = ({ marginBottom: 8, textAlign: 'center' }}> - Playback Error + {t('player_ui.playback_error')} = ({ lineHeight: 22 }} > - {errorDetails || 'An unknown error occurred during playback.'} + {errorDetails || t('player_ui.unknown_error')} = ({ style={{ marginRight: 6 }} /> - {copied ? 'Copied to clipboard' : 'Copy error details'} + {copied ? t('player_ui.copied_to_clipboard') : t('player_ui.copy_error')} @@ -135,7 +137,7 @@ export const ErrorModal: React.FC = ({ fontSize: 16, fontWeight: '700' }}> - Dismiss + {t('player_ui.dismiss')} diff --git a/src/components/player/modals/ResumeOverlay.tsx b/src/components/player/modals/ResumeOverlay.tsx index a5ff1837..7e61d7e3 100644 --- a/src/components/player/modals/ResumeOverlay.tsx +++ b/src/components/player/modals/ResumeOverlay.tsx @@ -2,6 +2,7 @@ import React, { useEffect } from 'react'; import { View, Text, TouchableOpacity } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { LinearGradient } from 'expo-linear-gradient'; +import { useTranslation } from 'react-i18next'; import { styles } from '../utils/playerStyles'; import { formatTime } from '../utils/playerUtils'; import { logger } from '../../../utils/logger'; @@ -27,6 +28,7 @@ export const ResumeOverlay: React.FC = ({ handleResume, handleStartFromBeginning, }) => { + const { t } = useTranslation(); useEffect(() => { // Removed excessive logging for props changes }, [showResumeOverlay, resumePosition, duration, title]); @@ -35,9 +37,9 @@ export const ResumeOverlay: React.FC = ({ // Removed excessive logging for overlay visibility return null; } - + // Removed excessive logging for overlay rendering - + return ( = ({ - Continue Watching + {t('player_ui.continue_watching')} {title} {season && episode && ` • S${season}E${episode}`} - 0 ? (resumePosition / duration) * 100 : 0}%` } - ]} + ]} /> @@ -71,19 +73,19 @@ export const ResumeOverlay: React.FC = ({ - - Start Over + {t('player_ui.start_over')} - - Resume + {t('player_ui.resume')} diff --git a/src/components/player/modals/SourcesModal.tsx b/src/components/player/modals/SourcesModal.tsx index 72a6ec42..c07c6c47 100644 --- a/src/components/player/modals/SourcesModal.tsx +++ b/src/components/player/modals/SourcesModal.tsx @@ -7,6 +7,7 @@ import Animated, { SlideInRight, SlideOutRight, } from 'react-native-reanimated'; +import { useTranslation } from 'react-i18next'; import { Stream } from '../../../types/streams'; interface SourcesModalProps { @@ -57,6 +58,7 @@ export const SourcesModal: React.FC = ({ onSelectStream, isChangingSource = false, }) => { + const { t } = useTranslation(); const { width } = useWindowDimensions(); const MENU_WIDTH = Math.min(width * 0.85, 400); @@ -123,7 +125,7 @@ export const SourcesModal: React.FC = ({ alignItems: 'center' }}> - Change Source + {t('player_ui.change_source')} @@ -142,7 +144,7 @@ export const SourcesModal: React.FC = ({ }}> - Switching source... + {t('player_ui.switching_source')} )} @@ -191,7 +193,7 @@ export const SourcesModal: React.FC = ({ fontSize: 14, flex: 1, }} numberOfLines={1}> - {stream.title || stream.name || `Stream ${index + 1}`} + {stream.title || stream.name || t('player_ui.stream', { number: index + 1 })} @@ -237,7 +239,7 @@ export const SourcesModal: React.FC = ({ - No sources found + {t('player_ui.no_sources_found')} )} diff --git a/src/components/player/modals/SpeedModal.tsx b/src/components/player/modals/SpeedModal.tsx index 7bc7fe90..9311a286 100644 --- a/src/components/player/modals/SpeedModal.tsx +++ b/src/components/player/modals/SpeedModal.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { View, Text, TouchableOpacity, useWindowDimensions, StyleSheet } from 'react-native'; import { MaterialIcons } from '@expo/vector-icons'; +import { useTranslation } from 'react-i18next'; import Animated, { FadeIn, FadeOut, @@ -55,6 +56,7 @@ const SpeedModal: React.FC = ({ holdToSpeedValue, setHoldToSpeedValue, }) => { + const { t } = useTranslation(); const { width } = useWindowDimensions(); const speedPresets = [0.5, 1.0, 1.25, 1.5, 2.0, 2.5]; const holdSpeedOptions = [1.0, 2.0, 3.0]; @@ -85,7 +87,7 @@ const SpeedModal: React.FC = ({ }} > - Playback Speed + {t('player_ui.playback_speed')} {/* Speed Selection Row */} @@ -108,7 +110,7 @@ const SpeedModal: React.FC = ({ onPress={() => setHoldToSpeedEnabled(!holdToSpeedEnabled)} style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: holdToSpeedEnabled ? 15 : 0 }} > - On Hold + {t('player_ui.on_hold')} = ({ selectedExternalSubtitleId, onOpenSyncModal, }) => { + const { t } = useTranslation(); const { width, height } = useWindowDimensions(); const isIos = Platform.OS === 'ios'; const isLandscape = width > height; @@ -151,14 +153,14 @@ export const SubtitleModals: React.FC = ({ > {/* Header */} - Subtitles + {t('player_ui.subtitles')} {/* Tab Bar */} - setActiveTab('built-in')} /> - setActiveTab('addon')} /> - setActiveTab('appearance')} /> + setActiveTab('built-in')} /> + setActiveTab('addon')} /> + setActiveTab('appearance')} /> @@ -174,7 +176,7 @@ export const SubtitleModals: React.FC = ({ }} style={{ padding: 10, borderRadius: 12, backgroundColor: selectedTextTrack === -1 ? 'white' : 'rgba(242, 184, 181)' }} > - None + {t('player_ui.none')} {ksTextTracks.map((track) => ( = ({ {availableSubtitles.length === 0 ? ( - Search Online Subtitles + {t('player_ui.search_online_subtitles')} ) : ( availableSubtitles.map((sub) => ( @@ -230,7 +232,7 @@ export const SubtitleModals: React.FC = ({ - Preview + {t('player_ui.preview')} @@ -262,7 +264,7 @@ export const SubtitleModals: React.FC = ({ - Quick Presets + {t('player_ui.quick_presets')} = ({ }} style={{ paddingHorizontal: chipPadH, paddingVertical: chipPadV, borderRadius: 20, backgroundColor: 'rgba(255,255,255,0.08)', borderWidth: 1, borderColor: 'rgba(255,255,255,0.15)' }} > - Default + {t('player_ui.default')} { @@ -282,7 +284,7 @@ export const SubtitleModals: React.FC = ({ }} style={{ paddingHorizontal: chipPadH, paddingVertical: chipPadV, borderRadius: 20, backgroundColor: 'rgba(255,215,0,0.12)', borderWidth: 1, borderColor: 'rgba(255,215,0,0.35)' }} > - Yellow + {t('player_ui.yellow')} { @@ -290,7 +292,7 @@ export const SubtitleModals: React.FC = ({ }} style={{ paddingHorizontal: chipPadH, paddingVertical: chipPadV, borderRadius: 20, backgroundColor: 'rgba(34,197,94,0.12)', borderWidth: 1, borderColor: 'rgba(34,197,94,0.35)' }} > - High Contrast + {t('player_ui.high_contrast')} { @@ -298,7 +300,7 @@ export const SubtitleModals: React.FC = ({ }} style={{ paddingHorizontal: chipPadH, paddingVertical: chipPadV, borderRadius: 20, backgroundColor: 'rgba(59,130,246,0.12)', borderWidth: 1, borderColor: 'rgba(59,130,246,0.35)' }} > - Large + {t('player_ui.large')} @@ -308,12 +310,12 @@ export const SubtitleModals: React.FC = ({ - Core + {t('player_ui.core')} - Font Size + {t('player_ui.font_size')} @@ -332,7 +334,7 @@ export const SubtitleModals: React.FC = ({ - Show Background + {t('player_ui.show_background')} = ({ - {isExoPlayerInternal ? 'Position' : 'Advanced'} + {isExoPlayerInternal ? t('player_ui.position') : t('player_ui.advanced')} {/* Text Color - Not supported on ExoPlayer internal subtitles */} {!isExoPlayerInternal && ( - Text Color + {t('player_ui.text_color')} {['#FFFFFF', '#FFD700', '#00E5FF', '#FF5C5C', '#00FF88', '#9b59b6', '#f97316'].map(c => ( @@ -367,7 +369,7 @@ export const SubtitleModals: React.FC = ({ {/* Align - Not supported on ExoPlayer internal subtitles */} {!isExoPlayerInternal && ( - Align + {t('player_ui.align')} {([{ key: 'left', icon: 'format-align-left' }, { key: 'center', icon: 'format-align-center' }, { key: 'right', icon: 'format-align-right' }] as const).map(a => ( setSubtitleAlign(a.key)} style={{ paddingHorizontal: isCompact ? 8 : 10, paddingVertical: isCompact ? 4 : 6, borderRadius: 8, backgroundColor: subtitleAlign === a.key ? 'rgba(255,255,255,0.18)' : 'rgba(255,255,255,0.08)', borderWidth: 1, borderColor: 'rgba(255,255,255,0.15)' }}> @@ -378,7 +380,7 @@ export const SubtitleModals: React.FC = ({ )} - Bottom Offset + {t('player_ui.bottom_offset')} setSubtitleBottomOffset(Math.max(0, subtitleBottomOffset - 5))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -394,7 +396,7 @@ export const SubtitleModals: React.FC = ({ {/* Background Opacity - Not supported on ExoPlayer internal subtitles */} {!isExoPlayerInternal && ( - Background Opacity + {t('player_ui.background_opacity')} setSubtitleBgOpacity(Math.max(0, +(subtitleBgOpacity - 0.1).toFixed(1)))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -410,16 +412,16 @@ export const SubtitleModals: React.FC = ({ )} {!isUsingInternalSubtitle && ( - Text Shadow + {t('player_ui.text_shadow')} setSubtitleTextShadow(!subtitleTextShadow)} style={{ paddingHorizontal: 10, paddingVertical: 8, borderRadius: 10, backgroundColor: subtitleTextShadow ? 'rgba(255,255,255,0.18)' : 'rgba(255,255,255,0.08)', borderWidth: 1, borderColor: 'rgba(255,255,255,0.15)', alignItems: 'center' }}> - {subtitleTextShadow ? 'On' : 'Off'} + {subtitleTextShadow ? t('player_ui.on') : t('player_ui.off')} )} {!isUsingInternalSubtitle && ( <> - Outline Color + {t('player_ui.outline_color')} {['#000000', '#FFFFFF', '#00E5FF', '#FF5C5C'].map(c => ( setSubtitleOutlineColor(c)} style={{ width: 22, height: 22, borderRadius: 11, backgroundColor: c, borderWidth: 2, borderColor: subtitleOutlineColor === c ? '#fff' : 'rgba(255,255,255,0.3)' }} /> @@ -427,7 +429,7 @@ export const SubtitleModals: React.FC = ({ - Outline Width + {t('player_ui.outline_width')} setSubtitleOutlineWidth(Math.max(0, subtitleOutlineWidth - 1))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -445,7 +447,7 @@ export const SubtitleModals: React.FC = ({ {!isUsingInternalSubtitle && ( - Letter Spacing + {t('player_ui.letter_spacing')} setSubtitleLetterSpacing(Math.max(0, +(subtitleLetterSpacing - 0.5).toFixed(1)))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -459,7 +461,7 @@ export const SubtitleModals: React.FC = ({ - Line Height + {t('player_ui.line_height')} setSubtitleLineHeightMultiplier(Math.max(1, +(subtitleLineHeightMultiplier - 0.1).toFixed(1)))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -478,7 +480,7 @@ export const SubtitleModals: React.FC = ({ {!isExoPlayerInternal && ( - Timing Offset (s) + {t('player_ui.timing_offset')} setSubtitleOffsetSec(+(subtitleOffsetSec - 0.1).toFixed(1))} style={{ width: controlBtn.size, height: controlBtn.size, borderRadius: controlBtn.radius, backgroundColor: 'rgba(255,255,255,0.18)', alignItems: 'center', justifyContent: 'center' }}> @@ -511,10 +513,10 @@ export const SubtitleModals: React.FC = ({ }} > - Visual Sync + {t('player_ui.visual_sync')} )} - Nudge subtitles earlier (-) or later (+) to sync if needed. + {t('player_ui.timing_hint')} )} @@ -527,7 +529,7 @@ export const SubtitleModals: React.FC = ({ }} style={{ paddingHorizontal: chipPadH, paddingVertical: chipPadV, borderRadius: 8, backgroundColor: 'rgba(255,255,255,0.1)', borderWidth: 1, borderColor: 'rgba(255,255,255,0.15)' }} > - Reset to defaults + {t('player_ui.reset_defaults')} diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index ecad7561..b8dba4dd 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -255,7 +255,9 @@ "added_to_collection_hero": "Added to Collection", "added_to_collection_desc_hero": "Added to your Trakt collection", "removed_from_collection_hero": "Removed from Collection", - "removed_from_collection_desc_hero": "Removed from your Trakt collection" + "removed_from_collection_desc_hero": "Removed from your Trakt collection", + "mark_as_watched": "Mark as Watched", + "mark_as_unwatched": "Mark as Unwatched" }, "cast": { "biography": "Biography", @@ -315,6 +317,64 @@ "starting_best_stream": "Starting best stream...", "loading_more_sources": "Loading more sources..." }, + "player_ui": { + "via": "via {{name}}", + "audio_tracks": "Audio Tracks", + "no_audio_tracks": "No audio tracks available", + "playback_speed": "Playback Speed", + "on_hold": "On Hold", + "playback_error": "Playback Error", + "unknown_error": "An unknown error occurred during playback.", + "copy_error": "Copy error details", + "copied_to_clipboard": "Copied to clipboard", + "dismiss": "Dismiss", + "continue_watching": "Continue Watching", + "start_over": "Start Over", + "resume": "Resume", + "change_source": "Change Source", + "switching_source": "Switching source...", + "no_sources_found": "No sources found", + "sources": "Sources", + "finding_sources": "Finding sources...", + "unknown_source": "Unknown Source", + "sources_limited": "Sources might be limited due to provider errors.", + "episodes": "Episodes", + "specials": "Specials", + "season": "Season {{season}}", + "stream": "Stream {{number}}", + "subtitles": "Subtitles", + "built_in": "Built-in", + "addons": "Addons", + "style": "Style", + "none": "None", + "search_online_subtitles": "Search Online Subtitles", + "preview": "Preview", + "quick_presets": "Quick Presets", + "default": "Default", + "yellow": "Yellow", + "high_contrast": "High Contrast", + "large": "Large", + "core": "Core", + "font_size": "Font Size", + "show_background": "Show Background", + "advanced": "Advanced", + "position": "Position", + "text_color": "Text Color", + "align": "Align", + "bottom_offset": "Bottom Offset", + "background_opacity": "Background Opacity", + "text_shadow": "Text Shadow", + "on": "On", + "off": "Off", + "outline_color": "Outline Color", + "outline_width": "Outline Width", + "letter_spacing": "Letter Spacing", + "line_height": "Line Height", + "timing_offset": "Timing Offset (s)", + "visual_sync": "Visual Sync", + "timing_hint": "Nudge subtitles earlier (-) or later (+) to sync if needed.", + "reset_defaults": "Reset to defaults" + }, "downloads": { "title": "Downloads", "no_downloads": "No Downloads Yet", diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 0ae61b5c..8f0be62d 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -255,7 +255,9 @@ "added_to_collection_hero": "Adicionado à Coleção", "added_to_collection_desc_hero": "Adicionado à sua coleção Trakt", "removed_from_collection_hero": "Removido da Coleção", - "removed_from_collection_desc_hero": "Removido da sua coleção Trakt" + "removed_from_collection_desc_hero": "Removido da sua coleção Trakt", + "mark_as_watched": "Marcar como Assistido", + "mark_as_unwatched": "Marcar como Não Assistido" }, "cast": { "biography": "Biografia", @@ -315,6 +317,64 @@ "starting_best_stream": "Iniciando melhor stream...", "loading_more_sources": "Carregando mais fontes..." }, + "player_ui": { + "via": "via {{name}}", + "audio_tracks": "Faixas de Áudio", + "no_audio_tracks": "Nenhuma faixa de áudio disponível", + "playback_speed": "Velocidade de Reprodução", + "on_hold": "Ao Segurar", + "playback_error": "Erro de Reprodução", + "unknown_error": "Ocorreu um erro desconhecido durante a reprodução.", + "copy_error": "Copiar detalhes do erro", + "copied_to_clipboard": "Copiado para a área de transferência", + "dismiss": "Dispensar", + "continue_watching": "Continuar Assistindo", + "start_over": "Recomeçar", + "resume": "Continuar", + "change_source": "Mudar Fonte", + "switching_source": "Trocando fonte...", + "no_sources_found": "Nenhuma fonte encontrada", + "sources": "Fontes", + "finding_sources": "Procurando fontes...", + "unknown_source": "Fonte Desconhecida", + "sources_limited": "As fontes podem ser limitadas devido a erros do provedor.", + "episodes": "Episódios", + "specials": "Especiais", + "season": "Temporada {{season}}", + "stream": "Stream {{number}}", + "subtitles": "Legendas", + "built_in": "Integradas", + "addons": "Addons", + "style": "Estilo", + "none": "Nenhuma", + "search_online_subtitles": "Buscar Legendas Online", + "preview": "Prévia", + "quick_presets": "Predefinições Rápidas", + "default": "Padrão", + "yellow": "Amarelo", + "high_contrast": "Alto Contraste", + "large": "Grande", + "core": "Principal", + "font_size": "Tamanho da Fonte", + "show_background": "Mostrar Fundo", + "advanced": "Avançado", + "position": "Posição", + "text_color": "Cor do Texto", + "align": "Alinhamento", + "bottom_offset": "Deslocamento Inferior", + "background_opacity": "Opacidade do Fundo", + "text_shadow": "Sombra do Texto", + "on": "Ligado", + "off": "Desligado", + "outline_color": "Cor do Contorno", + "outline_width": "Largura do Contorno", + "letter_spacing": "Espaçamento de Letras", + "line_height": "Altura da Linha", + "timing_offset": "Ajuste de Tempo (s)", + "visual_sync": "Sincronização Visual", + "timing_hint": "Ajuste as legendas para antes (-) ou depois (+) para sincronizar.", + "reset_defaults": "Redefinir padrões" + }, "downloads": { "title": "Downloads", "no_downloads": "Nenhum Download Ainda",