5

Attualmente sto cercando di impostare un progetto per implementare la localizzazione su file javascript (come descritto here) ma allo stesso tempo mi piacerebbe raggruppare e minimizzare il javascript nel progetto. Ho seguito un tutorial su bundling e minification hereGestori HTTP e bundle javascript in VS 2012

Sono riuscito a far funzionare entrambi separatamente, ma quando provo a farli funzionare insieme non riesco a far funzionare correttamente la localizzazione. Penso che questo sia dovuto al fatto che il raggruppamento crea la propria gestione delle rotte per il javascript in bundle/minificato che genera, quindi l'httpHandler che ho definito nel webconfig viene ignorato. Continuo a ricevere errori javascript che dicono "CustomTranslate non è definito".

Sto provando a farlo perché stiamo costruendo un numero di controlli usando ExtJS, ma dobbiamo essere in grado di applicare la localizzazione a quei controlli. Qualsiasi aiuto/idea su come posso farli lavorare insieme sarebbe apprezzato.

Sono non usando MVC, ma facendo questo in asp.net in Visual Studio 2012.

Ecco il mio codice:

BundleConfig.cs

namespace TranslationTest 
{ 
    public class BundleConfig 
    { 
     public static void RegisterBundles(BundleCollection bundles) 
     { 
      //default bundles addeed here... 

      bundles.Add(new ScriptBundle("~/bundles/ExtJS.axd").Include("~/Scripts/ExtJS/ext-all.js", "~/Scripts/ExtJS/TestForm.js")); 

     } 
    } 
}  

web.config :

<globalization uiCulture="auto" /> 
<httpHandlers> 
    <add verb="*" path="/bundles/ExtJS.axd" type="TranslationTest.ScriptTranslator, TranslationTest" /> 
</httpHandlers> 

Default.aspx

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TranslationTest._Default" %> 

<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent"> 
    <script src="/bundles/ExtJS.axd"></script> 
</asp:Content>  

TestForm.js:

Ext.require([ 
     'Ext.form.*', 
     'Ext.layout.container.Column', 
     'Ext.tab.Panel' 
]); 

Ext.onReady(function() { 

    Ext.QuickTips.init(); 

    var bd = Ext.getBody(); 

    bd.createChild({ tag: 'h2', html: 'Form 1' }); 


    var simple = Ext.create('Ext.form.Panel', { 
     url: 'save-form.php', 
     frame: true, 
     title: 'Simple Form', 
     bodyStyle: 'padding:5px 5px 0', 
     width: 350, 
     fieldDefaults: { 
      msgTarget: 'side', 
      labelWidth: 75 
     }, 
     defaultType: 'textfield', 
     defaults: { 
      anchor: '100%' 
     }, 

     items: [{ 
      fieldLabel: CustomTranslate(FirstName), 
      name: 'first', 
      allowBlank: false 
     }, { 
      fieldLabel: CustomTranslate(LastName), 
      name: 'last' 
     }, { 
      fieldLabel: CustomTranslate(Company), 
      name: 'company' 
     }, { 
      fieldLabel: CustomTranslate(Email), 
      name: 'email', 
      vtype: 'email' 
     }, { 
      xtype: 'timefield', 
      fieldLabel: CustomTranslate(Time), 
      name: 'time', 
      minValue: '8:00am', 
      maxValue: '6:00pm' 
     }], 

     buttons: [{ 
      text: CustomTranslate(Save) 
     }, { 
      text: CustomTranslate(Cancel) 
     }] 
    }); 

    simple.render(document.body); 


}); 

Attualmente il Nome, Cognome, ecc sono tutti memorizzati in file di risorse, come nell'esempio linkato sopra.

ScriptTranslator.cs

namespace TranslationTest 
{ 
    public class ScriptTranslator : IHttpHandler 
    { 
     #region IHttpHandler Members 

     public bool IsReusable 
     { 
      get { return false; } 
     } 

     public void ProcessRequest(HttpContext context) 
     { 
      string relativePath = context.Request.AppRelativeCurrentExecutionFilePath.Replace(".axd", string.Empty); 
      string absolutePath = context.Server.MapPath(relativePath); 
      string script = ReadFile(absolutePath); 
      string translated = TranslateScript(script); 

      context.Response.Write(translated); 

      Compress(context); 
      SetHeadersAndCache(absolutePath, context); 
     } 

     #endregion 

     private void SetHeadersAndCache(string file, HttpContext context) 
     { 
      context.Response.AddFileDependency(file); 
      context.Response.Cache.VaryByHeaders["Accept-Language"] = true; 
      context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true; 
      context.Response.Cache.SetLastModifiedFromFileDependencies(); 
      context.Response.Cache.SetExpires(DateTime.Now.AddDays(7)); 
      context.Response.Cache.SetValidUntilExpires(true); 
      context.Response.Cache.SetCacheability(HttpCacheability.Public); 
     } 

     #region Localization 

     private static Regex REGEX = new Regex(@"CustomTranslate\(([^\))]*)\)", RegexOptions.Singleline | RegexOptions.Compiled); 

     private string TranslateScript(string text) 
     { 
      MatchCollection matches = REGEX.Matches(text); 
      ResourceManager manager = new ResourceManager(typeof(TranslationTest.App_GlobalResources.text)); 

      foreach (Match match in matches) 
      { 
       object obj = manager.GetObject(match.Groups[1].Value); 
       if (obj != null) 
       { 
        text = text.Replace(match.Value, CleanText(obj.ToString())); 
       } 
      } 
      return text; 
     } 

