Merge pull request #967 from hishamco/language-switcher
Add Language switcher
This commit is contained in:
commit
1968b0283d
@ -17,6 +17,7 @@
|
|||||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v2.0.0</PackageReleaseNotes>
|
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v2.0.0</PackageReleaseNotes>
|
||||||
<RootNamespace>Oqtane</RootNamespace>
|
<RootNamespace>Oqtane</RootNamespace>
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
|
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -30,6 +31,7 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.0" PrivateAssets="all" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="5.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Localization" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -1,19 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Localization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.JSInterop;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Providers;
|
using Oqtane.Providers;
|
||||||
using Oqtane.Shared;
|
|
||||||
using Oqtane.Services;
|
using Oqtane.Services;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.UI;
|
||||||
|
|
||||||
namespace Oqtane.Client
|
namespace Oqtane.Client
|
||||||
{
|
{
|
||||||
@ -62,6 +66,7 @@ namespace Oqtane.Client
|
|||||||
builder.Services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
builder.Services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
||||||
builder.Services.AddScoped<ISqlService, SqlService>();
|
builder.Services.AddScoped<ISqlService, SqlService>();
|
||||||
builder.Services.AddScoped<ISystemService, SystemService>();
|
builder.Services.AddScoped<ISystemService, SystemService>();
|
||||||
|
builder.Services.AddScoped<ILocalizationService, LocalizationService>();
|
||||||
|
|
||||||
await LoadClientAssemblies(httpClient);
|
await LoadClientAssemblies(httpClient);
|
||||||
|
|
||||||
@ -88,6 +93,19 @@ namespace Oqtane.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
var host = builder.Build();
|
var host = builder.Build();
|
||||||
|
var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
|
||||||
|
var interop = new Interop(jsRuntime);
|
||||||
|
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
||||||
|
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie).UICultures[0].Value;
|
||||||
|
var localizationService = host.Services.GetRequiredService<ILocalizationService>();
|
||||||
|
var cultures = await localizationService.GetCulturesAsync();
|
||||||
|
|
||||||
|
if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
culture = cultures.Single(c => c.IsDefault).Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetCulture(culture);
|
||||||
|
|
||||||
ServiceActivator.Configure(host.Services);
|
ServiceActivator.Configure(host.Services);
|
||||||
|
|
||||||
@ -142,5 +160,12 @@ namespace Oqtane.Client
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SetCulture(string culture)
|
||||||
|
{
|
||||||
|
var cultureInfo = CultureInfo.GetCultureInfo(culture);
|
||||||
|
CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
|
||||||
|
CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
11
Oqtane.Client/Services/Interfaces/ILocalizationService.cs
Normal file
11
Oqtane.Client/Services/Interfaces/ILocalizationService.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
public interface ILocalizationService
|
||||||
|
{
|
||||||
|
Task<IEnumerable<Culture>> GetCulturesAsync();
|
||||||
|
}
|
||||||
|
}
|
22
Oqtane.Client/Services/LocalizationService.cs
Normal file
22
Oqtane.Client/Services/LocalizationService.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Services
|
||||||
|
{
|
||||||
|
public class LocalizationService : ServiceBase, ILocalizationService
|
||||||
|
{
|
||||||
|
private readonly SiteState _siteState;
|
||||||
|
|
||||||
|
public LocalizationService(HttpClient http, SiteState siteState) : base(http)
|
||||||
|
{
|
||||||
|
_siteState = siteState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Apiurl => CreateApiUrl(_siteState.Alias, "Localization");
|
||||||
|
|
||||||
|
public async Task<IEnumerable<Culture>> GetCulturesAsync() => await GetJsonAsync<IEnumerable<Culture>>(Apiurl);
|
||||||
|
}
|
||||||
|
}
|
@ -198,6 +198,8 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<LanguageSwitcher />
|
||||||
|
|
||||||
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) || (PageState.Page.IsPersonalizable && PageState.User != null))
|
@if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.Permissions) || (PageState.Page.IsPersonalizable && PageState.User != null))
|
||||||
{
|
{
|
||||||
if (PageState.EditMode)
|
if (PageState.EditMode)
|
||||||
|
46
Oqtane.Client/Themes/Controls/LanguageSwitcher.razor
Normal file
46
Oqtane.Client/Themes/Controls/LanguageSwitcher.razor
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
@namespace Oqtane.Themes.Controls
|
||||||
|
@inherits ThemeControlBase
|
||||||
|
@using System.Globalization
|
||||||
|
@using Microsoft.AspNetCore.Localization;
|
||||||
|
@using Oqtane.Models
|
||||||
|
@inject ILocalizationService LocalizationService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
@if (_supportedCultures != null && Visible)
|
||||||
|
{
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<button id="btnCultures" type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="oi oi-globe"></span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu" aria-labelledby="btnCultures">
|
||||||
|
@foreach (var culture in _supportedCultures)
|
||||||
|
{
|
||||||
|
<a class="dropdown-item @(CultureInfo.CurrentUICulture.Name == culture.Name ? "active" : String.Empty)" href="#" @onclick="@(async e => await SetCultureAsync(culture.Name))">@culture.DisplayName</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@code{
|
||||||
|
private IEnumerable<Culture> _supportedCultures;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool Visible { get; set; } = true;
|
||||||
|
|
||||||
|
protected override async Task OnParametersSetAsync()
|
||||||
|
{
|
||||||
|
_supportedCultures = await LocalizationService.GetCulturesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SetCultureAsync(string culture)
|
||||||
|
{
|
||||||
|
if (culture != CultureInfo.CurrentUICulture.Name)
|
||||||
|
{
|
||||||
|
var interop = new Interop(JSRuntime);
|
||||||
|
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture));
|
||||||
|
await interop.SetCookie(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue, 360);
|
||||||
|
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using Oqtane.Models;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Oqtane.UI
|
namespace Oqtane.UI
|
||||||
@ -233,6 +232,5 @@ namespace Oqtane.UI
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
Oqtane.Server/Controllers/LocalizationController.cs
Normal file
32
Oqtane.Server/Controllers/LocalizationController.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
|
namespace Oqtane.Controllers
|
||||||
|
{
|
||||||
|
[Route(ControllerRoutes.Default)]
|
||||||
|
public class LocalizationController : Controller
|
||||||
|
{
|
||||||
|
private readonly ILocalizationManager _localizationManager;
|
||||||
|
|
||||||
|
public LocalizationController(ILocalizationManager localizationManager)
|
||||||
|
{
|
||||||
|
_localizationManager = localizationManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET: api/localization
|
||||||
|
[HttpGet()]
|
||||||
|
public IEnumerable<Culture> Get()
|
||||||
|
=> _localizationManager.GetSupportedCultures().Select(c => new Culture {
|
||||||
|
Name = CultureInfo.GetCultureInfo(c).Name,
|
||||||
|
DisplayName = CultureInfo.GetCultureInfo(c).DisplayName,
|
||||||
|
IsDefault = _localizationManager.GetDefaultCulture()
|
||||||
|
.Equals(CultureInfo.GetCultureInfo(c).Name, StringComparison.OrdinalIgnoreCase)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
@ -31,11 +30,9 @@ namespace Oqtane.Extensions
|
|||||||
var defaultCulture = localizationManager.GetDefaultCulture();
|
var defaultCulture = localizationManager.GetDefaultCulture();
|
||||||
var supportedCultures = localizationManager.GetSupportedCultures();
|
var supportedCultures = localizationManager.GetSupportedCultures();
|
||||||
|
|
||||||
CultureInfo.CurrentUICulture = new CultureInfo(defaultCulture);
|
|
||||||
|
|
||||||
app.UseRequestLocalization(options => {
|
app.UseRequestLocalization(options => {
|
||||||
options.SetDefaultCulture(defaultCulture)
|
options.SetDefaultCulture(defaultCulture)
|
||||||
.AddSupportedUICultures(supportedCultures)
|
.AddSupportedCultures(supportedCultures)
|
||||||
.AddSupportedUICultures(supportedCultures);
|
.AddSupportedUICultures(supportedCultures);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@namespace Oqtane.Pages
|
@namespace Oqtane.Pages
|
||||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
@using System.Globalization
|
|
||||||
@using Microsoft.AspNetCore.Localization
|
|
||||||
@using Microsoft.Extensions.Configuration
|
@using Microsoft.Extensions.Configuration
|
||||||
@inject IConfiguration Configuration
|
@inject IConfiguration Configuration
|
||||||
@model Oqtane.Pages.HostModel
|
@model Oqtane.Pages.HostModel
|
||||||
|
|
||||||
@{
|
|
||||||
// Set localization cookie
|
|
||||||
var localizationCookieValue = CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture));
|
|
||||||
HttpContext.Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, localizationCookieValue);
|
|
||||||
}
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
@ -127,6 +127,7 @@ namespace Oqtane
|
|||||||
services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
services.AddScoped<ISiteTemplateService, SiteTemplateService>();
|
||||||
services.AddScoped<ISqlService, SqlService>();
|
services.AddScoped<ISqlService, SqlService>();
|
||||||
services.AddScoped<ISystemService, SystemService>();
|
services.AddScoped<ISystemService, SystemService>();
|
||||||
|
services.AddScoped<ILocalizationService, LocalizationService>();
|
||||||
|
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
11
Oqtane.Shared/Models/Culture.cs
Normal file
11
Oqtane.Shared/Models/Culture.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace Oqtane.Models
|
||||||
|
{
|
||||||
|
public class Culture
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
|
||||||
|
public bool IsDefault { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user