فارسی در اندروید

نمایش ایده‌آل نوشتهٔ دوجهته و حروف چسبیده

تا قبل از نسخهٔ 3.0 سیستم عامل اندروید، رام‌های حاصل از کمپایل پروژهٔ اُپن‌سورس اندروید قابلیت چسباندن حروف فارسی را نداشت. همچنین الگوریتم چیدن نویسه‌ها در متن‌های دوجهته نیز در نسخه‌های قدیمی‌تر مانند 2.1 ایراداتی داشتند و چیدمان حروف در آنها چندان قابل پیش‌بینی نبود.

سازندگان گوشی‌های همراهی که سهم قابل توجهی در بازار ایران داشتند و حتی واردکنندگان گوشی‌های اندرویدی بی‌کار ننشستند و برای گوشی‌هایی که راهی این منطقه بودند رام‌ها را دستکاری کردند که تا حدودی مشکل نمایش زیان را حل کنند.

ولی کابوس جدیدی برای برنامه‌نویس‌های ایرانی بوجود آمد: تنوع پیاده‌سازی‌های نمایش متن که برای محتوای یکسان نتایج متفاوتی را ارائه می‌دهند. در این مطلب به این می‌پردازیم که چگونه برنامه‌ٔ اندرویدی‌مان فارسی را به خوبی نشان دهد.

پیش از استدلال، نتیجه‌گیری‌ام را همینجا می‌آورم چون احتمالاً دوستش نخواهید داشت! پیشنهاد می‌کنم توجهی به این تنوع پیاده‌سازی نکنید و با فرض اینکه دستگاه مخاطبتان قادر به نمایش خط فارسی است برنامه‌تان را آماده کنید.

در اکثر موارد، بهترین کار برای نمایش مناسب متن فارسی در برنامهٔ اندرویدی‌تان نادیده گرفتن گوشی‌هایی است که قابلیت نمایش فارسی ندارند.

روش ایده‌آلی که روی همهٔ گوشی‌ها تضمینی کار کند بسیار سخت است. لازم است تمامی ویجت‌هایی که لازم دارید و با متن کار دارند را بازنویسی کنید و قسمت render متنشان را جایگزین کنید. کدهای جایگزین به خاطر اًپن‌سورس بودن فارسی‌تل در دسترس هستند ولی جایسازی آن‌ها در ویجت‌ها کار آسانی نیست. اگر مشکل زمان ندارید، و به هر دلیلی مجبورید مشکل فارسی را برای برنامهٔ خود حل نمایید، می‌توایند مستقیم بروید به قسمت آخر.

Shaper ها

راه حل آسان استفاده از یکی از کتابخانه‌های جاوایی shaping موجود است. آن‌هایی که می‌شناسم را اینجا فهرست می‌کنم، اگر چیزی جا انداختم ممنون می‌شم برایم در نظرات تذکرش دهید:

تقریباً اساس کار همهٔ این کتابخانه‌ها یک چیز است: جایگزین کردن نویسه‌های نماینگر حروف با نویسه‌های نمایانگر شکل حروف.

رابطهٔ حروف و شکل حروف در یونی‌کد

ﺏ با ب فرق دارد. باور ندارید؟ اولی را در یک ویرایشگر متن کپی کنید و سعی کنید به حرف دیگری بچسبانیدش.

کنترل+اف (یا کامند+اف) را بزنید و عبارت «کتاب» را جستجو کنید. می‌بینید که مرورگرتان این کلمه را در کتابخانه هم پیدا می‌کند. این اتفاق نیک به این دلیل می‌افتد که حرف ب‍ در کتابخانه فرقی با حرف ب در کتاب ندارد هر چند دو جور نمایش داده می‌شوند. اگر به جستجوی خود ادامه دهید متوجه می‌شوید که این «ﮐﺘﺎﺑﺨﺎﻧﻪ» از زیر دست جستجوی مرورگرتان گریخته است (کروم دارید؟ جستجوگرش سمج‌تر از این حرف‌هاست). دلیلش این است که این ﮐﺘﺎﺑﺨﺎﻧﻪ از چسبیدن نویسه‌های نمایشی شکل گرفته است. اگر قسمت آخرش را حذف کنید تبدیل به ﮐﺘﺎﺑ می‌شود و نه کتاب. این نوشته از بهداد اسفهبد در وبلاگ فارسی گوگل توضیحات مفصل‌تری دربارهٔ نویسه‌ها در یونی‌کد می‌دهد.

نکتهٔ دیگری که بین زبان‌های راست به چپ مشترک است موضوع ترتیب نویسه‌ها است. در کتابخانهٔ render متن اندروید، و احتمالاً تمامی دیگر کتابخانه‌های مدرن render متن در جهان، گام‌های زیر به ترتیب اتفاق می‌افتند:

۱. با توجه به قلم، برای هر یک از نویسه‌ها طول گلیف آن نویسه محاسبه می‌شود. (+)

۲. با توجه به فضای موجود و اعداد بدست آمده در مرحلهٔ قبل، محل شکستن خط پیدا می‌شود. (+)

۳. با توجه به تراز، محل اولین نویسه محاسبه می‌شود. مثلاً برای حالت چپ‌چین محل اولین نویسه صفر به معنی چپ‌ترین مکان خط است و برای حالت وسط‌چین برابر است با تفاضل طول محاسبه‌شده برای خط از کل فضای موجود تقسیم بر دو. (+)

۴. در محل اولین نویسه گلیف آن نویسه رسم می‌شود و سپس به اندازهٔ طول آن گلیف به سمت راست می‌رود. این کار تا آخرین نویسه خط تکرار می‌شود. (+)

