بازگشت به بلاگ

زمان مطالعهٔ فارسی را کتابخانه‌ات اشتباه حساب می‌کند

کتابخانه‌های محتوا کلمه را با /[a-zA-Z]+/ می‌شمارند. برای یک متن فارسی، نتیجه صفر است — و هیچ‌کس خطا نمی‌بیند.

هر بلاگی «۵ دقیقه مطالعه» را بالای پست نشان می‌دهد. عددش از یک شمارندهٔ کلمه می‌آید و کسی به آن شک نمی‌کند. تا وقتی که متن فارسی باشد.

چیزی که در سورس دیدیم

هنگام راه‌اندازی همین بلاگ، s.metadata() را از Velite برداشتیم. مستنداتش می‌گوید readingTime و wordCount برمی‌گرداند و این حرف درست است. ولی سورس نصب‌شده چیز دیگری می‌گوید:

var wordLength = (str) => {
  const reWord = /['’]?([a-zA-Z]+(?:['’]?[a-zA-Z]+)*)/g;
  const words = str.match(reWord) || [];
  return words.length;
};

شمارنده فقط a-zA-Z را کلمه می‌داند. برای زبان‌های چینی و ژاپنی و کره‌ای یک مسیر جدا دارد، ولی فارسی و عربی در هیچ‌کدام نمی‌افتند. یعنی برای یک مقالهٔ دوهزار کلمه‌ای فارسی، wordCount تقریباً صفر است و readingTime می‌شود یک دقیقه — همیشه.

بدترین بخشش این است که هیچ ارور و هیچ هشداری در کار نیست. عدد اشتباه با اعتماد کامل رندر می‌شود.

راه‌حل، سه خط

فارسی هم کلمه‌هایش را با فاصله جدا می‌کند. پس شمارش درست، شمارش توکن‌های جداشده با فاصله است:

const plain = context().file.plain ?? '';
const words = plain.split(/\s+/u).filter(Boolean).length;
const minutes = Math.max(1, Math.round(words / WORDS_PER_MINUTE));

یک نکتهٔ ریز که مهم است: نیم‌فاصله (U+200C) در «می‌کنند» فاصله نیست و در \s نمی‌افتد. برای همین «می‌کنند» یک کلمه می‌ماند، همان‌طور که باید.

درسی که می‌ماند

مستندات گفته بود چه چیزی برمی‌گرداند، نه اینکه چطور حسابش می‌کند. برای هر چیزی که به اسکریپت غیرلاتین دست می‌زند، سورسِ نصب‌شده حرف آخر را می‌زند نه صفحهٔ داکیومنت.

اگر پروژه‌ای فارسی دارید، همین امروز زمان مطالعهٔ پست‌هایتان را چک کنید. احتمالش هست که همه‌شان «۱ دقیقه» باشند.