IlmHamroh
JavaScript Full-stack/12-qism. JavaScript: ilg'or mavzular va kod sifati17/44-dars18 daqiqa
Mundarija (32)

JavaScript Intl.PluralRules, ListFormat va DisplayNames: ko'plik, ro'yxat va til nomlari

Qisqacha: Uchta kichik, lekin foydali asbob. Intl.PluralRules sonning ko'plik kategoriyasini aytadi ("one", "few", "many", "other") — so'zni o'zingiz shu kategoriya bo'yicha tanlaysiz. Intl.ListFormat massivni "osh, manti va lag'mon" ko'rinishida yozadi. Intl.DisplayNames kodni nomga aylantiradi: "UZ" → "Oʻzbekiston", "ru" → "ruscha". Chrome 154 da PluralRules hamma joyda bir xil ishlaydi, ListFormat va DisplayNames esa o'zbekchani bilmaydi.

Bu darsda

  • PluralRules.select bilan rus va ingliz tilida son bilan so'zni moslashtirasiz: 5 заказов, 1 order.
  • type: "ordinal" bilan 1st, 2nd, 3rd yasaysiz.
  • ListFormat bilan "va" va "yoki" ro'yxatlarini uch tilda yozasiz.
  • DisplayNames bilan til tanlash menyusi va davlatlar ro'yxatini kodsiz tarjima bilan to'ldirasiz.
  • Uchala asbobning Node 24 va Chrome 154 dagi farqini bilasiz.

Oldin bilishingiz kerak: Intl.NumberFormat, Intl.RelativeTimeFormat, Obyekt: kalit-qiymat juftliklari.

1. Nega bu kerak?

«Bahor»ning Telegram boti mijozga xabar yuboradi. O'zbekcha versiyasi oddiy: Sizda 3 ta buyurtma bor. O'zbek tilida sondan keyin so'z o'zgarmaydi: 1 ta buyurtma, 5 ta buyurtma.

Ruscha versiyada Sardor shunday yozdi:

js
function buyurtmalar(son) {
  return son === 1 ? `${son} заказ` : `${son} заказов`;
}

console.log(buyurtmalar(1)); // 1 заказ
console.log(buyurtmalar(2)); // 2 заказов
console.log(buyurtmalar(21)); // 21 заказов

Ikkalasi ham xato. Rus tilida 2 заказа va 21 заказ bo'lishi kerak. Qoida murakkab: oxirgi raqam, oxirgi ikki raqam, 11–14 istisnolari... RelativeTimeFormat darsida u bu qoidalarni o'zi bilardi (2 дня, 5 дней). Endi o'sha qoidalarga to'g'ridan-to'g'ri murojaat qilamiz.

Botning yana ikki muammosi bor. Biri — buyurtma tarkibi: osh, manti va lag'mon (o'zbekcha), плов, манты и лагман (ruscha). Ikkinchisi — sozlamalardagi til va davlat nomlari. Uchala muammoni ham bugungi asboblar hal qiladi.

2. Intl.PluralRules — ko'plik kategoriyasi

2.1 select nima qaytaradi

js
const ru = new Intl.PluralRules("ru");

console.log(ru.select(1)); // one
console.log(ru.select(2)); // few
console.log(ru.select(5)); // many
console.log(ru.select(21)); // one

select so'zni qaytarmaydi. U sonning kategoriyasini — tilning qaysi qoidasiga tushishini aytadi.

Ko'plik kategoriyasi (plural category) — sondan keyingi so'z bir xil shaklni oladigan sonlar guruhi. Xuddi bozordagi rastalar kabi: har son o'z rastasiga qo'yiladi, so'z shaklini esa rasta nomiga qarab tanlaysiz. Rasta nomlari inglizcha va barcha tillar uchun bir xil: zero, one, two, few, many, other.

