Skip to content

Commit

Permalink
Add SupportedCultures and DefaultCulture (#16968)
Browse files Browse the repository at this point in the history
Co-authored-by: Hisham Bin Ateya <[email protected]>
  • Loading branch information
sebastienros and hishamco authored Nov 8, 2024
1 parent 64e03ce commit dbc81b8
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace OrchardCore.DisplayManagement.Liquid.Filters;

[Obsolete("This filter is obsolete and will be removed in a future version. Use 'Culture.SupportedCultures' instead.")]
public class SupportedCulturesFilter : ILiquidFilter
{
private readonly ILocalizationService _localizationService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static OrchardCoreBuilder AddLiquidViews(this OrchardCoreBuilder builder)
services.AddScoped<IRazorViewExtensionProvider, LiquidViewExtensionProvider>();
services.AddSingleton<LiquidTagHelperFactory>();
#pragma warning disable CS0618 // Type or member is obsolete
services.Configure<TemplateOptions>(o =>
{
o.ValueConverters.Add(x =>
Expand All @@ -67,7 +68,6 @@ public static OrchardCoreBuilder AddLiquidViews(this OrchardCoreBuilder builder)
o.MemberAccessStrategy.Register<Shape>("*", new ShapeAccessor());
o.MemberAccessStrategy.Register<ZoneHolding>("*", new ShapeAccessor());
o.MemberAccessStrategy.Register<ShapeMetadata>();
o.MemberAccessStrategy.Register<CultureInfo>();
o.Scope.SetValue("Culture", new CultureValue());
Expand Down Expand Up @@ -163,7 +163,10 @@ public static OrchardCoreBuilder AddLiquidViews(this OrchardCoreBuilder builder)
.AddLiquidFilter<AppendVersionFilter>("append_version")
.AddLiquidFilter<ResourceUrlFilter>("resource_url")
.AddLiquidFilter<SanitizeHtmlFilter>("sanitize_html")
// Deprecated, remove in a future version.
.AddLiquidFilter<SupportedCulturesFilter>("supported_cultures");
#pragma warning restore CS0618 // Type or member is obsolete
});

return builder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,39 @@
using System.Text.Encodings.Web;
using Fluid;
using Fluid.Values;
using Microsoft.Extensions.DependencyInjection;
using OrchardCore.Liquid;
using OrchardCore.Localization;

namespace OrchardCore.DisplayManagement.Liquid.Values;

internal sealed class CultureValue : FluidValue
{
// When null it means this is the global "Culture" object that represents the current UI culture.
private readonly CultureInfo _culture;

private CultureInfo Culture => _culture ?? CultureInfo.CurrentUICulture;

public override FluidValues Type => FluidValues.Object;

/// <summary>
/// Creates a new instance of a <see cref="CultureValue"/> that uses <see cref="CultureInfo.CurrentUICulture"/> when resolved.
/// </summary>
public CultureValue()
{
_culture = null;
}

/// <summary>
/// Creates a new instance of a <see cref="CultureValue"/> for the specified culture.
/// </summary>
public CultureValue(CultureInfo culture)
{
ArgumentNullException.ThrowIfNull(culture);

_culture = culture;
}

public override bool Equals(FluidValue other)
{
if (other is null)
Expand All @@ -24,26 +49,53 @@ public override bool Equals(FluidValue other)

public override decimal ToNumberValue() => 0;

public override object ToObjectValue() => ToStringValue();
public override object ToObjectValue() => Culture;

public override string ToStringValue() => CultureInfo.CurrentUICulture.Name;
public override string ToStringValue() => Culture.Name;

#pragma warning disable CS0672 // Member overrides obsolete member
public override void WriteTo(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
#pragma warning restore CS0672 // Member overrides obsolete member
=> writer.Write(ToStringValue());
=> writer.Write(Culture.Name);

public async override ValueTask WriteToAsync(TextWriter writer, TextEncoder encoder, CultureInfo cultureInfo)
=> await writer.WriteAsync(CultureInfo.CurrentUICulture.Name);
=> await writer.WriteAsync(Culture.Name);

protected override FluidValue GetValue(string name, TemplateContext context)
=> name switch
public override ValueTask<FluidValue> GetValueAsync(string name, TemplateContext context)
{
return name switch
{
nameof(CultureInfo.Name) => new StringValue(CultureInfo.CurrentUICulture.Name),
"Dir" => new StringValue(CultureInfo.CurrentUICulture.GetLanguageDirection()),
nameof(CultureInfo.NativeName) => new StringValue(CultureInfo.CurrentUICulture.NativeName),
nameof(CultureInfo.DisplayName) => new StringValue(CultureInfo.CurrentUICulture.DisplayName),
nameof(CultureInfo.TwoLetterISOLanguageName) => new StringValue(CultureInfo.CurrentUICulture.TwoLetterISOLanguageName),
_ => NilValue.Instance
nameof(CultureInfo.Name) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.Name)),
nameof(CultureInfo.NativeName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.NativeName)),
nameof(CultureInfo.DisplayName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.DisplayName)),
nameof(CultureInfo.TwoLetterISOLanguageName) => ValueTask.FromResult<FluidValue>(new StringValue(Culture.TwoLetterISOLanguageName)),
"Dir" => ValueTask.FromResult<FluidValue>(new StringValue(Culture.GetLanguageDirection())),
"SupportedCultures" => _culture is null ? GetSupportedCulturesAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),
"DefaultCulture" => _culture is null ? GetDefaultCultureAsync(context) : ValueTask.FromResult<FluidValue>(NilValue.Instance),
_ => ValueTask.FromResult<FluidValue>(NilValue.Instance)
};
}

private static async ValueTask<FluidValue> GetSupportedCulturesAsync(TemplateContext context)
{
var ctx = context as LiquidTemplateContext
?? throw new InvalidOperationException($"An implementation of '{nameof(LiquidTemplateContext)}' is required");

var services = ctx.Services;
var localizationService = services.GetRequiredService<ILocalizationService>();
var supportedCultures = await localizationService.GetSupportedCulturesAsync();

return new ArrayValue(supportedCultures.Select(c => new CultureValue(CultureInfo.GetCultureInfo(c))).ToArray());
}

private static async ValueTask<FluidValue> GetDefaultCultureAsync(TemplateContext context)
{
var ctx = context as LiquidTemplateContext
?? throw new InvalidOperationException($"An implementation of '{nameof(LiquidTemplateContext)}' is required");

var services = ctx.Services;
var localizationService = services.GetRequiredService<ILocalizationService>();

return new CultureValue(CultureInfo.GetCultureInfo(await localizationService.GetDefaultCultureAsync()));
}
}
11 changes: 6 additions & 5 deletions src/docs/reference/modules/Liquid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,16 +509,17 @@ The following properties are available on the `Culture` object.
| `DisplayName` | `English (United States)` | The display name of the current culture. |
| `NativeName` | `English (United States)` | The native name of the current culture. |
| `TwoLetterISOLanguageName` | `en` | The two-letter ISO language name of the current culture. |
| `SupportedCultures` | `['en-US', 'fr' ]` | The list of the currently supported cultures in the site. Each result can be chained with other properties listed in this table. |
| `DefaultCulture` | `en-US` | The default culture as defined in the settings. |

##### supported_cultures filter
##### Usage

Returns the currently supported cultures. Here is an example of how to print the names of supported cultures using a list:
Here is an example of how to print the names of supported cultures and find which one is currently used:

```liquid
{% assign cultures = Culture | supported_cultures %}
<ul>
{% for culture in cultures %}
<li>{{ culture.Name }}</li>
{% for culture in Culture.SupportedCultures %}
<li class="{% if culture == Culture %}active{% endif %}">{{ culture.Name }}</li>
{% endfor %}
</ul>
```
Expand Down

0 comments on commit dbc81b8

Please sign in to comment.