Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Localization settings #13181

Merged
merged 48 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
249482d
User Localization settings
Skrypt Jan 31, 2023
78156fd
React to comment
Skrypt Jan 31, 2023
b8974b9
Something that works
Skrypt Jan 31, 2023
4ed3b3b
await NullProviderCultureResult;
Skrypt Jan 31, 2023
2b9b926
return default
Skrypt Feb 1, 2023
4260675
Set the user default culture to the localization default culture if n…
hishamco Jan 12, 2024
619834f
Set the user default time zone to the site settings default time zone…
hishamco Jan 12, 2024
1a9d823
UserLocalizationStartup -> Startup
hishamco Jan 12, 2024
125f7be
Refactoring
hishamco Jan 12, 2024
357fe3a
UserTimeZoneStartup -> Startup
hishamco Jan 12, 2024
e582c31
Refactoring
hishamco Jan 12, 2024
cbb4d6f
Use file-scope namespace
hishamco Jan 12, 2024
15e3a77
Add TimeZones to UserTimeZoneViewModel
hishamco Jan 12, 2024
7a38792
Remove extra whitespace
hishamco Jan 12, 2024
f6f789b
Merge branch 'main' into skrypt/admin-user-localization-setting
Piedone Jan 14, 2024
245bc8b
Add release note
hishamco Jan 15, 2024
a599188
Fix indentation
hishamco Jan 15, 2024
376b00a
Refactoring
hishamco Jan 15, 2024
a103b5f
CultureClaimType as constant
hishamco Jan 15, 2024
2a04a1b
Add comment on ConfigureOrder
hishamco Jan 15, 2024
64102fd
Add GetCulture() extension method
hishamco Jan 15, 2024
362e1a5
Address the feedback
hishamco Jan 15, 2024
6fc7e32
Remove unnecessary Configure() method
hishamco Jan 16, 2024
4d5cd8b
Set the configuration order on OrchardCore.Users.Localization
hishamco Jan 16, 2024
f6da84b
Remove ConfigureOrder from OrchardCore.Users.Localization
hishamco Jan 16, 2024
2b6a88a
Revert changes from OC.Localization
hishamco Jan 16, 2024
98eba6d
Merge branch 'main' into skrypt/admin-user-localization-setting
hishamco Jan 19, 2024
69f1afa
Merge branch 'main' into skrypt/admin-user-localization-setting
hishamco Jan 23, 2024
f7436d5
Set the User Localization feature priority
hishamco Jan 23, 2024
67afc77
Fix issue with default culture not selected
Skrypt Jan 25, 2024
265f94b
Merge branch 'main' into skrypt/admin-user-localization-setting
Skrypt Jan 25, 2024
7df0224
Revert Timezone changes
Skrypt Jan 25, 2024
089b172
Revert changes timezone
Skrypt Jan 25, 2024
a835a88
Simplify
Skrypt Jan 26, 2024
6ace93d
cleanup using
Skrypt Jan 26, 2024
839721b
Try to support Invariant Culture
Skrypt Jan 29, 2024
9d397fb
Merge branch 'main' into skrypt/admin-user-localization-setting
Skrypt Jan 29, 2024
f50d427
Support InvariatCulture
Skrypt Jan 30, 2024
d90704d
Constants
Skrypt Jan 30, 2024
0eb60da
Merge branch 'main' into skrypt/admin-user-localization-setting
Skrypt Jan 30, 2024
6cfc324
Update src/docs/releases/1.9.0.md
Skrypt Feb 1, 2024
98f21f4
Constants => UserLocalizationConstants
Skrypt Feb 1, 2024
2714dc2
Merge branch 'skrypt/admin-user-localization-setting' of https://gith…
Skrypt Feb 1, 2024
979584e
Add doc
Skrypt Feb 1, 2024
f64587c
Merge branch 'main' into skrypt/admin-user-localization-setting
Skrypt Feb 12, 2024
1eff31d
Update src/docs/reference/modules/Users/README.md
Skrypt Feb 12, 2024
3b986b1
Update src/OrchardCore.Modules/OrchardCore.Users/Localization/ViewMod…
Skrypt Feb 12, 2024
bf7246c
Update src/OrchardCore.Modules/OrchardCore.Users/Localization/Drivers…
Skrypt Feb 12, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace OrchardCore.Users.Localization
{
public static class Constants
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
{
public const string Invariant = "invariant";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Localization;
using OrchardCore.DisplayManagement.Entities;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.ModelBinding;
Expand All @@ -16,10 +17,14 @@ namespace OrchardCore.Users.Localization.Drivers;
public class UserLocalizationDisplayDriver : SectionDisplayDriver<User, UserLocalizationSettings>
{
private readonly ILocalizationService _localizationService;
protected readonly IStringLocalizer S;

public UserLocalizationDisplayDriver(ILocalizationService localizationService)
public UserLocalizationDisplayDriver(
ILocalizationService localizationService,
IStringLocalizer<UserLocalizationDisplayDriver> localizer)
{
_localizationService = localizationService;
S = localizer;
}

public override Task<IDisplayResult> EditAsync(UserLocalizationSettings section, BuildEditorContext context)
Expand All @@ -28,13 +33,23 @@ public override Task<IDisplayResult> EditAsync(UserLocalizationSettings section,
{
var supportedCultures = await _localizationService.GetSupportedCulturesAsync();

model.Culture = section.Culture;
model.SupportedCultures = supportedCultures.Select(culture =>
var cultureList = supportedCultures.Select(culture =>
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
new SelectListItem
{
Text = CultureInfo.GetCultureInfo(culture).DisplayName + " (" + culture + ")",
Value = culture
});
}).ToList();

cultureList.Insert(0, new SelectListItem() { Text = S["Use site's culture"], Value = "none" });

// If Invariant Culture is installed as a supported culture we bind it to a different culture code than String.Empty.
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
if (cultureList.Where(c => c.Value == "").Any())
{
cultureList.Where(c => c.Value == "").FirstOrDefault().Value = Constants.Invariant;
}

model.SelectedCulture = section.Culture;
model.CultureList = cultureList;
}).Location("Content:2"));
}

