Reputation: 183
I'm currently working with a project where you store a list of products in the database. Every product has a name, description... Now I want to translate the productname, description...
My current solution is to use a translation table, where I can add all the translated db entries like:
product.Title= result.GetLocalized(x => x.Title, language, _localizedPropertyRepository);
and the extenstion method:
public static string GetLocalized<T>(this T entity,
Expression<Func<T, string>> keySelector, LanguageDTO language, ILocalizedPropertyRepository localizedPropertyRepository)
where T : Mapping, ILocalizedEntity
{
...
resultStr = localizedPropertyRepository.GetLocalizedValue(language, entity.Id, localeKeyGroup, localeKey);
...
}
You can also see a similar example of it here: https://github.com/nopSolutions/nopCommerce/blob/develop/src/Libraries/Nop.Services/Localization/LocalizationExtensions.cs
My problem is, I'm not really happy with it. To work with an static class so I have access to the Context or send the whole injected object in the extension method doesn't look like a good practice. Are there other ways to solve this problem?
Also I work with AutoMapper where I map the whole Entity to a DTO. I think the current solution can't work with AutoMapper. I have to make something like:
CreateMap<Product, ProductDTO>()
.ForMember(x => x.Title, opt => opt.???GetLocalized(????));
But I need the entity in GetLocalized and not only the Property. Also I don't have access to the _localizedPropertyRepository or the language of the customer.
Upvotes: 1
Views: 797
Reputation: 183
Well it took me over a day, but I got a working solution. So if someone else is stuck with the same problem, here is my solution. I hope it helps:
public class Mapping
{
[DataMember]
public long Id { get; set; }
}
[DataContract]
public class ProductDTO: Mapping
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string ShortDescription{ get; set; }
}
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Product, ProductDTO>()
.ForMember(t => t.Name, opt => opt.ResolveUsing<LocalizationResolver, EntityInfo>(src => new EntityInfo()
{
LocaleKeyGroup = "Product",
LocaleKey = "Name",
DefaultValue = src.Name
}))
.ForMember(t => t.ShortDescription, opt => opt.ResolveUsing<LocalizationResolver, EntityInfo> (src => new EntityInfo()
{
LocaleKeyGroup = "Product",
LocaleKey = "ShortDescription",
DefaultValue = src.ShortDescription
}));
}
}
public class EntityInfo
{
public string LocaleKeyGroup { get; set; }
public string LocaleKey { get; set; }
public string DefaultValue { get; set; }
}
public class LocalizationResolver : IMemberValueResolver<Mapping, object, EntityInfo, string>
{
public string Resolve(Mapping source, object destination, EntityInfo sourceMember, string destMember,
ResolutionContext context)
{
context.Items.TryGetValue("Language", out object languageObject);
context.Items.TryGetValue("Repository", out object repositoryObject);
ILocalizedPropertyRepository repository = repositoryObject as ILocalizedPropertyRepository;
LanguageDTO language = languageObject as LanguageDTO;
if (language == null || repository == null)
{
throw new ArgumentNullException($"Language and LocalizationRepository as AutoMapper Parameter");
}
if(source.Id == 0)
{
return sourceMember.DefaultValue;
}
//Get the value from the DB
return LocalizationExtension.GetLocalized(sourceMember.LocaleKey, sourceMember.LocaleKeyGroup, sourceMember.DefaultValue, source.Id, language, repository);
}
}
public static class LocalizationExtension
{
public static string GetLocalized(string localeKey, string localeKeyGroup, string defaultValue, long entityId, LanguageDTO language, ILocalizedPropertyRepository localizedPropertyRepository)
{
var resultStr = String.Empty;
if (language != null)
{
resultStr = localizedPropertyRepository.GetLocalizedValue(language, entityId, localeKeyGroup, localeKey);
}
if (string.IsNullOrEmpty(resultStr))
{
resultStr = defaultValue;
}
return resultStr;
}
public static void Localice(IMappingOperationOptions<object, object> opt, LanguageDTO language, ILocalizedPropertyRepository localizedPropertyRepository)
{
opt.Items["Language"] = language;
opt.Items["Repository"] = localizedPropertyRepository;
}
}
There is still stuff to optimize. The method names aren't perfect. The creation of the EntityInfo is ugly. And I still have the use the whole repository object as a parameter because of the dependency injection. Also, it tries to get a localized value everytime, which is necessary in the "default" language and slows the whole stuff down a bit.
Upvotes: 1