diff --git a/CMP.Localiztion.Traduora.sln b/CMP.Localiztion.Traduora.sln index b246d0f..0429f53 100644 --- a/CMP.Localiztion.Traduora.sln +++ b/CMP.Localiztion.Traduora.sln @@ -5,10 +5,12 @@ VisualStudioVersion = 15.0.28307.329 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Web", "sample\Web\Web.csproj", "{17E01B10-44A9-4896-96C4-F6D948DEC5F9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CachedLocalizer", "src\Core\CachedLocalizer.csproj", "{79B4E158-DADA-4A56-A3BC-E0CCD012FA10}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamicDictionaryLocalizer", "src\Core\DynamicDictionaryLocalizer.csproj", "{79B4E158-DADA-4A56-A3BC-E0CCD012FA10}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Traduora.Provider", "src\Traduora\Traduora.Provider.csproj", "{A007D934-6807-49F7-B31F-34B9C6AFC5C9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Traduora.Localizer", "Traduora.Localizer\Traduora.Localizer.csproj", "{CD719FDF-97E1-48E1-9600-A1FD58DBCD97}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {A007D934-6807-49F7-B31F-34B9C6AFC5C9}.Debug|Any CPU.Build.0 = Debug|Any CPU {A007D934-6807-49F7-B31F-34B9C6AFC5C9}.Release|Any CPU.ActiveCfg = Release|Any CPU {A007D934-6807-49F7-B31F-34B9C6AFC5C9}.Release|Any CPU.Build.0 = Release|Any CPU + {CD719FDF-97E1-48E1-9600-A1FD58DBCD97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CD719FDF-97E1-48E1-9600-A1FD58DBCD97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CD719FDF-97E1-48E1-9600-A1FD58DBCD97}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CD719FDF-97E1-48E1-9600-A1FD58DBCD97}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Traduora.Localizer/Cache/TranslationPollingService.cs b/Traduora.Localizer/Cache/TranslationPollingService.cs new file mode 100644 index 0000000..c0b9752 --- /dev/null +++ b/Traduora.Localizer/Cache/TranslationPollingService.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Hosting; + +namespace Traduora.Localizer.Cache +{ + public class TranslationPollingService : BackgroundService + { + private readonly Func>>> _asyncDataProvider; + private readonly TimeSpan _refreshInterval; + + public TranslationPollingService( + Func>>> asyncDataProvider, + TimeSpan refreshInterval) + { + _asyncDataProvider = asyncDataProvider; + _refreshInterval = refreshInterval; + + Data = _asyncDataProvider().Result; + } + + public IReadOnlyDictionary> Data { get; set; } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + Data = await _asyncDataProvider(); + await Task.Delay(_refreshInterval, stoppingToken); + } + } + } +} diff --git a/sample/Web/Config/ConfigurationService.cs b/Traduora.Localizer/Config/ConfigurationService.cs similarity index 93% rename from sample/Web/Config/ConfigurationService.cs rename to Traduora.Localizer/Config/ConfigurationService.cs index 4ab14ba..8f194b2 100644 --- a/sample/Web/Config/ConfigurationService.cs +++ b/Traduora.Localizer/Config/ConfigurationService.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -namespace Web.Config +namespace Traduora.Localizer.Config { public static class ConfigurationService { diff --git a/sample/Web/Config/TraduoraApiSettings.cs b/Traduora.Localizer/Config/TraduoraApiSettings.cs similarity index 87% rename from sample/Web/Config/TraduoraApiSettings.cs rename to Traduora.Localizer/Config/TraduoraApiSettings.cs index a87f86c..3571f4d 100644 --- a/sample/Web/Config/TraduoraApiSettings.cs +++ b/Traduora.Localizer/Config/TraduoraApiSettings.cs @@ -1,6 +1,6 @@ using System; -namespace Web.Config +namespace Traduora.Localizer.Config { public class TraduoraApiSettings { diff --git a/sample/Web/Config/TraduoraSecretSettings.cs b/Traduora.Localizer/Config/TraduoraSecretSettings.cs similarity index 83% rename from sample/Web/Config/TraduoraSecretSettings.cs rename to Traduora.Localizer/Config/TraduoraSecretSettings.cs index c46e3bf..b078aed 100644 --- a/sample/Web/Config/TraduoraSecretSettings.cs +++ b/Traduora.Localizer/Config/TraduoraSecretSettings.cs @@ -1,4 +1,4 @@ -namespace Web.Config +namespace Traduora.Localizer.Config { public class TraduoraSecretSettings { diff --git a/sample/Web/ServiceExtensions.cs b/Traduora.Localizer/ServiceExtensions.cs similarity index 50% rename from sample/Web/ServiceExtensions.cs rename to Traduora.Localizer/ServiceExtensions.cs index da2b7f9..de5cfed 100644 --- a/sample/Web/ServiceExtensions.cs +++ b/Traduora.Localizer/ServiceExtensions.cs @@ -1,24 +1,28 @@ using System.Net.Http; -using CachedLocalizer; -using CachedLocalizer.Cache; +using DynamicDictionaryLocalizer; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Options; +using Traduora.Localizer.Cache; +using Traduora.Localizer.Config; using Traduora.Provider; -using Web.Config; -namespace Web +namespace Traduora.Localizer { public static class ServiceExtensions { private const string HttpClientName = "traduora"; - public static IServiceCollection AddTraduora(this IServiceCollection services) + public static IServiceCollection AddTraduora(this IServiceCollection services, IConfiguration config) { + services.AddTypedConfiguration(config); + services .AddHttpClient(HttpClientName) .ConfigureHttpClient((sp, client) => { - var traduoraApiSettings = sp.GetRequiredService>().Value; + TraduoraApiSettings traduoraApiSettings = sp.GetRequiredService>().Value; client.BaseAddress = traduoraApiSettings.BaseUrl; }); @@ -30,18 +34,21 @@ public static IServiceCollection AddTraduora(this IServiceCollection services) return new TraduoraProvider(httpClient); }); - services.AddTransient(); + services.AddTransient(); - services.AddSingleton(sp => + services.AddSingleton(sp => { - var traduoraApiSettings = sp.GetRequiredService>().Value; + TraduoraApiSettings traduoraApiSettings = + sp.GetRequiredService>().Value; - var cache = new DictionaryPollingCache( - sp.GetRequiredService().GetTranslations, + return new TranslationPollingService( + sp.GetRequiredService().GetTranslations, traduoraApiSettings.RefreshIntervalSeconds); - - return new CachedDictionaryStringLocalizer(cache.GetData); }); + services.AddSingleton(sp => sp.GetRequiredService()); + + services.AddSingleton(sp => + new DynamicDictionaryStringLocalizer(() => sp.GetRequiredService().Data)); return services; } diff --git a/Traduora.Localizer/Traduora.Localizer.csproj b/Traduora.Localizer/Traduora.Localizer.csproj new file mode 100644 index 0000000..645d88d --- /dev/null +++ b/Traduora.Localizer/Traduora.Localizer.csproj @@ -0,0 +1,34 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.configuration.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll + + + ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.dependencyinjection.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll + + + ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.hosting.abstractions\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll + + + ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.http\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Http.dll + + + ..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.extensions.options\2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll + + + + diff --git a/Traduora.Localizer/TraduoraService.cs b/Traduora.Localizer/TraduoraService.cs new file mode 100644 index 0000000..407b30c --- /dev/null +++ b/Traduora.Localizer/TraduoraService.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Traduora.Localizer.Config; +using Traduora.Provider; + +namespace Traduora.Localizer +{ + public class TraduoraService + { + private readonly TraduoraSecretSettings _config; + private readonly TraduoraProvider _traduora; + + public TraduoraService(IOptions config, TraduoraProvider traduora) + { + _config = config.Value; + _traduora = traduora; + } + + public async Task>> GetTranslations() + { + try + { + string key = await _traduora.Authenticate(_config.ClientId, _config.ClientSecret); + + return await _traduora.GetData(_config.ProjectId, key); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + + var emptyDictionary = new ReadOnlyDictionary> + (new Dictionary>()); + + return emptyDictionary; + } + } + } +} diff --git a/sample/Web/Logging/HttpLoggingHandler.cs b/sample/Web/Logging/HttpLoggingHandler.cs deleted file mode 100644 index ca1bb2e..0000000 --- a/sample/Web/Logging/HttpLoggingHandler.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Threading; -using System.Threading.Tasks; - -namespace Web.Logging -{ - /// - /// To be used for debugging API calls - /// - public class HttpLoggingHandler : DelegatingHandler - { - public HttpLoggingHandler(HttpMessageHandler innerHandler = null) - : base(innerHandler ?? new HttpClientHandler()) - { - } - - protected override async Task SendAsync(HttpRequestMessage request, - CancellationToken cancellationToken) - { - var req = request; - var id = Guid.NewGuid().ToString(); - var msg = $"[{id} - Request]"; - - Debug.WriteLine($"{msg}========Start=========="); - Debug.WriteLine($"{msg} {req.Method} {req.RequestUri.PathAndQuery} {req.RequestUri.Scheme}/{req.Version}"); - Debug.WriteLine($"{msg} Full Endpoint: {req.RequestUri.AbsoluteUri}"); - - foreach (var header in req.Headers) - Debug.WriteLine($"{msg} {header.Key}: {string.Join(", ", header.Value)}"); - - if (req.Content != null) - { - foreach (var header in req.Content.Headers) - Debug.WriteLine($"{msg} {header.Key}: {string.Join(", ", header.Value)}"); - - if (req.Content is StringContent || this.IsTextBasedContentType(req.Headers) || - this.IsTextBasedContentType(req.Content.Headers)) - { - var result = await req.Content.ReadAsStringAsync(); - - Debug.WriteLine($"{msg} Content:"); - Debug.WriteLine($"{msg} {string.Join("", result)}"); - } - } - - var start = DateTime.Now; - - var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); - - var end = DateTime.Now; - - Debug.WriteLine($"{msg} Duration: {end - start}"); - Debug.WriteLine($"{msg}==========End=========="); - - msg = $"[{id} - Response]"; - Debug.WriteLine($"{msg}=========Start========="); - - var resp = response; - - Debug.WriteLine( - $"{msg} {req.RequestUri.Scheme.ToUpper()}/{resp.Version} {(int) resp.StatusCode} {resp.ReasonPhrase}"); - - foreach (var header in resp.Headers) - Debug.WriteLine($"{msg} {header.Key}: {string.Join(", ", header.Value)}"); - - if (resp.Content != null) - { - foreach (var header in resp.Content.Headers) - Debug.WriteLine($"{msg} {header.Key}: {string.Join(", ", header.Value)}"); - - if (resp.Content is StringContent || this.IsTextBasedContentType(resp.Headers) || - this.IsTextBasedContentType(resp.Content.Headers)) - { - start = DateTime.Now; - var result = await resp.Content.ReadAsStringAsync(); - end = DateTime.Now; - - Debug.WriteLine($"{msg} Content:"); - Debug.WriteLine($"{msg} {string.Join("", result.Cast().Take(255))}..."); - Debug.WriteLine($"{msg} Duration: {end - start}"); - } - } - - Debug.WriteLine($"{msg}==========End=========="); - return response; - } - - readonly string[] types = new[] {"html", "text", "xml", "json", "txt", "x-www-form-urlencoded"}; - - bool IsTextBasedContentType(HttpHeaders headers) - { - IEnumerable values; - if (!headers.TryGetValues("Content-Type", out values)) - return false; - var header = string.Join(" ", values).ToLowerInvariant(); - - return types.Any(t => header.Contains(t)); - } - } -} \ No newline at end of file diff --git a/sample/Web/Startup.cs b/sample/Web/Startup.cs index 1853fa0..0dc6503 100644 --- a/sample/Web/Startup.cs +++ b/sample/Web/Startup.cs @@ -1,11 +1,10 @@ -using System; -using System.Globalization; +using System.Globalization; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Web.Config; +using Traduora.Localizer; namespace Web { @@ -23,13 +22,17 @@ public Startup(IConfiguration config) public void ConfigureServices(IServiceCollection services) { services.AddMvc(); - services.AddTypedConfiguration(_config); - services.AddTraduora(); + services.AddTraduora(_config); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + var supportedCultures = new[] { new CultureInfo("en"), @@ -38,11 +41,6 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) new CultureInfo("sv-SE"), }; - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture(supportedCultures[0]), diff --git a/sample/Web/TraduoraService.cs b/sample/Web/TraduoraService.cs deleted file mode 100644 index 157656e..0000000 --- a/sample/Web/TraduoraService.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.Extensions.Options; -using Traduora.Provider; -using Web.Config; - -namespace Web -{ - public class TraduoraService : ITraduoraService - { - private readonly TraduoraSecretSettings _config; - private readonly TraduoraProvider _traduora; - - public TraduoraService(IOptions config, TraduoraProvider traduora) - { - _config = config.Value; - _traduora = traduora; - } - - public async Task>> GetTranslations() - { - string key = await _traduora.Authenticate(_config.ClientId, _config.ClientSecret); - - return await _traduora.GetData(_config.ProjectId, key); - } - } - - public interface ITraduoraService - { - Task>> GetTranslations(); - } -} diff --git a/sample/Web/Web.csproj b/sample/Web/Web.csproj index 0ae5931..2e70113 100644 --- a/sample/Web/Web.csproj +++ b/sample/Web/Web.csproj @@ -10,13 +10,11 @@ - - - + diff --git a/src/Core/Cache/AsyncPollingCache.cs b/src/Core/Cache/AsyncPollingCache.cs deleted file mode 100644 index b679fde..0000000 --- a/src/Core/Cache/AsyncPollingCache.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace CachedLocalizer.Cache -{ - public class AsyncPollingCache - { - private readonly Func> _asyncDataProvider; - private readonly Timer _refreshTimer; - private T _data; - - public AsyncPollingCache(Func> asyncDataProvider, TimeSpan refreshInterval) - { - _asyncDataProvider = asyncDataProvider; - - _refreshTimer = new Timer(RefreshData, null, refreshInterval, refreshInterval); - } - - public T GetData() - { - if (_data != null) return _data; - - _data = _asyncDataProvider().Result; - return _data; - } - - private async void RefreshData(object _) - { - _data = await _asyncDataProvider(); - } - } -} diff --git a/src/Core/Cache/DictionaryPollingCache.cs b/src/Core/Cache/DictionaryPollingCache.cs deleted file mode 100644 index bcdeb48..0000000 --- a/src/Core/Cache/DictionaryPollingCache.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace CachedLocalizer.Cache -{ - public class DictionaryPollingCache : AsyncPollingCache>> - { - public DictionaryPollingCache( - Func>>> asyncDataProvider, TimeSpan refreshInterval) : - base(asyncDataProvider, refreshInterval) - { - } - } -} diff --git a/src/Core/CachedLocalizer.csproj b/src/Core/DynamicDictionaryLocalizer.csproj similarity index 68% rename from src/Core/CachedLocalizer.csproj rename to src/Core/DynamicDictionaryLocalizer.csproj index 01046db..e69f788 100644 --- a/src/Core/CachedLocalizer.csproj +++ b/src/Core/DynamicDictionaryLocalizer.csproj @@ -2,6 +2,8 @@ netstandard2.0 + DynamicDictionaryLocalizer + DynamicDictionaryLocalizer diff --git a/src/Core/CachedDictionaryStringLocalizer.cs b/src/Core/DynamicDictionaryStringLocalizer.cs similarity index 83% rename from src/Core/CachedDictionaryStringLocalizer.cs rename to src/Core/DynamicDictionaryStringLocalizer.cs index 284478a..47fb950 100644 --- a/src/Core/CachedDictionaryStringLocalizer.cs +++ b/src/Core/DynamicDictionaryStringLocalizer.cs @@ -4,21 +4,21 @@ using System.Linq; using Microsoft.Extensions.Localization; -namespace CachedLocalizer +namespace DynamicDictionaryLocalizer { - public class CachedDictionaryStringLocalizer : IStringLocalizer + public class DynamicDictionaryStringLocalizer : IStringLocalizer { private readonly Func>> _modelProvider; private readonly CultureInfo _culture; private CultureInfo Culture => _culture ?? CultureInfo.CurrentUICulture; - public CachedDictionaryStringLocalizer(Func>> modelProvider) + public DynamicDictionaryStringLocalizer(Func>> modelProvider) { _modelProvider = modelProvider; } - public CachedDictionaryStringLocalizer( + public DynamicDictionaryStringLocalizer( CultureInfo culture, Func>> modelProvider) : this(modelProvider) { @@ -64,7 +64,7 @@ public IEnumerable GetAllStrings(bool includeParentCultures) public IStringLocalizer WithCulture(CultureInfo culture) { - return new CachedDictionaryStringLocalizer(culture, _modelProvider); + return new DynamicDictionaryStringLocalizer(culture, _modelProvider); } } } \ No newline at end of file diff --git a/src/Traduora/Api/ApiCredentials.cs b/src/Traduora/Api/ApiCredentials.cs index 8a1b9a5..f6e2aa1 100644 --- a/src/Traduora/Api/ApiCredentials.cs +++ b/src/Traduora/Api/ApiCredentials.cs @@ -1,16 +1,9 @@ -using Newtonsoft.Json; - -namespace Traduora.Provider.Api +namespace Traduora.Provider.Api { internal class ApiCredentials { - [JsonProperty("clientId")] public string ClientId { get; set; } - - [JsonProperty("clientSecret")] public string ClientSecret { get; set; } - - [JsonProperty("grantType")] public string GrantType => "client_credentials"; } } \ No newline at end of file diff --git a/src/Traduora/Api/AuthResponse.cs b/src/Traduora/Api/AuthResponse.cs new file mode 100644 index 0000000..e9bf4e9 --- /dev/null +++ b/src/Traduora/Api/AuthResponse.cs @@ -0,0 +1,10 @@ +using Newtonsoft.Json.Linq; + +namespace Traduora.Provider.Api +{ + internal class AuthResponse + { + public JObject Data { get; set; } + public string AccessToken => Data["accessToken"].Value(); + } +} diff --git a/src/Traduora/Api/ITraduoraApi.cs b/src/Traduora/Api/ITraduoraApi.cs index afbbbf9..2c6c6eb 100644 --- a/src/Traduora/Api/ITraduoraApi.cs +++ b/src/Traduora/Api/ITraduoraApi.cs @@ -1,5 +1,5 @@ -using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; using Refit; namespace Traduora.Provider.Api @@ -7,13 +7,13 @@ namespace Traduora.Provider.Api internal interface ITraduoraApi { [Get("/projects/{projectId}/exports?format={format}&locale={locale}")] - Task GetExportedData(string projectId, string format, string locale, + Task> GetExportedData(string projectId, string format, string locale, [Header("Authorization")] string auth); [Get("/projects/{projectId}/translations")] - Task GetLocales(string projectId, [Header("Authorization")] string auth); + Task GetLocales(string projectId, [Header("Authorization")] string auth); [Post("/auth/token")] - Task GetToken([Body] ApiCredentials apiCredentials); + Task GetToken([Body] ApiCredentials apiCredentials); } } \ No newline at end of file diff --git a/src/Traduora/Api/LocalesResponse.cs b/src/Traduora/Api/LocalesResponse.cs new file mode 100644 index 0000000..4c165ed --- /dev/null +++ b/src/Traduora/Api/LocalesResponse.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; + +namespace Traduora.Provider.Api +{ + internal class LocalesResponse + { + public IEnumerable Data { get; set; } + } + + internal class LocaleWrapper + { + public Locale Locale { get; set; } + } + + internal class Locale + { + public string Code { get; set; } + public string Culture => Code.Replace('_', '-'); + } +} diff --git a/src/Traduora/TraduoraProvider.cs b/src/Traduora/TraduoraProvider.cs index e022f60..cc3c714 100644 --- a/src/Traduora/TraduoraProvider.cs +++ b/src/Traduora/TraduoraProvider.cs @@ -2,7 +2,8 @@ using System.Collections.ObjectModel; using System.Net.Http; using System.Threading.Tasks; -using Newtonsoft.Json.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; using Refit; using Traduora.Provider.Api; @@ -15,16 +16,23 @@ public class TraduoraProvider public TraduoraProvider(HttpClient httpClient) { - _traduoraApi = RestService.For(httpClient); + var refitSettings = new RefitSettings + { + ContentSerializer = new JsonContentSerializer( + new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver() + }) + }; + + _traduoraApi = RestService.For(httpClient, refitSettings); } public async Task Authenticate(string clientId, string clientSecret) { var authBody = new ApiCredentials { ClientId = clientId, ClientSecret = clientSecret }; - JToken responseJson = await _traduoraApi.GetToken(authBody); - - return responseJson["data"]["accessToken"].Value(); + return (await _traduoraApi.GetToken(authBody)).AccessToken; } public async Task>> @@ -33,15 +41,11 @@ public async Task>(); - JObject localesJson = await _traduoraApi.GetLocales(projectId, $"Bearer {authToken}"); + LocalesResponse localesJson = await _traduoraApi.GetLocales(projectId, $"Bearer {authToken}"); - foreach (JToken localeObject in localesJson["data"].Value()) + foreach (LocaleWrapper locale in localesJson.Data) { - string localeCode = localeObject["locale"]["code"].Value(); - - string culture = localeCode.Replace('_', '-'); - - output[culture] = await GetTranslations(projectId, localeCode, authToken, format); + output[locale.Locale.Culture] = await GetTranslations(projectId, locale.Locale.Code, authToken, format); } return new ReadOnlyDictionary>(output); @@ -51,20 +55,10 @@ private async Task> GetTranslations(string projectId, string locale, string authToken, string format = DefaultFormat) { - JObject exportedJson = await _traduoraApi.GetExportedData(projectId, format, locale, $"Bearer {authToken}"); - - return ToReadOnlyDictionary(exportedJson); - } - - private static IReadOnlyDictionary ToReadOnlyDictionary(JObject exportedJson) - { - var output = new Dictionary(); - foreach (JProperty jProperty in exportedJson.Properties()) - { - output[jProperty.Name] = jProperty.Value.Value(); - } + Dictionary exportedResult = + await _traduoraApi.GetExportedData(projectId, format, locale, $"Bearer {authToken}"); - return new ReadOnlyDictionary(output); + return new ReadOnlyDictionary(exportedResult); } } } \ No newline at end of file