دوستانی که قبلا با وبلاگ بنده آشنا بودن می دونند که معمولا هر پروژه ای که در اینجا به صورت خلاصه آموزش داده میشه حتما یک داستانی داره که چرا این پروژه خواه با ارزش خواه بی ارزش کار شده است. بنده در این مجموعه از مطالب آموزشی اصلا بر روی ارزش واقعی پروژه بحثی نکردم و نخواهم کرد چون اعتقاد دارم مطلب آموزشی ارزش اینگونه مباحث را ندارد.بگذریم و بریم سر اصل داستان و پروژه چند روز پیش دوستی تقاضا کرد که حدودا 50 صفحه مطلب فارسی را برایش ترجمه کنم، بنده هم با کمال خونسردی ابتدا جواب رد بر سینه اش زدم و گفتم وقت برای ترجمه ندارم. این دوست عزیز از جایی شنیده بود که Google Translator می تواند از عهده ی این کار بر آید از این رو گفت که از آن استفاده کنم بنده هم گوش زد های مربوطه را کردم که این ترجمه این سرویس آن چیزی نخواهد بود که تو انتظار داری. خلاصه توافق کردیم که مسئولیتش گردن خودش باشد.
پس از توافق با خود گفتم چه کسی حوصله کپی و درج مطالب را از فایل متنی به مترجم دارد. بهانه ای شد که زمانی را که صرف این عمل بیهوده میکنم، صرف تولید نرم افزاری کنم که به صورت اتوماتیک فایل متنی را گرفته به بخش های کوچک تقسیم کرده و سپس از طریق این سرویس ترجمه نماید.
از این رو شروع به نوشتن این برنامه کردم که توضیحات مفصل آن در ادامه خواهم داد.
من در این نرم افزار از یک کلاس Abstract به نام Translator استفاده کردم چرا Abstract چون اگه در آینده قرار باشه سرویس های دیگری غیر از Google Translator رو هم پشتیبانی باید اعضای این کلاس Override بشن. کلاسی که من برای ترجمه ی متون ازش استفاده می کنم GoogleTranslator هستش که همونطور که گفتم باید از کلاس Translator ارث ببره.
خوب در بالا هم گفتم که این نرم افزار ابتدا فایل رو باز میکنه و سپس فایل متنی رو به تکه های کوچک تقسیم می کنه و سپس هر chunk رو برای ترجمه کردن به کلاس GoogleTranslator میده .
نکته : چرا فایل رو به تکه تکه می کنیم، ببینید فرمت URL ای که من ازش استفاده میکنم با اون چیزی که شما در Browser مشاهده می کنید فوق می کنه. شما اگه از فرمتی http://translate.google.com/#en|fa|book استفاده کنید، این URL ای هستش که این سرویس از طریق Callback هنگام ترجمه تولید میکنه، اگه در این حالت شما از Firebug استفاده کنید تا ID تگ Result ی که متن ترجمه شده در آن قرار دارد را ببینید به راحتی قابل تشخیص خواهد بود، حال چنانچه این آدرس را از طریق HttpRequest بفرستید خواهید دید که Response برگشتی اصلا شامل چنین تگی نخواهد بود. و اما جواب که چرا فایل رو به خوب همونطور که می دونید در دات نت آدرس از لحاظ تعداد کاراکتر محدودیت داره و اگه بیشتر از اون محدوده ارسال بشه در Response پیغام خطا میده بنابراین چاره ای نیست جز اینکه فایل رو به chunk های کوچکتر تقسیم کنیم.
* – نحوه خواندن و ذخیره کردن در Queue با استفاده از تابع ReadFile :
public Queue ReadFile()
{
StreamReader fileReader =
new StreamReader(_inputFile, Encoding.UTF8);
if (BeforeReadFile != null)
BeforeReadFile(this, null);
string val;
char[] buffer = new char[128];
lock (this)
{
while (fileReader.Peek() >= 0)
{
fileReader.Read(buffer, 0, 128);
if (char.IsWhiteSpace(buffer[buffer.Length - 1]))
{
val = new String(buffer);
_linesQueue.Enqueue(val);
buffer = new char[128];
}
else
{
for (int i = buffer.Length; i >= 0; i--)
{
if (char.IsWhiteSpace(buffer[i - 1]))
{
val = new String(buffer).Substring(0, i);
_linesQueue.Enqueue(val);
buffer = new char[128];
break;
}
}
}
}
}
if (AfterReadFile != null)
AfterReadFile(this, null);
return _linesQueue;
}
این تابعیست که وضیفه خواندن فایل رو بر عهده داره، چند نکته وجود داره که باید رعایت بشن. بافری که من برای خواندن از فایل اختصاص دادم 128 کاراکتر است، این بدین معنی هستش که زمان خواندن از فایل 128 کاراکتر باید از فایل خونده بشه. خوب همونطور که میبینید بنده برای اینکه مطمئن بشم که آخرین کاراکتری که در بافر قرار داده شده وسط یک کلمه نیست بنده اون رو با متد IsWhiteSpace بررسی کردم. خوب اگر کاراکتر موجود در خانه آخر بافر کاراکتر فضای خالی باشه مشکلی نیست می فهمیم که مشکلی وجود نداره و می تونیم که Chunk Queue اضافه کنیم. حال اگر کاراکتری غیر از فضای خالی بود چه ؟ باید بافر رو به صورت نزولی از آخر به اول بررسی کنید اگر کاراکتر فضای خالی دیدید آنرا به Queue اضافه کنید.
نکته : در انتخاب اندازه بافر دقت کنید چون این عمل تاثیر مستقیم بر روی طول URL داره که محدودیت خاص خودش رو داره.
*- پاس کردن و ترجمه Chunk ها با استفاده از کلاس GoogleTranslator :
قدم بعدی این هستش که تکه های متنی که ازفایل خونده شده رو با استفاده از متد Translate کلاس Translator ترجمه کنیم. همانطور که در تابع ReadFile دیدید مقدار بازگشتی این تابع یک Queue هستش. بنابراین باید هر آیتم رو از این صف به تابع Translate پاس کنیم.
public override string TranslateText(string content)
{
string url = CreateWebURL(content);
HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
webRequest.KeepAlive = false;
webRequest.AutomaticDecompression =
DecompressionMethods.GZip | DecompressionMethods.Deflate;
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
// Get response stream and download all raw html
Stream resStream = webResponse.GetResponseStream();
StreamReader streamReader = new StreamReader(resStream, Encoding.UTF8);
// ---------------------------------------------
string html = streamReader.ReadToEnd();
return ParseContent(html);
}
خوب عملکرد این تابع خیلی ساده است، در این حد که متن را که به عنوان ورودی به تابع پاس شده است را با استفاده از HttpWebRequest و HttpWebResponse ترجمه کرده و با استفاده از تابع GetResponseStream محتویات را که شامل Html می باشد را خوانده و پس از Parse کردن آن مقدار متن ترجمه شده را بازگرداند.
*- تابع ParseContent :
public override string ParseContent(string html)
{
return HtmlParser.ParseHtml(html);
}
*- تابع ParseContent از کلاس HtmlParser :
internal static string ParseHtml(string html)
{
int identifierIndex = -1;
int firstSpanIndex = -1;
int spanCloseIndex = -1;
int spanCloseTagIndex = -1;
// Remove all html and text from start to index of result box
identifierIndex = html.IndexOf(ResultBoxIdentifier);
html = html.Remove(0, identifierIndex);
// ----------------------------------------------------------
// Delete all text to index of
firstSpanIndex = html.IndexOf(FirstSpanIdentifier);
html = html.Remove(0, firstSpanIndex);
// -------------------------------------
// -------------------------------------
spanCloseIndex = html.IndexOf(SpanCloseIdentifier);
html = html.Remove(0, spanCloseIndex + 1);
// -------------------------------------
// Delete all remain html data from end of the translated texts
spanCloseTagIndex = html.IndexOf(SpanCloseTagIdentifier);
html = html.Remove(spanCloseTagIndex, html.Length - spanCloseTagIndex);
// ------------------------------------------------------------
return html.Replace("'", "'").Replace("
", "\n");
}
وظیفه ی این دو تابع بالا اینه که تا زمان رسیدن به تگ span با id=»result_box» و بعد از متن ترجمه شده بقیه Html ای که از طریق Response دریافت شده رو حذف کرده و در نهابت متن ترجمه شده را برگردانند.
برای دانلود سورس اینجا رو کلیک کنید.
موفق باشید