Skip to content

Commit

Permalink
feat(extractor): add mapping between localization key and component
Browse files Browse the repository at this point in the history
  • Loading branch information
matthieu-crouzet committed Oct 17, 2023
1 parent ce5b7a6 commit a37894d
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export class LocalizationPresComponent implements Translatable<LocalizationPresT
@Localization('./localization-pres.localization.json')
public translations: LocalizationPresTranslation;

public test = 'false';

private subscription = new Subscription();

constructor(localizationService: LocalizationService, fb: FormBuilder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { logging } from '@angular-devkit/core';
import type { ComponentStructure } from '@o3r/components';
import { getLocalizationFileFromAngularElement } from '@o3r/extractors';
import { isO3rClassComponent } from '@o3r/schematics';
import * as fs from 'node:fs';
import * as path from 'node:path';
import * as ts from 'typescript';

Expand Down Expand Up @@ -29,6 +31,8 @@ export interface ComponentInformation {
templateUrl?: string;
/** Determine if the component is activating a ruleset */
linkableToRuleset: boolean;
/** List of localization keys used in the component */
localizationKeys?: string[];
}

/**
Expand Down Expand Up @@ -188,7 +192,18 @@ export class ComponentClassExtractor {
this.logger.debug(`${name!} is ignored because it is not a configurable component`);
}

return name && type ? { name, configName, contextName, isDynamicConfig: isDynamic, type, selector, templateUrl, linkableToRuleset } : undefined;
const localizationFiles = getLocalizationFileFromAngularElement(classNode);

const localizationKeys = (localizationFiles || []).reduce((acc: string[], file) => {
const resolvedFilePath = path.resolve(path.dirname(this.filePath), file);
const data = JSON.parse(fs.readFileSync(resolvedFilePath, 'utf-8'));
return acc.concat(Object.keys(data));
}, []);

return name && type ? {
name, configName, contextName, isDynamicConfig: isDynamic, type, selector, templateUrl, linkableToRuleset,
...(localizationKeys.length ? { localizationKeys } : {})
} : undefined;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ export class ComponentExtractor {
type: parsedItemRef.component.type,
context,
config,
linkableToRuleset: parsedItemRef.component.linkableToRuleset
linkableToRuleset: parsedItemRef.component.linkableToRuleset,
localizationKeys: parsedItemRef.component.localizationKeys
};

});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,12 @@
"linkableToRuleset": {
"type": "boolean",
"description": "Determine if the component is activating a ruleset"
},
"localizationKeys": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions packages/@o3r/components/src/core/component.output.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export interface ComponentClassOutput extends Output {
placeholders?: PlaceholderData[];
/** Determine if the component is activating a ruleset */
linkableToRuleset: boolean;
/** List of localization keys used in the component */
localizationKeys?: string[];
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/@o3r/extractors/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './common';
export * from './config-doc';
export * from './localization';
export * from './parser-factory';
export * from './tsdoc';
export * from './validator';
38 changes: 38 additions & 0 deletions packages/@o3r/extractors/src/utils/localization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as ts from 'typescript';

const localizationDecoratorName = 'Localization';

/**
* Retrieve the localization json files from TS Code
*
* @param node TSNode of the angular component class
* @param source Ts file source
*/
export function getLocalizationFileFromAngularElement(node: ts.ClassDeclaration): string[] | undefined {
const localizationPaths: string[] = [];
node.forEachChild((item) => {
if (!ts.isPropertyDeclaration(item)) {
return;
}

item.forEachChild((decorator) => {
if (
!ts.isDecorator(decorator)
|| !ts.isCallExpression(decorator.expression)
|| !ts.isIdentifier(decorator.expression.expression)
|| decorator.expression.expression.escapedText !== localizationDecoratorName
) {
return;
}

const firstArg = decorator.expression.arguments[0];
if (!firstArg || !ts.isStringLiteral(firstArg)) {
return;
}

localizationPaths.push(firstArg.text);
});
});

return localizationPaths.length ? localizationPaths : undefined;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { logging } from '@angular-devkit/core';
import { getLibraryCmsMetadata } from '@o3r/extractors';
import { getLibraryCmsMetadata, getLocalizationFileFromAngularElement } from '@o3r/extractors';
import type { JSONLocalization, LocalizationMetadata } from '@o3r/localization';
import { O3rCliError } from '@o3r/schematics';
import * as fs from 'node:fs';
Expand Down Expand Up @@ -103,37 +103,6 @@ export class LocalizationExtractor {
return angularItems.length ? angularItems : undefined;
}

/**
* Retrieve the localization json file from TS Code
*
* @param node TSNode of the angular component class
* @param source Ts file source
*/
private getLocalizationFileFromAngularElement(node: ts.ClassDeclaration, source: ts.SourceFile): string[] | undefined {
const localizationPaths: string[] = [];
node.forEachChild((item) => {
if (!ts.isPropertyDeclaration(item)) {
return;
}

item.forEachChild((decorator) => {
if (!ts.isDecorator(decorator)) {
return;
}

const text = decorator.getText(source);
const result = /^@Localization *\( *['"](.*)['"] *\)/.exec(text);
if (!result || !result[1]) {
return;
}

localizationPaths.push(result[1]);
});
});

return localizationPaths.length ? localizationPaths : undefined;
}

/**
* Get the list of referenced translation files
*
Expand Down Expand Up @@ -300,9 +269,9 @@ export class LocalizationExtractor {
const localizationFiles = tsFiles
.map((file) => ({file, source: program.getSourceFile(file)}))
.map(({ file, source }) => ({ file, classes: source && this.getAngularClassNode(source), source}))
.filter(({ classes, source }) => !!classes && !!source)
.map(({file, classes, source}) => classes!
.map((classItem) => this.getLocalizationFileFromAngularElement(classItem, source!))
.filter(({ classes }) => !!classes)
.map(({file, classes}) => classes!
.map((classItem) => getLocalizationFileFromAngularElement(classItem))
.filter((locFiles): locFiles is string[] => !!locFiles)
.reduce((acc: string[], locFiles) => {
acc.push(...locFiles.filter((f) => acc.indexOf(f) === -1));
Expand Down

0 comments on commit a37894d

Please sign in to comment.