picker/js/i18n.js
David 35a4dc2dbf
Some checks failed
Publish Docker image / image (push) Has been cancelled
fixes
2026-10-09 13:55:15 +02:00

173 lines
5.2 KiB
JavaScript

// All user-facing strings live here.
// Stakes are phrased so they read naturally after "The chosen one has to…"
// (en, bare verb) / "De gekozene…" (nl, conjugated verb), and slot into
// "You {stake}!" / "Jij {stake}!" on the reveal.
export const translations = {
en: {
appTitle: 'Picker',
hint: 'Everyone put a finger on the screen',
needMore: 'Waiting for more fingers…',
holdStill: 'Hold still…',
chicken: [
'Someone chickened out! 🐔',
'Cold feet? Someone let go! 🐔',
'Bawk bawk! Who let go? 🐔',
],
chickenOut: 'Chickened out! 🐔',
eliminated: 'Knocked out!',
liftFinger: 'Lift your finger',
youreIt: "You're it!",
youStake: 'You {stake}!',
teamsReady: 'Teams are set!',
orderDone: "That's the order!",
lastStanding: 'Last one standing!',
tapRestart: 'Tap to play again',
desktopHint: 'On a computer? Add ?debug=1 to the address to test with a mouse.',
tapForSound: '🔈 Tap the screen once to turn on sound',
team: 'Team {name}',
modeLabel: 'Mode',
mode: {
one: 'Pick one',
pickN: 'Pick several',
teams: 'Teams',
order: 'Order',
elimination: 'Elimination',
},
modeDesc: {
one: 'One finger is chosen.',
pickN: 'Several fingers are chosen.',
teams: 'Everyone is split into teams.',
order: 'Everyone gets a number, one by one.',
elimination: 'One finger is knocked out each round until one remains.',
},
pickNLabel: 'How many to pick',
teamsLabel: 'Number of teams',
stakesLabel: 'The chosen one has to…',
stakesPlaceholder: 'e.g. pay the bill',
stakesClear: 'Clear',
stakePresets: {
bill: 'pay the bill',
dishes: 'do the dishes',
first: 'go first',
round: 'get the next round',
movie: 'pick the movie',
},
themeLabel: 'Theme',
theme: { neon: 'Neon', pastel: 'Pastel', contrast: 'High contrast' },
languageLabel: 'Language',
soundLabel: 'Sound',
hapticsLabel: 'Vibration',
on: 'On',
off: 'Off',
done: 'Done',
settings: 'Settings',
mute: 'Mute sound',
unmute: 'Unmute sound',
fullscreen: 'Full screen',
exitFullscreen: 'Exit full screen',
decrease: 'Fewer',
increase: 'More',
},
nl: {
appTitle: 'Picker',
hint: 'Iedereen een vinger op het scherm',
needMore: 'Wachten op meer vingers…',
holdStill: 'Stil houden…',
chicken: [
'Iemand is er tussenuit geknepen! 🐔',
'Koudwatervrees? Iemand liet los! 🐔',
'Tok tok! Wie liet er los? 🐔',
],
chickenOut: 'Laf losgelaten! 🐔',
eliminated: 'Uitgeschakeld!',
liftFinger: 'Haal je vinger weg',
youreIt: 'Jij bent het!',
youStake: 'Jij {stake}!',
teamsReady: 'De teams staan!',
orderDone: 'Dat is de volgorde!',
lastStanding: 'Laatste overlevende!',
tapRestart: 'Tik om opnieuw te spelen',
desktopHint: 'Op een computer? Zet ?debug=1 achter het adres om met de muis te testen.',
tapForSound: '🔈 Tik één keer op het scherm voor geluid',
team: 'Team {name}',
modeLabel: 'Modus',
mode: {
one: 'Kies één',
pickN: 'Kies meerdere',
teams: 'Teams',
order: 'Volgorde',
elimination: 'Afvalrace',
},
modeDesc: {
one: 'Eén vinger wordt gekozen.',
pickN: 'Meerdere vingers worden gekozen.',
teams: 'Iedereen wordt in teams verdeeld.',
order: 'Iedereen krijgt een nummer, één voor één.',
elimination: 'Elke ronde valt er één af, tot er één overblijft.',
},
pickNLabel: 'Hoeveel kiezen',
teamsLabel: 'Aantal teams',
stakesLabel: 'De gekozene…',
stakesPlaceholder: 'bijv. betaalt de rekening',
stakesClear: 'Wissen',
stakePresets: {
bill: 'betaalt de rekening',
dishes: 'doet de afwas',
first: 'mag beginnen',
round: 'haalt het volgende rondje',
movie: 'kiest de film',
},
themeLabel: 'Thema',
theme: { neon: 'Neon', pastel: 'Pastel', contrast: 'Hoog contrast' },
languageLabel: 'Taal',
soundLabel: 'Geluid',
hapticsLabel: 'Trillen',
on: 'Aan',
off: 'Uit',
done: 'Klaar',
settings: 'Instellingen',
mute: 'Geluid uit',
unmute: 'Geluid aan',
fullscreen: 'Volledig scherm',
exitFullscreen: 'Volledig scherm sluiten',
decrease: 'Minder',
increase: 'Meer',
},
};
export const LANGS = ['en', 'nl'];
let current = 'en';
export function detectLang() {
const prefs = navigator.languages?.length ? navigator.languages : [navigator.language || 'en'];
for (const p of prefs) {
const base = String(p).toLowerCase().split('-')[0];
if (LANGS.includes(base)) return base;
}
return 'en';
}
export function setLang(lang) {
current = LANGS.includes(lang) ? lang : 'en';
document.documentElement.lang = current;
}
export function getLang() {
return current;
}
/** Look up a dotted key ("mode.one"); interpolate {vars}. Falls back to English. */
export function t(key, vars) {
const lookup = (lang) => key.split('.').reduce((o, k) => (o == null ? o : o[k]), translations[lang]);
let s = lookup(current);
if (s == null) s = lookup('en');
if (s == null) return key;
if (typeof s === 'string' && vars) {
s = s.replace(/\{(\w+)\}/g, (m, k) => (k in vars ? vars[k] : m));
}
return s;
}