Muhim: one — "bitta" degani emas. Bu "rus tilida 1 bilan bir xil shakl oladigan sonlar" guruhi. Unga 21, 101, 1001 ham kiradi. few — 2, 3, 4, 22, 23... many — 5–20, 25, 11... Bu ro'yxatni yodlash shart emas — formatlovchi biladi.

2.2 So'zni tanlash

Kategoriya bo'yicha so'zni lug'atdan olamiz:

js
const ru = new Intl.PluralRules("ru");
const ZAKAZ = {
  one: "заказ",
  few: "заказа",
  many: "заказов",
  other: "заказа",
};

function buyurtmalar(son) {
  return `${son} ${ZAKAZ[ru.select(son)]}`;
}

for (const son of [1, 2, 5, 11, 21, 22]) {
  console.log(buyurtmalar(son));
}

Konsolda:

text
1 заказ
2 заказа
5 заказов
11 заказов
21 заказ
22 заказа

ZAKAZ[ru.select(son)] — kvadrat qavsda kalit o'rniga ifoda: avval select ishlaydi, uning natijasi ("few") kalit bo'ladi. other — kasr sonlar uchun: 1,5 заказа. Uni ham yozing, aks holda undefined chiqadi.

Bu tartibni qadamma-qadam ko'ring:

Vizualda lug'at qisqa — other siz. Unda son ni 21 dan 1.5 ga o'zgartirsangiz, undefined chiqadi.

2.3 Har tilda nechta kategoriya

Tillar ko'plik shakllari soni bo'yicha juda farq qiladi. Kategoriyalar ro'yxatini resolvedOptions().pluralCategories beradi. Biz Node 24 da bir necha tilni tekshirdik:

Sanoq sonlar uchun ko'plik kategoriyalari soni
  • xitoy (zh)faqat other1 ta
  • o'zbek (uz)one, other2 ta
  • ingliz (en)one, other2 ta
  • rus (ru)one, few, many, other4 ta
  • arab (ar)zero, one, two, few, many, other6 ta

Manba: Node 24.21.0 (ICU 78.3, CLDR 48): new Intl.PluralRules(til).resolvedOptions().pluralCategories, 2026-10-05

Nimaga qarang: o'zbek tilida ham ikki kategoriya bor — one va other. Lekin o'zbekchada sondan keyin ot ko'plik qo'shimchasini olmaydi: 1 ta buyurtma, 5 ta buyurtma. Shuning uchun o'zbekcha matnda ikkala kategoriyaga bir xil so'z yozasiz. Turk, qozoq va tojik tillari ham ikki kategoriyali. Rus va ukrain — to'rt, arab — olti.

2.4 Ingliz tili va kasr sonlar

js
const en = new Intl.PluralRules("en");
const ORDER = { one: "order", other: "orders" };

for (const son of [0, 1, 3]) {
  console.log(`${son} ${ORDER[en.select(son)]}`);
}

Konsolda:

text
0 orders
1 order
3 orders

Ingliz tilida 0 — other: "0 orders". Fransuz tilida esa 0 — one. Shuning uchun "son 1 bo'lsa" degan if hech qaysi tilda ishonchli emas.

Bitta nozik joy: kategoriya sonning qanday ko'rinishiga ham bog'liq. 1 — "one", lekin ekranda 1.0 bo'lsa — "other" ("1.0 stars"). Buning uchun PluralRules ham NumberFormat dagi kasr sozlamalarini qabul qiladi:

js
const butun = new Intl.PluralRules("en");
const kasrli = new Intl.PluralRules("en", {
  minimumFractionDigits: 1,
});

console.log(butun.select(1), kasrli.select(1)); // one other

Qoida: PluralRules ga ham, NumberFormat ga ham bir xil sozlama bering — so'z ekrandagi songa mos kelsin.

2.5 NumberFormat bilan birga

Yuqoridagi misollarda sonni o'zimiz qo'shdik: ${son}. Lekin rus tilida kasr vergul bilan yoziladi, minglar esa bo'sh joy bilan ajraladi. Demak sonni Intl.NumberFormat formatlashi, so'zni esa PluralRules tanlashi kerak. Ikkalasi bir juft bo'lib ishlaydi:

