@ui5/task-adaptation
Version:
Custom task for ui5-builder which allows building UI5 Flexibility Adaptation Projects for SAP BTP, Cloud Foundry environment
99 lines • 5.98 kB
JavaScript
import { dotToUnderscore, escapeRegex, removePropertiesExtension } from "./commonUtil.js";
import ResourceUtil from "./resourceUtil.js";
import { posix as path } from "path";
export default class I18NMerger {
static analyzeAppVariantManifestChanges(rootFolder, tranlsationRegexPattern, { changes }) {
// check which files need to be copied and which files need to be merged and copied
// this is necessary because lrep does not support multiple enhanceWith with multiple locations
const mergePaths = new Set();
const copyPaths = new Set();
changes.forEach((change) => {
const i18nPathWithExtension = change.content?.bundleUrl || change.texts?.i18n;
if (i18nPathWithExtension) {
// build regex to match specific + language related files
const i18nPath = removePropertiesExtension(i18nPathWithExtension);
const resourcePath = path.join(rootFolder, i18nPath);
const regex = new RegExp(escapeRegex(resourcePath) + tranlsationRegexPattern);
if (change.changeType.includes("addNewModelEnhanceWith")) {
copyPaths.add(regex);
}
else {
mergePaths.add(regex);
}
}
});
return { mergePathsRegex: [...mergePaths.values()], copyPathsRegex: [...copyPaths.values()] };
}
static async mergeI18NFiles(baseAppResources, appVariantResources, projectNamespace, baseAppManifestI18NPath, appVariantInfo, taskUtil) {
const aggregatedResourceFilesMap = new Map(baseAppResources.map(baseAppResource => [baseAppResource.getPath(), baseAppResource]));
const i18nTargetFolder = dotToUnderscore(appVariantInfo.id);
const rootFolder = ResourceUtil.getRootFolder(projectNamespace);
const tranlsationRegexPattern = "((_[a-z]{2,3})?(_[a-zA-Z]{2,3}(_[a-zA-Z]{2,20})?)?)\.properties$";
const { copyPathsRegex: copyPathsValues, mergePathsRegex: mergePathsValues } = this.analyzeAppVariantManifestChanges(rootFolder, tranlsationRegexPattern, appVariantInfo);
for (const appVariantResource of appVariantResources) {
const appVariantResourcePath = appVariantResource.getPath();
if (appVariantResourcePath.endsWith(".properties")) {
// merge/copy logic
// check if file matches with regex in merge/copy
const mergePathMatch = mergePathsValues.map(path => appVariantResourcePath.match(path)).find(match => match);
const shouldMergeFile = !!mergePathMatch;
const shouldCopyFile = copyPathsValues.map(path => appVariantResourcePath.match(path)).find(match => match);
if (shouldMergeFile) {
let baseAppI18NPath = `${rootFolder}/${baseAppManifestI18NPath}${mergePathMatch[1] || ""}.properties`;
await this.mergePropertiesFiles(aggregatedResourceFilesMap, appVariantResource, baseAppI18NPath);
}
// Resource for to be copied file already exists so we only have to adjust path
// Otherwise we have to omit it. We always change the path to avoid omitting a base app file
this.moveToAppVarSubfolder(appVariantResource, rootFolder, i18nTargetFolder);
if (!shouldCopyFile) {
taskUtil.setTag(appVariantResource, taskUtil.STANDARD_TAGS.OmitFromBuildResult, true);
}
}
aggregatedResourceFilesMap.set(appVariantResource.getPath(), appVariantResource);
}
return Array.from(aggregatedResourceFilesMap.values());
}
/**
* Merge/Append base property file with property file from app variant
* FIXME Currently merge could duplicate keys which causes undefined
* behavior => Existing keys which are in merge content must be removed =>
* Actually only descriptor texts are relevant for merge which always have
* app variant Id as prefix => If we filter on them we do not need to remove
* existing overwritten keys (as there should be none)
*/
static async mergePropertiesFiles(aggregatedResourceFilesMap, variantResource, baseAppI18NPath) {
const baseAppI18NFile = aggregatedResourceFilesMap.get(baseAppI18NPath);
if (baseAppI18NFile) {
await this.mergeFiles(baseAppI18NFile, variantResource);
}
else {
// create the merge target file if it missing in base app. Maybe the language does not exist in the base app.
// Since the file might also be copied we do not just change the path of it but create another resource
await this.createFile(aggregatedResourceFilesMap, baseAppI18NPath, variantResource);
}
}
/**
* update the path of app variant property file so it will be copied into
<app_variant_id> folder
*/
static moveToAppVarSubfolder(variantResource, rootFolder, i18nBundleName) {
const relativeFilePath = variantResource.getPath().substring(rootFolder.length);
const newResourcePath = path.join(rootFolder, i18nBundleName, relativeFilePath);
variantResource.setPath(newResourcePath);
}
/**
* create new i18n file in case e.g. translation file does not exist in base
* app but in variant and copy of translation file is needed
*/
static async createFile(aggregatedResourceFilesMap, path, resource) {
const createdFile = await resource.clone();
createdFile.setPath(path);
aggregatedResourceFilesMap.set(path, createdFile);
}
static async mergeFiles(baseFile, variantFile) {
const variantFileContent = await variantFile.getString();
const mergedFileContent = await baseFile.getString();
baseFile.setString(`${mergedFileContent}\n\n#App variant specific text file\n\n${variantFileContent}`);
}
}
//# sourceMappingURL=i18nMerger.js.map