Localize Strings in Javascript - javascript

I'm currently using .resx files to manage my server side resources for .NET.
the application that I am dealing with also allows developers to plugin JavaScript into various event handlers for client side validation, etc.. What is the best way for me to localize my JavaScript messages and strings?
Ideally, I would like to store the strings in the .resx files to keep them with the rest of the localized resources.
I'm open to suggestions.

A basic JavaScript object is an associative array, so it can easily be used to store key/value pairs. So using JSON, you could create an object for each string to be localized like this:
var localizedStrings={
confirmMessage:{
'en/US':'Are you sure?',
'fr/FR':'Est-ce que vous ĂȘtes certain?',
...
},
...
}
Then you could get the locale version of each string like this:
var locale='en/US';
var confirm=localizedStrings['confirmMessage'][locale];

Inspired by SproutCore You can set properties of
strings:
'Hello'.fr = 'Bonjour';
'Hello'.es = 'Hola';
and then simply spit out the proper localization based on your locale:
var locale = 'en';
alert( message[locale] );

After Googling a lot and not satisfied with the majority of solutions presented, I have just found an amazing/generic solution that uses T4 templates. The complete post by Jochen van Wylick you can read here:
Using T4 for localizing JavaScript resources based on .resx files
Main advantages are:
Having only 1 place where resources are managed ( namely the .resx
files )
Support for multiple cultures
Leverage IntelliSense - allow for code completion
Disadvantages:
The shortcomings of this solution are of course that the size of the
.js file might become quite large. However, since it's cached by the
browser, we don't consider this a problem for our application. However
- this caching can also result in the browser not finding the resource called from code.
How this works?
Basically he defined a T4 template that points to your .resx files. With some C# code he traverses each and every resource string and add it to JavaScript pure key value properties that then are output in a single JavaScript file called Resources.js (you can tweak the names if you wish).
T4 template [ change accordingly 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("'","\\'")#>'
};
<# } #>
<# } #>
In the Form/View side
To have the correct translation picked up, add this in your master if you're using WebForms:
<script type="text/javascript">
var locale = '<%= System.Threading.Thread.CurrentThread.CurrentCulture.Name %>';
</script>
<script type="text/javascript" src="/Scripts/Resources.js"></script>
If you're using ASP.NET MVC (like me), you can do this:
<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>
The MetaAcceptLanguage helper I got from this awesome 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));
}
Use it
var msg = Resources.Common.Greeting[locale];
alert(msg);

With a satellite assembly (instead of a resx file) you can enumerate all strings on the server, where you know the language, thus generating a Javascript object with only the strings for the correct language.
Something like this works for us (VB.NET code):
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
However, we haven't found a way to do this for .resx files yet, sadly.

JSGettext does an excellent job -- dynamic loading of GNU Gettext .po files using pretty much any language on the backend. Google for "Dynamic Javascript localization with Gettext and PHP" to find a walkthrough for JSGettext with PHP (I'd post the link, but this silly site won't let me, sigh...)
Edit: this should be the link

I would use an object/array notation:
var phrases={};
phrases['fatalError'] ='On no!';
Then you can just swap the JS file, or use an Ajax call to redefine your phrase list.

There's a library for localizing JavaScript applications:
https://github.com/wikimedia/jquery.i18n
It can do parameter replacement, supports gender (clever he/she handling), number (clever plural handling, including languages that have more than one plural form), and custom grammar rules that some languages need.
The strings are stored in JSON files.
The only requirement is jQuery.

I did the following to localize JavaScript for a mobile app running HTML5:
1.Created a set of resource files for each language calling them like "en.js" for English. Each contained the different strings the app as follows:
var localString = {
appName: "your app name",
message1: "blah blah"
};
2.Used Lazyload to load the proper resource file based on the locale language of the app: https://github.com/rgrove/lazyload
3.Pass the language code via a Query String (As I am launching the html file from Android using PhoneGap)
4.Then I wrote the following code to load dynamically the proper resource file:
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.From the html file I refer to the strings as follows:
span id="appName"