js
const raqam = new Intl.NumberFormat("ru");
const tur = new Intl.PluralRules("ru");
const ZAKAZ = {
  one: "заказ",
  few: "заказа",
  many: "заказов",
  other: "заказа",
};

function buyurtmaYoz(son) {
  return `${raqam.format(son)} ${ZAKAZ[tur.select(son)]}`;
}

console.log(buyurtmaYoz(1.5)); // 1,5 заказа
console.log(buyurtmaYoz(1000)); // 1 000 заказов

Oraliq uchun alohida metod bor — selectRange. "1–5 buyurtma" ruschada 1–5 заказов bo'ladi. Rus tilida kategoriyani odatda oraliqning oxirgi soni belgilaydi, boshqa tillarda qoida boshqacha bo'lishi mumkin. Buni ham formatlovchi biladi:

js
const tur = new Intl.PluralRules("ru");

console.log(tur.selectRange(1, 5)); // many
console.log(tur.selectRange(1, 2)); // few

selectRange — yangiroq imkoniyat (ECMA-402 2023). Node 24 va Chrome 154 da u bir xil ishladi.

2.6 Tartib sonlar: type: "ordinal"

Ingliz tilida reytingda 1st, 2nd, 3rd, 4th yoziladi. Qoidasi yana murakkab: 11th, lekin 21st; 12th, lekin 22nd. type: "ordinal" shu qoidani beradi:

js
const tartib = new Intl.PluralRules("en", { type: "ordinal" });
const QOSHIMCHA = { one: "st", two: "nd", few: "rd", other: "th" };

function orin(son) {
  return `${son}${QOSHIMCHA[tartib.select(son)]}`;
}

console.log([1, 2, 3, 4, 11, 12, 21, 22, 23].map(orin).join(" "));
// 1st 2nd 3rd 4th 11th 12th 21st 22nd 23rd

O'zbek va rus tillarida tartib son uchun bitta kategoriya — other. O'zbekchada tartib son doim bir xil yoziladi: 1-o'rin, 21-o'rin.

Tekshirib ko'ring: new Intl.PluralRules("ru").select(111) nima qaytaradi — one mi?

Javob

"many". Oxirgi raqam 1 bo'lsa ham, oxirgi ikki raqam — 11. Rus tilida 11–14 bilan tugaydigan sonlar doim many: 111 заказов. Shuning uchun "oxirgi raqamga qara" degan qo'lda qoida yetmaydi.

3. Intl.ListFormat — ro'yxatni gapga aylantirish

Diqqat: Bu darsdagi "Konsolda" natijalari Node 24 da olingan. «Ishga tushir» tugmasi kodni brauzeringizda bajaradi, Chrome'da esa uz uchun ListFormat va DisplayNames natijalari boshqacha chiqadi. Sababini «Node va Chrome farqi» bo'limida ochamiz.

3.1 "va" bilan

Buyurtma tarkibini chiqarish kerak: ["osh", "manti", "lag'mon"]. join(", ") — osh, manti, lag'mon — "va" yo'q. Qo'lda yozish mumkin, lekin ikki element, bitta element, bo'sh massiv holatlarini ham o'ylash kerak. ListFormat hammasini biladi:

js
const uz = new Intl.ListFormat("uz");

const uchta = ["osh", "manti", "lag'mon"];

console.log(uz.format(uchta)); // osh, manti va lag'mon
console.log(uz.format(["osh", "manti"])); // osh va manti
console.log(uz.format(["osh"])); // osh
console.log(uz.format([])); //

Bo'sh massiv — bo'sh satr. Uch tilda:

js
const taomlar = ["plov", "manti", "lagman"];

console.log(new Intl.ListFormat("ru").format(taomlar));
console.log(new Intl.ListFormat("en").format(taomlar));
console.log(new Intl.ListFormat("en-GB").format(taomlar));

Konsolda:

