An Interest In:
Web News this Week
- March 28, 2024
- March 27, 2024
- March 26, 2024
- March 25, 2024
- March 24, 2024
- March 23, 2024
- March 22, 2024
Creating a custom json resource reader
In this post, we're going to create a custom Resource reader to use with dotnet core libraries. In the end, we can have a project dedicated to resources.
First, we need a class that represents our json
file:
using System.Collections.Generic;namespace I18N{ internal class JsonLocalization { public string Key { get; set; } public Dictionary<string, string> LocalizedValues { get; set; } }}
The Key
is an unique identifier for the localization and LocalizedValues
is a dictionary, which its key is the language and the value the text that must be displayed.
We also going to create a new type of Exception
, to easily pinpoint what went wrong with the application.
using System;namespace I18N{ public class I18NException : Exception { public I18NException(string message) : base(message) { } public I18NException(string message, Exception innerException) : base(message, innerException) { } public I18NException() { } }}
Here is where the magic happens, the JsonLocalizer
class will read our json resources files
, store them in memory and make them available to our application.
In our constructor we expect two parameters, useBase
and additionalPaths
.
If useBase
is set to true, the localizer will load *.json
files that are in the Resources
folder.additionalPaths
uses a type as a key, the localizer will use this type to find the assembly path and read the *.json
files in the Resources
folder.
using System;using System.Collections.Generic;using System.Globalization;using System.IO;using System.Linq;using Newtonsoft.Json;namespace I18N{ public class JsonLocalizer { private readonly Dictionary<string, JsonLocalization[]> _localization = new Dictionary<string, JsonLocalization[]>(); public JsonLocalizer(bool useBase = true, Dictionary<Type, string> additionalPaths = null) { if (useBase) PopulateLocalization("Resources"); if (additionalPaths == null) return; foreach (var additional in additionalPaths) { var codeBase = additional.Key.Assembly.CodeBase; var uri = new UriBuilder(codeBase); var data = Uri.UnescapeDataString(uri.Path); var path = Path.GetDirectoryName(data); var fullPath = Path.Combine(path, additional.Value); PopulateLocalization(fullPath); } } /// <summary> /// resource:key:culture /// resource is the resource name /// key is the key you're looking for /// culture is optional /// </summary> /// <param name="key"></param> public string this[string key] => GetString(key); private void PopulateLocalization(string path) { foreach (var resource in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) { try { var fileInfo = new FileInfo(resource); var fileName = fileInfo.Name.Substring(0, fileInfo.Name.IndexOf('.')); var loc = JsonConvert.DeserializeObject<JsonLocalization[]>(File.ReadAllText(resource)); _localization.Add(fileName, loc); } catch (ArgumentException e) { throw new I18NException($"Resource {resource} was already added, check your files.", e); } catch (Exception ex) { throw new I18NException("Something wrong is not right, check inner exception", ex); } } } private string GetString(string query) { try { string culture = null; var split = query.Split(':'); var resource = split[0]; var key = split[1]; if (split.Length > 2) culture = split[2]; culture = culture ?? CultureInfo.CurrentCulture.Name; return _localization .Single(l => l.Key == resource) .Value.Single(x => x.Key == key) .LocalizedValues[culture]; } catch (Exception ex) { throw new I18NException($"Couldn't find key: {query}", ex); } } }}
In dotnet core
applications, you can add the JsonLocalizer
using the IServiceCollection
in the ConfigureServices
method.
// use it in DI as a singletonpublic void ConfigureServices(IServiceCollection services){ // Other configurations ... services.AddSingleton<JsonLocalizer>();}
To handle additionalPaths
var additional = new Dictionary<Type, string> { { typeof(MyClass), "My Resource Folder" }, { typeof(MyAnotherClass), "My Resource Folder/Even Handles sub folders" } };var withExternalSources = new JsonLocalizer(additionalPaths: additional);
Now that we have everything set up, we can start using our localizer:
private readonly JsonLocalizer _localizer;public class MySampleClass(JsonLocalizer localizer){ _localizer = localizer;}public string GetLocalizedMessage(){ return _localizer["MyAppResource:MyKey"];}
The Localizer will find your text by:
FileName:Key:Language
Here are some examples of how to write your resource files:
File Name | Resource Name |
---|---|
MyResource.json | MyResource |
MyApp.Resource.json | MyApp |
MyApp-Errors.Resource.json | MyApp-Errors |
MyApp.Errors.Resource.json | MyApp |
The Key
is the key inside the resource file, and the Language
is the culture, if not informed, will use the CultureInfo.CurrentCulture
value.
The json
resource file should follow this format:
[ { "Key":"Name", "LocalizedValues":{ "en-US":"Name", "pt-BR":"Nome" } }, { "Key":"Age", "LocalizedValues":{ "en-US":"Age", "pt-BR":"Idade" } }]
Original Link: https://dev.to/eduardojuliao/creating-a-custom-text-resources-with-csharp-466p
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To