@bleedingdev/modern-js-create 3.2.0-ultramodern.10 → 3.2.0-ultramodern.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -561,8 +561,10 @@ const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260518.1';
561
561
  const OXLINT_VERSION = '1.65.0';
562
562
  const OXFMT_VERSION = '0.50.0';
563
563
  const ULTRACITE_VERSION = '7.7.0';
564
+ const I18NEXT_VERSION = '26.2.0';
564
565
  const REACT_VERSION = '^19.2.6';
565
566
  const REACT_DOM_VERSION = '^19.2.6';
567
+ const REACT_I18NEXT_VERSION = '17.0.8';
566
568
  const WORKSPACE_PACKAGE_VERSION = 'workspace:*';
567
569
  const RSTACK_AGENT_SKILLS_COMMIT = '61c948b42512e223bad44b83af4080eba48b2677';
568
570
  const baselineAgentSkills = [
@@ -585,6 +587,7 @@ const effectTsgoTypecheckCommand = "node -e \"const fs = require('node:fs'); con
585
587
  const modernPackageNames = [
586
588
  '@modern-js/app-tools',
587
589
  '@modern-js/plugin-bff',
590
+ '@modern-js/plugin-i18n',
588
591
  '@modern-js/plugin-tanstack',
589
592
  '@modern-js/runtime'
590
593
  ];
@@ -631,7 +634,7 @@ const remoteApps = [
631
634
  mfName: 'remoteCommerce',
632
635
  exposes: {
633
636
  './Route': './src/remote-entry.tsx',
634
- './Widget': './src/components/CommerceWidget.tsx'
637
+ './Widget': './src/components/commerce-widget.tsx'
635
638
  },
636
639
  ownership: {
637
640
  team: 'commerce-experience',
@@ -660,7 +663,7 @@ const remoteApps = [
660
663
  mfName: 'remoteIdentity',
661
664
  exposes: {
662
665
  './Route': './src/remote-entry.tsx',
663
- './Widget': './src/components/IdentityWidget.tsx'
666
+ './Widget': './src/components/identity-widget.tsx'
664
667
  },
665
668
  ownership: {
666
669
  team: 'identity-platform',
@@ -688,7 +691,7 @@ const remoteApps = [
688
691
  port: 3023,
689
692
  mfName: 'remoteDesignSystem',
690
693
  exposes: {
691
- './Button': './src/components/Button.tsx',
694
+ './Button': './src/components/button.tsx',
692
695
  './tokens': './src/tokens.ts'
693
696
  },
694
697
  ownership: {
@@ -917,6 +920,7 @@ function modernPackageSpecifier(packageName, packageSource) {
917
920
  }
918
921
  function appDependencies(scope, packageSource) {
919
922
  return {
923
+ '@modern-js/plugin-i18n': modernPackageSpecifier('@modern-js/plugin-i18n', packageSource),
920
924
  '@modern-js/plugin-tanstack': modernPackageSpecifier('@modern-js/plugin-tanstack', packageSource),
921
925
  '@modern-js/runtime': modernPackageSpecifier('@modern-js/runtime', packageSource),
922
926
  '@module-federation/modern-js-v3': MODULE_FEDERATION_VERSION,
@@ -924,8 +928,10 @@ function appDependencies(scope, packageSource) {
924
928
  '@tanstack/react-router': TANSTACK_ROUTER_VERSION,
925
929
  [ultramodern_workspace_packageName(scope, 'shared-contracts')]: WORKSPACE_PACKAGE_VERSION,
926
930
  [ultramodern_workspace_packageName(scope, 'shared-design-tokens')]: WORKSPACE_PACKAGE_VERSION,
931
+ i18next: I18NEXT_VERSION,
927
932
  react: REACT_VERSION,
928
- 'react-dom': REACT_DOM_VERSION
933
+ 'react-dom': REACT_DOM_VERSION,
934
+ 'react-i18next': REACT_I18NEXT_VERSION
929
935
  };
930
936
  }
931
937
  function appDevDependencies(packageSource) {
@@ -943,6 +949,7 @@ function createRootPackageJson(scope, packageSource) {
943
949
  private: true,
944
950
  name: scope,
945
951
  version: '0.1.0',
952
+ type: 'module',
946
953
  packageManager: 'pnpm@11.1.2',
947
954
  scripts: {
948
955
  dev: `pnpm --parallel --filter ${ultramodern_workspace_packageName(scope, shellApp.packageSuffix)} --filter ${ultramodern_workspace_packageName(scope, 'remote-commerce')} --filter ${ultramodern_workspace_packageName(scope, 'remote-identity')} --filter ${ultramodern_workspace_packageName(scope, 'remote-design-system')} dev`,
@@ -954,13 +961,14 @@ function createRootPackageJson(scope, packageSource) {
954
961
  build: 'pnpm -r --filter ./apps/** --filter ./services/** build',
955
962
  format: 'oxfmt .',
956
963
  'format:check': 'oxfmt --check .',
964
+ 'i18n:check': "node ./scripts/check-i18n-strings.mjs",
957
965
  lint: 'oxlint .',
958
966
  'lint:fix': 'oxlint . --fix',
959
- typecheck: 'pnpm -r --filter ./apps/** --filter ./services/** --filter ./packages/** typecheck',
967
+ typecheck: `pnpm -r --filter "@${scope}/*" typecheck`,
960
968
  'skills:install': "node ./scripts/bootstrap-agent-skills.mjs",
961
969
  'skills:check': "node ./scripts/bootstrap-agent-skills.mjs --check",
962
970
  'ultramodern:check': "node ./scripts/validate-ultramodern-workspace.mjs",
963
- check: 'pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm ultramodern:check'
971
+ check: 'pnpm format:check && pnpm lint && pnpm typecheck && pnpm i18n:check && pnpm skills:check && pnpm ultramodern:check'
964
972
  },
965
973
  engines: {
966
974
  node: '>=20',
@@ -991,7 +999,7 @@ function createRootPackageJson(scope, packageSource) {
991
999
  }
992
1000
  };
993
1001
  }
994
- function createTsConfigBase(scope) {
1002
+ function createTsConfigBase() {
995
1003
  return {
996
1004
  compilerOptions: {
997
1005
  target: 'ESNext',
@@ -1018,12 +1026,6 @@ function createTsConfigBase(scope) {
1018
1026
  noImplicitReturns: true,
1019
1027
  skipLibCheck: true,
1020
1028
  resolveJsonModule: true,
1021
- paths: Object.fromEntries(sharedPackages.map((sharedPackage)=>[
1022
- ultramodern_workspace_packageName(scope, sharedPackage.id),
1023
- [
1024
- `${sharedPackage.directory}/src/index.ts`
1025
- ]
1026
- ])),
1027
1029
  plugins: [
1028
1030
  {
1029
1031
  name: '@effect/language-service',
@@ -1051,20 +1053,6 @@ function createPackageTsConfig(packageDir, includeApi = false) {
1051
1053
  if (includeApi) include.push('api', 'shared');
1052
1054
  return {
1053
1055
  extends: `${relativeRootFor(packageDir)}/tsconfig.base.json`,
1054
- compilerOptions: {
1055
- baseUrl: '.',
1056
- paths: {
1057
- '@/*': [
1058
- './src/*'
1059
- ],
1060
- '@api/*': [
1061
- './api/*'
1062
- ],
1063
- '@shared/*': [
1064
- './shared/*'
1065
- ]
1066
- }
1067
- },
1068
1056
  include
1069
1057
  };
1070
1058
  }
@@ -1145,6 +1133,7 @@ function createSharedPackage(scope, id, description) {
1145
1133
  function createAppModernConfig(app) {
1146
1134
  return `// @effect-diagnostics processEnv:off
1147
1135
  import { appTools, defineConfig, presetUltramodern } from '@modern-js/app-tools';
1136
+ import { i18nPlugin } from '@modern-js/plugin-i18n';
1148
1137
  import { tanstackRouterPlugin } from '@modern-js/plugin-tanstack';
1149
1138
  import { moduleFederationPlugin } from '@module-federation/modern-js-v3';
1150
1139
 
@@ -1154,28 +1143,34 @@ const port = Number(process.env['${app.portEnv}'] ?? ${app.port});
1154
1143
  export default defineConfig(
1155
1144
  presetUltramodern(
1156
1145
  {
1157
- server: {
1158
- port,
1159
- ssr: {
1160
- mode: 'string',
1161
- moduleFederationAppSSR: true,
1162
- },
1163
- },
1164
1146
  output: {
1165
- polyfill: 'off',
1166
1147
  disableTsChecker: true,
1148
+ polyfill: 'off',
1167
1149
  splitRouteChunks: false,
1168
1150
  },
1169
1151
  plugins: [
1170
1152
  appTools(),
1153
+ i18nPlugin({
1154
+ localeDetection: {
1155
+ fallbackLanguage: 'en',
1156
+ languages: ['en', 'cs'],
1157
+ },
1158
+ }),
1171
1159
  tanstackRouterPlugin(),
1172
1160
  moduleFederationPlugin(),
1173
1161
  ],
1162
+ server: {
1163
+ port,
1164
+ ssr: {
1165
+ mode: 'string',
1166
+ moduleFederationAppSSR: true,
1167
+ },
1168
+ },
1174
1169
  },
1175
1170
  {
1176
1171
  appId,
1177
- enableModuleFederationSSR: true,
1178
1172
  enableBffRequestId: true,
1173
+ enableModuleFederationSSR: true,
1179
1174
  enableTelemetryExporters: true,
1180
1175
  telemetryFailLoudStartup: false,
1181
1176
  },
@@ -1183,6 +1178,47 @@ export default defineConfig(
1183
1178
  );
1184
1179
  `;
1185
1180
  }
1181
+ function createSharedModuleFederationConfig() {
1182
+ return ` shared: {
1183
+ '@modern-js/runtime': {
1184
+ requiredVersion: runtimeVersion,
1185
+ singleton: true,
1186
+ treeShaking: false,
1187
+ },
1188
+ '@tanstack/react-router': {
1189
+ requiredVersion: dependencies['@tanstack/react-router'],
1190
+ singleton: true,
1191
+ treeShaking: false,
1192
+ },
1193
+ i18next: {
1194
+ requiredVersion: dependencies.i18next,
1195
+ singleton: true,
1196
+ treeShaking: false,
1197
+ },
1198
+ react: {
1199
+ requiredVersion: reactVersion,
1200
+ singleton: true,
1201
+ treeShaking: false,
1202
+ },
1203
+ 'react-dom': {
1204
+ requiredVersion: reactDomVersion,
1205
+ singleton: true,
1206
+ treeShaking: false,
1207
+ },
1208
+ 'react-i18next': {
1209
+ requiredVersion: dependencies['react-i18next'],
1210
+ singleton: true,
1211
+ treeShaking: false,
1212
+ },
1213
+ }`;
1214
+ }
1215
+ function formatTsObjectLiteral(value) {
1216
+ const entries = Object.entries(value).sort(([left], [right])=>left.localeCompare(right));
1217
+ if (0 === entries.length) return '{}';
1218
+ return `{
1219
+ ${entries.map(([key, entryValue])=>` '${key}': '${entryValue}',`).join('\n')}
1220
+ }`;
1221
+ }
1186
1222
  function createShellModuleFederationConfig() {
1187
1223
  return `// @effect-diagnostics nodeBuiltinImport:off processEnv:off
1188
1224
  import { createRequire } from 'node:module';
@@ -1190,98 +1226,47 @@ import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
1190
1226
  import { dependencies } from './package.json';
1191
1227
 
1192
1228
  const require = createRequire(import.meta.url);
1193
- const runtimeVersion = (
1194
- require('@modern-js/runtime/package.json') as { version: string }
1195
- ).version;
1196
- const reactVersion = (require('react/package.json') as { version: string })
1197
- .version;
1198
- const reactDomVersion = (
1199
- require('react-dom/package.json') as { version: string }
1200
- ).version;
1229
+ const runtimeVersion = (require('@modern-js/runtime/package.json') as { version: string }).version;
1230
+ const reactVersion = (require('react/package.json') as { version: string }).version;
1231
+ const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
1201
1232
 
1202
1233
  export default createModuleFederationConfig({
1203
- name: '${shellApp.mfName}',
1204
1234
  dts: false,
1235
+ filename: 'remoteEntry.js',
1236
+ name: '${shellApp.mfName}',
1205
1237
  remotes: {
1206
1238
  commerce:
1207
1239
  process.env['REMOTE_COMMERCE_MF_MANIFEST'] ??
1208
1240
  'remoteCommerce@http://localhost:3021/mf-manifest.json',
1209
- identity:
1210
- process.env['REMOTE_IDENTITY_MF_MANIFEST'] ??
1211
- 'remoteIdentity@http://localhost:3022/mf-manifest.json',
1212
1241
  designSystem:
1213
1242
  process.env['REMOTE_DESIGN_SYSTEM_MF_MANIFEST'] ??
1214
1243
  'remoteDesignSystem@http://localhost:3023/mf-manifest.json',
1244
+ identity:
1245
+ process.env['REMOTE_IDENTITY_MF_MANIFEST'] ??
1246
+ 'remoteIdentity@http://localhost:3022/mf-manifest.json',
1215
1247
  },
1216
- shared: {
1217
- react: {
1218
- singleton: true,
1219
- requiredVersion: reactVersion,
1220
- treeShaking: false,
1221
- },
1222
- 'react-dom': {
1223
- singleton: true,
1224
- requiredVersion: reactDomVersion,
1225
- treeShaking: false,
1226
- },
1227
- '@tanstack/react-router': {
1228
- singleton: true,
1229
- requiredVersion: dependencies['@tanstack/react-router'],
1230
- treeShaking: false,
1231
- },
1232
- '@modern-js/runtime': {
1233
- singleton: true,
1234
- requiredVersion: runtimeVersion,
1235
- treeShaking: false,
1236
- },
1237
- },
1248
+ ${createSharedModuleFederationConfig()},
1238
1249
  });
1239
1250
  `;
1240
1251
  }
1241
1252
  function createRemoteModuleFederationConfig(app) {
1242
- const exposes = JSON.stringify(app.exposes ?? {}, null, 4).replace(/^/gm, ' ');
1253
+ const exposes = formatTsObjectLiteral(app.exposes ?? {});
1243
1254
  return `// @effect-diagnostics nodeBuiltinImport:off
1244
1255
  import { createRequire } from 'node:module';
1245
1256
  import { createModuleFederationConfig } from '@module-federation/modern-js-v3';
1246
1257
  import { dependencies } from './package.json';
1247
1258
 
1248
1259
  const require = createRequire(import.meta.url);
1249
- const runtimeVersion = (
1250
- require('@modern-js/runtime/package.json') as { version: string }
1251
- ).version;
1252
- const reactVersion = (require('react/package.json') as { version: string })
1253
- .version;
1254
- const reactDomVersion = (
1255
- require('react-dom/package.json') as { version: string }
1256
- ).version;
1260
+ const runtimeVersion = (require('@modern-js/runtime/package.json') as { version: string }).version;
1261
+ const reactVersion = (require('react/package.json') as { version: string }).version;
1262
+ const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
1257
1263
 
1258
1264
  export default createModuleFederationConfig({
1259
- name: '${app.mfName}',
1260
1265
  dts: false,
1261
- filename: 'remoteEntry.js',
1262
1266
  exposes: ${exposes},
1263
- shared: {
1264
- react: {
1265
- singleton: true,
1266
- requiredVersion: reactVersion,
1267
- treeShaking: false,
1268
- },
1269
- 'react-dom': {
1270
- singleton: true,
1271
- requiredVersion: reactDomVersion,
1272
- treeShaking: false,
1273
- },
1274
- '@tanstack/react-router': {
1275
- singleton: true,
1276
- requiredVersion: dependencies['@tanstack/react-router'],
1277
- treeShaking: false,
1278
- },
1279
- '@modern-js/runtime': {
1280
- singleton: true,
1281
- requiredVersion: runtimeVersion,
1282
- treeShaking: false,
1283
- },
1284
- },
1267
+ filename: 'remoteEntry.js',
1268
+ name: '${app.mfName}',
1269
+ ${createSharedModuleFederationConfig()},
1285
1270
  });
1286
1271
  `;
1287
1272
  }
@@ -1296,19 +1281,19 @@ const port = Number(process.env['${effectService.portEnv}'] ?? ${effectService.p
1296
1281
  export default defineConfig(
1297
1282
  presetUltramodern(
1298
1283
  {
1299
- server: {
1300
- port,
1301
- },
1302
1284
  bff: {
1303
- prefix: '/recommendations-api',
1304
- runtimeFramework: 'effect',
1305
1285
  effect: {
1306
1286
  openapi: {
1307
1287
  path: '/openapi.json',
1308
1288
  },
1309
1289
  },
1290
+ prefix: '/recommendations-api',
1291
+ runtimeFramework: 'effect',
1310
1292
  },
1311
1293
  plugins: [appTools(), bffPlugin()],
1294
+ server: {
1295
+ port,
1296
+ },
1312
1297
  },
1313
1298
  {
1314
1299
  appId,
@@ -1320,21 +1305,64 @@ export default defineConfig(
1320
1305
  );
1321
1306
  `;
1322
1307
  }
1308
+ function createAppRuntimeConfig() {
1309
+ return `import { defineRuntimeConfig } from '@modern-js/runtime';
1310
+ import { createInstance } from 'i18next';
1311
+
1312
+ const i18nInstance = createInstance();
1313
+
1314
+ export default defineRuntimeConfig({
1315
+ i18n: {
1316
+ i18nInstance,
1317
+ initOptions: {
1318
+ defaultNS: 'translation',
1319
+ fallbackLng: 'en',
1320
+ interpolation: {
1321
+ escapeValue: false,
1322
+ },
1323
+ ns: ['translation'],
1324
+ supportedLngs: ['en', 'cs'],
1325
+ },
1326
+ },
1327
+ router: {
1328
+ framework: 'tanstack',
1329
+ },
1330
+ });
1331
+ `;
1332
+ }
1323
1333
  function createShellPage() {
1324
- return `const remotes = [
1325
- 'remote-commerce',
1326
- 'remote-identity',
1327
- 'remote-design-system',
1328
- ];
1334
+ return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
1335
+ import { useTranslation } from 'react-i18next';
1336
+
1337
+ const remotes = ['remote-commerce', 'remote-identity', 'remote-design-system'];
1329
1338
 
1330
1339
  export default function ShellHome() {
1340
+ const { t } = useTranslation();
1341
+ const { changeLanguage, language } = useModernI18n();
1342
+ const languageOptions = [
1343
+ { code: 'en', label: t('language.en') },
1344
+ { code: 'cs', label: t('language.cs') },
1345
+ ];
1346
+
1331
1347
  return (
1332
1348
  <main>
1333
- <h1>UltraModern SuperApp Shell</h1>
1334
- <p data-testid="ultramodern-preset">presetUltramodern workspace</p>
1349
+ <nav aria-label={t('language.switcher')}>
1350
+ {languageOptions.map((option) => (
1351
+ <button
1352
+ disabled={language === option.code}
1353
+ key={option.code}
1354
+ onClick={() => void changeLanguage(option.code)}
1355
+ type="button"
1356
+ >
1357
+ {option.label}
1358
+ </button>
1359
+ ))}
1360
+ </nav>
1361
+ <h1>{t('shell.title')}</h1>
1362
+ <p data-testid="ultramodern-preset">{t('shell.preset')}</p>
1335
1363
  <ul>
1336
- {remotes.map(remote => (
1337
- <li key={remote}>{remote}</li>
1364
+ {remotes.map((remote) => (
1365
+ <li key={remote}>{t(\`shell.remotes.\${remote}\`)}</li>
1338
1366
  ))}
1339
1367
  </ul>
1340
1368
  </main>
@@ -1343,11 +1371,15 @@ export default function ShellHome() {
1343
1371
  `;
1344
1372
  }
1345
1373
  function createRemotePage(app) {
1346
- return `export default function ${toPascalCase(app.id)}Home() {
1374
+ return `import { useTranslation } from 'react-i18next';
1375
+
1376
+ export default function ${toPascalCase(app.id)}Home() {
1377
+ const { t } = useTranslation();
1378
+
1347
1379
  return (
1348
1380
  <main>
1349
- <h1>${app.displayName}</h1>
1350
- <p data-mf-role="${app.kind}">${app.domain ?? app.kind}</p>
1381
+ <h1>{t('remote.title')}</h1>
1382
+ <p data-mf-role="${app.kind}">{t('remote.domain')}</p>
1351
1383
  </main>
1352
1384
  );
1353
1385
  }
@@ -1362,17 +1394,21 @@ export default function Layout({ children }: { children: ReactNode }) {
1362
1394
  `;
1363
1395
  }
1364
1396
  function createRemoteEntry(app) {
1365
- const componentName = 'remote-identity' === app.id ? 'IdentityWidget' : 'CommerceWidget';
1366
- return `export { default } from './components/${componentName}';
1397
+ const componentFile = 'remote-identity' === app.id ? 'identity-widget' : 'commerce-widget';
1398
+ return `export { default } from './components/${componentFile}';
1367
1399
  `;
1368
1400
  }
1369
1401
  function createRemoteWidget(app) {
1370
1402
  const componentName = 'remote-identity' === app.id ? 'IdentityWidget' : 'CommerceWidget';
1371
- return `export default function ${componentName}() {
1403
+ return `import { useTranslation } from 'react-i18next';
1404
+
1405
+ export default function ${componentName}() {
1406
+ const { t } = useTranslation();
1407
+
1372
1408
  return (
1373
1409
  <section data-mf-remote="${app.id}">
1374
- <h2>${app.displayName}</h2>
1375
- <p>Owns the ${app.domain} vertical route surface.</p>
1410
+ <h2>{t('remote.widget.title')}</h2>
1411
+ <p>{t('remote.widget.body')}</p>
1376
1412
  </section>
1377
1413
  );
1378
1414
  }
@@ -1381,7 +1417,7 @@ function createRemoteWidget(app) {
1381
1417
  function createDesignButton() {
1382
1418
  return `import { designTokens } from '../tokens';
1383
1419
 
1384
- export default function Button({ label = 'Design System Button' }: { label?: string }) {
1420
+ export default function Button({ label }: { label: string }) {
1385
1421
  return (
1386
1422
  <button
1387
1423
  type="button"
@@ -1399,8 +1435,8 @@ export default function Button({ label = 'Design System Button' }: { label?: str
1399
1435
  function createDesignTokens() {
1400
1436
  return `export const designTokens = {
1401
1437
  color: {
1402
- foreground: '#133225',
1403
1438
  accent: '#2f8f68',
1439
+ foreground: '#133225',
1404
1440
  },
1405
1441
  radius: {
1406
1442
  control: '999px',
@@ -1408,6 +1444,62 @@ function createDesignTokens() {
1408
1444
  } as const;
1409
1445
  `;
1410
1446
  }
1447
+ function createEnglishTranslations(app) {
1448
+ if ('shell' === app.kind) return {
1449
+ language: {
1450
+ cs: 'Czech',
1451
+ en: 'English',
1452
+ switcher: 'Language'
1453
+ },
1454
+ shell: {
1455
+ preset: 'presetUltramodern workspace',
1456
+ remotes: {
1457
+ 'remote-commerce': 'Commerce Remote',
1458
+ 'remote-design-system': 'Design System Remote',
1459
+ 'remote-identity': 'Identity Remote'
1460
+ },
1461
+ title: 'UltraModern SuperApp Shell'
1462
+ }
1463
+ };
1464
+ return {
1465
+ remote: {
1466
+ domain: app.domain ?? app.kind,
1467
+ title: app.displayName,
1468
+ widget: {
1469
+ body: 'vertical' === app.kind ? `Owns the ${app.domain} vertical route surface.` : 'Provides shared UI primitives for the workspace.',
1470
+ title: app.displayName
1471
+ }
1472
+ }
1473
+ };
1474
+ }
1475
+ function createCzechTranslations(app) {
1476
+ if ('shell' === app.kind) return {
1477
+ language: {
1478
+ cs: 'Cestina',
1479
+ en: 'Anglictina',
1480
+ switcher: 'Jazyk'
1481
+ },
1482
+ shell: {
1483
+ preset: 'presetUltramodern workspace',
1484
+ remotes: {
1485
+ 'remote-commerce': 'Commerce remote',
1486
+ 'remote-design-system': 'Design system remote',
1487
+ 'remote-identity': 'Identity remote'
1488
+ },
1489
+ title: 'UltraModern SuperApp shell'
1490
+ }
1491
+ };
1492
+ return {
1493
+ remote: {
1494
+ domain: app.domain ?? app.kind,
1495
+ title: app.displayName,
1496
+ widget: {
1497
+ body: 'vertical' === app.kind ? `Vlastni ${app.domain} vertical route surface.` : 'Poskytuje sdilene UI prvky pro workspace.',
1498
+ title: app.displayName
1499
+ }
1500
+ }
1501
+ };
1502
+ }
1411
1503
  function createEffectSharedApi() {
1412
1504
  return `import {
1413
1505
  HttpApi,
@@ -1421,9 +1513,7 @@ const recommendationSchema = Schema.Struct({
1421
1513
  title: Schema.String,
1422
1514
  });
1423
1515
 
1424
- export const recommendationsEffectApi = HttpApi.make(
1425
- 'RecommendationsEffectApi',
1426
- ).add(
1516
+ export const recommendationsEffectApi = HttpApi.make('RecommendationsEffectApi').add(
1427
1517
  HttpApiGroup.make('recommendations').add(
1428
1518
  HttpApiEndpoint.get('list', '/effect/recommendations', {
1429
1519
  success: Schema.Struct({
@@ -1446,7 +1536,7 @@ import { recommendationsEffectApi } from '../../shared/effect/api';
1446
1536
  const recommendationsLayer = HttpApiBuilder.group(
1447
1537
  recommendationsEffectApi,
1448
1538
  'recommendations',
1449
- handlers =>
1539
+ (handlers) =>
1450
1540
  handlers.handle('list', () =>
1451
1541
  Effect.succeed({
1452
1542
  items: [
@@ -1749,16 +1839,19 @@ function writeApp(targetDir, scope, app, packageSource) {
1749
1839
  writeJson(targetDir, `${app.directory}/tsconfig.json`, createPackageTsConfig(app.directory));
1750
1840
  writeFile(targetDir, `${app.directory}/src/modern-app-env.d.ts`, "/// <reference types='@modern-js/app-tools/types' />\n");
1751
1841
  writeFile(targetDir, `${app.directory}/modern.config.ts`, createAppModernConfig(app));
1842
+ writeFile(targetDir, `${app.directory}/src/modern.runtime.ts`, createAppRuntimeConfig());
1843
+ writeJson(targetDir, `${app.directory}/config/public/locales/en/translation.json`, createEnglishTranslations(app));
1844
+ writeJson(targetDir, `${app.directory}/config/public/locales/cs/translation.json`, createCzechTranslations(app));
1752
1845
  writeFile(targetDir, `${app.directory}/module-federation.config.ts`, 'shell' === app.kind ? createShellModuleFederationConfig() : createRemoteModuleFederationConfig(app));
1753
1846
  writeFile(targetDir, `${app.directory}/src/routes/layout.tsx`, createLayout(app.id));
1754
1847
  writeFile(targetDir, `${app.directory}/src/routes/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
1755
1848
  if ('vertical' === app.kind) {
1756
1849
  writeFile(targetDir, `${app.directory}/src/remote-entry.tsx`, createRemoteEntry(app));
1757
- const widgetFile = 'remote-identity' === app.id ? 'IdentityWidget.tsx' : 'CommerceWidget.tsx';
1850
+ const widgetFile = 'remote-identity' === app.id ? 'identity-widget.tsx' : 'commerce-widget.tsx';
1758
1851
  writeFile(targetDir, `${app.directory}/src/components/${widgetFile}`, createRemoteWidget(app));
1759
1852
  }
1760
1853
  if ('horizontal-design-system' === app.kind) {
1761
- writeFile(targetDir, `${app.directory}/src/components/Button.tsx`, createDesignButton());
1854
+ writeFile(targetDir, `${app.directory}/src/components/button.tsx`, createDesignButton());
1762
1855
  writeFile(targetDir, `${app.directory}/src/tokens.ts`, createDesignTokens());
1763
1856
  }
1764
1857
  }
@@ -1785,27 +1878,27 @@ function writeSharedPackages(targetDir, scope) {
1785
1878
  });
1786
1879
  }
1787
1880
  writeFile(targetDir, 'packages/shared-contracts/src/index.ts', `export const ultramodernWorkspaceContract = {
1881
+ ownership: 'topology/ownership.json',
1788
1882
  preset: 'presetUltramodern',
1789
1883
  topology: 'topology/reference-topology.json',
1790
- ownership: 'topology/ownership.json',
1791
1884
  } as const;
1792
1885
  `);
1793
1886
  writeFile(targetDir, 'packages/shared-design-tokens/src/index.ts', `export const sharedDesignTokens = {
1794
1887
  color: {
1795
- surface: '#f6fbf7',
1796
- foreground: '#133225',
1797
1888
  accent: '#2f8f68',
1889
+ foreground: '#133225',
1890
+ surface: '#f6fbf7',
1798
1891
  },
1799
1892
  } as const;
1800
1893
  `);
1801
- writeFile(targetDir, 'packages/shared-effect-api/src/index.ts', `export type Recommendation = {
1894
+ writeFile(targetDir, 'packages/shared-effect-api/src/index.ts', `export interface Recommendation {
1802
1895
  id: string;
1803
1896
  title: string;
1804
- };
1897
+ }
1805
1898
 
1806
1899
  export const recommendationsApiContract = {
1807
- serviceId: '${effectService.id}',
1808
1900
  basePath: '/recommendations-api/effect/recommendations',
1901
+ serviceId: '${effectService.id}',
1809
1902
  } as const;
1810
1903
  `);
1811
1904
  }
@@ -1820,7 +1913,7 @@ function generateUltramodernWorkspace(options) {
1820
1913
  packageScope: scope
1821
1914
  });
1822
1915
  writeJson(options.targetDir, 'package.json', createRootPackageJson(scope, packageSource));
1823
- writeJson(options.targetDir, 'tsconfig.base.json', createTsConfigBase(scope));
1916
+ writeJson(options.targetDir, 'tsconfig.base.json', createTsConfigBase());
1824
1917
  writeJson(options.targetDir, 'topology/reference-topology.json', createTopology(scope));
1825
1918
  writeJson(options.targetDir, 'topology/ownership.json', createOwnership(scope));
1826
1919
  writeJson(options.targetDir, 'topology/local-overlays/development.json', createDevelopmentOverlay());
@@ -1904,7 +1997,7 @@ function detectBffRuntime() {
1904
1997
  process.exit(1);
1905
1998
  }
1906
1999
  function src_renderTemplate(template, data) {
1907
- const tagRegex = /\{\{(#if|#unless|\/if|\/unless)(?:\s+(\w+))?\}\}/g;
2000
+ const tagRegex = /\{\{(~?)(#if|#unless|\/if|\/unless)(?:\s+(\w+))?(~?)\}\}/g;
1908
2001
  function renderConditionals(startIndex, expectedClose) {
1909
2002
  let rendered = '';
1910
2003
  let cursor = startIndex;
@@ -1915,7 +2008,7 @@ function src_renderTemplate(template, data) {
1915
2008
  rendered: rendered + template.slice(cursor),
1916
2009
  nextIndex: template.length
1917
2010
  };
1918
- const [raw, tag, condition] = match;
2011
+ const [raw, , tag, condition, rightTrim] = match;
1919
2012
  const tagIndex = match.index;
1920
2013
  rendered += template.slice(cursor, tagIndex);
1921
2014
  cursor = tagIndex + raw.length;
@@ -1931,10 +2024,17 @@ function src_renderTemplate(template, data) {
1931
2024
  }
1932
2025
  if ('/if' === tag || '/unless' === tag) {
1933
2026
  const kind = '/if' === tag ? 'if' : 'unless';
1934
- if (expectedClose === kind) return {
1935
- rendered,
1936
- nextIndex: cursor
1937
- };
2027
+ if (expectedClose === kind) {
2028
+ let nextIndex = cursor;
2029
+ if ('~' === rightTrim) {
2030
+ const trailingWhitespace = /^\s*/u.exec(template.slice(nextIndex));
2031
+ nextIndex += trailingWhitespace?.[0].length ?? 0;
2032
+ }
2033
+ return {
2034
+ rendered,
2035
+ nextIndex
2036
+ };
2037
+ }
1938
2038
  rendered += raw;
1939
2039
  }
1940
2040
  }
@@ -2023,6 +2123,7 @@ function createBuiltinTemplateManifest(version) {
2023
2123
  'AGENTS.md',
2024
2124
  'README.md',
2025
2125
  'api/**',
2126
+ 'config/**',
2026
2127
  'modern.config.ts',
2027
2128
  'oxfmt.config.ts',
2028
2129
  'oxlint.config.ts',
@@ -2417,6 +2518,7 @@ async function main() {
2417
2518
  tsconfigVersion: singleAppModernPackageSpecifier('@modern-js/tsconfig', packageSource, useWorkspaceProtocol),
2418
2519
  pluginTanstackVersion: singleAppModernPackageSpecifier('@modern-js/plugin-tanstack', packageSource, useWorkspaceProtocol),
2419
2520
  pluginBffVersion: singleAppModernPackageSpecifier('@modern-js/plugin-bff', packageSource, useWorkspaceProtocol),
2521
+ pluginI18nVersion: singleAppModernPackageSpecifier('@modern-js/plugin-i18n', packageSource, useWorkspaceProtocol),
2420
2522
  isSubproject,
2421
2523
  routerFramework,
2422
2524
  bffRuntime,
@@ -2496,6 +2598,7 @@ function copyTemplate(src, dest, options) {
2496
2598
  tsconfigVersion: options.tsconfigVersion,
2497
2599
  pluginTanstackVersion: options.pluginTanstackVersion,
2498
2600
  pluginBffVersion: options.pluginBffVersion,
2601
+ pluginI18nVersion: options.pluginI18nVersion,
2499
2602
  isSubproject: options.isSubproject,
2500
2603
  isTanstackRouter: 'tanstack' === options.routerFramework,
2501
2604
  enableBff: 'none' !== options.bffRuntime,