From 611b37c847ee7ab2d0e157759acb9d4215bdbddb Mon Sep 17 00:00:00 2001 From: tapframe Date: Tue, 6 Jan 2026 14:57:08 +0530 Subject: [PATCH] added to remaining. metascreen --- src/components/metadata/HeroSection.tsx | 31 +++++++------ src/components/metadata/SeriesContent.tsx | 8 ++-- src/i18n/locales/en.json | 35 +++++++++++++- src/i18n/locales/pt.json | 35 +++++++++++++- src/screens/MetadataScreen.tsx | 56 +++++++++++------------ 5 files changed, 118 insertions(+), 47 deletions(-) diff --git a/src/components/metadata/HeroSection.tsx b/src/components/metadata/HeroSection.tsx index 73b586c..c53d020 100644 --- a/src/components/metadata/HeroSection.tsx +++ b/src/components/metadata/HeroSection.tsx @@ -51,6 +51,7 @@ import { useToast } from '../../contexts/ToastContext'; import { useTraktContext } from '../../contexts/TraktContext'; import { useSettings } from '../../hooks/useSettings'; import { useTrailer } from '../../contexts/TrailerContext'; +import { useTranslation } from 'react-i18next'; import { logger } from '../../utils/logger'; import { TMDBService } from '../../services/tmdbService'; import TrailerService from '../../services/trailerService'; @@ -149,6 +150,7 @@ const ActionButtons = memo(({ onToggleCollection?: () => void; }) => { const { currentTheme } = useTheme(); + const { t } = useTranslation(); const { showSaved, showTraktSaved, showRemoved, showTraktRemoved, showSuccess, showInfo } = useToast(); // Performance optimization: Cache theme colors @@ -235,9 +237,9 @@ const ActionButtons = memo(({ // Show appropriate toast if (wasInCollection) { - showInfo('Removed from Collection', 'Removed from your Trakt collection'); + showInfo(t('metadata.removed_from_collection_hero'), t('metadata.removed_from_collection_desc_hero')); } else { - showSuccess('Added to Collection', 'Added to your Trakt collection'); + showSuccess(t('metadata.added_to_collection_hero'), t('metadata.added_to_collection_desc_hero')); } }, [onToggleCollection, isInCollection, showSuccess, showInfo]); @@ -263,7 +265,7 @@ const ActionButtons = memo(({ const finalPlayButtonText = useMemo(() => { // For movies, handle watched state if (type === 'movie') { - return isWatched ? 'Watch Again' : playButtonText; + return isWatched ? t('metadata.watch_again') : playButtonText; } // For series, validate next episode existence for both watched and resume cases @@ -306,7 +308,7 @@ const ActionButtons = memo(({ return `Play S${seasonStr}E${episodeStr}`; } else { // If next episode doesn't exist, show generic text - return 'Completed'; + return t('metadata.completed'); } } else { // For non-watched episodes, check if current episode exists @@ -320,17 +322,17 @@ const ActionButtons = memo(({ return playButtonText; } else { // Current episode doesn't exist, fallback to generic play - return 'Play'; + return t('metadata.play'); } } } // Fallback label if parsing fails - return isWatched ? 'Play Next Episode' : playButtonText; + return isWatched ? t('metadata.play_next_episode') : playButtonText; } // Default fallback for non-series or missing data - return isWatched ? 'Play' : playButtonText; + return isWatched ? t('metadata.play') : playButtonText; }, [isWatched, playButtonText, type, watchProgress, groupedEpisodes]); // Count additional buttons (excluding Play and Save) - AI Chat no longer counted @@ -394,7 +396,7 @@ const ActionButtons = memo(({ color={inLibrary ? (isAuthenticated && isInWatchlist ? "#E74C3C" : currentTheme.colors.white) : currentTheme.colors.white} /> - {inLibrary ? 'Saved' : 'Save'} + {inLibrary ? t('metadata.saved') : t('metadata.save')} @@ -484,6 +486,7 @@ const WatchProgressDisplay = memo(({ trailerReady: boolean; }) => { const { currentTheme } = useTheme(); + const { t } = useTranslation(); const { isAuthenticated: isTraktAuthenticated, forceSyncTraktProgress } = useTraktContext(); // State to trigger refresh after manual sync @@ -567,7 +570,7 @@ const WatchProgressDisplay = memo(({ progressPercent: 100, formattedTime: watchedDate, episodeInfo, - displayText: watchedViaTrakt ? 'Watched on Trakt' : 'Watched', + displayText: watchedViaTrakt ? t('metadata.watched_on_trakt') : t('metadata.watched'), syncStatus: isTraktAuthenticated && watchProgress?.traktSynced ? '' : '', // Clean look for watched isTraktSynced: watchProgress?.traktSynced && isTraktAuthenticated, isWatched: true @@ -597,22 +600,22 @@ const WatchProgressDisplay = memo(({ } // Enhanced display text with Trakt integration - let displayText = progressPercent >= 85 ? 'Watched' : `${Math.round(progressPercent)}% watched`; + let displayText = progressPercent >= 85 ? t('metadata.watched') : t('metadata.percent_watched', { percent: Math.round(progressPercent) }); let syncStatus = ''; // Show Trakt sync status if user is authenticated if (isTraktAuthenticated) { if (isUsingTraktProgress) { - syncStatus = ' • Using Trakt progress'; + syncStatus = ' • ' + t('metadata.using_trakt_progress'); if (watchProgress.traktSynced) { - syncStatus = ' • Synced with Trakt'; + syncStatus = ' • ' + t('metadata.synced_with_trakt_progress'); } } else if (watchProgress.traktSynced) { - syncStatus = ' • Synced with Trakt'; + syncStatus = ' • ' + t('metadata.synced_with_trakt_progress'); // If we have specific Trakt progress that differs from local, mention it if (watchProgress.traktProgress !== undefined && Math.abs(progressPercent - watchProgress.traktProgress) > 5) { - displayText = `${Math.round(progressPercent)}% watched (${Math.round(watchProgress.traktProgress)}% on Trakt)`; + displayText = t('metadata.percent_watched_trakt', { percent: Math.round(progressPercent), traktPercent: Math.round(watchProgress.traktProgress) }); } } else { // Do not show "Sync pending" label anymore; leave status empty. diff --git a/src/components/metadata/SeriesContent.tsx b/src/components/metadata/SeriesContent.tsx index caa8d2e..328db39 100644 --- a/src/components/metadata/SeriesContent.tsx +++ b/src/components/metadata/SeriesContent.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState, useRef, useCallback, useMemo, memo } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, ActivityIndicator, Dimensions, useWindowDimensions, useColorScheme, FlatList, Modal, Pressable } from 'react-native'; +import { useTranslation } from 'react-i18next'; import * as Haptics from 'expo-haptics'; import FastImage from '@d11/react-native-fast-image'; import { MaterialIcons } from '@expo/vector-icons'; @@ -54,6 +55,7 @@ const SeriesContentComponent: React.FC = ({ }) => { const { currentTheme } = useTheme(); const { settings } = useSettings(); + const { t } = useTranslation(); const { width } = useWindowDimensions(); const isDarkMode = useColorScheme() === 'dark'; @@ -740,7 +742,7 @@ const SeriesContentComponent: React.FC = ({ return ( - Loading episodes... + {t('metadata.loading_episodes')} ); } @@ -749,7 +751,7 @@ const SeriesContentComponent: React.FC = ({ return ( - No episodes available + {t('metadata.no_episodes_available')} ); } @@ -785,7 +787,7 @@ const SeriesContentComponent: React.FC = ({ color: currentTheme.colors.highEmphasis, fontSize: isTV ? 28 : isLargeTablet ? 26 : isTablet ? 24 : 18 } - ]}>Seasons + ]}>{t('metadata.seasons')} {/* Dropdown Toggle Button */} { const handleSpoilerPress = useCallback((comment: any) => { Alert.alert( - 'Spoiler Warning', - 'This comment contains spoilers. Are you sure you want to reveal it?', + t('metadata.spoiler_warning'), + t('metadata.spoiler_warning_desc'), [ { - text: 'Cancel', + text: t('metadata.cancel'), style: 'cancel', }, { - text: 'Reveal Spoilers', + text: t('metadata.reveal_spoilers'), style: 'destructive', onPress: () => { setRevealedSpoilers(prev => new Set([...prev, comment.id.toString()])); @@ -744,7 +744,7 @@ const MetadataScreen: React.FC = () => { }, ] ); - }, []); + }, [t]); // Source switching removed @@ -1025,7 +1025,7 @@ const MetadataScreen: React.FC = () => { fontSize: isTV ? 20 : isLargeTablet ? 18 : isTablet ? 17 : 16, marginBottom: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 } - ]}>Network + ]}>{t('metadata.network')} { fontSize: isTV ? 20 : isLargeTablet ? 18 : isTablet ? 17 : 16, marginBottom: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 } - ]}>Production + ]}>{t('metadata.production')} { fontSize: isTV ? 20 : isLargeTablet ? 18 : isTablet ? 17 : 16, marginBottom: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 } - ]}>Movie Details + ]}>{t('metadata.movie_details')} {metadata.movieDetails.tagline && ( - Tagline + {t('metadata.tagline')} "{metadata.movieDetails.tagline}" @@ -1176,14 +1176,14 @@ const MetadataScreen: React.FC = () => { {metadata.movieDetails.status && ( - Status + {t('metadata.status')} {metadata.movieDetails.status} )} {metadata.movieDetails.releaseDate && ( - Release Date + {t('metadata.release_date')} {new Date(metadata.movieDetails.releaseDate).toLocaleDateString('en-US', { year: 'numeric', @@ -1196,7 +1196,7 @@ const MetadataScreen: React.FC = () => { {metadata.movieDetails.runtime && ( - Runtime + {t('metadata.runtime')} {Math.floor(metadata.movieDetails.runtime / 60)}h {metadata.movieDetails.runtime % 60}m @@ -1205,7 +1205,7 @@ const MetadataScreen: React.FC = () => { {metadata.movieDetails.budget && metadata.movieDetails.budget > 0 && ( - Budget + {t('metadata.budget')} ${metadata.movieDetails.budget.toLocaleString()} @@ -1214,7 +1214,7 @@ const MetadataScreen: React.FC = () => { {metadata.movieDetails.revenue && metadata.movieDetails.revenue > 0 && ( - Revenue + {t('metadata.revenue')} ${metadata.movieDetails.revenue.toLocaleString()} @@ -1223,14 +1223,14 @@ const MetadataScreen: React.FC = () => { {metadata.movieDetails.originCountry && metadata.movieDetails.originCountry.length > 0 && ( - Origin Country + {t('metadata.origin_country')} {metadata.movieDetails.originCountry.join(', ')} )} {metadata.movieDetails.originalLanguage && ( - Original Language + {t('metadata.original_language')} {metadata.movieDetails.originalLanguage.toUpperCase()} )} @@ -1248,7 +1248,7 @@ const MetadataScreen: React.FC = () => { title: metadata.name || 'Gallery' })} > - Backdrop Gallery + {t('metadata.backdrop_gallery')} @@ -1294,18 +1294,18 @@ const MetadataScreen: React.FC = () => { fontSize: isTV ? 20 : isLargeTablet ? 18 : isTablet ? 17 : 16, marginBottom: isTV ? 16 : isLargeTablet ? 14 : isTablet ? 12 : 12 } - ]}>Show Details + ]}>{t('metadata.show_details')} {metadata.tvDetails.status && ( - Status + {t('metadata.status')} {metadata.tvDetails.status} )} {metadata.tvDetails.firstAirDate && ( - First Air Date + {t('metadata.first_air_date')} {new Date(metadata.tvDetails.firstAirDate).toLocaleDateString('en-US', { year: 'numeric', @@ -1318,7 +1318,7 @@ const MetadataScreen: React.FC = () => { {metadata.tvDetails.lastAirDate && ( - Last Air Date + {t('metadata.last_air_date')} {new Date(metadata.tvDetails.lastAirDate).toLocaleDateString('en-US', { year: 'numeric', @@ -1331,21 +1331,21 @@ const MetadataScreen: React.FC = () => { {metadata.tvDetails.numberOfSeasons && ( - Seasons + {t('metadata.seasons')} {metadata.tvDetails.numberOfSeasons} )} {metadata.tvDetails.numberOfEpisodes && ( - Total Episodes + {t('metadata.total_episodes')} {metadata.tvDetails.numberOfEpisodes} )} {metadata.tvDetails.episodeRunTime && metadata.tvDetails.episodeRunTime.length > 0 && ( - Episode Runtime + {t('metadata.episode_runtime')} {metadata.tvDetails.episodeRunTime.join(' - ')} min @@ -1354,21 +1354,21 @@ const MetadataScreen: React.FC = () => { {metadata.tvDetails.originCountry && metadata.tvDetails.originCountry.length > 0 && ( - Origin Country + {t('metadata.origin_country')} {metadata.tvDetails.originCountry.join(', ')} )} {metadata.tvDetails.originalLanguage && ( - Original Language + {t('metadata.original_language')} {metadata.tvDetails.originalLanguage.toUpperCase()} )} {metadata.tvDetails.createdBy && metadata.tvDetails.createdBy.length > 0 && ( - Created By + {t('metadata.created_by')} {metadata.tvDetails.createdBy.map(creator => creator.name).join(', ')} @@ -1388,7 +1388,7 @@ const MetadataScreen: React.FC = () => { title: metadata.name || 'Gallery' })} > - Backdrop Gallery + {t('metadata.backdrop_gallery')}