Related
I'm working on a JavaScript app and have so far entered all my strings as plain text.
This is starting to feel really hacky (I'm used to gettext) so I'd prefer to wrap them all in something like {{translatable_string}} and have a gulp task just search/replace them all during the build step.
So, my question is; is there a generic (no framework-specific like angular-gettext or something like that) gettext replacer out there?
Obviously it doesn't even have to be connected to JavaScript in any way, you should be able to run it on any file type and have {{translatable_string}}:s be translated.
You may want to look into using gulp-replace. As they explained in this answer, you should be able to use it to find and replace any string that you want in the stream.
I suggest a database of strings for your translations if dynamic generation of page content is possible for your app. Starting with English or whichever is normal but the need to localize content is a tough issue without a robust system. A simple MongoDB table can be used to store the content, and when the app needs an interface it can be loaded with the right localized strings. As a for instance:
if(err) alert("Please turn off caps lock");
could become:
if(err) alert(Please_turn_off_caps_lock.English);
If you are needing to build static pages with gulp, a database in conjunction with gulp-replace sounds interesting. Using gulp-data to call up and package the strings, you can then feed it to gulp-replace and alter the files. The extensible nature of databases or document stores enable you to expand your localization without hacking on individual files or trees all the time.
Try gulp-gettext-parser.
var gettext = require("gulp-gettext-parser");
var rename = require("gulp-rename");
gulp.task("gettext", function() {
return gulp.src("src/**/*.js")
.pipe(gettext())
.pipe(rename("bundle.po"))
.pipe(gulp.dest("dist/"));
});
Perhaps what you need is mustache.js, take a look: https://github.com/janl/mustache.js/
I'm not used to work with mustache, but I had to do some updates in a project done with it, and I was surprised the capabilities it have.
If you're familiar with jade (now renamed to pug), you'll find is something similar but at the end, you're not forced to generate only html files, you cand generate any kind of text file.
This blog could be helpful to understand the differences between some other templating languages over Nodejs: https://strongloop.com/strongblog/compare-javascript-templates-jade-mustache-dust/
Here is what I intend to build:
There is a service providing data with RESTful JSON-only API. The server setup is Python + Flask.
There are several clients making use of this API, like a normal web app, mobile-compatible client and a Facebook App.
Now, my assumptions/decisions:
I decided on the server providing only data through JSON, thus handing over the presentation completely to the client-side.
I desire to make the web app mobile compatible, thus eliminating need of a separate mobile client.
Also, for Facebook app, I decided to use Facebook Canvas, which would render parts of the normal web app, thus reusing the code.
Feel free to correct me if anything is wrong in above assumptions. Though the above is theoretically possible, I would like to know if the practical implementation is feasible or not.
Now, the web app, after having fetched the base page/template from server, will have to handle the rendering dynamically after fetching data through JSON API. The data is quite simple: multiple-option questions, answering which user receives another question. At the end, user can share the result or invite other users.
With this setup, do I need a framework like angularjs or jQuery would suffice?
My main concern here is how do I handle internationalization? I initially intended to user Flask-Babel to internationalize HTML templates. But having zeroed in on JSON-only API, I don't have a clue as to how/where I handle it now: on client-side or server-side? What are the tools I use for it?
One approach I could think of was to have data in different languages on server itself, and send the JSON response with data in appropriate language, depending on some attribute the client sends in request.
Another approach is to let client do all the translation for a common dataset that server sends. I am not sure of this approach though.
You could find this plugin really helpful.
As far as the usage , it is quite simple to set it up for a single page application that is powered by a JSON API.
If we take a look at a sample usage :
HTML:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="[PATH]/jquery.js" /> // optional
<script type="text/javascript" src="[PATH]/i18next.js" />
</head>
<body>
<ul class="nav">
<li></li>
<li></li>
<li></li>
</ul>
</body>
Json (loaded resource):
{
"app": {
"name": "i18next"
},
"nav": {
"home": "Home",
"page1": "Page One",
"page2": "Page Two"
}
}
JS:
i18n.init(function(t) {
// translate nav
$(".nav").i18n();
// programatical access
var appName = t("app.name");
});
https://github.com/wikimedia/jquery.i18n may be close match. It can handle a lot of languages and messages are in json files and it is complete client side library.
If all of your interface code lives on the client side, so should your i18n. You would use a i18n library that works with the JavaScript framework you are using. For angular, that might be angular-gettext.
If you are developing several client you might use different i18n libraries in different client applications. Try to make sure they all compile gettext .po files – it will make it easier for your translators.
Using jQuery, Angular, etc. is a decision you should make based on your comfort with the technology, the needs of your application, and compatibility with the Facebook Canvas approach. Angular has powerful data binding, but it requires a mind shift compared to jQuery, for instance, so I suggest poking around with each to see if they meet your needs.
As for internationalization, you can use a plugin like jQuery.i18n, or you could roll your own, something I have done with jQuery and jQuery.Mustache for templating. The short version is that you use HTML templates to store your layout, then render them from inside jQuery like so:
var data = {myLabel: 'Some label', myOtherLabel: 'Some Other Label'};
$("#myDiv")
.html( $.Mustache.render( "MyTemplateId", data ) );
in html template:
<script type="text/html" id="MyTemplateId">
<div>
<label for="myInput">{{MyLabel}}</label> <input name="myInput" id="myInput type="text"/>
<label for="myOtherInput">{{MyOtherLabel}}</label> <input name="myOtherInput" id="myOtherInput type="text"/>
</div>
and on your page layout:
<div id="myDiv>
<!-- dynamic content inserted here -->
</div>
You use a loader command with jQuery.Mustache (https://github.com/jonnyreeves/jquery-Mustache) to load your templates from the server, and since you are using templates, you can fill in your values based on user language selection. How you store your internationalized data is dependent on your app. As Michael suggested, if it is a small amount of static content, maybe you just store it all in your JS files as constants and load into your Mustache render() methods as needed. If you have a larger amount/dynamic multilingual content, you should probably store it on the server and load it dynamically. One consideration is the number of languages you plan to support. If you go beyond a handful of languages, consider storing it on the server and loading language data on demand.
I like this approach because it gives you granular, runtime control over your layout and over internationalization. It also stores the data on the server but loads programatically from the client, maintaining a clean separation of concerns for your application layers.
As for responsive/mobile friendly design, using templating (Mustache) and checking the viewport at load time allows you to determine browser capabilities and serve the approrpriate layout without having to prompt the user to select a mobile/desktop experience.
If you go this route, you should also research script loaders like RequireJS and StealJS to handle dependency loading for your scripts, and to handle the initial browser check and layout generation.
Your question is too broad. I can only answer part of it and here are some of the answers:
I desire to make the web app mobile compatible, thus eliminating need of a separate mobile client.
In order to make sure that things are working fine you need to handle
Also, for Facebook app, I decided to use Facebook Canvas, which would render parts of the normal web app, thus reusing the code.
I am not sure.
With this setup, do I need a framework like angularjs or jQuery would suffice?
As you tagged that you are targeting this as a single page application. Therefore, I would recommend you to go for single page frameworks like Anglarjs, knockout.js or Node.js. A quick and good comparison between these frameworks can be found from here
Also this post shares how to implement Internationalization in Angularjs
My main concern here is how do I handle internationalization?
some of these frameworks provide support for handling internationalization and localization natively. For other you can find some links that will help you achieve internationalization.
Whereas if you use jQuery you will to define your own framework for handling single-page-application and apart for that you will need a huge bunch of add-on's to accomplish your objective.
Hope this helps!!!
Steps to implement i18n via js & json:
define css class for i18n tag, e.g. <span class="i18n" id="i18n_username"></span>
define i18n values for different language in different .properties file, e.g. in userhome_en_US.properties, there is a key value: username = Username
write backend API to load .properties file by language, and return in json key-value format, e.g. send param: lang=en_US, page=userhome to I18nAction -> loadI18n(), then it will return json value via ajax: {"username":"Username"},
write js function to load i18n key-value by lang & page param,
update i18n text on web page, by get the tag via css class, and replace content, e.g. use jquery to get all span tag that has class="i18n", then remove the i18n_ prefix of the id, then use it as key to get the value from returned json, then replace the content of span,
I did write util programs like this, it's quite flexible & easy to use. The basic concept is come from struts2 framework's i18n feature.
Although I don't know your technical constraints in detail, I believe it all depends on your volume of data :
If you have few "questions / answers" that probably won't evolve much over time, you can treat I18N as constants. Putting everything on the client side makes sense.
If you have a big amount of "questions / answers" that will probably evolve, I believe you have to treat I18N as data.
Since you have made a JSON API, the odds are that your Q/A is your data, and it already belongs to your server side.
The real question is : do you want to deliver a new version of your client app everytime you add or correct a question?
That's why I would do this :
One approach I could think of was to have data in different languages on server itself, and send the JSON response with data in appropriate language, depending on some attribute the client sends in request.
edit (precision) : I'm talking about the questions and answers. For the application messages (menus, text, help messages, etc), you should use your client framework's i18n components. The other answers provide a lot of good tools.
When building webapps with MVC web framworks like Django, Kohana, Rails and the like, I put together the application without JS-driven components initially, and then add them afterwards as "improvements" to the UI.
This approach leads to non-intrusive JS, but I don't have a good "standard" way of how to go about organizing the JS work. Most of the JS I write in apps like these are 10-30 line JQuery snippets that hook into some very specific part of the UI.
So far I often end up inlining these things together with the part of the UI they manage. This makes me feel dirty, I'd like to keep the JS code as organized as the python / php / ruby code, I'd like for it to be testable and I'd like for it to be reusable.
What is the best way to go about organizing JS code in a setup like this, where we're not building a full-blown JS client app, and the main meat is still server side?
I am also very interested in what other people have to say about this. The approach I've taken is to use object literal notation to store the bulk of the function, and store these in one file included on all pages (the library)
uiHelper = {
inputDefault:function(defaulttext){
// function to swap default text into input elements
},
loadSubSection:function(url){
// loads new page using ajax instead of refreshing page
},
makeSortable:function(){
// apply jQuery UI sortable properties to list and remove non javascript controls
}
}
Then I include a .js file on any page that needs to use the library that ties the elements on that page to the function in the library. I've tried to make each function as reuseable as possible and sometimes the event binding function on the page calls several of my library functions.
$(document).ready(function(){
$('#mybutton').live('click',uiHelper.loadSubSection);
//more complicated helper
$('#myotherbutton').live('click',function(){
uiHelper.doThisThing;
uiHelper.andThisThing;
});
});
edit: using jsDoc http://jsdoc.sourceforge.net/ notation for commenting for these functions can produce documentation for the 'library' and helps keep your code easy to read (functions split by comments).
The following question is along similar lines to your own - you should check it out...
Commonly accepted best practices around code organization in JavaScript
When dealing with JS code, you should first analyze whether it will be used right away when the page loads. If it's not used right away (meaning the user must do something to invoke it) you should package this into a JS file and include it later so the load time is perceived faster for the user. This means that anything that the user will sees should go first and JS related to the functionality should be imported near the end of the file.
Download this tool to analyze your website: http://getfirebug.com/
If the JS code is small enough, it should just be inline with the HTML.
Hope that helps a bit.
For quick little user interface things like that I put everything into a single javascript file that I include on every page. Then in the javascript file I check what exists on the page and run code accordingly. I might have this in UIMagic.js for example. I have jQuery, so excuse those jQuery-isms if they aren't familiar to you.
function setupMenuHover() {
if ($("li.menu").length) { // The page has a menu
$("li.menu").hover(function() { ... }, function() { ... });
}
}
$(setupMenuHover);
function setupFacebookWizbang() {
if (typeof FB != "undefined") { // The page has Facebook's Javascript API
...
}
}
$(setupFacebookWizbang);
I've found this to be a sane enough approach.
My preferred method is to store inline javascript in it's own file (so that I can edit it easily with syntax highlighting etc.), and then include it on the page by loading the contents directly:
'<script type="text/javascript">'+open('~/js/page-inline.js').read()+'</script>'
This may not perform well though, unless your templating library can cache this sort of thing.
With Django you might be able to just include the js file:
<script type="text/javascript">
{% include "js/page-inline.js" %}
</script>
Not sure if that caches the output.
If you are still worried about being 'dirty', then you could check out the following projects, which try to bridge the server/client side language mismatch:
http://pyjs.org/ (Python generating JavaScript)
http://code.google.com/webtoolkit/ (Java generating JavaScript)
http://nodejs.org/ (JavaScript all the way!)
When I first started with Javascript, I usually just put whatever I needed into functions and called them when I needed them. That was then.
Now, as I am building more and more complex web applications with Javascript; taking advantage of its more responsive user interaction, I am realizing that I need to make my code more readable - not only by me, but anyone who replaces me. Besides that, I would like the reduce the moments of 'what the heck, why did I do this' when I read my own code months later (yes, I am being honest here, I do have what the heck was I thinking moments myself, although I try to avoid such cases)
A couple weeks ago, I got into Joose, and so far, it has been good, but I am wondering what the rest do to make their chunk their codes into meaningful segments and readable by the next programmer.
Besides making it readable, what are your steps in making your HTML separated from your code logic? Say you need to create dynamic table rows with data. Do you include that in your Javascript code, appending the td element to the string or do you do anything else. I am looking for real world solutions and ideas, not some theoretical ideas posed by some expert.
So, in case you didnt't understand the above, do you use OOP practices. If you don't what do you use?
For really JS-heavy applications, you should try to mimic Java.
Have as little JS in your HTML as possible (preferably - just the call to the bootstrap function)
Break the code into logical units, keep them all in separate files
Use a script to concatenate/minify the files into a single bundle which you will serve as part of your app
Use JS namespaces to avoid cluttering up the global namespace:
var myapp = {};
myapp.FirstClass = function() { ... };
myapp.FirstClass.prototype.method = function() { ... };
myapp.SecondClass = function() { ... };
Using all these techniques together will yield a very manageable project, even if you are not using any frameworks.
I use unobtrusive javascript, so, outside of the script tags I don't keep any javascript in the html.
The two are completely separated.
A javascript function will start when the DOM tree is completed, which will go through the html and add the javascript events, and whatever else needs to be changed.
In order to organize, I tend to have some javascript files that are named similar to the html pages that they use, and then for common functions I tend to group them by what they do, and pick a name that explains that.
So, for example, if I have UI functions then I may call them: myapp_ui_functions.js
I try to put the name of the application in the filename, unless there is some javascript that is common to several projects, such as strings.js.
I have (usually) one file that contains a bunch of functions and that's it. That is included in every page that uses Javascript. In the pages themselves, I'll make the calls to the functions like:
$(function() {
$("#delete").click(delete_user);
$("#new").click(new_user);
});
where delete_user() and new_user() are defined in the external file.
I too use unobtrusive Javascript, which for me means jQuery (there are other libraries that are unobtrusive).
You don't want a separate file for each page. That just means more unnecessary external HTTP requests. With one file—assuming you've cached it effectively—it'll be downloaded once and that's it (until it changes).
If I have a large amount of Javascript or the site is effectively split into multiple areas then I may split the Javascript but that's not often the case.
Also, in terms of my source code, I may have multiple JS files but I'll often end up combining them into one download for the client (to reduce HTTP requests).
More at Multiple javascript/css files: best practices? and Supercharging Javascript in PHP.
I've been rewriting a lot of my reusable code as jQuery plugins. I moved to jQuery from Prototype when I started doing ASP.NET MVC. Overtime I've migrated a lot my reusable code, or at least the ideas, from Prototype-based OO to jQuery-style plugins. Most of these are stored in their own JS files (mainly intranet apps so page load speed is pretty high anyway despite the extra requests). I suppose I could add a build step that coalesces these if I needed to.
I've also settled on a MasterPage approach that uses a ContentPlaceHolder for scripts that is right before the closing body tag. The standard jQuery/jQuery UI loads, and any other common JS goes right before the script placeholder in the MasterPage. I have tiny bit of JS at the top of the MasterPage that defines an array that holds any functions that partial views need to run on page load. These functions are run from the base document.ready() function in the MasterPage.
All of my JS is completely separate from my mark up. Some JS may exist in partial views -- these are encapsulated when the partial may be included more than once to make it specific to that instance of the view -- but generally not. Typically only included in the placeholders so that it's loaded at the bottom of the page.
Also, if you want to go OO heavy, check out mochikit: http://www.mochikit.com/
I find that developing your javascript using OO methodology is the way to go if you want it to be clean, readable and even somewhat secure. I posted the following question
Cleanest format for writing javascript objects
And got some fantastic responses on how to write my javascript code well. If you follow these basic principles you can use almost any library, such as yui, jquery and prototype, with ease.
https://urbantastic-blog.tumblr.com/post/81336210/tech-tuesday-the-fiddly-bits/amp
Heath from Urbantastic writes about his HTML generation system:
All the HTML in Urbantastic is completely static. All dynamic data is sent via AJAX in JSON format and then combined with the HTML using Javascript. Put another way, the server software for Urbantastic produces and consumes JSON exclusively. HTML, CSS, Javascript, and images are all sent via a different service (a vanilla Nginx server).
I think this is an interesting model as it separates presentation from data physically. I am not an expert in architecture but it seems like there would be a jump in efficiency and stability.
However, the following concerns me:
[subjective] Clojure is extremely powerful; Javascript is not. Writing all the content generation on a language created for another goals will create some pain (imagine writing Javascript-type code in CSS). Unless he has a macro-system for generating Javascript, Heath is probably up to constant switching between JavaScript and Clojure. He'll also have a lot of JS code; probably a lot more than Clojure. That might not be good in terms of power, rapid development, succinctness and all the things we are looking at when switching to LISP-based langauges.
[performance] I am not sure on this but rendering everything on user's machine might lag.
[accessibility] If you have JS disabled you can't use site at all.
[accessibility#2] i suspect that a lot of dynamic data filling with JavaScript will create cross-browser issues.
Can anyone comment? I'd be interested in reading your opinions on this type of architecture.
References:
Link to discussion on HN.
Link to discussion on /r/programming.
"All the HTML in Urbantastic is completely static. All dynamic data is sent via AJAX in JSON format and then combined with the HTML using Javascript."
I think that's the standard model of an RIA. The emphasis word seems to be 'All' here. Cause in many websites a lot of the dynamic content is still not obtained through Ajax, only key features are.
I don't think the rendering issues would be a major bottleneck if you don't have a huge webpage with a lot of elements.
JS accessibility is indeed a problem. But then, users who want to experience AJAX must have JS enabled. Have you done a survey on how many of YOUR users don't have it enabled?
The advantage is, you can serve 99% (by weight) of the content through CDN (like Akamai) or even put it on external storage (eg. S3). Serving only the JSON it's almost impossible for a site to get slashdoted.
When AJAX began to hit it big, late 2005 I wrote a client-side template engine and basically turned my blogger template into a fully fledged AJAX experience.
The thing is, that template stuff, it was really easy to implement and it eliminated a lot of the grunt work.
Here's how it's was done.
<div id="blogger-post-template">
<h1><span id="blogger-post-header"/></h1>
<p><span id="blogger-post-body"/><p>
<div>
And then in JavaScript:
var response = // <- AJAX response
var container = document.getElementById("blogger-post-template");
if (!template) { // template context
template = container.cloneNode(true); // deep clone
}
// clear container
while(container.firstChild)
container.removeChild(template.firstChild);
container.appendChild(instantiate(template, response));
The instantiate function makes a deep clone of the template then searches the clone for identifiers to replace with data found in the response. The end result is a populated DOM tree which was originally defined in HTML. If I had more than one result I just looped through the above code.