پرتوپرتو

فارسی‌محور بودن

اصل اول پرتو — طراحی از ابتدا برای زبان فارسی، نه ترجمه از انگلیسی

چرا فارسی اول؟

اکثر کتابخانه‌های UI برای LTR (انگلیسی) ساخته شده‌اند و RTL به عنوان «حالت جایگزین» اضافه می‌شود. این رویکرد مشکلات زیادی ایجاد می‌کند: فاصله‌گذاری معکوس، آیکون‌های برعکس، انیمیشن‌های ناهماهنگ.

پرتو از صفر برای فارسی طراحی شده است. RTL تنها حالت اصلی است، نه یک افزونه.

یکی از اصول بنیادین پرتو این است: فارسی اول، RTL بومی. این صفحه آنچه را که این اصل در عمل معنا می‌دهد توضیح می‌دهد.


پیکربندی پایه

تگ HTML

<html lang="fa" dir="rtl"></html>

این دو attribute باید همیشه روی تگ <html> باشند:

  • lang="fa" — برای screen readerها و موتورهای جستجو
  • dir="rtl" — برای کارکرد صحیح CSS Logical Properties

CSS Logical Properties

پرتو از CSS Logical Properties به جای مقادیر فیزیکی استفاده می‌کند. این یعنی چیدمان‌ها به صورت خودکار با جهت متن تطبیق می‌یابند.

جدول معادل‌ها

فیزیکی — استفاده نکنیدLogical — استفاده کنیدمعنا
ml-*ms-*margin-inline-start
mr-*me-*margin-inline-end
pl-*ps-*padding-inline-start
pr-*pe-*padding-inline-end
left-*start-*موقعیت از ابتدای خط
right-*end-*موقعیت از انتهای خط
border-l-*border-s-*حاشیه ابتدای خط
border-r-*border-e-*حاشیه انتهای خط
rounded-l-*rounded-s-*گوشه ابتدای خط
rounded-r-*rounded-e-*گوشه انتهای خط
text-lefttext-startتراز متن
text-righttext-endتراز متن

مثال

// درست — با dir="rtl" به سمت راست قرار می‌گیرد
<div className="ms-4 ps-6 border-s-2 text-start">
  محتوا
</div>

// غلط — در RTL و LTR یکسان عمل می‌کند، تغییر جهت نمی‌دهد
<div className="ml-4 pl-6 border-l-2 text-left">
  محتوا
</div>

استثنا: مرکزگرایی مطلق

left-1/2 -translate-x-1/2 برای مرکز قرار دادن المان‌های absolute جهت‌دار نیستند و این یک استثنا مجاز است:

// این استفاده صحیح است
<div className="absolute left-1/2 -translate-x-1/2">محتوای مرکزی</div>

اعداد فارسی

ارقام فارسی از فونت می‌آیند، نه از جاوااسکریپت. این تنها یک ترجیح سبکی نیست؛ نتیجهٔ یک واقعیت قابل‌اندازه‌گیری است.

چرا — اثبات، نه ادعا

قابلیت ss01 در YekanBakh-VF یک lookup جانشینی است که هر ده گلیف رقم لاتین را به گلیف رقم فارسی نگاشت می‌کند (این با پارس مستقیم جدول GSUB فونت تأیید شده)، و globals.css آن را سراسری روشن می‌کند:

/* پیش‌فرضِ خودِ دیزاین‌سیستم — لازم نیست کاری کنید */
font-feature-settings: 'rlig' 1, 'calt' 1, 'ss01' 1;

نتیجه: می‌نویسید 1234، کاربر می‌بیند «۱۲۳۴»، و codepointها لاتین می‌مانند. این چهار چیز را سالم نگه می‌دارد که تبدیل با جاوااسکریپت هر چهار را می‌شکند:

چه چیزی سالم می‌ماندچرا با تبدیل JS می‌شکند
Copy/Pasteرقم U+06F۱ در Excel یا ماشین‌حساب عدد نیست
Screen readerرفتار قارئ‌ها روی U+06Fx یکدست نیست
مرتب‌سازی و مقایسهرشتهٔ «۱۰» و «۹» درست مرتب نمی‌شوند
Ctrl+Fکاربری که «1234» تایپ کند، پیدا نمی‌کند

این را در کد محصول خودتان تکرار نکنید

چند صفحهٔ الگو قبلاً toLocaleString('fa-IR') را توصیه می‌کردند که با همین اصل در تناقض بود. تناقض به نفع همین صفحه حل شد: در کد محصولی که روی پرتو سوار است، تبدیل دستی هیچ سودی ندارد و آن چهار مورد بالا را از بین می‌برد.

