احتمالا تا به امروز در برنامههای جاوا اسکریپتی خود از کتابخانههای ثالث و یا توابع ویژهای برای نمایش شمسی تاریخ، نمایش فارسی اعداد، افزودن جدا کنندهی سه رقمی اعداد (جداکنندهی هزارگان)، نمایش تاریخ نسبی مانند 1 روز قبل و ... استفاده کردهاید. خبر خوب اینکه موتور جاوا اسکریپتی تمام مرورگرهای جدید (از فایرفاکس 29 و کروم 24 به بعد) به صورت توکار یک چنین تبدیلهایی را پشتیبانی میکنند و برای مثال برای تبدیل تاریخ میلادی به شمسی و نمایش آن، در بسیاری از موارد نیازی به کتابخانهی حجیم moment.js (و یا سایر روشهای مرسوم خانگی) نیست.
معرفی 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)
برای کار با این شیء، نیازی به import هیچ ماژول و یا کتابخانهای نیست و جزئی از جاوا اسکریپت استاندارد میباشد. به همین جهت کار با آن حجمی را به برنامهی شما اضافه نخواهد کرد.
تمام این سازندهها میتوانند با یک فرهنگ و یا آرایهای از فرهنگهای مدنظر شروع شوند:
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'
}
برای نمونه، ذکر Intl.DateTimeFormat بدون هیچ تنظیمی و فقط با تعیین فرهنگ فارسی:
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));
در این حالت اگر نیاز بود حتما اعداد ماه و روز، دو رقمی باشند، میتوان تنظیم 2-digit را صریحا ذکر کرد:
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));
نمایش تاریخهای نسبی مانند «1 روز بعد»
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"));
با خروجیهای «۱ روز پیش» و «
۱ روز بعد»
نمایش اعداد فارسی توسط i18n API
احتمالا برای تبدیل اعداد انگلیسی به فارسی و نمایش آنها، متدهایی را برای 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));
با این خروجی: «۰۳٫۱۴»