Supporting multiple "sitelen pi toki pona"

30 Dec 2021 - Genevieve Clifford

Toki Pona (lit. talk-good) is an artlang created by Sonja Lang (jan Sonja) in 2001. I’ve been learning Toki Pona over the past two weeks and would like to support the language on my website.

When I say “support”, I don’t mean internationalisation (i18n). i18n would require a concerted effort to translate every page on this website, and every future blog post into Toki Pona, and although I love the language, it really is infeasible for me. What I really mean is supporting different sitelen.


Sitelen is the Toki Pona word for ‘write’, ‘writing’, ‘drawing’, and so on. In this context, sitelen refers to the writing system used for Toki Pona. Most written Toki Pona is written using the Latin alphabet (sitelen Latina), but there are a myriad different writing systems, from logographic systems like sitelen pona created by jan Sonja to a hieroglyphic system called sitelen sitelen created by Jonathan Gabel.

I am thankfully in luck, as the hard work has already been done for me! The logographic sitelen pona has been transformed into two fonts: linja-pona and sitelen-pona-pona. sitelen sitelen can also be translated into SVG glyphs using the sitelen-sitelen JavaScript module, however, sitelen sitelen is meant to be used as a decorative style, and is not intended for day-to-day usage. This wouldn’t work in the context of this website, so I have decided to skip sitelen sitelen.

Both fonts convert text rendered in Latin unicode characters and transform them into sitelen pona logograms. Using them is trivial, you just need to set your website up to use the fonts through a bit of CSS, a bit like this:

@font-face {
  font-family: 'sitelen pona pona';
  src: url('path/to/sitelen-pona-pona.otf');
  font-style: normal;
  font-weight: 400;

What’s the big deal then?

Although it is easy to set a font up to be used on the website, I’d like to be able to give the reader the option to read Toki Pona using either sitelen Latina, sitelen pona pona, or linja pona, allowing them to choose. I also intend not to write entire posts or documents in Toki Pona, only fragments. What I’d like is a little reusable widget that lets me have the option to display fragments of Toki Pona in each of the aforementioned sitelen.

This is not as trivial (at least for me), so I’ve decided to document how I’ve done this using CSS and a bit of JavaScript.

Widget design

Because I use Jekyll to build this website, it means I can make use of Liquid, a templating language for Ruby. You could do something similar using eRB (say if you use Rails or middleman) or whatever myriad approaches there are in JS (or the language/framework of your choice).

I’ll design an include block and pass in content through a capture block, so I can use the following syntax in HTML or Markdown:

<!-- capture block: -->
{% capture toki-fragment-one %}
toki! mi toki e toki-pona!
{% endcapture %}

<!-- passing in content from capture into include: -->
{% include toki.html content=toki-fragment-one %}

Now let’s define the widget that toki.html refers to!

<!-- _includes/toki.html -->
<div class="toki-pona-container">
  <nav class="toki-nav">
      <li>Select sitelen:</li>
      <li><a class="current" href="javascript: void(0)" onclick="changeSitelen(this, 'sitelen-latina')">sitelen Latina</a></li>
      <li><a href="javascript: void(0)" onclick="changeSitelen(this, 'linja-pona')">linja pona</a></li>
      <li><a href="javascript: void(0)" onclick="changeSitelen(this, 'sitelen-pona-pona')">sitelen pona pona</a></li>
  <div class="toki-pona-content">
      {{ include.content }}

// assets/js/toki.js
function changeSitelen(container, sitelen) {
  const overallContainer = container.parentElement.parentElement.parentElement.parentElement;

  // set current link
  var linkList = overallContainer.getElementsByTagName('A');
  for (let item of linkList) {
    item.className = '';
  container.className = 'current';

  // change sitelen
  const contentContainer = overallContainer.getElementsByClassName('toki-pona-content')[0];
  const content = contentContainer.firstElementChild;
  content.className = sitelen;

<!-- _layouts/default.html -->
<!-- ... -->
  <!-- ... -->
  <script src="/assets/js/toki.js"></script>
  <!-- ... -->

// _sass/main.scss

// ...
// toki pona rendering
.linja-pona {
  font-family: 'linja pona';
  font-feature-settings: "liga" 1, "clig" 1, "calt" 1, "kern" 1, "mark" 1;
  text-rendering: optimizeLegibility;
  font-size: 1.4em;

.sitelen-pona-pona {
  font-family: 'sitelen pona pona';
  text-rendering: optimizeLegibility;
  font-feature-settings: "liga" 1;
  font-size: 1.4em;

.sitelen-latina {
  font-family: 'Space Mono', 'Courier New', Courier, monospace;
  font-size: 1em;

div.toki-pona-container {
  border: 1px dotted #ffb000;
  border-radius: 5px;
  nav.toki-nav {
    font-size: small;
    border-bottom: 1px dotted #ffb000;
    padding: 10px;
  div.toki-pona-content {
    padding: 10px;

I know JS enthusiasts are about to excommunicate me to the sun based on the code I’ve written, I am sincerely sorry, but I have little respect for the language. What we’ve got here is a drop-in widget for rendering Toki Pona!

When used as detailed above, Jekyll includes the block and passes in content as defined in the Liquid block. This creates a div with a nav for changing sitelen, along with a space below in which the writing is rendered. When a sitelen link is clicked, the changeSitelen() method is called, which changes the class of the nested div to either linja-pona, sitelen-pona-pona, or sitelen-latina. These correspond to classes defined in CSS, changing this through JS changes the font (and some applicable font settings) rendered in the nested div, thus changing the sitelen.

The aforementioned phrase in the syntax written above is rendered as follows:

toki! mi toki e toki-pona!

Example and discussion

Success! Well, qualified success. Having done some testing, the thing works in that it will render whatever you throw into it in the corresponding typeface. However, that doesn’t mean that it works entirely correctly. I’ll show you what I mean:

toki! mi jan Senewije Kilipo, mi meli-tonsi en mi pali sin lon [tomo sona pi ma Apatawe].
mi kama sona e sona pi ilo sona. jan li pilin ike tan jan ike lon ilo sona, la mi pona e ona.
mi kama sona lon [tomo sona pi ma Apatawe] en [tomo sona pi ma Peminan]. mi kama jo e lipu pona pi [Best-Overall-Performance] tan tomo sona pi ma Apatawe.
musi pi kama jan ante en sitelen toki pi ilo sona (toki pi ilo sona Rubi, toki pi ilo sona Piton, en toki pi ilo sona Sawa) en lukin pi tomo tawa pi jan mute en musi pi musi kute li pona tawa mi.

The above text is a translation of my about page into Toki Pona and contains a number of English transliterations, like my name (jan Senewije Kilipo), and place names for Swansea and Birmingham (ma Apatawe and ma Peminan respectively). These look fine in sitelen Latina and sitelen pona pona (where they appear in cartouches), but don’t work properly in linja pona. Maybe this is a PEBKAC issue, but no matter what I type, it doesn’t embed sitelen Latina in a cartouche!

Another problem that the design doesn’t address is that of default sitelen. Although the user can choose between sitelen on a block-by-block basis, it is a little annoying to have to do this (if a user doesn’t want to see sitelen Latina by default). I’d like to implement cookies to control this, in a similar way to how the toggle glow effect works. I’d actually like to overhaul the way that’s implemented too and use a settings page or drop-down for all these settings, but I’ll do that in a later revision!

I hope that you found this useful, or if not useful, at least interesting!

The Information Exchange is the personal website of Genevieve Clifford, made with love between 2019 and 2022.
Creative Commons Licence
Privacy Policy.