Multiple Umbraco deployments - override the defaul...
# help-with-umbraco
c
I have a system running with two deployments, one in an English speaking region and another in a Chinese speaking region. They are now both running from the same database (Thanks to @Sebastiaan for his advice on that) I have both English and Chinese variants setup, when I go to the website in the English location it shows english, but when I go to the Chinese region I want it to display in Chinese, is there a way I can override the default language via configuration? Im currently only running a home page, I have the English on
/
and the Chinese on
/zh/
I probably need to have the enflish on
/en/
and setup a redirect (some how) to the correct language, Im running the sites in Azure Webapps currently. Does anyone have any advice on how to achieve the above?
I should add that right now I'm doing it with middleware, this is possibly not the best resolution, and Id assume there is a better option:
Copy code
csharp
public class LanguageRedirectMiddleware(RequestDelegate next, IConfiguration configuration)
{
    private readonly string? _defaultSiteLanguage = configuration["DefaultSiteLanguage"];

    public async Task InvokeAsync(HttpContext context)
    {
        var path = context.Request.Path.Value;

        // Check for root path
        if (string.IsNullOrEmpty(path) || path == "/")
        {
            // Use the default site language from configuration
            var newPath = $"/{_defaultSiteLanguage}";

            // Redirect to the new path
            context.Response.Redirect(newPath);
            return;
        }

        // Continue to the next middleware
        await next(context);
    }
}
m
You could override Umbraco's default controller, on my phone so can't anchor down but it's the last section of https://docs.umbraco.com/umbraco-cms/reference/routing/custom-controllers
As for redirecting by location, if your using cloudflare they send CF-IPCountry header so you could use that to workout the redirection https://developers.cloudflare.com/fundamentals/reference/http-request-headers/#cf-ipcountry Otherwise something like https://www.nuget.org/packages/MaxMind.GeoIP2/#readme-body-tab to do the lookup yourself is an option.
c
thanks, I extended the middleware and it screwed with the backoffice but that seems to be working nicely now, I did think about cloudflare as the redirecting but wasnt sure if I should go with that or with frontdoor
m
How are you registering your middleware? Assuming you want to keep using that over the controller option, as you can it up to ignore /umbraco
Yeah FrontDoor or CF make way more sense than coding it in
c
so Ive updated the middleware and its as below now, I like the middleware option as its "just works" and doesnt need a lot of maintainung, I was hopeful that I didnt need it and umbraco had something for this out of the box that I didn't know about. I need frontdoor or CF because the website frontend is hosted in different regions, which is a requirement handed down to me for the project, so in the MVP I'm just running two locations. I haven't put any distribution facility like CF in yet its too early in the project to worry about that too much 🙂 I'm sure I'll hit on some more snags with this as the project progresses and I'll have to add some other 'ignored routes' but for now it works. Im invoking the middleware using:
app.UseMiddleware<LanguageRedirectMiddleware>();
Copy code
using Umbraco.Cms.Core.Services;

public class LanguageRedirectMiddleware
{
    private readonly RequestDelegate _next;
    private readonly string? _defaultSiteLanguage;
    private readonly ILocalizationService _localizationService;
    private readonly string[] _supportedLanguages;

    public LanguageRedirectMiddleware(RequestDelegate next, IConfiguration configuration, ILocalizationService localizationService)
    {
        _next = next;
        _defaultSiteLanguage = configuration["DefaultSiteLanguage"];
        _localizationService = localizationService;
        _supportedLanguages = GetSupportedLanguages();
    }

    private string[] GetSupportedLanguages()
    {
        var languages = _localizationService.GetAllLanguages().Select(lang => lang.IsoCode.ToLower()).ToArray();
        return languages;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        var path = context.Request.Path.Value?.ToLower();

        if (path is null or "/")
        {
            // Use the default site language from configuration
            var newPath = $"/{_defaultSiteLanguage}";

            // Redirect to the new path
            context.Response.Redirect(newPath);
            return;
        }
        
        // Check if the request path has a file extension
        if (path.StartsWith("/umbraco", StringComparison.CurrentCultureIgnoreCase) || path.Contains('.') && !path.EndsWith("/"))
        {
            // Continue to the next middleware without redirecting
            await _next(context);
            return;
        }
        
        // Check if the path does not start with any supported language prefix
        if (!_supportedLanguages.Any(lang => path.StartsWith($"/{lang.ToLower()}", StringComparison.CurrentCultureIgnoreCase)))
        {
            // Construct the new path based on the default language
            var newPath = $"/{_defaultSiteLanguage}{path}";

            // Redirect to the new path
            context.Response.Redirect(newPath);
            return;
        }

        // Continue to the next middleware
        await _next(context);
    }
}
m
If you register it as below (was taking from a postPipeline so might need a tweak) it will only run on Umbraco routed requests avoiding it been run at all on /umbraco
Copy code
c#
options.AddFilter(new UmbracoPipelineFilter(
                "languageRedirect",
                prePipeline: applicationBuilder =>
                {
                    applicationBuilder.UseMiddleware<LanguageRedirectMiddleware>();
                }));
        });
c
would this be done inside a composer?
m
Yeah let me grab the missing bit 😄
Copy code
builder.Services.Configure<UmbracoPipelineOptions>(options =>
        {
c
okay thanks, I'll give that a whirl later and see if it makes things nicer 🙂
3 Views