61.1 같은 숫자인데 나라마다 다르게 보인다고요?

숫자 1234567.891을 화면에 뿌려볼게요. 우리 눈엔 1,234,567.891이 자연스럽죠. 세 자리마다 콤마, 소수점은 점. 그런데 독일 사람이 보면 이상해요. 독일에선 1.234.567,891처럼 점과 콤마가 정반대거든요.


진짜 그런지 Intl.NumberFormat(자바스크립트 국제화 숫자 포맷터)으로 같은 숫자를 나라별로 찍어봤어요.


const n = 1234567.891;
new Intl.NumberFormat("en-US").format(n);
new Intl.NumberFormat("de-DE").format(n);
new Intl.NumberFormat("fr-FR").format(n);
new Intl.NumberFormat("ar-EG").format(n);
new Intl.NumberFormat("hi-IN").format(n);


결과예요.


en-US: 1,234,567.891
de-DE: 1.234.567,891
fr-FR: 1 234 567,891
ar-EG: ١٬٢٣٤٬٥٦٧٫٨٩١
hi-IN: 12,34,567.891


보세요. 독일은 점과 콤마가 뒤바뀌고, 프랑스는 공백으로 자리를 끊어요. 이집트 아랍어는 아예 숫자 모양(아랍-인도 숫자)이 다르고, 인도(hi-IN)는 12,34,567처럼 세 자리가 아니라 두 자리씩 끊어요. 우리가 당연하다고 여긴 콤마 규칙이 사실은 지역 약속일 뿐인 거죠.

61.2 그럼 콤마를 직접 찍으면 안 되나요?

세 자리마다 콤마를 끼우는 함수를 손수 짤 수도 있어요. 저도 그랬죠. 그런데 방금 봤듯 세 자리 규칙 자체가 지역마다 다르니 인도용으로 다시 짜고 소수점 기호 바꾸다 보면 함수가 걷잡을 수 없이 커져요. 이 골치 아픈 걸 브라우저와 Node가 이미 내장하고 있어요. 바로 Intl.NumberFormat이고, 만드는 법은 간단해요.


const nf = new Intl.NumberFormat("ko-KR");
nf.format(1234567.891);
// 결과: 1,234,567.891


첫 번째 인자가 로케일(locale, 언어와 지역 코드)이에요. "ko-KR"은 한국어-대한민국, "de-DE"는 독일어-독일이죠. 이 값 하나만 바꾸면 콤마 위치, 소수점 기호, 자리 묶는 방식이 알아서 그 지역 것으로 바뀌어요. 같은 형식을 여러 번 쓸 땐 한 번 만들어 재사용하는 편이 빨라요.

61.3 통화는 어떻게 붙이죠?

돈 단위는 함정이 많아요. 앞에 "₩"만 붙이면 될 것 같지만 기호 위치소수점 처리도 나라마다 다르거든요. 포맷터에 style을 "currency"로 주고 currency에 통화 코드(ISO 4217, 세 글자짜리 통화 코드)를 넘겨요.


new Intl.NumberFormat("ko-KR", { style: "currency", currency: "KRW" }).format(15000);
new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(1234.5);
new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(1234.5);
new Intl.NumberFormat("ja-JP", { style: "currency", currency: "JPY" }).format(1234.5);


찍어보면 이래요.


ko-KR KRW: ₩15,000
en-US USD: $1,234.50
de-DE EUR: 1.234,50 €
ja-JP JPY: ¥1,235


차이가 확 보이죠. 유로는 독일식이라 기호가 뒤에 붙고 소수점도 콤마예요. 특히 일본 엔은 소수점이 아예 없어요. 엔은 보조 단위를 안 쓰니 1234.5가 반올림돼 ¥1,235로 나와요. 통화별 규칙표를 currency 옵션 하나가 다 아는 셈이죠. 하나, currency를 생략하면 에러라 style이 currency면 통화 코드는 꼭 줘야 해요.

61.4 기호 말고 코드나 이름으로 보여주려면요?

가끔 "$" 대신 "USD"처럼 코드로 보여주고 싶을 때가 있어요. 여러 통화를 한 표에 나열하면 기호만으론 헷갈리니까요. 이건 currencyDisplay 옵션으로 정해요.


