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

Issue & Update on how to use the library with app router #1207

Open
erwanriou opened this issue Apr 3, 2024 · 1 comment
Open

Issue & Update on how to use the library with app router #1207

erwanriou opened this issue Apr 3, 2024 · 1 comment

Comments

@erwanriou
Copy link

erwanriou commented Apr 3, 2024

What version of this package are you using?
tried canary and last official
What operating system, Node.js, and npm version?
20 and 10
What happened?

I am writing this issue after desperately trying to make the library work with the app router since 2 week already. I somehow managed to make everything work locally with the dynamic rendering (static ssr would only build the default locale).

I tried a consequent amount of different configurations, but not a single one worked so far. All example that i could find didn't worked either. Canary version of the library (that need to be implemented with npm i --force) doesn't seems to help either. So i though that i would put here all the configurations that have here and let's see if someone would have an idea to how debug it.

If i fix my issue i offer myself to build an advanced usage example for this library including multi vendor and dynamic page routing.

1. The configuration that almost worked

1.1 package.json

here i used "next-translate": "2.6.2" and "next-translate-plugin": "2.6.2"

1.2 next.config.js

In this case i used the i18n routing with:

const { domains, defaultLocale, localeDetection, locales } = require("./i18n")

module.exports = nextTranslate({
  // OTHER STUFF HERE
  output: "standalone",
  i18n: {
    locales,
    defaultLocale,
    localeDetection,
    domains
  }
}

i made sure to have all the domains etc coming from the i18n file as it is a nice place to centralize all this information.

1.3 i18n.js
here also i tried with the [lang] parameter and it didn't helped so i ended removing it

const defaultDomains = () => {
  return [
    {
      domain: "www.example.dev",
      defaultLocale: "us"
    },
    {
      domain: "www.example.dev.br",
      defaultLocale: "br"
    }
    // etc
  ]
}

module.exports = {
  locales: ["us", "in", "gb", "es", "fr", "dk", "br", "pt", "mx"],
  defaultLocale: "us",
  localeDetection: false,
  domains: defaultDomains(),
  pages: {
    "*": ["nav", "error"],
    "/": ["home"],
    "/[profession]": ["home", "architect", "partner", "how", "error"],
    "/[profession]/[city]": ["home", "architect", "partner", "how"],
    "/blog": ["blog"],
    "/not-found": ["architect", "partner", "error"],
    // etc
  }
}

1.4 middleware

Make sure to have the middleware inside the src

import { defaultLocale } from "@i18n"
import { NextResponse } from "next/server"

export function middleware(request) {
  const locale = request.nextUrl.locale || defaultLocale
  request.nextUrl.searchParams.set("lang", locale)
  request.nextUrl.href = request.nextUrl.href.replace(`/${locale}`, "")
  return NextResponse.rewrite(request.nextUrl)
}

This is the one i used that was suggested by @aralroca in some of the examples i could find.

1.5 folder architecture

My folder architecture would look that this:
Screenshot from 2024-04-03 22-39-34

where the layout would make usage of the const { lang } = useTranslation() to get the lang for metadata and html lang.
As you can see there is no [lang] folder in this solution as all my attempts to make this work with a [lang] folder resulted in a fail.

1.6 The issue

this configuration worked perfectly in development but unfortunately in production it only worked partially. If the defaultLocale match the defaultLocale from a specific domain then it work but if it doesn't most of the pages at the root level would not work correctly. The only way to make then work is to add the /br/us that correspond to the /domainDefaultLocal/defaultLocal in the path and it somehow mysteriously work.

i tried to custom the middleware to redirect the pathname to that specific case on some url:

 if (request.nextUrl.pathname === "/") {
    request.nextUrl.pathname = `${pathname}${locale}/${defaultLocale}`
    return NextResponse.rewrite(request.nextUrl)
  }

but then i get an error of

Screenshot from 2024-04-04 04-10-44

2. Asking for help

I really tried all examples, with different type of structure with the [lang] wrapper. Different middlewares. The new canary versions. removing manually some config from the next.config.js such as the i18n = 'undefined' and non of all trial could even work a single time in production.

Most of the time i had a 404 in the home page but i couldn't make the translation work in the other pages anyways.

So here i am, a bit lost, asking for a good soul to try to indicate me the path to follow :)

@erwanriou
Copy link
Author

erwanriou commented Apr 5, 2024

Update: I made it work in production finally... It's a bit flacky but it does the work.

1. Remove the reference to the domains in your i18n.js and next.config.js

This was the main blocker for me. It somehow remove the weird url redirect that was not working correctly.

2. Update the middleware to look like this:

import { Domains } from "some-file-where-you-have-a-list-of-domain-and-their-locals"
import { NextResponse } from "next/server"

export const middleware = async request => {
  const { searchParams } = request.nextUrl

  // GET DEFAULT LOCALE
  const host = request.headers.get("host")
  const { defaultLocale: locale = "us" } = Domains?.find(({ domain }) => domain === host)

  // APPLY LANGUAGE
  searchParams.set("lang", locale)

  return NextResponse.rewrite(request.nextUrl)
}

export const config = {
  matcher: ["/((?!api|_next/image|favicon.ico).*)", "/"]
}

where the Domains object look like

const Domains = [
    {
      domain: "www.example.dev",
      defaultLocale: "us"
    },
    {
      domain: "www.example.dev.br",
      defaultLocale: "br"
    }
]

What i am doing here is to get the host from the header to manage to know what language attribute and from there setup the language with the searchParams.set("lang", locale)

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

1 participant