Tinklaraščio įrašas
10/6/2025

Intl API galia: išsamus vadovas po naršyklėje integruotą internacionalizaciją

Internacionalizacija nėra tik vertimas. Tai datų formatavimas, žodžių daugiskaitos sudarymas, vardų rikiavimas ir dar daugiau – visa tai pagal konkrečias lokales. Užuot pasikliavus sunkiasvorėmis trečiųjų šalių bibliotekomis, modernus „JavaScript“ siūlo Intl API – galingą, integruotą būdą tvarkytis su i18n. Tylus priminimas, kad internetas yra išties pasaulinis.

Egzistuoja paplitusi klaidinga nuomonė, kad internacionalizacija (i18n) yra tiesiog teksto vertimas. Nors vertimas yra labai svarbus, tai tik vienas aspektas. Viena iš sudėtingiausių dalių yra informacijos pritaikymas prie įvairių kultūrinių lūkesčių: kaip parodyti datą Japonijoje, palyginti su Vokietija? Koks teisingas būdas sudaryti daiktavardžio daugiskaitą arabų kalboje, palyginti su anglų? Kaip surikiuoti vardų sąrašą įvairiomis kalbomis?

Daugelis programuotojų, spręsdami šiuos iššūkius, pasikliovė sunkiasvorėmis trečiųjų šalių bibliotekomis arba, dar blogiau, individualiai sukurtomis formatavimo funkcijomis. Šie sprendimai, nors ir veikiantys, dažnai sukelia didelių pridėtinių išlaidų: padidėjusį rinkinio dydį (angl. bundle size), galimus našumo butelio kaklelius ir nuolatinę kovą siekiant neatsilikti nuo besikeičiančių lingvistinių taisyklių ir lokalės duomenų.

Susipažinkite su ECMAScript internacionalizacijos API, geriau žinomu kaip Intl objektu. Ši tyli jėgainė, integruota tiesiai į modernias „JavaScript“ aplinkas, yra dažnai nuvertinamas, tačiau neįtikėtinai galingas, integruotas, našus ir standartus atitinkantis sprendimas duomenų internacionalizacijai tvarkyti. Tai liudijimas apie interneto įsipareigojimą būti pasauliniu, suteikiant vieningą ir efektyvų būdą formatuoti skaičius, datas, sąrašus ir dar daugiau pagal konkrečias lokales.

Intl ir lokalės: daugiau nei tik kalbų kodai

Intl pagrindas yra lokalės (angl. locale) koncepcija. Lokalė yra daug daugiau nei tik dviejų raidžių kalbos kodas (pvz., en anglų kalbai ar es ispanų). Ji apima visą kontekstą, reikalingą tinkamai pateikti informaciją konkrečiai kultūrinei grupei. Tai apima:

  • Kalbą: Pagrindinę lingvistinę priemonę (pvz., en, es, fr).
  • Rašto sistemą: Rašto sistemą (pvz., Latn lotynų, Cyrl kirilicos). Pavyzdžiui, zh-Hans supaprastintai kinų kalbai, palyginti su zh-Hant tradicinei kinų kalbai.
  • Regioną: Geografinę sritį (pvz., US Jungtinėms Valstijoms, GB Didžiajai Britanijai, DE Vokietijai). Tai labai svarbu tos pačios kalbos variantams, pavyzdžiui, en-US ir en-GB, kurie skiriasi datos, laiko ir skaičių formatavimu.
  • Nuostatas/variantus: Kitas specifines kultūrines ar lingvistines nuostatas. Daugiau informacijos rasite W3C gairėse „Kalbos žymės pasirinkimas“.

Paprastai lokalę norėsite pasirinkti pagal tinklalapio kalbą. Tai galima nustatyti iš lang atributo:

JavaScript

// Gaukite puslapio kalbą iš HTML lang atributo
const pageLocale = document.documentElement.lang || 'en-US'; //
Atsarginis variantas 'en-US'

Kartais galite norėti pakeisti puslapio lokalę konkrečia lokale, pavyzdžiui, rodydami turinį keliomis kalbomis:

// Priverstinai nustatykite konkrečią lokalę, nepriklausomai nuo puslapio kalbos
const tutorialFormatter = new Intl.NumberFormat('zh-CN', {
style: 'currency', currency: 'CNY' });

console.log(`Kinų pavyzdys:
${tutorialFormatter.format(199.99)}`); // Rezultatas: ¥199.99

Kai kuriais atvejais galite norėti naudoti vartotojo pageidaujamą kalbą:

// Naudokite vartotojo pageidaujamą kalbą
const browserLocale = navigator.language || 'ja-JP';

const formatter = new Intl.NumberFormat(browserLocale, { style: 
'currency', currency: 'JPY' });

Kai sukuriate Intl formatuotoją, galite pasirinktinai perduoti vieną ar daugiau lokalės eilučių. Tuomet API pasirinks tinkamiausią lokalę pagal prieinamumą ir pageidavimą.

Pagrindinės formatavimo jėgainės

Intl objektas atveria kelis konstruktorius, kiekvieną skirtą konkrečiai formatavimo užduočiai. Panagrinėkime dažniausiai naudojamus, kartu su keliais galingais, dažnai nepastebimais perliukais.

