124 lines
4.1 KiB
JavaScript
124 lines
4.1 KiB
JavaScript
(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 SCALES = [
|
|
{ singular: '', plural: '', join: true },
|
|
{ singular: 'Tausend', plural: 'Tausend', join: true },
|
|
{ singular: 'Million', plural: 'Millionen', join: false },
|
|
{ singular: 'Milliarde', plural: 'Milliarden', join: false },
|
|
{ singular: 'Billion', plural: 'Billionen', join: false },
|
|
{ singular: 'Billiarde', plural: 'Billiarden', join: false },
|
|
{ singular: 'Trillion', plural: 'Trillionen', join: false },
|
|
{ singular: 'Trilliarde', plural: 'Trilliarden', join: false },
|
|
{ singular: 'Quadrillion', plural: 'Quadrillionen', join: false }
|
|
|
|
];
|
|
const GROUP_NUMBER_FORMATTER = new Intl.NumberFormat('de-DE');
|
|
|
|
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 integerToWords(value) {
|
|
if (!Number.isFinite(value)) {
|
|
return '';
|
|
}
|
|
|
|
if (value === 0) {
|
|
return 'null';
|
|
}
|
|
|
|
let number = Math.floor(Math.abs(value));
|
|
const groups = [];
|
|
|
|
while (number > 0) {
|
|
groups.push(number % 1000);
|
|
number = Math.floor(number / 1000);
|
|
}
|
|
|
|
const parts = [];
|
|
|
|
for (let i = groups.length - 1; i >= 0; i -= 1) {
|
|
const groupValue = groups[i];
|
|
if (groupValue === 0) {
|
|
continue;
|
|
}
|
|
|
|
const scale = SCALES[i] || { singular: '', plural: '', join: false };
|
|
if (i >= 2) {
|
|
const scaleLabel = groupValue === 1 ? scale.singular : scale.plural;
|
|
const prefix = groupValue === 1 ? 'eine' : GROUP_NUMBER_FORMATTER.format(groupValue);
|
|
parts.push(prefix + ' ' + scaleLabel);
|
|
} else if (i === 1) {
|
|
parts.push(GROUP_NUMBER_FORMATTER.format(groupValue) + ' ' + scale.singular);
|
|
} else {
|
|
parts.push(GROUP_NUMBER_FORMATTER.format(groupValue));
|
|
}
|
|
}
|
|
|
|
const result = parts.join('\n');
|
|
return value < 0 ? 'minus ' + result : result;
|
|
}
|
|
|
|
function numberToGermanText(value) {
|
|
if (!Number.isFinite(value)) {
|
|
return '';
|
|
}
|
|
|
|
const integerPart = Math.trunc(value);
|
|
const fractionalPart = Math.abs(value - integerPart);
|
|
const integerText = integerToWords(integerPart);
|
|
|
|
if (fractionalPart < 1e-10) {
|
|
return integerText;
|
|
}
|
|
|
|
const decimalDigits = fractionalPart
|
|
.toFixed(10)
|
|
.replace(/^0\./, '')
|
|
.replace(/0+$/, '')
|
|
.split('')
|
|
.map(function (digit) {
|
|
return ['null', 'eins', 'zwei', 'drei', 'vier', 'fuenf', 'sechs', 'sieben', 'acht', 'neun'][Number(digit)];
|
|
})
|
|
.join(' ');
|
|
|
|
return integerText + '\nKomma ' + decimalDigits;
|
|
}
|
|
|
|
global.numberToGermanText = numberToGermanText;
|
|
})(window);
|