1

My C#/WF application uses some files, which are different for different languages. These file can not be placed as resources in satellite assemblies. I wish however to put them in the same directories as the satellite assemblies reside, but I need to know actually where the assembly resides (including the situation, when default language embedded in the binary file is used).

For example, when application switches automatically to polish language, I wish to retreive location:

D:\<app folder>\pl-PL\

Is there a way to do so? Please note, that I wish to retreive this information from the assembly and not by guessing the folder location.


With help of Steve B, here's a solution:

string FindSatelliteAssemblyLocation(CultureInfo culture)
{
    if (culture == CultureInfo.InvariantCulture)
        return Path.GetDirectoryName(Application.ExecutablePath);

    try
    {
        Uri location = new Uri(Assembly.GetExecutingAssembly().GetSatelliteAssembly(culture).CodeBase);
        return Path.GetDirectoryName(location.LocalPath);
    }
    catch
    {
        return FindSatelliteAssemblyLocation(culture.Parent);
    }
}
Spook
  • 25,318
  • 18
  • 90
  • 167

2 Answers2

1

You may use the current thread UI culture to get the language :

var subfolder = System.Threading.Thread.CurrentUICulture.Name;
Steve B
  • 36,818
  • 21
  • 101
  • 174
  • It seems you and I have similar approaches, but you use CurrentUICulture, whereas I'm just suggesting CurrentCulture. Do you know what exactly the differences of each are? – red_sky Nov 06 '12 at 16:59
  • Read the [documentation](http://msdn.microsoft.com/en-us/library/h158zycw.aspx). It states than `CurrentCulture` is the thread culture (not sure what it means), where `CurrentUICulture` is the culture used when looking into localized resources. Which is what the op is asking. – Steve B Nov 06 '12 at 17:03
  • I actually was reading that. Both come from the current thread (as in, each thread has both its own CurrentCulture and CurrentUICulture), however, which is why I'm not certain what the difference is. I know CurrentCulture is based on the localization set on the machine itself, but I don't see how this should ever be different than the localization of the UI (which is also user-determined). – red_sky Nov 06 '12 at 17:07
  • I found the definitive answer: http://stackoverflow.com/a/329041/821132 I'll update my answer. – red_sky Nov 06 '12 at 17:09
  • Yes, but it is vulnerable to situation when - for example - localized assembly is in folder pl and thread's locale is pl-PL. Attempting to load satellite assembly of thread's locale will fail. – Spook Nov 06 '12 at 18:55
  • @Spook: you can rely on the `CultureInfo.Parent` to provide a fallback behavior, same as the out of the box resources management. First, try `pl-pl`, if not found try `pl`, if not found, try 'neutral'. NOt hard to implement I believe. – Steve B Nov 07 '12 at 08:25
  • Ok, now I can write complete function. Thanks! – Spook Nov 08 '12 at 18:28
-1

I feel like you could use a combination of System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase) and CultureInfo.CurrentUICulture to figure this out.

For example, if your assembly is located in C:\Program Files\MyCompany\App\ and the Current UI Culture is en_US, you could combine the two:

string exeDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
string culture = CultureInfo.CurrentUICulture.Name;

string langDir = System.IO.Path.Combine(exeDir, culture);

To produce "C:\Program Files\MyCompany\App\en_US"

red_sky
  • 834
  • 9
  • 17
  • I would use `Path.Combine` instead of string.join. It's more explicit of its usage. – Steve B Nov 06 '12 at 17:05
  • Sigh... **Please note, that I wish to retreive this information from the assembly and not by guessing the folder location.** – Spook Nov 06 '12 at 17:09
  • Spook, I don't understand what you're talking about? This doesn't "guess" anything. It gets it all from the current assembly. Also, Steve, I'll update my answer. – red_sky Nov 06 '12 at 17:10
  • By guessing I mean combining application path and culture name. AFAIR location of satellite assemblies may be changed and this method will be useless then. – Spook Nov 06 '12 at 17:12
  • Giving that the code I supplied gets the folder location of whatever assembly you're running, and then appends the culture, how would it be wrong? I really can't understand the issue here, as this does perfectly what you're "I wish to retrieve location: ..." refers to. From what I know about satellite assemblies, they don't have any executable code in them, just resources, so you're going to have to run the main executable at some point anyway. Why would the satellite locations change? – red_sky Nov 06 '12 at 17:17
  • By reading http://msdn.microsoft.com/en-us/library/21a15yht(v=vs.100).aspx, I don't see any problem with this solution. The satellite assemblies will always be under the directory of your main executable. – red_sky Nov 06 '12 at 17:18
  • Unless they are in GAC, for instance. The solution with appending culture name to application folder will fail in many situations. Consider for example the system's locale to be Polish(Poland) (pl-PL), and localization placed inside Polish folder (pl). The program **will** be localized correctly, but attempt to guess path by applying UI's locale to program's path will return non-existing folder. My solution won't work either, by the way (I have to edit my answer). – Spook Nov 06 '12 at 18:35
  • The localization should never be just the language. It should always have a country component to it. For example, Mexican Spanish is different than Spain Spanish (or Canadian French versus France French). You should be using these to name the folders, not just the language. See: http://msdn.microsoft.com/en-us/library/21a15yht.aspx Subsection "Resources in a Global Assembly Cache" #8 – red_sky Nov 06 '12 at 19:33