Intl CSS & JS: the comedy of pain



This content originally appeared on DEV Community and was authored by PixelPerfect Pro

drunk raccoon

You ever try to make your site “global-ready”? yeah, I did once.
I thought: “oh cool, I’ll just add a lang="ar" and ship it.”

two hours later: my navbar’s on the wrong side, my dates look like lottery numbers, and my boss says:
“hey, users in japan think our deal ends next year. fix it.”

That’s when I realized: css + js intl features are not optional. they’re survival gear.
So here’s my top 16 pain points turned into lessons — with jokes, blood.

1. Margins that betray you — margin-inline

old me:

.card { margin-left: 20px; }

rtl users: “wtf is this spacing?”
new me:

.card { margin-inline: 20px; }

🎤 Impression of my old css: “sorry bro, I only work in english.”
👉 mdn: logical props

2. Padding that loves both sides — padding-inline

if you still write padding-left and padding-right, you’re that guy at the gym using jeans instead of gym shorts.
don’t be that guy.

3. Vertical writing-mode

.text { writing-mode: vertical-rl; }

good for japanese.
bad for me the first time, because I rotated every div with transform: rotate(90deg).

🎤 “look at my app! it’s tetris!”

👉 mdn: writing-mode

4. :dir() selector

button:dir(rtl) { transform: rotate(180deg); }

it’s like a lie detector for direction.
“you rtl? i can tell. stop lying.”

5. line-break: loose vs strict

Asian languages don’t use spaces.
So your perfect grid? boom — text exploded like popcorn in a microwave.

👉 mdn: line-break

6. hyphens: auto

German words are like boss fights.

.text { hyphens: auto; }

without it, your layout screams “nein!”

7. text-transform with respect

Turkish devs still hate me for uppercasing “istanbul” wrong.

İ

vs

I

I learned the hard way.

👉 mdn: text-transform

8. font-variant-east-asian

ever see kana squished like a sandwich?
fix it with this.

p { font-variant-east-asian: ruby; }

9. Unicode-bidi — the nuclear switch

I once mixed hebrew + english in a chat app.
the text looked like my cat walked over the keyboard.
then i found this:

p { unicode-bidi: plaintext; }

instant fix.

10. list-style in other worlds

ul { list-style: arabic-indic; }

arabic numbers.
no more 1. 2. 3. — now it’s culturally correct.

JS Intl — the revenge arc

11. Intl.NumberFormat (aka stop replacing commas like a caveman)

new Intl.NumberFormat("de-DE").format(1234567.89);
// 1.234.567,89

before: I used .replace(".", ",").
after: I went to therapy.

12. Intl.DateTimeFormat (dates that don’t start wars)

new Intl.DateTimeFormat("ja-JP", { dateStyle: "full" })
  .format(new Date("2025-08-12"));
// 2025年8月12日火曜日

before: everyone thought our sale was in december.
after: we stopped refunding angry users.

13. Intl.PluralRules (no more “1 items”)

const pr = new Intl.PluralRules("ru-RU");
pr.select(3); // "few"

before: I used if (count === 1) ? "item" : "items".
russians: laughing at me like eddie murphy.

14. Intl.DisplayNames

new Intl.DisplayNames(["fr"], { type: "language" }).of("fr");
// "français"

before: “Language: fr.”
users: “what the hell is fr? a new crypto coin?”

15. Intl.RelativeTimeFormat

new Intl.RelativeTimeFormat("en", { numeric: "auto" })
  .format(-1, "day");
// "yesterday"

before: I wrote “1 days ago.”
qa wrote me up.

16. Intl.Collator (alphabet soup ordering)

["ä", "z"].sort(new Intl.Collator("de").compare);
// ["ä", "z"]

before: I sorted strings with localeCompare.
after: swedish users stopped emailing me about their alphabet rights.

Grand finale

Look — internationalization is not “advanced.”
It’s survival. it’s respect. It’s the difference between users loving your product… and users thinking your site was made by a drunk raccoon.

CSS logical props + js intl apis = no more pain emails at 3am.
and yes, my hand still hurts, but I’m smiling, because I don’t have to replace(".", ",") ever again.


This content originally appeared on DEV Community and was authored by PixelPerfect Pro