const v = 1234.5;
const opt = { style: "currency", currency: "USD" };
new Intl.NumberFormat("en-US", { ...opt, currencyDisplay: "symbol" }).format(v);
new Intl.NumberFormat("en-US", { ...opt, currencyDisplay: "code" }).format(v);
new Intl.NumberFormat("en-US", { ...opt, currencyDisplay: "name" }).format(v);


결과예요.


symbol: $1,234.50
code: USD 1,234.50
name: 1,234.50 US dollars


기본값은 symbol(기호)이에요. code는 통화 코드를, name풀어 쓴 이름을 붙여줘요. name은 로케일을 "ko-KR"로 바꾸면 "미국 달러"처럼 한국어로 나와요. 정산 내역처럼 어느 통화인지 또렷해야 하는 곳에선 code나 name이 훨씬 안전해요.

61.5 퍼센트랑 단위도 되나요?

되고말고요. 같은 포맷터가 퍼센트단위(unit)까지 담당해요. 퍼센트는 style을 "percent"로 줘요. 여기서 자주 넘어지는데, 퍼센트는 0.12를 넣어야 12%로 나와요. 0과 1 사이 비율을 넣어야지, 12를 넣으면 1,200%가 돼버려요.


new Intl.NumberFormat("ko-KR", { style: "percent" }).format(0.1234);
new Intl.NumberFormat("ko-KR", { style: "percent", minimumFractionDigits: 1 }).format(0.1234);


결과
12%
12.3%


기본은 소수점을 버려 12%, 자릿수를 주면 12.3%처럼 살려요. 단위는 style을 "unit"로 두고 unit에 단위 이름을 줘요.


new Intl.NumberFormat("ko-KR", { style: "unit", unit: "kilometer-per-hour" }).format(80);
new Intl.NumberFormat("en-US", { style: "unit", unit: "megabyte", unitDisplay: "long" }).format(16);


결과
80km/h
16 megabytes


단위 이름은 "kilometer-per-hour"처럼 정해진 목록에서 골라 쓰고, unitDisplay를 "long"으로 주면 풀어 쓴 말로 바뀌어요.

61.6 소수점 자릿수랑 큰 수 줄이기는요?

실무에서 제일 자주 만지는 두 가지예요. 하나는 소수점 자릿수 고정이에요. 가격표에서 3을 "3.00"으로 자리를 맞추고 싶을 때가 있잖아요. minimumFractionDigits(최소 소수 자릿수)와 maximumFractionDigits(최대 소수 자릿수)로 잡아요.


new Intl.NumberFormat("ko-KR", { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(3);
new Intl.NumberFormat("ko-KR", { maximumFractionDigits: 0 }).format(3.7);


결과
3.00
4


최소를 2로 주면 없는 소수점도 0으로 채워 3.00, 최대를 0으로 주면 반올림해 3.7이 4가 돼요. 다른 하나는 큰 수 줄이기예요. 조회수를 좁은 카드에 다 못 넣을 때 notation을 "compact"로 줘요.


new Intl.NumberFormat("ko-KR", { notation: "compact" }).format(12345678);
new Intl.NumberFormat("en-US", { notation: "compact" }).format(12345678);


결과
1235만
12M


같은 수인데 한국어는 "1235만", 영어는 "12M"으로 그 지역 감각에 맞게 줄여줘요. 만, 억, K, M 대응표를 언어별로 들 필요 없이 옵션 하나로 끝나요.

61.7 오늘 배운 걸 묶어볼게요

숫자와 통화 국제화의 뼈대를 접어볼게요.


핵심
1. 콤마와 소수점 기호는 지역 약속이니 손으로 짜지 말고 로케일을 넘겨요.
2. 통화는 style "currency" + currency 코드로 기호 위치와 소수점까지 자동.
3. currencyDisplay로 기호, 코드, 이름 중에 골라요.
4. percent는 0과 1 사이 비율, unit은 정해진 단위 이름.
5. 자릿수는 fractionDigits로, 큰 수는 compact로 줄여요.


정리하면 숫자를 문자열로 만드는 순간이 국제화의 첫 갈림길이에요. 그 자리를 Intl.NumberFormat에 맡기면 로케일 하나 바꾸는 것만으로 전 세계 표기를 따라가요. 손으로 콤마 찍던 습관만 내려놓으면 돼요.