Hîsyêô Syllabary

Newest candidate for Koqatha's official writing system.

by MadcapJake

HTML

<label>
  <input id="quoteTypeDoubleAngle" type="radio" name="quoteType" checked /> 《 and 》
</label>
<label>
  <input id="quoteTypeSquare" type="radio" name="quoteType" /> 「 and 」
</label>
<br /><br />
<div class="inWrapper">
  <label>Latin:</label>  
  <textarea id="latinIn" cols="80" rows="3" spellcheck="false">
    zowo hônyo cûtî bûlo fîkî ulyô socok xe kôs zoston mût boxô dîzel yê zowo legêfû onô.
  </textarea>
  <button id="copyHisyeo" type="button">Copy 👇</button>
</div>
<div class="hidden" id="hisyeoOutText"></div>
<div id="hisyeoOut"></div>

CSS

@import url('https://fonts.cdnfonts.com/css/charis-sil');
@import url('https://fonts.cdnfonts.com/css/doulos-sil');
@import url('https://fonts.cdnfonts.com/css/gentium-plus');
@import url('https://fonts.cdnfonts.com/css/noto-sans');

@font-face {
  font-family: HisyakuiSans;
  src: url('https://hisyeo.github.io/HisyakuiSans.woff2');
}


* {
  /* font-family: 'Charis SIL', sans-serif; */
  font-family: 'Gentium Plus', sans-serif;
  /* font-family: "Noto Sans", sans-serif; */
  /* font-family: "Arial", sans-serif; */
  
}

.inWrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

#hisyeoOut {
  font-family: HisyakuiSans, Helvetica, sans-serif;
  margin-top: 5px;
  padding: 3px;
  border: 2px solid black;
  width: auto;
  min-height: 20px;
  border-radius: 5px;
  font-size: 2em;
  background-color: white;
}


.hidden {
  display: none;
}

label {
  padding-right: 20px;
}

button {
  margin: 3px;
  color: black;
}

button.flash {
  animation: flash 1s linear forwards;
}

@keyframes flash {
 0% { color: red; }
 100% { color: black; } 
}

JavaScript

const quotation = ['\u25D6', '\u25D7'],
        diacritic = '\u0304',
        lCons =  ' hkgtcsxdzbfmnwly', sCons = ' hkgtcsxdzbfmnwly',
        lVowels = 'ôuûiîeê', sVowels = 'orujiqe',
        lDiacritics = 'ktlnsc', sDiacritics = 'KTLNSC';

quoteTypeDoubleAngle.oninput = quoteTypeSquare.oninput = () => latinIn.oninput()

index = (loc, val) => loc.indexOf(val.toLowerCase())

latinIn.oninput = function (e) {
    let quotation = quoteTypeSquare.checked ? ['「 ', ' 」'] : ['《 ', ' 》']
    hisyeoOutText.innerText = latinIn.value
        // Pre-process quotation marks, replacing with [ and ] as placeholder quotation marks
        .split('"')
        .reduce((acc, v, i) => acc + (i % 2 ? '[' : ']') + v)
        // Pre-process proper nouns, adding { and } as placeholder transliteration marks
        .replace(/\b[A-ZÔÊÎÛ][A-ZÔÊÎÛa-zôêîûꞌ']*(?: [A-ZÔÊÎÛ][A-ZÔÊÎÛa-zôêîûꞌ']*)*/g, '{$&}')
        // Replace abugida characters
        .replace(
            /([hkgtcsxdzbfmnwly])o(?=[oôuûiîeê])|([hkgtcsxdzbfmnwly])?([oôuûiîeê])([ktlnsc](?![oôuûiîeê]))?|([hkgtcsxdzbfmnwly])(?![oôuûiîeê])/gi, // RegEx: cons?+vowel+n? | const
            (_, p0, p1, p2, p3, p4) => {
                // console.log(`p0: ${p0}\tp1: ${p1}\tp2: ${p2}\tp3: ${p3}\tp4: ${p4}`)
                return p0 ? sCons[index(lCons, p0)] + 'A' :             // default vowel saver
                  p4 ? sCons[index(lCons, p4)] :                        // null onset
                    (sCons[(p1 ? index(lCons, p1) : -1)] ?? '') +       // onset
                    (sVowels[index(lVowels, p2)] ?? (!p1 ? 'a' : '')) + // vowel
                    (p3 ? sDiacritics[index(lDiacritics, p3)] : '')     // coda
            }
                      
        )
        // Replace punctuation
        .replace(/\[/g, quotation[0])
        .replace(/]/g, quotation[1])
        .replace(/\{/g, '〈 ')
        .replace(/}/g, ' 〉')
        // Replace newlines with a placeholder character to later...