valdisiljuconoks / localization-provider-opti

Database driven localization provider for Optimizely (ex. Episerver) websites
Apache License 2.0
11 stars 16 forks source link

DBLocalization seems to prevent xml localization for second culture #183

Closed huguesl closed 1 year ago

huguesl commented 1 year ago

Using Optimizely CMS 12, Asp.Net Core 6.

We have DBLocalization working fine in both English and French. XML Localization in English also works well as a fallback, however French localization doesn't work. If DBLocalization init code is commented out in Startup.cs, both English and French xml localization works well.

For some reason, when DBLocalization is used, XML French localization stops working (English xml works fine).

We're trying different configurations of options but nothing seems to get french xml working when DBLocalization is used.

Has anyone run into this? Thank you

valdisiljuconoks commented 1 year ago

Hi,

Can you share you setup code? So you have both - db and xml files, right?

huguesl commented 1 year ago

Hi, Yes, we're trying to get DB and xml working together, xml as fallback default values. DBLocalization works fine, but seems to be interfering with xml. When db localization is enabled in Startup, only the english xml culture works, french stops working for some reason. Here's our Startup code, there's a lot there but we keep localization options to a minimum, at the very bottom:

I added services.AddLocalization to see if it would help but it doesn't make a difference. Tried several different options for DBLocalizationProvider but nothing seemed to solve the issue.

