Get all available cultures from a .resx file group

Look for satellite assemblies in your application's directory: for each subdirectory, check if its name corresponds to a culture name, and if it contains a .resources.dll file :

public IEnumerable<CultureInfo> GetAvailableCultures()
{
    var programLocation = Process.GetCurrentProcess().MainModule.FileName;
    var resourceFileName = Path.GetFileNameWithoutExtension(programLocation) + ".resources.dll";
    var rootDir = new DirectoryInfo(Path.GetDirectoryName(programLocation));
    return from c in CultureInfo.GetCultures(CultureTypes.AllCultures)
           join d in rootDir.EnumerateDirectories() on c.IetfLanguageTag equals d.Name
           where d.EnumerateFiles(resourceFileName).Any()
           select c;
}

based on the answer by @hans-holzbart at Programmatic way to get all the available languages (in satellite assemblies) but fixed to not return the InvariantCulture too and wrapped into a reusable method:

public static IEnumerable<CultureInfo> GetAvailableCultures()
{
  List<CultureInfo> result = new List<CultureInfo>();

  ResourceManager rm = new ResourceManager(typeof(Resources));

  CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
  foreach (CultureInfo culture in cultures)
  {
    try
    {
      if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work

      ResourceSet rs = rm.GetResourceSet(culture, true, false);
      if (rs != null)
        result.Add(culture);
    }
    catch (CultureNotFoundException)
    {
      //NOP
    }
  }
  return result;
}

using that method, you can get a list of strings to add to some ComboBox with the following:

public static ObservableCollection<string> GetAvailableLanguages()
{
  var languages = new ObservableCollection<string>();
  var cultures = GetAvailableCultures();
  foreach (CultureInfo culture in cultures)
    languages.Add(culture.NativeName + " (" + culture.EnglishName + " [" + culture.TwoLetterISOLanguageName + "])");
  return languages;
}