text
plov, manti и lagman
plov, manti, and lagman
plov, manti and lagman

Amerika inglizchasida and dan oldin ham vergul qo'yiladi — "Oxford comma" deb ataladi. Britaniya inglizchasida — yo'q. Biz buni o'ylamadik ham — til kodi yetarli bo'ldi.

ListFormat da ham formatToParts bor. U ikki xil bo'lak qaytaradi: element — massivdagi qiymat, literal — vergul yoki "va". Masalan, har taom nomini havola qilib, "va" ni oddiy matn qoldirish uchun:

js
const uz = new Intl.ListFormat("uz");
const qismlar = uz.formatToParts(["osh", "manti"]);

console.log(qismlar.map((q) => `${q.type}:${q.value}`).join(" | "));
// element:osh | literal: va  | element:manti

literal bo'lagida "va" atrofidagi bo'sh joylar ham bor — shuning uchun natijada ikki bo'sh joy ko'rinadi.

3.2 "yoki" va birliklar

type sozlamasi ro'yxat turini tanlaydi:

type Ma'nosi uz natijasi
"conjunction" (standart) "va" Click, Payme va naqd
"disjunction" "yoki" Click, Payme yoki naqd
"unit" o'lchov bo'laklari 2 kg 300 g

"unit" — "2 kg 300 g", "1 soat 30 daqiqa" kabi bo'laklar uchun, ular orasida "va" aytilmaydi. Ingliz tilida u vergul qo'yadi: 2 kg, 300 g.

style — "long", "short", "narrow". Ingliz tilida short — plov, manti, & lagman, narrow — plov, manti, lagman. O'zbekchada long va short bir xil, narrow esa "va" ni tashlab yuboradi.

3.3 Faqat satrlar

js
const uz = new Intl.ListFormat("uz");

console.log(uz.format(["osh", 5]));
text
TypeError: Iterable yielded 5 which is not a string

Tarjimasi: "Iterable 5 ni berdi, u satr emas". format istalgan iterable'ni qabul qiladi (massiv, Set), lekin ichidagi har element satr bo'lishi kerak. Son bo'lsa, avval formatlang: narxlar.map((n) => som.format(n)). Ehtiyot bo'ling: oddiy satr ham iterable — format("abc") xato bermaydi, a, b va c qaytaradi.

Tekshirib ko'ring: Mijoz to'lov usulini tanlashi kerak: "Click yoki Payme". Qaysi type kerak?

Javob

type: "disjunction". Natija: Click yoki Payme, ruschada — Click или Payme. Standart conjunction esa "Click va Payme" deb yozadi — ma'no o'zgaradi.

4. Intl.DisplayNames — kodlardan nomlar

4.1 Davlat, til, valyuta

Dasturda ma'lumot kod bilan saqlanadi: davlat — "UZ", til — "ru", valyuta — "UZS". Ekranga esa nom kerak. DisplayNames — tayyor tarjima lug'ati:

js
const davlat = new Intl.DisplayNames("uz", { type: "region" });
const til = new Intl.DisplayNames("uz", { type: "language" });
const valyuta = new Intl.DisplayNames("uz", { type: "currency" });

console.log(davlat.of("UZ"));
console.log(davlat.of("KZ"));
console.log(til.of("ru"));
console.log(til.of("en-US"));
console.log(valyuta.of("UZS"));

Konsolda:

text
Oʻzbekiston
Qozogʻiston
ruscha
ingliz (Amerika)
O‘zbekiston so‘mi

type majburiy — formatlovchi qaysi lug'atdan qidirishni bilishi kerak. Qiymatlari:

type Kod uz natijasi
"region" "DE", "419" Germaniya, Lotin Amerikasi
"language" "tg" tojik
"currency" "USD" AQSH dollari
"script" "Cyrl" kirill
"calendar" "islamic" hijriy taqvim
"dateTimeField" "weekday" hafta kuni

