2a8d055da3
Build and push image / build (push) Successful in 1m19s
- 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>
1194 lines
52 KiB
TypeScript
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.`;
|
|
}
|