1. Intl.DateTimeFormat: datos ir laikai, globaliai

Datų ir laikų formatavimas yra klasikinė i18n problema. Ar turėtų būti MM/DD/YYYY, ar DD.MM.YYYY? Ar mėnuo turėtų būti skaičius, ar pilnas žodis? Intl.DateTimeFormat visa tai lengvai išsprendžia.

const date = new Date(2025, 6, 27, 14, 30, 0); // 2025 m. birželio 27 d., 14:30

// Konkreti lokalė ir parinktys (pvz., ilga data, trumpas laikas)
const options = {
	weekday: 'long',
	year: 'numeric',
	month: 'long',
	day: 'numeric',
	hour: 'numeric',
	minute: 'numeric',
	timeZoneName: 'shortOffset' // pvz., "GMT+3"
};

console.log(new Intl.DateTimeFormat('en-US',
options).format(date));

// "Friday, June 27, 2025 at 2:30 PM GMT+3"
console.log(new Intl.DateTimeFormat('de-DE',
options).format(date));

// "Freitag, 27. Juni 2025 um 14:30 GMT+3"//

Naudojant dateStyle ir timeStyle įprastiems šablonams
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle:
'full', timeStyle: 'short' }).format(date));

// "Friday, 27 June 2025 at 14:30"

console.log(new Intl.DateTimeFormat('ja-JP', { dateStyle:
'long', timeStyle: 'short' }).format(date));

// "2025年6月27日 14:30"

DateTimeFormat parinkčių lankstumas yra didžiulis, leidžiantis kontroliuoti metus, mėnesį, dieną, savaitės dieną, valandą, minutę, sekundę, laiko juostą ir dar daugiau.

2. Intl.NumberFormat: skaičiai su kultūriniais niuansais

Be paprastų dešimtainių skaičių, skaičiams reikia kruopštaus tvarkymo: tūkstančių skyrikliai, dešimtainiai ženklai, valiutų simboliai ir procentų ženklai labai skiriasi priklausomai nuo lokalės.

const price = 123456.789;

// Valiutos formatavimas
console.log(new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(price));
// "$123,456.79" (automatiškai apvalina)

console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(price));
// "123.456,79 €"

// Matavimo vienetai
console.log(new Intl.NumberFormat('en-US', { style: 'unit', unit: 'meter', unitDisplay: 'long' }).format(100));
// "100 meters"

console.log(new Intl.NumberFormat('fr-FR', { style: 'unit', unit: 'kilogram', unitDisplay: 'short' }).format(5.5));
// "5,5 kg"

Parinktys, tokios kaip minimumFractionDigits, maximumFractionDigits ir notation (pvz., scientific, compact), suteikia dar tikslesnę kontrolę.

3. Intl.ListFormat: natūralios kalbos sąrašai

Sąrašų pateikimas yra stebėtinai sudėtingas. Anglų kalba naudoja „and“ jungimui ir „or“ atskyrimui. Daugelyje kalbų yra skirtingi jungtukai, o kai kurioms reikalinga specifinė skyryba.Šis API supaprastina užduotį, kuri kitu atveju reikalautų sudėtingos sąlyginės logikos:

const items = ['obuoliai', 'apelsinai', 'bananai'];

// Jungiamasis ("ir") sąrašas
console.log(new Intl.ListFormat('en-US', { type: 'conjunction' }).format(items));
// "apples, oranges, and bananas"

console.log(new Intl.ListFormat('de-DE', { type: 'conjunction' }).format(items));
// "Äpfel, Orangen und Bananen"

// Skiriamasis ("arba") sąrašas
console.log(new Intl.ListFormat('en-US', { type: 'disjunction' }).format(items));
// "apples, oranges, or bananas"

console.log(new Intl.ListFormat('fr-FR', { type: 'disjunction' }).format(items));
// "pommes, oranges ou bananes"

4. Intl.RelativeTimeFormat: žmonėms suprantamos laiko žymos

Rodymas „prieš 2 dienas“ ar „po 3 mėnesių“ yra įprastas vartotojo sąsajoje, tačiau tikslus šių frazių lokalizavimas reikalauja didelių duomenų kiekių. Intl.RelativeTimeFormat tai automatizuoja.

const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });

console.log(rtf.format(-1, 'day'));    // "yesterday"
console.log(rtf.format(1, 'day'));     // "tomorrow"
console.log(rtf.format(-7, 'day'));    // "7 days ago"
console.log(rtf.format(3, 'month'));   // "in 3 months"
console.log(rtf.format(-2, 'year'));   // "2 years ago"

// Prancūzų pavyzdys:
const frRtf = new Intl.RelativeTimeFormat('fr-FR', { numeric: 'auto', style: 'long' });

console.log(frRtf.format(-1, 'day'));    // "hier"
console.log(frRtf.format(1, 'day'));     // "demain"
console.log(frRtf.format(-7, 'day'));    // "il y a 7 jours"
console.log(frRtf.format(3, 'month'));   // "dans 3 mois"

