Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug?] 404 page not generated for selected language #284

Open
nathancatania opened this issue Dec 20, 2023 · 7 comments
Open

[Bug?] 404 page not generated for selected language #284

nathancatania opened this issue Dec 20, 2023 · 7 comments

Comments

@nathancatania
Copy link

I have a site with two languages: English and Japanese.

If a user hits the 404 page when the English language is selected (English is the default), the nav and all elements switch to Japanese and the user is left on the Japanese version of the site.

This also occurs with the site for this plugin!

  1. Access the English version of the site: https://ultrabug.github.io/mkdocs-static-i18n/
  2. Click a URL (or edit the URL) that points to a page that doesn't exist, eg: https://ultrabug.github.io/mkdocs-static-i18n/w
  3. The URL will be that of the English site (and the page that doesn't exist), but the site itself will be the French version.

image

  1. Attempting to navigate away from the page results in the user being stuck on the alternative language (i.e: French) and having to use the language switcher to get back.
@kamilkrzyskow
Copy link
Contributor

AFAIK only one 404 page is allowed, as the web server has to load a working file with a proper error message and styling. As for why the 404 page is in French/Japanese is because it's the last language that is built, and therefore overwrites the English (initial) version.

I don't think there is an easy solution to this, because the 404 html source is rendered in another language, so even if there was some kind of working solution to remember the selected language it still wouldn't help in this case 🤔

The only solution I see right now, is to override the 404 page yourself and define your own additional logic on the JavaScript side to render the correct language, which of course I understand, isn't ideal.

@ultrabug
Copy link
Owner

Same as @kamilkrzyskow this is problem is tied to MkDocs itself and the plugin can't have a generic solution for all themes either...

@eXpl0it3r
Copy link

Running into this issue as well with English & French, where French is being used for the 404 page.

Is there are possibility to somehow force the English version? I don't mind the French page getting an English error page, but the other way around is a bit more annoying, as the majority of users will be using the English site.

The only solution I see right now, is to override the 404 page yourself and define your own additional logic on the JavaScript side to render the correct language, which of course I understand, isn't ideal.

Any concrete example on how to achieve this? 😄

@kamilkrzyskow
Copy link
Contributor

kamilkrzyskow commented Nov 20, 2024

@eXpl0it3r
I don't have a specific example, but in the 404.html template override you could check for the URL with JavaScript and:

  • replace other URLs on the site to include the /lang_code/ part to make sure the navigation works
  • store a mapping of values from default language to other languages Home page EN -> Home page FR and replace the values on the page dynamically to make sure the display is correct

Another idea would be a hook, which would assure that each generate 404.html for a given language would be preserved in a separate site_dir/_other404/fr.html file.
Then in 404.html JavaScript fetch the _other404/lang_code.html and replace the whole DOM.
The issue here is that it might create a weird "flash" while the CSS reloads, but I'm not sure.

However, if the site is hosted on a server you can control you could map the 404 code to the appropriate _other404/lang.html file, instead of dealing with the 404.html template shenanigans. This includes something like Apache/Nginx etc., GitHub Pages or Netlify don't support controlling of the 404 status response afaik.

This isn't a critical issue imo, so I'll likely not try to fix it myself.

@mgriff88
Copy link

Thanks for your advice, @kamilkrzyskow . As I mentioned in another post, same has been happening to me with English and Japanese. What I ended up doing was creating two new files -- /en/404.md and /ja/404.md. Then I put the following into the 404.html override template:

{% extends "base.html" %}

{% block htmltitle %}
  <title>Page Not Found - 404</title>
{% endblock %}

{% block scripts %}
  {{ super() }}
  <script>
    (function() {
      // Determine the language context from the current URL path
      const pathSegments = window.location.pathname.split('/');
      
      // Check if the first path segment is 'ja', default to 'en' otherwise
      const langCode = (pathSegments[1] === 'ja') ? 'ja' : 'en';
      
      // Define the target 404 URLs based on the determined language context
      const target404Path = langCode === 'ja' ? '/ja/404/' : '/404/';
      
      // If not already on the correct language path, redirect to it
      if (window.location.pathname !== target404Path) {
        window.location.href = target404Path;
      }
    })();
  </script>
{% endblock %}

This now redirects to the corresponding 404.md page, which keeps you on the correct language site. Hope that helps someone else!

@kamilkrzyskow
Copy link
Contributor

Overall, nice solution @mgriff88, much simpler to what I was suggesting 👍

However, now it redirects from example.com/some/path/that/is/incorrect/ to example.com/404/
I can see this being a matter of preference, but to me this removes "data" about the actual path that was incorrect, which was some/path/that/is/incorrect/

This could be solved with some ref query parameter during the redirect, which would store the actual URL that got 404 error.

Also what happens after the user decides to go back in the browser ⬅️? Is the previous value being stored in the history and it will redirect to /404 again? I'm not sure personally if assigning to location.href is the same as https://developer.mozilla.org/en-US/docs/Web/API/Location/replace

@mgriff88
Copy link

Good points, @kamilkrzyskow , you do lose the context of what the wrong/path/ is in this case. Here it is with a ref as you suggested:

{% extends "base.html" %}

{% block htmltitle %}
  <title>Page Not Found - 404</title>
{% endblock %}

{% block scripts %}
  {{ super() }}
  <script>
    (function() {
      // Determine the language context from the current URL path
      const pathSegments = window.location.pathname.split('/');
      
      // Check if the first path segment is 'ja', default to 'en' otherwise
      const langCode = (pathSegments[1] === 'ja') ? 'ja' : 'en';
      
      // Define the target 404 URLs based on the determined language context
      const target404Path = langCode === 'ja' ? '/ja/404/' : '/404/';
      
      // Extract the current path for the referrer parameter
      const currentPath = window.location.pathname + window.location.search + window.location.hash;
      
      // Construct the target URL with the ref query parameter containing just the path
      const targetUrlWithRef = `${target404Path}?ref=${currentPath}`;
      
      // If not already on the correct language path with the ref parameter, redirect to it
      if (window.location.pathname !== target404Path || !window.location.search.includes('ref=')) {
        window.location.href = targetUrlWithRef;
      }
    })();
  </script>
{% endblock %}

And the result looks something like this: http://127.0.0.1:8000/404/?ref=/does/not/exist/

I've tested the back browser button in Chrome, Firefox, and Edge, and it works fine in all of them, no infinite looping or anything, just goes back to the page with the broken link.

Thanks for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants