Programmatically retrieve text from a Resx file based on a specific culture
Use .resx files for storing multiple languages inside a WCF Service without compiling the files.
Problem:
I need to develop a multiple language web service. The articles on the web focus on two things.
- Using resx files with web pages. You change the culture in your web site and asp.net automatically uses the correct resx file. That is, assuming you name it in the correct format and place it in the correct folder.
- Using resx files globally in your application. This unfortunately compiles your resx files though and you cannot easily edit them .
I needed to be able to programmatically retrieve the correct resx file, keep the resx file uncompiled so it could be edited, and do so within a web service.
This post assumes you have already found a bunch of articles via Google about how to set a thread’s culture, or a page’s culture. I found those articles as well. They were helpful learning how use .Resx files for a multiple language web site. However, I needed to use multiple languages in a WCF Service and ASMX Web Service.
Solution:
The solution is to use the resource manager class, but override it so you can use resx files. Then you can easily grab the text you need from the correct language. You can use this method in a web service or anywhere in your application.
Here is the code:
ResxResourceManager.vb
Imports System.ServiceModel
Imports System.Runtime.Serialization
Imports System.Resources
Imports System.Reflection
Namespace MyNamespace
Public Class ResxResourceManager
Inherits ResourceManager
Public Sub New(ByVal baseName As String, ByVal resourceDir As String)
BaseNameField = baseName
ResourceSets = New Hashtable()
Dim baseType As Type = Me.GetType.BaseType
Dim flags As BindingFlags = BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.SetField
baseType.InvokeMember("moduleDir", flags, Nothing, Me, New Object() {resourceDir})
baseType.InvokeMember("_userResourceSet", flags, Nothing, Me, New Object() {GetType(ResXResourceSet)})
baseType.InvokeMember("UseManifest", flags, Nothing, Me, New Object() {False})
End Sub
Protected Overrides Function GetResourceFileName(ByVal culture As Globalization.CultureInfo) As String
Dim resourceFileName As String = MyBase.GetResourceFileName(culture).ToLower
Return resourceFileName.Replace(".resources", ".resx")
End Function
End Class
End Namespace
Usage:
Dim sBinDirectory As String
sBinDirectory = HostingEnvironment.ApplicationPhysicalPath & "App_LocalResources\"
Dim rm As New ResxResourceManager("States", sBinDirectory)
Dim StateName As String = CStr(rm.GetString(StateCode, CultureInfo.CreateSpecificCulture("en-EN")))
Notes:
- I use “HostingEnvironment.ApplicationPhysicalPath” instead of Server.Mappath since this is a WCF Service
- You must add some references to your project :
- Imports System.ServiceModel
- Imports System.Runtime.Serialization
- In the code sample above “States” is the prefix of the resx file. So I would have the following files:
- States.resx
- States.it.resx
- States.es.resx
- Of course, you place these files inside the “App_LocalResources” directory which is set to the “sBinDirectory” variable
- In the code above StateCode is a variable. It is the name of value you want from the resx file. In my example it would be something like “PA” or “NY” or “CA”. It would return the text “Pennsylvania”, etc.