Retrieving Locale-Specific Streams

Once nice feature in VS .NET is that it's really easy to add content to your assemblies as an embedded resource. Just add your file to your project (doesn't matter if it's XML or an image or binary) and set the Build Action of that file to Embedded Resource. VS .NET does all the work for you to get that file's content into your assembly as a resource entry. Furthermore, if you want a culture-specific version of that file, just put the right culture value between the name of the file and its' extension, and VS .NET will make the right satellite assembly. In other words, if you have a file called "Data.xml" and you want to have a French version of it, make a new file in the project called "Data.fr.xml" and, bingo!, you'll have a resources assembly in a fr folder underneath the bin directory.

The problem is, just how do you retrieve that resource information? When I ran into this problem a while ago, it took a bit of digging in the Framework but I finally figured it out. Here's the code that shows you how it's done - the class that does the grunt work is called StreamResolver:

public sealed class StreamResolver
{
    private StreamResolver() : base() {}

    public static Stream GetStream(string resource)
    {
        return StreamResolver.GetStream(resource, 
            Assembly.GetCallingAssembly(),
            Thread.CurrentThread.CurrentCulture);
    }

    public static Stream GetStream(string resource, Assembly assembly)
    {
        return StreamResolver.GetStream(resource, 
            assembly,
            Thread.CurrentThread.CurrentCulture);
    }

    public static Stream GetStream(string resource, Assembly assembly, 
        CultureInfo culture)
    {
        Stream stream = null;
        CultureInfo currentCulture = culture;

        do
        {
            try
            {
                Assembly satelliteAssembly = 
                    assembly.GetSatelliteAssembly(currentCulture);
                stream = satelliteAssembly.GetManifestResourceStream(
                    resource);

                if(stream == null)
                {
                    currentCulture = currentCulture.Parent;
                }
            }
            catch(FileNotFoundException) 
            {
                currentCulture = currentCulture.Parent;
            }
            catch(FileLoadException) 
            {
                currentCulture = currentCulture.Parent;
            }
        } while(currentCulture != CultureInfo.InvariantCulture && 
            stream == null);

        if(stream == null)
        {
            stream = assembly.GetManifestResourceStream(resource);
        }

        return stream;
    }
}

Hope this helps someone out!

* Posted at 03.24.2005 02:05:34 PM CST | Link *

Blog History