mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
⚡ Support versioned nodes
This commit is contained in:
parent
99963b04a5
commit
9819c25ec5
|
@ -40,6 +40,10 @@ class NodeTypesClass implements INodeTypes {
|
||||||
return this.nodeTypes[nodeType].type;
|
return this.nodeTypes[nodeType].type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of `getByNameAndVersion` that includes the node's source path,
|
||||||
|
* to be used for locating the node's `/translations` dir.
|
||||||
|
*/
|
||||||
getWithPath(
|
getWithPath(
|
||||||
nodeTypeName: string,
|
nodeTypeName: string,
|
||||||
version: number,
|
version: number,
|
||||||
|
|
|
@ -145,7 +145,7 @@ import { InternalHooksManager } from './InternalHooksManager';
|
||||||
import { TagEntity } from './databases/entities/TagEntity';
|
import { TagEntity } from './databases/entities/TagEntity';
|
||||||
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
import { WorkflowEntity } from './databases/entities/WorkflowEntity';
|
||||||
import { NameRequest } from './WorkflowHelpers';
|
import { NameRequest } from './WorkflowHelpers';
|
||||||
import { getTranslationPath } from './TranslationHelpers';
|
import { getExpectedNodeTranslationPath } from './TranslationHelpers';
|
||||||
|
|
||||||
require('body-parser-xml')(bodyParser);
|
require('body-parser-xml')(bodyParser);
|
||||||
|
|
||||||
|
@ -1186,23 +1186,26 @@ class App {
|
||||||
if (language === 'en') {
|
if (language === 'en') {
|
||||||
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
|
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
|
||||||
const { description } = nodeTypes.getByNameAndVersion(name, version);
|
const { description } = nodeTypes.getByNameAndVersion(name, version);
|
||||||
if (description) acc.push(description);
|
acc.push(description);
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add node translations where available
|
const nodeTypesWithTranslations: INodeTypeDescription[] = [];
|
||||||
return nodeInfos.reduce<INodeTypeDescription[]>((acc, { name, version }) => {
|
|
||||||
const { description, sourcePath } = nodeTypes.getWithPath(name, version);
|
|
||||||
const mainTranslationPath = getTranslationPath(sourcePath, language);
|
|
||||||
|
|
||||||
if (description && existsSync(mainTranslationPath)) {
|
for (const { name, version } of nodeInfos) {
|
||||||
description.translation = require(mainTranslationPath);
|
const { description, sourcePath } = nodeTypes.getWithPath(name, version);
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
const nodeTranslationPath = await getExpectedNodeTranslationPath(sourcePath, language);
|
||||||
|
|
||||||
|
if (existsSync(nodeTranslationPath)) {
|
||||||
|
description.translation = require(nodeTranslationPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (description) acc.push(description);
|
nodeTypesWithTranslations.push(description);
|
||||||
return acc;
|
}
|
||||||
}, []);
|
|
||||||
|
return nodeTypesWithTranslations;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,39 @@
|
||||||
import { join, dirname } from 'path';
|
import { join, dirname } from 'path';
|
||||||
|
import { readdir } from 'fs/promises';
|
||||||
|
import { Dirent } from 'fs';
|
||||||
|
|
||||||
/**
|
const ALLOWED_VERSIONED_DIRNAME_LENGTH = [2, 3]; // v1, v10
|
||||||
* Retrieve the path to the translation file for a node.
|
|
||||||
*/
|
function isVersionedDirname(dirent: Dirent) {
|
||||||
export function getTranslationPath(nodeSourcePath: string, language: string): string {
|
if (!dirent.isDirectory()) return false;
|
||||||
return join(dirname(nodeSourcePath), 'translations', `${language}.js`);
|
|
||||||
|
return (
|
||||||
|
ALLOWED_VERSIONED_DIRNAME_LENGTH.includes(dirent.name.length) &&
|
||||||
|
dirent.name.toLowerCase().startsWith('v')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMaxVersion(from: string) {
|
||||||
|
const entries = await readdir(from, { withFileTypes: true });
|
||||||
|
|
||||||
|
const dirnames = entries.reduce<string[]>((acc, cur) => {
|
||||||
|
if (isVersionedDirname(cur)) acc.push(cur.name);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!dirnames.length) return null;
|
||||||
|
|
||||||
|
return Math.max(...dirnames.map((d) => parseInt(d.charAt(1), 10)));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getExpectedNodeTranslationPath(
|
||||||
|
nodeSourcePath: string,
|
||||||
|
language: string,
|
||||||
|
): Promise<string> {
|
||||||
|
const nodeDir = dirname(nodeSourcePath);
|
||||||
|
const maxVersion = await getMaxVersion(nodeDir);
|
||||||
|
|
||||||
|
return maxVersion
|
||||||
|
? join(nodeDir, `v${maxVersion}`, 'translations', `${language}.js`)
|
||||||
|
: join(nodeDir, 'translations', `${language}.js`);
|
||||||
}
|
}
|
||||||
|
|
35
packages/nodes-base/nodes/Mattermost/v1/translations/de.ts
Normal file
35
packages/nodes-base/nodes/Mattermost/v1/translations/de.ts
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
module.exports = {
|
||||||
|
mattermost: {
|
||||||
|
header: {
|
||||||
|
displayName: '🇩🇪 Mattermost',
|
||||||
|
description: '🇩🇪 Consume Mattermost API',
|
||||||
|
},
|
||||||
|
credentialsModal: {
|
||||||
|
mattermostApi: {
|
||||||
|
accessToken: {
|
||||||
|
displayName: '🇩🇪 Access token',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodeView: {
|
||||||
|
resource: {
|
||||||
|
displayName: '🇩🇪 Resource',
|
||||||
|
description: '🇩🇪 The resource to operate on.',
|
||||||
|
options: {
|
||||||
|
channel: {
|
||||||
|
displayName: '🇩🇪 Channel',
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
displayName: '🇩🇪 Message',
|
||||||
|
},
|
||||||
|
reaction: {
|
||||||
|
displayName: '🇩🇪 Reaction',
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
displayName: '🇩🇪 User',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
Loading…
Reference in a new issue