تو گروه علیبابا، ما تمام تلاشمون رو میکنیم تا بتونیم خدمات سفر رو اول به مردم ایران و بعد به بقیهی کشورها ارائه کنیم. به همین خاطر، سر و کله زدن با زبانهای مختلف برای تیم فرانتاند ما تبدیل به یک کار روزمره شده.
اما زمانی که تازه وارد علیبابا شده بودم و وظیفهی ساختن پنل پشتیبانی محصولات رو برعهده گرفتم، هیچ موقع با چنین چالشی خصوصا تو این سطح روبرو نشده بودم.
راحت میشد یک سری متن رو با کمک node-i18n ترجمه کرد اما برای تاریخ بجز Moment.js چه کاری میشد انجام داد؟ برای نمایش دادن اعداد فارسی به کاربرای ایرانی و اعداد انگلیسی به کاربرای خارجی چطور؟ و خیلی مشکلات دیگه. البته هر کدوم رو میشه با کمک چندین و چند پلاگین رفع کرد. تمام این کارها باعث میشد حجم نهایی اپلیکیشن بالا بره یا پرفورمنس به صورت چشمگیری کاهش پیدا کنه و خب کی اینو دوست داره؟
به دنبال جواب دادن این سوالها، با API نسبتا جدیدی که به صورت built-in توی جاواسکریپت وجود داره و کم کم ساپورت خوبی پیدا کرده، آشنا شدم: ECMAScript Internationalization API
تو یک سری مقاله تلاش میکنم تجربهای که در مورد کار کردن با این API بدست آوردم رو با بقیه سهیم بشم.
مقالههایی که از این سری منتشر شدن:
- توسعهی سادهتر اپلیکیشنهای وب چند زبانه با Intl API
API Internationalization
API Internationalization (جهانی سازی) ECMAScript یک سری عملیات زبانی رو به ما میده و بهمون کمک میکنه تا بتونیم وب اپلیکیشنهامون رو برای آدمهای بیشتری آماده کنیم. این API توی ECMA-402 (آره خیلی خیلی قدیمیه!) استاندارد شد ولی تا چند سال پیش ساپورت خوبی نداشت. اما دیگه با رد شدن ساپورت اکثر بخشهای این API از ۹۰٪، میشه بهش اعتماد کرد و از دست پلاگینهای third-party خلاص شد.
این API میتونه از طریق آبجکت Intl برامون کارهای مختلفی مثل تبدیل کردن تاریخ میلادی به شمسی، جمع بستن آیتمها یا فرمت کردن اعداد رو انجام بده.
دیتاهای پشت این API از طریق ریپازیتورهای دادهی محلی متداول یونیکد (Unicode Common Locale Data Repository) یا به اختصار CLDR تأمین میشه.
CLDR
CLDR یه سری دیتای استاندارد جهانی هستند که ترجمهی اسمهای خاصی رو تو خودش جا میده. این ترجمهها عبارتند از:
- ترجمهی اسم زبانها
- ترجمهی اسم کشورها و محدودهها
- ترجمهی اسم واحدهای پولی (به همراه حالتهای مفرد و جمعشون)
- ترجمهی اسم کامل و مخفف روزهای هفته، ماهها، دورانها (مثل: دهه، قرن و ...) و بخشهای روز (مثل: صبح، ظهر و …)
- ترجمهی محدودههای زمانی و شهرهای مثال برای هر محدوده زمانی
- ترجمهی فیلدهای تقویم
- پترن برای فرمت و پارس کردن تاریخها و بخشهای روز
- لیستی از کاراکترهای موجود در زبان
- پترن برای فرمت و پارس کردن ارقام
- قواعد جمع بستن در زبان
- قواعد فرمت کردن ارقام در سیستمهای عددی قدیمی (مثل اعداد رومی)
- قوانین هجی کردن ارقام به حروف
- قوانین ترجمه رسمالخطی (بر اساس BGN/PCGN romanization)