Davlat kodi — ikki katta harf (ISO 3166) yoki uch raqam (BMT mintaqa kodi: 419 — Lotin Amerikasi, 150 — Yevropa). Til kodi — Intl.DateTimeFormat darsidagi til kodlari.

Apostroflarga yana qarang: Oʻzbekiston da ʻ (U+02BB), O‘zbekiston so‘mi da ‘ (U+2018). ICU ma'lumotlarining ikki joyidan — ikki xil belgi. Bunday nomni o'z matningiz bilan === orqali solishtirsangiz, false chiqishi mumkin.

4.2 Til tanlash menyusi

Saytdagi til tugmalarida har til o'z tilida yoziladi: o‘zbek, русский, English. Buning uchun har kodni o'sha tilning o'zida so'raymiz:

js
for (const kod of ["uz", "ru", "en"]) {
  const nomlar = new Intl.DisplayNames(kod, { type: "language" });
  console.log(`${kod}: ${nomlar.of(kod)}`);
}

Konsolda:

text
uz: o‘zbek
ru: русский
en: English

Bu — Chrome ham o'zbekcha natija beradigan kam joylardan biri (o‘zbek). Sababini «Node va Chrome» bo'limida ko'ramiz.

4.3 Noma'lum kod va fallback

Kod lug'atda bo'lmasa, standart holatda kodning o'zi qaytadi:

js
const til = new Intl.DisplayNames("uz", { type: "language" });
const qatiy = new Intl.DisplayNames("uz", {
  type: "language",
  fallback: "none",
});

console.log(til.of("kaa")); // kaa
console.log(qatiy.of("kaa")); // undefined

kaa — qoraqalpoq tili kodi. O'zbekcha bazada uning nomi yo'q. fallback: "none" bilan undefined qaytadi — shunda o'zingiz zaxira nom qo'yasiz. Chrome 154 da ham undefined. Tekshiruvni ?? "Noma'lum" bilan yozing — u undefined ni ham, null ni ham ushlaydi.

Shakli noto'g'ri kod esa xato tashlaydi: davlat.of("UZB") → RangeError (uch harfli davlat kodi qabul qilinmaydi).

O'zingiz to'ldiring: davlat nomlari uchun type sozlamasiga qiymati beriladi.

5. Node va Chrome farqi

DateTimeFormat, RelativeTimeFormat va NumberFormat darslarida ko'rdik: Chrome 154 da uz lotin ma'lumotlari yo'q, resolvedOptions baribir uz deydi. Bu darsdagi uch asbobda manzara turlicha. Biz darsdagi barcha misollarni Chrome 154 da ham sinadik:

Asbob (uz) Node 24 Chrome 154
PluralRules to'liq bir xil (barcha tillar)
ListFormat osh, manti va lag'mon osh, manti, and lag'mon
DisplayNames, region "UZ" Oʻzbekiston Uzbekistan
DisplayNames, language "ru" ruscha ru
DisplayNames, language "uz" o‘zbek o‘zbek

Rus va ingliz tillari uchun uchala asbob ikkala muhitda bir xil natija berdi.

Uch xil xulq:

  • PluralRules — ko'plik qoidalari kichik jadval, Chrome ularni hamma tillar uchun olib yuradi.
  • ListFormat — Chrome o'zbekcha yo'qligini ochiq aytadi: supportedLocalesOf(["uz"]) → [], resolvedOptions().locale → brauzerning o'z tili (bizda "en-US"). Ya'ni brauzer boshqa tilga o'tganini yashirmaydi. Jadvaldagi , and ham shu en-US dan — en-GB tilli brauzerda vergulsiz and chiqadi.
  • DisplayNames — Chrome "uz bor" deydi (resolvedOptions().locale → "uz", xuddi DateTimeFormat dagidek), lekin nomlar inglizcha (Uzbekistan) yoki kodning o'zi (ru). Faqat tilning o'z nomi (o‘zbek) bor. Ehtimol, Chrome bu nomlarni o'z sozlamalaridagi tillar ro'yxati uchun saqlaydi — lekin bu bizning taxminimiz, hujjatda yozilmagan.