Well, I think that you can consider this. English-Spanish example:
Write 2 Js Scripts, like that:
en-GB.js
lang = {
date_message: 'The start date is incorrect',
...
};
es-ES.js
lang = {
date_message: 'Fecha de inicio incorrecta',
...
};
Server side - code behind:
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
Where sLang could be "en-GB", you know, depending on current user's selection ...
Javascript calls:
alert (lang.date_message);
And it works, very easy, I think.

Expanding on diodeus.myopenid.com's answer: Have your code write out a file containing a JS array with all the required strings, then load the appropriate file/script before the other JS code.

The MSDN way of doing it, basically is:
You create a separate script file for each supported language and culture. In each script file, you include an object in JSON format that contains the localized resources values for that language and culture.
I can't tell you the best solution for your question, but IMHO this is the worst way of doing it. At least now you know how NOT to do it.

We use MVC and have simply created a controller action to return a localized string. We maintain the user's culture in session and set the thread culture before any call to retrieve a language string, AJAX or otherwise. This means we always return a localized string.
I'll admit, it isn't the most efficient method but getting a localised string in javascript is seldom required as most localization is done in our partial views.
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;
}
}
}
Controller Action
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;
}
};

Related

How to get domain from email address in Javascript?

I want to get the domain part from an email address, in Javascript. It's easy to extract the domain from an email like via split: "joe#example.com", which is example.com.
However, emails also come in forms like "joe#subdomain1.example.com.uk", of which the domain is example.com.uk, instead of subdomain1.example.com.uk. The problem here is that subdomain1 can be mistakenly considered as part of the domain.
How do I do this reliably?
That is really not a trivial problem as it might seem at first glance.
Luckily there are libs that solves this, tld-extract is a popular choice which uses Mozilla's Public Suffix List (a volunteer based list). The usage is
var parser = require('tld-extract');
console.log( parser("www.google.com") );
console.log( parser("google.co.uk") );
/**
* >> { tld: 'com', domain: 'google.com', sub: 'www' }
* >> { tld: 'co.uk', domain: 'google.co.uk', sub: '' }
*/
To extract the server address part from email address first split by # character like this
const email = "john#sub.domain.com"
const address = email.split('#').pop()
const domain = parser(address).domain
See more in depth discussion about the problem solution check the README of a similar python library.
tldextract on the other hand knows what all gTLDs and ccTLDs look like
by looking up the currently living ones according to the Public Suffix
List (PSL). So, given a URL, it knows its subdomain from its domain,
and its domain from its country code.
Make sure to learn about the list on Public Suffix List website and understand it is based on volunteer work and might not be exhaustive at all time.
The Public Suffix List is a cross-vendor initiative to provide an
accurate list of domain name suffixes, maintained by the hard work of
Mozilla volunteers and by submissions from registries, to whom we are
very grateful.
Since there was and remains no algorithmic method of finding the
highest level at which a domain may be registered for a particular
top-level domain (the policies differ with each registry), the only
method is to create a list. This is the aim of the Public Suffix List.
I agree that the best solution for this problem would be to use a library, like what was suggested in https://stackoverflow.com/a/49893282/2735286.
Yet if you have a long enough list with top level domains and subdomains, you could write some code which extracts whatever characters are found after the '#' sign and then from the domain you try to find out whether you have a top level or subdomain. When you know if you are dealing with a top level domain you know where you can find the main domain name and so everything before it must be a subdomain. The same applies to the subdomain.
This is a naive implementation, but you could try this:
// TODO: needs to have an exhaustive list of top level domains
const topLevelDomains = ["com", "org", "int", "gov", "edu", "net", "mil"];
// TODO: Needs an exhaustive list of subdomains
const subdomains = ["co.uk", "org.uk", "me.uk", "ltd.uk", "plc.uk"];
function extract(str) {
const suffix = str.match(/.+#(.+)/);
if (suffix) {
const groups = suffix.pop().split(".");
const lastPart = groups[groups.length - 1];
if (isSubDomain(groups[groups.length - 2] + "." + lastPart)) {
console.log("Sub domain detected in: " + groups);
if (groups.length > 3) {
console.log("Possible subdomain: " + groups.splice(0, groups.length - 3));
console.log();
}
} else if (isTopLevelDomain(lastPart)) {
console.log("Top level domain detected in: " + groups);
if (groups.length > 2) {
console.log("Possible subdomain: " + groups.splice(0, groups.length - 2));
console.log();
}
}
}
}
function isTopLevelDomain(lastPart) {
return (topLevelDomains.find(s => s === lastPart));
}
function isSubDomain(lastPart) {
return (subdomains.find(s => s === lastPart));
}
extract("joe#example.com");
extract("joe#subdomain1.example.co.uk");
extract("joe#subdomain2.example.edu");
extract("joe#subdomain3.example.ltd.uk");
extract("joe#test.subdomain3.example.plc.uk");
Please challenge the logic, if I got this wrong.
// Not a proper solution because of email pattern is not fixed. Use below if it is appropriate solution according to your problem .
jQuery( document ).ready(function() {
//var input = 'joe#subdomain1.com';
var input = 'joe#subdomain1.example.com.uk';
var first_split = input.split("#")[1];
var second_split = first_split.split(".");
if(second_split.length == 2) {
console.log('domain is : '+first_split);
} else if(second_split.length > 2) {
var str = first_split.substring(first_split.indexOf(".") + 1);
console.log('domain is : '+str);
}
});

Scrape webpage that requires md5 hash as a parameter

I am trying to scrape the data from the below link, in a c# console app:
https://www.eex-transparency.com/homepage/power/germany/production/availability/non-usability
Using the developer tools in chrome I can see that its possible to get a json response, the url to get this is:
https://www.eex-transparency.com/dsp/tem-12?country=de&expires=1454345128&md5=TRhtJei_go4ueLeekBc8yw
the website uses this js file (https://www.eex-transparency.com/assets/js/tpe-website.js) to generate the expires and md5 hash key. I think I've figured out that the expires value is a unix datetime. I have never used javascript before so finding it hard to figure out how they construct the md5.
The Javascript that generates these code is:
generateCryptedParams=function(url,clientIP)
{
var cryptedParams,md5,md5Encoded,md5WithoutSpeciaChars,parser,timePoint,urlPath;
return timePoint=moment().tz("Europe/Berlin").add(1,"minute").unix(),
parser=document.createElement("a"),
parser.href=url,
urlPath=parser.pathname,
"/"!==urlPath[0]&&(urlPath="/"+urlPath),
md5=CryptoJS.MD5(urlPath+timePoint+clientIP+" zYeHzBomGdgV"),
md5Encoded=md5.toString(CryptoJS.enc.Base64),
md5WithoutSpeciaChars=replaceSpecialChars(md5Encoded),
cryptedParams={"expires":timePoint,"md5":md5WithoutSpeciaChars}
}
replaceSpecialChars=function(str)
{
var key,specialChars,value;
specialChars={"=":"","\\+":"-","/":"_","%":"_"};
for(key in specialChars)
value=specialChars[key],
str=str.replace(new RegExp(key,"g"),value);
return str
}
As i said I think I'm comfortable with the timepoint part but the md5 is confusing me. Below is my C# code to replicate their but when I pass the md5 hash their site returns a 403 Forbidden error.
public Tuple<string, Int32> GenerateCrypto(string url, string ipAddress)
{
string cetId = "Central European Standard Time";
TimeZoneInfo cetZone = TimeZoneInfo.FindSystemTimeZoneById(cetId);
var CETDateTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, cetZone);
//Int32 unixTimestamp = (Int32)(CETDateTime.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
Int32 unixTimestamp = (Int32)(DateTime.UtcNow.AddMinutes(1).Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
url = url.Split('/')[3];
var md5 = CipherUtility.GenerateMd5(url + unixTimestamp + ipAddress + " zYeHzBomGdgV");
var md5Encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(md5));
var md5withoutSpecialCharts = replaceSpecialChars(md5Encoded);
md5withoutSpecialCharts = md5withoutSpecialCharts.Substring(0, 22);
return new Tuple<string, Int32>(md5withoutSpecialCharts, unixTimestamp);
}
The solution was that I needed to concatenate a const string to all the elements before hashing it.

Read a file with latest Date from a folder using JQuery

I already have a folder, with the files in it with names below in a specific format i.e. MODEL_RELEASEDATE
File names in the folder named Smartphone
SmartphoneA_11122012
SmartphoneA_01022013
SmartphoneA_09102013
SmartphoneA_10072012
SmartphoneA_12042012
**SmartphoneB_08282013**
SmartphoneB_04152013
SmartphoneB_08282012
SmartphoneB_01062013
.
.
.
.
and so on
I want to write a jquery code where I can use a specific keyword from format, from above list, I will pass the value SmartphoneA and I should be able to read the file with the latest release date. Same as in case when I pass the keyword SmartphoneB.
If I pass k/w SmartphoneB, result should be served from file highlighted above, i.e. SmartphoneB_08282013
my current code reads the file name only with specific k/w. I have few alterations to be made.
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
var metaKeywords=$('meta[name=keywords]').attr("content");//this utility works based upon the keywords on the pages.
var reqdKeyword = new Array();
reqdKeyword = metaKeywords.split(",");
var randKeyword = reqdKeyword[Math.floor(Math.random() * reqdKeyword.length)];
var cdnUrl = "http://abc.com/xyz/mobiles/";
var jsnUrl = ".json?callback=showDetail";
var finalUrl= cdnUrl.concat(randKeyword.trim()).concat(jsnUrl);
/*
Rest of the code goes here
*/
</script>
The cool thing about dates is that you can easily sort them if you have the date in "descending" order (i.e., year month day hour second). Using that, we can go through your files to grab just the ones that start with the right prefix, then easily grab the latest one:
var filenames = [
'SmartphoneA_11122012',
'SmartphoneA_01022013',
'SmartphoneA_09102013',
'SmartphoneA_10072012',
'SmartphoneA_12042012',
'SmartphoneB_08282013',
'SmartphoneB_04152013',
'SmartphoneB_08282012',
'SmartphoneB_01062013'
],
whichPhone = 'SmartphoneB', // Dummy value, this would come from user interaction or whatever
possibleFiles = [];
// This goes through your list of filenames and picks out just the ones that match `whichPhone`, then puts them into another array containing a "cleaned-up" date and some other metadata-esque stuff
for (var i = 0, j = filenames.length; i < j; i++) {
var filename = filenames[i];
if (filename.indexOf(whichPhone) > -1) {
possibleFiles.push({
index: i,
filename: filename,
date: parseInt(filename.split('_')[1].replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}), 10)
});
}
}
// Now we go through the `possibleFiles` and figure out which one has the latest date
var latestFileDate = 0,
theActualFilenameYouWantFinally;
for (var i = 0, j = possibleFiles.length; i < j; i++) {
var possibleFile = possibleFiles[i];
if (possibleFile.date > latestFileDate) {
latestFileDate = possibleFile.date;
theActualFilenameYouWantFinally = filenames[possibleFile.index];
}
}
// And, finally, your result
console.log(theActualFilenameYouWantFinally);
EDIT: I didn't use jQuery for this answer because meh, you don't really need jQuery for things like this. Don't get me wrong, John Resig is brilliant, and I use jQuery in almost everything, but for loops are damned fast and easy to work with, and stuff like this isn't really jQuery's strong suit anyhow.
You will need a server-side code to return you a list of URIs (file names), then you can write JavaScript code to parse it (but in this case it is probably better if your server-side code will return the right name right away based on query string). In the worst case scenario you can place a dir.txt file on the server which will be listing all the files in that folder and e.g. run cron job to update it as needed.
jQuery will have no way to list remote files on the server unless your server supports it in one way or another.
Update
Once you have the file you need:
a) tokenize it into an array, e.g. like this
var names = dir.split("\n");
b) leave only strings starting with keyword and cut keyword off
names = $(names).map(function(n,i) {
return (n.indexOf(keyword) == 0) ? n.split('_')[1] : null;
}).get();
now you have an array like this ['11122012', '01022013', ...]
c) find max date in this array
var dateNum = Math.max.apply( null,
$.map(names,function(n,i){ return parseInt(
n.replace(/(\d{2})(\d{2})(\d{4})/, function(match, month, day, year) {
return year + month + day;
}))
}) );
var maxDate = dateNum.toString().replace(/(\d{4})(\d{2})(\d{2})/,
function (match, year, month, day) { return month + day + year; }
);
var fileName = keyword + "_" + maxDate;
voila, your fileName contains the name with max date.
There are other ways of doing it, e.g. really parsing the date into Date object. Also, you can simply iterate your files once, without array mapping and Math.max() iterator. As the amount of code wins over speed here, to find the optimal one depends on where you could re-use its bits and pieces without compromising maintainability.
http://jsfiddle.net/Exceeder/VLB2E/

