This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
لذا لفترة من الوقت الآن لقد استخدمت "ايسي نمت" لترجمة .md
إلى لغات مختلفة هنا هنا/ / / / لقد أردت أن "السطح" هذا حتى تتمكنوا جميعا من الحصول على اللعب معه أيضا.
انظر الجزء الثاني من هذا السلسلة هنا هنا.
النسر المُعين بينكم سيكون قد لاحظتم أنني أضفت قطرة صغيرة إلى مُحرّر الهدف.
هذه قائمة من اللغات التي أترجمها (ياسي نمت هي نوع من خنزير مورد لذا قمت بتحديد عدد اللغات التي يمكنني ترجمتها).
[رابعاً -
عند تحديد لغة من الأسفل، واضغط على زر سترسل مهمة 'ترجمة' إلى هذا API:
[ApiController]
[Route("api/[controller]")]
public class TranslateController(
BackgroundTranslateService backgroundTranslateService,
TranslateCacheService translateCacheService) : ControllerBase
{
[HttpPost("start-translation")]
public async Task<IActionResult> StartTranslation([FromBody] MarkdownTranslationModel model)
{
// Create a unique identifier for this translation task
var taskId = Guid.NewGuid().ToString("N");
var userId = Request.GetUserId(Response);
// Trigger translation and store the associated task
var translationTask = await backgroundTranslateService.Translate(model);
var translateTask = new TranslateTask(taskId, model.Language, translationTask);
translateCacheService.AddTask(userId, translateTask);
// Return the task ID to the client
return Ok(new { TaskId = taskId });
}
}
يقوم (ثيس) ببعض الأشياء:
خدمة (كوكي) هي امتداد بسيط على كائن Httpque. إنه يتأكد من وجود كعكة، إن لم تكن موجودة، فإنه يخلق كعكة جديدة. هذا مُستخدَم إلى تعرّف و.
public static class UserIdHtlper
{
public static string GetUserId(this HttpRequest request, HttpResponse response)
{
var userId = request.Cookies["UserIdentifier"];
if (userId == null)
{
userId = Guid.NewGuid().ToString();
var cookieOptions = new CookieOptions
{
Expires = DateTimeOffset.UtcNow.AddMinutes(60),
HttpOnly = true,
Secure = true,
SameSite = SameSiteMode.Strict
};
response.Cookies.Append("UserIdentifier", userId, cookieOptions);
}
return userId;
}
}
تستخدم خدمة المخبأ مخبأ بسيطاً داخل الذاكرة لتحمّل جميع مهام الترجمة لمستعمل واحد (أنت! ). سترين أنّي وضعتُ المخبأ لينتهي بعد ساعة. هذا لأنني لا أريد التمسك بهذه المهام لفترة طويلة.
public class TranslateCacheService(IMemoryCache memoryCache)
{
public List<TranslateTask> GetTasks(string userId)
{
if (memoryCache.TryGetValue(userId, out List<TranslateTask>? task)) return task;
return new List<TranslateTask>();
}
public void AddTask(string userId, TranslateTask task)
{
if (memoryCache.TryGetValue(userId, out List<TranslateTask>? tasks))
{
tasks ??= new List<TranslateTask>();
tasks.Add(task);
memoryCache.Set(userId, tasks, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
}
else
{
memoryCache.Set(userId, new List<TranslateTask> { task }, new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
}
}
}
public record TranslateTask(string TaskId, string language, Task<TaskCompletion>? Task);
سأغطي هذا في الجزء التالي، إنه نوع من الوحش.
Translate
تستخدم طريقة AMPLEULEULETION Source للسماح لنا بتتبع حالة مهمة الترجمة. public async Task<Task<TaskCompletion>> Translate(MarkdownTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result of the translation
var translateMessage = new PageTranslationModel
{
Language = message.Language,
OriginalFileName = "",
OriginalMarkdown = message.OriginalMarkdown,
Persist = false
};
return await Translate(translateMessage);
}
private async Task<Task<TaskCompletion>> Translate(PageTranslationModel message)
{
// Create a TaskCompletionSource that will eventually hold the result of the translation
var tcs = new TaskCompletionSource<TaskCompletion>();
// Send the translation request along with the TaskCompletionSource to be processed
await _translations.SendAsync((message, tcs));
return tcs.Task;
}
كما يمكنك أن ترى كل ما يفعله هذا حقاً هو إرسال ترجمة إلى BufferBlock
(سأنظر إلى القنوات في المستقبل، قد يكون نهجاً أفضل))ع(
كما أنه يستخدم أيضاً TaskCompletionSource
(ب) تتبع حالة مهمة الترجمة.
داخل خدمة المعالجة (التي سنغطيها لاحقاً مرة أخرى) TaskCompletionSource
(بآلاف دولارات الولايات المتحدة)
var translatedMarkdown =
await markdownTranslatorService.TranslateMarkdown(translateModel.OriginalMarkdown,
translateModel.Language, cancellationToken);
tcs.SetResult(new TaskCompletion(translatedMarkdown, translateModel.Language, true, DateTime.Now));
}
من خلال القيام بذلك يمكننا أن ننشر حالة مهام الترجمة التي قمنا بتخزينها في مخبأنا ونعطي المستخدم تغذية مرتدة عن حالة الترجمة. وهذا يمكن أن يستغرق عدة دقائق اعتماداً على حركة المرور وطول ملف العلامة.
لقد رأيتِ مسبقاً أننا وضعنا لكِ بسكويتة متصفح هذا مُستخدَم إلى تعرّف و. بعد تقديم الترجمة سنستخدم إقتراع HTMX لضرب هذا الإجراء الذي ببساطة يعيد الترجمات لك.
[HttpGet]
[Route("get-translations")]
public IActionResult GetTranslations()
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translations = tasks;
return PartialView("_GetTranslations", translations);
}
متى a قائمة من و استخدام إلى تحديد a ترجمة و الإيطالية بوصة محرّر. هذا استخدام API نقطة نهاية إلى get مهمة;
[HttpGet]
[Route("get-translation/{taskId}")]
public Results<JsonHttpResult<TaskCompletion>, BadRequest<string>> GetTranslation(string taskId)
{
var userId = Request.GetUserId(Response);
var tasks = translateCacheService.GetTasks(userId);
var translationTask = tasks.FirstOrDefault(t => t.TaskId == taskId);
if(translationTask?.Task?.Status != System.Threading.Tasks.TaskStatus.RanToCompletion)
{
return TypedResults.BadRequest<string>("Task not completed");
}
return TypedResults.Json(translationTask.Task.Result);
}
ما زال الوقت مبكراً وأنا أبني هذا لكن أنا متحمس لرؤية أين يذهب. أنا سَأَغطّي خدمةَ الخلفيةَ بالتفصيل في الجزءِ القادمِ.