Expand All @@ -44,7 +59,7 @@ public override async Task<IDisplayResult> UpdateAsync(User model, UserLocalizat

if (await context.Updater.TryUpdateModelAsync(viewModel, Prefix))
{
section.Culture = viewModel.Culture;
section.Culture = viewModel.SelectedCulture;
}

return await EditAsync(section, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public Task GenerateAsync(IUser user, ClaimsIdentity claims)
{
var localizationSetting = currentUser.As<UserLocalizationSettings>();

if (!string.IsNullOrEmpty(localizationSetting.Culture))
if (localizationSetting.Culture != "none")
{
claims.AddClaim(new Claim(CultureClaimType, localizationSetting.Culture));
claims.AddClaim(new Claim(CultureClaimType, localizationSetting.Culture == Constants.Invariant ? "" : localizationSetting.Culture));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpC
return NullProviderCultureResult;
}

var userCulture = httpContext.User.GetCulture();
var userCulture = httpContext.User.GetCulture(); // String.Empty here means that it did not find the Culture Claim.

if (string.IsNullOrWhiteSpace(userCulture))
if (String.IsNullOrWhiteSpace(userCulture))
{
return NullProviderCultureResult;
}

return Task.FromResult(new ProviderCultureResult(userCulture));
return Task.FromResult(new ProviderCultureResult(userCulture == Constants.Invariant ? "" : userCulture));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace OrchardCore.Users.Localization.ViewModels;

public class UserLocalizationViewModel
{
public string Culture { get; set; }
public string SelectedCulture { get; set; }

[BindNever]
public IEnumerable<SelectListItem> SupportedCultures { get; set; } = new List<SelectListItem>();
public IEnumerable<SelectListItem> CultureList { get; set; } = new List<SelectListItem>();
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
}
2 changes: 1 addition & 1 deletion src/OrchardCore.Modules/OrchardCore.Users/Manifest.cs
hishamco marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
Description = "Provides a way to set the culture per user.",
Dependencies = new[] { "OrchardCore.Users", "OrchardCore.Localization" },
Category = "Settings",
Priority = "-1"
Priority = "-1" // Added to avoid changing the order in the localization module.
)]

[assembly: Feature(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
@using OrchardCore.Users.Localization.ViewModels
@model UserLocalizationViewModel

<div class="mb-3" asp-validation-class-for="Culture">
<label asp-for="Culture">@T["Default User Culture"]</label>
<select asp-for="Culture" asp-items="Model.SupportedCultures" class="form-select">
<option value="">@T["Use site's culture"]</option>
<div class="mb-3" asp-validation-class-for="SelectedCulture">
<label asp-for="SelectedCulture">@T["Default User Culture"]</label>
<select asp-for="SelectedCulture" asp-items="Model.CultureList" class="form-select">
</select>
<span asp-validation-for="Culture"></span>
<span asp-validation-for="SelectedCulture"></span>
<span class="hint">@T["Determines the default culture used by this user."]</span>
</div>
57 changes: 57 additions & 0 deletions src/docs/releases/1.9.0.md
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,63 @@ Added new extensions to make registering custom deployment step easier
- services.AddDeployment<TSource, TStep, TDisplayDriver>();
- services.AddDeploymentWithoutSource<TStep, TDisplayDriver>();

### GraphQL Module

When identifying content types for GraphQL exposure, we identify those without a stereotype to provide you with control over the behavior of stereotyped content types. A new option, `DiscoverableSterotypes`, has been introduced in `GraphQLContentOptions`. This allows you to specify stereotypes that should be discoverable by default.

For instance, if you have several content types stereotyped as `ExampleStereotype`, you can make them discoverable by incorporating the following code into the startup class:

```csharp
services.Configure<GraphQLContentOptions>(options =>
{
options.DiscoverableSterotypes.Add("ExampleStereotype");
});
```

### Admin

The admin menu has undergone performance enhancements, and new helpers have been added. When incorporating `INavigationProvider` in your project, you can now utilize `NavigationHelper.IsAdminMenu(name)` instead of the previous approach using `string.Equals(name, "admin", StringComparison.OrdinalIgnoreCase)`. Moreover, when passing route values to an action, it is advised to store them in a constant variable. An illustrative example is provided below.
```
public class AdminMenu : INavigationProvider
{
private static readonly RouteValueDictionary _routeValues = new()
{
{ "area", "OrchardCore.Settings" },
{ "groupId", AdminSiteSettingsDisplayDriver.GroupId },
};

protected readonly IStringLocalizer S;

public AdminMenu(IStringLocalizer<AdminMenu> stringLocalizer)
{
S = stringLocalizer;
}

public Task BuildNavigationAsync(string name, NavigationBuilder builder)
{
if (!NavigationHelper.IsAdminMenu(name))
{
return Task.CompletedTask;
}

builder
.Add(S["Configuration"], configuration => configuration
.Add(S["Settings"], settings => settings
.Add(S["Admin"], S["Admin"].PrefixPosition(), admin => admin
.AddClass("admin")
.Id("admin")
.Action("Index", "Admin", _routeValues)
.Permission(PermissionsAdminSettings.ManageAdminSettings)
.LocalNav()
)
)
);

return Task.CompletedTask;
}
}
```

## Users Module

Added new user localization feature that allows to set default culture per user in the admin UI.
Skrypt marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
Loading