logo
Kurashizu Blogwhere ideas flow
  • Home
  • News
  • Blog
  • About
  • Home
  • News
  • Blog
  • About

© 2026 Kurashizu. All rights reserved.

Admin·New Post·Service Status
Powered by Cloudflare·30.10.26
← Back to news

Noto means "no tofu": fixing dotted circles in Myanmar text

Original article
datocms.com|44 points|25 comments|by steffoz|Oct 6, 2026

Noto means "no tofu": fixing dotted circles in Myanmar text

By Roger Tuan, Ronak Ganatra, and Silvano Stralla
Posted on October 6th, 2026

Author 1 Author 2 Author 3

⚡ TL;DR

A client noticed that content written in S'gaw Karen was rendering with strange dotted circles when viewed in Firefox. Instead of a quick patch for one language, we dove deep into the mechanics of typography, eventually implementing a fix that supports 43 different scripts.

The CMS now utilizes Google's Noto fonts as a fallback for scripts the user's OS cannot render, loading them dynamically only when required. We discovered that true localization involves much more than just translation—it requires a deep dive into locale codes, font fallbacks, and text direction.


The "Tofu" Problem 🫠

It started with a support ticket: Fix S'gaw Karen text rendering in Firefox. For those unfamiliar, S'gaw Karen is a language primarily spoken in Thailand and Myanmar.

In Firefox, the text wasn't just "wrong"—it was littered with dotted circles around characters. This led us down a technical rabbit hole involving Unicode and the complexities of global text rendering.

Rendering Issue

If you manage a multilingual site via a headless CMS, the lessons we learned are likely applicable to your frontend as well. We've split this exploration into two parts: what we did and why it matters for you.

Localization is a Stack, Not a Single Step

Many people think localization is just translating text into common languages like English, Spanish, or French. However, those all share the Latin alphabet. Even adding Mandarin is just the beginning.

Real localization is a multi-layered architectural decision:

The Localization Framework

LayerCore QuestionDatoCMS Implementation
ModelWhich content needs translation?Field-level localization; optional translations per model.
LocaleWhich language and region?Specific codes like en-GB or pt-BR (crucial since Swiss German ≠\neq= Austrian German).
WorkflowWho translates, QAs, and publishes?Locale-based permissions, scheduling, and AI Translation plugins.
DeliveryWhat happens if a translation is missing?Use of fallbackLocales, _locales, and _allFieldLocales in the API.
DirectionWhich way does the text run?LTR (Left-to-Right), RTL (Right-to-Left), or TTB (Top-to-Bottom).
RenderingCan the device actually draw the glyphs?Ensuring the CMS and frontend can render the specific script.

Note: Most developers focus on the top of this stack. However, the bottom layer—Rendering—is where rare scripts break, and it's often invisible until a user with a specific OS/browser combination encounters it.


The Nuance: Language≠Script≠Locale\text{Language} \neq \text{Script} \neq \text{Locale}Language=Script=Locale

This is where things get complex. These three concepts do not always align linearly.

  • S'gaw Karen is a language, but it uses the Myanmar script (also used by Burmese, Shan, and Mon).
  • Serbian can be written in either Cyrillic or Latin scripts.
  • Punjabi uses Gurmukhi in India but Shahmukhi in Pakistan.
  • Locale codes vary: kar refers to Karen languages generally, while ksw specifically denotes S'gaw Karen.

Complex Script Behaviors

Latin-based reading doesn't prepare you for how other scripts function:

  • Stacking: Myanmar and Balinese scripts stack consonants vertically.
  • Reordering: In Khmer and Myanmar, some vowels are typed after a consonant but rendered before it.
  • Spacing: Lao, Khmer, and Myanmar typically do not use spaces between words.
  • Directionality: 6 of our 43 new scripts are RTL (Right-to-Left), including Adlam, N'Ko, and Syriac.

Script Samples

Here is how some of these scripts look when rendered correctly:

ScriptSamplePhonetic/LiteralUsed For
Myanmarမြန်မာMyanmarBurmese, S'gaw Karen, Mon
GeorgianქართულიKartuliGeorgian, Svan
EthiopicግዕዝGe'ezAmharic, Tigrinya
Khmerខ្មែរKhmerKhmer
Tibetanབོད་BödTibetan, Dzongkha
CherokeeᏣᎳᎩTsalagiCherokee
TifinaghⵜⵉⴼⵉⵏⴰⵖTifinaghTamazight

Understanding "Tofu" and Dotted Circles

When a browser fails to render a script, it usually happens in one of two ways:

  1. Tofu (The Empty Box): The browser searched every available font and found no glyph for that character. It renders a □\square□ (hence the name "tofu").
  2. Dotted Circles: The browser found a font, but the text shaping engine failed to combine the characters. In scripts like Myanmar, syllables are built from a base letter plus modifiers. If they can't be stitched together, the modifier is placed on a dotted circle—essentially the browser saying, "I have this mark, but I don't know which letter it belongs to."

Tofu vs Rendered

Because rendering depends on the OS, the browser, and installed fonts, you cannot simply "fix it once." Every user has a different fallback chain.

The Solution: Noto Fonts

To solve this, we implemented Google's Noto (which literally stands for "No Tofu") fonts. Instead of relying on the user's system, the CMS now provides a reliable fallback.

To keep performance high, we don't load every script at once. We use a dynamic loading strategy:

// Conceptual logic for dynamic font loading
if (contentContainsScript(scriptId)) {
  loadNotoFont(scriptId); 
}

After Fix

Your Font Hunting Checklist

If you are building a truly global application, use this checklist to ensure your users aren't seeing tofu:

  • Identify all target scripts (not just languages).
  • Test across multiple OS/Browser combos (Windows/Chrome ≠\neq= macOS/Safari ≠\neq= Linux/Firefox).
  • Verify text direction (Ensure dir="rtl" is applied to the HTML element for RTL scripts).
  • Implement a robust fallback chain (e.g., font-family: 'YourBrandFont', 'Noto Sans Myanmar', sans-serif;).
  • Check for "shaping" issues (Look for those dreaded dotted circles).

Agentic Commerce