Создание средства чтения ресурсов json для ядра dotnet
В этом посте мы собираемся создать пользовательское средство чтения ресурсов для использования с основными библиотеками dotnet. В конце концов, у нас может быть проект, посвященный ресурсам.
Во-первых, нам нужен класс, представляющий наш json
файл:
using System.Collections.Generic;
namespace I18N
{
internal class JsonLocalization
{
public string Key { get; set; }
public Dictionary<string, string> LocalizedValues { get; set; }
}
}
Является Key
уникальным идентификатором локализации и LocalizedValues
представляет собой словарь, ключом которого является язык, а значением — текст, который необходимо отобразить.
Мы также собираемся создать новый тип Exception
, чтобы легко определить, что пошло не так с приложением.
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()
{
}
}
}
Вот где происходит волшебство, JsonLocalizer
класс будет читать наши файлы json resources files
, сохранять их в памяти и делать их доступными для нашего приложения.
В нашем конструкторе мы ожидаем два параметра useBase
и additionalPaths
.
Если useBase
установлено значение true, локализатор будет загружать *.json
файлы, находящиеся в Resources
папке.additionalPaths
использует тип в качестве ключа, локализатор будет использовать этот тип для поиска пути сборки и чтения *.json
файлов в Resources
папке.
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);
}
}
}
}
В dotnet core
приложениях вы можете добавить JsonLocalizer
использование метода IServiceCollection
in ConfigureServices
.
// use it in DI as a singleton
public void ConfigureServices(IServiceCollection services)
{
// Other configurations ...
services.AddSingleton<JsonLocalizer>();
}
Обрабатывать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);
Теперь, когда у нас все настроено, мы можем начать использовать наш локализатор:
private readonly JsonLocalizer _localizer;
public class MySampleClass(JsonLocalizer localizer)
{
_localizer = localizer;
}
public string GetLocalizedMessage()
{
return _localizer["MyAppResource:MyKey"];
}
Локализатор найдет ваш текст по:
FileName:Key:Language
Вот несколько примеров того, как писать файлы ресурсов:
Имя файла | Имя ресурса |
---|---|
MyResource.json | Мой ресурс |
MyApp.Resource.json | Мое приложение |
MyApp-Errors.Resource.json | MyApp-ошибки |
MyApp.Errors.Resource.json | Мое приложение |
Это Key
ключ внутри файла ресурсов, а Language
культура, если она не проинформирована, будет использовать это CultureInfo.CurrentCulture
значение.
Файл json
ресурсов должен иметь следующий формат:
[
{
"Key":"Name",
"LocalizedValues":{
"en-US":"Name",
"pt-BR":"Nome"
}
},
{
"Key":"Age",
"LocalizedValues":{
"en-US":"Age",
"pt-BR":"Idade"
}
}
]
Только полноправные пользователи могут оставлять комментарии. Аутентифицируйтесь пожалуйста, используя сервисы.