From bbdd4c0504bd94c4a0980bfce4e9896ce0c0ac3f Mon Sep 17 00:00:00 2001 From: tapframe Date: Wed, 7 Jan 2026 00:05:02 +0530 Subject: [PATCH] updated remaining contents for localization --- src/components/metadata/CastDetailsModal.tsx | 36 ++--- src/i18n/locales/ar.json | 29 +++- src/i18n/locales/en.json | 27 +++- src/i18n/locales/es.json | 29 +++- src/i18n/locales/fr.json | 29 +++- src/i18n/locales/pt.json | 27 +++- src/screens/CastMoviesScreen.tsx | 144 ++++++++++--------- 7 files changed, 215 insertions(+), 106 deletions(-) diff --git a/src/components/metadata/CastDetailsModal.tsx b/src/components/metadata/CastDetailsModal.tsx index 278a163..cce5b25 100644 --- a/src/components/metadata/CastDetailsModal.tsx +++ b/src/components/metadata/CastDetailsModal.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; import { View, Text, @@ -70,6 +71,7 @@ export const CastDetailsModal: React.FC = ({ onClose, castMember, }) => { + const { t } = useTranslation(); const { currentTheme } = useTheme(); const navigation = useNavigation>(); const [personDetails, setPersonDetails] = useState(null); @@ -82,14 +84,14 @@ export const CastDetailsModal: React.FC = ({ if (visible && castMember) { modalOpacity.value = withTiming(1, { duration: 250 }); modalScale.value = withSpring(1, { damping: 20, stiffness: 200 }); - + if (!hasFetched || personDetails?.id !== castMember.id) { fetchPersonDetails(); } } else { modalOpacity.value = withTiming(0, { duration: 200 }); modalScale.value = withTiming(0.9, { duration: 200 }); - + if (!visible) { setHasFetched(false); setPersonDetails(null); @@ -99,7 +101,7 @@ export const CastDetailsModal: React.FC = ({ const fetchPersonDetails = async () => { if (!castMember || loading) return; - + setLoading(true); try { const details = await tmdbService.getPersonDetails(castMember.id); @@ -150,11 +152,11 @@ export const CastDetailsModal: React.FC = ({ const birthDate = new Date(birthday); let age = today.getFullYear() - birthDate.getFullYear(); const monthDiff = today.getMonth() - birthDate.getMonth(); - + if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) { age--; } - + return age; }; @@ -196,8 +198,8 @@ export const CastDetailsModal: React.FC = ({ height: MODAL_HEIGHT, overflow: 'hidden', borderRadius: isTablet ? 32 : 24, - backgroundColor: Platform.OS === 'android' - ? 'rgba(20, 20, 20, 0.95)' + backgroundColor: Platform.OS === 'android' + ? 'rgba(20, 20, 20, 0.95)' : 'transparent', }, modalStyle, @@ -280,7 +282,7 @@ export const CastDetailsModal: React.FC = ({ )} - + = ({ fontSize: isTablet ? 14 : 13, fontWeight: '500', }} numberOfLines={2}> - as {castMember.character} + {t('cast.as_character', { character: castMember.character })} )} @@ -336,7 +338,7 @@ export const CastDetailsModal: React.FC = ({ fontSize: 14, marginTop: 12, }}> - Loading details... + {t('cast.loading_details')} ) : ( @@ -352,8 +354,8 @@ export const CastDetailsModal: React.FC = ({ borderColor: 'rgba(255, 255, 255, 0.06)', }}> {personDetails?.birthday && ( - @@ -369,7 +371,7 @@ export const CastDetailsModal: React.FC = ({ fontSize: 13, fontWeight: '500', }}> - {calculateAge(personDetails.birthday)} years old + {t('cast.years_old', { age: calculateAge(personDetails.birthday) })} )} @@ -389,7 +391,7 @@ export const CastDetailsModal: React.FC = ({ fontWeight: '500', flex: 1, }}> - Born in {personDetails.place_of_birth} + {t('cast.born_in', { place: personDetails.place_of_birth })} )} @@ -420,7 +422,7 @@ export const CastDetailsModal: React.FC = ({ fontWeight: '600', letterSpacing: 0.3, }}> - View Filmography + {t('cast.view_filmography')} @@ -454,7 +456,7 @@ export const CastDetailsModal: React.FC = ({ textTransform: 'uppercase', letterSpacing: 0.5, }}> - Also Known As + {t('cast.also_known_as')} = ({ textAlign: 'center', fontWeight: '500', }}> - No additional information available + {t('cast.no_info_available')} )} diff --git a/src/i18n/locales/ar.json b/src/i18n/locales/ar.json index 389b89d..4e8885c 100644 --- a/src/i18n/locales/ar.json +++ b/src/i18n/locales/ar.json @@ -110,7 +110,7 @@ "try_different": "جرب تصنيفاً أو كتالوجاً مختلفاً", "select_catalog_desc": "اختر كتالوجاً للاكتشاف", "tap_catalog_desc": "اضغط على الكتالوج أعلاه للبدء", - "search_placeholder": "ابحث عن أفلام، مسلسلات...", + "placeholder": "ابحث عن أفلام، مسلسلات...", "keep_typing": "استمر في الكتابة...", "type_characters": "اكتب حرفين على الأقل للبحث", "no_results": "لم يتم العثور على نتائج", @@ -279,7 +279,28 @@ "born_in": "وُلد في {{place}}", "filmography": "قائمة الأفلام", "also_known_as": "يُعرف أيضاً بـ", - "no_info_available": "لا توجد معلومات إضافية متاحة" + "no_info_available": "لا توجد معلومات إضافية متاحة", + "as_character": "as {{character}}", + "loading_details": "Loading details...", + "years_old": "{{age}} years old", + "view_filmography": "View Filmography", + "filter": "Filter", + "sort_by": "Sort By", + "sort_popular": "Popular", + "sort_latest": "Latest", + "sort_upcoming": "Upcoming", + "upcoming_badge": "UPCOMING", + "coming_soon": "Coming Soon", + "filmography_count": "Filmography • {{count}} titles", + "loading_filmography": "Loading filmography...", + "load_more_remaining": "Load More ({{count}} remaining)", + "alert_error_title": "Error", + "alert_error_message": "Unable to load \"{{title}}\". Please try again later.", + "alert_ok": "OK", + "no_upcoming": "No upcoming releases available for this actor", + "no_content": "No content available for this actor", + "no_movies": "No movies available for this actor", + "no_tv": "No TV shows available for this actor" }, "comments": { "title": "تعليقات Trakt", @@ -1124,7 +1145,7 @@ "clear_cache_desc": "سيؤدي هذا لإزالة رابط المستودع المحفوظ ومسح كل بيانات البلاجنز المخزنة مؤقتاً. ستحتاج لإعادة إدخال رابط المستودع.", "add_new_repo": "إضافة مستودع جديد", "available_plugins": "البلاجنز المتاحة ({{count}})", - "search_placeholder": "البحث في البلاجنز...", + "placeholder": "البحث في البلاجنز...", "all": "الكل", "filter_all": "كل الأنواع", "filter_movies": "أفلام", @@ -1171,4 +1192,4 @@ "cancel": "إلغاء", "add": "إضافة" } -} +} \ No newline at end of file diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 9ed4d63..24dbb69 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -110,7 +110,7 @@ "try_different": "Try a different genre or catalog", "select_catalog_desc": "Select a catalog to discover", "tap_catalog_desc": "Tap the catalog chip above to get started", - "search_placeholder": "Search movies, shows...", + "placeholder": "Search movies, shows...", "keep_typing": "Keep typing...", "type_characters": "Type at least 2 characters to search", "no_results": "No results found", @@ -279,7 +279,28 @@ "born_in": "Born in {{place}}", "filmography": "Filmography", "also_known_as": "Also Known As", - "no_info_available": "No additional information available" + "no_info_available": "No additional information available", + "as_character": "as {{character}}", + "loading_details": "Loading details...", + "years_old": "{{age}} years old", + "view_filmography": "View Filmography", + "filter": "Filter", + "sort_by": "Sort By", + "sort_popular": "Popular", + "sort_latest": "Latest", + "sort_upcoming": "Upcoming", + "upcoming_badge": "UPCOMING", + "coming_soon": "Coming Soon", + "filmography_count": "Filmography • {{count}} titles", + "loading_filmography": "Loading filmography...", + "load_more_remaining": "Load More ({{count}} remaining)", + "alert_error_title": "Error", + "alert_error_message": "Unable to load \"{{title}}\". Please try again later.", + "alert_ok": "OK", + "no_upcoming": "No upcoming releases available for this actor", + "no_content": "No content available for this actor", + "no_movies": "No movies available for this actor", + "no_tv": "No TV shows available for this actor" }, "comments": { "title": "Trakt Comments", @@ -1124,7 +1145,7 @@ "clear_cache_desc": "This will remove the saved repository URL and clear all cached plugin data. You will need to re-enter your repository URL.", "add_new_repo": "Add New Repository", "available_plugins": "Available Plugins ({{count}})", - "search_placeholder": "Search plugins...", + "placeholder": "Search plugins...", "all": "All", "filter_all": "All Types", "filter_movies": "Movies", diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 1a9a6c1..87bffca 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -110,7 +110,7 @@ "try_different": "Prueba con un género o catálogo diferente", "select_catalog_desc": "Selecciona un catálogo para descubrir", "tap_catalog_desc": "Toca el catálogo arriba para empezar", - "search_placeholder": "Buscar películas, series...", + "placeholder": "Buscar películas, series...", "keep_typing": "Sigue escribiendo...", "type_characters": "Escribe al menos 2 caracteres para buscar", "no_results": "No se encontraron resultados", @@ -279,7 +279,28 @@ "born_in": "Nacido/a en {{place}}", "filmography": "Filmografía", "also_known_as": "También conocido/a como", - "no_info_available": "No hay información adicional disponible" + "no_info_available": "No additional information available", + "as_character": "as {{character}}", + "loading_details": "Loading details...", + "years_old": "{{age}} years old", + "view_filmography": "View Filmography", + "filter": "Filter", + "sort_by": "Sort By", + "sort_popular": "Popular", + "sort_latest": "Latest", + "sort_upcoming": "Upcoming", + "upcoming_badge": "UPCOMING", + "coming_soon": "Coming Soon", + "filmography_count": "Filmography • {{count}} titles", + "loading_filmography": "Loading filmography...", + "load_more_remaining": "Load More ({{count}} remaining)", + "alert_error_title": "Error", + "alert_error_message": "Unable to load \"{{title}}\". Please try again later.", + "alert_ok": "OK", + "no_upcoming": "No upcoming releases available for this actor", + "no_content": "No content available for this actor", + "no_movies": "No movies available for this actor", + "no_tv": "No TV shows available for this actor" }, "comments": { "title": "Comentarios de Trakt", @@ -1124,7 +1145,7 @@ "clear_cache_desc": "Esto eliminará la URL guardada y los datos en caché. Tendrás que introducir de nuevo la URL del repositorio.", "add_new_repo": "Añadir nuevo repositorio", "available_plugins": "Plugins disponibles ({{count}})", - "search_placeholder": "Buscar plugins...", + "placeholder": "Buscar plugins...", "all": "Todo", "filter_all": "Todos los tipos", "filter_movies": "Películas", @@ -1171,4 +1192,4 @@ "cancel": "Cancelar", "add": "Añadir" } -} +} \ No newline at end of file diff --git a/src/i18n/locales/fr.json b/src/i18n/locales/fr.json index c3e72b6..4d4c3d3 100644 --- a/src/i18n/locales/fr.json +++ b/src/i18n/locales/fr.json @@ -110,7 +110,7 @@ "try_different": "Essayez un genre ou un catalogue différent", "select_catalog_desc": "Sélectionnez un catalogue à découvrir", "tap_catalog_desc": "Appuyez sur le jeton de catalogue ci-dessus pour commencer", - "search_placeholder": "Rechercher des films, séries...", + "placeholder": "Rechercher des films, séries...", "keep_typing": "Continuez à taper...", "type_characters": "Tapez au moins 2 caractères pour rechercher", "no_results": "Aucun résultat trouvé", @@ -278,7 +278,28 @@ "personal_info": "Infos personnelles", "born_in": "Né à {{place}}", "filmography": "Filmographie", - "also_known_as": "Aussi connu sous le nom de", + "also_known_as": "Aussi connu(e) sous le nom de", + "as_character": "as {{character}}", + "loading_details": "Loading details...", + "years_old": "{{age}} years old", + "view_filmography": "View Filmography", + "filter": "Filter", + "sort_by": "Sort By", + "sort_popular": "Popular", + "sort_latest": "Latest", + "sort_upcoming": "Upcoming", + "upcoming_badge": "UPCOMING", + "coming_soon": "Coming Soon", + "filmography_count": "Filmography • {{count}} titles", + "loading_filmography": "Loading filmography...", + "load_more_remaining": "Load More ({{count}} remaining)", + "alert_error_title": "Error", + "alert_error_message": "Unable to load \"{{title}}\". Please try again later.", + "alert_ok": "OK", + "no_upcoming": "No upcoming releases available for this actor", + "no_content": "No content available for this actor", + "no_movies": "No movies available for this actor", + "no_tv": "No TV shows available for this actor", "no_info_available": "Aucune information supplémentaire disponible" }, "comments": { @@ -1124,7 +1145,7 @@ "clear_cache_desc": "Cela supprimera l'URL du dépôt enregistrée et effacera toutes les données de plugin mises en cache. Vous devrez ressaisir votre URL de dépôt.", "add_new_repo": "Ajouter un nouveau dépôt", "available_plugins": "Plugins disponibles ({{count}})", - "search_placeholder": "Rechercher des plugins...", + "placeholder": "Rechercher des plugins...", "all": "Tout", "filter_all": "Tous les types", "filter_movies": "Films", @@ -1171,4 +1192,4 @@ "cancel": "Annuler", "add": "Ajouter" } -} +} \ No newline at end of file diff --git a/src/i18n/locales/pt.json b/src/i18n/locales/pt.json index 25e5233..1a8610a 100644 --- a/src/i18n/locales/pt.json +++ b/src/i18n/locales/pt.json @@ -110,7 +110,7 @@ "try_different": "Tente um gênero ou catálogo diferente", "select_catalog_desc": "Selecione um catálogo para descobrir", "tap_catalog_desc": "Toque no botão de catálogo acima para começar", - "search_placeholder": "Buscar filmes, séries...", + "placeholder": "Buscar filmes, séries...", "keep_typing": "Continue digitando...", "type_characters": "Digite pelo menos 2 caracteres para buscar", "no_results": "Nenhum resultado encontrado", @@ -278,7 +278,28 @@ "personal_info": "Informações Pessoais", "born_in": "Nascido em {{place}}", "filmography": "Filmografia", - "also_known_as": "Também Conhecido Como", + "also_known_as": "Também conhecido(a) como", + "as_character": "como {{character}}", + "loading_details": "Carregando detalhes...", + "years_old": "{{age}} anos", + "view_filmography": "Ver Filmografia", + "filter": "Filtrar", + "sort_by": "Ordenar Por", + "sort_popular": "Popular", + "sort_latest": "Mais Recente", + "sort_upcoming": "Próximos Lançamentos", + "upcoming_badge": "EM BREVE", + "coming_soon": "Em Breve", + "filmography_count": "Filmografia • {{count}} títulos", + "loading_filmography": "Carregando filmografia...", + "load_more_remaining": "Carregar Mais ({{count}} restantes)", + "alert_error_title": "Erro", + "alert_error_message": "Não foi possível carregar \"{{title}}\". Por favor, tente novamente mais tarde.", + "alert_ok": "OK", + "no_upcoming": "Nenhum lançamento futuro disponível para este ator", + "no_content": "Nenhum conteúdo disponível para este ator", + "no_movies": "Nenhum filme disponível para este ator", + "no_tv": "Nenhuma série disponível para este ator", "no_info_available": "Nenhuma informação adicional disponível" }, "comments": { @@ -1090,7 +1111,7 @@ "clear_cache_desc": "Isso removerá a URL do repositório salvo e limpará todos os dados de plugins armazenados em cache. Você precisará digitar a URL do repositório novamente.", "add_new_repo": "Adicionar Novo Repositório", "available_plugins": "Plugins Disponíveis ({{count}})", - "search_placeholder": "Pesquisar plugins...", + "placeholder": "Pesquisar plugins...", "all": "Todos", "filter_all": "Todos Tipos", "filter_movies": "Filmes", diff --git a/src/screens/CastMoviesScreen.tsx b/src/screens/CastMoviesScreen.tsx index 87e397c..3b9d39b 100644 --- a/src/screens/CastMoviesScreen.tsx +++ b/src/screens/CastMoviesScreen.tsx @@ -1,4 +1,5 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; import { View, Text, @@ -59,6 +60,7 @@ type CastMoviesScreenRouteProp = RouteProp; const CastMoviesScreen: React.FC = () => { const { currentTheme } = useTheme(); + const { t } = useTranslation(); const navigation = useNavigation>(); const route = useRoute(); const { castMember } = route.params; @@ -89,27 +91,27 @@ const CastMoviesScreen: React.FC = () => { const fetchCastCredits = async () => { if (!castMember) return; - + setLoading(true); try { const credits = await tmdbService.getPersonCombinedCredits(castMember.id); - + if (credits && credits.cast) { const currentDate = new Date(); - + // Combine cast roles with enhanced data, excluding talk shows and variety shows const allCredits = credits.cast .filter((item: any) => { // Filter out talk shows, variety shows, and ensure we have required data const hasPoster = item.poster_path; const hasReleaseDate = item.release_date || item.first_air_date; - + if (!hasPoster || !hasReleaseDate) return false; - + // Enhanced talk show filtering const title = (item.title || item.name || '').toLowerCase(); const overview = (item.overview || '').toLowerCase(); - + // List of common talk show and variety show keywords const talkShowKeywords = [ 'talk', 'show', 'late night', 'tonight show', 'jimmy fallon', 'snl', 'saturday night live', @@ -120,18 +122,18 @@ const CastMoviesScreen: React.FC = () => { 'red carpet', 'premiere', 'after party', 'behind the scenes', 'making of', 'documentary', 'special', 'concert', 'live performance', 'mtv', 'vh1', 'bet', 'comedy', 'roast' ]; - + // Check if any keyword matches - const isTalkShow = talkShowKeywords.some(keyword => + const isTalkShow = talkShowKeywords.some(keyword => title.includes(keyword) || overview.includes(keyword) ); - + return !isTalkShow; }) .map((item: any) => { const releaseDate = new Date(item.release_date || item.first_air_date); const isUpcoming = releaseDate > currentDate; - + return { id: item.id, title: item.title || item.name, @@ -144,7 +146,7 @@ const CastMoviesScreen: React.FC = () => { isUpcoming, }; }); - + setMovies(allCredits); } } catch (error) { @@ -223,41 +225,41 @@ const CastMoviesScreen: React.FC = () => { isUpcoming: movie.isUpcoming }); } - + try { if (__DEV__) console.log('Attempting to get Stremio ID for:', movie.media_type, movie.id.toString()); - + // Get Stremio ID using catalogService const stremioId = await catalogService.getStremioId(movie.media_type, movie.id.toString()); - + if (__DEV__) console.log('Stremio ID result:', stremioId); - + if (stremioId) { if (__DEV__) console.log('Successfully found Stremio ID, navigating to Metadata with:', { id: stremioId, type: movie.media_type }); - + // Convert TMDB media type to Stremio media type const stremioType = movie.media_type === 'tv' ? 'series' : movie.media_type; - + if (__DEV__) console.log('Navigating with Stremio type conversion:', { originalType: movie.media_type, stremioType: stremioType, id: stremioId }); - + navigation.dispatch( - StackActions.push('Metadata', { - id: stremioId, - type: stremioType + StackActions.push('Metadata', { + id: stremioId, + type: stremioType }) ); } else { if (__DEV__) console.warn('Stremio ID is null/undefined for movie:', movie.title); throw new Error('Could not find Stremio ID'); } - } catch (error: any) { + } catch (error: any) { if (__DEV__) { console.error('=== Error in handleMoviePress ==='); console.error('Movie:', movie.title); @@ -265,9 +267,9 @@ const CastMoviesScreen: React.FC = () => { console.error('Error message:', error.message); console.error('Error stack:', error.stack); } - setAlertTitle('Error'); - setAlertMessage(`Unable to load "${movie.title}". Please try again later.`); - setAlertActions([{ label: 'OK', onPress: () => {} }]); + setAlertTitle(t('cast.alert_error_title')); + setAlertMessage(t('cast.alert_error_message', { title: movie.title })); + setAlertActions([{ label: t('cast.alert_ok'), onPress: () => { } }]); setAlertVisible(true); } }; @@ -278,7 +280,7 @@ const CastMoviesScreen: React.FC = () => { const renderFilterButton = (filter: 'all' | 'movies' | 'tv', label: string, count: number) => { const isSelected = selectedFilter === filter; - + return ( { paddingHorizontal: 18, paddingVertical: 10, borderRadius: 25, - backgroundColor: isSelected - ? currentTheme.colors.primary + backgroundColor: isSelected + ? currentTheme.colors.primary : 'rgba(255, 255, 255, 0.08)', marginRight: 12, borderWidth: isSelected ? 0 : 1, @@ -311,7 +313,7 @@ const CastMoviesScreen: React.FC = () => { const renderSortButton = (sort: 'popularity' | 'latest' | 'upcoming', label: string, icon: string) => { const isSelected = sortBy === sort; - + return ( { paddingHorizontal: 16, paddingVertical: 8, borderRadius: 20, - backgroundColor: isSelected - ? 'rgba(255, 255, 255, 0.15)' + backgroundColor: isSelected + ? 'rgba(255, 255, 255, 0.15)' : 'transparent', marginRight: 12, flexDirection: 'row', @@ -329,10 +331,10 @@ const CastMoviesScreen: React.FC = () => { onPress={() => setSortBy(sort)} activeOpacity={0.7} > - { )} - + {/* Upcoming indicator */} {item.isUpcoming && ( { marginLeft: 4, letterSpacing: 0.2, }}> - UPCOMING + {t('cast.upcoming_badge')} )} @@ -463,7 +465,7 @@ const CastMoviesScreen: React.FC = () => { }} /> - + { }} numberOfLines={2}> {`${item.title}`} - + {item.character && ( { marginTop: 3, fontWeight: '500', }} numberOfLines={1}> - {`as ${item.character}`} + {t('cast.as_character', { character: item.character })} )} - + { {`${new Date(item.release_date).getFullYear()}`} )} - + {item.isUpcoming && ( { marginLeft: 2, letterSpacing: 0.2, }}> - Coming Soon + {t('cast.coming_soon')} )} @@ -538,7 +540,7 @@ const CastMoviesScreen: React.FC = () => { [1, 0.9], Extrapolate.CLAMP ); - + return { opacity, }; @@ -547,7 +549,7 @@ const CastMoviesScreen: React.FC = () => { return ( {/* Minimal Header */} - { headerAnimatedStyle ]} > - @@ -579,7 +581,7 @@ const CastMoviesScreen: React.FC = () => { > - + { )} - + { fontWeight: '500', letterSpacing: 0.2, }}> - {`Filmography • ${movies.length} titles`} + {t('cast.filmography_count', { count: movies.length })} @@ -652,16 +654,16 @@ const CastMoviesScreen: React.FC = () => { letterSpacing: 0.5, textTransform: 'uppercase', }}> - Filter + {t('cast.filter')} - - {renderFilterButton('all', 'All', movies.length)} - {renderFilterButton('movies', 'Movies', movieCount)} - {renderFilterButton('tv', 'TV Shows', tvCount)} + {renderFilterButton('all', t('catalog.all'), movies.length)} + {renderFilterButton('movies', t('catalog.movies'), movieCount)} + {renderFilterButton('tv', t('catalog.tv_shows'), tvCount)} @@ -675,16 +677,16 @@ const CastMoviesScreen: React.FC = () => { letterSpacing: 0.5, textTransform: 'uppercase', }}> - Sort By + {t('cast.sort_by')} - - {renderSortButton('popularity', 'Popular', 'trending-up')} - {renderSortButton('latest', 'Latest', 'schedule')} - {renderSortButton('upcoming', 'Upcoming', 'event')} + {renderSortButton('popularity', t('cast.sort_popular'), 'trending-up')} + {renderSortButton('latest', t('cast.sort_latest'), 'schedule')} + {renderSortButton('upcoming', t('cast.sort_upcoming'), 'event')} @@ -703,7 +705,7 @@ const CastMoviesScreen: React.FC = () => { marginTop: 12, fontWeight: '500', }}> - Loading filmography... + {t('cast.loading_filmography')} ) : ( @@ -755,7 +757,7 @@ const CastMoviesScreen: React.FC = () => { fontSize: 14, fontWeight: '600', }}> - {`Load More (${filteredAndSortedMovies.length - displayLimit} remaining)`} + {t('cast.load_more_remaining', { count: filteredAndSortedMovies.length - displayLimit })} )} @@ -763,7 +765,7 @@ const CastMoviesScreen: React.FC = () => { ) : null } ListEmptyComponent={ - { marginBottom: 8, textAlign: 'center', }}> - No Content Found + {t('catalog.no_content_found')} { lineHeight: 20, fontWeight: '500', }}> - {sortBy === 'upcoming' - ? 'No upcoming releases available for this actor' - : selectedFilter === 'all' - ? 'No content available for this actor' + {sortBy === 'upcoming' + ? t('cast.no_upcoming') + : selectedFilter === 'all' + ? t('cast.no_content') : selectedFilter === 'movies' - ? 'No movies available for this actor' - : 'No TV shows available for this actor' + ? t('cast.no_movies') + : t('cast.no_tv') }