Skip to content

Type inference breaks when passing locale parameter to getTranslations() #2227

@issam-seghir

Description

@issam-seghir

Description

When using getTranslations() with an explicit locale parameter in the options object, TypeScript type inference breaks, causing all translation keys to be typed as never. However, when calling getTranslations() without parameters (after calling setRequestLocale()), the type inference works correctly.

Environment

  • next-intl: ^4.7.0
  • Next.js: 16.1.3
  • TypeScript: 5.9.3
  • Next.js App Router with typedRoutes: true

Reproduction

Scenario 1: Type Error ❌

import { getTranslations } from "next-intl/server";
import { routing } from "@/i18n/routing";

export default async function manifest() {
    const locale = routing.defaultLocale; // Type: "en" | "fr" | "ar"
    const t = await getTranslations({ locale, namespace: "Manifest" });

    // TypeScript Error: Argument of type '"name"' is not assignable to parameter of type 'never'
    return {
        name: t("name"),
        short_name: t("short_name"),
        description: t("description"),
    };
}

Scenario 2: Works Correctly ✅

import { getTranslations, setRequestLocale } from "next-intl/server";
import { routing } from "@/i18n/routing";

export default async function manifest() {
    const locale = routing.defaultLocale;
    setRequestLocale(locale);
    
    const t = await getTranslations("Manifest");

    // No TypeScript errors - type inference works correctly
    return {
        name: t("name"),
        short_name: t("short_name"),
        description: t("description"),
    };
}

Expected Behavior

When passing { locale, namespace } to getTranslations(), TypeScript should properly infer the translation keys from the messages structure, just as it does when using the recommended setRequestLocale() pattern.

Current Behavior

Passing an explicit locale parameter breaks type inference, resulting in all translation keys being typed as never, which causes TypeScript errors when trying to access any translation key.

Additional Context

Locale Type Definition

// @/i18n/routing.ts
export const routing = defineRouting({
    locales: ["en", "fr", "ar"],
    defaultLocale: "ar",
});

export type Locale = (typeof routing.locales)[number]; // "en" | "fr" | "ar"

Messages Structure

// messages/en.json
{
  "Manifest": {
    "name": "Ecomenia - All-in-One B2B E-commerce Platform",
    "short_name": "Ecomenia",
    "description": "Manage your e-commerce business with ease"
  }
}

Workaround

The current workaround is to call getTranslations() without parameters:

const t = await getTranslations("Manifest");

While this works, it would be helpful if the explicit parameter syntax also worked correctly for cases where setting the request locale globally isn't appropriate or desirable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions