How to use multiple language routes with node and i18n? - node.js

I am building a simple website and would like the links to be translated.
Ex:
about-us / a-propos-de-nous
Currently, I've noticed that to set the language with i18n, you need to redirect the user in order for it to catch on by doing something like:
app.get('/fr', (req, res) => {
i18n.setLocale('fr');
res.cookie('i18n', 'fr');
res.redirect('/');
});
But how would that work if a user visit the following urls directly?
app.get(['/about-us', '/a-propos-de-nous'], (req, res) => {
// How do I set the proper locale here? I can't do any redirect otherwise
// I'll be caught in a redirect loop.
res.render('about-us');
});

You can get the requested path from req.url, you could check which one it was and set the language accordingly.
app.get(['/about-us', '/a-propos-de-nous'], (req, res) => {
if(req.url === '/about-us') {
i18n.setLocale('en');
res.cookie('i18n', 'en');
} else if(req.url === '/a-propos-de-nous') {
i18n.setLocale('fr');
res.cookie('i18n', 'fr');
}
res.render('about-us');
});
You could also prefix the path like example.com/fr/a-propos-de-nous, which would make it a little easier to extract the language from the request.

Related

Express Flash Message over multiple redirects

I have been using express-flash for a project and it has been working fine with redirects and page renders. However, I have a route /dashboard which redirects further into /dashboard/admin & /dashboard/staff as shown in the code below. Passing a message using req.flash and redirecting to /dashboard does not show up on the page. Other pages with single redirects are able to display the messages without any issue. I am guessing this problem is because of the second redirect from /dashboard to /dashboard/.*
req.flash('success_msg','Successful');
res.redirect("/dashboard");
in router.js:
app.get('/dashboard', (req, res) => {
if (req.user.role === "ADMIN") {
res.redirect("/dashboard/admin");
}
if (req.user.role === "STAFF") {
res.redirect("/dashboard/staff");
}
})
Is there a way to work around this issue, adding any statement in my router file to forward messages further into the redirects?
The flash message with value Successful is only available inside the req object in the middleware that handles the /dashboard endpoint. If you want to further redirect, you have to assign again the flash message to the next middleware.
app.get('/dashboard', (req, res) => {
// If there is any flash message with key success_msg,
// give it to the next middleware
if (res.locals.success_msg) {
req.flash('success_msg', res.locals.success_msg)
}
if (req.user.role === "ADMIN") {
res.redirect("/dashboard/admin");
}
if (req.user.role === "STAFF") {
res.redirect("/dashboard/staff");
}
})

response.redirect() with parameters

I want to redirect to a page where the path is like /users/home/:id
response.redirect('/users/home')
The above code will redirect to /users/home but I want to redirect it to a page like '/users/home/1' dynamically with parameters. How shall I solve it?Do explain with some examples
You could use template literals to form the new url, for example:
app.get("/users/home/:id", (req, res) => {
res.redirect(`/users/alternate_home/${req.params.id}`);
});
app.get("/users/alternate_home/:id", (req, res) => {
res.json(users);
});

How to use two responses at once?

