(function (global) { const ONES = ['', 'eins', 'zwei', 'drei', 'vier', 'fuenf', 'sechs', 'sieben', 'acht', 'neun']; const ONES_COMPOUND = ['', 'ein', 'zwei', 'drei', 'vier', 'fuenf', 'sechs', 'sieben', 'acht', 'neun']; const TEENS = ['zehn', 'elf', 'zwoelf', 'dreizehn', 'vierzehn', 'fuenfzehn', 'sechzehn', 'siebzehn', 'achtzehn', 'neunzehn']; const TENS = ['', '', 'zwanzig', 'dreissig', 'vierzig', 'fuenfzig', 'sechzig', 'siebzig', 'achtzig', 'neunzig']; const DIGIT_WORDS = ['null', 'eins', 'zwei', 'drei', 'vier', 'fuenf', 'sechs', 'sieben', 'acht', 'neun']; const SCALES = [ { singular: '', plural: '' }, { singular: 'Tausend', plural: 'Tausend' }, { singular: 'Million', plural: 'Millionen' }, { singular: 'Milliarde', plural: 'Milliarden' }, { singular: 'Billion', plural: 'Billionen' }, { singular: 'Billiarde', plural: 'Billiarden' }, { singular: 'Trillion', plural: 'Trillionen' }, { singular: 'Trilliarde', plural: 'Trilliarden' }, { singular: 'Quadrillion', plural: 'Quadrillionen' } ]; function chunkToWords(value) { if (value === 0) { return ''; } if (value === 1) { return 'eins'; } let text = ''; const hundreds = Math.floor(value / 100); const remainder = value % 100; if (hundreds > 0) { text += (hundreds === 1 ? 'ein' : ONES_COMPOUND[hundreds]) + 'hundert'; } if (remainder > 0) { if (remainder < 10) { text += ONES[remainder]; } else if (remainder < 20) { text += TEENS[remainder - 10]; } else { const ones = remainder % 10; const tens = Math.floor(remainder / 10); if (ones > 0) { text += ONES_COMPOUND[ones] + 'und'; } text += TENS[tens]; } } return text; } function normalizeGermanNumberString(value) { if (typeof value === 'number') { if (!Number.isFinite(value)) { return ''; } return String(value).replace('.', ','); } if (typeof value !== 'string') { return ''; } return value.trim().replace(/\s+/g, ''); } function splitNormalizedNumber(value) { const normalized = normalizeGermanNumberString(value); if (normalized === '') { return null; } const sign = normalized.startsWith('-') ? '-' : ''; const unsigned = sign ? normalized.slice(1) : normalized; const cleaned = unsigned.replace(/\./g, ''); const parts = cleaned.split(','); if (parts.length > 2) { return null; } const integerPart = (parts[0] || '0').replace(/^0+(?=\d)/, '') || '0'; const fractionalPart = parts[1] || ''; if (!/^\d+$/.test(integerPart) || (fractionalPart !== '' && !/^\d+$/.test(fractionalPart))) { return null; } return { sign, integerPart, fractionalPart }; } function integerStringToWords(integerString, sign) { if (integerString === '0') { return 'null'; } const groups = []; for (let index = integerString.length; index > 0; index -= 3) { groups.push(integerString.slice(Math.max(0, index - 3), index)); } const parts = []; for (let i = groups.length - 1; i >= 0; i -= 1) { const groupValue = Number(groups[i]); if (groupValue === 0) { continue; } const scale = SCALES[i] || { singular: '', plural: '' }; if (i >= 2) { const prefix = groupValue === 1 ? 'eine' : String(groupValue); const label = groupValue === 1 ? scale.singular : scale.plural; parts.push(prefix + ' ' + label); } else if (i === 1) { parts.push(groupValue === 1 ? 'ein ' + scale.singular : String(groupValue) + ' ' + scale.singular); } else { parts.push(String(groupValue)); } } const result = parts.join('\n'); return sign === '-' ? 'minus ' + result : result; } function numberToGermanText(value) { const parsed = splitNormalizedNumber(value); if (!parsed) { return ''; } const integerText = integerStringToWords(parsed.integerPart, parsed.sign); if (!parsed.fractionalPart || /^0+$/.test(parsed.fractionalPart)) { return integerText; } const decimalDigits = parsed.fractionalPart .split('') .map(function (digit) { return DIGIT_WORDS[Number(digit)]; }) .join(' '); return integerText + '\nKomma ' + decimalDigits; } global.numberToGermanText = numberToGermanText; })(window);