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

Make locales case insensitive. Allow automatic resolving to the URL with the casing provided in the locales property. #775

Closed
codesfromshad opened this issue Jan 11, 2024 · 1 comment · Fixed by #861
Labels
contributions welcome Good for people looking to contribute enhancement New feature or request

Comments

@codesfromshad
Copy link

codesfromshad commented Jan 11, 2024

Is your feature request related to a problem? Please describe.

When locales are specified according to the IETF BCP 47 specification, a mismatch in character casing in a URL request can lead to issues. For instance, if the locales are defined as [bn-BD, en-UK, ...] but a request is made using a URL with an incorrect casing, such as bn-bd, this discrepancy results in a 404 error.

Describe the solution you'd like

To address the issue described, the solution should involve implementing a case-insensitive matching mechanism for locale identifiers in the package. This means that when a URL request is made, the package should recognize and correctly handle locales regardless of their character casing. For example, if the locales are defined as [bn-BD, en-UK, ...], the package should treat a request with bn-bd as valid and correctly map it to bn-BD, also rewrite the URL to reflect the correct case, changing bn-bd to bn-BD. This approach will prevent 404 errors due to case mismatches and ensure that the package adheres to the flexibility often expected in handling language tags as per the IETF BCP 47 specification. In summary, the desired outcome is a more forgiving and robust handling of locale identifiers, accommodating variations in character casing.

Describe alternatives you've considered

This is my current workaround:

// middleware.ts

import { getCanonicalLocales } from "@formatjs/intl-getcanonicallocales";
import type { I18nConfig, Locale } from "i18n.config";
import { defaultLocale, locales } from "i18n.config";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import createMiddleware from "next-intl/middleware";

export default async function middleware(request: NextRequest) {
  const { pathname, search } = request.nextUrl;

  // Get the potential locale from the first path segment of `pathname`
  const potentialLocale = pathname.split("/")[1];

  // Initialize canonical locale as an empty string
  let canonicalLocale = "";

  try {
    // Attempt to get a validated and canonicalized version of the potential locale
    canonicalLocale = getCanonicalLocales(potentialLocale)[0];
  } 
  // Catch and ignore `RangeError` for invalid locales
  catch (error) {}

  // If the canonical locale is valid and different from the potential one,
  // and is included in our list of supported `locales`, perform a redirection
  if (canonicalLocale !== potentialLocale && locales.includes(canonicalLocale as Locale)) {
    // Construct a new URL path with the canonical locale
    const newPathname = pathname.replace(`/${potentialLocale}`, `/${canonicalLocale}`);
    // Redirect request to the new URL with the canonical locale
    return NextResponse.redirect(new URL(`${newPathname}${search}`, request.url));
  }
 
  // Create and apply `next-intl`'s middleware for handling i18n-routing
  const handleI18nRouting = createMiddleware({
    locales: locales,
    defaultLocale: defaultLocale as Locale,
    alternateLinks: true,
    localeDetection: true,
    localePrefix: "as-needed",
  });

  // Process request through `next-intl`'s middleware
  const response = handleI18nRouting(request);
 
  // Return the response from `next-intl`'s middleware
  return response;
}

// Only apply this middleware to files in the `app` directory
export const config = {
  matcher: [
    "/((?!api|static|.*\\..*|_next).*)", 

    // Only needed if you are using the `basePath` option in `next.config.js`
    // { source: "/" }
  ]
};
@codesfromshad codesfromshad added enhancement New feature or request unconfirmed Needs triage. labels Jan 11, 2024
@amannn
Copy link
Owner

amannn commented Feb 6, 2024

Thanks for bringing this up! I noticed MDN uses such a redirect too:

GET https://developer.mozilla.org/en-us/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat

… redirects to the /en-US version.

I'm wondering if there are any cases where this is not desired. If yes, I think the workaround you're using is viable, but if everyone benefits from this, I could definitely see this in core.

This might require more analysis, I'd be happy if other users who are interested in this feature could chime in!

@amannn amannn added contributions welcome Good for people looking to contribute and removed unconfirmed Needs triage. labels Feb 6, 2024
amannn added a commit that referenced this issue Feb 20, 2024
juanforlizzi pushed a commit to juanforlizzi/next-intl that referenced this issue Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
contributions welcome Good for people looking to contribute enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants