first commit
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
import { Injectable, computed, signal } from '@angular/core';
|
||||
|
||||
export type LangCode = 'en' | 'fr';
|
||||
|
||||
// Simple key-value dictionaries. Extend as needed.
|
||||
const EN: Record<string, string> = {
|
||||
'app.name': 'NewTube',
|
||||
// Header
|
||||
'search.placeholder': 'Search...',
|
||||
'label.provider': 'Provider',
|
||||
'label.region': 'Region',
|
||||
// Regions
|
||||
'region.US': 'United States',
|
||||
'region.FR': 'France',
|
||||
'region.BR': 'Brazil',
|
||||
'region.DE': 'Germany',
|
||||
'region.GB': 'United Kingdom',
|
||||
'region.CA': 'Canada',
|
||||
'btn.edit': 'Edit',
|
||||
'btn.login': 'Login',
|
||||
'btn.register': 'Register',
|
||||
'menu.account': 'Account',
|
||||
'menu.preferences': 'Preferences',
|
||||
'menu.appearance': 'Appearance',
|
||||
'menu.logout': 'Logout',
|
||||
'theme.black': 'Black',
|
||||
'theme.dark': 'Dark',
|
||||
'theme.blue': 'Blue',
|
||||
'theme.light': 'Light',
|
||||
// Preferences
|
||||
'preferences.title': 'Preferences',
|
||||
'preferences.general': 'General',
|
||||
'preferences.general_hint': 'Customize your experience',
|
||||
'preferences.peertube_hint': 'Manage your PeerTube instances',
|
||||
'preferences.add_instance_placeholder': 'e.g. example.org',
|
||||
'preferences.no_instances': 'No instances yet.',
|
||||
'preferences.active': 'Active',
|
||||
'preferences.set_active': 'Set Active',
|
||||
'label.language': 'Language',
|
||||
'label.defaultProvider': 'Default Provider',
|
||||
'label.theme': 'Theme',
|
||||
'label.quality': 'Default Quality',
|
||||
'btn.save': 'Save',
|
||||
'btn.add': 'Add',
|
||||
'btn.remove': 'Remove',
|
||||
// Sidebar
|
||||
'nav.home': 'Home',
|
||||
'nav.shorts': 'Shorts',
|
||||
'nav.subscriptions': 'Subscriptions',
|
||||
'nav.you': 'You',
|
||||
'nav.history': 'History',
|
||||
'nav.playlists': 'Playlists',
|
||||
'nav.liked': 'Liked videos',
|
||||
'nav.explore': 'Explore',
|
||||
'explore.music': 'Music',
|
||||
'explore.gaming': 'Gaming',
|
||||
'explore.news': 'News',
|
||||
'explore.sports': 'Sports',
|
||||
'explore.learning': 'Learning',
|
||||
// Home
|
||||
'home.trending': 'Trending',
|
||||
'loading.more': 'Loading more...',
|
||||
'search.hint': 'Type something in the search bar to get started.',
|
||||
'search.noResults': 'No results found.',
|
||||
// Themes + Provider/Theme pages
|
||||
'themes.viewAll': 'View All',
|
||||
'themes.live': 'Live Streams',
|
||||
'themes.recorded': 'Recorded Streams',
|
||||
'themes.videos': 'Videos',
|
||||
'themes.categories': 'Categories',
|
||||
'themes.backToThemes': 'Back to themes',
|
||||
'themes.changeProvider': 'Change provider',
|
||||
// Common
|
||||
'common.error': 'An error occurred.',
|
||||
'empty.noItems': 'No items.',
|
||||
'common.more': 'More',
|
||||
'common.less': 'Less',
|
||||
// Filters
|
||||
'filter.sort': 'Sort by',
|
||||
'filter.sort.recent': 'Most recent',
|
||||
'filter.sort.viewed': 'Most viewed',
|
||||
'filter.sort.longest': 'Longest',
|
||||
'filter.duration': 'Duration',
|
||||
'filter.duration.any': 'Any',
|
||||
'filter.duration.short': 'Short (<10m)',
|
||||
'filter.duration.medium': 'Medium (10–30m)',
|
||||
'filter.duration.long': 'Long (30m+)',
|
||||
'filter.language': 'Language',
|
||||
'filter.date': 'Date',
|
||||
// Optional per-theme labels
|
||||
'theme.finance-crypto': 'Finance & Crypto',
|
||||
'theme.gaming': 'Gaming',
|
||||
'theme.news': 'News',
|
||||
'theme.sports': 'Sports',
|
||||
};
|
||||
|
||||
const FR: Record<string, string> = {
|
||||
'app.name': 'NewTube',
|
||||
// Header
|
||||
'search.placeholder': 'Rechercher...',
|
||||
'label.provider': 'Fournisseur',
|
||||
'label.region': 'Région',
|
||||
// Régions
|
||||
'region.US': 'États-Unis',
|
||||
'region.FR': 'France',
|
||||
'region.BR': 'Brésil',
|
||||
'region.DE': 'Allemagne',
|
||||
'region.GB': 'Royaume-Uni',
|
||||
'region.CA': 'Canada',
|
||||
'btn.edit': 'Modifier',
|
||||
'btn.login': 'Connexion',
|
||||
'btn.register': 'Inscription',
|
||||
'menu.account': 'Compte',
|
||||
'menu.preferences': 'Préférences',
|
||||
'menu.appearance': 'Apparence',
|
||||
'menu.logout': 'Déconnexion',
|
||||
'theme.black': 'Noir',
|
||||
'theme.dark': 'Sombre',
|
||||
'theme.blue': 'Bleu',
|
||||
'theme.light': 'Clair',
|
||||
// Preferences
|
||||
'preferences.title': 'Préférences',
|
||||
'preferences.general': 'Préférences générales',
|
||||
'preferences.general_hint': 'Personnalisez votre expérience',
|
||||
'preferences.peertube_hint': 'Gérez vos instances PeerTube',
|
||||
'preferences.add_instance_placeholder': 'ex: example.org',
|
||||
'preferences.no_instances': 'Aucune instance pour le moment.',
|
||||
'preferences.active': 'Actif',
|
||||
'preferences.set_active': 'Définir actif',
|
||||
'label.language': 'Langue',
|
||||
'label.defaultProvider': 'Fournisseur par défaut',
|
||||
'label.theme': 'Thème',
|
||||
'label.quality': 'Qualité par défaut',
|
||||
'btn.save': 'Enregistrer',
|
||||
'btn.add': 'Ajouter',
|
||||
'btn.remove': 'Supprimer',
|
||||
// Sidebar
|
||||
'nav.home': 'Accueil',
|
||||
'nav.shorts': 'Shorts',
|
||||
'nav.subscriptions': 'Abonnements',
|
||||
'nav.you': 'Vous',
|
||||
'nav.history': 'Historique',
|
||||
'nav.playlists': 'Listes de lecture',
|
||||
'nav.liked': 'Vidéos que vous aimez',
|
||||
'nav.explore': 'Explorer',
|
||||
'explore.music': 'Musique',
|
||||
'explore.gaming': 'Jeux vidéo',
|
||||
'explore.news': 'Actualités',
|
||||
'explore.sports': 'Sports',
|
||||
'explore.learning': 'Apprentissage',
|
||||
// Home
|
||||
'home.trending': 'Tendances',
|
||||
'loading.more': 'Chargement...',
|
||||
'search.hint': 'Tapez quelque chose dans la barre de recherche pour commencer.',
|
||||
'search.noResults': 'Aucun résultat.',
|
||||
// Themes + Provider/Theme pages
|
||||
'themes.viewAll': 'Voir tout',
|
||||
'themes.live': 'En direct',
|
||||
'themes.recorded': 'Rediffusions',
|
||||
'themes.videos': 'Vidéos',
|
||||
'themes.categories': 'Catégories',
|
||||
'themes.backToThemes': 'Retour aux thèmes',
|
||||
'themes.changeProvider': 'Changer de provider',
|
||||
// Common
|
||||
'common.error': 'Une erreur est survenue.',
|
||||
'empty.noItems': 'Aucun élément.',
|
||||
'common.more': 'Plus',
|
||||
'common.less': 'Moins',
|
||||
// Filters
|
||||
'filter.sort': 'Tri',
|
||||
'filter.sort.recent': 'Plus récents',
|
||||
'filter.sort.viewed': 'Plus vus',
|
||||
'filter.sort.longest': 'Plus longs',
|
||||
'filter.duration': 'Durée',
|
||||
'filter.duration.any': 'Toute',
|
||||
'filter.duration.short': 'Courte (<10m)',
|
||||
'filter.duration.medium': 'Moyenne (10–30m)',
|
||||
'filter.duration.long': 'Longue (30m+)',
|
||||
'filter.language': 'Langue',
|
||||
'filter.date': 'Date',
|
||||
// Optional per-theme labels
|
||||
'theme.finance-crypto': 'Finance & Crypto',
|
||||
'theme.gaming': 'Jeux vidéo',
|
||||
'theme.news': 'Actualités',
|
||||
'theme.sports': 'Sports',
|
||||
};
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class I18nService {
|
||||
private readonly LS_KEY = 'newtube.lang';
|
||||
private readonly dictionaries: Record<string, Record<string, string>> = { en: EN, fr: FR };
|
||||
private readonly defaultLang: LangCode = 'en';
|
||||
|
||||
// initialize from localStorage, fallback 'en'
|
||||
lang = signal<LangCode>((() => {
|
||||
try {
|
||||
const ls = (localStorage.getItem(this.LS_KEY) || '').toLowerCase();
|
||||
return (ls === 'fr' ? 'fr' : 'en') as LangCode;
|
||||
} catch {
|
||||
return 'en';
|
||||
}
|
||||
})());
|
||||
|
||||
readonly currentDict = computed(() => this.dictionaries[this.lang()] || this.dictionaries[this.defaultLang]);
|
||||
|
||||
constructor() {
|
||||
try {
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.setAttribute('lang', this.lang());
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
setLanguage(l: string | null | undefined) {
|
||||
const v = (String(l || '').toLowerCase() === 'fr') ? 'fr' : 'en';
|
||||
this.lang.set(v as LangCode);
|
||||
try {
|
||||
localStorage.setItem(this.LS_KEY, v);
|
||||
if (typeof document !== 'undefined') {
|
||||
document.documentElement.setAttribute('lang', v);
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
t(key: string, params?: Record<string, any>): string {
|
||||
const dict = this.currentDict();
|
||||
const base = dict[key] ?? this.dictionaries[this.defaultLang][key] ?? key;
|
||||
if (params) {
|
||||
return Object.keys(params).reduce((acc, k) => acc.replace(new RegExp('{' + k + '}', 'g'), String(params[k])), base);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user