mirror of https://github.com/abpframework/abp.git
111 changed files with 2235 additions and 414 deletions
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
|||
{ |
|||
[Serializable] |
|||
public class ExtensionEnumDto |
|||
{ |
|||
public List<ExtensionEnumFieldDto> Fields { get; set; } |
|||
|
|||
public string LocalizationResource { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending |
|||
{ |
|||
[Serializable] |
|||
public class ExtensionEnumFieldDto |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public object Value { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,150 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.Reflection; |
|||
|
|||
namespace Volo.Abp.ObjectExtending |
|||
{ |
|||
public static class MvcUiObjectExtensionPropertyInfoExtensions |
|||
{ |
|||
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> { |
|||
typeof(int), |
|||
typeof(long), |
|||
typeof(byte), |
|||
typeof(sbyte), |
|||
typeof(short), |
|||
typeof(ushort), |
|||
typeof(uint), |
|||
typeof(long), |
|||
typeof(ulong), |
|||
typeof(float), |
|||
typeof(double), |
|||
typeof(decimal), |
|||
typeof(int?), |
|||
typeof(long?), |
|||
typeof(byte?), |
|||
typeof(sbyte?), |
|||
typeof(short?), |
|||
typeof(ushort?), |
|||
typeof(uint?), |
|||
typeof(long?), |
|||
typeof(ulong?), |
|||
typeof(float?), |
|||
typeof(double?), |
|||
typeof(decimal?) |
|||
}; |
|||
|
|||
public static string GetInputFormatOrNull(this IBasicObjectExtensionPropertyInfo property) |
|||
{ |
|||
if (property.IsDate()) |
|||
{ |
|||
return "{0:yyyy-MM-dd}"; |
|||
} |
|||
|
|||
if (property.IsDateTime()) |
|||
{ |
|||
return "{0:yyyy-MM-ddTHH:mm}"; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public static string GetInputValueOrNull(this IBasicObjectExtensionPropertyInfo property, object value) |
|||
{ |
|||
if (value == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (TypeHelper.IsFloatingType(property.Type)) |
|||
{ |
|||
return value.ToString()?.Replace(',', '.'); |
|||
} |
|||
|
|||
/* Let the ASP.NET Core handle it! */ |
|||
return null; |
|||
} |
|||
|
|||
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) |
|||
{ |
|||
foreach (var attribute in propertyInfo.Attributes) |
|||
{ |
|||
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); |
|||
if (inputTypeByAttribute != null) |
|||
{ |
|||
return inputTypeByAttribute; |
|||
} |
|||
} |
|||
|
|||
return GetInputTypeFromTypeOrNull(propertyInfo.Type) |
|||
?? "text"; //default
|
|||
} |
|||
|
|||
private static string GetInputTypeFromAttributeOrNull(Attribute attribute) |
|||
{ |
|||
if (attribute is EmailAddressAttribute) |
|||
{ |
|||
return "email"; |
|||
} |
|||
|
|||
if (attribute is UrlAttribute) |
|||
{ |
|||
return "url"; |
|||
} |
|||
|
|||
if (attribute is HiddenInputAttribute) |
|||
{ |
|||
return "hidden"; |
|||
} |
|||
|
|||
if (attribute is PhoneAttribute) |
|||
{ |
|||
return "tel"; |
|||
} |
|||
|
|||
if (attribute is DataTypeAttribute dataTypeAttribute) |
|||
{ |
|||
switch (dataTypeAttribute.DataType) |
|||
{ |
|||
case DataType.Password: |
|||
return "password"; |
|||
case DataType.Date: |
|||
return "date"; |
|||
case DataType.Time: |
|||
return "time"; |
|||
case DataType.EmailAddress: |
|||
return "email"; |
|||
case DataType.Url: |
|||
return "url"; |
|||
case DataType.PhoneNumber: |
|||
return "tel"; |
|||
case DataType.DateTime: |
|||
return "datetime-local"; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static string GetInputTypeFromTypeOrNull(Type type) |
|||
{ |
|||
if (type == typeof(bool)) |
|||
{ |
|||
return "checkbox"; |
|||
} |
|||
|
|||
if (type == typeof(DateTime)) |
|||
{ |
|||
return "datetime-local"; |
|||
} |
|||
|
|||
if (NumberTypes.Contains(type)) |
|||
{ |
|||
return "number"; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,116 +1,35 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Linq; |
|||
|
|||
namespace Volo.Abp.ObjectExtending |
|||
{ |
|||
public static class ObjectExtensionPropertyInfoAspNetCoreMvcExtensions |
|||
{ |
|||
private static readonly HashSet<Type> NumberTypes = new HashSet<Type> { |
|||
typeof(int), |
|||
typeof(long), |
|||
typeof(byte), |
|||
typeof(sbyte), |
|||
typeof(short), |
|||
typeof(ushort), |
|||
typeof(uint), |
|||
typeof(long), |
|||
typeof(ulong), |
|||
typeof(float), |
|||
typeof(double), |
|||
typeof(int?), |
|||
typeof(long?), |
|||
typeof(byte?), |
|||
typeof(sbyte?), |
|||
typeof(short?), |
|||
typeof(ushort?), |
|||
typeof(uint?), |
|||
typeof(long?), |
|||
typeof(ulong?), |
|||
typeof(float?), |
|||
typeof(double?), |
|||
private static readonly Type[] DateTimeTypes = |
|||
{ |
|||
typeof(DateTime), |
|||
typeof(DateTimeOffset) |
|||
}; |
|||
|
|||
public static string GetInputType(this ObjectExtensionPropertyInfo propertyInfo) |
|||
public static bool IsDate(this IBasicObjectExtensionPropertyInfo property) |
|||
{ |
|||
foreach (var attribute in propertyInfo.Attributes) |
|||
{ |
|||
var inputTypeByAttribute = GetInputTypeFromAttributeOrNull(attribute); |
|||
if (inputTypeByAttribute != null) |
|||
{ |
|||
return inputTypeByAttribute; |
|||
} |
|||
} |
|||
|
|||
return GetInputTypeFromTypeOrNull(propertyInfo.Type) |
|||
?? "text"; //default
|
|||
return DateTimeTypes.Contains(property.Type) && |
|||
property.GetDataTypeOrNull() == DataType.Date; |
|||
} |
|||
|
|||
private static string GetInputTypeFromAttributeOrNull(Attribute attribute) |
|||
public static bool IsDateTime(this IBasicObjectExtensionPropertyInfo property) |
|||
{ |
|||
if (attribute is EmailAddressAttribute) |
|||
{ |
|||
return "email"; |
|||
} |
|||
|
|||
if (attribute is UrlAttribute) |
|||
{ |
|||
return "url"; |
|||
} |
|||
|
|||
if (attribute is HiddenInputAttribute) |
|||
{ |
|||
return "hidden"; |
|||
} |
|||
|
|||
if (attribute is PhoneAttribute) |
|||
{ |
|||
return "tel"; |
|||
} |
|||
|
|||
if (attribute is DataTypeAttribute dataTypeAttribute) |
|||
{ |
|||
switch (dataTypeAttribute.DataType) |
|||
{ |
|||
case DataType.Password: |
|||
return "password"; |
|||
case DataType.Date: |
|||
return "date"; |
|||
case DataType.Time: |
|||
return "time"; |
|||
case DataType.EmailAddress: |
|||
return "email"; |
|||
case DataType.Url: |
|||
return "url"; |
|||
case DataType.PhoneNumber: |
|||
return "tel"; |
|||
case DataType.DateTime: |
|||
return "datetime-local"; |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
return DateTimeTypes.Contains(property.Type) && |
|||
!property.IsDate(); |
|||
} |
|||
|
|||
private static string GetInputTypeFromTypeOrNull(Type type) |
|||
public static DataType? GetDataTypeOrNull(this IBasicObjectExtensionPropertyInfo property) |
|||
{ |
|||
if (type == typeof(bool)) |
|||
{ |
|||
return "checkbox"; |
|||
} |
|||
|
|||
if (type == typeof(DateTime)) |
|||
{ |
|||
return "datetime-local"; |
|||
} |
|||
|
|||
if (NumberTypes.Contains(type)) |
|||
{ |
|||
return "number"; |
|||
} |
|||
|
|||
return null; |
|||
return property |
|||
.Attributes |
|||
.OfType<DataTypeAttribute>() |
|||
.FirstOrDefault()?.DataType; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,21 +1,28 @@ |
|||
using Microsoft.AspNetCore.SignalR; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Security.Claims; |
|||
using Volo.Abp.Users; |
|||
|
|||
namespace Volo.Abp.AspNetCore.SignalR |
|||
{ |
|||
public class AbpSignalRUserIdProvider : IUserIdProvider, ITransientDependency |
|||
{ |
|||
public ICurrentUser CurrentUser { get; } |
|||
|
|||
public AbpSignalRUserIdProvider(ICurrentUser currentUser) |
|||
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; |
|||
|
|||
private readonly ICurrentUser _currentUser; |
|||
|
|||
public AbpSignalRUserIdProvider(ICurrentPrincipalAccessor currentPrincipalAccessor, ICurrentUser currentUser) |
|||
{ |
|||
CurrentUser = currentUser; |
|||
_currentPrincipalAccessor = currentPrincipalAccessor; |
|||
_currentUser = currentUser; |
|||
} |
|||
|
|||
public virtual string GetUserId(HubConnectionContext connection) |
|||
{ |
|||
return CurrentUser.Id?.ToString(); |
|||
using (_currentPrincipalAccessor.Change(connection.User)) |
|||
{ |
|||
return _currentUser.Id?.ToString(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,16 @@ |
|||
namespace Volo.Abp.Cli.ProjectBuilding.Templates.Console |
|||
{ |
|||
public class ConsoleTemplate : ConsoleTemplateBase |
|||
{ |
|||
/// <summary>
|
|||
/// "console".
|
|||
/// </summary>
|
|||
public const string TemplateName = "console"; |
|||
|
|||
public ConsoleTemplate() |
|||
: base(TemplateName) |
|||
{ |
|||
DocumentUrl = CliConsts.DocsLink + "/en/abp/latest/Getting-Started-Console-Application"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Cli.ProjectBuilding.Building; |
|||
|
|||
namespace Volo.Abp.Cli.ProjectBuilding.Templates.Console |
|||
{ |
|||
public abstract class ConsoleTemplateBase : TemplateInfo |
|||
{ |
|||
protected ConsoleTemplateBase([NotNull] string name) : |
|||
base(name) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
|
|||
namespace Volo.Abp |
|||
{ |
|||
public class AbpInitializationException : AbpException |
|||
{ |
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpException"/> object.
|
|||
/// </summary>
|
|||
public AbpInitializationException() |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpException"/> object.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
public AbpInitializationException(string message) |
|||
: base(message) |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Creates a new <see cref="AbpException"/> object.
|
|||
/// </summary>
|
|||
/// <param name="message">Exception message</param>
|
|||
/// <param name="innerException">Inner exception</param>
|
|||
public AbpInitializationException(string message, Exception innerException) |
|||
: base(message, innerException) |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Constructor for serializing.
|
|||
/// </summary>
|
|||
public AbpInitializationException(SerializationInfo serializationInfo, StreamingContext context) |
|||
: base(serializationInfo, context) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
using Microsoft.Extensions.Localization; |
|||
|
|||
namespace Volo.Abp.Localization |
|||
{ |
|||
/// <summary>
|
|||
/// This class is designed to be used internal by the framework.
|
|||
/// </summary>
|
|||
public static class AbpInternalLocalizationHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Searches an array of keys in an array of localizers.
|
|||
/// </summary>
|
|||
/// <param name="localizers">
|
|||
/// An array of localizers. Search the keys on the localizers.
|
|||
/// Can contain null items in the array.
|
|||
/// </param>
|
|||
/// <param name="keys">
|
|||
/// An array of keys. Search the keys on the localizers.
|
|||
/// Should not contain null items in the array.
|
|||
/// </param>
|
|||
/// <param name="defaultValue">
|
|||
/// Return value if none of the localizers has none of the keys.
|
|||
/// </param>
|
|||
/// <returns></returns>
|
|||
public static string LocalizeWithFallback( |
|||
IStringLocalizer[] localizers, |
|||
string[] keys, |
|||
string defaultValue) |
|||
{ |
|||
foreach (var key in keys) |
|||
{ |
|||
foreach (var localizer in localizers) |
|||
{ |
|||
if (localizer == null) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
var localizedString = localizer[key]; |
|||
if (!localizedString.ResourceNotFound) |
|||
{ |
|||
return localizedString.Value; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return defaultValue; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace Volo.Abp.ObjectExtending |
|||
{ |
|||
public interface IBasicObjectExtensionPropertyInfo |
|||
{ |
|||
[NotNull] |
|||
public string Name { get; } |
|||
|
|||
[NotNull] |
|||
public Type Type { get; } |
|||
|
|||
[NotNull] |
|||
public List<Attribute> Attributes { get; } |
|||
|
|||
[NotNull] |
|||
public List<Action<ObjectExtensionPropertyValidationContext>> Validators { get; } |
|||
|
|||
[CanBeNull] |
|||
public ILocalizableString DisplayName { get; } |
|||
|
|||
/// <summary>
|
|||
/// Uses as the default value if <see cref="DefaultValueFactory"/> was not set.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public object DefaultValue { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Used with the first priority to create the default value for the property.
|
|||
/// Uses to the <see cref="DefaultValue"/> if this was not set.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public Func<object> DefaultValueFactory { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System; |
|||
using Volo.Abp.Localization; |
|||
|
|||
namespace Volo.Abp.ObjectExtending.Modularity |
|||
{ |
|||
public static class ExtensionPropertyConfigurationExtensions |
|||
{ |
|||
public static string GetLocalizationResourceNameOrNull( |
|||
this ExtensionPropertyConfiguration property) |
|||
{ |
|||
var resourceType = property.GetLocalizationResourceTypeOrNull(); |
|||
if (resourceType == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return LocalizationResourceNameAttribute.GetName(resourceType); |
|||
} |
|||
|
|||
public static Type GetLocalizationResourceTypeOrNull( |
|||
this ExtensionPropertyConfiguration property) |
|||
{ |
|||
if (property.DisplayName != null && |
|||
property.DisplayName is LocalizableString localizableString) |
|||
{ |
|||
return localizableString.ResourceType; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -1,9 +1,12 @@ |
|||
using System.Security.Claims; |
|||
using System; |
|||
using System.Security.Claims; |
|||
|
|||
namespace Volo.Abp.Security.Claims |
|||
{ |
|||
public interface ICurrentPrincipalAccessor |
|||
{ |
|||
ClaimsPrincipal Principal { get; } |
|||
|
|||
IDisposable Change(ClaimsPrincipal principal); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,50 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Localization; |
|||
using Scriban; |
|||
using Scriban.Runtime; |
|||
using Scriban.Syntax; |
|||
|
|||
namespace Volo.Abp.TextTemplating |
|||
{ |
|||
public class TemplateLocalizer : IScriptCustomFunction |
|||
{ |
|||
private readonly IStringLocalizer _localizer; |
|||
|
|||
public TemplateLocalizer(IStringLocalizer localizer) |
|||
{ |
|||
_localizer = localizer; |
|||
} |
|||
|
|||
public object Invoke(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, |
|||
ScriptBlockStatement blockStatement) |
|||
{ |
|||
return GetString(arguments); |
|||
} |
|||
|
|||
public ValueTask<object> InvokeAsync(TemplateContext context, ScriptNode callerContext, ScriptArray arguments, |
|||
ScriptBlockStatement blockStatement) |
|||
{ |
|||
return new ValueTask<object>(GetString(arguments)); |
|||
} |
|||
|
|||
private string GetString(ScriptArray arguments) |
|||
{ |
|||
if (arguments.IsNullOrEmpty()) |
|||
{ |
|||
return string.Empty; |
|||
} |
|||
|
|||
var name = arguments[0]; |
|||
if (name == null || name.ToString().IsNullOrWhiteSpace()) |
|||
{ |
|||
return string.Empty; |
|||
} |
|||
|
|||
var args = arguments.Skip(1).Where(x => x != null && !x.ToString().IsNullOrWhiteSpace()).ToArray(); |
|||
return args.Any() ? _localizer[name.ToString(), args] : _localizer[name.ToString()]; |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +1,35 @@ |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ExceptionHandling |
|||
{ |
|||
public class ExceptionTestPage : AbpPageModel |
|||
{ |
|||
public void OnGetUserFriendlyException1() |
|||
public void OnGetUserFriendlyException_void() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
public IActionResult OnGetUserFriendlyException2() |
|||
|
|||
public Task OnGetUserFriendlyException_Task() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
public IActionResult OnGetUserFriendlyException_ActionResult() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
public JsonResult OnGetUserFriendlyException_JsonResult() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
public Task<JsonResult> OnGetUserFriendlyException_Task_JsonResult() |
|||
{ |
|||
throw new UserFriendlyException("This is a sample exception!"); |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,6 @@ |
|||
{ |
|||
"culture": "de", |
|||
"texts": { |
|||
"hello": "Hello" |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
using System.Collections.Generic; |
|||
using System.Security.Claims; |
|||
using Shouldly; |
|||
using Volo.Abp.Testing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Security.Claims |
|||
{ |
|||
public class CurrentPrincipalAccessor_Test : AbpIntegratedTest<AbpSecurityTestModule> |
|||
{ |
|||
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor; |
|||
|
|||
public CurrentPrincipalAccessor_Test() |
|||
{ |
|||
_currentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_Get_Changed_Principal_If() |
|||
{ |
|||
var claimsPrincipal = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> |
|||
{ |
|||
new Claim(ClaimTypes.Name,"bob"), |
|||
new Claim(ClaimTypes.NameIdentifier,"123456") |
|||
})); |
|||
|
|||
var claimsPrincipal2 = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> |
|||
{ |
|||
new Claim(ClaimTypes.Name,"lee"), |
|||
new Claim(ClaimTypes.NameIdentifier,"654321") |
|||
})); |
|||
|
|||
|
|||
_currentPrincipalAccessor.Principal.ShouldBe(null); |
|||
|
|||
using (_currentPrincipalAccessor.Change(claimsPrincipal)) |
|||
{ |
|||
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); |
|||
|
|||
using (_currentPrincipalAccessor.Change(claimsPrincipal2)) |
|||
{ |
|||
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal2); |
|||
} |
|||
|
|||
_currentPrincipalAccessor.Principal.ShouldBe(claimsPrincipal); |
|||
} |
|||
_currentPrincipalAccessor.Principal.ShouldBeNull(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,6 +1,7 @@ |
|||
{ |
|||
"culture": "en", |
|||
"texts": { |
|||
"HelloText": "Hello" |
|||
} |
|||
} |
|||
"HelloText": "Hello {0}", |
|||
"HowAreYou": "how are you?" |
|||
} |
|||
} |
|||
|
|||
@ -1,6 +1,7 @@ |
|||
{ |
|||
"culture": "tr", |
|||
"texts": { |
|||
"HelloText": "Merhaba" |
|||
} |
|||
} |
|||
"HelloText": "Merhaba {0}", |
|||
"HowAreYou": "nasılsın?" |
|||
} |
|||
} |
|||
|
|||
@ -1 +1 @@ |
|||
{{L "HelloText"}}. Please click to the following link to get an email to reset your password! |
|||
{{L "HelloText" model.name}}, {{L "HowAreYou" }}. Please click to the following link to get an email to reset your password! |
|||
@ -1,12 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Blogging |
|||
{ |
|||
public class BloggingTwitterOptions |
|||
{ |
|||
public string Site { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Blogging.SocialMedia |
|||
{ |
|||
public class BloggingTwitterOptions |
|||
{ |
|||
public string Site { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Docs.Admin |
|||
{ |
|||
public static class DocsAdminRemoteServiceConsts |
|||
{ |
|||
public const string RemoteServiceName = "AbpDocsAdmin"; |
|||
} |
|||
} |
|||
@ -1,11 +1,17 @@ |
|||
using Volo.Abp.Modularity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Http.Client; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Docs.Admin |
|||
{ |
|||
[DependsOn( |
|||
typeof(DocsAdminApplicationContractsModule))] |
|||
typeof(DocsAdminApplicationContractsModule), |
|||
typeof(AbpHttpClientModule))] |
|||
public class DocsAdminHttpApiClientModule : AbpModule |
|||
{ |
|||
//TODO: Create client proxies!
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddHttpClientProxies(typeof(DocsAdminApplicationContractsModule).Assembly, DocsAdminRemoteServiceConsts.RemoteServiceName); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Docs |
|||
{ |
|||
public static class DocsRemoteServiceConsts |
|||
{ |
|||
public const string RemoteServiceName = "AbpDocs"; |
|||
} |
|||
} |
|||
@ -1,11 +1,18 @@ |
|||
using Volo.Abp.Modularity; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Http.Client; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Docs |
|||
{ |
|||
[DependsOn( |
|||
typeof(DocsApplicationContractsModule))] |
|||
typeof(DocsApplicationContractsModule), |
|||
typeof(AbpHttpClientModule) |
|||
)] |
|||
public class DocsHttpApiClientModule : AbpModule |
|||
{ |
|||
//TODO: Create client proxies
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
context.Services.AddHttpClientProxies(typeof(DocsApplicationContractsModule).Assembly, DocsRemoteServiceConsts.RemoteServiceName); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.Identity |
|||
{ |
|||
public class UserLookupCountInputDto |
|||
{ |
|||
public string Filter { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,140 @@ |
|||
import { |
|||
createLocalizationPipeKeyGenerator, |
|||
createLocalizer, |
|||
createLocalizerWithFallback, |
|||
} from '../utils/localization-utils'; |
|||
|
|||
describe('Localization Utils', () => { |
|||
describe('#createLocalizer', () => { |
|||
const localize = createLocalizer({ |
|||
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
|||
defaultResourceName: 'x', |
|||
currentCulture: null, |
|||
languages: [], |
|||
}); |
|||
|
|||
test.each` |
|||
resource | key | defaultValue | expected |
|||
${'_'} | ${'TEST'} | ${'DEFAULT'} | ${'TEST'} |
|||
${'foo'} | ${'bar'} | ${'DEFAULT'} | ${'baz'} |
|||
${'x'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'a'} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${''} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${undefined} | ${'bar'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'foo'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'x'} | ${'y'} | ${'DEFAULT'} | ${'z'} |
|||
${'a'} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${''} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${undefined} | ${'y'} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'foo'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'x'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'a'} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${''} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${undefined} | ${''} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'foo'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'x'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${'a'} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${''} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${undefined} | ${undefined} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
`(
|
|||
'should return $expected when resource name is $resource and key is $key', |
|||
({ resource, key, defaultValue, expected }) => { |
|||
const result = localize(resource, key, defaultValue); |
|||
|
|||
expect(result).toBe(expected); |
|||
}, |
|||
); |
|||
}); |
|||
|
|||
describe('#createLocalizerWithFallback', () => { |
|||
const localizeWithFallback = createLocalizerWithFallback({ |
|||
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
|||
defaultResourceName: 'x', |
|||
currentCulture: null, |
|||
languages: [], |
|||
}); |
|||
|
|||
test.each` |
|||
resources | keys | defaultValue | expected |
|||
${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'} |
|||
${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'baz'} |
|||
${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['foo']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
|||
${['x']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
|||
${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
|||
${['']} | ${['y']} | ${'DEFAULT'} | ${'z'} |
|||
${[]} | ${['y']} | ${'DEFAULT'} | ${'z'} |
|||
${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'baz'} |
|||
${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
|||
${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
|||
${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
|||
${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'z'} |
|||
${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
`(
|
|||
'should return $expected when resource names are $resources and keys are $keys', |
|||
({ resources, keys, defaultValue, expected }) => { |
|||
const result = localizeWithFallback(resources, keys, defaultValue); |
|||
|
|||
expect(result).toBe(expected); |
|||
}, |
|||
); |
|||
}); |
|||
|
|||
describe('#createLocalizationPipeKeyGenerator', () => { |
|||
const generateLocalizationPipeKey = createLocalizationPipeKeyGenerator({ |
|||
values: { foo: { bar: 'baz' }, x: { y: 'z' } }, |
|||
defaultResourceName: 'x', |
|||
currentCulture: null, |
|||
languages: [], |
|||
}); |
|||
|
|||
test.each` |
|||
resources | keys | defaultKey | expected |
|||
${['', '_']} | ${['TEST', 'OTHER']} | ${'DEFAULT'} | ${'TEST'} |
|||
${['foo']} | ${['bar']} | ${'DEFAULT'} | ${'foo::bar'} |
|||
${['x']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${['bar']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['foo']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['x']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['a', 'b', 'c']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['']} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${[]} | ${['y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['foo']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'foo::bar'} |
|||
${['x']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['a', 'b', 'c']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['']} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${[]} | ${['bar', 'y']} | ${'DEFAULT'} | ${'x::y'} |
|||
${['foo']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['x']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${['']} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['foo']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['x']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['a', 'b', 'c']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${['']} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
${[]} | ${[]} | ${'DEFAULT'} | ${'DEFAULT'} |
|||
`(
|
|||
'should return $expected when resource names are $resources and keys are $keys', |
|||
({ resources, keys, defaultKey, expected }) => { |
|||
const result = generateLocalizationPipeKey(resources, keys, defaultKey); |
|||
|
|||
expect(result).toBe(expected); |
|||
}, |
|||
); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,56 @@ |
|||
import { ApplicationConfiguration } from '../models/application-configuration'; |
|||
|
|||
export function createLocalizer(localization: ApplicationConfiguration.Localization) { |
|||
return (resourceName: string, key: string, defaultValue: string) => { |
|||
if (resourceName === '_') return key; |
|||
|
|||
const resource = localization.values[resourceName]; |
|||
|
|||
if (!resource) return defaultValue; |
|||
|
|||
return resource[key] || defaultValue; |
|||
}; |
|||
} |
|||
|
|||
export function createLocalizerWithFallback(localization: ApplicationConfiguration.Localization) { |
|||
const findLocalization = createLocalizationFinder(localization); |
|||
|
|||
return (resourceNames: string[], keys: string[], defaultValue: string) => { |
|||
const { localized } = findLocalization(resourceNames, keys); |
|||
return localized || defaultValue; |
|||
}; |
|||
} |
|||
|
|||
export function createLocalizationPipeKeyGenerator( |
|||
localization: ApplicationConfiguration.Localization, |
|||
) { |
|||
const findLocalization = createLocalizationFinder(localization); |
|||
|
|||
return (resourceNames: string[], keys: string[], defaultKey: string) => { |
|||
const { resourceName, key } = findLocalization(resourceNames, keys); |
|||
return !resourceName ? defaultKey : resourceName === '_' ? key : `${resourceName}::${key}`; |
|||
}; |
|||
} |
|||
|
|||
function createLocalizationFinder(localization: ApplicationConfiguration.Localization) { |
|||
const localize = createLocalizer(localization); |
|||
|
|||
return (resourceNames: string[], keys: string[]) => { |
|||
resourceNames = resourceNames.concat(localization.defaultResourceName).filter(Boolean); |
|||
|
|||
const resourceCount = resourceNames.length; |
|||
const keyCount = keys.length; |
|||
|
|||
for (let i = 0; i < resourceCount; i++) { |
|||
const resourceName = resourceNames[i]; |
|||
|
|||
for (let j = 0; j < keyCount; j++) { |
|||
const key = keys[j]; |
|||
const localized = localize(resourceName, key, null); |
|||
if (localized) return { resourceName, key, localized }; |
|||
} |
|||
} |
|||
|
|||
return { resourceName: undefined, key: undefined, localized: undefined }; |
|||
}; |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue