Azure-functions-host: Strings localization resx

Created on 7 Nov 2017  路  22Comments  路  Source: Azure/azure-functions-host

I have developed an Italian / English application.
I have created 2 resx files to manage the texts, in the local everything works perfectly, on azure, instead only the texts of the default resx file are displayed (in Italian in this case)

Thanks to @andreatosato who created a sample project to better understand the issue.

[FunctionName("ResourceFunc")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    log.Info(Thread.CurrentThread.CurrentCulture.DisplayName);
    log.Info(Thread.CurrentThread.CurrentUICulture.DisplayName);
    System.Resources.ResourceManager rm = new System.Resources.ResourceManager("ResourceApp.Prova", System.Reflection.Assembly.GetExecutingAssembly());
    log.Info(rm.GetString("Nome"));
    return  req.CreateResponse(HttpStatusCode.OK, rm.GetString("Nome"));
}

I Have 2 file resources, Prova and Prova.en
the key "Name" have value "Italiano" in the file "Prova" and "Inglese" in the file "Prova.en"
this is the result:
local:

Thread.CurrentThread.CurrentCulture.DisplayName: English (United States)
Thread.CurrentThread.CurrentUICulture.DisplayName: English (United States)
rm.GetString("Nome"): Inglese

Azure:

Thread.CurrentThread.CurrentCulture.DisplayName: English (United States)
Thread.CurrentThread.CurrentUICulture.DisplayName: English (United States)
rm.GetString("Nome"): Italiano

file:
https://github.com/andreatosato/FunctionApp

Most helpful comment

Same here :( The workaround proposed by @stevedenman didn't work for me either, so it'd be great if you guys provide a way to cope with this until we have an official solution. Thanks!

All 22 comments

@davidebbo are you familiar with how string resources work in an ASP.NET context (or do you know someone on the team who does)?

My guess is that the lookup that normally happens for resource assemblies does not work for Function apps, because the bin folder under wwwroot is not the real bin folder of the ASP.NET app (which is the runtime). To fix this, we'd need to somehow hook into the .NET logic the locates resource assemblies, similar to how we use AssemblyResolve events to load regular assemblies in the user's bin.

I do have the same problem. Are there any new insights regarding this issue?

I am sorry to bother you, but are there any new insights regarding this behaviour?

@davidebbo Do you have any information on the release date?

@andreatosato the work to make this change is not yet planned, so there is no ETA at this time.

Do you have any work around in the mean time?

@larry-lau This is how I worked around it; https://stackoverflow.com/a/48678685/519356

This works for resources I have control over. However, libraries like Humanizer.Core is still won't work in Azure Functions.

Same here :( The workaround proposed by @stevedenman didn't work for me either, so it'd be great if you guys provide a way to cope with this until we have an official solution. Thanks!

I am using JSON plain files until the Azure Function team implements this option.

Anyone has other suggestions instead of JSON files?

Can't get localization to work in Functions. :(

Any update?

I have quick workaround. Its not ideal but it works

    public static class ResourceWrapper
    {
        private static Dictionary<string, ResourceSet> _resourceSets = new Dictionary<string, ResourceSet>();
        static ResourceWrapper()
        {
            _resourceSets.Add("uk", Load("uk"));
            _resourceSets.Add("ru", Load("ru"));
            _resourceSets.Add("en", Emails.ResourceManager.GetResourceSet(CultureInfo.InvariantCulture, false, false));
        }

        private static ResourceSet Load(string lang)
        {
            var asm = System.Reflection.Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, "bin", lang, "Function.App.resources.dll"));
             var resourceName = $"Function.App.Resources.Emails.{lang}.resources";
             var tt = asm.GetManifestResourceNames();
            return new ResourceSet(asm.GetManifestResourceStream(resourceName));
        }

        public static string GetString(string key)
        {
            return _resourceSets[CultureInfo.CurrentUICulture.TwoLetterISOLanguageName].GetString(key);
        }
    }

Are there any updates?
Some parts of our business logic are shared between an Azure-Function and a WPF application. It would be great if we wouldn't have to implement a workaround, but instead being able to get the same result for the following code:
LocStrings.ResourceManager.GetString("SomeStringResource", culture).

I've done some playing and from what I can tell you only need to load the satellite assemblies (the ones ending in .resources.dll) into the App Domain and then everything works as expected, this should work for Humanizer etc. too, assuming that's how they work.

Just run something like this at process startup (not necessarily each function call) and everything just appears to work.

        private void LoadLocalizationAssemblies()
        {
            var binDir = Path.Combine(Environment.CurrentDirectory, "bin");

            var assemblyFiles = Directory.EnumerateFiles(binDir, "*.resources.dll", SearchOption.AllDirectories);
            foreach (var file in assemblyFiles)
            {
                Assembly.LoadFrom(file);
            }
        }

This is based on what I found with playing around with what @stevedenman said above. I don't think you need any wrappers or custom resource sets.

+1
Any update on this? We have a Function App that acts as a back-end to a Microsoft flow connector and we require to localize the strings before sending the response?
Is there any way to use any resx/xml/ResourceManager to localize strings?

Same problem here. I have an azure function using Razor for email templating and I'd like to put localization resource files in the same razor class library containing the views. The problem is that the resulting directory structure is:

...
bin/FuncName.dll
...
bin/RazorClassLibrary.dll
bin/RazorClassLibrary.Views.dll
bin/en/RazorClassLibrary.resources.dll
bin/es/RazorClassLibrary.resources.dll
bin/fr/RazorClassLibrary.resources.dll
etc...

I've not been able to use resource dlls using any of the built in localization facilities. Neither HtmlLocalizer nor StringLocalizer work, and got mad trying to work around this using their respective factories by specifying the assembly and namespace names.

@bragma and @sandeepnmenon can you share the version of Azure Functions you're using? I'm assuming this is V2 and V1, respectively, is that correct?

This issue is tracking the problem in for V1, which will not be addressed (please refer to some of the suggested workarounds above), so I'm closing. For V2, could you please open a separate issue with details?

@bragma and @sandeepnmenon can you share the version of Azure Functions you're using? I'm assuming this is V2 and V1, respectively, is that correct?

This issue is tracking the problem in for V1, which will not be addressed (please refer to some of the suggested workarounds above), so I'm closing. For V2, could you please open a separate issue with details?

You are right, I am using V2. Sorry for the confusion.

We were using V1. But now have migrated to V2.
Is there any new issue open for V2?

Any update? I'm working on an azure function for Alexa (ttps://blogs.msdn.microsoft.com/appconsult/2018/11/02/build-your-first-alexa-skill-with-alexa-net-and-azure-functions-the-basics/). I need to localize the response based on request. I tried with resx but they doesn't work. I also used the hack written in this thread and in local host it work but than when I published my azure function on Azure and I try to execute, appear an error that say me that not found any dll in path. How can I localize my AF? Thanks

Was this page helpful?
0 / 5 - 0 ratings