     private static string CleanText(string text) 
     { 
      text = text.Replace("'", "\\'"); 
      text = text.Replace("\\", "\\\\"); 
      return text; 
     } 

     private static string ReadFile(string absolutePath) 
     { 
      if (File.Exists(absolutePath)) 
      { 
       using (StreamReader reader = new StreamReader(absolutePath)) 
       { 
        return reader.ReadToEnd(); 
       } 
      } 
      return null; 
     } 

     #endregion 

     #region Compression 

     private const string GZIP = "gzip"; 
     private const string DEFLATE = "deflate"; 

     private static void Compress(HttpContext context) 
     { 
      if (IsEncodingAccepted(DEFLATE, context)) 
      { 
       context.Response.Filter = new DeflateStream(context.Response.Filter, CompressionMode.Compress); 
       SetEncoding(DEFLATE, context); 
      } 
      else if (IsEncodingAccepted(GZIP, context)) 
      { 
       context.Response.Filter = new GZipStream(context.Response.Filter, CompressionMode.Compress); 
       SetEncoding(GZIP, context); 
      } 
     } 

     private static bool IsEncodingAccepted(string encoding, HttpContext context) 
     { 
      return context.Request.Headers["Accept-encoding"] != null && context.Request.Headers["Accept-encoding"].Contains(encoding); 
     } 

     private static void SetEncoding(string encoding, HttpContext context) 
     { 
      context.Response.AppendHeader("Content-encoding", encoding); 
     } 

     #endregion 

    } 
} 

Global.asax.cs

namespace TranslationTest 
{ 
    public class Global : HttpApplication 
    { 
     void Application_Start(object sender, EventArgs e) 
     { 
      Microsoft.Web.Optimization.BundleTable.Bundles.EnableDefaultBundles(); 

      BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles); 
      AuthConfig.RegisterOpenAuth(); 
     } 
    } 
} 

Spero di aver coperto tutto, ma per favore fatemi sapere se c'è qualcosa che manca. Grazie in anticipo!!

+0

Btw, probabilmente vale anche la pena di ricordare che ho anche provato a far sì che il mio traduttore di sceneggiature implementasse anche IRouteHandler, ma non ho avuto molta fortuna neanche in quella direzione. – Paul

risposta

5

Ok, ho impostato tutto nel tuo esempio e ho funzionato, ma devi usare l'interfaccia IBundleTransform. I dettagli di tutto ciò che ho fatto sono postati qui sotto.

Ho dovuto creare una classe per gestire la trasformazione del bundle (cioè la traduzione) invece di consentire il comportamento predefinito.

public class JsLocalizationTransform : IBundleTransform 
    { 
     public JsLocalizationTransform(){} 

     #region IBundleTransform Members 

     public void Process(BundleContext context, BundleResponse response) 
     { 
      string translated = TranslateScript(response.Content); 

      response.Content = translated; 
     } 

     #endregion 

     #region Localization 

     private static Regex REGEX = new Regex(@"CustomTranslate\(([^\))]*)\)", RegexOptions.Singleline | RegexOptions.Compiled); 

     private string TranslateScript(string text) 
     { 
      MatchCollection matches = REGEX.Matches(text); 
      ResourceManager manager = new ResourceManager(typeof(TranslationTest.App_GlobalResources.text)); 

      foreach (Match match in matches) 
      { 
       object obj = manager.GetObject(match.Groups[1].Value); 
       if (obj != null) 
       { 
        text = text.Replace(match.Value, CleanText(obj.ToString())); 
       } 
      } 

      return text; 
     } 

     private static string CleanText(string text) 
     { 
      //text = text.Replace("'", "\\'"); 
      text = text.Replace("\\", "\\\\"); 

      return text; 
     } 
     #endregion 

    } 

Poi, nel metodo BundleConfig.RegisterBundles è necessario creare e aggiungere il pacchetto in questo modo:

var extjsBundle = new Bundle("~/bundles/ExtJS").Include("~/Scripts/ExtJS/ext-all.js", "~/Scripts/ExtJS/TestForm.js"); 
    extjsBundle.Transforms.Clear(); 
    extjsBundle.Transforms.Add(new JsLocalizationTransform()); 
    extjsBundle.Transforms.Add(new JsMinify()); 
    bundles.Add(extjsBundle); 

ho potuto quindi rimuovere il HttpHandler da web.config come quello ottiene configurato automaticamente attraverso Bundler. Ho anche dovuto apportare alcune modifiche al metodo Application_Start in global.asax.cs

void Application_Start(object sender, EventArgs e) 
     { 
      //Microsoft.Web.Optimization.BundleTable.Bundles.EnableDefaultBundles(); 
      BundleTable.EnableOptimizations = true; //Added this line.. 
      BundleConfig.RegisterBundles(System.Web.Optimization.BundleTable.Bundles); 
      AuthConfig.RegisterOpenAuth(); 
     } 

Poiché la classe JSLocalisationTransform sta gestendo la trasformazione fascio e la traduzione, ho eliminato completamente la classe ScriptTranslator.

Spero che questo aiuti.

+0

Perfetto, grazie Grant – Paul