435 lines
15 KiB
TypeScript
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,
|
|
},
|
|
};
|
|
}
|