{ core, document, helpers, symbols, styles, toTex, ... }: { maxStars ? 5, ... }: let inherit(core) debug indentation list number set string type; inherit(document) Multilingual; inherit(helpers) formatSection; inherit(symbols.forkAwesome) star star-half-o star-o; toTex' = body: string.concatWith " " (toTex body); languageLevels = { "native" = { description = { deu = "Muttersprache"; eng = "Native Language"; }; level = Multilingual { deu = "nativ"; eng = "native"; }; stars = 1.0; }; "C2" = { description = { deu = "Kompetente Sprachverwendung"; eng = "Proficient User"; }; level = "C2"; stars = 7 / 8.; }; "C1" = { description = { deu = "Kompetente Sprachverwendung"; eng = "Proficient User"; }; level = "C1"; stars = 6 / 8.; }; "B2" = { description = { deu = "Selbstständige Sprachverwendung"; eng = "Independent User"; }; level = "B2"; stars = 5 / 8.; }; "B1" = { description = { deu = "Selbstständige Sprachverwendung"; eng = "Independent User"; }; level = "B1"; stars = 4 / 8.; }; "A2" = { description = { deu = "Elementare Sprachverwendung"; eng = "Basic User"; }; level = "A2"; stars = 3 / 8.; }; "A1" = { description = { deu = "Elementare Sprachverwendung"; eng = "Basic User"; }; level = "A1"; stars = 2 / 8.; }; "latinum" = { description = { deu = "Latinum"; eng = "Latinum"; }; level = null; stars = 1 / 8.; }; }; languageNames = { ces = { deu = "Tschechisch"; eng = "Czech"; }; deu = { deu = "Deutsch"; eng = "German"; }; eng = { deu = "Englisch"; eng = "English"; }; epo = { deu = "Esperanto"; eng = "Esperanto"; }; heb = { deu = "Ivrit"; eng = "Ivrit"; }; lat = { deu = "Latein"; eng = "Latin"; }; }; rateHalfStars = value: maximum: let full = number.floor (value * maximum); empty = number.floor ((1 - value) * maximum); half = maximum - full - empty; in (list.generate (_: star) full) ++ (list.ifOrEmpty (half != 0) star-half-o) ++ (list.generate (_: star-o) empty); formatLanguage = name: { description, level, stars, ... }: let name' = styles.skillType (toTex' (Multilingual name)); level' = if level != null then styles.skillSet (toTex' level) else ""; description' = styles.description (toTex' (Multilingual description)); stars' = if stars != null then string.concat (rateHalfStars stars maxStars) else ""; in "${name'} & ${description'} & ${level'} & ${styles.entryLocation stars'} \\\\%"; in languages: let emptyLevel = { description = ""; level = ""; stars = 0; }; languages' = set.mapToList ( language: level: { name = languageNames.${language} or language; level = type.matchPrimitiveOrPanic level { null = emptyLevel; int = debug.panic "languages'" { text = "Level of type integer must be between 0 and `maxStars` (${string maxStars}) inclusive, got:"; data = level; when = level < 0 || level > maxStars; } ( emptyLevel // { stars = 1.0 * level / maxStars; }); float = debug.panic "languages'" { text = "Level of type float must be between 0.0 and 1.0 inclusive, got:"; data = level; when = level < 0.0 || level > 1.0; } ( emptyLevel // { stars = level; }); set = emptyLevel // level; string = languageLevels.${level}; }; } ) languages; compare = foo: bar: foo.level.stars > bar.level.stars; stars' = string.concat (rateHalfStars 0 maxStars); in formatSection ( Multilingual { deu = "Sprachen"; eng = "Languages"; } ) ( [ "\\vspace{-1em}%" "\\begin{center}%" indentation.more "\\setlength{\\tabcolsep}{1ex}%" "\\setlength{\\extrarowheight}{0pt}%" "\\begin{tabularx}{\\textwidth}{rXrl}%" indentation.more ] ++ ( list.map ({ name, level }: formatLanguage name level) (list.sort compare languages') ) ++ [ indentation.less "\\end{tabularx}%" indentation.less "\\end{center}%" ] )