Search code examples
next.jsinternationalizationfaviconi18nextapp-router

Nextjs 14 / Next.js 14 favicon problem after changing project structure to add Internationalization


I'm facing an issue with favicon display in Next.js 14.0.2. The problem arose after I added internalization and changed my project structure. In short, this is my project structure:

- app
  - [lang]
    - _components
    - _dictionaries
    - dictionaries.ts
    - layout.tsx
    - page.tsx
  - favicon.ico

middleware.ts     

After i moved all the general files from the app folder to the [lang] i created middleware to redirect user from / to /en or /ru depending on his locale:

import { match } from '@formatjs/intl-localematcher';
import Negotiator from 'negotiator';

function getLocale(request: any): string {
    const headers = request.headers || {};
    const acceptLanguageHeader = headers['accept-language'] || 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7';
    const negotiator = new Negotiator({ headers: { 'accept-language': acceptLanguageHeader } });
    const languages = negotiator.languages();
    const locales = ['ru', 'en'];
    const defaultLocale = 'ru';

    return match(languages, locales, defaultLocale);
}

export function middleware(request: any) {
    const { pathname } = request.nextUrl;
    const locales = ['ru', 'en'];

    const pathnameHasLocale = locales.some(
        (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
    );

    if (pathnameHasLocale) return;

    const locale = getLocale(request);
    request.nextUrl.pathname = `/${locale}${pathname}`;
    return Response.redirect(request.nextUrl);
}

export const config = {
    matcher: [
        '/((?!_next).*)',
    ],
};

So now i have two favicon.ico GET-requests in the Network tab and the icon is not displayed on the tab in the browser. First returns 302 Found (at the localhost:3000/favicon.ico) and the next one returns 404 Not Found (now on the different url with locale path localhost:3000/en/favicon.ico). Any ideas to solve this problem? If necessary, I will supplement the question with the necessary listings and clarifications.

repo with code: https://github.com/mondevyat/next1402/


Solution

  • You need to exclude the favicon in the matcher in middleware.

    matcher: [
    "/((?!api|_next/static|_next/image|img/|favicon.ico).*)",
    ]
    

    Look here: nextjsMatcherDoc