<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Sitey]]></title><description><![CDATA[Sitey]]></description><link>https://siteypk.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6acbc3aec36c2eed5cd21d2e/f0e26432-b242-4c8c-a4f3-673ffecac3a0.png</url><title>Sitey</title><link>https://siteypk.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Mon, 12 Oct 2026 16:52:15 GMT</lastBuildDate><atom:link href="https://siteypk.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Urdu on Android: phone numbers that swap halves, and other RTL bugs]]></title><description><![CDATA[Sitey is an Android app for people in Pakistan. It makes visiting cards, invoices, menus, result cards and shadi cards, in Urdu and English, with Urdu set in Nastaliq. Most of our Urdu bugs had nothin]]></description><link>https://siteypk.hashnode.dev/urdu-on-android-phone-numbers-that-swap-halves-and-other-rtl-bugs</link><guid isPermaLink="true">https://siteypk.hashnode.dev/urdu-on-android-phone-numbers-that-swap-halves-and-other-rtl-bugs</guid><category><![CDATA[Android]]></category><category><![CDATA[Kotlin]]></category><category><![CDATA[localization]]></category><dc:creator><![CDATA[Sitey]]></dc:creator><pubDate>Sun, 11 Oct 2026 18:07:20 GMT</pubDate><content:encoded><![CDATA[<p>Sitey is an Android app for people in Pakistan. It makes visiting cards, invoices, menus, result cards and shadi cards, in Urdu and English, with Urdu set in Nastaliq. Most of our Urdu bugs had nothing to do with the font. They came from numbers, direction and line height. Here are the ones that cost us the most time, and what fixed them.</p>
<h2>Phone numbers that swap halves</h2>
<p>A user types this into the phone field of an Urdu visiting card:</p>
<pre><code>0300 1234567
</code></pre>
<p>The card shows <code>1234567 0300</code>.</p>
<p>Nothing changed the text. In a right-to-left paragraph the Unicode bidi algorithm sees the space as a break between two separate number runs, and it lays those runs out right to left. In Pakistan phone numbers are usually written with a space (<code>0300 1234567</code>, <code>+92 300 1234567</code>), and account numbers come in groups too, so this shows up on cards, invoices and fee challans.</p>
<p>The fix is to wrap every multi-part number in a left-to-right isolate (<code>U+2066</code> LRI … <code>U+2069</code> PDI) when we draw it:</p>
<pre><code class="language-kotlin">private const val DIGIT = "[0-9\u06F0-\u06F9\u0660-\u0669]"
/** A number with at least one space, dash, slash, dot, colon or comma between digit groups. */
private val spacedNumber = Regex("\\+?$DIGIT+(?:[ \\-/.:,]$DIGIT+)+")

fun isolateNumbers(text: String): String =
    if (!hasUrdu(text)) text
    else spacedNumber.replace(text) { "\u2066${it.value}\u2069" }
</code></pre>
<p>Three details mattered:</p>
<ul>
<li><strong>Only at render time.</strong> The saved text is never changed, so copying or editing the field gives back exactly what the user typed.</li>
<li><strong>Urdu and Arabic-Indic digits too.</strong> An Urdu keyboard can type <code>۰۳۰۰</code> instead of <code>0300</code>.</li>
<li><strong>Don't isolate twice.</strong> Our real version skips parts that are already inside an isolate, and tests check that English text and single numbers are left alone.</li>
</ul>
<h2>"1800" became "180 0"</h2>
<p>On a zoomed-in invoice preview, a price of 1800 could show a gap: <code>180 0</code>. We set the text paint to linear text and subpixel positioning, and we measure with the same paint and the same isolation we draw with. If you measure with one paint and draw with another, numbers will drift.</p>
<h2>Tables have to be mirrored, not just right-aligned</h2>
<p>An Urdu invoice isn't an English invoice with right-aligned text. The first column (item name) goes on the right, and the totals go on the left. We draw invoices, result cards and exam date sheets as their mirror image in Urdu. A device test checks that the first column really is the rightmost one in Urdu, and the leftmost in English as a control.</p>
<h2>Nastaliq is tall, so prices floated</h2>
<p>Nastaliq lines are much taller than Latin lines, because the letters slope and stack. On a menu, prices were drawn from the top of each dish line, so next to a tall Urdu dish name the price hung near the top of the row. We now centre the price on the dish line.</p>
<p>The same height problem shows up on the web. Our site uses <code>line-height: 2.4</code> for Urdu body text and about 2 for Urdu headings, against 1.6 for English. Below that, the dots and tails of one line run into the next.</p>
<h2>Bottom sheets forgot the direction</h2>
<p>The app was in Urdu (right to left), but bottom sheets opened left to right. In Compose a bottom sheet opens in its own window, and it doesn't take the layout direction from the screen behind it. We set the direction again inside our shared sheet component, and that fixed six sheets at once.</p>
<h2>The 260 KB font on English pages</h2>
<p>Our website has an "اردو" button on every English page. That one word made every English page download Noto Nastaliq Urdu, about 260 KB, and Lighthouse put it on the first-paint path. A prompt page scored 65 on mobile performance, with a 6-second LCP.</p>
<p>The fix was one CSS rule: on English pages, Urdu links use the phone's own Arabic-script font.</p>
<pre><code class="language-css">html:not([lang="ur"]) a[lang="ur"] {
  font-family: system-ui, "Noto Naskh Arabic", "Noto Sans Arabic", sans-serif;
  line-height: inherit;
}
</code></pre>
<p>Urdu pages still load Nastaliq. The same page then scored 100 in a local Lighthouse run.</p>
<h2>What I'd check first in any Urdu or Arabic app</h2>
<ol>
<li>Type a phone number with a space into an RTL field and look at it.</li>
<li>Draw prices on a zoomed preview and look for gaps.</li>
<li>Open every bottom sheet and dialog in RTL.</li>
<li>Put a long Nastaliq line next to anything that should line up with it.</li>
<li>See which fonts your English pages download.</li>
</ol>
<p>You can see the Urdu pages at <a href="https://app.sitey.pk/ur/">app.sitey.pk/ur/</a>. If you've hit other RTL bugs, I'd like to hear about them in the comments.</p>
<p><em>This post was written with AI assistance, from our own code and commit history.</em></p>
]]></content:encoded></item></channel></rss>