Say my web app has two locales: English(myapp.com/en/
) and French(myapp.com/fr/
). I want to localize my 404 pages, so that request to myapp.c
One way of achieving this functionality is by using rewrites:
{
...
"hosting": {
"rewrites": [
{
"source": "/fr/**",
"destination": "/fr/404.html"
},
{
"source": "**",
"destination": "/en/404.html"
}
]
}
This will serve the /fr/404.html/
page for unmatched requests inside /fr/
directory and /en/404.html
for any other unmatched request.
The downside of this approach is that the returned status code is 200 instead of 404.
A better solution is to rewrite unmatched requests to Cloud Functions that return the needed 404 page and the 404 status code. Note, that the 404 pages have to be located in functions/lib
directory, not public
.
Also, with the use of proper Cache-Control
header, you can allow the Firebase Hosting to cache the output of the Functions so that they don't have to run every time a 404 page is requested.
Firebase config:
{
...
"hosting": {
"rewrites": [
{
"source": "/fr/**",
"function": "pageNotFoundFr"
},
{
"source": "**",
"function": "pageNotFound"
}
]
}
The functions:
exports.pageNotFound = functions.https.onRequest((req, res) => {
res.set("Cache-Control", "public, max-age=31536000")
res.status(404).sendFile("en/404.html", {root: __dirname})
})
exports.pageNotFoundFr = functions.https.onRequest((req, res) => {
res.set("Cache-Control", "public, max-age=31536000")
res.status(404).sendFile("fr/404.html", {root: __dirname})
})
But this approach duplicates the code and can be messy in case you have more languages.
It would be better to extract the request handler into a function:
exports.pageNotFound = functions.https.onRequest(notFoundHanler("en"))
exports.pageNotFoundFr = functions.https.onRequest(notFoundHanler("fr"))
function notFoundHandler(lang) {
return function (req, res) {
res.set("Cache-Control", "public, max-age=31536000")
res.status(404).sendFile(`${lang}/404.html`, {root: __dirname})
}
}
Update: I filed a feature request for multiple 404 pages to Firebase and they replied that it will be taken into consideration.
As of August 12th 2020, Firebase Hosting now includes support for i18n internalization.
Here's how to use it:
localized
) under your public
directory.firebase.json
file to include a reference to this new directory:// firebase.json
"hosting": {
"public": "public",
"ignore": [
// ...
],
"i18n": {
"root": "/localized" // directory that contains your "i18n content"
}
// ...
}
localized
directory, create a new directory named fr
, and that's where you can add your french 404.html
file.firebase deploy
to deploy your site and now your french users should be redirected to the correct page :)See the Firebase Docs for more information on country and language codes.