Dojo Toolkit: how to escape an HTML string?

A user of my HTML 5 application can enter his name in a form, and this name will be displayed elsewhere. More specifically, it will become the innerHTML of some HTML element.
The problem is that this can be exploited if one enters valid HTML markup in the form, i.e. some sort of HTML injection, if you will.
The user's name is only stored and displayed on the client side so in the end the user himself is the only one who is affected, but it's still sloppy.
Is there a way to escape a string before I put it in an elements innerHTML in Dojo? I guess that Dojo at one point did in fact have such a function (dojo.string.escape()) but it doesn't exist in version 1.7.
Thanks.
dojox.html.entities.encode(myString);
Dojo has the module dojox/html/entities for HTML escaping. Unfortunately, the official documentation still provides only pre-1.7, non-AMD example.
Here is an example how to use that module with AMD:
var str = "<strong>some text</strong>"
require(['dojox/html/entities'], function(entities) {
var escaped = entities.encode(str)
console.log(escaped)
})
Output:
<strong>some text</strong>
As of Dojo 1.10, the escape function is still part of the string module.
http://dojotoolkit.org/api/?qs=1.10/dojo/string
Here's how you can use it as a simple template system.
require([
'dojo/string'
], function(
string
){
var template = '<h1>${title}</h1>';
var message = {title: 'Hello World!<script>alert("Doing something naughty here...")</script>'}
var html = string.substitute(
template
, message
, string.escape
);
});
I tried to find out how other libraries implement this function and I stole the idea of the following from MooTools:
var property = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
elem[property] = "<" + "script" + ">" + "alert('a');" + "</" + "script" + ">";
So according to MooTools there is either the innerText or the textContent property which can escape HTML.
Check this example of dojo.replace:
require(["dojo/_base/lang"], function(lang){
function safeReplace(tmpl, dict){
// convert dict to a function, if needed
var fn = lang.isFunction(dict) ? dict : function(_, name){
return lang.getObject(name, false, dict);
};
// perform the substitution
return lang.replace(tmpl, function(_, name){
if(name.charAt(0) == '!'){
// no escaping
return fn(_, name.slice(1));
}
// escape
return fn(_, name).
replace(/&/g, "&").
replace(/</g, "<").
replace(/>/g, ">").
replace(/"/g, """);
});
}
// that is how we use it:
var output = safeReplace("<div>{0}</div",
["<script>alert('Let\' break stuff!');</script>"]
);
});
Source: http://dojotoolkit.org/reference-guide/1.7/dojo/replace.html#escaping-substitutions

Is there a way to do String.Format() in javascript?

So I have a client who does not allow any server side coding, except in rare occurences classic asp, so everything is HTML and javascript.
So basically I need to build a URL from the form and then redirect. Javascript isn't necessarily my thing, but this would take me 5 minutes in asp.net using String.Format.
Is there a String.Format method in javascript?
Ouch, that sucks.
Stolen from another post:
String.format = function() {
var s = arguments[0];
for (var i = 0; i < arguments.length - 1; i++) {
var reg = new RegExp("\\{" + i + "\\}", "gm");
s = s.replace(reg, arguments[i + 1]);
}
return s;
}
no, there's no such thing in javascript, but some people have already written a printf for js
e.g JavaScript equivalent to printf/string.format
I was looking for a similar thing and settled on Prototype's "Template" object.
From the Prototype examples
// the template (our formatting expression)
var myTemplate = new Template(
'The TV show #{title} was created by #{author}.');
// our data to be formatted by the template
var show = {
title: 'The Simpsons',
author: 'Matt Groening',
network: 'FOX'
};
// let's format our data
myTemplate.evaluate(show);
// -> "The TV show The Simpsons was created by Matt Groening."

Categories

Resources