3

We are using mvc 5 and we want to use resource files for our localization. We have a dll used by many customer applications in which we would like to place some defaut view models: application structure

The ViewModel now looks something like this:

public class Person
{
    //...
    [Display(ResourceType = typeof(Resources), Name = "NameKey")] //type or namespace Resources could not be found
    public string FirstName { get; set; }
    //...
}

This view model works fine when placed in either CustomerX or CustomerY project, but breaks when moved to the referenced BaseWebApp as Resources is not a known type there. At rendering time resource file is available, the only thing that throws a monkey wrench in the scheme is the resource's Type as the location specifier. Is there an other way to specify the resource file as source of localization strings?

k.c.
  • 1,755
  • 1
  • 29
  • 53

1 Answers1

1

Solution with satellite assemblies:

After some research the best solution would be Creating Satellite Assemblies.

A satellite assembly is a compiled library (DLL) that contains (“localizable”) resources such as strings, bitmaps, etc. You are likely to use them when creating a multilingual (UI) application. Satellite assemblies provide you with the capability of designing and deploying your solution to multiple cultures, rather than hard coding strings, bitmaps, etc., into your main application. Satellite assemblies are used to deploy applications in multiple cultures (not languages), with 1 satellite assembly per culture - this is the default behavior, but you can obviously have more granular control if you handle the build process manually.

When working with satellite assemblies you can even override the default culture contained in the original dll.

Solution with custom ResourceManager

Last you could roll your own Resource class implementation based on the one that is generated by the resx files and then select no code generation on the editor.

public class PersonResources
{
    private static System.Resources.ResourceManager resourceMan;
    private static System.Globalization.CultureInfo resourceCulture;

    static PersonResources() {
        // shouldbe something like "MyAssembyName"
        string assemblyName = System.Configuration.ConfigurationManager.AppSettings["ResourceAssembly"];
        if (!string.IsNullOrEmpty(assemblyName)) {
            resourceAssembly = System.Reflection.Assembly.LoadWithPartialName(assemblyName);
            resourceName = resourceAssembly.GetName().Name + ".Resources.PersonResources";
        }
    }

    private static readonly System.Reflection.Assembly resourceAssembly;
    private static readonly string resourceName;

    /// <summary>
    ///   Returns the cached ResourceManager instance used by this class.
    /// </summary>
    public static System.Resources.ResourceManager ResourceManager {
        get {
            if (ReferenceEquals(resourceMan, null)) {
                System.Resources.ResourceManager temp = new System.Resources.ResourceManager(resourceName, resourceAssembly);
                resourceMan = temp;
            }
            return resourceMan;
        }
    }

    /// <summary>
    ///   Overrides the current thread's CurrentUICulture property for all
    ///   resource lookups using this strongly typed resource class.
    /// </summary>
    public static System.Globalization.CultureInfo Culture {
        get {
            return resourceCulture;
        }
        set {
            resourceCulture = value;
        }
    }


    public static string NameKey {
        get {
            return ResourceManager.GetString("NameKey", resourceCulture);
        }
    }

    public static string LastNameKey {
        get {
            return ResourceManager.GetString("LastNameKey", resourceCulture);
        }
    }
}

You would have to make one class per resource type and based on your description you would then put these classes on your BaseWebApp. Check the resourceAssembly & resourceName members above, they are populated in the static constructor via AppSettings where you must point to the assembly that has the embedded resx files.

Original Solution

You should simply move the resources to accompany the project where the VMs are located. That would be your BaseWebApp.

An other way to do it is make a dedicated resources project and mark the classes generated by your resx's as public instead of the default which is internal. This may help you organize your resources better. enter image description here

cleftheris
  • 4,626
  • 38
  • 55
  • part of the problem is, that the resource files must be able to differ between customer apps (supporting different languages, different labels for the fields, etc.). – k.c. Aug 27 '15 at 10:25
  • @k.c. you can use T4 templates to generate your resx custom resource classes [like so](http://www.codeproject.com/Articles/269362/Using-T-Templates-to-generate-custom-strongly-typ) – cleftheris Aug 27 '15 at 11:27
  • Building a custom resource class with the keys hard coded in there seems do-able, but ik looks like more work than it takes out of the solution even when I start writting T4. Thanks for showing me the way – k.c. Aug 27 '15 at 14:19
  • @k.c. True but it is one off. – cleftheris Aug 27 '15 at 16:53