Skip to content
Open
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
2 changes: 1 addition & 1 deletion src/My.Extensions.Localization.Json/JsonStringLocalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ protected virtual IEnumerable<LocalizedString> GetAllStrings(bool includeParentC
}
}

protected string GetStringSafely(string name, CultureInfo culture)
protected virtual string GetStringSafely(string name, CultureInfo culture)
{
ArgumentNullException.ThrowIfNull(name);

Expand Down
25 changes: 25 additions & 0 deletions src/My.Extensions.Localization.Json/JsonStringLocalizerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,31 @@
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
}

/// <summary>
/// Gets the cache used to store resource names.
/// </summary>
protected IResourceNamesCache ResourceNamesCache => _resourceNamesCache;

/// <summary>
/// Gets the cache used to store localizer instances.
/// </summary>
protected ConcurrentDictionary<string, JsonStringLocalizer> LocalizerCache => _localizerCache;

/// <summary>
/// Gets the resources relative path.
/// </summary>
protected string ResourcesRelativePath => _resourcesRelativePath;

Check failure on line 59 in src/My.Extensions.Localization.Json/JsonStringLocalizerFactory.cs

View workflow job for this annotation

GitHub Actions / build

The name '_resourcesRelativePath' does not exist in the current context

Check failure on line 59 in src/My.Extensions.Localization.Json/JsonStringLocalizerFactory.cs

View workflow job for this annotation

GitHub Actions / build

The name '_resourcesRelativePath' does not exist in the current context

/// <summary>
/// Gets the resources type.
/// </summary>
protected ResourcesType ResourcesType => _resourcesType;

/// <summary>
/// Gets the logger factory.
/// </summary>
protected ILoggerFactory LoggerFactory => _loggerFactory;