بدین‌ترتیب لازم است برای متن‌های راست‌به‌چپ و از آن پیچیده‌تر متن‌های ترکیبی قبل از مرحلهٔ ۱ ترتیب نمایشی نویسه‌ها به دست آید و این الگوریتم روی ترتیب نماشی نویسه‌ها اجرا شود و نه ترتیب منطقی‌شان. همچنین با توجه به حروف اول پاراگراف ممکن است لازم باشد تراز خط معکوس گردد. پیچیده‌تر از آن زمانی است که لازم است ترتیب نویسه‌های منطقی از روی نمایشی محاسبه شود؛ مثل زمان انتخاب متن.

راه‌حل مشکل چینش حروف در بعضی از رام‌ها

مشکلات استفاده از shaper

  • برای ورود متن فارسی به این راحتی‌ها جواب نمی‌دهد. لازم است که متن واقعی از متنی که نمایش داده می‌شود جدا نگهداری شود. این یعنی عدم امکان استفادهٔ کم دنگ و فنگ از ویجت ورود متن پیش‌فرض اندروید. همچنین کلمهٔ آخر متن باید در ازای ورود هر کاراکتر مجدداً reshape شود.

  • حتی برای نمایش متن هم همیشه جواب نمی‌دهد. الگوریتم چیدن نویسه‌ها در اندروید تا قبل از نسخهٔ 2.2 ایراد داشت. حتی بعضی از رام‌های دستکاری شدهٔ htc در نسخه‌های جدیدتر نیز همچنان مشکل دارند. برای حل این مسأله بعضی از این shaper ها به reorder هم مجهز هستند ولی تفاوت در میان نسخه‌ها باعث می‌شود که باز مسأله به آسانی حل نشود. راه حلی که یکی از بزنامه‌سازان (دقیق یادم نیست، احتمالاً اقلیم) برای این مشکل استفاده کرده بود و ما هم در تقویم فارسی‌تل از همان روش استفاده کردیم، نمایش دو متن یکی reorder شده و دیگری reorder نشده به کاربر بود. کاربر با انتخاب متنی که به درستی می‌دید در واقع مشخص می‌کرد که آیا دستگاهش نیاز به reorder دارد یا خیر.

  • دلخوری کاربری که گوشی‌اش فارسی دارد از خرابی متن فارسی پررنگ‌تر از خوشحالی کاربری است که گوشی‌اش فارسی ندارد ولی برنامهٔ شما برایش فارسی نمایش می‌دهد. لذا این موضوع که reorder کردن متن ممکن است با فارسی‌سازی گوشی تداخل پیدا کند موضوع مهمی است.

    ۲۷٪ کاربران بازار زبان گوشی‌شان فارسی است.

    تعداد گوشی‌های اندرویدی در بازار ایران که توان نمایش فارسی دارند با سرعت زیادی رو به افزایش است. از میان کاربرانی که طی هفتهٔ اخیر بازار را روی گوشی‌شان نصب کرده‌اند ۳۵٪ زبان گوشی خود را روی فارسی قرار داده‌اند. این نسبت در ژوئن سال پیش فقط ۲٫۵٪ بوده است. با توجه به تعداد کاربرانی که زبان نرم‌افزار بازار را روی فارسی قرار داده‌اند ولی زبان گوشی‌شان فارسی نیست می‌توان حدس زد که دست کم ۷۰٪ گوشی‌های اندرویدی که الان در ایران به فروش می‌رسند از خط فارسی پشتیبانی می‌کنند. این را بگذارید کنار این موضوع که عمر متوسط گوشی‌های همراه چیزی در حدود دو سال است (منتظر تخمین دقیق‌تر و موثق‌تری هستم). درصد بالایی از مشتری‌های بالاقوهٔ شما مشکلی با زبان فارسی نخواهند داشت.

زمستان ۱۳۸۹ بازار را دوزبانه تدوین کردیم تا کاربرانی که مشکل نمایش فارسی دارند نیز بتوانند از بازار استفاده کنند. بهار ۱۳۹۱ است و پروژهٔ دیگری در راه داریم. و به دلایلی که آوردم این بار آن را فقط به زبان فارسی و بدون مکانیسم shaping درون-برنامه‌ای ارائه خواهیم کرد.

پیاده‌سازی پیشنهادی

همچنان علاقه‌مندید که کاربرانتان نمایش مناسب فارسی را مستقل از نسخهٔ سیستم عاملشان تجربه کنند؟ لازم است آستین بالا بزنید و Custom View بنویسید. اولین ویجتی که لازم است بازنویسی کنید TextView است. در آخرین مرحله که متن روی صفحه قرار می‌گیرد reorder و shaping را با کتابخانهٔ دلخواهتان انجام دهید. ما از FriBiDi استفاده کردیم. لازم است که تا پایین‌ترین مرحلهٔ نمایش متن در کدهای شما اتفاق بیفتد. اگر از توابع سطح بالاتر اندروید برای نمایش متن استفاده کنید ممکن است در بعضی رام‌ها متن‌تان دوباره reorder شود و این متن را خراب خواهد کرد.

دکمه، ورودی متن و دیگر ویجت‌ها آسان هستند چرا که تقریباً همگی برای نمایش متن از TextView استفاده می‌کنند و کافیست که مشابه آن‌ها و بدون تغییر کد Custom View هایی نوشته شوند که از TextView جدید شما استفاده می‌کنند. قسمت سخت WebView خواهد بود که در حال حاضر راه حلی برای آن ندارم. ما در فارسی‌تل در کد WebKit دست بردیم و تکرار این کار با Custom View عملی نیست. چنانچه راه مناسبی مناسبی می‌شناسید، خوشحال می‌شوم که در قسمت نظارت به آن اشاره کنید.

امکان نظرات توسط Disqus.