I have a working template engine (pug) to fill it's website with content depending from the situation. Acutally that template is rendered for the site '/show'.
Now I also need to change the url of this website depending from the content. That means I need the same template with new content for sites like: '/tree', '/house', '/urban' an do so. '/show' is the starting point, I need to change it's url with the new content.
I'm sure there is an easy answer, but I can't find the fitting question for that. So I can't find the right answer per searchengine. (Express.js res.render() and res.redirect() was my closest success, but it is not helpful for me.
I know, the following code is incorrect, at least because of the two resp.
server.get('/show', (req, resp) => {
loadContent(function(err, content){
if(content){
resp.location('/tree');
resp.render('myTemplate', content);
} else{
console.log(err);
}
})
});
How can I send my content to the template and replace the url to see both on the browser?
to send data to your pug template with express js use this syntax
const router = require('express').Router();
server.get('/show', (req, res, next) => {
loadContent(function(err, content){
if(content){
res.render('myTemplate', { content: content });
} else{
console.log(err);
}
})
and you will get it
script.
var content = !{content};
Well, I've found my problem. My approach was incorrect.
With
server.get('/:kindOfSite', function(req, resp){...});
I'm able to load the same template for different sites.
Learning can get hard sometimes...
Remember that your express route handlers are just functions. There's nothing that forces you to use an anonymous function. You can just use a regular function:
function handleRequest (req, resp) {
loadContent(function(err, content){
if(content){
resp.location('/tree');
resp.render('myTemplate', content);
} else{
console.log(err);
}
})
}
server.get('/show', handleRequest);
server.get('/tree', handleRequest);
server.get('/house', handleRequest);
server.get('/urban', handleRequest);
Indeed, you can do a bit of metaprogramming and call server.get() in a loop:
['/show','/tree','/house','/urban].forEach(route => {
server.get(route,handleRequest)
});
In fact, Express accepts regular expressions as route paths:
server.get(/\/(show|tree|house|urban)/, (req, resp) => {
loadContent(function(err, content){
if(content){
resp.location('/tree');
resp.render('myTemplate', content);
} else{
console.log(err);
}
})
});

How to handle unknown pages in Node.js?

Here is a question I have concerning a Node.js app of mine (working with Express) on Heroku.
I want to handle unknown URL. More precisely:
If I look at this URL in a browser: https://myapp.herokuapp.com/ I see what I expect.
If I look a this one: https://myapp.herokuapp.com/xxyyyzzWhatever I also see what I expect. That is:
Cannot GET /xxyyyzzWhatever
Instead of displaying: Cannot GET /xxyyyzzWhatever
I want to do other things. At this point I have referred to these documents:
http://expressjs.com/en/guide/error-handling.html and http://thecodebarbarian.com/80-20-guide-to-express-error-handling; and I can get quite a bit of control on what is displayed.
I have implemented this kind of code:
app.get('*', function(req, res, next) {
setImmediate(() => { next(new Error('woops')); });
});
app.use(function(error, req, res, next) {
const xPt = req.path.substring(1,req.path.length);
res.json({ message: error.message reachPoint: xPt});
});
But what I really want is to have something like:
if (xPt.substring(0,1) == "A") {display("You are lucky");}
else if (xPt.substring(0,1) == "Z") {display("You are very unlucky");}
else if ((xPt.substring(0,1) >= "B")&&(xPt.substring(0,1) <= "R"))
{goto("https://stackoverflow.com/")}
else {goto("http://www.google.com/")}
Any tip on the way to go?
you can use following:
app.use(function (req, res, next) {
res.status(404).send("Sorry can't find that!")
});
https://expressjs.com/en/starter/faq.html

Express redirect error: can't set headers after they are sent

When this code hits the redirect line it throws the 'Can't set headers after they are sent error' and doesn't redirect. I'm guilty of not fully understanding headers and how express works with them. This link about this error is confusing me a bit, probably because I don't have a basic enough understanding of what's going on. Also, I know this is a bit of a naive approach to authenticating, but I'm just trying to get basic things to work.
app.post('/api/login', function(req, res) {
if (req.body.password === auth.password) {
auth.date = new Date()
res.redirect('/admin')
} else {
console.log("wrong pw")
}
})
UPDATE : thank you to #Brendan Ashworth I missed an obvious else, which I've added now and no longer get the error.
However this line doesn't change the contents of my page
res.sendfile('./public/admin/views/tunes.html')
It worked before I wrapped it with the auth check
var auth = require('../config/auth')
module.exports = function(app) {
/*
* CONTENT API
*/
//...
/*
* Admin Routes
*/
app.get('/admin/login', function(req, res) {
res.sendfile('./public/admin/views/login.html')
})
app.post('/api/login', function(req, res) {
if (req.body.password === auth.password) {
auth.date = new Date()
res.redirect('/admin')
} else {
res.json({message: 'Wrong password!'})
}
})
app.get('/admin', function(req, res) {
if (auth.date) {
res.sendfile('./public/admin/views/tunes.html')
console.log("test") //
} else { //added else
res.redirect('/admin/login')
}
})
app.get('/admin/:url', function(req, res) {
if (auth.date) {
res.sendfile('./public/admin/views/' + req.params.url + '.html')
} else { //added else
res.redirect('/admin/login')
}
})
// frontend routes
// route to handle all angular requests
app.get('*', function(req, res) {
res.sendfile('./public/views/index.html')
})
}
FINAL UPDATE!! The last thing I needed was to handle the redirect client side after sending the file. Simple authentication works perfectly now!
$http.post('/api/login', $scope.auth).success(function() {
window.location.href = '/admin'
})
An explanation of the error Can't set headers after they are sent error:
All HTTP responses follow this basic structure:
.. Response Line ..
.. Headers ..
.. Body ..
If you want to redirect a user, first the Response Line will be sent with a redirect code (lets say 300), then the Headers will be sent with a Location: xxx header.
Then, we can finally send a body (not in the case of a redirect, but in general). However - in the case with your code - you are sending a Body response then trying to redirect the user. Since the headers (and response line) have both already been sent (because you sent the body), it can't send more headers after the body.
An example of this in your code would be:
app.get('/admin', function(req, res) {
if (auth.date) {
res.sendfile('./public/admin/views/tunes.html')
}
res.redirect('/admin/login')
})
If I'm assuming right, you actually want to return after the res.sendfile() call. If auth.date is truthy, then you'll be sending a file (i.e. body response) and then giving a redirect code - that doesn't work.
after redirect just call res.stop();

Resources