public IStringLocalizer Create(Type resourceSource)
{
ArgumentNullException.ThrowIfNull(resourceSource);
Expand Down
168 changes: 168 additions & 0 deletions test/My.Extensions.Localization.Json.Tests/ExtensibilityTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
using System;
using System.Collections.Concurrent;
using System.Globalization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Moq;
using My.Extensions.Localization.Json.Caching;
using My.Extensions.Localization.Json.Internal;
using My.Extensions.Localization.Json.Tests.Common;
using Xunit;

namespace My.Extensions.Localization.Json.Tests;

public class ExtensibilityTests
{
private readonly Mock<IOptions<JsonLocalizationOptions>> _localizationOptions;
private readonly ILoggerFactory _loggerFactory;

public ExtensibilityTests()
{
_localizationOptions = new Mock<IOptions<JsonLocalizationOptions>>();
_localizationOptions.Setup(o => o.Value)
.Returns(() => new JsonLocalizationOptions { ResourcesPath = "Resources" });
_loggerFactory = NullLoggerFactory.Instance;
}

[Fact]
public void CustomJsonStringLocalizerFactory_CanOverrideCreateJsonStringLocalizer()
{
// Arrange
LocalizationHelper.SetCurrentCulture("fr-FR");
var factory = new CustomJsonStringLocalizerFactory(_localizationOptions.Object, _loggerFactory);

// Act
var localizer = factory.Create(typeof(Test));

// Assert
Assert.NotNull(localizer);
Assert.True(factory.CreateJsonStringLocalizerWasCalled);
}

[Fact]
public void CustomJsonStringLocalizerFactory_CanAccessProtectedProperties()
{
// Arrange
var factory = new CustomJsonStringLocalizerFactory(_localizationOptions.Object, _loggerFactory);

// Assert
Assert.NotNull(factory.GetResourceNamesCache());
Assert.NotNull(factory.GetLocalizerCache());
Assert.Equal("Resources", factory.GetResourcesRelativePath());
Assert.Equal(ResourcesType.TypeBased, factory.GetResourcesType());
Assert.NotNull(factory.GetLoggerFactory());
}

[Fact]
public void CustomJsonStringLocalizer_CanOverrideGetStringSafely()
{
// Arrange
LocalizationHelper.SetCurrentCulture("fr-FR");
var factory = new CustomLocalizerFactory(_localizationOptions.Object, _loggerFactory);
var localizer = factory.Create(typeof(Test)) as CustomJsonStringLocalizer;

// Act
var result = localizer["Hello"];

// Assert
Assert.NotNull(localizer);
Assert.True(localizer.GetStringSafelyWasCalled);
}

[Fact]
public void CustomJsonStringLocalizer_CanOverrideGetAllStrings()
{
// Arrange
LocalizationHelper.SetCurrentCulture("fr-FR");
var factory = new CustomLocalizerFactory(_localizationOptions.Object, _loggerFactory);
var localizer = factory.Create(typeof(Test)) as CustomJsonStringLocalizer;

// Act
var result = localizer.GetAllStrings(true);

// Assert
Assert.NotNull(localizer);
Assert.True(localizer.GetAllStringsWasCalled);
}

/// <summary>
/// Custom factory that overrides CreateJsonStringLocalizer to demonstrate extensibility.
/// </summary>
private class CustomJsonStringLocalizerFactory : JsonStringLocalizerFactory
{
public bool CreateJsonStringLocalizerWasCalled { get; private set; }

public CustomJsonStringLocalizerFactory(
IOptions<JsonLocalizationOptions> localizationOptions,
ILoggerFactory loggerFactory)
: base(localizationOptions, loggerFactory)
{
}

protected override JsonStringLocalizer CreateJsonStringLocalizer(string resourcesPath, string resourceName)
{
CreateJsonStringLocalizerWasCalled = true;
return base.CreateJsonStringLocalizer(resourcesPath, resourceName);
}

// Expose protected properties for testing
public IResourceNamesCache GetResourceNamesCache() => ResourceNamesCache;
public ConcurrentDictionary<string, JsonStringLocalizer> GetLocalizerCache() => LocalizerCache;
public string GetResourcesRelativePath() => ResourcesRelativePath;
public ResourcesType GetResourcesType() => ResourcesType;
public ILoggerFactory GetLoggerFactory() => LoggerFactory;
}

/// <summary>
/// Custom factory that creates CustomJsonStringLocalizer instances.
/// </summary>
private class CustomLocalizerFactory : JsonStringLocalizerFactory
{
public CustomLocalizerFactory(
IOptions<JsonLocalizationOptions> localizationOptions,
ILoggerFactory loggerFactory)
: base(localizationOptions, loggerFactory)
{
}

protected override JsonStringLocalizer CreateJsonStringLocalizer(string resourcesPath, string resourceName)
{
var resourceManager = ResourcesType == ResourcesType.TypeBased
? new JsonResourceManager(resourcesPath, resourceName)
: new JsonResourceManager(resourcesPath);
var logger = LoggerFactory.CreateLogger<CustomJsonStringLocalizer>();

return new CustomJsonStringLocalizer(resourceManager, ResourceNamesCache, logger);
}
}

/// <summary>
/// Custom localizer that overrides GetStringSafely to demonstrate extensibility.
/// </summary>
private class CustomJsonStringLocalizer : JsonStringLocalizer
{
public bool GetStringSafelyWasCalled { get; private set; }
public bool GetAllStringsWasCalled { get; private set; }

public CustomJsonStringLocalizer(
JsonResourceManager jsonResourceManager,
IResourceNamesCache resourceNamesCache,
ILogger logger)
: base(jsonResourceManager, resourceNamesCache, logger)
{
}

protected override string GetStringSafely(string name, CultureInfo culture)
{
GetStringSafelyWasCalled = true;
return base.GetStringSafely(name, culture);
}

public override System.Collections.Generic.IEnumerable<Microsoft.Extensions.Localization.LocalizedString> GetAllStrings(bool includeParentCultures)
{
GetAllStringsWasCalled = true;
return base.GetAllStrings(includeParentCultures);
}
}
}
Loading