-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTranslationService.cs
More file actions
150 lines (127 loc) · 5.97 KB
/
Copy pathTranslationService.cs
File metadata and controls
150 lines (127 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace TapLingo
{
public class TranslationResult
{
public string TranslatedText { get; set; } = "";
public string DetectedSourceLanguage { get; set; } = "";
public string Engine { get; set; } = "";
}
public static class TranslationService
{
// HttpClient יחיד לאורך חיי האפליקציה (best practice)
private static readonly HttpClient _httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(15)
};
public static async Task<TranslationResult> TranslateAsync(string text, AppSettings settings)
{
if (string.IsNullOrWhiteSpace(text))
throw new ArgumentException("אין טקסט לתרגום");
return settings.Engine switch
{
TranslationEngine.DeepL => await TranslateWithDeepLAsync(text, settings),
_ => await TranslateWithGoogleAsync(text, settings),
};
}
/// <summary>
/// תרגום באמצעות Google Translate API הציבורי (ללא מפתח)
/// משתמש ב-endpoint של gtx שמשמש את Google Translate web
/// </summary>
private static async Task<TranslationResult> TranslateWithGoogleAsync(string text, AppSettings settings)
{
var source = string.IsNullOrWhiteSpace(settings.SourceLanguage) ? "auto" : settings.SourceLanguage;
var target = settings.TargetLanguage;
var encoded = Uri.EscapeDataString(text);
var url = $"https://translate.googleapis.com/translate_a/single?client=gtx" +
$"&sl={source}&tl={target}&dt=t&q={encoded}";
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
// התשובה היא מערך JSON עם מבנה מקונן:
// [[[translated, original, ...], ...], null, detectedLang, ...]
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
var sb = new StringBuilder();
if (root.ValueKind == JsonValueKind.Array && root.GetArrayLength() > 0)
{
var sentences = root[0];
if (sentences.ValueKind == JsonValueKind.Array)
{
foreach (var sentence in sentences.EnumerateArray())
{
if (sentence.ValueKind == JsonValueKind.Array && sentence.GetArrayLength() > 0)
{
var translated = sentence[0].GetString();
if (!string.IsNullOrEmpty(translated))
sb.Append(translated);
}
}
}
}
string detectedLang = "";
if (root.GetArrayLength() > 2 && root[2].ValueKind == JsonValueKind.String)
{
detectedLang = root[2].GetString() ?? "";
}
return new TranslationResult
{
TranslatedText = sb.ToString(),
DetectedSourceLanguage = detectedLang,
Engine = "Google Translate"
};
}
/// <summary>
/// תרגום באמצעות DeepL API
/// </summary>
private static async Task<TranslationResult> TranslateWithDeepLAsync(string text, AppSettings settings)
{
if (string.IsNullOrWhiteSpace(settings.DeepLApiKey))
throw new InvalidOperationException("נדרש מפתח API של DeepL. הגדר אותו בקובץ ההגדרות.");
var baseUrl = settings.DeepLUseFreeTier
? "https://api-free.deepl.com/v2/translate"
: "https://api.deepl.com/v2/translate";
// DeepL דורש קודי שפה באותיות גדולות (EN, DE, HE וכו')
var target = settings.TargetLanguage.ToUpperInvariant();
var formData = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>
{
new("text", text),
new("target_lang", target)
};
if (!string.IsNullOrWhiteSpace(settings.SourceLanguage) &&
!settings.SourceLanguage.Equals("auto", StringComparison.OrdinalIgnoreCase))
{
formData.Add(new("source_lang", settings.SourceLanguage.ToUpperInvariant()));
}
using var content = new FormUrlEncodedContent(formData);
using var request = new HttpRequestMessage(HttpMethod.Post, baseUrl) { Content = content };
request.Headers.Add("Authorization", $"DeepL-Auth-Key {settings.DeepLApiKey}");
var response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var err = await response.Content.ReadAsStringAsync();
throw new HttpRequestException($"DeepL החזיר שגיאה ({(int)response.StatusCode}): {err}");
}
var json = await response.Content.ReadAsStringAsync();
using var doc = JsonDocument.Parse(json);
var translations = doc.RootElement.GetProperty("translations");
if (translations.GetArrayLength() == 0)
throw new Exception("DeepL לא החזיר תרגום");
var first = translations[0];
var translated = first.GetProperty("text").GetString() ?? "";
var detected = first.TryGetProperty("detected_source_language", out var ds)
? ds.GetString() ?? ""
: "";
return new TranslationResult
{
TranslatedText = translated,
DetectedSourceLanguage = detected,
Engine = "DeepL"
};
}
}
}