Golang : Mapping Iban to Dunging alphabets

For this tutorial, we will learn how to map Iban(Sea Dayak) language to the Dunging alphabets. According to this article by The Borneo Post, the Dunging alphabets was developed by Dunging ak Gunggu within a span of 15 years – from 1947 to 1962.

Handwritten notes in Dunging

Handwritten notes in Dunging

NOTE : I'm not an Iban and I do not speak Iban language. For me, I just want the world to know about the existence of this written language of the Iban people.It would be nice to let the future generations know about this form of written language.

To get this Dunging mapping program to work, you will need the code below and the fonts. --> Click here to download the fonts(zip file). <--

web interface dunging

Here you go!

 package main

 import (

 var dungingIbanMap = map[string]string{
  "ah": "ah.jpg",
  "ak": "ak.jpg",
  "an": "an.jpg",
  "am": "am.jpg",
  "as": "as.jpg",
  "ba": "ba.jpg",
  "eig":  "eig.jpg",
  "e": "E.jpg", // case insensitive
  "E": "E.jpg", // case insensitive
  "iem":  "iem.jpg",
  "il": "il.jpg",
  "is": "is.jpg",
  "ka": "ka.jpg",
  "na": "na.jpg",
  "oh": "oh.jpg",
  "ok": "ok.jpg",
  "op": "op.jpg",
  "pa": "pa.jpg",
  "sa": "sa.jpg",
  "un": "un.jpg",
  "uw": "uw.jpg",
  "a": "a.jpg", // case insensitive
  "A": "A.jpg", // case insensitive
  "al": "al.jpg",
  "ao": "ao.jpg",
  "at": "at.jpg",
  "cha":  "cha.jpg",
  "ein":  "ein.jpg",
  "ek": "ek.jpg",
  "ga": "ga.jpg",
  "ieng": "ieng.jpg",
  "ip": "ip.jpg",
  "it": "it.jpg",
  "la": "la.jpg",
  "nga":  "nga.jpg",
  "oi": "oi.jpg",
  "om": "om.jpg",
  "or": "or.jpg",
  "ra": "ra.jpg",
  "ta": "ta.jpg",
  "us": "us.jpg",
  "ya": "ya.jpg",
  "ang":  "ang.jpg",
  "ap": "ap.jpg",
  "au": "au.jpg",
  "da": "da.jpg",
  "eix":  "eix.jpg",
  "eng":  "eng.jpg",
  "ieh":  "ieh.jpg",
  "I": "I.jpg", // case insensitive
  "i": "I.jpg", // case insensitive
  "ir": "ir.jpg",
  "ja": "ja.jpg",
  "ma": "ma.jpg",
  "nya":  "nya.jpg",
  "O": "O.jpg", // case insensitive
  "o": "O.jpg", // case insensitive
  "ong":  "ong.jpg",
  "oug":  "oug.jpg",
  "R": "R.jpg", // case insensitive
  "r": "R.jpg", // case insensitive
  "ul": "ul.jpg",
  "ut": "ut.jpg",

 const inputPage = `<html><body>

 <form method="post" action="/dunging">
 <p><h1>Get Dunging alphabets</h2></p>

 <textarea name="input" rows="4" cols="50"></textarea><br>
 <input type="submit" name="Get Dunging Alpabets" value="Get Dunging Alpabets">
 <p><img src="https://www.omniglot.com/images/writing/iban2.gif"></p>

 var inputTemplate = template.Must(template.New("").Parse(inputPage))

 func dungingInputPageHandler(w http.ResponseWriter, r *http.Request) {

  conditionsMap := map[string]interface{}{}
  if err := inputTemplate.Execute(w, conditionsMap); err != nil {

 func dungingIban(w http.ResponseWriter, r *http.Request) {

  if r.FormValue("input") != "" {
 input := r.FormValue("input")

 header := `<!DOCTYPE html>
 function goBack() {
 <button onclick="goBack()">Go Back</button><br><br>`

 w.Write([]byte(fmt.Sprintf("%s", header)))

 for k, v := range strings.Fields(strings.ToLower(input)) {
 fmt.Println(k, v, dungingIbanMap[string(v)])
 img := "<img src='/fonts/" + dungingIbanMap[string(v)] + "'>"
 w.Write([]byte(fmt.Sprintf("%s", img)))

 footer := `</body></html>`
 w.Write([]byte(fmt.Sprintf("%s", footer)))



 func main() {

  mux := http.NewServeMux()
  mux.HandleFunc("/", dungingInputPageHandler)
  mux.HandleFunc("/dunging", dungingIban)

  fileServer := http.FileServer(http.Dir("./fonts"))
  mux.Handle("/fonts/", http.StripPrefix("/fonts", fileServer))

  port := ":9999"
  fmt.Println("Point your browser to localhost" + port)
  http.ListenAndServe(port, mux)

  // the program should executing here. Below are some of my research codes that you might be interested to explore later.

  // sanity check test
  //all := "is cha op sa or ya ma nya om au us ka it oi A ja ga ok E pa am as ieh iem ao oh ah ut al ak nga ieng an un ek ip a uw il I ra ap ta na da at ul eng la ein ba ong eix eig ir ang oug R O"

  //allSlice := strings.Fields(all)
  //for k, v := range allSlice {
  // fmt.Println(k, string(v), dungingIbanMap[string(v)])

  //ibanText := "Selamat Datai" <-- this is present day Iban(similar to BM) -- cannot use!
  //ibanText := "salamat datai" // <-- old way of writing?
  //ibanText := "chabut" // remember! the Dunging fonts were created back in 1962!!

  // nevermind, we use the first line of PANTUN IBAN LENYAU SURAT
  ibanText := []string{"da a ya ao", "la a ma ao", "ma ra ein ao", "ka a op it ya ao", "la a ma ao", "ja ma an"}

  for i, j := range ibanText {
 fmt.Println("Line : ", i)
 for k, v := range strings.Fields(strings.ToLower(j)) {
 fmt.Println(k, v, dungingIbanMap[string(v)])

  // first, scan for 2 characters because this group is the most common
  //processedIbanText := chunkSplit(ibanText, 2, " ")

  //lower case every characters
  //for _, v := range strings.Fields(strings.ToLower(processedIbanText)) {
  //fmt.Println(string(v), dungingIbanMap[string(v)])
  // if dungingIbanMap[string(v)] != "" {
  //  twoCharsMapped = append(twoCharsMapped, dungingIbanMap[string(v)])
  // } else {
  //  twoCharsMapped = append(twoCharsMapped, string(v))
  // }


 // from https://stackoverflow.com/questions/27516387/what-is-the-correct-way-to-find-the-min-between-two-integers-in-go
 func MinOf(vars ...float64) float64 {
  min := vars[0]

  for _, i := range vars {
 if min > i {
 min = i

  return min

 func translatedChangeDistance(old, new int) (delta float64) {
  diff := float64(new - old)
  delta = (diff / float64(old)) * 100
  return math.Abs(delta) // turn negative to positive

 func countMappings(inputMap []string) float64 {
  // how many items in the slice?
  length := len(inputMap)
  counter := 0
  for _, v := range inputMap {
 counter = counter + strings.Count(string(v), ".jpg")

  //fmt.Println("Length ", length)
  //fmt.Println("Counter ", counter)
  totalTranslated := translatedChangeDistance(length, counter)
  return totalTranslated

 // from https://www.socketloop.com/tutorials/golang-chunk-split-or-divide-a-string-into-smaller-chunk-example

 func chunkSplit(body string, limit int, end string) string {

  var charSlice []rune

  // push characters to slice
  for _, char := range body {
 charSlice = append(charSlice, char)

  var result string = ""

  for len(charSlice) >= 1 {
 // convert slice/array back to string
 // but insert end at specified limit

 result = result + string(charSlice[:limit]) + end

 // discard the elements that were copied over to result
 charSlice = charSlice[limit:]

 // change the limit
 // to cater for the last few words in
 // charSlice
 if len(charSlice) < limit {
 limit = len(charSlice)


  return result


Sample output:

sample out of dunging

Happy coding!










Malay-Iban dictionary

  See also : Golang : Gargish-English language translator

By Adam Ng(黃武俊)

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.