Amaliy xulosa: o'zbekcha ro'yxat yoki davlat nomi brauzerda kerak bo'lsa — natijani tekshiring (format(["a", "b"]) === "a va b") va kerak bo'lsa o'z kichik lug'atingizga o'ting. Yoki matnni serverda yasang.

Tekshirib ko'ring: Nega ListFormat uchun Chrome'da supportedLocalesOf tekshiruvi ishlaydi, RelativeTimeFormat uchun esa ishlamaydi?

Javob

ListFormat da Chrome o'zbek tili yo'qligini aytadi: supportedLocalesOf(["uz"]) bo'sh massiv qaytaradi. RelativeTimeFormat da esa u ["uz"] deydi, lekin baribir zaxira shablonni ishlatadi. Har asbob o'z ma'lumotlari bilan alohida — shuning uchun eng ishonchli tekshiruv doim natijaning o'zi.

6. Ko'p uchraydigan xatolar

6.1 son === 1 bilan ko'plik

Rus tilida 21 заказ, ingliz tilida 0 orders, fransuz tilida 0 — birlik. "Bitta bo'lsa birlik, aks holda ko'plik" faqat ba'zi tillarda va ba'zi sonlarda to'g'ri. Tuzatish: PluralRules.select + lug'at.

6.2 Lug'atda other yo'q

ZAKAZ[ru.select(1.5)] — other. Lug'atda other bo'lmasa — 1.5 undefined. Tuzatish: har lug'atga tilning barcha kategoriyalarini yozing — ro'yxatini resolvedOptions().pluralCategories dan oling.

6.3 select natijasini so'z deb o'ylash

