Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 67 additions & 2 deletions src/My.Extensions.Localization.Json/Internal/JsonResourceLoader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;

namespace My.Extensions.Localization.Json.Internal;
Expand All @@ -23,9 +22,75 @@ public static IDictionary<string, string> Load(string filePath)

using var document = JsonDocument.Parse(reader.BaseStream, _jsonDocumentOptions);

resources = document.RootElement.EnumerateObject().ToDictionary(e => e.Name, e => e.Value.ToString());
var rootELement = document.RootElement.Clone();

JsonElementToDictionary(rootELement, resources);
}

return resources;
}

private static void JsonElementToDictionary(JsonElement element, Dictionary<string, string> result)
{
foreach (var item in element.EnumerateObject())
{
JsonElementToObject(item.Value, result, item.Name);
}
}

private static void JsonElementToObject(JsonElement element, Dictionary<string, string> result, string path)
{
const char period = '.';
if (element.ValueKind == JsonValueKind.Object)
{
foreach (var item in element.EnumerateObject())
{
if (string.IsNullOrEmpty(path))
{
path = item.Name;
}
else
{
path += period + item.Name;
}

JsonElementToObject(item.Value, result, path);

if (path.Contains(period))
{
path = path[..path.LastIndexOf(period)];
}
}
}
else if (element.ValueKind == JsonValueKind.Array)
{
JsonElementToArray(element, result, path);
}
else
{
JsonElementToValue(element, result, path);
}
}

private static void JsonElementToArray(JsonElement element, Dictionary<string, string> result, string path)
{
const char openBracket = '[';
var index = 0;
foreach (var item in element.EnumerateArray())
{
path += $"[{index}]";

JsonElementToObject(item, result, path);

if (path.Contains(openBracket))
{
path = path[..path.LastIndexOf(openBracket)];
}

++index;
}
}

private static void JsonElementToValue(JsonElement element, Dictionary<string, string> result, string path)
=> result.Add(path, element.ToString());
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Collections.Concurrent;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json;

namespace My.Extensions.Localization.Json.Internal;

Expand Down Expand Up @@ -30,7 +32,7 @@ public virtual ConcurrentDictionary<string, string> GetResourceSet(CultureInfo c
var allResources = new ConcurrentDictionary<string, string>();
do
{
if (_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources))
if (_resourcesCache.TryGetValue(culture.Name, out var resources))
{
foreach (var entry in resources)
{
Expand All @@ -45,7 +47,7 @@ public virtual ConcurrentDictionary<string, string> GetResourceSet(CultureInfo c
}
else
{
_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources);
_resourcesCache.TryGetValue(culture.Name, out var resources);

return resources;
}
Expand All @@ -63,11 +65,11 @@ public virtual string GetString(string name)

do
{
if (_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources))
if (_resourcesCache.TryGetValue(culture.Name, out var resources))
{
if (resources.TryGetValue(name, out string value))
if (resources.TryGetValue(name, out var value))
{
return value;
return value.ToString();
}
}

Expand All @@ -86,13 +88,13 @@ public virtual string GetString(string name, CultureInfo culture)
return null;
}

if (!_resourcesCache.TryGetValue(culture.Name, out ConcurrentDictionary<string, string> resources))
if (!_resourcesCache.TryGetValue(culture.Name, out var resources))
{
return null;
}

return resources.TryGetValue(name, out string value)
? value
return resources.TryGetValue(name, out var value)
? value.ToString()
: null;
}

Expand Down Expand Up @@ -157,4 +159,26 @@ ConcurrentDictionary<string, string> GetOrAddResourceCache(string resourceFile)
});
}
}

private static string GetJsonElement(JsonElement jsonElement, string path)
{
if (jsonElement.ValueKind == JsonValueKind.Null || jsonElement.ValueKind == JsonValueKind.Undefined)
{
return default;
}

string[] segments = path.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);

for (int n = 0; n < segments.Length; n++)
{
jsonElement = jsonElement.TryGetProperty(segments[n], out JsonElement value) ? value : default;

if (jsonElement.ValueKind == JsonValueKind.Null || jsonElement.ValueKind == JsonValueKind.Undefined)
{
return default;
}
}

return jsonElement.ToString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ public void GetTranslation_StronglyTypeResourceName()
}

[Theory]
[InlineData(true, 3)]
[InlineData(false, 2)]
[InlineData(true, 9)]
[InlineData(false, 8)]
public void JsonStringLocalizer_GetAllStrings(bool includeParent, int expected)
{
// Arrange
Expand Down Expand Up @@ -160,6 +160,23 @@ public async void CultureBasedResourcesUsesIStringLocalizer()
var response = await client.GetAsync("/");
}

[Theory]
[InlineData("fr-FR", "Book.Page.One", "Page Un")]
[InlineData("fr-FR", "Book.Page.Two", "Page Deux")]
[InlineData("fr-FR", "Articles[0].Content", "Contenu 1")]
[InlineData("fr-FR", "Articles[1].Content", "Contenu 2")]
public void GetTranslationUsingKeyHeirarchy(string culture, string name, string expected)
{
// Arrange
LocalizationHelper.SetCurrentCulture(culture);

// Act
string translation = _localizer[name];

// Assert
Assert.Equal(expected, translation);
}

private class SharedResource
{
public string Hello { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
{
"Hello": "Bonjour",
"Hello, {0}": "Bonjour, {0}"
"Hello, {0}": "Bonjour, {0}",
"Book": {
"Page": {
"One": "Page Un",
"Two": "Page Deux"
}
},
"Articles": [
{
"Title": "Titre 1",
"Content": "Contenu 1"
},
{
"Title": "Titre 2",
"Content": "Contenu 2"
}
]
}