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.