ساخت یک پورتفولیوی دوزبانه و قابل نگهداری
مقاله منتخبیک مقالهٔ آزمایشی بلند دربارهٔ معماری، تایپوگرافی، گردش کار محتوا، کارایی و آزمون در پورتفولیوی انگلیسی و فارسی.
- انتشار
- انتشار:
- بهروزرسانی
- بهروزرسانی:
- دقیقه مطالعه
- ۹ دقیقه مطالعه
#چرا این مقاله وجود دارد؟
یک پورتفولیو معمولاً آنقدر کوچک است که ساده به نظر برسد و آنقدر مهم است که ضعف هر تصمیم را آشکار کند. هویت حرفهای، نوشتهها، پروژهها، اطلاعات تماس، فایلهای رسانهای، آمار و بخش مدیریت همگی در یک محصول نسبتاً کوچک کنار هم قرار میگیرند. وقتی زبان دوم—بهخصوص زبانی با جهت نوشتار متفاوت—اضافه میشود، این وبسایت کوچک به یک تمرین جدی در طراحی سیستم تبدیل خواهد شد.
این مقاله یک دادهٔ آزمایشی دائمی برای همین تمرین است. متن آن عمداً بلند است، از عناصر متنوع Markdown استفاده میکند و یک نسخهٔ انگلیسی مرتبط نیز دارد. بنابراین بدون آنکه پس از هر بازنشانی پایگاه داده محتوای موقت بسازیم، میتوانیم تایپوگرافی، چیدمان واکنشگرا، کنتراست پوستهها، تنظیمات مطالعه، پیوند زبانها، خوراکها، فراداده و کل مسیر انتشار را بررسی کنیم.
یک مقالهٔ آزمایشی خوب باید شبیه محتوای واقعی باشد، نه چند خط متن بیمعنا. ساختار واقعی، ایرادهای واقعی را آشکار میکند.
هدف، ساخت پیچیدهترین پورتفولیوی ممکن نیست. هدف این است که تغییرهای معمول قابل پیشبینی باشند. افزودن یک پروژه، تغییر نام یک عنوان، نوشتن یک پاراگراف فارسی یا جایگزینی فونت باید در سیستم حرکت کند، بدون آنکه در بخش دیگری غافلگیری ایجاد شود.
#مرزهای سیستم را شفاف تعریف کنید
مهمترین پرسش معماری این نیست که «از کدام فریمورک استفاده کنیم؟»؛ پرسش بهتر این است که «مالک این داده کدام بخش است؟» در یک پورتفولیوی قابل نگهداری، هر نوع داده جای مشخصی دارد.
- PostgreSQL مالک متن مقاله، وضعیت انتشار، نامک و فراداده است.
- فضای ذخیرهسازی شیءگرا مالک تصویرها، سندها و فایلهای دودویی است.
- برنامهٔ وب مالک نمایش و ترکیب مسیرها است.
- API مالک اعتبارسنجی، مجوزها و تغییر وضعیت است.
- بستهٔ قراردادهای مشترک، شکل دادهٔ مبادلهشده میان این مرزها را تعریف میکند.
وقتی مالکیت روشن باشد، فهم خطاها آسانتر میشود. اگر عنوان مقاله اشتباه است، رکورد محتوا را بررسی میکنیم. اگر تصویر نمایش داده نمیشود، سراغ مرجع رسانه میرویم. اگر پاراگراف فارسی فونت اشتباهی دارد، ویژگی زبان و CSS را بررسی میکنیم، نه اینکه متن ذخیرهشده را بازنویسی کنیم.
در طراحی نامناسب، یک مقدار واحد میان فایلهای منبع، متغیرهای محیطی، رکوردهای پایگاه داده و وضعیت کلاینت پخش میشود. این روش در ابتدا راحت به نظر میرسد، اما هر ویرایش بعدی را به مسئلهای برای هماهنگسازی تبدیل میکند.
#نوشتههای دوزبانه را سندهای مرتبط در نظر بگیرید
نسخهٔ انگلیسی و ترجمهٔ فارسی یک موضوع مشترک دارند، اما یک سند واحد با جایگزینی چند رشته نیستند. هر نسخه به عنوان، نامک، خلاصه، توضیح موتور جستوجو، متن، تاریخ انتشار و وضعیت ویرایشی مستقل نیاز دارد. ترجمه ممکن است دیرتر آماده شود، ساختار متفاوتی داشته باشد یا مثالهایی انتخاب کند که برای خوانندهٔ آن زبان روشنتر است.
ارتباط پایدار باید در سطح نوشته باشد:
نوشته
├── نسخهٔ انگلیسی
└── نسخهٔ فارسی
این سلسلهمراتب کوچک امکان ساخت انتخابگر زبان را فراهم میکند، بدون آنکه انتشار همزمان دو نسخه اجباری باشد. همچنین از یک بازگشت خطرناک جلوگیری میکند: اگر ترجمهٔ فارسی وجود ندارد، محتوای انگلیسی نباید صرفاً برای پر کردن صفحه زیر نشانی فارسی نمایش داده شود.
برای آزمون، دستکم این وضعیتها را بررسی کنید:
- هر دو ترجمه منتشر شدهاند و به یکدیگر پیوند دارند.
- فقط نسخهٔ انگلیسی منتشر شده و مسیر فارسی وجود ندارد.
- فقط نسخهٔ فارسی منتشر شده و فهرست انگلیسی آن را افشا نمیکند.
- نامک یک ترجمه تغییر میکند، بدون آنکه مسیر زبان دیگر هدایت شود.
#تایپوگرافی بخشی از درستی محصول است
گاهی دربارهٔ تایپوگرافی مانند یک تزئین صحبت میشود، اما پشتیبانی از خط یک نیاز عملکردی است. فونتی که در انگلیسی زیباست ممکن است هیچ نویسهٔ فارسی نداشته باشد. مرورگر در این حالت برای هر نویسه به فونت دیگری برمیگردد و نتیجه میتواند فاصلههای ناهماهنگ، تأکید شکسته یا مربعهای ناخوانا باشد.
این سایت برای متن رابط لاتین از JetBrains Mono و برای محتوای فارسی از شبنم استفاده میکند. فایلهای فارسی، نسخههای بدون لاتین شبنم هستند؛ در نتیجه عبارتهای ترکیبی مانند TypeScript، Next.js و نشانیهای وب بهصورت طبیعی با فونت لاتین نمایش داده میشوند. این جداسازی از ارسال دو نسخهٔ تکراری نویسههای لاتین جلوگیری میکند.
وزنهای مهم فونت بهصورت هدفمند نگاشت شدهاند:
| کاربرد | وزن CSS | فایل استفادهشده |
|---|---|---|
| متن عادی | ۴۰۰ | شبنم معمولی |
| تأکید متوسط | ۵۰۰ | شبنم متوسط |
| عنوان و متن پررنگ | ۷۰۰ | شبنم پررنگ |
وزنهایی که طراحی هرگز انتخاب نمیکند نباید در پوشهٔ عمومی داراییها باقی بمانند. مرورگرهای مدرن به woff2 نیاز دارند؛ نگهداشتن نسخههای تکراری .eot، .ttf و .woff حجم مخزن و انتشار را افزایش میدهد، بدون آنکه تجربهٔ پشتیبانیشده را بهتر کند.
#جهت نوشتار به محتوا تعلق دارد
یک صفحهٔ دوزبانه میتواند در یک نمای واحد، سربرگ انگلیسی، مقالهٔ فارسی، قطعهکد چپبهراست و نشانی انگلیسی داشته باشد. بنابراین جهت باید روی کوچکترین مرز معنادار سند تعریف شود، نه با یک حدس سراسری در JavaScript.
روی ناحیهٔ مطالعهٔ فارسی lang="fa" و dir="rtl" قرار دهید. کد را بهصورت چپبهراست ایزوله نگه دارید. از ویژگیهای منطقی CSS مانند margin-inline-start، padding-inline-end و text-align: start استفاده کنید؛ این ویژگیها با تغییر جهت بهطور خودکار سازگار میشوند.
.article-body {
padding-inline: 1.25rem;
text-align: start;
}
.article-body pre {
direction: ltr;
unicode-bidi: isolate;
}
این رویکرد برای فناوریهای کمکی نیز مفید است. اطلاعات زبان، قواعد تلفظ را تغییر میدهد و جهت درست مانع جابهجایی غیرمنتظرهٔ نشانهگذاری و عددها میشود.
#یک مسیر محتوای قطعی بسازید
متن Markdown ذخیرهشده منبع اصلی حقیقت است. HTML رندرشده فقط یک حافظهٔ نهان مشتقشده از آن منبع است. هر ذخیره باید پایان خطها را یکسان کند، ساختار را اعتبارسنجی کند، خروجی را پاکسازی کند، درخت عنوانها را بسازد، زمان مطالعه را محاسبه کند و چکیدهای رمزنگاریشده از متن اصلی نگه دارد.
یک مسیر سادهشده شبیه نمونهٔ زیر است:
const source = normalize(markdown);
const digest = sha256(source);
const rendered = await renderMarkdownBody(source);
await save({
source,
digest,
html: rendered.html,
headings: rendered.headings,
readingMinutes: rendered.readingTimeMinutes,
rendererVersion: rendered.rendererVersion,
});
چکیده از ناهماهنگی تصادفی میان منبع و خروجی جلوگیری میکند. نسخهٔ رندرکننده نیز مهاجرتها را شفاف میسازد: وقتی رفتار رندر تغییر کند، ردیفهای قدیمی پیدا و دوباره تولید میشوند، نه اینکه HTML ناسازگار بیصدا به کاربر نمایش داده شود.
دادهٔ seed قطعی نیز همین اصل را دنبال میکند. شناسهها و زمان انتشار ثابت باعث میشوند اجرای دوباره امن باشد. عملیات upsert بر اساس هویت نوشته تضمین میکند که دادهٔ آزمایشی فقط یک بار ظاهر شود، نه یک بار برای هر نشست توسعه.
#برای شکست طراحی کنید، نه فقط موفقیت
یک پورتفولیوی واقعی به سامانههایی وابسته است که میتوانند مستقل از یکدیگر شکست بخورند. شاید پایگاه داده در دسترس نباشد، اما فایلهای ثابت کار کنند. ممکن است دریافت آمار GitHub طول بکشد، در حالی که متن مقاله سالم است. شاید یک فایل رسانهای قرنطینه شود، ولی بقیهٔ نوشته معتبر بماند.
رفتار مفید باید آرام و دقیق باشد:
- شکست یک آمار اختیاری فقط همان آمار را پنهان میکند، نه کل صفحه را.
- خروجی منتشرشدهٔ خراب از فهرست عمومی حذف میشود و مورد اعتماد قرار نمیگیرد.
- ترجمهٔ موجودنباشد یک پاسخ روشن همراه با زبانهای در دسترس میدهد.
- سرویس محتوای ازدسترسخارج یک سطح بازیابی پایدار نمایش میدهد.
- محتوای پیشنویس و زمانبندیشده هرگز وارد فهرست یا خوراک عمومی نمیشود.
هر تصمیم باید در همان مرزی آزمون شود که آن را اعمال میکند. آزمون واحد برای تجزیه و اعتبارسنجی عالی است. آزمون یکپارچه تراکنشهای پایگاه داده را ثابت میکند. آزمون مرورگر جهت، تایپوگرافی، ناوبری و نبود چشمک در اولین نمایش را بررسی میکند.
#کارایی از خویشتنداری میآید
کارایی پورتفولیو معمولاً به بهینهسازی عجیب نیاز ندارد؛ کافی است کار کمتری به مرورگر ارسال شود.
با این فهرست کوتاه شروع کنید:
- فقط فایل حیاتی فونت برای مسیر جاری را از پیش بارگیری کنید.
- خانوادههای اختیاری را تا زمان انتخاب خواننده تنبل نگه دارید.
- تصویرهای واکنشگرا را با اندازههای مشخص ارائه کنید.
- مؤلفههایی را که میتوانند روی سرور رندر شوند بیدلیل hydrate نکنید.
- خواندن عمومی را بر اساس زبان cache کنید و فقط برچسبهای مرتبط را باطل کنید.
- حرکت را اختیاری نگه دارید و ترجیح کاهش حرکت را رعایت کنید.
همین خویشتنداری نگهداری را نیز بهتر میکند. هر دارایی، وابستگی و اثر سمت کلاینت باید هزینهٔ دائمی خود را توجیه کند.
#ماتریس عملی بررسی
پیش از کامل دانستن تجربهٔ دوزبانه، بهجای یک مسیر خوشبینانه، یک ماتریس را بررسی کنید.
| بخش | بررسی انگلیسی | بررسی فارسی |
|---|---|---|
| تایپوگرافی | وزنهای لاتین درست بارگیری شوند | شکل و اتصال نویسههای شبنم درست باشد |
| جهت | چیدمان چپبهراست بماند | متن و فهرست مقاله راستبهچپ باشد |
| کد | بلوکها چپبهراست بمانند | کد ترکیبی ایزوله بماند |
| پوسته | کنتراست روشن و تیره مناسب باشد | کنتراست با حروف فارسی مناسب باشد |
| کشف محتوا | خوراک انگلیسی نسخهٔ انگلیسی را داشته باشد | خوراک فارسی نسخهٔ فارسی را داشته باشد |
| زبان جایگزین | به نسخهٔ فارسی منتشرشده پیوند دهد | به نسخهٔ انگلیسی منتشرشده پیوند دهد |
اندازهٔ صفحه را تغییر دهید، با صفحهکلید حرکت کنید، اندازهٔ مطالعه را افزایش دهید، پوسته را عوض کنید و پنل شبکه را ببینید. بررسی خودکار از بازگشت خطا جلوگیری میکند و یک بازبینی بصری کوتاه، مشکلهای ریتم و شکل حروف را آشکار میسازد که آزمون ساختاری قادر به توصیفشان نیست.
#نگهداریپذیری چه حسی دارد؟
سیستم قابل نگهداری سیستمی نیست که هرگز تغییر نکند؛ سیستمی است که پیامدهای تغییر را آشکار میکند. جایگزینی فونت فارسی باید تعداد محدودی اعلان، فایل، قرارداد و آزمون را تغییر دهد. افزودن ترجمه باید یک سند مرتبط بسازد، نه کل نوشته را تکرار کند. بهروزرسانی رندرکننده باید همهٔ خروجیهای قدیمی را قابل شناسایی کند.
این مقالهٔ آزمایشی برای سنجش همین استاندارد ساخته شده است. بهاندازهای بلند است که مشکل فاصلهٔ خطوط را آشکار کند، آنقدر تنوع دارد که رندرکنندهٔ Markdown را به کار بگیرد و آنقدر پایدار است که پس از هر بار seed پایگاه داده در دسترس باشد.
اگر همهٔ این متن در هر دو زبان خوانا باشد، پس از refresh باقی بماند، در فهرستها درست ظاهر شود و بعد از seed تمیز همچنان معتبر باشد، پورتفولیو دیگر فقط در سطح داده دوزبانه نیست؛ بلکه بهعنوان یک سیستم کامل دوزبانه عمل میکند.