0

I have 3 resource files:

/Resources/Values.en-US.resx
/Resources/Values.es-ES.resx
/Resources/Values.fr-FR.resx


(English, Spanish, French)

From here I want to 'scan' what languages (from these resource files) are available so I can put them in a list and display them to the user for selecting. After releasing my program, people should be able to add more languages. The program will scan for new languages and make them available from a list.

Is there a way to get the files from Resources folder?

user989988
  • 1,051
  • 11
  • 28
  • 1
    Possible duplicate of [Programmatic way to get all the available languages (in satellite assemblies)](https://stackoverflow.com/questions/553244/programmatic-way-to-get-all-the-available-languages-in-satellite-assemblies) – Prolog Jan 01 '19 at 19:54

1 Answers1

1

You can iterate through files located under application content directory, then select the resource files, extract the culture fragment from the file name and eventually create a list of cultures.

First, inject the IHostingEnvironment to use the ContentRootPath property it provides.

private readonly IHostingEnvironment _hostingEnvironment;

public HomeController(IHostingEnvironment hostingEnvironment)
{
    _hostingEnvironment = hostingEnvironment;
}

As long as you keep all your resource files under ./Resources/ directory you should be fine.

Next, create DirectoryInfo:

var contentRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "Resources");

DirectoryInfo contentDirectoryInfo;
try
{
    contentDirectoryInfo = new DirectoryInfo(contentRootPath);
}
catch (DirectoryNotFoundException)
{
    // Here you should handle "Resources" directory not found exception.
    throw;
}

Get the resource file names:

var resoruceFilesInfo = contentDirectoryInfo.GetFiles("*.resx", SearchOption.AllDirectories);
var resoruceFileNames = resoruceFilesInfo.Select(info => info.Name);

All three examples of resource files you provided follow a culture naming pattern. That is, a combination of an ISO 639 two-letter lowercase culture code associated with a language and an ISO 3166 two-letter uppercase subculture code associated with a country or region. For proper culture fragment extraction I suggest using a Regular Expression like this one below:

var regex = new Regex(@"(?<=\.)[a-z]{2}-[A-Z]{2}(?=\.resx$)");
var culturePrefixes = resoruceFileNames.Select(fileName => regex.Match(fileName).Value);

Finally, create a culture collection:

var cultureList = culturePrefixes.Select(prefix => new CultureInfo(prefix));
Prolog
  • 1,901
  • 1
  • 12
  • 24
  • Thank you! Should I be adding all this code in Startup.cs? Including injecting IHostingEnvironment? – user989988 Jan 01 '19 at 07:31
  • I have a class library which includes Startup.cs. I need to specify path to Resources folder in Startup.cs. I have Resources folder in a different class library. Please let me know how to do that? – user989988 Jan 01 '19 at 07:37
  • Answering your first question - best thing to do is to put all that code into one place, maybe method, or event better a service, you could [inject](https://docs.microsoft.com/pl-pl/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2) later. My initial suggestion was to put that code inside a controller e.g. `HomeController` as shown in code sample, then initialize it with [IHostingEnvironment](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hosting.ihostingenvironment?view=aspnetcore-2.1) service which is provided by default by ASP.NET Core. – Prolog Jan 01 '19 at 14:04
  • Your second question is more tricky. If you would like to list languages of resource files stored in different library referenced by ASP.NET Core application, then my solution is **no longer valid** for such scenario. I used content path from `IHostingEnvironment` natively provided by ASP.NET Core application. You cannot perform the same trick for standalone library, because (as the name itself suggests) it is a library not a Core application. For the moment, I cannot think of easy way to achieve this. That does not mean there is none. – Prolog Jan 01 '19 at 16:15
  • Though, you could try to use the paths provided by [Assembly](https://docs.microsoft.com/pl-pl/dotnet/api/system.reflection.assembly?view=netframework-4.7.2) and then traverse upwards. Still, for me this seems too hacky and far from ideal. – Prolog Jan 01 '19 at 16:16
  • @Hans Holbart [answer](https://stackoverflow.com/a/11047894/8065832) works fine. Create an empty list of cultures and add those which [ResourceManager](https://docs.microsoft.com/pl-pl/dotnet/api/system.resources.resourcemanager?view=netframework-4.7.2) is able to resolve for getting [ResourceSet](https://docs.microsoft.com/en-us/dotnet/api/system.resources.resourceset?view=netframework-4.7.2). Keep a dummy class in your "Resources" folder to use it as type anchor for initialization of `ResourceManager`. – Prolog Jan 01 '19 at 19:53