It now uses `Intl.NumberFormat` for as many formats as it can. 

I've also tried to identify different locale-dependent styles. Indian and Swiss with Latin digits are the only ones I found. Firefox thinks that an Algeria locale code should return Tibetan digits, which must be wrong.

I've also added scientific, engineering and compact renderings, offered by Intl.NumberFormat.
This commit is contained in:
Christian Lawson-Perfect 2025-04-14 13:24:13 +00:00
parent 45faac5b14
commit cf8049b8a6

278
script.js
View file

@ -2,6 +2,14 @@ function span(first, n=10) {
return [...new Array(n)].map((_,i) => first.slice(0,first.length-1)+String.fromCharCode(first.charCodeAt(first.length-1) + i));
}
function intl_formatter(system, name, locale='nu', extra) {
const formatter = new Intl.NumberFormat(locale, Object.assign({numberingSystem:system},extra));
return {
name,
fn: formatter.format
}
}
function positional_unicode_span(name, zero, base=10n, extra) {
// Make a function to render a positional number system whose digits are in a contiguous span of unicode code points.
return Object.assign({
@ -22,9 +30,11 @@ function positional_unicode_span(name, zero, base=10n, extra) {
}, extra || {})
}
function positional_symbols(name, symbols) {
function positional_symbols(name, symbols, extra) {
if(extra) {
}
// Make a function to render a positional number system whose digits are drawn from the given string.
return {
return Object.assign({
name,
fn: (n) => {
let o = '';
@ -40,7 +50,7 @@ function positional_symbols(name, symbols) {
}
return o;
}
};
}, extra || {});
}
function concatenative(power_lists, base=10n) {
@ -122,8 +132,6 @@ const systems = {
}
},
arabic: positional_unicode_span('Eastern Arabic', '٠'),
roman: {
name: 'Roman',
fn: concatenative([
@ -159,7 +167,7 @@ const systems = {
])
},
hebrew: {
hebr: {
name: 'Hebrew',
fn: (n) => {
if(n >= 10000n) {
@ -175,7 +183,6 @@ const systems = {
let o = '';
for(let symbols of [ones,tens,hundreds,thousands]) {
console.log(symbols, n);
if(n==0n) {
break;
}
@ -189,7 +196,24 @@ const systems = {
}
},
greek: {
indian: intl_formatter('latn','Indian','en-in'),
latn_commas: intl_formatter('latn','Latin with commas','en-gb'),
latn_spaces: intl_formatter('latn','Latin with spaces','fi-fi'),
latn_dots: intl_formatter('latn','European','eu'),
latn_swiss: intl_formatter('latn','Swiss','de-ch'),
scientific: intl_formatter('latn','Engineering','en',{notation:'scientific'}),
engineering: intl_formatter('latn','Engineering','en',{notation:'engineering'}),
compact: intl_formatter('latn','Compact','en',{notation:'compact'}),
grek: {
name: 'Greek',
fn: concatenative([
["Αʹ", "Βʹ", "Γʹ", "Δʹ", "Εʹ", "Ϛʹ", "Ζʹ", "Ηʹ", "Θʹ" ],
@ -201,7 +225,7 @@ const systems = {
])
},
chinese: {
hans: {
name: 'Chinese',
fn: chinese_system(
'',
@ -213,9 +237,9 @@ const systems = {
counting_rod_horizontal: positional_symbols('Counting rod (horizontal)', [''].concat(span('𝍠',9))),
counting_rod_vertical: positional_symbols('Counting rod (vertical)', [''].concat(span('𝍩',9)), 10n, {orientation: 'vertical-lr'}),
counting_rod_vertical: positional_symbols('Counting rod (vertical)', [''].concat(span('𝍩',9)), {orientation: 'vertical-lr'}),
suzhou: {
hant: {
name: 'Suzhou',
fn: (n) => {
const zero = '';
@ -235,7 +259,7 @@ const systems = {
}
},
ethiopic: {
ethi: {
name: 'Ethiopic',
fn: concatenative([
span('፩',9),
@ -283,7 +307,7 @@ const systems = {
])
},
armenian: {
armn: {
name: 'Armenian',
fn: concatenative([
['Ա','Բ','Գ','Դ','Ե','Զ','Է','Ը','Թ'],
@ -313,7 +337,7 @@ const systems = {
])
},
cyrillic: {
cyrl: {
name: 'Cyrillic',
fn: (() => {
const units = ["А","В","Г","Д","Є","Ѕ","З","И","Ѳ"];
@ -362,114 +386,10 @@ const systems = {
mayan: positional_unicode_span('Mayan', '𝋠', 20n, {orientation: 'vertical-lr'}),
nko: positional_unicode_span('N\'Ko', '߀'),
devanagari: positional_unicode_span('Devanagari', ''),
bengali: positional_unicode_span('Bengali', ''),
gurmukhi: positional_unicode_span('Gurmukhi',''),
gujarati: positional_unicode_span('Gujarati', ''),
odia: positional_unicode_span('Odia', ''),
tamil: positional_unicode_span('Tamil', ''),
telugu: positional_unicode_span('Telugu', ''),
kannada: positional_unicode_span('Kannada', ''),
malayalam: positional_unicode_span('Malayalam', ''),
thai: positional_unicode_span('Thai', ''),
lao: positional_unicode_span('Lao', ''),
tibetan: positional_unicode_span('Tibetan', '༠'),
burmese: positional_unicode_span('Burmese', ''),
khmer: positional_unicode_span('Khmer', '០'),
mongolian: positional_unicode_span('Mongolian', '᠐'),
limbu: positional_unicode_span('Limbu', '᥆'),
new_tai_lue: positional_unicode_span('New Tai Lue', '᧐'),
lek_hora: positional_unicode_span('Lek Hora','᪀'),
lek_nai_tham: positional_unicode_span('Lek Nai Tham', '᪐'),
balinese: positional_unicode_span('Balinese', '᭐'),
sundanese: positional_unicode_span('Sundanese', '᮰'),
lepcha: positional_unicode_span('Lepcha', '᱀'),
ol_chiki: positional_unicode_span('Ol Chiki', '᱐'),
vai: positional_unicode_span('Vai', '꘠'),
saurashtra: positional_unicode_span('Saurashtra', '꣐'),
kayah_li: positional_unicode_span('Kayah Li', '꤀'),
javanese: positional_unicode_span('Javanese', '꧐'),
cham: positional_unicode_span('Cham', '꩐'),
meitei: positional_unicode_span('meitei', '꯰'),
osmanya: positional_unicode_span('Osmanya', '𐒠'),
brahmi: positional_unicode_span('Brahmi', '𑁦'),
sorang_sompeng: positional_unicode_span('Sorang Sompeng', '𑃰'),
chakma: positional_unicode_span('Chakma', '𑄶'),
sharada: positional_unicode_span('Sharada', '𑇐'),
takri: positional_unicode_span('Takri', '𑛀'),
sinhala: positional_unicode_span('Sinhala', '෦'),
tai_laing: positional_unicode_span('Tai Laing', '꧰'),
khudabadi: positional_unicode_span('Khudabadi', '𑋰'),
tirhuta: positional_unicode_span('Tirhuta', '𑓐'),
modi: positional_unicode_span('Modi', '𑙐'),
warang_citi: positional_unicode_span('Warang Citi', '𑣠'),
mro: positional_unicode_span('Mro', '𖩠'),
pahawh_hmong: positional_unicode_span('Pahawh Hmong', '𖭐'),
ahom: positional_unicode_span('Tai Ahom', '𑜰'),
prachalit: positional_unicode_span('Prachalit', '𑑐'),
hanifi_rohingya: positional_unicode_span('Hanifi Rohingya', '𐴰'),
bhaiksuki: positional_unicode_span('Bhaiksuki', '𑱐'),
masaram_gondi: positional_unicode_span('Masaram Gondi', '𑵐'),
gunjala_gondi: positional_unicode_span('Gunjala Gondi', '𑶠'),
medefaidrin: positional_unicode_span('Medefaidrin', '𖺀', 20n),
nyiakeng_puachue_hmong: positional_unicode_span('Nyiakeng Puachue Hmong', '𞅀'),
wancho: positional_unicode_span('Wancho', '𞋰'),
adlam: positional_unicode_span('Adlam', '𞥐'),
kaktovik: positional_unicode_span('Kaktovik', '𝋀', 20n),
// garay: positional_unicode_span('Garay', '𐵀'), //(not in noto??)
@ -506,25 +426,133 @@ const systems = {
}
}
const intl_system_names = {
"adlm": "Adlam",
"ahom": "Ahom",
"arab": "Arabic-Indic",
"arabext": "Farsi/Urdu",
"armn": "Armenian upper case",
"armnlow": "Armenian lower case",
"bali": "Balinese",
"beng": "Bengali",
"bhks": "Bhaiksuki",
"brah": "Brahmi",
"cakm": "Chakma",
"cham": "Cham",
"cyrl": "Cyrillic",
"deva": "Devanagari",
"diak": "Dives Akuru",
"ethi": "Ethiopic",
"fullwide": "Full width",
"gara": "Garay",
"geor": "Georgian",
"gong": "Gunjala Gondi",
"gonm": "Masaram Gondi",
"grek": "Greek upper case",
"greklow": "Greek lower case",
"gujr": "Gujarati",
"gukh": "Gurung Khema",
"guru": "Gurmukhi",
"hanidays": "Han calendar",
"hanidec": "Chinese (positional)",
"hans": "Simplified Chinese",
"hansfin": "Simplified Chinese financial",
"hant": "Traditional Chinese",
"hantfin": "Traditional Chinese financial",
"hebr": "Hebrew",
"hmng": "Pahawh Hmong",
"hmnp": "Nyiakeng Puachue Hmong",
"java": "Javanese",
"jpan": "Japanese",
"jpanfin": "Japanese financial",
"jpanyear": "Japanese calendar",
"kali": "Kayah Li",
"kawi": "Kawi",
"khmr": "Khmer",
"knda": "Kannada",
"krai": "Kirat Rai",
"lana": "Tai Tham Hora",
"lanatham": "Tai Tham",
"laoo": "Lao",
"latn": "Latin",
"lepc": "Lepcha",
"limb": "Limbu",
"mathbold": "Mathematical bold",
"mathdbl": "Mathematical double-struck",
"mathmono": "Mathematical monospace",
"mathsanb": "Mathematical sans-serif bold",
"mathsans": "Mathematical sans-serif",
"mlym": "Malayalam",
"modi": "Modi",
"mong": "Mongolian",
"mroo": "Mro",
"mtei": "Meetei Mayek",
"mymr": "Myanmar",
"mymrepka": "Myanmar Eastern Pwo Karen",
"mymrpao": "Myanmar Pao",
"mymrshan": "Myanmar Shan",
"mymrtlng": "Myanmar Tai Laing",
"nagm": "Nag Mundari",
"newa": "Newa",
"nkoo": "N'Ko",
"olck": "Ol Chiki",
"onao": "Ol Onal",
"orya": "Oriya",
"osma": "Osmanya",
"outlined": "Outlined digits",
"rohg": "Hanifi Rohingya",
"roman": "Roman upper case",
"romanlow": "Roman lowercase",
"saur": "Saurashtra",
"segment": "7-segment display",
"shrd": "Sharada",
"sind": "Khudawadi",
"sinh": "Sinhala Lith",
"sora": "Sora_Sompeng",
"sund": "Sundanese",
"sunu": "Sunuwar",
"takr": "Takri",
"talu": "New Tai Lue",
"taml": "Tamil",
"tamldec": "Modern Tamil decimal",
"telu": "Telugu",
"thai": "Thai",
"tibt": "Tibetan",
"tirh": "Tirhuta",
"tnsa": "Tangsa",
"vaii": "Vai",
"wara": "Warang Citi",
"wcho": "Wancho"
}
Intl.supportedValuesOf('numberingSystem').forEach(system => {
systems[system] = intl_formatter(system, intl_system_names[system]);
});
const dl = document.getElementById('systems');
Object.entries(systems).forEach(([id, entry]) => {
function sort_by_name([_,{name: a}], [__,{name: b}]) {
return a < b ? -1 : a>b ? 1 : 0;
}
Object.entries(systems).toSorted(sort_by_name).forEach(([id, entry]) => {
const {name, orientation} = entry;
const dt = document.createElement('dt');
dt.textContent = name;
dl.append(dt);
const dd = document.createElement('dd');
if(orientation) {
dd.style['writing-mode'] = orientation;
}
const bdi = document.createElement('bdi');
dd.append(bdi);
dl.append(dd);
entry.dd = dd;
if(orientation) {
bdi.style['writing-mode'] = orientation;
}
entry.dd = bdi;
})
function update() {
const n = BigInt(decimal_input.value || '0');
Object.values(systems).forEach(({name,fn,dd}) => {
console.log(name);
dd.textContent = fn(n);
});
}
@ -533,4 +561,4 @@ const decimal_input = document.getElementById('decimal');
update();
decimal_input.addEventListener('input', update);
decimal_input.addEventListener('input', update)