diff --git a/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs index 8bb5372a..5a800c7b 100644 --- a/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneLocalizationExtensions.cs @@ -1,3 +1,5 @@ +using System; + namespace Microsoft.Extensions.Localization { public static class OqtaneLocalizationExtensions @@ -18,5 +20,42 @@ namespace Microsoft.Extensions.Localization } return localizedValue; } + + /// + /// Creates an IStringLocalizer based on a type name. This extension method is useful in scenarios where the default IStringLocalizer is unable to locate the resources. + /// + /// + /// the full type name ie. GetType().FullName + /// + public static IStringLocalizer Create(this IStringLocalizerFactory localizerFactory, string fullTypeName) + { + var typename = fullTypeName; + + // handle generic types + var type = Type.GetType(fullTypeName); + if (type.IsGenericType) + { + typename = type.GetGenericTypeDefinition().FullName; + typename = typename.Substring(0, typename.IndexOf("`")); // remove generic type info + } + + // format typename + if (typename.Contains(",")) + { + typename = typename.Substring(0, typename.IndexOf(",")); // remove assembly info + } + + // remove rootnamespace + var rootnamespace = ""; + var attributes = type.Assembly.GetCustomAttributes(typeof(RootNamespaceAttribute), false); + if (attributes.Length > 0) + { + rootnamespace = ((RootNamespaceAttribute)attributes[0]).RootNamespace; + } + typename = typename.Replace(rootnamespace + ".", ""); + + // create IStringLocalizer using factory + return localizerFactory.Create(typename, type.Assembly.GetName().Name); + } } } diff --git a/Oqtane.Client/Modules/Controls/LocalizableComponent.cs b/Oqtane.Client/Modules/Controls/LocalizableComponent.cs index 44f1a403..82f0bfba 100644 --- a/Oqtane.Client/Modules/Controls/LocalizableComponent.cs +++ b/Oqtane.Client/Modules/Controls/LocalizableComponent.cs @@ -1,16 +1,14 @@ using System; -using System.Text; using Microsoft.AspNetCore.Components; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; -using Oqtane.Shared; namespace Oqtane.Modules.Controls { public class LocalizableComponent : ModuleControlBase { + [Inject] public IStringLocalizerFactory LocalizerFactory { get; set; } + private IStringLocalizer _localizer; - private IStringLocalizer _resourceLocalizer; [Parameter] public string ResourceKey { get; set; } @@ -20,37 +18,6 @@ namespace Oqtane.Modules.Controls protected bool IsLocalizable { get; private set; } - protected IStringLocalizer T - { - get - { - if (_resourceLocalizer == null) - { - using (var scope = ServiceActivator.GetScope()) - { - var controlType = GetType(); - var controlTypeName = controlType.Name; - var assemblyName = controlType.Assembly.GetName().Name; - - if (controlType.IsGenericType) - { - // Trim generic type suffix - controlTypeName = controlTypeName[..controlTypeName.IndexOf('`')]; - } - - controlTypeName = controlType.FullName[..(controlType.FullName.IndexOf(controlTypeName) + controlTypeName.Length)]; - - var baseName = GetBaseName(controlTypeName, assemblyName); - var localizerFactory = scope.ServiceProvider.GetService(); - - _resourceLocalizer = localizerFactory.Create(baseName, assemblyName); - } - } - - return _resourceLocalizer; - } - } - protected string Localize(string name) => _localizer?[name] ?? name; protected string Localize(string propertyName, string propertyValue) @@ -63,22 +30,15 @@ namespace Oqtane.Modules.Controls var key = $"{ResourceKey}.{propertyName}"; var value = Localize(key); - if (value == key) + if (value == key || value == String.Empty) { - // Returns default property value (English version) instead of ResourceKey.PropertyName + // return default property value if key does not exist in resource file or value is empty return propertyValue; } else { - if (value == String.Empty) - { - // Returns default property value (English version) - return propertyValue; - } - else - { - return value; - } + // return localized value + return value; } } @@ -93,39 +53,9 @@ namespace Oqtane.Modules.Controls if (!String.IsNullOrEmpty(ResourceKey) && !String.IsNullOrEmpty(ResourceType)) { - var moduleType = Type.GetType(ResourceType); - if (moduleType != null) - { - using (var scope = ServiceActivator.GetScope()) - { - var localizerFactory = scope.ServiceProvider.GetService(); - _localizer = localizerFactory.Create(moduleType); - - IsLocalizable = true; - } - } + _localizer = LocalizerFactory.Create(ResourceType); + IsLocalizable = true; } } - - private static string GetBaseName(string typeName, string assemblyName) - { - var baseName = new StringBuilder(typeName); - - var tokens = assemblyName.Split("."); - - foreach (var token in tokens) - { - var index = baseName.ToString().IndexOf(token); - - if (index == -1) - { - continue; - } - - baseName.Remove(index, token.Length + 1); - } - - return baseName.ToString(); - } } } diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index 25485ebd..e317f38b 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -1,6 +1,6 @@ @namespace Oqtane.Modules.Controls -@inherits LocalizableComponent - +@inherits ModuleControlBase +@inject IStringLocalizerFactory LocalizerFactory @typeparam TableItem @if (ItemList != null) @@ -49,7 +49,7 @@ UpdateList(_pages))>
  • - @T["PageOfPages", _page, _pages] + @Localizer["PageOfPages", _page, _pages]
  • } @@ -157,67 +157,73 @@ UpdateList(_pages))>
  • - @T["PageOfPages", _page, _pages] + @Localizer["PageOfPages", _page, _pages]
  • } } @code { - private int _pages = 0; - private int _page = 1; - private int _maxItems = 10; - private int _displayPages = 5; - private int _startPage = 0; - private int _endPage = 0; - private int _columns = 0; + private IStringLocalizer Localizer; + private int _pages = 0; + private int _page = 1; + private int _maxItems = 10; + private int _displayPages = 5; + private int _startPage = 0; + private int _endPage = 0; + private int _columns = 0; - [Parameter] - public string Format { get; set; } // Table or Grid + [Parameter] + public string Format { get; set; } // Table or Grid - [Parameter] - public string Toolbar { get; set; } // Top, Bottom or Both + [Parameter] + public string Toolbar { get; set; } // Top, Bottom or Both - [Parameter] - public RenderFragment Header { get; set; } = null; // only applicable to Table layouts + [Parameter] + public RenderFragment Header { get; set; } = null; // only applicable to Table layouts - [Parameter] - public RenderFragment Row { get; set; } = null; // required + [Parameter] + public RenderFragment Row { get; set; } = null; // required - [Parameter] - public RenderFragment Detail { get; set; } = null; // only applicable to Table layouts + [Parameter] + public RenderFragment Detail { get; set; } = null; // only applicable to Table layouts - [Parameter] - public IEnumerable Items { get; set; } // the IEnumerable data source + [Parameter] + public IEnumerable Items { get; set; } // the IEnumerable data source - [Parameter] - public string PageSize { get; set; } // number of items to display on a page + [Parameter] + public string PageSize { get; set; } // number of items to display on a page - [Parameter] - public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior + [Parameter] + public string Columns { get; set; } // only applicable to Grid layouts - default is zero indicating use responsive behavior - [Parameter] - public string CurrentPage { get; set; } // sets the initial page to display + [Parameter] + public string CurrentPage { get; set; } // sets the initial page to display - [Parameter] - public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection + [Parameter] + public string DisplayPages { get; set; } // maximum number of page numbers to display for user selection - [Parameter] - public string Class { get; set; } // class for the containing element - ie. for Table or
    for Grid + [Parameter] + public string Class { get; set; } // class for the containing element - ie.
    for Table or
    for Grid - [Parameter] - public string RowClass { get; set; } // class for row element - ie.
    for Table or
    for Grid + [Parameter] + public string RowClass { get; set; } // class for row element - ie.
    for Table or
    for Grid - [Parameter] - public string ColumnClass { get; set; } // class for column element - only applicable to Grid format + [Parameter] + public string ColumnClass { get; set; } // class for column element - only applicable to Grid format - [Parameter] - public Action OnPageChange { get; set; } // a method to be executed in the calling component when the page changes + [Parameter] + public Action OnPageChange { get; set; } // a method to be executed in the calling component when the page changes - private IEnumerable ItemList { get; set; } + private IEnumerable ItemList { get; set; } - protected override void OnParametersSet() - { + protected override void OnInitialized() + { + Localizer = LocalizerFactory.Create(GetType().FullName); + } + + protected override void OnParametersSet() + { if (string.IsNullOrEmpty(Format)) { Format = "Table";