چه چیزی مجاز است

جداکننده و مختصرسازی کار جاوااسکریپت است — چون آن‌ها شکل عدد نیستند، قالب آن‌اند:

import { ,  } from '@partodata/ui/server'

// جداکنندهٔ هزارها. خروجی رقم لاتین است و فونت آن را فارسی نشان می‌دهد.
// دقت: ss01 فقط ارقام را جانشین می‌کند. کاما، نقطه و ٪ دست‌نخورده می‌مانند —
// پوشش آن lookup با پارس مستقیم GSUB سنجیده شد و فقط ده گلیف رقم است.
(1234567) // → «1,234,567»، که «۱,۲۳۴,۵۶۷» دیده می‌شود
(1234567, 'short') // → «1.2M» — فقط بسترِ لاتین؛ هشدار زیر را ببینید

// مقدار مختصر با پسوند فارسی. پسوند لاتین را هرگز روی رقم فارسی نگذارید.
(1234567, 'fa') // → «۱.۲ میلیون»
(1234567, 'en') // → «1.2M»

`formatNumber(n, 'short')` را در رابط فارسی به کار نبرید

خروجی‌اش 1.2M است و چون ss01 سراسری است، کاربر «۱.۲M» می‌بیند — رقم فارسی با پسوند لاتین، همان چیزی که چند خط بالاتر منع شد. برای مقدار مختصر در رابط فارسی formatLargeNumber(n, 'fa') را به کار ببرید؛ 'short' برای locale="en" است.

`convertToLocalNumbers` کجا جا دارد

این تابع export شده و برای مسیرهای غیرنمایشی لازم است — جایی که فونت در دسترس نیست: خروجی PDF، رندر روی canvas، یا عنصری که font-family را عوض می‌کند. برای متن معمولیِ رابط لازم نیست. خودِ کامپوننت‌های دیزاین‌سیستم آن را صدا می‌زنند چون یک کتابخانه نمی‌تواند فرض کند مصرف‌کننده فونت یکان بخ را نگه داشته است.

خلاف جهت: وقتی رقم لاتین می‌خواهید

چون ss01 سراسری است، ارقام لاتین را همه‌جا فارسی می‌کند. اگر جایی واقعاً رقم لاتین لازم دارید (تقویم میلادی، شناسه، کد رهگیری) باید صریحاً خلافش را بگویید — همان کاری که globals.css برای تقویم LTR می‌کند: font-variant-numeric: lining-nums به‌همراه عوض‌کردن font-family.


آیکون‌های جهت‌دار

برخی آیکون‌ها مانند فلش‌ها در RTL باید چرخانده شوند:

import { Icons } from '@partodata/ui'

// آیکون فلش که در RTL چرخش می‌خورد
<Icons.arrowRight className="rtl:rotate-180" />
<Icons.chevronRight className="rtl:rotate-180" />

کلاس‌های Tailwind برای RTL

// فقط در RTL نمایش داده می‌شود
<div className="hidden rtl:block">محتوای RTL</div>

// فقط در LTR نمایش داده می‌شود
<div className="hidden ltr:block">LTR Content</div>

چک‌لیست RTL

قبل از commit کردن هر کامپوننت جدید:

  • هیچ property فیزیکی (ml, mr, pl, pr, left, right, border-l, border-r) در کد وجود ندارد
  • متن‌ها text-start دارند (نه text-right)
  • آیکون‌های جهت‌دار کلاس rtl:rotate-180 دارند
  • dropdown‌ها و popoverها از طرف درست باز می‌شوند
  • انیمیشن‌های کشویی جهت RTL را رعایت می‌کنند

تایپوگرافی فارسی

فضاگذاری (letter-spacing)

در متن فارسی، letter-spacing مثبت اغلب خوانایی را کاهش می‌دهد:

// مناسب برای فارسی
<h1 className="tracking-normal">عنوان</h1>

// نامناسب — فاصله بیش از حد بین حروف فارسی
<h1 className="tracking-widest">عنوان</h1>

شکستن خط

برای متن‌های طولانی فارسی، overflow-wrap را تنظیم کنید:

word-break: normal;
overflow-wrap: break-word;

خلاصه

قانونتوضیح
lang="fa" dir="rtl" روی <html>پایه هر صفحه
CSS Logical Propertiesms/me نه ml/mr، ps/pe نه pl/pr
OpenType برای اعدادfont-feature-settings: "ss01" 1 — پیش‌فرض سیستم
rtl:rotate-180آیکون‌های جهت‌دار مثل فلش‌ها
فونت یکان بخپیش‌فرض سیستم — تغییر ندهید

صفحات مرتبط