Files
hidden11/lib/i18n.ts
T
alexandrev-tibco 2a8d055da3
Build and push image / build (push) Successful in 1m19s
Fix Close label translation and replace liga with campeonato in clues
- Fix feedback color label: Close → Cerca/Proche/Nah/Vicino/Perto
  in all non-English locales (was using the verb "to close" instead
  of "near/close")
- Replace "liga/ligas" with "campeonato/campeonatos" in all ES
  translations that refer to league titles, to avoid confusion with
  the competition name LaLiga
- Add new player fields (ballonDOr, goldenBoot, worldCupWinner,
  copaAmericaWinner, eurocupWinner) and rework clue generation with
  difficulty-aware mixing (easy=all direct, medium=2 direct+2 harder,
  hard=1 direct+2 medium+comparisons)
- Add new clue types: club, trophy (World Cup/Euro/Copa), award
  (Ballon d'Or/Golden Boot), with full i18n support in 6 languages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 07:18:58 +02:00

1194 lines
52 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;
copyLink: string;
feedback: string;
feedbackType: string;
feedbackMessage: string;
feedbackPlaceholder: string;
feedbackSend: string;
feedbackSuccess: string;
feedbackError: string;
feedbackBug: string;
feedbackSuggestion: string;
feedbackGeneral: string;
dailySubtitle: string;
difficulty: Record<Difficulty, string>;
exact: string;
fixed: string;
field: string;
hint: string;
hide: string;
locked: string;
miss: string;
noAttemptsLeft: string;
onboardingEyebrow: string;
onboardingLead: string;
onboardingStepOne: string;
onboardingStepOneTitle: string;
onboardingStepThree: string;
onboardingStepThreeTitle: string;
onboardingStepTwo: string;
onboardingStepTwoTitle: string;
onboardingTitle: string;
pickAndValidate: (position: string) => string;
playerListTitle: (position: string) => string;
playerSearch: string;
playersAvailable: (count: number) => string;
playToday: string;
puzzle: string;
puzzleFinished: string;
searchPlaceholder: (position: string) => string;
select: string;
showSolution: string;
share: string;
challengeFriend: string;
challengeShareLead: string;
completedTitle: string;
completedPerfect: string;
completedPartial: string;
firstMoveLead: string;
firstMoveTitle: string;
resultSummary: string;
shareLead: string;
shareNow: string;
stats: string;
statsLead: string;
streak: string;
maxStreak: string;
played: string;
perfectDays: string;
averageTime: string;
bestTime: string;
distribution: string;
solvePrevious: string;
solutionRevealed: 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",
copyLink: "Copy link",
feedback: "Feedback",
feedbackType: "Type",
feedbackMessage: "Message",
feedbackPlaceholder: "Tell us what should change, what broke, or what you'd like next.",
feedbackSend: "Send feedback",
feedbackSuccess: "Thanks. Feedback sent.",
feedbackError: "Could not send feedback. Try again.",
feedbackBug: "Bug",
feedbackSuggestion: "Suggestion",
feedbackGeneral: "General",
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.",
onboardingEyebrow: "Daily football puzzle",
onboardingLead: "Use the clues to complete a hidden five-player lineup before the attempts run out.",
onboardingStepOne: "Pick one player for each position around the pitch.",
onboardingStepOneTitle: "Build the XI",
onboardingStepThree: "Clear Easy to unlock Medium, then finish Hard.",
onboardingStepThreeTitle: "Beat all levels",
onboardingStepTwo: "Green is exact, yellow is close, black is a miss.",
onboardingStepTwoTitle: "Read the result",
onboardingTitle: "Find the hidden lineup",
pickAndValidate: (position) => `Pick a ${position} and validate the lineup.`,
playerListTitle: (position) => `${position} players`,
playerSearch: "Player search",
playersAvailable: (count) => `${count} available`,
playToday: "Play today",
puzzle: "Puzzle",
puzzleFinished: "Puzzle finished.",
searchPlaceholder: (position) => `Search player for ${position}`,
select: "Select",
showSolution: "Show solution",
share: "Share",
challengeFriend: "Challenge a friend",
challengeShareLead: "I played today's hidden11. Can you beat me?",
completedTitle: "Daily result ready",
completedPerfect: "Perfect day. All three levels cleared.",
completedPartial: "Day finished. Share the score and come back tomorrow.",
firstMoveLead: "Pick a player, validate the lineup, and use the colors to narrow it down.",
firstMoveTitle: "Start today's puzzle",
resultSummary: "Today's result",
shareLead: "Daily result ready",
shareNow: "Share now",
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.",
solutionRevealed: "Solution revealed.",
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",
copyLink: "Copiar enlace",
feedback: "Feedback",
feedbackType: "Tipo",
feedbackMessage: "Mensaje",
feedbackPlaceholder: "Cuéntanos qué habría que cambiar, qué falla o qué te gustaría ver.",
feedbackSend: "Enviar feedback",
feedbackSuccess: "Gracias. Feedback enviado.",
feedbackError: "No se ha podido enviar el feedback. Prueba otra vez.",
feedbackBug: "Error",
feedbackSuggestion: "Sugerencia",
feedbackGeneral: "General",
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.",
onboardingEyebrow: "Puzzle diario de fútbol",
onboardingLead: "Usa las pistas para completar una alineación oculta de cinco jugadores antes de quedarte sin intentos.",
onboardingStepOne: "Elige un jugador para cada posición del campo.",
onboardingStepOneTitle: "Construye el XI",
onboardingStepThree: "Supera Fácil para desbloquear Medio y termina Difícil.",
onboardingStepThreeTitle: "Completa los niveles",
onboardingStepTwo: "Verde es exacto, amarillo es cerca y negro es fallo.",
onboardingStepTwoTitle: "Lee el resultado",
onboardingTitle: "Encuentra la alineación oculta",
pickAndValidate: (position) => `Elige un ${position} y valida la alineación.`,
playerListTitle: (position) => `Jugadores ${position}`,
playerSearch: "Buscar jugador",
playersAvailable: (count) => `${count} disponibles`,
playToday: "Jugar hoy",
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminado.",
searchPlaceholder: (position) => `Buscar jugador para ${position}`,
select: "Elegir",
showSolution: "Ver solución",
share: "Compartir",
challengeFriend: "Retar a un amigo",
challengeShareLead: "He jugado al hidden11 de hoy. ¿Puedes superarme?",
completedTitle: "Resultado diario listo",
completedPerfect: "Día perfecto. Los tres niveles completados.",
completedPartial: "Día terminado. Comparte tu resultado y vuelve mañana.",
firstMoveLead: "Elige un jugador, valida la alineación y usa los colores para ajustar.",
firstMoveTitle: "Empieza el puzzle de hoy",
resultSummary: "Resultado de hoy",
shareLead: "Resultado diario listo",
shareNow: "Compartir ahora",
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.",
solutionRevealed: "Solución revelada.",
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.",
"The goalkeeper and striker have both won league titles in Spain.": "El portero y el delantero han ganado campeonatos en España.",
"The defender and winger have both won league titles in Germany.": "El defensa y el extremo han ganado campeonatos en Alemania.",
"The winger and striker were once teammates at Juventus.": "El extremo y el delantero coincidieron en la Juventus.",
"The midfielder has played league football in Austria, Germany and England.": "El centrocampista ha jugado en liga en Austria, Alemania e Inglaterra.",
"The goalkeeper and defender have both won league titles in Portugal.": "El portero y el defensa han ganado campeonatos en Portugal.",
"The defender has won league titles in Portugal and Germany.": "El defensa ha ganado campeonatos en Portugal y Alemania.",
"The midfielder has won league titles in Italy and France.": "El centrocampista ha ganado campeonatos en Italia y Francia.",
"The winger and midfielder both moved to France after starring in Italy.": "El extremo y el centrocampista llegaron a Francia después de destacar en Italia.",
"The striker was the top scorer in France before moving to Italy.": "El delantero fue máximo goleador en Francia antes de irse a Italia.",
},
},
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",
copyLink: "Copier le lien",
feedback: "Feedback",
feedbackType: "Type",
feedbackMessage: "Message",
feedbackPlaceholder: "Dites-nous ce qu'il faut changer, ce qui casse, ou ce que vous voulez voir ensuite.",
feedbackSend: "Envoyer",
feedbackSuccess: "Merci. Feedback envoyé.",
feedbackError: "Impossible d'envoyer le feedback. Réessayez.",
feedbackBug: "Bug",
feedbackSuggestion: "Suggestion",
feedbackGeneral: "Général",
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.",
onboardingEyebrow: "Puzzle football quotidien",
onboardingLead: "Utilise les indices pour compléter une équipe cachée de cinq joueurs avant la fin des essais.",
onboardingStepOne: "Choisis un joueur pour chaque position du terrain.",
onboardingStepOneTitle: "Construis le XI",
onboardingStepThree: "Termine Facile pour déverrouiller Moyen, puis finis Difficile.",
onboardingStepThreeTitle: "Bats les niveaux",
onboardingStepTwo: "Vert est exact, jaune est proche, noir est raté.",
onboardingStepTwoTitle: "Lis le résultat",
onboardingTitle: "Trouve l'équipe cachée",
pickAndValidate: (position) => `Choisis un ${position} et valide l'équipe.`,
playerListTitle: (position) => `Joueurs ${position}`,
playerSearch: "Recherche joueur",
playersAvailable: (count) => `${count} disponibles`,
playToday: "Jouer aujourd'hui",
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminé.",
searchPlaceholder: (position) => `Chercher un joueur pour ${position}`,
select: "Choisir",
showSolution: "Voir la solution",
share: "Partager",
challengeFriend: "Défier un ami",
challengeShareLead: "J'ai joué au hidden11 du jour. Peux-tu faire mieux ?",
completedTitle: "Résultat du jour prêt",
completedPerfect: "Journée parfaite. Les trois niveaux terminés.",
completedPartial: "Journée terminée. Partage ton score et reviens demain.",
firstMoveLead: "Choisis un joueur, valide l'équipe et utilise les couleurs pour progresser.",
firstMoveTitle: "Commence le puzzle du jour",
resultSummary: "Résultat du jour",
shareLead: "Résultat du jour prêt",
shareNow: "Partager",
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.",
solutionRevealed: "Solution révélée.",
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",
copyLink: "Link kopieren",
feedback: "Feedback",
feedbackType: "Typ",
feedbackMessage: "Nachricht",
feedbackPlaceholder: "Sag uns, was geändert werden soll, was kaputt ist oder was du dir wünschst.",
feedbackSend: "Feedback senden",
feedbackSuccess: "Danke. Feedback gesendet.",
feedbackError: "Feedback konnte nicht gesendet werden. Bitte erneut versuchen.",
feedbackBug: "Fehler",
feedbackSuggestion: "Vorschlag",
feedbackGeneral: "Allgemein",
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.",
onboardingEyebrow: "Tägliches Fußballrätsel",
onboardingLead: "Nutze die Hinweise, um eine versteckte Fünfer-Aufstellung zu lösen, bevor die Versuche weg sind.",
onboardingStepOne: "Wähle einen Spieler für jede Position auf dem Feld.",
onboardingStepOneTitle: "Baue das XI",
onboardingStepThree: "Löse Leicht, um Mittel freizuschalten, und beende Schwer.",
onboardingStepThreeTitle: "Schlage alle Stufen",
onboardingStepTwo: "Grün ist exakt, gelb ist nah, schwarz ist falsch.",
onboardingStepTwoTitle: "Lies das Ergebnis",
onboardingTitle: "Finde die versteckte Aufstellung",
pickAndValidate: (position) => `Wähle einen ${position} und prüfe die Aufstellung.`,
playerListTitle: (position) => `${position}-Spieler`,
playerSearch: "Spieler suchen",
playersAvailable: (count) => `${count} verfügbar`,
playToday: "Heute spielen",
puzzle: "Puzzle",
puzzleFinished: "Rätsel beendet.",
searchPlaceholder: (position) => `Spieler für ${position} suchen`,
select: "Wählen",
showSolution: "Lösung anzeigen",
share: "Teilen",
challengeFriend: "Freund herausfordern",
challengeShareLead: "Ich habe das heutige hidden11 gespielt. Schaffst du mehr?",
completedTitle: "Tagesergebnis bereit",
completedPerfect: "Perfekter Tag. Alle drei Stufen geschafft.",
completedPartial: "Tag beendet. Teile dein Ergebnis und komm morgen zurück.",
firstMoveLead: "Wähle einen Spieler, prüfe die Aufstellung und nutze die Farben.",
firstMoveTitle: "Starte das heutige Rätsel",
resultSummary: "Heutiges Ergebnis",
shareLead: "Tagesergebnis bereit",
shareNow: "Jetzt teilen",
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.",
solutionRevealed: "Lösung angezeigt.",
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",
copyLink: "Copia link",
feedback: "Feedback",
feedbackType: "Tipo",
feedbackMessage: "Messaggio",
feedbackPlaceholder: "Dicci cosa va cambiato, cosa non funziona o cosa vorresti vedere.",
feedbackSend: "Invia feedback",
feedbackSuccess: "Grazie. Feedback inviato.",
feedbackError: "Impossibile inviare il feedback. Riprova.",
feedbackBug: "Bug",
feedbackSuggestion: "Suggerimento",
feedbackGeneral: "Generale",
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.",
onboardingEyebrow: "Puzzle calcistico quotidiano",
onboardingLead: "Usa gli indizi per completare una formazione nascosta di cinque giocatori prima di finire i tentativi.",
onboardingStepOne: "Scegli un giocatore per ogni posizione in campo.",
onboardingStepOneTitle: "Costruisci l'XI",
onboardingStepThree: "Completa Facile per sbloccare Medio, poi finisci Difficile.",
onboardingStepThreeTitle: "Batti i livelli",
onboardingStepTwo: "Verde è esatto, giallo è vicino, nero è errore.",
onboardingStepTwoTitle: "Leggi il risultato",
onboardingTitle: "Trova la formazione nascosta",
pickAndValidate: (position) => `Scegli un ${position} e valida la formazione.`,
playerListTitle: (position) => `Giocatori ${position}`,
playerSearch: "Cerca giocatore",
playersAvailable: (count) => `${count} disponibili`,
playToday: "Gioca oggi",
puzzle: "Puzzle",
puzzleFinished: "Puzzle finito.",
searchPlaceholder: (position) => `Cerca giocatore per ${position}`,
select: "Scegli",
showSolution: "Mostra soluzione",
share: "Condividi",
challengeFriend: "Sfida un amico",
challengeShareLead: "Ho giocato all'hidden11 di oggi. Riesci a battermi?",
completedTitle: "Risultato giornaliero pronto",
completedPerfect: "Giornata perfetta. Tutti e tre i livelli completati.",
completedPartial: "Giornata finita. Condividi il risultato e torna domani.",
firstMoveLead: "Scegli un giocatore, valida la formazione e usa i colori.",
firstMoveTitle: "Inizia il puzzle di oggi",
resultSummary: "Risultato di oggi",
shareLead: "Risultato giornaliero pronto",
shareNow: "Condividi ora",
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.",
solutionRevealed: "Soluzione rivelata.",
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",
copyLink: "Copiar link",
feedback: "Feedback",
feedbackType: "Tipo",
feedbackMessage: "Mensagem",
feedbackPlaceholder: "Diz-nos o que deve mudar, o que está a falhar ou o que queres ver a seguir.",
feedbackSend: "Enviar feedback",
feedbackSuccess: "Obrigado. Feedback enviado.",
feedbackError: "Não foi possível enviar o feedback. Tenta outra vez.",
feedbackBug: "Erro",
feedbackSuggestion: "Sugestão",
feedbackGeneral: "Geral",
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.",
onboardingEyebrow: "Puzzle diário de futebol",
onboardingLead: "Usa as pistas para completar um onze escondido de cinco jogadores antes de ficares sem tentativas.",
onboardingStepOne: "Escolhe um jogador para cada posição no campo.",
onboardingStepOneTitle: "Constrói o XI",
onboardingStepThree: "Termina Fácil para desbloquear Médio, depois acaba Difícil.",
onboardingStepThreeTitle: "Vence os níveis",
onboardingStepTwo: "Verde é exato, amarelo é perto, preto é falha.",
onboardingStepTwoTitle: "Lê o resultado",
onboardingTitle: "Encontra o onze escondido",
pickAndValidate: (position) => `Escolhe um ${position} e valida o onze.`,
playerListTitle: (position) => `Jogadores ${position}`,
playerSearch: "Pesquisar jogador",
playersAvailable: (count) => `${count} disponíveis`,
playToday: "Jogar hoje",
puzzle: "Puzzle",
puzzleFinished: "Puzzle terminado.",
searchPlaceholder: (position) => `Pesquisar jogador para ${position}`,
select: "Escolher",
showSolution: "Ver solução",
share: "Partilhar",
challengeFriend: "Desafiar um amigo",
challengeShareLead: "Joguei o hidden11 de hoje. Consegues superar-me?",
completedTitle: "Resultado diário pronto",
completedPerfect: "Dia perfeito. Os três níveis concluídos.",
completedPartial: "Dia terminado. Partilha o resultado e volta amanhã.",
firstMoveLead: "Escolhe um jogador, valida o onze e usa as cores para ajustar.",
firstMoveTitle: "Começa o puzzle de hoje",
resultSummary: "Resultado de hoje",
shareLead: "Resultado diário pronto",
shareNow: "Partilhar agora",
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.",
solutionRevealed: "Solução revelada.",
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: createClueDictionary(locale, {
...fallback.clue,
...dictionary.clue,
}),
};
}
function createClueDictionary(locale: Locale, overrides: Record<string, string>): Record<string, string> {
return new Proxy(overrides, {
get(target, property) {
if (typeof property !== "string") {
return undefined;
}
return target[property] ?? translateGeneratedClue(property, locale);
},
});
}
function translateGeneratedClue(clue: string, locale: Locale): string {
if (locale === "en") {
return clue;
}
const playsFor = clue.match(/^The (.+) plays for (.+)\.$/);
if (playsFor) {
return tPlaysFor(locale, playsFor[1], playsFor[2]);
}
const wonWorldCup = clue.match(/^The (.+) has won the World Cup\.$/);
if (wonWorldCup) {
return tWonWorldCup(locale, wonWorldCup[1]);
}
const wonEuro = clue.match(/^The (.+) has won the European Championship\.$/);
if (wonEuro) {
return tWonEuro(locale, wonEuro[1]);
}
const wonCopa = clue.match(/^The (.+) has won the Copa América\.$/);
if (wonCopa) {
return tWonCopaAmerica(locale, wonCopa[1]);
}
const wonBallonDOr = clue.match(/^The (.+) has won the Ballon d'Or\.$/);
if (wonBallonDOr) {
return tWonBallonDOr(locale, wonBallonDOr[1]);
}
const wonGoldenBootMultiple = clue.match(/^The (.+) has won (\d+) European Golden Boots\.$/);
if (wonGoldenBootMultiple) {
return tWonGoldenBoots(locale, wonGoldenBootMultiple[1], Number(wonGoldenBootMultiple[2]));
}
const wonGoldenBoot = clue.match(/^The (.+) has won the European Golden Boot\.$/);
if (wonGoldenBoot) {
return tWonGoldenBoots(locale, wonGoldenBoot[1], 1);
}
const playForSameClub = clue.match(/^The (.+) and (.+) play for the same club\.$/);
if (playForSameClub) {
return tPlayForSameClub(locale, playForSameClub[1], playForSameClub[2]);
}
const sharedClub = clue.match(/^(\d+|Two) players share the same club\.$/);
if (sharedClub) {
const count = sharedClub[1] === "Two" ? 2 : Number(sharedClub[1]);
return tSharedClub(locale, count);
}
const leagueCount = clue.match(/^(\d+) players? play in (.+)\.$/);
if (leagueCount) {
return tLeagueCount(locale, Number(leagueCount[1]), leagueCount[2]);
}
const outsideTopFive = clue.match(/^The (.+) plays outside the top five leagues\.$/);
if (outsideTopFive) {
return tOutsideTopFive(locale, outsideTopFive[1]);
}
const positionLeague = clue.match(/^The (.+) plays in (.+)\.$/);
if (positionLeague) {
return tPositionLeague(locale, positionLeague[1], positionLeague[2]);
}
const positionRegion = clue.match(/^The (.+) comes from (.+)\.$/);
if (positionRegion) {
return tPositionRegion(locale, positionRegion[1], positionRegion[2]);
}
const differentClubs = clue.match(/^All five players come from different clubs\.$/);
if (differentClubs) {
return tAllDifferentClubs(locale);
}
const moreChampions = clue.match(/^The (.+) has more Champions League titles than the (.+)\.$/);
if (moreChampions) {
return tMoreChampions(locale, moreChampions[1], moreChampions[2]);
}
const sameChampions = clue.match(/^The (.+) and (.+) have won the same number of Champions League titles\.$/);
if (sameChampions) {
return tSameChampions(locale, sameChampions[1], sameChampions[2]);
}
const wonLeagueTitles = clue.match(/^The (.+) has won (\d+) league titles?\.$/);
if (wonLeagueTitles) {
return tWonLeagueTitles(locale, wonLeagueTitles[1], Number(wonLeagueTitles[2]));
}
const noLeagueTitle = clue.match(/^The (.+) has not won a league title\.$/);
if (noLeagueTitle) {
return tNoLeagueTitle(locale, noLeagueTitle[1]);
}
const atMostLeagueTitles = clue.match(/^The (.+) has won at most 2 league titles\.$/);
if (atMostLeagueTitles) {
return tAtMostLeagueTitles(locale, atMostLeagueTitles[1], 2);
}
const betweenLeagueTitles = clue.match(/^The (.+) has won between 3 and 5 league titles\.$/);
if (betweenLeagueTitles) {
return tBetweenLeagueTitles(locale, betweenLeagueTitles[1], 3, 5);
}
const moreThanLeagueTitles = clue.match(/^The (.+) has won more than 5 league titles\.$/);
if (moreThanLeagueTitles) {
return tMoreThanLeagueTitles(locale, moreThanLeagueTitles[1], 5);
}
const wonChampionsTitles = clue.match(/^The (.+) has won (\d+) Champions League titles?\.$/);
if (wonChampionsTitles) {
return tWonChampionsTitles(locale, wonChampionsTitles[1], Number(wonChampionsTitles[2]));
}
const wonCountries = clue.match(/^The (.+) has won league titles in (.+)\.$/);
if (wonCountries) {
return tWonCountries(locale, wonCountries[1], wonCountries[2]);
}
const bothTopFlight = clue.match(/^The (.+) and (.+) both have played in top-flight football\.$/);
if (bothTopFlight) {
return tBothTopFlight(locale, bothTopFlight[1], bothTopFlight[2]);
}
const teammates = clue.match(/^The (.+) and (.+) were once teammates at (.+)\.$/);
if (teammates) {
return tTeammates(locale, teammates[1], teammates[2], teammates[3]);
}
const sameLeagueTitles = clue.match(/^The (.+) and (.+) have won the same number of league titles\.$/);
if (sameLeagueTitles) {
return tSameLeagueTitles(locale, sameLeagueTitles[1], sameLeagueTitles[2]);
}
const moreLeagueTitles = clue.match(/^The (.+) has more league titles than the (.+)\.$/);
if (moreLeagueTitles) {
return tMoreLeagueTitles(locale, moreLeagueTitles[1], moreLeagueTitles[2]);
}
const nationality = clue.match(/^The (.+) is from (.+)\.$/);
if (nationality) {
return tNationality(locale, nationality[1], nationality[2]);
}
return clue;
}
const positionTranslations: Record<Locale, Record<string, string>> = {
en: { defender: "defender", goalkeeper: "goalkeeper", midfielder: "midfielder", striker: "striker", winger: "winger" },
es: { defender: "defensa", goalkeeper: "portero", midfielder: "centrocampista", striker: "delantero", winger: "extremo" },
fr: { defender: "défenseur", goalkeeper: "gardien", midfielder: "milieu", striker: "attaquant", winger: "ailier" },
de: { defender: "Verteidiger", goalkeeper: "Torwart", midfielder: "Mittelfeldspieler", striker: "Stürmer", winger: "Flügelspieler" },
it: { defender: "difensore", goalkeeper: "portiere", midfielder: "centrocampista", striker: "attaccante", winger: "ala" },
pt: { defender: "defesa", goalkeeper: "guarda-redes", midfielder: "médio", striker: "avançado", winger: "extremo" },
};
const countryTranslations: Record<Locale, Record<string, string>> = {
en: {},
es: {
Argentina: "Argentina",
Austria: "Austria",
Belgium: "Bélgica",
Brazil: "Brasil",
Canada: "Canadá",
Croatia: "Croacia",
England: "Inglaterra",
France: "Francia",
Georgia: "Georgia",
Germany: "Alemania",
Italy: "Italia",
Netherlands: "Países Bajos",
Norway: "Noruega",
Poland: "Polonia",
Portugal: "Portugal",
Scotland: "Escocia",
Spain: "España",
Sweden: "Suecia",
Switzerland: "Suiza",
Ukraine: "Ucrania",
},
fr: {
Argentina: "Argentine",
Austria: "Autriche",
Belgium: "Belgique",
Brazil: "Brésil",
Canada: "Canada",
Croatia: "Croatie",
England: "Angleterre",
France: "France",
Georgia: "Géorgie",
Germany: "Allemagne",
Italy: "Italie",
Netherlands: "Pays-Bas",
Norway: "Norvège",
Poland: "Pologne",
Portugal: "Portugal",
Scotland: "Écosse",
Spain: "Espagne",
Sweden: "Suède",
Switzerland: "Suisse",
Ukraine: "Ukraine",
},
de: {
Argentina: "Argentinien",
Austria: "Österreich",
Belgium: "Belgien",
Brazil: "Brasilien",
Canada: "Kanada",
Croatia: "Kroatien",
England: "England",
France: "Frankreich",
Georgia: "Georgien",
Germany: "Deutschland",
Italy: "Italien",
Netherlands: "Niederlande",
Norway: "Norwegen",
Poland: "Polen",
Portugal: "Portugal",
Scotland: "Schottland",
Spain: "Spanien",
Sweden: "Schweden",
Switzerland: "Schweiz",
Ukraine: "Ukraine",
},
it: {
Argentina: "Argentina",
Austria: "Austria",
Belgium: "Belgio",
Brazil: "Brasile",
Canada: "Canada",
Croatia: "Croazia",
England: "Inghilterra",
France: "Francia",
Georgia: "Georgia",
Germany: "Germania",
Italy: "Italia",
Netherlands: "Paesi Bassi",
Norway: "Norvegia",
Poland: "Polonia",
Portugal: "Portogallo",
Scotland: "Scozia",
Spain: "Spagna",
Sweden: "Svezia",
Switzerland: "Svizzera",
Ukraine: "Ucraina",
},
pt: {
Argentina: "Argentina",
Austria: "Áustria",
Belgium: "Bélgica",
Brazil: "Brasil",
Canada: "Canadá",
Croatia: "Croácia",
England: "Inglaterra",
France: "França",
Georgia: "Geórgia",
Germany: "Alemanha",
Italy: "Itália",
Netherlands: "Países Baixos",
Norway: "Noruega",
Poland: "Polónia",
Portugal: "Portugal",
Scotland: "Escócia",
Spain: "Espanha",
Sweden: "Suécia",
Switzerland: "Suíça",
Ukraine: "Ucrânia",
},
};
function pos(locale: Locale, position: string): string {
return positionTranslations[locale][position] ?? position;
}
function countries(locale: Locale, value: string): string {
return value
.split(" and ")
.map((country) => countryTranslations[locale][country] ?? country)
.join(tAnd(locale));
}
function region(locale: Locale, value: string): string {
const translations: Record<Locale, Record<string, string>> = {
en: {},
es: { Africa: "África", Europe: "Europa", "North America": "Norteamérica", "South America": "Sudamérica" },
fr: { Africa: "Afrique", Europe: "Europe", "North America": "Amérique du Nord", "South America": "Amérique du Sud" },
de: { Africa: "Afrika", Europe: "Europa", "North America": "Nordamerika", "South America": "Südamerika" },
it: { Africa: "Africa", Europe: "Europa", "North America": "Nord America", "South America": "Sud America" },
pt: { Africa: "África", Europe: "Europa", "North America": "América do Norte", "South America": "América do Sul" },
};
return translations[locale][value] ?? value;
}
function tAnd(locale: Locale): string {
return locale === "de" ? " und " : locale === "it" ? " e " : locale === "pt" ? " e " : locale === "fr" ? " et " : " y ";
}
function tSharedClub(locale: Locale, count: number): string {
if (locale === "es") return count === 2 ? "Dos jugadores comparten club." : `${count} jugadores comparten club.`;
if (locale === "fr") return count === 2 ? "Deux joueurs partagent le même club." : `${count} joueurs partagent le même club.`;
if (locale === "de") return count === 2 ? "Zwei Spieler haben denselben Klub." : `${count} Spieler haben denselben Klub.`;
if (locale === "it") return count === 2 ? "Due giocatori condividono lo stesso club." : `${count} giocatori condividono lo stesso club.`;
return count === 2 ? "Dois jogadores partilham o mesmo clube." : `${count} jogadores partilham o mesmo clube.`;
}
function tLeagueCount(locale: Locale, count: number, league: string): string {
if (locale === "es") return `${count} ${count === 1 ? "jugador juega" : "jugadores juegan"} en ${league}.`;
if (locale === "fr") return `${count} ${count === 1 ? "joueur évolue" : "joueurs évoluent"} en ${league}.`;
if (locale === "de") return `${count} ${count === 1 ? "Spieler spielt" : "Spieler spielen"} in der ${league}.`;
if (locale === "it") return `${count} ${count === 1 ? "giocatore gioca" : "giocatori giocano"} in ${league}.`;
return `${count} ${count === 1 ? "jogador joga" : "jogadores jogam"} na ${league}.`;
}
function tPositionLeague(locale: Locale, position: string, league: string): string {
const place = countries(locale, league);
if (locale === "es") return `El ${pos(locale, position)} juega en ${place}.`;
if (locale === "fr") return `Le ${pos(locale, position)} évolue en ${place}.`;
if (locale === "de") return `Der ${pos(locale, position)} spielt in ${place}.`;
if (locale === "it") return `Il ${pos(locale, position)} gioca in ${place}.`;
return `O ${pos(locale, position)} joga em ${place}.`;
}
function tPositionRegion(locale: Locale, position: string, value: string): string {
if (locale === "es") return `El ${pos(locale, position)} viene de ${region(locale, value)}.`;
if (locale === "fr") return `Le ${pos(locale, position)} vient de ${region(locale, value)}.`;
if (locale === "de") return `Der ${pos(locale, position)} kommt aus ${region(locale, value)}.`;
if (locale === "it") return `Il ${pos(locale, position)} viene da ${region(locale, value)}.`;
return `O ${pos(locale, position)} vem de ${region(locale, value)}.`;
}
function tOutsideTopFive(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} juega fuera de las cinco grandes ligas.`;
if (locale === "fr") return `Le ${pos(locale, position)} évolue hors des cinq grands championnats.`;
if (locale === "de") return `Der ${pos(locale, position)} spielt ausserhalb der fünf grossen Ligen.`;
if (locale === "it") return `Il ${pos(locale, position)} gioca fuori dai cinque grandi campionati.`;
return `O ${pos(locale, position)} joga fora das cinco grandes ligas.`;
}
function tAllDifferentClubs(locale: Locale): string {
if (locale === "es") return "Los cinco jugadores son de clubes diferentes.";
if (locale === "fr") return "Les cinq joueurs viennent de clubs différents.";
if (locale === "de") return "Alle fünf Spieler kommen aus unterschiedlichen Klubs.";
if (locale === "it") return "Tutti e cinque i giocatori vengono da club diversi.";
return "Os cinco jogadores vêm de clubes diferentes.";
}
function tMoreChampions(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} tiene más Champions League que el ${pos(locale, right)}.`;
if (locale === "fr") return `Le ${pos(locale, left)} a plus de Ligues des champions que le ${pos(locale, right)}.`;
if (locale === "de") return `Der ${pos(locale, left)} hat mehr Champions-League-Titel als der ${pos(locale, right)}.`;
if (locale === "it") return `Il ${pos(locale, left)} ha più Champions League del ${pos(locale, right)}.`;
return `O ${pos(locale, left)} tem mais Champions League do que o ${pos(locale, right)}.`;
}
function tSameChampions(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} y el ${pos(locale, right)} han ganado el mismo número de Champions League.`;
if (locale === "fr") return `Le ${pos(locale, left)} et le ${pos(locale, right)} ont gagné le même nombre de Ligues des champions.`;
if (locale === "de") return `Der ${pos(locale, left)} und der ${pos(locale, right)} haben gleich viele Champions-League-Titel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, left)} e il ${pos(locale, right)} hanno vinto lo stesso numero di Champions League.`;
return `O ${pos(locale, left)} e o ${pos(locale, right)} ganharam o mesmo número de Champions League.`;
}
function tWonLeagueTitles(locale: Locale, position: string, count: number): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado ${count} ${count === 1 ? "campeonato" : "campeonatos"}.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné ${count} ${count === 1 ? "championnat" : "championnats"}.`;
if (locale === "de") return `Der ${pos(locale, position)} hat ${count} Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto ${count} ${count === 1 ? "campionato" : "campionati"}.`;
return `O ${pos(locale, position)} ganhou ${count} ${count === 1 ? "campeonato" : "campeonatos"}.`;
}
function tNoLeagueTitle(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} no ha ganado ningún campeonato.`;
if (locale === "fr") return `Le ${pos(locale, position)} n'a gagné aucun championnat.`;
if (locale === "de") return `Der ${pos(locale, position)} hat keinen Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} non ha vinto alcun campionato.`;
return `O ${pos(locale, position)} não ganhou nenhum campeonato.`;
}
function tAtMostLeagueTitles(locale: Locale, position: string, count: number): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado como máximo ${count} campeonatos.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné au maximum ${count} championnats.`;
if (locale === "de") return `Der ${pos(locale, position)} hat höchstens ${count} Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto al massimo ${count} campionati.`;
return `O ${pos(locale, position)} ganhou no máximo ${count} campeonatos.`;
}
function tBetweenLeagueTitles(locale: Locale, position: string, min: number, max: number): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado entre ${min} y ${max} campeonatos.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné entre ${min} et ${max} championnats.`;
if (locale === "de") return `Der ${pos(locale, position)} hat zwischen ${min} und ${max} Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto tra ${min} e ${max} campionati.`;
return `O ${pos(locale, position)} ganhou entre ${min} e ${max} campeonatos.`;
}
function tMoreThanLeagueTitles(locale: Locale, position: string, count: number): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado más de ${count} campeonatos.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné plus de ${count} championnats.`;
if (locale === "de") return `Der ${pos(locale, position)} hat mehr als ${count} Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto più di ${count} campionati.`;
return `O ${pos(locale, position)} ganhou mais de ${count} campeonatos.`;
}
function tWonChampionsTitles(locale: Locale, position: string, count: number): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado ${count} ${count === 1 ? "Champions League" : "Champions League"}.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné ${count} ${count === 1 ? "Ligue des champions" : "Ligues des champions"}.`;
if (locale === "de") return `Der ${pos(locale, position)} hat ${count} Champions-League-Titel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto ${count} ${count === 1 ? "Champions League" : "Champions League"}.`;
return `O ${pos(locale, position)} ganhou ${count} ${count === 1 ? "Champions League" : "Champions League"}.`;
}
function tWonCountries(locale: Locale, position: string, value: string): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado campeonatos en ${countries(locale, value)}.`;
if (locale === "fr") return `Le ${pos(locale, position)} a gagné des championnats en ${countries(locale, value)}.`;
if (locale === "de") return `Der ${pos(locale, position)} hat Ligatitel in ${countries(locale, value)} gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto campionati in ${countries(locale, value)}.`;
return `O ${pos(locale, position)} ganhou campeonatos em ${countries(locale, value)}.`;
}
function tBothTopFlight(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} y el ${pos(locale, right)} han jugado en primera división.`;
if (locale === "fr") return `Le ${pos(locale, left)} et le ${pos(locale, right)} ont joué en première division.`;
if (locale === "de") return `Der ${pos(locale, left)} und der ${pos(locale, right)} haben erstklassig gespielt.`;
if (locale === "it") return `Il ${pos(locale, left)} e il ${pos(locale, right)} hanno giocato in massima serie.`;
return `O ${pos(locale, left)} e o ${pos(locale, right)} jogaram na primeira divisão.`;
}
function tTeammates(locale: Locale, left: string, right: string, club: string): string {
if (locale === "es") return `El ${pos(locale, left)} y el ${pos(locale, right)} fueron compañeros en ${club}.`;
if (locale === "fr") return `Le ${pos(locale, left)} et le ${pos(locale, right)} ont été coéquipiers à ${club}.`;
if (locale === "de") return `Der ${pos(locale, left)} und der ${pos(locale, right)} waren einst Teamkollegen bei ${club}.`;
if (locale === "it") return `Il ${pos(locale, left)} e il ${pos(locale, right)} sono stati compagni al ${club}.`;
return `O ${pos(locale, left)} e o ${pos(locale, right)} foram colegas no ${club}.`;
}
function tSameLeagueTitles(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} y el ${pos(locale, right)} han ganado el mismo número de campeonatos.`;
if (locale === "fr") return `Le ${pos(locale, left)} et le ${pos(locale, right)} ont gagné le même nombre de championnats.`;
if (locale === "de") return `Der ${pos(locale, left)} und der ${pos(locale, right)} haben gleich viele Ligatitel gewonnen.`;
if (locale === "it") return `Il ${pos(locale, left)} e il ${pos(locale, right)} hanno vinto lo stesso numero di campionati.`;
return `O ${pos(locale, left)} e o ${pos(locale, right)} ganharam o mesmo número de campeonatos.`;
}
function tMoreLeagueTitles(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} tiene más campeonatos que el ${pos(locale, right)}.`;
if (locale === "fr") return `Le ${pos(locale, left)} a plus de championnats que le ${pos(locale, right)}.`;
if (locale === "de") return `Der ${pos(locale, left)} hat mehr Ligatitel als der ${pos(locale, right)}.`;
if (locale === "it") return `Il ${pos(locale, left)} ha più campionati del ${pos(locale, right)}.`;
return `O ${pos(locale, left)} tem mais campeonatos do que o ${pos(locale, right)}.`;
}
function tNationality(locale: Locale, position: string, country: string): string {
if (locale === "es") return `El ${pos(locale, position)} es de ${countries(locale, country)}.`;
if (locale === "fr") return `Le ${pos(locale, position)} vient de ${countries(locale, country)}.`;
if (locale === "de") return `Der ${pos(locale, position)} kommt aus ${countries(locale, country)}.`;
if (locale === "it") return `Il ${pos(locale, position)} viene da ${countries(locale, country)}.`;
return `O ${pos(locale, position)} é de ${countries(locale, country)}.`;
}
function tPlaysFor(locale: Locale, position: string, club: string): string {
if (locale === "es") return `El ${pos(locale, position)} juega en el ${club}.`;
if (locale === "fr") return `Le ${pos(locale, position)} joue au ${club}.`;
if (locale === "de") return `Der ${pos(locale, position)} spielt für den ${club}.`;
if (locale === "it") return `Il ${pos(locale, position)} gioca nell'${club}.`;
return `O ${pos(locale, position)} joga no ${club}.`;
}
function tWonWorldCup(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} es campeón del mundo.`;
if (locale === "fr") return `Le ${pos(locale, position)} est champion du monde.`;
if (locale === "de") return `Der ${pos(locale, position)} ist Weltmeister.`;
if (locale === "it") return `Il ${pos(locale, position)} è campione del mondo.`;
return `O ${pos(locale, position)} é campeão do mundo.`;
}
function tWonEuro(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado la Eurocopa.`;
if (locale === "fr") return `Le ${pos(locale, position)} a remporté le Championnat d'Europe.`;
if (locale === "de") return `Der ${pos(locale, position)} hat die Europameisterschaft gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto il Campionato Europeo.`;
return `O ${pos(locale, position)} ganhou o Campeonato da Europa.`;
}
function tWonCopaAmerica(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado la Copa América.`;
if (locale === "fr") return `Le ${pos(locale, position)} a remporté la Copa América.`;
if (locale === "de") return `Der ${pos(locale, position)} hat die Copa América gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto la Copa América.`;
return `O ${pos(locale, position)} ganhou a Copa América.`;
}
function tWonBallonDOr(locale: Locale, position: string): string {
if (locale === "es") return `El ${pos(locale, position)} ha ganado el Balón de Oro.`;
if (locale === "fr") return `Le ${pos(locale, position)} a remporté le Ballon d'Or.`;
if (locale === "de") return `Der ${pos(locale, position)} hat den Ballon d'Or gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto il Pallone d'Oro.`;
return `O ${pos(locale, position)} ganhou a Bola de Ouro.`;
}
function tWonGoldenBoots(locale: Locale, position: string, count: number): string {
if (count === 1) {
if (locale === "es") return `El ${pos(locale, position)} ha ganado la Bota de Oro europea.`;
if (locale === "fr") return `Le ${pos(locale, position)} a remporté le Soulier d'Or européen.`;
if (locale === "de") return `Der ${pos(locale, position)} hat den Europäischen Goldenen Schuh gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto la Scarpa d'Oro europea.`;
return `O ${pos(locale, position)} ganhou a Chuteira de Ouro europeia.`;
}
if (locale === "es") return `El ${pos(locale, position)} ha ganado ${count} Botas de Oro europeas.`;
if (locale === "fr") return `Le ${pos(locale, position)} a remporté ${count} Souliers d'Or européens.`;
if (locale === "de") return `Der ${pos(locale, position)} hat ${count} Europäische Goldene Schuhe gewonnen.`;
if (locale === "it") return `Il ${pos(locale, position)} ha vinto ${count} Scarpe d'Oro europee.`;
return `O ${pos(locale, position)} ganhou ${count} Chuteiras de Ouro europeias.`;
}
function tPlayForSameClub(locale: Locale, left: string, right: string): string {
if (locale === "es") return `El ${pos(locale, left)} y el ${pos(locale, right)} juegan en el mismo club.`;
if (locale === "fr") return `Le ${pos(locale, left)} et le ${pos(locale, right)} jouent dans le même club.`;
if (locale === "de") return `Der ${pos(locale, left)} und der ${pos(locale, right)} spielen beim selben Klub.`;
if (locale === "it") return `Il ${pos(locale, left)} e il ${pos(locale, right)} giocano nello stesso club.`;
return `O ${pos(locale, left)} e o ${pos(locale, right)} jogam no mesmo clube.`;
}