Parinktis numeric: 'always' priverstų rodyti „1 day ago“ vietoj „yesterday“.

5. Intl.PluralRules: daugiskaitos sudarymo įvaldymas

Tai bene vienas kritiškiausių i18n aspektų. Skirtingose kalbose yra labai skirtingos daugiskaitos taisyklės (pvz., anglų kalba turi vienaskaitą/daugiskaitą, arabų – nulį, vieną, du, kelis, daug…). Intl.PluralRules leidžia nustatyti „daugiskaitos kategoriją“ tam tikram skaičiui konkrečioje lokalėje.

const prEn = new Intl.PluralRules('en-US');

console.log(prEn.select(0));    // "other" (pvz., "0 items")
console.log(prEn.select(1));    // "one"   (pvz., "1 item")
console.log(prEn.select(2));    // "other" (pvz., "2 items")

const prAr = new Intl.PluralRules('ar-EG');

console.log(prAr.select(0));    // "zero"
console.log(prAr.select(1));    // "one"
console.log(prAr.select(2));    // "two"
console.log(prAr.select(10));   // "few"
console.log(prAr.select(100));  // "other"

Šis API tiesiogiai nesudaro teksto daugiskaitos, bet suteikia esminę klasifikaciją, reikalingą pasirinkti teisingą vertimo eilutę iš jūsų pranešimų rinkinių. Pavyzdžiui, jei turite pranešimų raktus kaip item.one, item.other, naudotumėte pr.select(count), kad pasirinktumėte tinkamą.

6. Intl.DisplayNames: lokalizuoti visko pavadinimai

Reikia parodyti kalbos, regiono ar rašto sistemos pavadinimą vartotojo pageidaujama kalba? Intl.DisplayNames yra jūsų išsamus sprendimas.

// Rodyti kalbų pavadinimus anglų kalba
const langNamesEn = new Intl.DisplayNames(['en'], { type: 'language' });

console.log(langNamesEn.of('fr'));      // "French"
console.log(langNamesEn.of('es-MX'));   // "Mexican Spanish"

// Rodyti kalbų pavadinimus prancūzų kalba
const langNamesFr = new Intl.DisplayNames(['fr'], { type: 'language' });

console.log(langNamesFr.of('en'));      // "anglais"
console.log(langNamesFr.of('zh-Hans')); // "chinois (simplifié)"

// Rodyti regionų pavadinimus
const regionNamesEn = new Intl.DisplayNames(['en'], { type: 'region' });

console.log(regionNamesEn.of('US'));    // "United States"
console.log(regionNamesEn.of('DE'));    // "Germany"

// Rodyti rašto sistemų pavadinimus
const scriptNamesEn = new Intl.DisplayNames(['en'], { type: 'script' });

console.log(scriptNamesEn.of('Latn'));  // "Latin"
console.log(scriptNamesEn.of('Arab'));  // "Arabic"

Su Intl.DisplayNames išvengsite begalės kalbų, regionų ar rašto sistemų pavadinimų fiksavimo kode, išlaikydami savo programą tvirtą ir lengvasvorę.

Naršyklių palaikymas

Galbūt svarstote apie naršyklių suderinamumą. Geros naujienos yra tai, kad Intl turi puikų palaikymą visose moderniose naršyklėse. Visos pagrindinės naršyklės („Chrome“, „Firefox“, „Safari“, „Edge“) visiškai palaiko aptartą pagrindinį funkcionalumą (DateTimeFormat, NumberFormat, ListFormat, RelativeTimeFormat, PluralRules, DisplayNames). Galite užtikrintai naudoti šiuos API be polifilų (angl. polyfills) didžiajai savo vartotojų daliai.

Išvada: priimkite pasaulinį internetą su Intl

Intl API yra modernaus interneto kūrimo, skirto pasaulinei auditorijai, kertinis akmuo. Jis suteikia „front-end“ programuotojams galimybę su minimaliomis pastangomis pateikti labai lokalizuotas vartotojo patirtis, pasinaudojant naršyklės integruotomis, optimizuotomis galimybėmis.

Pradėję naudoti Intl, jūs sumažinsite priklausomybes, sumažinsite rinkinių dydžius ir pagerinsite našumą – visa tai užtikrindami, kad jūsų programa gerbia ir prisitaiko prie įvairių lingvistinių ir kultūrinių vartotojų lūkesčių visame pasaulyje. Nustokite vargti su individualia formatavimo logika ir priimkite šį standartus atitinkantį įrankį!

Svarbu prisiminti, kad Intl tvarko duomenų formatavimą. Nors ir neįtikėtinai galingas, jis neišsprendžia visų internacionalizacijos aspektų. Turinio vertimas, dvipusis tekstas (RTL/LTR), lokalės specifinė tipografika ir gilūs kultūriniai niuansai, nesusiję su duomenų formatavimu, vis dar reikalauja kruopštaus apsvarstymo. (Galbūt apie tai parašysime ateityje!) Tačiau, norint tiksliai ir intuityviai pateikti dinaminius duomenis, Intl yra naršyklėje integruotas atsakymas.

Tolesniam skaitymui ir ištekliai