Files
hidden11/lib/i18n.ts
T
alexandrev-tibco fa04b20e30 Initial hidden11 MVP
2026-05-02 20:50:36 +02:00

435 lines
15 KiB
TypeScript

import type { Difficulty } from "./types";
export type Locale = "en" | "es" | "fr" | "de" | "it" | "pt";
export const SUPPORTED_LOCALES: { code: Locale; label: string }[] = [
{ code: "en", label: "EN" },
{ code: "es", label: "ES" },
{ code: "fr", label: "FR" },
{ code: "de", label: "DE" },
{ code: "it", label: "IT" },
{ code: "pt", label: "PT" },
];
export type Dictionary = {
allCompleted: string;
available: string;
browsePlayers: (position: string) => string;
close: string;
closeModal: string;
copied: string;
copy: string;
dailySubtitle: string;
difficulty: Record<Difficulty, string>;
exact: string;
fixed: string;
field: string;
hint: string;
hide: string;
locked: string;
miss: string;
noAttemptsLeft: string;
pickAndValidate: (position: string) => string;
playerListTitle: (position: string) => string;
playerSearch: string;
playersAvailable: (count: number) => string;
puzzle: string;
puzzleFinished: string;
searchPlaceholder: (position: string) => string;
select: string;
share: string;
shareLead: string;
stats: string;
statsLead: string;
streak: string;
maxStreak: string;
played: string;
perfectDays: string;
averageTime: string;
bestTime: string;
distribution: string;
solvePrevious: string;
solved: string;
time: string;
tries: string;
unlocked: (difficulty: string) => string;
validate: string;
reset: string;
reveal: string;
show: string;
left: (count: number) => string;
completeLineup: string;
attemptsRemaining: (count: number) => string;
clueTitle: string;
language: string;
noHintAvailable: string;
hintRevealed: (position: string) => string;
clue: Record<string, string>;
};
const dictionaries: Record<Locale, Dictionary> = {
en: {
allCompleted: "All puzzles completed.",
available: "available",
browsePlayers: (position) => `Browse all ${position} players`,
close: "Close",
closeModal: "Close player list",
copied: "Copied",
copy: "Copy",
dailySubtitle: "Daily five-player football puzzle",
difficulty: { easy: "Easy", medium: "Medium", hard: "Hard" },
exact: "Exact",
fixed: "fixed",
field: "Field",
hint: "Hint",
hide: "Hide",
locked: "locked",
miss: "Miss",
noAttemptsLeft: "No attempts left.",
pickAndValidate: (position) => `Pick a ${position} and validate the lineup.`,
playerListTitle: (position) => `${position} players`,
playerSearch: "Player search",
playersAvailable: (count) => `${count} available`,
puzzle: "Puzzle",
puzzleFinished: "Puzzle finished.",
searchPlaceholder: (position) => `Search player for ${position}`,
select: "Select",
share: "Share",
shareLead: "Daily result ready",
stats: "Stats",
statsLead: "Come back tomorrow to keep the streak alive.",
streak: "Streak",
maxStreak: "Best streak",
played: "Played",
perfectDays: "Perfect days",
averageTime: "Avg time",
bestTime: "Best time",
distribution: "Distribution",
solvePrevious: "Solve the previous puzzle to unlock this lineup.",
solved: "solved",
time: "Time",
tries: "tries",
unlocked: (difficulty) => `${difficulty} unlocked.`,
validate: "Validate",
reset: "Reset",
reveal: "Reveal",
show: "Show",
left: (count) => `${count} left`,
completeLineup: "Complete the lineup before validating.",
attemptsRemaining: (count) => `${count} attempts remaining.`,
clueTitle: "Clues",
language: "Language",
noHintAvailable: "No hints available.",
hintRevealed: (position) => `${position} revealed.`,
clue: {},
},
es: {
allCompleted: "Todos los puzzles completados.",
available: "disponible",
browsePlayers: (position) => `Ver todos los jugadores ${position}`,
close: "Cerca",
closeModal: "Cerrar lista de jugadores",
copied: "Copiado",
copy: "Copiar",
dailySubtitle: "Puzzle diario de fútbol de cinco jugadores",
difficulty: { easy: "Fácil", medium: "Medio", hard: "Difícil" },
exact: "Exacto",
fixed: "fijo",
field: "Campo",
hint: "Pista",
hide: "Ocultar",
locked: "bloqueado",
miss: "Fallo",
noAttemptsLeft: "No quedan intentos.",
pickAndValidate: (position) => `Elige un ${position} y valida la alineación.`,
playerListTitle: (position) => `Jugadores ${position}`,
playerSearch: "Buscar jugador",
playersAvailable: (count) => `${count} disponibles`,
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminado.",
searchPlaceholder: (position) => `Buscar jugador para ${position}`,
select: "Elegir",
share: "Compartir",
shareLead: "Resultado diario listo",
stats: "Stats",
statsLead: "Vuelve mañana para mantener la racha.",
streak: "Racha",
maxStreak: "Mejor racha",
played: "Jugados",
perfectDays: "Días perfectos",
averageTime: "Tiempo medio",
bestTime: "Mejor tiempo",
distribution: "Distribución",
solvePrevious: "Resuelve el puzzle anterior para desbloquear esta alineación.",
solved: "resuelto",
time: "Tiempo",
tries: "intentos",
unlocked: (difficulty) => `${difficulty} desbloqueado.`,
validate: "Validar",
reset: "Reset",
reveal: "Revelar",
show: "Mostrar",
left: (count) => `${count} restantes`,
completeLineup: "Completa la alineación antes de validar.",
attemptsRemaining: (count) => `Quedan ${count} intentos.`,
clueTitle: "Pistas",
language: "Idioma",
noHintAvailable: "No quedan pistas disponibles.",
hintRevealed: (position) => `${position} revelado.`,
clue: {
"Two players share the same club.": "Dos jugadores comparten club.",
"Four players play in England.": "Cuatro jugadores juegan en Inglaterra.",
"The striker is Norwegian.": "El delantero es noruego.",
"The winger is English.": "El extremo es inglés.",
"Three players are from Real Madrid.": "Tres jugadores son del Real Madrid.",
"The goalkeeper is Belgian.": "El portero es belga.",
"The winger is Brazilian.": "El extremo es brasileño.",
"The striker plays in Spain but not for Real Madrid.": "El delantero juega en España, pero no en el Real Madrid.",
"The revealed player plays in Spain.": "El jugador revelado juega en España.",
"Two players are current Premier League players.": "Dos jugadores juegan actualmente en la Premier League.",
"The defender is French.": "El defensa es francés.",
"The striker plays in Germany.": "El delantero juega en Alemania.",
"The midfielder plays for Napoli.": "El centrocampista juega en el Napoli.",
},
},
fr: {
allCompleted: "Tous les puzzles sont terminés.",
available: "disponible",
browsePlayers: (position) => `Voir tous les joueurs ${position}`,
close: "Proche",
closeModal: "Fermer la liste des joueurs",
copied: "Copié",
copy: "Copier",
dailySubtitle: "Puzzle football quotidien à cinq joueurs",
difficulty: { easy: "Facile", medium: "Moyen", hard: "Difficile" },
exact: "Exact",
fixed: "fixe",
field: "Terrain",
hint: "Indice",
hide: "Masquer",
locked: "verrouillé",
miss: "Raté",
noAttemptsLeft: "Plus d'essais.",
pickAndValidate: (position) => `Choisis un ${position} et valide l'équipe.`,
playerListTitle: (position) => `Joueurs ${position}`,
playerSearch: "Recherche joueur",
playersAvailable: (count) => `${count} disponibles`,
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminé.",
searchPlaceholder: (position) => `Chercher un joueur pour ${position}`,
select: "Choisir",
share: "Partager",
shareLead: "Résultat du jour prêt",
stats: "Stats",
statsLead: "Reviens demain pour garder ta série.",
streak: "Série",
maxStreak: "Meilleure série",
played: "Joués",
perfectDays: "Jours parfaits",
averageTime: "Temps moyen",
bestTime: "Meilleur temps",
distribution: "Distribution",
solvePrevious: "Résous le puzzle précédent pour déverrouiller cette équipe.",
solved: "résolu",
time: "Temps",
tries: "essais",
unlocked: (difficulty) => `${difficulty} déverrouillé.`,
validate: "Valider",
reset: "Reset",
reveal: "Révéler",
show: "Afficher",
left: (count) => `${count} restants`,
completeLineup: "Complète l'équipe avant de valider.",
attemptsRemaining: (count) => `${count} essais restants.`,
clueTitle: "Indices",
language: "Langue",
noHintAvailable: "Aucun indice disponible.",
hintRevealed: (position) => `${position} révélé.`,
clue: {},
},
de: {
allCompleted: "Alle Rätsel abgeschlossen.",
available: "verfügbar",
browsePlayers: (position) => `Alle ${position}-Spieler anzeigen`,
close: "Nah",
closeModal: "Spielerliste schließen",
copied: "Kopiert",
copy: "Kopieren",
dailySubtitle: "Tägliches Fußballrätsel mit fünf Spielern",
difficulty: { easy: "Leicht", medium: "Mittel", hard: "Schwer" },
exact: "Exakt",
fixed: "fix",
field: "Feld",
hint: "Tipp",
hide: "Ausblenden",
locked: "gesperrt",
miss: "Fehl",
noAttemptsLeft: "Keine Versuche übrig.",
pickAndValidate: (position) => `Wähle einen ${position} und prüfe die Aufstellung.`,
playerListTitle: (position) => `${position}-Spieler`,
playerSearch: "Spieler suchen",
playersAvailable: (count) => `${count} verfügbar`,
puzzle: "Puzzle",
puzzleFinished: "Rätsel beendet.",
searchPlaceholder: (position) => `Spieler für ${position} suchen`,
select: "Wählen",
share: "Teilen",
shareLead: "Tagesergebnis bereit",
stats: "Stats",
statsLead: "Komm morgen zurück, um die Serie zu halten.",
streak: "Serie",
maxStreak: "Beste Serie",
played: "Gespielt",
perfectDays: "Perfekte Tage",
averageTime: "Ø Zeit",
bestTime: "Beste Zeit",
distribution: "Verteilung",
solvePrevious: "Löse das vorherige Rätsel, um diese Aufstellung freizuschalten.",
solved: "gelöst",
time: "Zeit",
tries: "Versuche",
unlocked: (difficulty) => `${difficulty} freigeschaltet.`,
validate: "Prüfen",
reset: "Reset",
reveal: "Aufdecken",
show: "Anzeigen",
left: (count) => `${count} übrig`,
completeLineup: "Vervollständige die Aufstellung vor dem Prüfen.",
attemptsRemaining: (count) => `${count} Versuche übrig.`,
clueTitle: "Hinweise",
language: "Sprache",
noHintAvailable: "Keine Tipps verfügbar.",
hintRevealed: (position) => `${position} aufgedeckt.`,
clue: {},
},
it: {
allCompleted: "Tutti i puzzle completati.",
available: "disponibile",
browsePlayers: (position) => `Vedi tutti i giocatori ${position}`,
close: "Vicino",
closeModal: "Chiudi lista giocatori",
copied: "Copiato",
copy: "Copia",
dailySubtitle: "Puzzle calcistico quotidiano da cinque giocatori",
difficulty: { easy: "Facile", medium: "Medio", hard: "Difficile" },
exact: "Esatto",
fixed: "fisso",
field: "Campo",
hint: "Aiuto",
hide: "Nascondi",
locked: "bloccato",
miss: "Errore",
noAttemptsLeft: "Nessun tentativo rimasto.",
pickAndValidate: (position) => `Scegli un ${position} e valida la formazione.`,
playerListTitle: (position) => `Giocatori ${position}`,
playerSearch: "Cerca giocatore",
playersAvailable: (count) => `${count} disponibili`,
puzzle: "Puzzle",
puzzleFinished: "Puzzle finito.",
searchPlaceholder: (position) => `Cerca giocatore per ${position}`,
select: "Scegli",
share: "Condividi",
shareLead: "Risultato giornaliero pronto",
stats: "Stats",
statsLead: "Torna domani per mantenere la serie.",
streak: "Serie",
maxStreak: "Miglior serie",
played: "Giocati",
perfectDays: "Giorni perfetti",
averageTime: "Tempo medio",
bestTime: "Miglior tempo",
distribution: "Distribuzione",
solvePrevious: "Risolvi il puzzle precedente per sbloccare questa formazione.",
solved: "risolto",
time: "Tempo",
tries: "tentativi",
unlocked: (difficulty) => `${difficulty} sbloccato.`,
validate: "Valida",
reset: "Reset",
reveal: "Rivela",
show: "Mostra",
left: (count) => `${count} rimasti`,
completeLineup: "Completa la formazione prima di validare.",
attemptsRemaining: (count) => `${count} tentativi rimasti.`,
clueTitle: "Indizi",
language: "Lingua",
noHintAvailable: "Nessun aiuto disponibile.",
hintRevealed: (position) => `${position} rivelato.`,
clue: {},
},
pt: {
allCompleted: "Todos os puzzles concluídos.",
available: "disponível",
browsePlayers: (position) => `Ver todos os jogadores ${position}`,
close: "Perto",
closeModal: "Fechar lista de jogadores",
copied: "Copiado",
copy: "Copiar",
dailySubtitle: "Puzzle diário de futebol com cinco jogadores",
difficulty: { easy: "Fácil", medium: "Médio", hard: "Difícil" },
exact: "Exato",
fixed: "fixo",
field: "Campo",
hint: "Dica",
hide: "Ocultar",
locked: "bloqueado",
miss: "Falha",
noAttemptsLeft: "Sem tentativas restantes.",
pickAndValidate: (position) => `Escolhe um ${position} e valida o onze.`,
playerListTitle: (position) => `Jogadores ${position}`,
playerSearch: "Pesquisar jogador",
playersAvailable: (count) => `${count} disponíveis`,
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminado.",
searchPlaceholder: (position) => `Pesquisar jogador para ${position}`,
select: "Escolher",
share: "Partilhar",
shareLead: "Resultado diário pronto",
stats: "Stats",
statsLead: "Volta amanhã para manter a sequência.",
streak: "Sequência",
maxStreak: "Melhor sequência",
played: "Jogados",
perfectDays: "Dias perfeitos",
averageTime: "Tempo médio",
bestTime: "Melhor tempo",
distribution: "Distribuição",
solvePrevious: "Resolve o puzzle anterior para desbloquear este onze.",
solved: "resolvido",
time: "Tempo",
tries: "tentativas",
unlocked: (difficulty) => `${difficulty} desbloqueado.`,
validate: "Validar",
reset: "Reset",
reveal: "Revelar",
show: "Mostrar",
left: (count) => `${count} restantes`,
completeLineup: "Completa o onze antes de validar.",
attemptsRemaining: (count) => `${count} tentativas restantes.`,
clueTitle: "Pistas",
language: "Idioma",
noHintAvailable: "Sem dicas disponíveis.",
hintRevealed: (position) => `${position} revelado.`,
clue: {},
},
};
export function detectLocale(language?: string): Locale {
const code = language?.toLowerCase().split("-")[0];
if (code === "es" || code === "fr" || code === "de" || code === "it" || code === "pt") return code;
return "en";
}
export function getDictionary(locale: Locale): Dictionary {
const dictionary = dictionaries[locale];
const fallback = dictionaries.en;
return {
...fallback,
...dictionary,
clue: {
...fallback.clue,
...dictionary.clue,
},
};
}