diff --git a/src/accessibility.typ b/src/accessibility.typ index 475e1bb..3900bd6 100644 --- a/src/accessibility.typ +++ b/src/accessibility.typ @@ -349,51 +349,51 @@ "‰": "per mille", ), fi: ( - A: "ampeeria", - au: "astronomista yksikköä", - B: "beliä", - Bq: "becquereliä", - C: "coulombia", - cd: "kandelaa", - d: "päivää", - Da: "daltonia", - dB: "desibeliä", - sym.degree: "astetta", - sym.degree + "C": "Celsiusastetta", - eV: "elektronivolttia", - F: "faradia", - g: "grammaa", - Gy: "graytä", - H: "henryä", - h: "tuntia", - ha: "hehtaaria", - Hz: "hertsiä", - J: "joulea", - K: "kelviniä", - kat: "katalia", - kg: "kilogrammaa", - L: "litraa", - lm: "luumenia", - lx: "luksia", - m: "metriä", - sym.prime: "kaariminuuttia", - min: "minuuttia", - mol: "moolia", - sym.prime.double: "kaarisekuntia", - N: "newtonia", - Np: "neperiä", - sym.Omega: "ohmia", - Pa: "pascalia", - rad: "radiaania", - s: "sekuntia", - S: "siemensiä", - sr: "steradiaania", - Sv: "sieverttiä", - t: "tonnia", - T: "teslaa", - V: "volttia", - W: "wattia", - Wb: "weberiä", + A: "ampeeri", + au: "astronominen yksikkö", + B: "bel", + Bq: "becquerel", + C: "coulombi", + cd: "kandela", + d: "päivä", + Da: "dalton", + dB: "desibeli", + sym.degree: "aste", + sym.degree + "C": "Celsiusaste", + eV: "elektronivoltti", + F: "faradi", + g: "gramma", + Gy: "gray", + H: "henry", + h: "tunti", + ha: "hehtaari", + Hz: "hertsi", + J: "joule", + K: "kelvin", + kat: "katal", + kg: "kilogramma", + L: "litra", + lm: "luumen", + lx: "luksi", + m: "metri", + sym.prime: "kaariminuutti", + min: "minuuti", + mol: "mooli", + sym.prime.double: "kaarisekunti", + N: "newton", + Np: "neper", + sym.Omega: "ohmi", + Pa: "pascal", + rad: "radiaani", + s: "sekunti", + S: "siemens", + sr: "steradiaani", + Sv: "sievertti", + t: "tonni", + T: "tesla", + V: "voltti", + W: "watti", + Wb: "weber", "%": "prosentti", "‰": "promille", ), @@ -472,6 +472,108 @@ ), ) +#let finnish-plural-units = ( + A: "ampeeria", + au: "astronomista yksikköä", + B: "beliä", + Bq: "becquereliä", + C: "coulombia", + cd: "kandelaa", + d: "päivää", + Da: "daltonia", + dB: "desibeliä", + sym.degree: "astetta", + sym.degree + "C": "Celsiusastetta", + eV: "elektronivolttia", + F: "faradia", + g: "grammaa", + Gy: "graytä", + H: "henryä", + h: "tuntia", + ha: "hehtaaria", + Hz: "hertsiä", + J: "joulea", + K: "kelviniä", + kat: "katalia", + kg: "kilogrammaa", + L: "litraa", + lm: "luumenia", + lx: "luksia", + m: "metriä", + sym.prime: "kaariminuuttia", + min: "minuuttia", + mol: "moolia", + sym.prime.double: "kaarisekuntia", + N: "newtonia", + Np: "neperiä", + sym.Omega: "ohmia", + Pa: "pascalia", + rad: "radiaania", + s: "sekuntia", + S: "siemensiä", + sr: "steradiaania", + Sv: "sieverttiä", + t: "tonnia", + T: "teslaa", + V: "volttia", + W: "wattia", + Wb: "weberiä", + "%": "prosentti", + "‰": "promille", +) + +// Needed by pluralize when a unit is in a denominator. +// The unit suffixes are in a form where each word would be preceded by the word "jaettuna" or "divided by". +#let finnish-denom-units = ( + A: "ampeerilla", + au: "astronomisella yksikköllä", + B: "belillä", + Bq: "becquerelillä", + C: "coulombilla", + cd: "kandelalla", + d: "päivällä", + Da: "daltonilla", + dB: "desibelillä", + sym.degree: "asteella", + sym.degree + "C": "Celsiusasteella", + eV: "elektronivoltilla", + F: "faradilla", + g: "grammalla", + Gy: "grayllä", + H: "henryllä", + h: "tunnilla", + ha: "hehtaarilla", + Hz: "hertsillä", + J: "joulella", + K: "kelvinillä", + kat: "katalilla", + kg: "kilogrammalla", + L: "litralla", + lm: "luumenilla", + lx: "luksilla", + m: "metrillä", + sym.prime: "kaariminuuttilla", + min: "minuutilla", + mol: "moolilla", + sym.prime.double: "kaarisekunnilla", + N: "newtonilla", + Np: "neperillä", + sym.Omega: "ohmilla", + Pa: "pascalilla", + rad: "radiaanilla", + s: "sekunnilla", + S: "siemensillä", + sr: "steradiaanilla", + Sv: "sievertillä", + t: "tonnilla", + T: "teslalla", + V: "voltilla", + W: "watilla", + Wb: "weberillä", + "%": "prosentilla", + "‰": "promillella", +) + // How to form the plural of a constituent unit. For each language, this should // be a function that takes a unit symbol string, e.g. "Hz", // and a float `count` which is assumed to be of some plural amount, @@ -506,6 +608,18 @@ return singular }, + fi: (unit, count, is-in-denom) => { + if is-in-denom { + // Things get more complex here since when in a denominator we need a form of each word where things happen IN something. + // Like literally IN one second, or IN one meter. And of course Finnish has a specific suffix for each word for this. + // Often this just means adding a "ss" before the last letter of the quantity form of each word but not always. + // For example "metriä sekunnissa" means "meters per second" or "meters in one second". + return finnish-denom-units.at(unit) + } else { + return finnish-plural-units.at(unit) + } + }, + fr: (unit, count, is-in-denom) => { let singular = units.fr.at(unit, default: units.en.at(unit)) if unit in ("lx", "Hz", "S", "%", "‰") { @@ -656,9 +770,9 @@ // Masculine if ( unit in ( - "A", "B", "Bq", "C", "d", "Da", "dB", "eV", "F", "g", "Gy", "H", "ha", - "Hz", "J", "K", "kat", "kg", "L", "lm", "lx", "m", "mol", "N", "Np", - str(sym.Omega), "Pa", "rad", "S", "sr", "Sv", "T", "V", "W", "Wb", + "A", "B", "Bq", "C", "d", "Da", "dB", "eV", "F", "g", "Gy", "H", "ha", + "Hz", "J", "K", "kat", "kg", "L", "lm", "lx", "m", "mol", "N", "Np", + str(sym.Omega), "Pa", "rad", "S", "sr", "Sv", "T", "V", "W", "Wb", "%", "‰", ) ) { @@ -798,7 +912,7 @@ let units = units.en + units.at(lang, default: units.en) let get-unit(unit-code) = { if plural { (pluralize.at(lang))(unit-code, count, is-in-denom) } // Add your language here to `pluralize` the denominator - else if is-in-denom and lang == "sl" { + else if is-in-denom and lang in ("sl", "fi") { (pluralize.at(lang))(unit-code, count, is-in-denom) } else { units.at(unit-code) } } diff --git a/tests/accessibility/test.typ b/tests/accessibility/test.typ index 41694e2..3f94cb2 100644 --- a/tests/accessibility/test.typ +++ b/tests/accessibility/test.typ @@ -1,17 +1,14 @@ #import "/src/zero.typ": * -#set page(width: auto, height: auto, margin: 2pt) - - #import "/src/units.typ": parse-unit #import "/src/accessibility.typ": * #import "/src/parsing.typ": parse-numeral #import "/src/state.typ": num-state +#set page(width: auto, height: auto, margin: 2pt) + +#set text(lang: "en") -#num[2+-0.2]\ -#num(uncertainty-mode: "compact")[2+-0001.2] -#num[+1e.5] #context { assert.eq( generate-num-alt-description( @@ -25,56 +22,10 @@ ), "minus 1.34 plus 0.5 minus 2 times 2 to the power of -2", ) +} - set text(lang: "de") - context { - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+-2e-2") + num-state.get() - ), - "minus 1,34 plus minus 2 mal 10 hoch -2", - ) - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+0.5-2e-2") - + num-state.get() - + (base: 2), - ), - "minus 1,34 plus 0,5 minus 2 mal 2 hoch -2", - ) - } - set text(lang: "fr") - context { - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+-2e-2") + num-state.get(), - ), - "moins 1,34 plus moins 2 fois 10 à la puissance -2", - ) - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), - ), - "moins 1,34 plus 0,5 moins 2 fois 2 à la puissance -2", - ) - } - - set text(lang: "be") - context { - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+-2e-2") + num-state.get(), - ), - "− 1.34 + − 2 × 10 ^ -2", - ) - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), - ), - "− 1.34 + 0.5 − 2 × 2 ^ -2", - ) - } +#context { assert(unit-component-description("mm") == "millimeter") assert(unit-component-description("kg") == "kilogram") assert(unit-component-description("au") == "astronomical unit") @@ -114,186 +65,335 @@ generate-unit-alt-description(..parse-unit("N s/m").values(), value: 2), "newton seconds per meter", ) +} - set text(lang: "de") - context { - assert.eq( - generate-unit-alt-description( - ..parse-unit("m^2/µs^3").values(), - ), - "Quadratmeter pro Kubikmikrosekunde", - ) - assert.eq( - generate-unit-alt-description( - ..parse-unit("m^4/s/K").values(), - ), - "Meter hoch 4 pro Sekunde pro Kelvin", - ) - assert.eq( - generate-unit-alt-description( - ..parse-unit("mN m").values(), - ), - "Millinewton Meter", - ) +#set text(lang: "de") +#context { + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+-2e-2") + num-state.get(), + ), + "minus 1,34 plus minus 2 mal 10 hoch -2", + ) + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), + ), + "minus 1,34 plus 0,5 minus 2 mal 2 hoch -2", + ) +} - // Plural +#set text(lang: "fr") +#context { + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+-2e-2") + num-state.get(), + ), + "moins 1,34 plus moins 2 fois 10 à la puissance -2", + ) + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), + ), + "moins 1,34 plus 0,5 moins 2 fois 2 à la puissance -2", + ) +} - assert.eq( - generate-unit-alt-description(..parse-unit("h").values(), value: 2), - "Stunden", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("d").values(), value: 2), - "Tage", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("T").values(), value: 2), - "Tesla", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("au").values(), value: 2), - "astronomische Einheiten", - ) - } +#set text(lang: "be") +#context { + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+-2e-2") + num-state.get(), + ), + "− 1.34 + − 2 × 10 ^ -2", + ) + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), + ), + "− 1.34 + 0.5 − 2 × 2 ^ -2", + ) +} - set text(lang: "fr") - context { - assert.eq( - generate-unit-alt-description( - ..parse-unit("m^2/s^3/l^4").values(), - ), - "mètre carré par seconde cube par litre à la puissance 4", - ) - assert.eq( - generate-unit-alt-description( - ..parse-unit("MN m").values(), - ), - "méganewton mètre", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("h").values(), value: 2), - "heures", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("h").values(), value: 1.5), - "heure", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("h").values(), value: -0.5), - "heure", - ) - assert.eq( - generate-unit-alt-description(..parse-unit("°C").values(), value: 2), - "degrés Celsius", - ) - } +#set text(lang: "de") +#context { + assert.eq( + generate-unit-alt-description( + ..parse-unit("m^2/µs^3").values(), + ), + "Quadratmeter pro Kubikmikrosekunde", + ) + assert.eq( + generate-unit-alt-description( + ..parse-unit("m^4/s/K").values(), + ), + "Meter hoch 4 pro Sekunde pro Kelvin", + ) + assert.eq( + generate-unit-alt-description( + ..parse-unit("mN m").values(), + ), + "Millinewton Meter", + ) - set text(lang: "sl") - context { - // [1/2] Tests the `phrases` the same way as English - // No special rules apply, hence the copied tests - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+-2e-2") + num-state.get(), - ), - "minus 1,34 plus minus 2 krat 10 na stopnjo -2", - ) - assert.eq( - generate-num-alt-description( - parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), - ), - "minus 1,34 plus 0,5 minus 2 krat 2 na stopnjo -2", - ) + // Plural - // [2/3] Tests the `prefixes` in a single test - // Use the `\u{00b5}` micro sign, not `\u{03bc}` - assert.eq( - unit-component-description("µA"), - "mikroamper", - ) + assert.eq( + generate-unit-alt-description(..parse-unit("h").values(), value: 2), + "Stunden", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("d").values(), value: 2), + "Tage", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("T").values(), value: 2), + "Tesla", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("au").values(), value: 2), + "astronomische Einheiten", + ) +} - // [3/3] Tests the `units` in its own way +#set text(lang: "fr") +#context { + assert.eq( + generate-unit-alt-description( + ..parse-unit("m^2/s^3/l^4").values(), + ), + "mètre carré par seconde cube par litre à la puissance 4", + ) + assert.eq( + generate-unit-alt-description( + ..parse-unit("MN m").values(), + ), + "méganewton mètre", + ) - let nums = (-5.5, -5, -3, -2, -1.0, -1, 0, 1, 1.0, 2, 3, 5, 5.5, "1/") + assert.eq( + generate-unit-alt-description(..parse-unit("h").values(), value: 2), + "heures", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("h").values(), value: 1.5), + "heure", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("h").values(), value: -0.5), + "heure", + ) + assert.eq( + generate-unit-alt-description(..parse-unit("°C").values(), value: 2), + "degrés Celsius", + ) +} - // Slovenian units, not all but the first which are unique - // The entries are `unit: (0, 1, 1.0, 2, 3, 5, 5.5, denominator's)` - // A `3` and `4` are always the same, and made inseparable in the code, so only `3` is tested for - // Since the negatives are supposed to be a complete mirror of the positives, the first half of the array is taken from the second - // Rules which only apply at higher counts are tested for lower as well anyway - let units-sl = ( - // Feminine, regular - cd: ("kandel", "kandela", "kandele", "kandeli", "kandele", "kandel", "kandele", "kandelo"), +#set text(lang: "fi") +#context { + assert.eq( + generate-unit-alt-description( + ..parse-unit("m^2").values(), + value: 1, + ), + "metri toiseen", + ) + assert.eq( + generate-unit-alt-description( + ..parse-unit("m^6").values(), + value: -2, + ), + "metriä potenssiin 6", + ) + assert.eq( + generate-unit-alt-description( + ..parse-unit("m/s/N").values(), + value: 1, + ), + "metri jaettuna sekunnilla jaettuna newtonilla", + ) +} - // Masculine, regular - A: ("amperov", "amper", "ampera", "ampera", "amperi", "amperov", "ampera", "amper"), - // Masculine, special hardcoded - d: ("dni", "dan", "dneva", "dneva", "dnevi", "dni", "dneva", "dan"), - H: ("henrijev", "henri", "henrija", "henrija", "henriji", "henrijev", "henrija", "henri"), - lm: ("lumnov", "lumen", "lumna", "lumna", "lumni", "lumnov", "lumna", "lumen"), - T: ("tesel", "tesla", "tesle", "tesli", "tesle", "tesel", "tesle", "teslo"), - "%": ("odstotkov", "odstotek", "odstotka", "odstotka", "odstotki", "odstotkov", "odstotka", "odstotek"), - "‰": ("odtisočkov", "odtisoček", "odtisočka", "odtisočka", "odtisočki", "odtisočkov", "odtisočka", "odtisoček"), +#set text(lang: "sl") +#context { + // [1/2] Tests the `phrases` the same way as English + // No special rules apply, hence the copied tests + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+-2e-2") + num-state.get(), + ), + "minus 1,34 plus minus 2 krat 10 na stopnjo -2", + ) + assert.eq( + generate-num-alt-description( + parse-numeral("-1.34+0.5-2e-2") + num-state.get() + (base: 2), + ), + "minus 1,34 plus 0,5 minus 2 krat 2 na stopnjo -2", + ) - // Masculine, special rule for `*ber/*ter` - L: ("litrov", "liter", "litra", "litra", "litri", "litrov", "litra", "liter"), + // [2/3] Tests the `prefixes` in a single test + // Use the `\u{00b5}` micro sign, not `\u{03bc}` + assert.eq( + unit-component-description("µA"), + "mikroamper", + ) - // Masculine, special rule for `*c/*j` - Gy: ("grejev", "grej", "greja", "greja", "greji", "grejev", "greja", "grej"), + // [3/3] Tests the `units` in its own way + + let nums = (-5.5, -5, -3, -2, -1.0, -1, 0, 1, 1.0, 2, 3, 5, 5.5, "1/") + + // Slovenian units, not all but the first which are unique + // The entries are `unit: (0, 1, 1.0, 2, 3, 5, 5.5, denominator's)` + // A `3` and `4` are always the same, and made inseparable in the code, so only `3` is tested for + // Since the negatives are supposed to be a complete mirror of the positives, the first half of the array is taken from the second + // Rules which only apply at higher counts are tested for lower as well anyway + let units-sl = ( + // Feminine, regular + cd: ( + "kandel", + "kandela", + "kandele", + "kandeli", + "kandele", + "kandel", + "kandele", + "kandelo", + ), - // Combined words - au: ("astronomskih enot", "astronomska enota", "astronomske enote", "astronomski enoti", "astronomske enote", "astronomskih enot", "astronomske enote", "astronomsko enoto"), - sym.degree + "C": ("stopinj Celzija", "stopinja Celzija", "stopinje Celzija", "stopinji Celzija", "stopinje Celzija", "stopinj Celzija", "stopinje Celzija", "stopinjo Celzija"), - ) + // Masculine, regular + A: ( + "amperov", + "amper", + "ampera", + "ampera", + "amperi", + "amperov", + "ampera", + "amper", + ), - for (key, words) in units-sl { - words = words.slice(1, -1).rev() + words - if nums.len() != words.len() { - panic("The `nums` and `words` arrays for `" + key + "` need to be of same length") - } + // Masculine, special hardcoded + d: ("dni", "dan", "dneva", "dneva", "dnevi", "dni", "dneva", "dan"), + H: ( + "henrijev", + "henri", + "henrija", + "henrija", + "henriji", + "henrijev", + "henrija", + "henri", + ), + lm: ( + "lumnov", + "lumen", + "lumna", + "lumna", + "lumni", + "lumnov", + "lumna", + "lumen", + ), + T: ("tesel", "tesla", "tesle", "tesli", "tesle", "tesel", "tesle", "teslo"), + "%": ( + "odstotkov", + "odstotek", + "odstotka", + "odstotka", + "odstotki", + "odstotkov", + "odstotka", + "odstotek", + ), + "‰": ( + "odtisočkov", + "odtisoček", + "odtisočka", + "odtisočka", + "odtisočki", + "odtisočkov", + "odtisočka", + "odtisoček", + ), - let pairs = nums.zip(words) - let (denom, denom-unit) = pairs.pop() + // Masculine, special rule for `*ber/*ter` + L: ( + "litrov", + "liter", + "litra", + "litra", + "litri", + "litrov", + "litra", + "liter", + ), - let guad(u, n) = generate-unit-alt-description( - ..parse-unit(u).values(), value: n, - ) + // Masculine, special rule for `*c/*j` + Gy: ( + "grejev", + "grej", + "greja", + "greja", + "greji", + "grejev", + "greja", + "grej", + ), - // All integer and float numbers - for (count, unit) in pairs { - assert.eq(guad(key, count), unit) - } - // When the unit is in a denominator; a hardcoded count here should be sufficient - assert.eq(guad(denom + key, 99), " na " + denom-unit) - } - } -} + // Combined words + au: ( + "astronomskih enot", + "astronomska enota", + "astronomske enote", + "astronomski enoti", + "astronomske enote", + "astronomskih enot", + "astronomske enote", + "astronomsko enoto", + ), + sym.degree + "C": ( + "stopinj Celzija", + "stopinja Celzija", + "stopinje Celzija", + "stopinji Celzija", + "stopinje Celzija", + "stopinj Celzija", + "stopinje Celzija", + "stopinjo Celzija", + ), + ) + for (key, words) in units-sl { + words = words.slice(1, -1).rev() + words + if nums.len() != words.len() { + panic( + "The `nums` and `words` arrays for `" + + key + + "` need to be of same length", + ) + } + let pairs = nums.zip(words) + let (denom, denom-unit) = pairs.pop() + let guad(u, n) = generate-unit-alt-description( + ..parse-unit(u).values(), + value: n, + ) -// #set document(title: "title") -// // Custom description -// #num(alt: "asd")[1.34] + // All integer and float numbers + for (count, unit) in pairs { + assert.eq(guad(key, count), unit) + } + // When the unit is in a denominator; a hardcoded count here should be sufficient + assert.eq(guad(denom + key, 1), " na " + denom-unit) + } +} -// hELLO -// // Auto description -// #num[-1.34+-2] -// #num[-8.34(3)] -// #num[1.34+-2e-2] -// #set text(lang: "fr") -// #num[-1.34+-2] -// #num[-8.34(3)] -// #num[1.34+-2e-2] -#zi.m-s2[2] -// #set text(lang: "CA") -// #num[-1.34+-2] -// #num[-8.34(3)] -// #num[1.34+-2e-2] diff --git a/tests/metadata/.gitignore b/tests/metadata/.gitignore index 8e21a98..2e4c5d8 100644 --- a/tests/metadata/.gitignore +++ b/tests/metadata/.gitignore @@ -2,3 +2,4 @@ /diff/ /out/ +/ref/