Localiser des chaînes dans Javascript

J'utilise actuellement des fichiers .resx pour gérer mes ressources côté serveur pour .NET.

L'application que je traite permet également aux développeurs de connecter JavaScript à différents gestionnaires d'événements pour la validation côté client, etc. Quel est le meilleur moyen pour moi de localiser mes messages et ces chaînes JavaScript?

Idéalement, je voudrais stocker les chaînes dans les fichiers .resx pour les conserver avec le reste des ressources localisées.

Je suis ouvert aux suggestions.

Un objet JavaScript de base est un tableau associatif, de sorte qu'il peut facilement être utilisé pour stocker des paires de clés / valeurs. Donc, en utilisant JSON , vous pouvez créer un objet pour chaque chaîne à localiser comme ceci:

 var localizedStrings={ confirmMessage:{ 'en/US':'Are you sure?', 'fr/FR':'Est-ce que vous êtes certain?', ... }, ... } 

Ensuite, vous pouvez obtenir la version locale de chaque chaîne comme ceci:

 var locale='en/US'; var confirm=localizedStrings['confirmMessage'][locale]; 

Inspiré par SproutCore Vous pouvez définir les propriétés des chaînes:

 'Hello'.fr = 'Bonjour'; 'Hello'.es = 'Hola'; 

Et puis crachez la localisation appropriée en fonction de votre locale:

 var locale = 'en'; alert( message[locale] ); 

Après Googling beaucoup et pas satisfaits de la majorité des solutions présentées, je viens de trouver une solution géniale / générique qui utilise des modèles T4 . La publication complète de Jochen van Wylick vous pouvez lire ici:

Utilisation de T4 pour localiser les ressources JavaScript en fonction des fichiers .resx

Les principaux avantages sont les suivants:

  1. N'ayant qu'un seul endroit où les ressources sont gérées (à savoir les fichiers .resx)
  2. Soutien aux cultures multiples
  3. Tirer parti de IntelliSense – autoriser l'achèvement du code

Désavantages:

Les lacunes de cette solution sont évidemment que la taille du fichier .js pourrait devenir assez importante. Toutefois, étant donné qu'il est mis en cache par le navigateur, nous ne considérons pas cela comme un problème pour notre application. Cependant – cette mise en cache peut également entraîner le fait que le navigateur ne trouve pas la ressource appelée à partir du code.


Comment cela fonctionne?

Fondamentalement, il a défini un modèle T4 qui pointe vers vos fichiers .resx. Avec un code C #, il parcourt chaque chaîne de ressource et l'additionne aux propriétés de la valeur de la clé pure JavaScript qui sont envoyées dans un seul fichier JavaScript appelé Resources.js (vous pouvez modifier les noms si vous le souhaitez).


Modèle T4 [modifiez en conséquence pour pointer vers votre emplacement des fichiers .resx]

 <#@ 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("'","\\'")#>' }; <# } #> <# } #> 

Du côté Forme / Vue

Pour récupérer la traduction correcte, ajoutez ceci dans votre maître si vous utilisez WebForms:

 <script type="text/javascript"> var locale = '<%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>'; </script> <script type="text/javascript" src="/Scripts/Resources.js"></script> 

Si vous utilisez ASP.NET MVC (comme moi), vous pouvez le faire:

 <script type="text/javascript"> // Setting Locale that will be used by JavaScript translations var locale = $("meta[name='accept-language']").attr("content"); </script> <script type="text/javascript" src="/Scripts/Resources.js"></script> 

L'assistant de MetaAcceptLanguage j'ai obtenu de cette impressionnante publication de Scott Hanselman:

Mondialisation, internationalisation et localisation dans ASP.NET MVC 3, JavaScript et jQuery – Partie 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)); } 

Utilise le

 var msg = Resources.Common.Greeting[locale]; alert(msg); 

