معرفی API استاندارد بومی سازی JavaScript
Internationalization یا به صورت خلاصه i18n (یعنی یک i به همراه 18 حرف و یک n)، پروسهای که در آن برنامه به نحوی طراحی میشود تا خروجی آن قابلیت استفادهی برای انواع و اقسام فرهنگها را داشته باشد. برای مثال دو متد زیر را در نظر بگیرید:
function formatDate(d) { var month = d.getMonth() + 1; var date = d.getDate(); var year = d.getFullYear(); return month + "/" + date + "/" + year; } function formatMoney(amount) { return "$" + amount.toFixed(2); }
پیشتر جاوا اسکریپت برای مدیریت یک چنین مواردی (i18n-aware formatting) از متد toLocaleString استفاده میکرد (و هنوز هم برای پشتیبانی از برنامههای قدیمی، از API عمومی آن حذف نشدهاست) و خروجی آن از هر مرورگر و پیاده سازی خاصی، به مرورگر دیگری میتواند متفاوت باشد؛ حتی اگر جزئیات دقیقی هم درخواست شود. برای رفع این مشکل، استاندارد ECMAScript Internationalization API ارائه شد تا قابلیتهای توکار i18n جاوا اسکریپت را بهبود بخشیده و همچنین یکدست کند. توسط آن امکان انتخاب یک یا چند منطقهی خاص و سپس فرمت کردن تاریخ، اعداد و یا حتی مرتب سازی واژهها و عبارات با معرفی collations، میسر میباشد. در اینجا حتی امکان سفارشی سازی این فرمتها نیز پیشبینی شدهاست.
معرفی اینترفیس Intl
i18n API در یک شیء سراسری به نام Intl قابل دسترسی است و تعدادی از سازندههای آن Intl.Collator ،Intl.DateTimeFormat و Intl.NumberFormat نام دارند؛ مانند:
const result = new Intl.NumberFormat("fa").format(123456)
تمام این سازندهها میتوانند با یک فرهنگ و یا آرایهای از فرهنگهای مدنظر شروع شوند:
const portugueseTime = new Intl.DateTimeFormat(["pt-BR", "pt-PT"], options);
پارامتر اختیاری دوم آنها نیز تنظیماتی است که جهت سفارشی سازی این بومی سازی میتوان تعریف کرد.
نمایش شمسی تاریخ میلادی توسط i18n API
پس از معرفی i18n API، اکنون میخواهیم در طی مثالهایی، تمام کتابخانههای ثالث تبدیل تاریخ میلادی به شمسی را کنار گذاشته و با استفاده از جاوا اسکریپت استاندارد، این تبدیل را انجام دهیم. پارامتر دوم سازندهی new Intl.DateTimeFormat که تنظیمات آنرا مشخص میکند، میتواند به همراه ترکیبی از موارد زیر باشد که مقادیر مجاز برای آنها را نیز مشاهده میکنید:
{ weekday: 'narrow' | 'short' | 'long', era: 'narrow' | 'short' | 'long', year: 'numeric' | '2-digit', month: 'numeric' | '2-digit' | 'narrow' | 'short' | 'long', day: 'numeric' | '2-digit', hour: 'numeric' | '2-digit', minute: 'numeric' | '2-digit', second: 'numeric' | '2-digit', timeZoneName: 'short' | 'long', // Time zone to express it in timeZone: 'Asia/Shanghai', // Force 12-hour or 24-hour hour12: true | false, // Rarely-used options hourCycle: 'h11' | 'h12' | 'h23' | 'h24', formatMatcher: 'basic' | 'best fit' }
var dateFormat = new Intl.DateTimeFormat("fa"); console.log(dateFormat.format(Date.now()));
نمایش تاریخ شمسی با فرمت «۱۳۹۸ اسفند ۱, پنجشنبه»
برای تبدیل تاریخ میلادی به شمسی میتوان از سازندهی new Intl.DateTimeFormat با فرهنگ fa استفاده کرد. در اینجا ذکر مقدار long برای نام روز هفته، سبب درج نام روز میشود. نمایش سال به صورت عددی تنظیم شدهاست، ماه را به صورت بلند و نام کامل نمایش میدهد و مقدار روز را به صورت عددی درج میکند. این اعداد نیز فارسی هستند:
const date = new Date(Date.UTC(2020, 1, 20, 3, 0, 0, 200)); const faDate = new Intl.DateTimeFormat("fa", { weekday: "long", year: "numeric", month: "long", day: "numeric" }).format(date); console.log(faDate);
اگر فقط نیاز به نمایش «۱ اسفند ۱۳۹۸» بود، میتوان از تنظیمات زیر که در آن ماه، روز و سال ذکر شدهاند و در آن، ماه به صورت کامل و بلند نمایش داده میشود، استفاده کرد:
const isoString = new Date().toISOString(); const date = new Date(isoString); console.log( new Intl.DateTimeFormat("fa", { month: "long", day: "numeric", year: "numeric" }).format(date) );
یک نکته: همین خروجی را با متد قدیمی toLocaleDateString نیز میتوان به دست آورد؛ اما روش توصیه شده برای برنامههای جدید، همان استفاده از new Intl است.
console.log( new Date().toLocaleDateString("fa", { month: "long", day: "numeric", year: "numeric" }) );
نمایش تاریخ شمسی با فرمت «۹۸/۱۲/۱، ۶:۳۰»
برای اینکار پس از ذکر فرهنگ fa، تمام اجزای تاریخ را به صورت عددی مشخص میکنیم و سال را نیز دو رقمی نمایش خواهیم داد:
const date = new Date(Date.UTC(2020, 1, 20, 3, 0, 0, 200)); const fmt = new Intl.DateTimeFormat("fa", { year: "2-digit", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric" }); console.log(fmt.format(date));
const faDateTime = new Intl.DateTimeFormat("fa", { year: "2-digit", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", timeZoneName: "short" }).format; const now = Date.now(); console.log(faDateTime(now));
و یا اگر «۱ اسفند ۱۳۹۸، ۰۹:۲۹ (UTC)» مدنظر بود، میتوان ماه را به long تنظیم کرد و مقدار timeZone را صریحا ذکر نمود (که البته ذکر تنظیمات timeZone اختیاری است):
const faTime = new Intl.DateTimeFormat("fa", { year: "numeric", month: "long", day: "numeric", hour: "2-digit", minute: "2-digit", timeZoneName: "short", timeZone: "UTC" }); console.log(faTime.format(now));
const rtf = new Intl.RelativeTimeFormat("en", { localeMatcher: "best fit", // other values: "lookup" numeric: "always", // other values: "auto" style: "long", // other values: "short" or "narrow" }); console.log(rtf.format(-1, "day")); console.log(rtf.format(1, "day"));
احتمالا برای تبدیل اعداد انگلیسی به فارسی و نمایش آنها، متدهایی را برای replace حروف و اعداد طراحی کردهاید. به کمک شیء استاندارد Intl.NumberFormat دیگر نیازی به آنها نخواهید داشت!
خروجی شیء Intl.NumberFormat به همراه ذکر فرهنگ فارسی و هیچ تنظیم اضافهتری
console.log(new Intl.NumberFormat("fa").format(123456));
اگر میخواهید این جداکنندهی هزارگان نمایش داده نشود، نیاز است تنظیمات آنرا به همراه useGrouping: false، به صورت زیر ذکر کرد:
console.log( new Intl.NumberFormat("fa", { useGrouping: false }).format(123456) );
این شیء یک مقدار غیرعددی را
console.log(new Intl.NumberFormat("fa").format("تست"));
و یا برای نمایش واحد پولی، میتوان حالت نمایش را به currency و نوع currency را به IRR که ریال است، تنظیم کرد:
const gasPrice = new Intl.NumberFormat("fa", { style: "currency", currency: "IRR", minimumFractionDigits: 3 }); console.log(gasPrice.format(5.2597));
برای نمایش درصد پس از اعداد میتوان از تنظیم زیر استفاده کرد:
const faPercent = new Intl.NumberFormat("fa", { style: "percent", minimumFractionDigits: 2 }).format; console.log(faPercent(0.438));
و یا برای نمایش ممیز به همراه تنظیم دقت آن داریم:
const persianDecimal = new Intl.NumberFormat("fa", { minimumIntegerDigits: 2, maximumFractionDigits: 2 }); console.log(persianDecimal.format(3.1416));