// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
// Boston, MA 02110-1301, USA.
+#nullable enable
+
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
+using System.Xml.XPath;
using OpenTween.Connection;
namespace OpenTween.Api
public class MicrosoftTranslatorApi
{
public static readonly Uri IssueTokenEndpoint = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");
- public static readonly Uri TranslateEndpoint = new Uri("https://api.microsofttranslator.com/v2/Http.svc/Translate");
+ public static readonly Uri TranslateEndpoint = new Uri("https://api.cognitive.microsofttranslator.com/translate");
- public string AccessToken { get; internal set; }
- public DateTime RefreshAccessTokenAt { get; internal set; }
+ public string AccessToken { get; internal set; } = "";
+ public DateTimeUtc RefreshAccessTokenAt { get; internal set; } = DateTimeUtc.MinValue;
private HttpClient Http => this.localHttpClient ?? Networking.Http;
- private readonly HttpClient localHttpClient;
+ private readonly HttpClient? localHttpClient;
public MicrosoftTranslatorApi()
: this(null)
{
}
- public MicrosoftTranslatorApi(HttpClient http)
- {
- this.localHttpClient = http;
- }
+ public MicrosoftTranslatorApi(HttpClient? http)
+ => this.localHttpClient = http;
- public async Task<string> TranslateAsync(string text, string langTo, string langFrom = null)
+ public async Task<string> TranslateAsync(string text, string langTo, string? langFrom = null)
{
await this.UpdateAccessTokenIfExpired()
.ConfigureAwait(false);
var param = new Dictionary<string, string>
{
- ["text"] = text,
+ ["api-version"] = "3.0",
["to"] = langTo,
};
var requestUri = new Uri(TranslateEndpoint, "?" + MyCommon.BuildQueryString(param));
- using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
- {
- request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.AccessToken);
-
- using (var response = await this.Http.SendAsync(request).ConfigureAwait(false))
- {
- return await response.Content.ReadAsStringAsync()
- .ConfigureAwait(false);
- }
- }
+ using var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
+ request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", this.AccessToken);
+
+ var escapedText = JsonUtils.EscapeJsonString(text);
+ var json = $@"[{{""Text"": ""{escapedText}""}}]";
+
+ using var body = new StringContent(json, Encoding.UTF8, "application/json");
+ request.Content = body;
+
+ using var response = await this.Http.SendAsync(request)
+ .ConfigureAwait(false);
+
+ response.EnsureSuccessStatusCode();
+
+ var responseJson = await response.Content.ReadAsByteArrayAsync()
+ .ConfigureAwait(false);
+
+ using var jsonReader = JsonReaderWriterFactory.CreateJsonReader(responseJson, XmlDictionaryReaderQuotas.Max);
+ var xElm = XElement.Load(jsonReader);
+ var transtlationTextElm = xElm.XPathSelectElement("/item/translations/item/text[1]");
+
+ return transtlationTextElm?.Value ?? "";
}
public async Task UpdateAccessTokenIfExpired()
{
- if (this.AccessToken != null && this.RefreshAccessTokenAt > DateTime.Now)
+ if (!MyCommon.IsNullOrEmpty(this.AccessToken) && this.RefreshAccessTokenAt > DateTimeUtc.Now)
return;
var (accessToken, expiresIn) = await this.GetAccessTokenAsync()
this.AccessToken = accessToken;
// アクセストークンの実際の有効期限より 30 秒早めに失効として扱う
- this.RefreshAccessTokenAt = DateTime.Now + expiresIn - TimeSpan.FromSeconds(30);
+ this.RefreshAccessTokenAt = DateTimeUtc.Now + expiresIn - TimeSpan.FromSeconds(30);
}
internal virtual async Task<(string AccessToken, TimeSpan ExpiresIn)> GetAccessTokenAsync()
{
- using (var request = new HttpRequestMessage(HttpMethod.Post, IssueTokenEndpoint))
- {
- request.Headers.Add("Ocp-Apim-Subscription-Key", ApplicationSettings.TranslatorSubscriptionKey);
+ using var request = new HttpRequestMessage(HttpMethod.Post, IssueTokenEndpoint);
+ request.Headers.Add("Ocp-Apim-Subscription-Key", ApplicationSettings.TranslatorSubscriptionKey);
- using (var response = await this.Http.SendAsync(request).ConfigureAwait(false))
- {
- var accessToken = await response.Content.ReadAsStringAsync()
- .ConfigureAwait(false);
+ using var response = await this.Http.SendAsync(request)
+ .ConfigureAwait(false);
+
+ response.EnsureSuccessStatusCode();
+
+ var accessToken = await response.Content.ReadAsStringAsync()
+ .ConfigureAwait(false);
- return (accessToken, TimeSpan.FromMinutes(10));
- }
- }
+ return (accessToken, TimeSpan.FromMinutes(10));
}
}
}