-1

next-i18next.config.js

const nextI18NextConfig = {
  i18n: {
    defaultLocale: "fr",
    locales: ["en", "fr"],
    reloadOnPrerender: process.env.NODE_ENV === "development",
  },
}

module.exports = nextI18NextConfig

topics.json

{
  "feedback-introduction": {
    "fr": {
      "name": "Introduction à la rétroaction"
    },
    "en": {
      "name": "Introduction to feedback"
    }
  }
}

topics.tsx

…
import i18n from "./next-i18next.config.js"
import topics from "./topics.json"

export default () => {
  const { locale } = useRouter()
  const { t } = useTranslation("common")
  var localizedTopics: string[] = []
  for (const [slug, topic] of Object.entries(topics)) {
    localizedTopics.push(topic[locale as "en" | "fr"].name)
  }
  …
}

Instead of using locale as "en" | "fr", I would like to infer "en" | "fr" programatically from locales in next-i18next.config.js.

Is that possible?

sunknudsen
  • 6,356
  • 3
  • 39
  • 76
  • Does this answer your question? [What does the "as const" mean in TypeScript and what is its use case?](https://stackoverflow.com/questions/66993264/what-does-the-as-const-mean-in-typescript-and-what-is-its-use-case) – Jared Smith Feb 24 '23 at 21:20
  • It doesn’t… attempting to reformulate question. – sunknudsen Feb 24 '23 at 21:25
  • What do you mean you can't use `const`? Just put it in the other file? Please edit the question to have sufficient detail to state the issue. – Jared Smith Feb 24 '23 at 21:33
  • If I understand correctly, the problem is: 1. The file containing `const nextI18NextConfig = ...` is somewhere in `node_modules`; 2. It is in Javascript and doesn't provide type declarations. Is this correct? – Alexey Romanov Feb 24 '23 at 21:37
  • @AlexeyRomanov assumptions are very close… see updated question. – sunknudsen Feb 24 '23 at 21:41

2 Answers2

2

Can one infer type of i18n.locales programatically from another file?

In short: if the exporting source does not provide the literal type information that you want, then it will not be available to the compiler.

String literal types can be inferred at the numeric indexes of the array if the exporting file provides string literal type information. Otherwise, array element types are inferred using what's described as best common type in the handbook.

Here's an example:

TS Playground

// import {array1} from "./some_module.js";
const array1 = ["a", "b", "c"];
type Element1 = typeof array1[number];
   //^? type Element1 = string

const array2 = ["a", "b", "c"] as const;
type Element2 = typeof array2[number];
   //^? type Element2 = "a" | "b" | "c"

const array3: ("a" | "b" | "c" | "d")[] = ["a", "b", "c"];
type Element3 = typeof array3[number];
   //^? type Element3 = "a" | "b" | "c" | "d"

jsejcksn
  • 27,667
  • 4
  • 38
  • 62
1

If you have import i18n from "./next-i18next.config.js" then the file is under your control. If for some reason it has to be JS and not TS, but you can change the file itself, it may be possible to use https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html. But I have not been able to get it to work.

const en = /** @type {const} */("en");
const fr = /** @type {const} */("fr");

const locales = /** @type {const} */([en, fr]);

const nextI18NextConfig = /** @type {const} */({
  i18n: {
    defaultLocale: "fr",
    locales: ["en", "fr"],
    reloadOnPrerender: false,
  },
});

Playground

You can see en and fr have desired types, but it doesn't work for locales or nextI18NextConfig and I wasn't able to find a syntax which does.

Instead my suggestion would be to actually define the config in a TS file with as const. Then ./next-i18next.config.js can simply import and reexport it.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487