Avec un assemblage satellite (au lieu d'un fichier resx), vous pouvez énumérer toutes les chaînes sur le serveur, où vous connaissez la langue, générant ainsi un objet Javascript avec uniquement les chaînes pour la langue correcte.

Quelque chose comme ça fonctionne pour nous (code VB.NET):

 Dim rm As New ResourceManager([resource name], [your assembly]) Dim rs As ResourceSet = rm.GetResourceSet(Thread.CurrentThread.CurrentCulture, True, True) For Each kvp As DictionaryEntry In rs [Write out kvp.Key and kvp.Value] Next 

Cependant, nous n'avons pas encore trouvé de façon de le faire pour les fichiers .resx malheureusement.

JSGettext fait un excellent travail – chargement dynamique des fichiers GNU Gettext .po en utilisant à peu près n'importe quelle langue sur le backend. Google pour "Dynamic Javascript localisation avec Gettext et PHP" pour trouver un passage à niveau pour JSGettext avec PHP (je publierais le lien, mais ce site stupide ne me laissera pas, soupir …)

Modifier : ce devrait être le lien

J'utiliserais une notation objet / tableau:

 var phrases={}; phrases['fatalError'] ='On no!'; 

Ensuite, vous pouvez simplement échanger le fichier JS ou utiliser un appel Ajax pour redéfinir votre liste de phrases.

Il existe une bibliothèque pour localiser les applications JavaScript: https://github.com/wikimedia/jquery.i18n

Il peut faire le remplacement des paramètres, soutient le genre (manipulation judicieuse de l'élève), le nombre (manipulation du pluriel intelligent, y compris les langues qui ont plus d'un formulaire pluriel) et des règles de grammaire personnalisées dont certaines langues ont besoin.

Les chaînes sont stockées dans les fichiers JSON.

La seule exigence est jQuery.

J'ai fait ce qui suit pour localiser JavaScript pour une application mobile exécutant HTML5:

1. Créé un ensemble de fichiers de ressources pour chaque langue les appelant comme "en.js" pour l'anglais. Chacun contenait les différentes chaînes de l'application comme suit:

 var localString = { appName: "your app name", message1: "blah blah" }; 

2. Utilisé Lazyload pour charger le fichier de ressources approprié en fonction de la langue locale de l'application: https://github.com/rgrove/lazyload

3. Passez le code de langue via une Chaîne de requête (Comme je lance le fichier html depuis Android en utilisant PhoneGap)

4. Ensuite, j'ai écrit le code suivant pour charger dynamiquement le fichier de ressources approprié:

 var lang = getQueryString("language"); localization(lang); function localization(languageCode) { try { var defaultLang = "en"; var resourcesFolder = "values/"; if(!languageCode || languageCode.length == 0) languageCode = defaultLang; // var LOCALIZATION = null; LazyLoad.js(resourcesFolder + languageCode + ".js", function() { if( typeof LOCALIZATION == 'undefined') { LazyLoad.js(resourcesFolder + defaultLang + ".js", function() { for(var propertyName in LOCALIZATION) { $("#" + propertyName).html(LOCALIZATION[propertyName]); } }); } else { for(var propertyName in LOCALIZATION) { $("#" + propertyName).html(LOCALIZATION[propertyName]); } } }); } catch (e) { errorEvent(e); } } function getQueryString(name) { name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); var regexS = "[\\?&]" + name + "=([^&#]*)"; var regex = new RegExp(regexS); var results = regex.exec(window.location.href); if(results == null) return ""; else return decodeURIComponent(results[1].replace(/\+/g, " ")); } 

5. À partir du fichier html, je me réfère aux chaînes suivantes:

 span id="appName" 

Eh bien, je pense que vous pouvez considérer cela. Exemple anglais-espagnol:

Ecrivez 2 scripts Js, comme ça:

 en-GB.js lang = { date_message: 'The start date is incorrect', ... }; es-ES.js lang = { date_message: 'Fecha de inicio incorrecta', ... }; 

Côté serveur – code derrière:

 Protected Overrides Sub InitializeCulture() Dim sLang As String sLang = "es-ES" Me.Culture = sLang Me.UICulture = sLang Page.ClientScript.RegisterClientScriptInclude(sLang & ".js", "../Scripts/" & sLang & ".js") MyBase.InitializeCulture() End Sub 

Où sLang pourrait être "en-GB", vous savez, selon la sélection de l'utilisateur actuel …

Appels Javascript:

 alert (lang.date_message); 

Et cela fonctionne, très facile, je pense.

Étendre la réponse de diodeus.myopenid.com: demandez à votre code d'écrire un fichier contenant une matrice JS avec toutes les chaînes requises, puis chargez le fichier / script approprié avant l'autre code JS.

Nous utilisons MVC et avons simplement créé une action de contrôleur pour renvoyer une chaîne localisée. Nous maintenons la culture de l'utilisateur en session et définissons la culture de thread avant tout appel pour récupérer une chaîne de langue, AJAX ou autrement. Cela signifie que nous renvoyons toujours une chaîne localisée.

J'avouerai que ce n'est pas la méthode la plus efficace, mais l'obtention d'une chaîne localisée dans javascript est rarement requise car la plupart des localisations sont effectuées dans nos vues partielles.

Global.asax.cs

 protected void Application_PreRequestHandlerExecute(object sender, EventArgs e) { if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState) { // Set the current thread's culture var culture = (CultureInfo)Session["CultureInfo"]; if (culture != null) { Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } } } 

Action du contrôleur

 public string GetString(string key) { return Language.ResourceManager.GetString(key); } 

Javascript

 /* Retrieve a localized language string given a lookup key. Example use: var str = language.getString('MyString'); */ var language = new function () { this.getString = function (key) { var retVal = ''; $.ajax({ url: rootUrl + 'Language/GetString?key=' + key, async: false, success: function (results) { retVal = results; } }); return retVal; } }; 

La manière MSDN de le faire, c'est essentiellement:

Vous créez un fichier de script distinct pour chaque langue et culture supportée. Dans chaque fichier de script, vous incluez un objet au format JSON qui contient les valeurs de ressources localisées pour cette langue et cette culture.

Je ne peux pas vous dire la meilleure solution pour votre question, mais IMHO c'est la pire façon de le faire. Au moins maintenant, vous savez comment ne pas le faire.