Skip to content

Commit fecb7e3

Browse files
committed
feat(nf): support angular i18n
1 parent f244fd0 commit fecb7e3

File tree

10 files changed

+145
-23
lines changed

10 files changed

+145
-23
lines changed
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
{
22
"name": "@softarc/native-federation",
3-
"version": "2.0.23",
3+
"version": "2.0.25",
44
"type": "commonjs",
55
"license": "MIT",
66
"dependencies": {
77
"json5": "^2.2.0",
88
"npmlog": "^6.0.2",
9-
"@softarc/native-federation-runtime": "2.0.23"
9+
"@softarc/native-federation-runtime": "2.0.25"
1010
}
1111
}

libs/native-federation-core/src/lib/core/build-for-federation.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export async function buildForFederation(
2727
fedOptions: FederationOptions,
2828
externals: string[],
2929
buildParams = defaultBuildParams
30-
) {
30+
): Promise<FederationInfo> {
3131
let artefactInfo: ArtefactInfo | undefined;
3232

3333
if (!buildParams.skipMappingsAndExposed) {

libs/native-federation-esbuild/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@softarc/native-federation-esbuild",
3-
"version": "2.0.23",
3+
"version": "2.0.25",
44
"type": "commonjs",
55
"dependencies": {
66
"@rollup/plugin-commonjs": "^22.0.2",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"name": "@softarc/native-federation-node",
3-
"version": "2.0.23"
3+
"version": "2.0.25"
44
}

libs/native-federation-runtime/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@softarc/native-federation-runtime",
3-
"version": "2.0.23",
3+
"version": "2.0.25",
44
"dependencies": {
55
"tslib": "^2.3.0"
66
},

libs/native-federation/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@angular-architects/native-federation",
3-
"version": "19.0.11",
3+
"version": "19.0.13",
44
"main": "src/index.js",
55
"generators": "./collection.json",
66
"builders": "./builders.json",
@@ -20,8 +20,8 @@
2020
},
2121
"dependencies": {
2222
"@babel/core": "^7.19.0",
23-
"@softarc/native-federation": "2.0.23",
24-
"@softarc/native-federation-runtime": "2.0.23",
23+
"@softarc/native-federation": "2.0.25",
24+
"@softarc/native-federation-runtime": "2.0.25",
2525
"@types/browser-sync": "^2.29.0",
2626
"@chialab/esbuild-plugin-commonjs": "^0.18.0",
2727
"browser-sync": "^3.0.2",

libs/native-federation/src/builders/build/builder.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
createBuilder,
1515
} from '@angular-devkit/architect';
1616

17-
import { DevServerBuilderOptions } from '@angular-devkit/build-angular';
1817
import { normalizeOptions } from '@angular-devkit/build-angular/src/builders/dev-server/options';
1918

2019
import { setLogLevel, logger } from '@softarc/native-federation/build';
@@ -33,7 +32,7 @@ import { targetFromTargetString } from '@angular-devkit/architect';
3332
import { NfBuilderSchema } from './schema';
3433
import { reloadBrowser, setError } from '../../utils/dev-server';
3534
import { RebuildHubs } from '../../utils/rebuild-events';
36-
import { updateIndexHtml, updateScriptTags } from '../../utils/updateIndexHtml';
35+
import { updateScriptTags } from '../../utils/updateIndexHtml';
3736
import { existsSync, mkdirSync, rmSync } from 'fs';
3837
import {
3938
EsBuildResult,
@@ -45,6 +44,8 @@ import { createSharedMappingsPlugin } from '../../utils/shared-mappings-plugin';
4544
// import { NextHandleFunction } from 'vite';
4645
import { PluginBuild } from 'esbuild';
4746
import { FederationInfo } from '@softarc/native-federation-runtime';
47+
import { getI18nConfig, translateFederationArtefacts } from '../../utils/i18n';
48+
import { createOrUpdateGithubRelease } from 'nx/src/command-line/release/utils/github';
4849

4950
function _buildApplication(options, context, pluginsOrExtensions) {
5051
let extensions;
@@ -122,7 +123,7 @@ export async function* runBuilder(
122123
options.baseHref = nfOptions.baseHref;
123124
}
124125

125-
if(nfOptions.outputPath){
126+
if (nfOptions.outputPath) {
126127
options.outputPath = nfOptions.outputPath;
127128
}
128129

@@ -134,7 +135,6 @@ export async function* runBuilder(
134135
setLogLevel(options.verbose ? 'verbose' : 'info');
135136

136137
const outputPath = options.outputPath;
137-
138138
const outputOptions: Required<
139139
Exclude<ApplicationBuilderOptions['outputPath'], string>
140140
> = {
@@ -145,9 +145,12 @@ export async function* runBuilder(
145145
base: typeof outputPath === 'string' ? outputPath : outputPath.base,
146146
};
147147

148+
const i18n = await getI18nConfig(context);
149+
148150
const browserOutputPath = path.join(
149151
outputOptions.base,
150-
outputOptions.browser
152+
outputOptions.browser,
153+
i18n?.sourceLocale || ''
151154
);
152155

153156
const fedOptions: FederationOptions = {
@@ -235,12 +238,18 @@ export async function* runBuilder(
235238
});
236239
}
237240

241+
let federationResult: FederationInfo;
238242
try {
239-
await buildForFederation(config, fedOptions, externals);
243+
federationResult = await buildForFederation(config, fedOptions, externals);
240244
} catch (e) {
241245
process.exit(1);
242246
}
243247

248+
const hasLocales = i18n?.locales && Object.keys(i18n.locales).length > 0;
249+
if (!runServer && hasLocales) {
250+
translateFederationArtefacts(i18n, outputOptions.base, federationResult);
251+
}
252+
244253
options.deleteOutputPath = false;
245254

246255
const appBuilderName = '@angular-devkit/build-angular:application';
@@ -261,6 +270,7 @@ export async function* runBuilder(
261270
)
262271
: buildApplication(options, context, {
263272
codePlugins: plugins as any,
273+
indexHtmlTransformer: transformIndexHtml(nfOptions),
264274
});
265275

266276
// builderRun.output.subscribe(async (output) => {
@@ -285,9 +295,9 @@ export async function* runBuilder(
285295
);
286296
}
287297

288-
if (write && !runServer && !nfOptions.skipHtmlTransform) {
289-
updateIndexHtml(fedOptions, nfOptions);
290-
}
298+
// if (write && !runServer && !nfOptions.skipHtmlTransform) {
299+
// updateIndexHtml(fedOptions, nfOptions);
300+
// }
291301

292302
// if (!runServer) {
293303
// yield output;

libs/native-federation/src/schematics/init/schematic.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121

2222
import {
2323
addPackageJsonDependency,
24+
getPackageJsonDependency,
2425
NodeDependencyType,
2526
} from '@schematics/angular/utility/dependencies';
2627

@@ -40,6 +41,10 @@ type NormalizedOptions = {
4041
port: number;
4142
};
4243

44+
type PackageJson = {
45+
dependencies: Record<string, string>;
46+
};
47+
4348
export function updatePackageJson(tree: Tree): void {
4449
const packageJson = tree.readJson('package.json');
4550

@@ -72,6 +77,9 @@ export default function config(options: MfSchematicSchema): Rule {
7277
return async function (tree, context) {
7378
const workspaceFileName = getWorkspaceFileName(tree);
7479
const workspace = JSON.parse(tree.read(workspaceFileName).toString('utf8'));
80+
const packageJson = JSON.parse(
81+
tree.read('package.json').toString('utf8')
82+
) as PackageJson;
7583

7684
const normalized = normalizeOptions(options, workspace, tree);
7785

@@ -126,6 +134,14 @@ export default function config(options: MfSchematicSchema): Rule {
126134
// updatePackageJson(tree);
127135
// patchAngularBuild(tree);
128136

137+
addPackageJsonDependency(tree, {
138+
name: '@angular/animations',
139+
type: NodeDependencyType.Default,
140+
version:
141+
getPackageJsonDependency(tree, '@angular/core')?.version || 'latest',
142+
overwrite: false,
143+
});
144+
129145
addPackageJsonDependency(tree, {
130146
name: 'es-module-shims',
131147
type: NodeDependencyType.Default,

libs/native-federation/src/utils/angular-esbuild-adapter.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ export function loadEsmModule<T>(modulePath: string | URL): Promise<T> {
420420
//
421421
// Usually, ngServerMode is set during bundling. However, we need to infer this
422422
// value at runtime as we are using the same shared bundle for @angular/core
423-
// on the server and in the browser.
423+
// on the server and in the browser.
424424
//
425425
function setNgServerMode(): void {
426426
const fileToPatch = 'node_modules/@angular/core/fesm2022/core.mjs';
@@ -432,10 +432,7 @@ function setNgServerMode(): void {
432432
if (!content.includes(lineToAdd)) {
433433
content = lineToAdd + '\n' + content;
434434
fs.writeFileSync(fileToPatch, content);
435-
console.log('patched!');
436-
} else {
437-
console.log('not patched!');
438-
}
435+
}
439436
}
440437
} catch (e) {
441438
console.error(
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { BuilderContext } from '@angular-devkit/architect';
2+
import { logger } from '@softarc/native-federation/build';
3+
import { execSync } from 'child_process';
4+
import path from 'path';
5+
import fs from 'fs';
6+
import { FederationInfo } from '@softarc/native-federation-runtime';
7+
8+
export type WorkspaceConfig = {
9+
i18n?: I18nConfig;
10+
};
11+
12+
export type I18nConfig = {
13+
sourceLocale: string;
14+
locales: Record<string, string>;
15+
};
16+
17+
export async function getI18nConfig(
18+
context: BuilderContext
19+
): Promise<I18nConfig | undefined> {
20+
const workspaceConfig = (await context.getProjectMetadata(
21+
context.target?.project || ''
22+
)) as WorkspaceConfig;
23+
24+
const i18nConfig = workspaceConfig?.i18n;
25+
return i18nConfig;
26+
}
27+
28+
export async function translateFederationArtefacts(
29+
i18n: I18nConfig,
30+
outputPath: string,
31+
federationResult: FederationInfo
32+
) {
33+
34+
logger.info('Writing Translations');
35+
36+
const translationFiles =
37+
'"' +
38+
Object.values(i18n.locales || {})
39+
.map((value) => JSON.stringify(value))
40+
.join(' ')
41+
.replace(/"/g, '') +
42+
'"';
43+
44+
const locales = Object.keys(i18n.locales);
45+
const targetLocales = locales.join(' ');
46+
47+
const sourceLocale = i18n.sourceLocale;
48+
49+
const translationOutPath = path.join(outputPath, 'browser', '{{LOCALE}}');
50+
51+
const federationFiles = [
52+
...federationResult.shared.map((s) => s.outFileName),
53+
...federationResult.exposes.map((e) => e.outFileName),
54+
];
55+
56+
// Here, we use a glob with an exhaustive list i/o `"*.js"`
57+
// to improve performance
58+
const sourcePattern = '{' + federationFiles.join(',') + '}';
59+
60+
const sourceLocalePath = path.join(
61+
outputPath,
62+
'browser',
63+
sourceLocale,
64+
);
65+
66+
const cmd = `node node_modules/.bin/localize-translate -r ${sourceLocalePath} -s "${sourcePattern}" -t ${translationFiles} -o ${translationOutPath} --target-locales ${targetLocales} -l ${sourceLocale}`;
67+
68+
ensureDistFolders(locales, outputPath);
69+
copyRemoteEntry(locales, outputPath, sourceLocalePath);
70+
71+
logger.debug('Running: ' + cmd);
72+
73+
execCommand(cmd, 'Successfully translated');
74+
}
75+
76+
function execCommand(cmd: string, defaultSuccessInfo: string) {
77+
try {
78+
const output = execSync(cmd);
79+
logger.info(output.toString() || defaultSuccessInfo);
80+
} catch (error) {
81+
logger.error(error.message);
82+
}
83+
}
84+
85+
function copyRemoteEntry(locales: string[], outputPath: string, sourceLocalePath: string) {
86+
const remoteEntry = path.join(sourceLocalePath, 'remoteEntry.json');
87+
88+
for (const locale of locales) {
89+
const localePath = path.join(outputPath, 'browser', locale, 'remoteEntry.json');
90+
fs.copyFileSync(remoteEntry, localePath);
91+
}
92+
}
93+
94+
function ensureDistFolders(locales: string[], outputPath: string) {
95+
for (const locale of locales) {
96+
const localePath = path.join(outputPath, 'browser', locale);
97+
fs.mkdirSync(localePath, { recursive: true })
98+
}
99+
}

0 commit comments

Comments
 (0)