Skip to content

Commit

Permalink
Merge branch 'feature/replace-jsonconverter' of github.com:stefanolse…
Browse files Browse the repository at this point in the history
…n/LocalizationProvider into stefanolsen-feature/replace-jsonconverter
  • Loading branch information
valdisiljuconoks committed Dec 5, 2024
2 parents 7fce628 + a6d1e07 commit 6468c50
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 25 deletions.
29 changes: 4 additions & 25 deletions common/src/DbLocalizationProvider/LocalizationProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
using System.Text.RegularExpressions;
using DbLocalizationProvider.Abstractions;
using DbLocalizationProvider.Internal;
using DbLocalizationProvider.Json;
using DbLocalizationProvider.Queries;
using DbLocalizationProvider.Sync;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using JsonConverter = DbLocalizationProvider.Json.JsonConverter;

namespace DbLocalizationProvider;

Expand All @@ -28,8 +25,7 @@ public class LocalizationProvider : ILocalizationProvider
private readonly ResourceKeyBuilder _keyBuilder;
internal readonly IQueryExecutor _queryExecutor;
private readonly ScanState _scanState;
private readonly JsonConverter _converter;
private readonly JsonSerializer _serializer;
private readonly ReflectionConverter _reflectionConverter;

/// <summary>
/// Creates new localization provider with all the required settings and services injected.
Expand All @@ -54,12 +50,8 @@ public LocalizationProvider(
_fallbackCollection = context.Value._fallbackCollection;
_queryExecutor = queryExecutor;
_scanState = scanState;

_converter = new JsonConverter(_queryExecutor, _scanState);
_serializer = new JsonSerializer
{
ContractResolver = new StaticPropertyContractResolver()
};

_reflectionConverter = new ReflectionConverter(_queryExecutor, _scanState);
}

/// <summary>
Expand Down Expand Up @@ -228,20 +220,7 @@ public T Translate<T>()
/// <returns>Translated class</returns>
public T Translate<T>(CultureInfo language)
{
var className = typeof(T).FullName;

var json = _converter.GetJson(className, language.Name, _fallbackCollection);

// get the actual class Json representation (we need to select token through FQN of the class)
// to supported nested classes - we need to fix a bit resource key name
var jsonToken = json.SelectToken(className.Replace('+', '.'));

if (jsonToken == null)
{
return (T)Activator.CreateInstance(typeof(T), new object[] { });
}

return jsonToken.ToObject<T>(_serializer);
return _reflectionConverter.Convert<T>(language.Name, _fallbackCollection);
}

/// <summary>
Expand Down
88 changes: 88 additions & 0 deletions common/src/DbLocalizationProvider/ReflectionConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using DbLocalizationProvider.Abstractions;
using DbLocalizationProvider.Queries;
using DbLocalizationProvider.Sync;

namespace DbLocalizationProvider;

public class ReflectionConverter
{
private readonly IQueryExecutor _queryExecutor;
private readonly ScanState _scanState;

public ReflectionConverter(IQueryExecutor queryExecutor, ScanState scanState)
{
_queryExecutor = queryExecutor;
_scanState = scanState;
}

public T Convert<T>(string languageName, FallbackLanguagesCollection fallbackCollection)
{
// TODO: Can the dictionary be cached?
// TODO: Can we go around query execution and use repository directly?
var resources = _queryExecutor
.Execute(new GetAllResources.Query())
.ToDictionary(x => x.ResourceKey, StringComparer.Ordinal);

var newObject = Activator.CreateInstance<T>();

FillProperties(newObject!, languageName, resources, fallbackCollection);

return newObject;
}

private void FillProperties(object instance, string languageName, Dictionary<string, LocalizationResource> resources, FallbackLanguagesCollection fallbackCollection)
{
var type = instance!.GetType();
var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static);
foreach (var propertyInfo in properties)
{
if (propertyInfo.MemberType == MemberTypes.NestedType)
{
var nestedObject = Activator.CreateInstance(propertyInfo.PropertyType);
if (nestedObject == null)
{
continue;
}

FillProperties(nestedObject, languageName, resources, fallbackCollection);

propertyInfo.SetValue(instance, nestedObject);
}

if (propertyInfo.PropertyType != typeof(string))
{
continue;
}

string? translation;
string key = $"{type.FullName}.{propertyInfo.Name}";
if (_scanState.UseResourceAttributeCache.TryGetValue(key, out var targetResourceKey))
{
if (resources.TryGetValue(targetResourceKey, out var foundResource))
{
translation = foundResource.Translations.GetValueWithFallback(
languageName,
fallbackCollection.GetFallbackLanguages(languageName));

propertyInfo.SetValue(instance, translation);
continue;
}
}

if (!resources.TryGetValue(key, out var resource))
{
continue;
}

translation = resource.Translations.GetValueWithFallback(
languageName,
fallbackCollection.GetFallbackLanguages(languageName));

propertyInfo.SetValue(instance, translation);
}
}
}

0 comments on commit 6468c50

Please sign in to comment.