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

Internationalized routing #102

Open
khalibloo opened this issue Mar 6, 2023 · 2 comments
Open

Internationalized routing #102

khalibloo opened this issue Mar 6, 2023 · 2 comments
Labels
✨ enhancement New feature or request

Comments

@khalibloo
Copy link

khalibloo commented Mar 6, 2023

If a project supports multiple languages, it is often useful to provide different URLs for the pages depending on what language is selected. For example, https://de.example.com/mypage or https://example.com/de/mypage.

The latter example can be done to some extent with route params, but it's a little tricky to handle 404 pages using that method. Maybe using rewrites would provide a more elegant solution in the absence of a builtin solution, but I've yet to try that out.

@cyco130
Copy link
Member

cyco130 commented Mar 6, 2023

I added a (quick and dirty) URL localization example: https://github.com/rakkasjs/rakkasjs/tree/main/examples/localized-urls

The gist of it is, you use the beforePageLookup hook in common-hooks.ts. You extract the language from the URL (in whatever way you want, subdomain, subpath etc.) and, if necessary, you update the URL to remove it from the path. This way you can even update the path to be in the appropriate language (e.g. /home in English and /accueil in French).

Alternatively (or additionally) you can detect the language by looking at the Accept-Language on the server or navigator.language(s) on the client.

But this doesn't take care of URLs in your links, which you have to do yourself.

Better localized URL support is one of the reasons I started Rakkas (0.5 had a more complete system) so I'll keep this issue open because I have many more ideas to implement :)

import { CommonHooks } from "rakkasjs";

declare module "rakkasjs" {
  interface PageContext {
    lang: "en" | "fr";
  }
}

const commonHooks: CommonHooks = {
  beforePageLookup(ctx, url) {
    const lang = url.pathname.split("/")[1];

    if (lang === "en" || lang === "fr") {
      ctx.lang = lang;
      const newUrl = new URL(url);
      newUrl.pathname = url.pathname.slice(lang.length + 1);
      return { rewrite: newUrl };
    } else if (url.pathname === "/") {
      let lang = "en"; // Default language

      if (import.meta.env.SSR) {
        // Detect language from Accept-Language header
        const header =
          ctx.requestContext!.request.headers.get("accept-language");
        if (header?.startsWith("fr")) {
          lang = "fr";
        }
      } else {
        // Detect language from browser language(s)
        const navLang = (navigator.languages ?? [navigator.language])[0];
        if (navLang?.startsWith("fr")) {
          lang = "fr";
        }
      }

      const newUrl = new URL(url);
      newUrl.pathname = `/${lang}`;

      return { redirect: newUrl };
    }

    return true;
  },
};

export default commonHooks;

@cyco130
Copy link
Member

cyco130 commented Mar 9, 2023

Just chiming in to say that I updated the example. You're supposed to return { rewrite: newURL } instead of modifying the existing URL object. That's why I needed the infinite loop control (and some things still didn't work).

@cyco130 cyco130 added the ✨ enhancement New feature or request label May 23, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
✨ enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants