From 2d8d2075cdcb177425b94cee652ec704f7b93a09 Mon Sep 17 00:00:00 2001 From: Halil ibrahim Kalkan Date: Fri, 20 Jul 2018 16:56:40 +0300 Subject: [PATCH] Introduce ILanguageProvider, UseAbpRequestLocalization --- .../Toolbar/LanguageSwitch/Default.cshtml | 2 +- .../Toolbar/LanguageSwitch/LanguageInfo.cs | 11 --- .../LanguageSwitchViewComponent.cs | 51 ++++++------- .../LanguageSwitchViewComponentModel.cs | 8 +- .../BasicThemeMainTopToolbarContributor.cs | 11 ++- .../AbpApplicationBuilderExtensions.cs | 73 ++++++++++++++++++- .../Volo.Abp.AspNetCore.csproj | 1 + .../Volo.Abp.Localization.csproj | 4 +- .../Abp/Localization/AbpLocalizationModule.cs | 11 ++- .../Localization/AbpLocalizationOptions.cs | 6 +- .../Localization/DefaultLanguageProvider.cs | 22 ++++++ .../Abp/Localization/ILanguageProvider.cs | 10 +++ .../Volo/Abp/Localization/LanguageInfo.cs | 48 ++++++++++++ .../LanguageProviderExtensions.cs | 13 ++++ .../Localization/LocalizationSettingNames.cs | 7 ++ .../LocalizationSettingProvider.cs | 14 ++++ 16 files changed, 232 insertions(+), 60 deletions(-) delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageInfo.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DefaultLanguageProvider.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILanguageProvider.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageProviderExtensions.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingNames.cs create mode 100644 framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml index 7131fa1175..53d56ebfa3 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml @@ -8,7 +8,7 @@ \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageInfo.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageInfo.cs deleted file mode 100644 index 05af1040f9..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch -{ - public class LanguageInfo - { - public string Name { get; set; } - - public string DisplayName { get; set; } - - public string Icon { get; set; } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs index 62f8fbc9b2..336dccecee 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponent.cs @@ -1,49 +1,44 @@ -using System.Globalization; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; +using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch { public class LanguageSwitchViewComponent : AbpViewComponent { - private readonly RequestLocalizationOptions _options; + private readonly ILanguageProvider _languageProvider; - public LanguageSwitchViewComponent(IOptions options) + public LanguageSwitchViewComponent(ILanguageProvider languageProvider) { - _options = options.Value; + _languageProvider = languageProvider; } - public IViewComponentResult Invoke() + public async Task InvokeAsync() { - //TODO: Better handle culture & uiculture separation! + var languages = await _languageProvider.GetLanguagesAsync(); + var currentLanguage = FindCurrentLanguage(languages); var model = new LanguageSwitchViewComponentModel { - CurrentLanguage = new LanguageInfo - { - Name = CultureInfo.CurrentUICulture.Name, - DisplayName = CultureInfo.CurrentUICulture.DisplayName, - Icon = null //TODO! - } + CurrentLanguage = currentLanguage, + OtherLanguages = languages.Where(l => l != currentLanguage).ToList() }; - - foreach (var supportedUiCulture in _options.SupportedUICultures) - { - if (model.CurrentLanguage.Name == supportedUiCulture.Name) - { - continue; - } - - model.OtherLanguages.Add(new LanguageInfo - { - Name = supportedUiCulture.Name, - DisplayName = supportedUiCulture.DisplayName, - Icon = null //TODO! - }); - } - + return View("~/Themes/Basic/Components/Toolbar/LanguageSwitch/Default.cshtml", model); } + + private LanguageInfo FindCurrentLanguage(IReadOnlyList languages) + { + return languages.FirstOrDefault(l => + l.CultureName == CultureInfo.CurrentCulture.Name && + l.UiCultureName == CultureInfo.CurrentUICulture.Name) + ?? languages.FirstOrDefault(l => l.CultureName == CultureInfo.CurrentCulture.Name) + ?? languages.FirstOrDefault(l => l.UiCultureName == CultureInfo.CurrentUICulture.Name); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponentModel.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponentModel.cs index 7f2eb7a9fd..248675dbe1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponentModel.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Toolbar/LanguageSwitch/LanguageSwitchViewComponentModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Volo.Abp.Localization; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch { @@ -6,11 +7,6 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar { public LanguageInfo CurrentLanguage { get; set; } - public List OtherLanguages { get; } - - public LanguageSwitchViewComponentModel() - { - OtherLanguages = new List(); - } + public List OtherLanguages { get; set; } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs index dea0ea73d2..e0738d424f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Toolbars/BasicThemeMainTopToolbarContributor.cs @@ -1,11 +1,9 @@ -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; +using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.UserMenu; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; +using Volo.Abp.Localization; using Volo.Abp.Users; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars @@ -24,9 +22,10 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Toolbars return Task.CompletedTask; } - var requestLocalizationOptions = context.ServiceProvider.GetService>(); + var languageProvider = context.ServiceProvider.GetService(); - if (requestLocalizationOptions.Value.SupportedCultures.Count > 1) + //TODO: This duplicates GetLanguages() usage. Can we eleminate this? + if (languageProvider.GetLanguages().Count > 1) { context.Toolbar.Items.Add(new ToolbarItem(typeof(LanguageSwitchViewComponent))); } diff --git a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs index 61b5fc6455..9631e0aef2 100644 --- a/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs +++ b/framework/src/Volo.Abp.AspNetCore/Microsoft/AspNetCore/Builder/AbpApplicationBuilderExtensions.cs @@ -1,15 +1,24 @@ -using JetBrains.Annotations; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.DependencyInjection; using Volo.Abp; using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Uow; using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; +using Volo.Abp.Settings; +using Volo.Abp.Threading; namespace Microsoft.AspNetCore.Builder { public static class AbpApplicationBuilderExtensions { + private const string ExceptionHandlingMiddlewareMarker = "_AbpExceptionHandlingMiddleware_Added"; + public static void InitializeApplication([NotNull] this IApplicationBuilder app) { Check.NotNull(app, nameof(app)); @@ -31,16 +40,72 @@ namespace Microsoft.AspNetCore.Builder .UseMiddleware(); } + public static IApplicationBuilder UseAbpRequestLocalization(this IApplicationBuilder app) + { + IReadOnlyList languages; + string defaultLanguage; + + using (var scope = app.ApplicationServices.CreateScope()) + { + var languageProvider = scope.ServiceProvider.GetRequiredService(); + var settingManager = scope.ServiceProvider.GetRequiredService(); + + languages = AsyncHelper.RunSync(() => languageProvider.GetLanguagesAsync()); + defaultLanguage = settingManager.GetOrNull(LocalizationSettingNames.DefaultLanguage); + } + + if (!languages.Any()) + { + return app.UseRequestLocalization(); + } + + var options = new RequestLocalizationOptions + { + DefaultRequestCulture = DefaultGetRequestCulture(defaultLanguage, languages), + + SupportedCultures = languages + .Select(l => l.CultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray(), + + SupportedUICultures = languages + .Select(l => l.UiCultureName) + .Distinct() + .Select(c => new CultureInfo(c)) + .ToArray() + }; + + return app.UseRequestLocalization(options); + } + public static IApplicationBuilder UseAbpExceptionHandling(this IApplicationBuilder app) { - //Prevent multiple add - if (app.Properties.ContainsKey("_AbpExceptionHandlingMiddleware_Added")) //TODO: Constant + if (app.Properties.ContainsKey(ExceptionHandlingMiddlewareMarker)) { return app; } - app.Properties["_AbpExceptionHandlingMiddleware_Added"] = true; + app.Properties[ExceptionHandlingMiddlewareMarker] = true; return app.UseMiddleware(); } + + private static RequestCulture DefaultGetRequestCulture(string defaultLanguage, IReadOnlyList languages) + { + if (defaultLanguage == null) + { + var firstLanguage = languages.First(); + return new RequestCulture(firstLanguage.CultureName, firstLanguage.UiCultureName); + } + + if (!defaultLanguage.Contains(";")) + { + return new RequestCulture(defaultLanguage, defaultLanguage); + } + + var splitted = defaultLanguage.Split(';'); + return new RequestCulture(splitted[0], splitted[1]); + + } } } diff --git a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj index 541e917198..52f7a106da 100644 --- a/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj +++ b/framework/src/Volo.Abp.AspNetCore/Volo.Abp.AspNetCore.csproj @@ -32,6 +32,7 @@ + diff --git a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj index a85af92dc3..81042b0ce8 100644 --- a/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj +++ b/framework/src/Volo.Abp.Localization/Volo.Abp.Localization.csproj @@ -1,4 +1,4 @@ - + @@ -22,7 +22,7 @@ - + diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 9ceaf569ac..51cabbc821 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -1,11 +1,15 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Localization.Resources.AbpValidation; using Volo.Abp.Modularity; +using Volo.Abp.Settings; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Localization { - [DependsOn(typeof(AbpVirtualFileSystemModule))] + [DependsOn( + typeof(AbpVirtualFileSystemModule), + typeof(AbpSettingsModule) + )] public class AbpLocalizationModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) @@ -24,6 +28,11 @@ namespace Volo.Abp.Localization .AddVirtualJson("/Localization/Resources/AbpValidation"); }); + context.Services.Configure(options => + { + options.DefinitionProviders.Add(); + }); + context.Services.AddAssemblyOf(); } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptions.cs index fd79a1ffb2..ea5232bb04 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptions.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationOptions.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Collections; +using System.Collections.Generic; +using Volo.Abp.Collections; namespace Volo.Abp.Localization { @@ -8,10 +9,13 @@ namespace Volo.Abp.Localization public ITypeList GlobalContributors { get; } + public List Languages { get; } + public AbpLocalizationOptions() { Resources = new LocalizationResourceDictionary(); GlobalContributors = new TypeList(); + Languages = new List(); } } } diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DefaultLanguageProvider.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DefaultLanguageProvider.cs new file mode 100644 index 0000000000..23af572fd0 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/DefaultLanguageProvider.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Localization +{ + public class DefaultLanguageProvider : ILanguageProvider, ITransientDependency + { + protected AbpLocalizationOptions Options { get; } + + public DefaultLanguageProvider(IOptions options) + { + Options = options.Value; + } + + public Task> GetLanguagesAsync() + { + return Task.FromResult((IReadOnlyList)Options.Languages); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILanguageProvider.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILanguageProvider.cs new file mode 100644 index 0000000000..e3e32114f0 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/ILanguageProvider.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Volo.Abp.Localization +{ + public interface ILanguageProvider + { + Task> GetLanguagesAsync(); + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs new file mode 100644 index 0000000000..05c243f92c --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageInfo.cs @@ -0,0 +1,48 @@ +using System; +using JetBrains.Annotations; + +namespace Volo.Abp.Localization +{ + public class LanguageInfo + { + [NotNull] + public virtual string CultureName { get; protected set; } + + [NotNull] + public virtual string UiCultureName { get; protected set; } + + [NotNull] + public virtual string DisplayName { get; protected set; } + + [CanBeNull] + public virtual string FlagIcon { get; set; } + + public LanguageInfo( + string cultureName, + string uiCultureName = null, + string displayName = null, + string flagIcon = null) + { + ChangeCultureInternal(cultureName, uiCultureName, displayName); + FlagIcon = flagIcon; + } + + public virtual void ChangeCulture(string cultureName, string uiCultureName = null, string displayName = null) + { + ChangeCultureInternal(cultureName, uiCultureName, displayName); + } + + private void ChangeCultureInternal(string cultureName, string uiCultureName, string displayName) + { + CultureName = Check.NotNullOrWhiteSpace(cultureName, nameof(cultureName)); + + UiCultureName = !uiCultureName.IsNullOrWhiteSpace() + ? uiCultureName + : cultureName; + + DisplayName = !displayName.IsNullOrWhiteSpace() + ? displayName + : cultureName; + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageProviderExtensions.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageProviderExtensions.cs new file mode 100644 index 0000000000..5c7ffe6508 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LanguageProviderExtensions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Volo.Abp.Threading; + +namespace Volo.Abp.Localization +{ + public static class LanguageProviderExtensions + { + public static IReadOnlyList GetLanguages(this ILanguageProvider languageProvider) + { + return AsyncHelper.RunSync(() => languageProvider.GetLanguagesAsync()); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingNames.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingNames.cs new file mode 100644 index 0000000000..1b53f8c3bb --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingNames.cs @@ -0,0 +1,7 @@ +namespace Volo.Abp.Localization +{ + public static class LocalizationSettingNames + { + public const string DefaultLanguage = "Abp.Localization.DefaultLanguage"; + } +} diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs new file mode 100644 index 0000000000..c748156506 --- /dev/null +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationSettingProvider.cs @@ -0,0 +1,14 @@ +using Volo.Abp.Settings; + +namespace Volo.Abp.Localization +{ + public class LocalizationSettingProvider : SettingDefinitionProvider + { + public override void Define(ISettingDefinitionContext context) + { + context.Add( + new SettingDefinition(LocalizationSettingNames.DefaultLanguage, "en", isVisibleToClients: true) + ); + } + } +} \ No newline at end of file