This project has moved. For the latest updates, please go here.

Localization of Javascript files

Aug 27, 2014 at 4:30 PM
Hi,

I'm having some difficulty creating a custom bundler for Localization of JS bundles.

The current bundler implements IBundleTransform and uses the language of the current context (given via url-parameter) to replace placeholders in the JS with the localized strings.
public class I18NBundler : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        ....
    }
}
I though I'd just add the BundleTransformer to the mix and now it doesn't work. In an effort to work around the issue I've created a new class implementing ITranslator, trying to use it as a pre-processor for the assets.
public class I18NTranslator : ITranslator
{
    private static string InsertTranslation(Match m, Language language)
    {
        ...
    }

    public IAsset Translate(IAsset asset)
    {
        if (asset == null)
        {
            throw new ArgumentNullException("asset");
        }

        var language = ...
        var content = this.pattern.Replace(asset.Content, m => InsertTranslation(m, language));

        asset.Content = content;

        return asset;
    }

    public IList<IAsset> Translate(IList<IAsset> assets)
    {
        return assets.Select(this.Translate).ToList();
    }

    public bool IsDebugMode { get; set; }
}
This works the first time I load the script from the browser but it seems to get cached. Is there a way to make changes to the way BundleTransformer caches the results?

It doesn't seem to matter if I put it as a PostProcessor either.

I can't seem to get it to work even if I set the disableServerCache-attribute on assetHandler to true.

Is there any other way to make sure the bundle is cached based on an incoming url parameter?
Coordinator
Aug 27, 2014 at 4:36 PM
Hello, Minimoe!

What file extension have localized files?
Coordinator
Aug 27, 2014 at 5:06 PM
If you localize the files with .js extension, then you'd better create the postprocessor (as an example you can use the source code of the BundleTransformer.Autoprefixer module). And then register the newly created postprocessor in Web.config file in the /configuration/bundleTransformer/core/postProcessors element. After this, specify the name of postprocessor in the defaultPostProcessors attribute of /configuration/bundleTransformer/core/js element.

P.S.: In Bundle Transformer does not need to implement IBundleTransform interface, because of its implementing StyleTransformer and ScriptTransformer classes.
Coordinator
Aug 27, 2014 at 5:22 PM
Edited Aug 27, 2014 at 5:25 PM
This works the first time I load the script from the browser but it seems to get cached. Is there a way to make changes to the way BundleTransformer caches the results?
This problem (caching problem) you need to solve at level of the Microsoft ASP.NET Web Optimization Framework.
I can't seem to get it to work even if I set the disableServerCache-attribute on assetHandler to true.
This the debugging HTTP-handler's settings
Coordinator
Aug 27, 2014 at 6:16 PM
public class I18NBundler : IBundleTransform
{
    public void Process(BundleContext context, BundleResponse response)
    {
        ....
    }
}
This code should also have problems with caching.
Aug 28, 2014 at 9:12 AM
Edited Aug 28, 2014 at 9:14 AM
Thanks for the quick reply. After posting this I cloned the repo to have a look at the code.

I ended up using a PostProcessor for the localization and creating a new Bundle-class to determine cache.
public class I18NPostProcessor : IPostProcessor
{
    private static string InsertTranslation(Match m, Language language) { ... }

    public IAsset PostProcess(IAsset asset)
    {
        var language = ...
        asset.Content = this.pattern.Replace(asset.Content, m => InsertTranslation(m, language));
        return asset;
    }

    public IList<IAsset> PostProcess(IList<IAsset> assets)
    {
        return assets.Select(this.PostProcess).ToList();
    }

    public bool UseInDebugMode { get; set; }
}
public sealed class I18NBundle : Bundle
{
    public I18NBundle(string virtualPath) : this(virtualPath, null) { }

    private I18NBundle(string virtualPath, string cdnPath)
        : base(virtualPath, cdnPath, new[] { BundleTransformerContext.Current.Scripts.GetDefaultTransformInstance() })
    {
        this.Builder = new NullBuilder();
    }

    public override string GetCacheKey(BundleContext context)
    {
        var language = ...
        return "{0};{1}".Fmt(base.GetCacheKey(context), language.CultureInfo.Name);
    }
}
To make this work exactly like I want to I will probably also have to add my translation files as a cache dependency. But that's for another day.

Thanks again for a great lib!