Version
5.27.1
Describe the bug
The generator (i18n:once / i18n:watch) fails when TypeScript 6.0+ is installed in the project.
TypeScript 6.0 changed the default module option from CommonJS to esnext:
"module defaults to esnext: Similarly, the new default module is esnext, acknowledging that ESM is now the dominant module format."
The generator internally calls ts.createProgram without an explicit module option (in packages/generator/src/parse-language-file.mts). With TypeScript 6.0+, this now emits import/export statements instead of require() calls into the temp-output directory. When Node.js subsequently loads these files via dynamic import(), it treats them as ESM — which does not support bare directory imports (e.g. import { x } from '../../some/dir' without /index.js), causing the error below.
The bug affects any project where the base locale file (de/index.ts, en/index.ts, …) imports from another module, which includes:
- Projects using the built-in typesafe-i18n namespace feature (sub-folders in the locale directory)
- Projects using custom imports from outside the locale directory
Projects with all translations inline and no imports are not affected.
A possible fix seems to be a single line: adding module: ts.ModuleKind.CommonJS explicitly to the ts.createProgram call forces CJS output regardless of the TypeScript version's default:
const program = ts.createProgram([languageFilePath], {
outDir: tempPath,
allowJs: true,
resolveJsonModule: true,
skipLibCheck: true,
sourceMap: false,
noLib: true,
+ module: ts.ModuleKind.CommonJS, // Ensure CJS output regardless of TS version defaults
});
Reproduction
Minimal folder structure to reproduce:
src/
i18n/
de/
settings/
index.ts ← any namespace or external import
index.ts ← imports from ./settings or another directory
With typescript >= 6.0.0 and node >= 22.12.0, running typesafe-i18n --no-watch fails.
Logs
[typesafe-i18n] ERROR: import failed for .../node_modules/typesafe-i18n/temp-output/0/i18n/de/index.js
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import '.../node_modules/typesafe-i18n/temp-output/0/features/bookmarks/i18n'
is not supported resolving ES modules imported from .../node_modules/typesafe-i18n/temp-output/0/i18n/de/index.js
Config
{
"$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json",
"adapters": [],
"baseLocale": "de",
"outputFormat": "TypeScript",
"esmImports": ".js",
"generateOnlyTypes": false,
"runAfterGenerator": "yarn prettier:i18n"
}
Additional information
Temporary workaround via yarn patch (typesafe-i18n-npm-5.27.1-37bc79b222.patch):
diff --git a/cli/typesafe-i18n.mjs b/cli/typesafe-i18n.mjs
--- a/cli/typesafe-i18n.mjs
+++ b/cli/typesafe-i18n.mjs
@@ -22862,7 +22862,8 @@ var transpileTypescriptFiles = ...
resolveJsonModule: true,
skipLibCheck: true,
sourceMap: false,
- noLib: true
+ noLib: true,
+ module: ts.ModuleKind.CommonJS // Tell TS to use CommonJS imports
});
This has sucessfully fixed the issue in a real-world repository: jxn-30/better-moodle@00c0843
Version
5.27.1
Describe the bug
The generator (
i18n:once/i18n:watch) fails when TypeScript 6.0+ is installed in the project.TypeScript 6.0 changed the default
moduleoption fromCommonJStoesnext:The generator internally calls
ts.createProgramwithout an explicitmoduleoption (inpackages/generator/src/parse-language-file.mts). With TypeScript 6.0+, this now emitsimport/exportstatements instead ofrequire()calls into thetemp-outputdirectory. When Node.js subsequently loads these files viadynamic import(), it treats them as ESM — which does not support bare directory imports (e.g.import { x } from '../../some/dir'without/index.js), causing the error below.The bug affects any project where the base locale file (
de/index.ts,en/index.ts, …) imports from another module, which includes:Projects with all translations inline and no imports are not affected.
A possible fix seems to be a single line: adding
module: ts.ModuleKind.CommonJSexplicitly to thets.createProgramcall forces CJS output regardless of the TypeScript version's default:const program = ts.createProgram([languageFilePath], { outDir: tempPath, allowJs: true, resolveJsonModule: true, skipLibCheck: true, sourceMap: false, noLib: true, + module: ts.ModuleKind.CommonJS, // Ensure CJS output regardless of TS version defaults });Reproduction
Minimal folder structure to reproduce:
With
typescript >= 6.0.0andnode >= 22.12.0, runningtypesafe-i18n --no-watchfails.Logs
Config
{ "$schema": "https://unpkg.com/typesafe-i18n@5.27.1/schema/typesafe-i18n.json", "adapters": [], "baseLocale": "de", "outputFormat": "TypeScript", "esmImports": ".js", "generateOnlyTypes": false, "runAfterGenerator": "yarn prettier:i18n" }Additional information
Temporary workaround via
yarn patch(typesafe-i18n-npm-5.27.1-37bc79b222.patch):This has sucessfully fixed the issue in a real-world repository: jxn-30/better-moodle@00c0843