ریپازیتوری توسط توسط یه تیم متشکل از نمایندههای شرکتهای بزرگی مثل مایکروسافت و گوگل نگهداری میشه ولی هر کسی میتونه توش contribiute کنه.
فان فکت: حتما دیدید که تلگرام موقع تایپ کردن، بهتون یه اموجی ساجست میده؟ تلگرام هم از همین دیتاها برای این کار استفاده میکنه.
کار با Intl
آبجکت intl
چندین کانستراکتور و فانکشنالیتی مختلف داره. مثل:
- Intl.DateTimeFormat
یک کانستراکتور برای آبجکتهایی که حساس به زبان، زمان و ساعت رو فرمت میکنند. به طور کلی، کاری که این کانستراکتور میکنه، اینه که یک آبجکت زمان رو به همراه زبان مورد نظر و چند آپشن دیگه دریافت میکنه و زمان و ساعت رو به اون زبان تحویل میده.
به عنوان مثال ازnew Date()
به"۱۳۹۸ آذر ۱۱, دوشنبه، ساعت ۱۵:۲۸"
- Intl.ListFormat
یک کانستراکتور برای آبجکتهایی که حساس به زبان، لیست رو فرمت میکنند. کاری که این کانستراکتور میکنه اینه که یک آرایه رو به همراه زبان مورد نظر دریافت میکنه و اون رو به استرینگ تبدیل میکنه.
به عنوان مثال از['علیبابا', 'جاباما', 'هلوپرشیا']
به"علیبابا، جاباما، و هلوپرشیا"
- Intl.NumberFormat
یک کانستراکتور برای آبجکتهایی که حساس به زبان، ارقام رو فرمت میکنند. این کانستراکتور یک رقم رو به همراه زبان مورد نظر و یک سری آپشن دریافت میکنه، بهشون جداکنندهی هزارگان، واحدی پولی و چیزهای دیگه اضافه میکنه و در نهایت به صورت استرینگ برمیگردونه.
به عنوان مثال از12500
به"ریال ۱۲٬۵۰۰"
- Intl.RelativeTimeFormat
یک کانستراکتور برای آبجکتهایی که حساس به زبان، زمان نسبی رو فرمت میکنند. کاری که این کانستراکتور میکنه اینه که یک رقم، زبان مورد نظر و نوع نسبت رو دریافت میکنه و فاصله زمانی رو به صورت استرینگ برمیگردونه.
به عنوان مثال از12
به"۱۲ روز پیش"
برای مشخص کردن زبان یا locale (تلفظ شده به صورت /ləʊˈkɑːl/)، باید از یک استرینگ یا آرایهای از تگ زبان استاندارد BCP 47 استفاده کرد. البته اگه هیچ locale مشخص نشه (یا حتی undefined باشه)، به صورت دیفالت از زبان ران تایم استفاده میشه.
BCP 47
تگ BCP 47، یک زبان رو به صورت مینیمال و با یک کد اصلی زبان تعریف میکنه. توی متداولترین حالتش، میتونه به ترتیب حاوی: یک کد زبانی، یک کد رسمالخطی، یک کد کشوری و یا منطقهای باشه که با خط تیره از همدیگه جدا شدن. این تگها case sensitive نیستن اما رسمه که کد کشور و منطقه به صورت UPPERCASE باشه، رسمالخط به صورت TitleCaseو بقیه به صورت lowercase.
به طول مثال:
'fa'
نشون دهندهی زبان فارسی (زبان اصلی)'en-US'
نشون دهندهی زبان انگلیسی در آمریکا (زبان اصلی به همراه کد کشور)'zh-Hans-SG'
نشون دهندهی زبان چینی ساده شده در کشور سنگاپور (زبان اصلی به همراه کد رسمالخط و کد کشور)
ساپورت intl
در حال حاضر، ساپورت نسبتا خوبی از کانستراکتورهای intl
میشه ولی حتی برای اونهایی که ساپورت نمیشن هم خیلی راه میشه ployfill نوشت.
شروع سری
اگه این توضیحاتی که بهتون دادم، باعث شد که به مطالعه بیشتر در مورد این API علاقهمند بشید و یا دلتون میخواد که ببینید چطوری میشه از هر کدوم از این فیچرها تو دنیای واقعی استفاده کرد، بهتون پیشنهاد میدم که به خوندن ادامهی این سری بپردازید.
در ضمن خیلی خوشحال میشم اگر موضوعی بود باهام از طریق ایمیل (j.izadfar@alibaba.ir) یا توییتر (JavidIzadfar@) در میون بزارید.