public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<DataAccessOptions>(options => options.ConnectionStrings.Add(new ConnectionStringOptions
            {
                Name = "EcfSqlConnection",
                ConnectionString = _configuration.GetConnectionString("EcfSqlConnection")
            }));
            services.AddCmsAspNetIdentity<SiteUser>(o =>
            {
                if (string.IsNullOrEmpty(o.ConnectionStringOptions?.ConnectionString))
                {
                    o.ConnectionStringOptions = new ConnectionStringOptions
                    {
                        Name = "EcfSqlConnection",
                        ConnectionString = _configuration.GetConnectionString("EcfSqlConnection")
                    };
                }
            });
        //UI
        if (_webHostingEnvironment.IsDevelopment())
        {
            services.Configure<ClientResourceOptions>(uiOptions =>
            {
                uiOptions.Debug = true;
            });
        }

        var useAzureBlob = _configuration.GetValue<bool>("EPiServer:Cms:AzureBlobProvider:Active");

        if (useAzureBlob)
        {
            services.AddAzureBlobProvider(o =>
            {
                o.ConnectionString = _configuration.GetValue<string>("EPiServer:Cms:AzureBlobProvider:ConnectionString");
                o.ContainerName = _configuration.GetValue<string>("EPiServer:Cms:AzureBlobProvider:ContainerName");
            });
        }

        services.AddMvc(o =>
        {
            o.Conventions.Add(new FeatureConvention());
            o.ModelBinderProviders.Insert(0, new DecimalModelBinderProvider());
            o.ModelBinderProviders.Insert(0, new PaymentModelBinderProvider());
        })
        .AddRazorOptions(ro => ro.ViewLocationExpanders.Add(new FeatureViewLocationExpander()));

        services.AddAadServices(_configuration);

        services.AddCommerce();
        services.AddFind();
        services.AddSocialFramework();
        services.AddDisplay();
        services.TryAddEnumerable(Microsoft.Extensions.DependencyInjection.ServiceDescriptor.Singleton(typeof(IFirstRequestInitializer), typeof(ContentInstaller)));
        services.AddDetection();
        services.AddTinyMceConfiguration();
        services.AddHeadlessServices(_configuration);

        services.AddIntegrationServices();
        services.AddControllersWithViews()
            .AddMvcLocalization()
            .AddNewtonsoftJson(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
            })
            .AddRazorRuntimeCompilation();

        //site specific
        //services.AddEmbeddedLocalization<Startup>();
        services.Configure<OrderOptions>(o => o.DisableOrderDataLocalization = true);

        services.ConfigureContentApiOptions(o =>
        {
            o.EnablePreviewFeatures = true;
            o.IncludeEmptyContentProperties = true;
            o.FlattenPropertyModel = false;
            o.IncludeMasterLanguage = false;

        });

        // Content Definitions API
        services.AddContentDefinitionsApi(options =>
        {
            // Accept anonymous calls
            options.DisableScopeValidation = true;
        });

        // Content Management
        services.AddContentManagementApi(options =>
        {
            // Accept anonymous calls
            options.DisableScopeValidation = true;
        });

        services.AddNotFoundHandler(o => o.UseSqlServer(_configuration.GetConnectionString("EPiServerDB")), policy => policy.RequireRole(Roles.CmsAdmins));
        services.AddOptimizelyNotFoundHandler();
        services.Configure<ProtectedModuleOptions>(x =>
        {
            if (!x.Items.Any(x => x.Name.Equals("CF")))
            {
                x.Items.Add(new ModuleDetails
                {
                    Name = "CF"
                });
            }
        });

        // Don't camelCase Json output -- leave property names unchanged
        services.AddControllers()
            .AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.PropertyNamingPolicy = null;
            });

        // Add ContentManager (currently commented because of a bug in EPiServeR.Labs.ContentManager) Should be fixed when version 1.1.0 is released
        services.AddContentManager();

        // Add BlockEnhancements
        services.AddBlockEnhancements();
        services.Configure<BlockEnhancementsOptions>(options =>
        {
            //var blockEnhancements = new BlockEnhancementsOptions
            options.LocalContentFeatureEnabled = false;
            options.HideForThisFolder = false;
            options.AllowQuickEditOnSharedBlocks = true;
            options.PublishPageWithBlocks = true;
        });

        // Add AdvancedReviews
        services.AddAdvancedReviews();
        services.AddGetaCategories();
        services.AddODPVisitorGroups();

        //Add Localization
        services.AddLocalization(options =>
        {
            options.ResourcesPath = Path.Combine(_webHostingEnvironment.ContentRootPath, "lang");

        });

        services.AddDbLocalizationProvider(options =>
        {
            options.UseSqlServer(_configuration.GetConnectionString("EPiServerDB"));
        }).AddOptimizely();

        services
            .AddDbLocalizationProviderAdminUI(options =>
            {
                options.UseAvailableLanguageListFromStorage = true;
            })
            .AddOptimizelyAdminUI();

    }`

`public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseNotFoundHandler(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); }

        app.UseGetaCategories();
        app.UseGetaCategoriesFind();

        app.UseAnonymousId();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseDbLocalizationProvider();
        app.UseDbLocalizationProviderAdminUI();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapAadEndpoints(_configuration);
            endpoints.MapControllerRoute(name: "Default", pattern: "{controller}/{action}/{id?}");
            endpoints.MapControllers();
            endpoints.MapRazorPages();
            endpoints.MapContent();
        });
    }`
valdisiljuconoks commented 1 year ago

Just verified (but with Norwegian language) - it's working as expected. So here is my setup:

services.AddLocalization(options =>
{
    options.ResourcesPath = Path.Combine(_webHostingEnvironment.ContentRootPath, "lang");
});
<?xml version="1.0" encoding="utf-8"?>
<languages>
  <language name="Swedish" id="sv">
    <resourcefromxml>
      <prop1>Property 1 from XML file (SV)</prop1>
    </resourcefromxml>
  </language>
  <language name="Norsk" id="no">
    <resourcefromxml>
      <prop1>Property 1 from XML file (NO)</prop1>
    </resourcefromxml>
  </language>
</languages>
@Html.Translate("/resourcefromxml/prop1").ToString()

works as expected and shows Norwegian content if browsing in "no" culture:

image

maybe there is something else about your setup that we haven't noticed.. sample code is available in Alloy sandbox: https://github.com/valdisiljuconoks/localization-provider-epi/commit/f62f8d835877a4d60846abf686ae84c7ae5227ad

huguesl commented 1 year ago

Thank you for taking the time for this, much appreciated.

If you add DBLocalizationProvider.Episerver and DblocalizationProvider.AdminUI.Episerver to the project and configure them in Startup, does xml localization continue to work as expected for both languages?

valdisiljuconoks commented 1 year ago

yes, check out alloy sandbox. Translate() returns correct resource text for both languages.

huguesl commented 1 year ago

Ok, it might work in our project as well. Where we're running into issues is when using @Html.LabelFor(x => x.Name) along with LocalizedDisplay attributes and other attributes on the properties. Is that supposed to work as well?