mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-20 16:22:04 +00:00
added Hindi
This commit is contained in:
parent
86f6bc4ae2
commit
77f5cb2b80
15 changed files with 1476 additions and 86 deletions
|
|
@ -8,5 +8,6 @@ export const LOCALES = [
|
||||||
{ code: 'it', key: 'italian' },
|
{ code: 'it', key: 'italian' },
|
||||||
{ code: 'es', key: 'spanish' },
|
{ code: 'es', key: 'spanish' },
|
||||||
{ code: 'hr', key: 'croatian' },
|
{ code: 'hr', key: 'croatian' },
|
||||||
{ code: 'zh-CN', key: 'chinese' }
|
{ code: 'zh-CN', key: 'chinese' },
|
||||||
|
{ code: 'hi', key: 'hindi' }
|
||||||
];
|
];
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "الإيطالية",
|
"italian": "الإيطالية",
|
||||||
"croatian": "الكرواتية",
|
"croatian": "الكرواتية",
|
||||||
"chinese": "الصينية (المبسطة)",
|
"chinese": "الصينية (المبسطة)",
|
||||||
|
"hindi": "الهندية",
|
||||||
"account": "الحساب",
|
"account": "الحساب",
|
||||||
"content_discovery": "المحتوى والاكتشاف",
|
"content_discovery": "المحتوى والاكتشاف",
|
||||||
"appearance": "المظهر",
|
"appearance": "المظهر",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Italienisch",
|
"italian": "Italienisch",
|
||||||
"croatian": "Kroatisch",
|
"croatian": "Kroatisch",
|
||||||
"chinese": "Chinesisch (Vereinfacht)",
|
"chinese": "Chinesisch (Vereinfacht)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Konto",
|
"account": "Konto",
|
||||||
"content_discovery": "Inhalt & Entdeckung",
|
"content_discovery": "Inhalt & Entdeckung",
|
||||||
"appearance": "Aussehen",
|
"appearance": "Aussehen",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Italian",
|
"italian": "Italian",
|
||||||
"croatian": "Croatian",
|
"croatian": "Croatian",
|
||||||
"chinese": "Chinese (Simplified)",
|
"chinese": "Chinese (Simplified)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"content_discovery": "Content & Discovery",
|
"content_discovery": "Content & Discovery",
|
||||||
"appearance": "Appearance",
|
"appearance": "Appearance",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Italiano",
|
"italian": "Italiano",
|
||||||
"croatian": "Croata",
|
"croatian": "Croata",
|
||||||
"chinese": "Chino (Simplificado)",
|
"chinese": "Chino (Simplificado)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Cuenta",
|
"account": "Cuenta",
|
||||||
"content_discovery": "Contenido y descubrimiento",
|
"content_discovery": "Contenido y descubrimiento",
|
||||||
"appearance": "Apariencia",
|
"appearance": "Apariencia",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Italien",
|
"italian": "Italien",
|
||||||
"croatian": "Croate",
|
"croatian": "Croate",
|
||||||
"chinese": "Chinois (Simplifié)",
|
"chinese": "Chinois (Simplifié)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Compte",
|
"account": "Compte",
|
||||||
"content_discovery": "Contenu et découverte",
|
"content_discovery": "Contenu et découverte",
|
||||||
"appearance": "Apparence",
|
"appearance": "Apparence",
|
||||||
|
|
|
||||||
1366
src/i18n/locales/hi.json
Normal file
1366
src/i18n/locales/hi.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Talijanski",
|
"italian": "Talijanski",
|
||||||
"croatian": "Hrvatski",
|
"croatian": "Hrvatski",
|
||||||
"chinese": "Kineski (Pojednostavljeni)",
|
"chinese": "Kineski (Pojednostavljeni)",
|
||||||
|
"hindi": "Hindski",
|
||||||
"account": "Račun",
|
"account": "Račun",
|
||||||
"content_discovery": "Sadržaj i otkrivanje",
|
"content_discovery": "Sadržaj i otkrivanje",
|
||||||
"appearance": "Izgled",
|
"appearance": "Izgled",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "Italiano",
|
"italian": "Italiano",
|
||||||
"croatian": "Croato",
|
"croatian": "Croato",
|
||||||
"chinese": "Cinese (Semplificato)",
|
"chinese": "Cinese (Semplificato)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"content_discovery": "Contenuti e Scoperta",
|
"content_discovery": "Contenuti e Scoperta",
|
||||||
"appearance": "Aspetto",
|
"appearance": "Aspetto",
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,7 @@
|
||||||
"italian": "Italiano",
|
"italian": "Italiano",
|
||||||
"croatian": "Croata",
|
"croatian": "Croata",
|
||||||
"chinese": "Chinês (Simplificado)",
|
"chinese": "Chinês (Simplificado)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Conta",
|
"account": "Conta",
|
||||||
"content_discovery": "Conteúdo e Descoberta",
|
"content_discovery": "Conteúdo e Descoberta",
|
||||||
"appearance": "Aparência",
|
"appearance": "Aparência",
|
||||||
|
|
|
||||||
|
|
@ -646,6 +646,7 @@
|
||||||
"italian": "Italiano",
|
"italian": "Italiano",
|
||||||
"croatian": "Croata",
|
"croatian": "Croata",
|
||||||
"chinese": "Chinês (Simplificado)",
|
"chinese": "Chinês (Simplificado)",
|
||||||
|
"hindi": "Hindi",
|
||||||
"account": "Conta",
|
"account": "Conta",
|
||||||
"content_discovery": "Conteúdo e Descoberta",
|
"content_discovery": "Conteúdo e Descoberta",
|
||||||
"appearance": "Aparência",
|
"appearance": "Aparência",
|
||||||
|
|
|
||||||
|
|
@ -632,6 +632,7 @@
|
||||||
"italian": "意大利语",
|
"italian": "意大利语",
|
||||||
"croatian": "克罗地亚语",
|
"croatian": "克罗地亚语",
|
||||||
"chinese": "简体中文",
|
"chinese": "简体中文",
|
||||||
|
"hindi": "印地语",
|
||||||
"account": "账户",
|
"account": "账户",
|
||||||
"content_discovery": "内容与发现",
|
"content_discovery": "内容与发现",
|
||||||
"appearance": "外观",
|
"appearance": "外观",
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import it from './locales/it.json';
|
||||||
import de from './locales/de.json';
|
import de from './locales/de.json';
|
||||||
|
|
||||||
import hr from './locales/hr.json';
|
import hr from './locales/hr.json';
|
||||||
|
import hi from './locales/hi.json';
|
||||||
import zhCN from './locales/zh-CN.json';
|
import zhCN from './locales/zh-CN.json';
|
||||||
|
|
||||||
export const resources = {
|
export const resources = {
|
||||||
|
|
@ -21,4 +22,5 @@ export const resources = {
|
||||||
de: { translation: de },
|
de: { translation: de },
|
||||||
hr: { translation: hr },
|
hr: { translation: hr },
|
||||||
'zh-CN': { translation: zhCN },
|
'zh-CN': { translation: zhCN },
|
||||||
|
hi: { translation: hi },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ const DonorCard: React.FC<DonorCardProps> = ({ donor, currentTheme, isTablet })
|
||||||
try {
|
try {
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
if (isNaN(date.getTime())) return dateString;
|
if (isNaN(date.getTime())) return dateString;
|
||||||
|
|
||||||
return date.toLocaleDateString(undefined, {
|
return date.toLocaleDateString(undefined, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: 'short',
|
month: 'short',
|
||||||
|
|
@ -333,7 +333,7 @@ const ContributorsScreen: React.FC = () => {
|
||||||
try {
|
try {
|
||||||
const date = new Date(dateString);
|
const date = new Date(dateString);
|
||||||
if (isNaN(date.getTime())) return dateString;
|
if (isNaN(date.getTime())) return dateString;
|
||||||
|
|
||||||
// Use locale-aware formatting
|
// Use locale-aware formatting
|
||||||
return date.toLocaleDateString(undefined, {
|
return date.toLocaleDateString(undefined, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
|
@ -382,15 +382,17 @@ const ContributorsScreen: React.FC = () => {
|
||||||
const sorted = Array.from(map.values()).sort((a, b) => b.total - a.total);
|
const sorted = Array.from(map.values()).sort((a, b) => b.total - a.total);
|
||||||
|
|
||||||
let lastTotal: number | null = null;
|
let lastTotal: number | null = null;
|
||||||
let lastRank = 0;
|
let currentRank = 0;
|
||||||
|
|
||||||
return sorted.map((entry, index) => {
|
return sorted.map((entry) => {
|
||||||
const rank = lastTotal !== null && entry.total === lastTotal ? lastRank : index + 1;
|
if (lastTotal === null || entry.total !== lastTotal) {
|
||||||
|
currentRank += 1;
|
||||||
|
}
|
||||||
lastTotal = entry.total;
|
lastTotal = entry.total;
|
||||||
lastRank = rank;
|
|
||||||
return {
|
return {
|
||||||
...entry,
|
...entry,
|
||||||
rank,
|
rank: currentRank,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}, [donations, getDonationTs]);
|
}, [donations, getDonationTs]);
|
||||||
|
|
@ -803,87 +805,87 @@ const ContributorsScreen: React.FC = () => {
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{donationsLoading ? (
|
{donationsLoading ? (
|
||||||
<View style={styles.loadingContainer}>
|
<View style={styles.loadingContainer}>
|
||||||
<ActivityIndicator size="large" color={currentTheme.colors.primary} />
|
<ActivityIndicator size="large" color={currentTheme.colors.primary} />
|
||||||
<Text style={[styles.loadingText, { color: currentTheme.colors.mediumEmphasis }]}>{t('contributors.loading_donors')}</Text>
|
<Text style={[styles.loadingText, { color: currentTheme.colors.mediumEmphasis }]}>{t('contributors.loading_donors')}</Text>
|
||||||
</View>
|
</View>
|
||||||
) : donationsError ? (
|
) : donationsError ? (
|
||||||
<View style={styles.errorContainer}>
|
<View style={styles.errorContainer}>
|
||||||
<Feather name="alert-circle" size={48} color={currentTheme.colors.mediumEmphasis} />
|
<Feather name="alert-circle" size={48} color={currentTheme.colors.mediumEmphasis} />
|
||||||
<Text style={[styles.errorText, { color: currentTheme.colors.mediumEmphasis }]}>
|
<Text style={[styles.errorText, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
{donationsError}
|
{donationsError}
|
||||||
</Text>
|
</Text>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.retryButton, { backgroundColor: currentTheme.colors.primary }]}
|
style={[styles.retryButton, { backgroundColor: currentTheme.colors.primary }]}
|
||||||
onPress={() => loadDonations(true)}
|
onPress={() => loadDonations(true)}
|
||||||
>
|
>
|
||||||
<Text style={[styles.retryText, { color: currentTheme.colors.white }]}>{t('common.retry')}</Text>
|
<Text style={[styles.retryText, { color: currentTheme.colors.white }]}>{t('common.retry')}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
) : donations.length === 0 ? (
|
) : donations.length === 0 ? (
|
||||||
<View style={styles.emptyContainer}>
|
<View style={styles.emptyContainer}>
|
||||||
<Feather name="gift" size={48} color={currentTheme.colors.mediumEmphasis} />
|
<Feather name="gift" size={48} color={currentTheme.colors.mediumEmphasis} />
|
||||||
<Text style={[styles.emptyText, { color: currentTheme.colors.mediumEmphasis }]}>{t('contributors.no_donors')}</Text>
|
<Text style={[styles.emptyText, { color: currentTheme.colors.mediumEmphasis }]}>{t('contributors.no_donors')}</Text>
|
||||||
</View>
|
</View>
|
||||||
|
) : (
|
||||||
|
donorsTab === 'latest' ? (
|
||||||
|
latestDonations.map((donor, index) => (
|
||||||
|
<DonorCard
|
||||||
|
key={`${donor.name}-${donor.date}-${index}`}
|
||||||
|
donor={donor}
|
||||||
|
currentTheme={currentTheme}
|
||||||
|
isTablet={isTablet}
|
||||||
|
/>
|
||||||
|
))
|
||||||
) : (
|
) : (
|
||||||
donorsTab === 'latest' ? (
|
leaderboardDonations.map((entry, index) => (
|
||||||
latestDonations.map((donor, index) => (
|
<View
|
||||||
<DonorCard
|
key={`${entry.name}-${entry.currency}-${index}`}
|
||||||
key={`${donor.name}-${donor.date}-${index}`}
|
style={[
|
||||||
donor={donor}
|
styles.leaderboardCard,
|
||||||
currentTheme={currentTheme}
|
{ backgroundColor: currentTheme.colors.elevation1 },
|
||||||
isTablet={isTablet}
|
isTablet && styles.tabletContributorCard
|
||||||
/>
|
]}
|
||||||
))
|
>
|
||||||
) : (
|
<View style={styles.leaderboardAvatar}>
|
||||||
leaderboardDonations.map((entry, index) => (
|
{getRankAnimation(entry.rank) ? (
|
||||||
<View
|
<View style={styles.leaderboardBadge}>
|
||||||
key={`${entry.name}-${entry.currency}-${index}`}
|
|
||||||
style={[
|
|
||||||
styles.leaderboardCard,
|
|
||||||
{ backgroundColor: currentTheme.colors.elevation1 },
|
|
||||||
isTablet && styles.tabletContributorCard
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<View style={styles.leaderboardAvatar}>
|
|
||||||
{getRankAnimation(entry.rank) ? (
|
|
||||||
<View style={styles.leaderboardBadge}>
|
|
||||||
<Text style={[styles.leaderboardRankText, { color: currentTheme.colors.white }]}>{entry.rank}</Text>
|
|
||||||
<LottieView
|
|
||||||
source={getRankAnimation(entry.rank)}
|
|
||||||
autoPlay
|
|
||||||
loop={false}
|
|
||||||
style={styles.leaderboardLottie}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<Text style={[styles.leaderboardRankText, { color: currentTheme.colors.white }]}>{entry.rank}</Text>
|
<Text style={[styles.leaderboardRankText, { color: currentTheme.colors.white }]}>{entry.rank}</Text>
|
||||||
)}
|
<LottieView
|
||||||
</View>
|
source={getRankAnimation(entry.rank)}
|
||||||
<View style={styles.contributorInfo}>
|
autoPlay
|
||||||
<Text style={[
|
loop={false}
|
||||||
styles.username,
|
style={styles.leaderboardLottie}
|
||||||
{ color: currentTheme.colors.highEmphasis },
|
/>
|
||||||
isTablet && styles.tabletUsername
|
</View>
|
||||||
]}>
|
) : (
|
||||||
{entry.name}
|
<Text style={[styles.leaderboardRankText, { color: currentTheme.colors.white }]}>{entry.rank}</Text>
|
||||||
</Text>
|
)}
|
||||||
<Text style={[
|
|
||||||
styles.donorAmount,
|
|
||||||
{ color: currentTheme.colors.mediumEmphasis },
|
|
||||||
isTablet && styles.tabletContributions
|
|
||||||
]}>
|
|
||||||
{entry.total.toFixed(2)} {entry.currency} · {entry.count} {entry.count === 1 ? 'donation' : 'donations'}
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.donorMessage, { color: currentTheme.colors.mediumEmphasis }]}>
|
|
||||||
Rank #{entry.rank} · Last: {formatDonationDate(entry.lastDate)}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
))
|
<View style={styles.contributorInfo}>
|
||||||
)
|
<Text style={[
|
||||||
)}
|
styles.username,
|
||||||
|
{ color: currentTheme.colors.highEmphasis },
|
||||||
|
isTablet && styles.tabletUsername
|
||||||
|
]}>
|
||||||
|
{entry.name}
|
||||||
|
</Text>
|
||||||
|
<Text style={[
|
||||||
|
styles.donorAmount,
|
||||||
|
{ color: currentTheme.colors.mediumEmphasis },
|
||||||
|
isTablet && styles.tabletContributions
|
||||||
|
]}>
|
||||||
|
{entry.total.toFixed(2)} {entry.currency} · {entry.count} {entry.count === 1 ? 'donation' : 'donations'}
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.donorMessage, { color: currentTheme.colors.mediumEmphasis }]}>
|
||||||
|
Rank #{entry.rank} · Last: {formatDonationDate(entry.lastDate)}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
) : activeTab === 'contributors' ? (
|
) : activeTab === 'contributors' ? (
|
||||||
// Contributors Tab
|
// Contributors Tab
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,15 @@ export const AboutSettingsContent: React.FC<AboutSettingsContentProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsCard title={t('settings.sections.information')} isTablet={isTablet}>
|
<SettingsCard title={t('settings.sections.information')} isTablet={isTablet}>
|
||||||
|
{isTablet && (
|
||||||
|
<SettingItem
|
||||||
|
title={t('contributors.title', 'Contributors')}
|
||||||
|
icon="users"
|
||||||
|
onPress={() => navigation.navigate('Contributors')}
|
||||||
|
renderControl={() => <ChevronRight />}
|
||||||
|
isTablet={isTablet}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={t('settings.items.legal')}
|
title={t('settings.items.legal')}
|
||||||
icon="file-text"
|
icon="file-text"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue