Devanagari on the web: the parts that still break
Adding Nepali to a website looks like a translation job. You get the copy translated, you drop it in, it renders, everyone signs off. Then the bugs start arriving, and they are never in the translation.
This is the list we have accumulated. None of these are exotic. We have hit every one of them on real projects.
1. Font fallback silently mangles conjuncts
Devanagari joins consonants into conjunct forms, and rendering them correctly depends on the font containing the right ligatures and the shaping engine being given a font that supports the script.
If your CSS specifies a Latin-only font first, the browser falls back for the characters that font lacks. Sometimes that fallback is a font with poor Devanagari coverage, and you get conjuncts broken into separate glyphs with visible halant marks, or inconsistent shaping between paragraphs.
The fix is to be explicit rather than to hope. Declare a Devanagari-capable font in the stack for Nepali content, and check it on Windows, Android, iOS and Linux — the default system fonts differ on each, and so does the result.
Test on the operating systems your visitors use, not the one you develop on. Devanagari fallback is one of the areas where they genuinely disagree.
2. Line height that was fine for Latin is not fine here
Devanagari carries vowel marks above the shirorekha and below the baseline. Set the line height at a value tuned for Latin text and those marks collide with the line above and below.
Nepali text generally needs more leading than the equivalent Latin text at the same size. On a bilingual page this means the two languages usually need slightly different line-height values, not one shared number. It is a small CSS change and it is the difference between text that looks typeset and text that looks broken.
3. Mixed-script line breaking
A sentence in Nepali containing a Latin product name, a number, a phone number or a URL is extremely common. Browsers break these lines at points that are technically permitted and visually wrong, splitting a phone number across two lines or orphaning a single Latin word.
Non-breaking spaces and explicit word-break rules solve it, but only if somebody notices. This is the category of bug that gets found by a native reader looking at the page, not by any automated test.
4. Search and sorting ignore normalisation
This is the one that causes real damage, because it is invisible.
Unicode allows the same visible text to be encoded more than one way. Two strings can look identical on screen and be different byte sequences. If a user types their name into a search box using one input method and the record was saved through another, an exact-match query returns nothing. The record is there. The search says it is not.
The fix is to normalise consistently — pick a normalisation form, apply it on write and on query, and make sure your database collation agrees with your application. This must be decided early. Retrofitting it means rewriting existing rows, and by then you have data in both forms.
Sorting has the same root cause. A naive byte sort does not produce Nepali alphabetical order. If you are showing an ordered list of names to a Nepali reader, you need locale-aware collation, or the list will look arbitrary to the people using it.
5. Validation written for Latin rejects valid names
Somewhere in nearly every codebase is a name field validated against a pattern that permits A–Z, spaces and maybe an apostrophe. Every Nepali name entered in Devanagari fails it.
The same applies to address fields, to "letters only" rules, and to any length limit written assuming one character is one byte. A Devanagari string that is fifteen characters on screen can exceed a byte limit set at thirty.
Our rule now is that name and address fields accept Unicode letters by default, and any limit is counted in characters, not bytes. Rejecting a person's actual legal name is not validation, it is a defect.
6. Numerals need a decision, not a default
Devanagari has its own numeral forms. Nepali content sometimes uses them, frequently uses Western Arabic numerals, and often mixes both — dates in one form and prices in another is entirely normal.
There is no universally correct answer, which is exactly why it needs to be an explicit decision recorded in the project rather than left to whoever types the next page. Pick a rule per content type and write it down.
7. The date is not the date
Nepal uses the Bikram Sambat calendar for official and everyday purposes alongside the Gregorian calendar. A system storing only one of them will eventually be asked to display the other.
Store the underlying timestamp in a single unambiguous form, convert for display, and be explicit in the interface about which calendar a given date is in. Ambiguous dates cause errors that are found late and are expensive when they are found.
What we do about it
We keep a standing checklist covering all of the above and run it on every bilingual project, plus a page of test strings — conjuncts, mixed script, long names, both numeral sets, both calendars — that we render on every target platform before launch.
It is not sophisticated. It just means we stop rediscovering the same seven bugs on every project, which is the entire point. This is one of the threads described on our research page, and it is the one that has paid for itself fastest.