After extensively researching various solutions without finding one that met my needs, I stumbled upon a fantastic and versatile approach using T4 templates. For full details, check out the post by Jochen van Wylick here:
Utilizing T4 to localize JavaScript resources based on .resx files
The key benefits include:
- Central resource management in a single location (.resx files)
- Support for multiple cultures
- IntelliSense support for code completion
However, there are some drawbacks as well:
One downside is that the resulting .js file may become large in size. Although it's cached by the browser which eliminates performance issues in our application, this caching can cause problems if the browser fails to locate the requested resource.
How does this method work?
Essentially, a T4 template is created to reference the .resx files. Through C# code, each resource string is parsed and added to JavaScript as key-value properties, culminating in a single JavaScript file named Resources.js
(names can be customized).
T4 template [modify as needed to point to your .resx files location]
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ assembly name="System.Windows.Forms" #>
<#@ import namespace="System.Resources" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".js"#>
<#
var path = Path.GetDirectoryName(Host.TemplateFile) + "/../App_GlobalResources/";
var resourceNames = new string[1]
{
"Common"
};
#>
/**
* Resources
* ---------
* This file is auto-generated by a tool
* 2012 Jochen van Wylick
**/
var Resources = {
<# foreach (var name in resourceNames) { #>
<#=name #>: {},
<# } #>
};
<# foreach (var name in resourceNames) {
var nlFile = Host.ResolvePath(path + name + ".nl.resx" );
var enFile = Host.ResolvePath(path + name + ".resx" );
ResXResourceSet nlResxSet = new ResXResourceSet(nlFile);
ResXResourceSet enResxSet = new ResXResourceSet(enFile);
#>
<# foreach (DictionaryEntry item in nlResxSet) { #>
Resources.<#=name#>.<#=item.Key.ToString()#> = {
'nl-NL': '<#=("" + item.Value).Replace("\r\n", string.Empty).Replace("'","\\'")#>',
'en-GB': '<#=("" + enResxSet.GetString(item.Key.ToString())).Replace("\r\n", string.Empty).Replace("'","\\'")#>'
};
<# } #>
<# } #>
Incorporating into Form/View
To ensure accurate translations, add this snippet in your master page if using WebForms:
<script type="text/javascript">
var locale = '<%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>';
</script>
<script type="text/javascript" src="/Scripts/Resources.js"></script>
For ASP.NET MVC users, like myself, the implementation would look like this:
<script type="text/javascript">
// Setting Locale for JavaScript translations
var locale = $("meta[name='accept-language']").attr("content");
</script>
<script type="text/javascript" src="/Scripts/Resources.js"></script>
The MetaAcceptLanguage
helper mentioned above is from an informative post by Scott Hanselman:
Globalization, Internationalization and Localization in ASP.NET MVC 3, JavaScript and jQuery - Part 1
public static IHtmlString MetaAcceptLanguage<T>(this HtmlHelper<T> html)
{
var acceptLanguage =
HttpUtility.HtmlAttributeEncode(
Thread.CurrentThread.CurrentUICulture.ToString());
return new HtmlString(
String.Format("<meta name=\"{0}\" content=\"{1}\">", "accept-language",
acceptLanguage));
}
Implementation Example
var msg = Resources.Common.Greeting[locale];
alert(msg);