console.log(\${son} ${ru.select(son)}`)→5 many. select` — kategoriya, so'z emas.

6.4 ListFormat ga son berish

format([35000, 28000]) → TypeError. Tuzatish: avval har elementni NumberFormat bilan satrga aylantiring.

6.5 DisplayNames da type ni unutish

js
const nomlar = new Intl.DisplayNames("uz");
text
TypeError: invalid_argument

Xabar qisqa va tushunarsiz — ICU ichidagi kod. Ma'nosi: "argument noto'g'ri" — bu yerda type yo'q. Xuddi shu matn of("UZB") da RangeError bilan chiqadi. Shunday qisqa xabar ko'rsangiz, type ni va kod shaklini tekshiring.

7. Mashqlar

1-mashq (oson): Ruscha "N ta taom"

taomlarSoni(son) funksiyasi ruscha qaytarsin: 1 блюдо, 2 блюда, 5 блюд, 21 блюдо, 1.5 блюда. Kategoriyalar: one — блюдо, few — блюда, many — блюд, other — блюда. Ishora: lug'at + select.

Yechim
js
const ru = new Intl.PluralRules("ru");
const BLYUDO = {
  one: "блюдо",
  few: "блюда",
  many: "блюд",
  other: "блюда",
};

function taomlarSoni(son) {
  return `${son} ${BLYUDO[ru.select(son)]}`;
}

console.log([1, 2, 5, 21, 1.5].map(taomlarSoni).join(", "));
// 1 блюдо, 2 блюда, 5 блюд, 21 блюдо, 1.5 блюда

1.5 ruschada 1,5 deb yozilishi kerak. Buni «NumberFormat bilan birga» bo'limidagidek Intl.NumberFormat("ru") bilan tuzatasiz.

2-mashq (o'rta): Inglizcha reyting

«Bahor» filiallari reytingi: [{ nom: "Chilonzor", ball: 4.8 }, { nom: "Yunusobod", ball: 4.9 }, { nom: "Sergeli", ball: 4.5 }]. Ballar bo'yicha kamayish tartibida saralang va inglizcha chiqaring: 1st — Yunusobod (4.9 stars). Ishora: toSorted, type: "ordinal" va "star/stars" uchun oddiy PluralRules — minimumFractionDigits: 1 bilan, chunki ball doim 4.9 ko'rinishida.

Yechim
js
const tartib = new Intl.PluralRules("en", { type: "ordinal" });
const kategoriya = new Intl.PluralRules("en", {
  minimumFractionDigits: 1,
});
const ball = new Intl.NumberFormat("en", {
  minimumFractionDigits: 1,
});
const QOSHIMCHA = { one: "st", two: "nd", few: "rd", other: "th" };
const YULDUZ = { one: "star", other: "stars" };

const filiallar = [
  { nom: "Chilonzor", ball: 4.8 },
  { nom: "Yunusobod", ball: 4.9 },
  { nom: "Sergeli", ball: 4.5 },
];

filiallar
  .toSorted((a, b) => b.ball - a.ball)
  .forEach((f, i) => {
    const orin = `${i + 1}${QOSHIMCHA[tartib.select(i + 1)]}`;
    const soz = YULDUZ[kategoriya.select(f.ball)];
    const baho = `${ball.format(f.ball)} ${soz}`;
    console.log(`${orin} — ${f.nom} (${baho})`);
  });

Konsolda:

text
1st — Yunusobod (4.9 stars)
2nd — Chilonzor (4.8 stars)
3rd — Sergeli (4.5 stars)

Uchta formatlovchi bitta sozlama bilan ishlaydi: ekranda 4.9, ko'plik ham 4.9 uchun tanlanadi. Ball 1 bo'lsa, 1.0 stars chiqadi — ekrandagi 1.0 ga mos.

3-mashq (qiyin): Buyurtma xabari uch tilda

xabarYoz(til, taomlar) — taomlar massivi (o'zbekcha nomlar emas, har tilda alohida beriladi) uchun quyidagini qaytarsin: uz — Buyurtmangiz: osh va manti (2 ta taom), ru — Ваш заказ: плов и манты (2 блюда), en — Your order: plov and manti (2 dishes). Har til uchun matn qoliplarini obyektda saqlang. Ishora: ListFormat, PluralRules; o'zbekcha uchun one va other bir xil.

Yechim
js
const MATNLAR = {
  uz: {
    bosh: "Buyurtmangiz",
    soz: { one: "ta taom", other: "ta taom" },
  },
  ru: {
    bosh: "Ваш заказ",
    soz: { one: "блюдо", few: "блюда", many: "блюд", other: "блюда" },
  },
  en: {
    bosh: "Your order",
    soz: { one: "dish", other: "dishes" },
  },
};

function xabarYoz(til, taomlar) {
  const { bosh, soz } = MATNLAR[til];
  const royxat = new Intl.ListFormat(til).format(taomlar);
  const tur = new Intl.PluralRules(til).select(taomlar.length);
  return `${bosh}: ${royxat} (${taomlar.length} ${soz[tur]})`;
}

console.log(xabarYoz("uz", ["osh", "manti"]));
console.log(xabarYoz("ru", ["плов", "манты"]));
console.log(xabarYoz("en", ["plov", "manti", "tea"]));

Konsolda:

text
Buyurtmangiz: osh va manti (2 ta taom)
Ваш заказ: плов и манты (2 блюда)
Your order: plov, manti, and tea (3 dishes)

Kodda bitta ham if (til === ...) yo'q: til farqlari formatlovchilarda va MATNLAR lug'atida. Real loyihalarda aynan shunday tuziladi. i18n (internationalization — dasturni ko'p tilga moslash; so'zning birinchi va oxirgi harfi orasida 18 ta harf bor) kutubxonalari shu g'oyani kengaytiradi.

4-mashq: Vazifalar qadami — teglar qatori

vazifalar ilovasida teglar qatori hozir join(", ") bilan yasaladi: Teglar: #bozor — 2, #uy — 1. Kanon kodni o'zgartirmaymiz. Uning o'rniga kurs/mashqlar/12/17-teglar-royxati/teglar.mjs da teglarMatni(sanoq) ning ListFormat li variantini yozing: Map dan #bozor (2), #uy (1) va #o'quv (1) matnini yasasin. Brauzerda o'zbekcha bo'lmasa, oddiy join(", ") ga qaytsin.

Yechim
js
const royxat = new Intl.ListFormat("uz");
const UZBEKCHA_BOR = royxat.format(["a", "b"]) === "a va b";

export function teglarMatni(sanoq) {
  const qismlar = [...sanoq].map(([teg, soni]) => `${teg} (${soni})`);
  return UZBEKCHA_BOR ? royxat.format(qismlar) : qismlar.join(", ");
}

const sanoq = new Map([["#bozor", 2], ["#uy", 1], ["#o'quv", 1]]);
console.log(teglarMatni(sanoq));

Konsolda:

text
#bozor (2), #uy (1) va #o'quv (1)

[...sanoq] — Map dan [kalit, qiymat] juftliklari massivi. Node'da UZBEKCHA_BOR — true, Chrome 154 da — false, shuning uchun u yerda #bozor (2), #uy (1), #o'quv (1) chiqadi: "and" emas, oddiy vergul.

bash
git add 12/17-teglar-royxati/teglar.mjs
git commit -m "12/17: teglar qatori ListFormat bilan"

8. Real ishda

  • Ko'p tilli saytlar (i18n). i18next kutubxonasi kalitlarni buyurtma_one, buyurtma_few, buyurtma_many ko'rinishida saqlaydi va to'g'ri kalitni aynan Intl.PluralRules bilan tanlaydi. FormatJS esa ICU MessageFormat sintaksisini ishlatadi: {son, plural, one {# заказ} few {# заказа} many {# заказов} other {# заказа}} — ichida o'sha to'rt kategoriyani taniysiz.
  • Formalar. Davlat tanlash ro'yxati (<select>) — kodlar serverdan, nomlar DisplayNames dan. Yangi til qo'shilganda tarjima qilishga hojat yo'q.
  • Telegram botlar. Bot serverda — Node'da — ishlaydi, demak uz ma'lumotlari to'liq. Botni kursning backend qismida yozamiz.
  • Intervyu. "Rus tilida 5 товаров ni qanday to'g'ri chiqarasiz?" — PluralRules ni bilish i18n tajribasi borligini ko'rsatadi.

Xulosa

  • PluralRules.select(son) — kategoriya (one, few, many, other...), so'z emas; so'zni lug'atdan olasiz va other ni unutmaysiz.
  • Kategoriyalar soni tilga bog'liq: xitoy — 1, o'zbek va ingliz — 2, rus — 4, arab — 6; type: "ordinal" — 1st, 22nd.
  • ListFormat — osh, manti va lag'mon; type: conjunction (va), disjunction (yoki), unit; faqat satrlar.
  • DisplayNames — kod → nom (region, language, currency, script...); type majburiy, fallback: "none".
  • Chrome 154: PluralRules — bir xil; ListFormat — o'zbekcha yo'q va buni aytadi; DisplayNames — "bor" deydi, lekin inglizcha nom beradi.

Keyingi dars: Intl.Collator va Intl.Segmenter — o'zbek alifbosi bo'yicha saralash (o', g', sh, ch qayerda turadi?) va matnni so'z hamda gaplarga to'g'ri bo'lishni ko'ramiz.

Manbalar

  • MDN: "Intl.PluralRules", "Intl.ListFormat", "Intl.DisplayNames" — developer.mozilla.org
  • Unicode CLDR: "Language Plural Rules" jadvali — cldr.unicode.org
  • ECMA-402, "PluralRules", "ListFormat", "DisplayNames" — tc39.es/ecma402
  • web-features 3.40: intl-plural-rules — Baseline 2019-sentabr; intl-list-format, intl-display-names — Baseline 2021-aprel
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript Intl.PluralRules, ListFormat va DisplayNames: ko'plik, ro'yxat va til nomlari — IlmHamroh