Skip to content

Commit

Permalink
feat(editor): Use i18n component instead od v-html for localization
Browse files Browse the repository at this point in the history
* feat(editor): Export i18n instance and bind it to Vue instance

* feat(editor): Audit usage of v-html and replace with alternatives where possible

* 🔀 Fix conflicted element in RunDataTable

* ♻️ Refactor issues elements with the new TitledList component

* 🐛 Fixing unknown node modal dialog content rendering

Co-authored-by: Milorad Filipovic <milorad@n8n.io>
  • Loading branch information
OlegIvaniv and MiloradFilipovic committed Sep 5, 2022
1 parent bbd967b commit 287533e
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 65 deletions.
Expand Up @@ -50,7 +50,7 @@
<span
size="small"
:class="[$style.infoText, infoTextErrorMessage ? $style.error : '']"
v-html="infoTextErrorMessage"
v-text="infoTextErrorMessage"
></span>
</div>
<el-checkbox
Expand Down
Expand Up @@ -13,7 +13,7 @@
<div :class="$style.descriptionContainer" v-if="this.mode === COMMUNITY_PACKAGE_MANAGE_ACTIONS.UPDATE">
<n8n-info-tip theme="info" type="note" :bold="false">
<template>
<span v-html="getModalContent.description"></span>
<span v-text="getModalContent.description"></span>
</template>
</n8n-info-tip>
</div>
Expand Down
Expand Up @@ -5,7 +5,7 @@
</div>
<div>
<font-awesome-icon icon="exclamation-triangle" />
<span v-html="$locale.baseText('executionDetails.readOnly.readOnly')"></span>
<span v-text="$locale.baseText('executionDetails.readOnly.readOnly')"></span>
</div>
</n8n-tooltip>
</template>
Expand All @@ -22,4 +22,4 @@ export default Vue.extend({
svg {
margin-right: 6px;
}
</style>
</style>
14 changes: 7 additions & 7 deletions packages/editor-ui/src/components/Node.vue
Expand Up @@ -6,13 +6,13 @@
<div v-if="!data.disabled" :class="{'node-info-icon': true, 'shift-icon': shiftOutputCount}">
<div v-if="hasIssues" class="node-issues">
<n8n-tooltip placement="bottom" >
<div slot="content" v-html="nodeIssues"></div>
<titled-list slot="content" :title="`${$locale.baseText('node.issues')}:`" :items="nodeIssues" />
<font-awesome-icon icon="exclamation-triangle" />
</n8n-tooltip>
</div>
<div v-else-if="waiting" class="waiting">
<n8n-tooltip placement="bottom">
<div slot="content" v-html="waiting"></div>
<div slot="content" v-text="waiting"></div>
<font-awesome-icon icon="clock" />
</n8n-tooltip>
</div>
Expand Down Expand Up @@ -105,6 +105,7 @@ import {
} from 'n8n-workflow';
import NodeIcon from '@/components/NodeIcon.vue';
import TitledList from '@/components/TitledList.vue';
import mixins from 'vue-typed-mixins';
Expand All @@ -121,6 +122,7 @@ export default mixins(
).extend({
name: 'Node',
components: {
TitledList,
NodeIcon,
},
computed: {
Expand Down Expand Up @@ -200,14 +202,12 @@ export default mixins(
executing: this.isExecuting,
};
},
nodeIssues (): string {
nodeIssues (): string[] {
if (this.data.issues === undefined) {
return '';
return [];
}
const nodeIssues = NodeHelpers.nodeIssuesToString(this.data.issues, this.data);
return `${this.$locale.baseText('node.issues')}:<br />&nbsp;&nbsp;- ` + nodeIssues.join('<br />&nbsp;&nbsp;- ');
return NodeHelpers.nodeIssuesToString(this.data.issues, this.data);
},
nodeDisabledIcon (): string {
if (this.data.disabled === false) {
Expand Down
7 changes: 6 additions & 1 deletion packages/editor-ui/src/components/NodeCredentials.vue
Expand Up @@ -42,7 +42,7 @@

<div :class="$style.warning" v-if="issues.length">
<n8n-tooltip placement="top" >
<div slot="content" v-html="`${$locale.baseText('nodeCredentials.issues')}:<br />&nbsp;&nbsp;- ` + issues.join('<br />&nbsp;&nbsp;- ')"></div>
<titled-list slot="content" :title="`${$locale.baseText('nodeCredentials.issues')}:`" :items="issues" />
<font-awesome-icon icon="exclamation-triangle" />
</n8n-tooltip>
</div>
Expand Down Expand Up @@ -74,6 +74,8 @@ import { genericHelpers } from '@/components/mixins/genericHelpers';
import { nodeHelpers } from '@/components/mixins/nodeHelpers';
import { showMessage } from '@/components/mixins/showMessage';
import TitledList from '@/components/TitledList.vue';
import { mapGetters } from "vuex";
import mixins from 'vue-typed-mixins';
Expand All @@ -89,6 +91,9 @@ export default mixins(
'node', // INodeUi
'overrideCredType', // cred type
],
components: {
TitledList,
},
data () {
return {
NEW_CREDENTIALS_TEXT: `- ${this.$locale.baseText('nodeCredentials.createNew')} -`,
Expand Down
30 changes: 17 additions & 13 deletions packages/editor-ui/src/components/NodeSettings.vue
Expand Up @@ -28,11 +28,14 @@
</div>
<div v-if="isCommunityNode" :class="$style.descriptionContainer">
<div class="mb-l">
<span
v-html="$locale.baseText('nodeSettings.communityNodeUnknown.description', { interpolate: { packageName: node.type.split('.')[0] } })"
@click="onMissingNodeTextClick"
>
</span>
<i18n path="nodeSettings.communityNodeUnknown.description" tag="span" @click="onMissingNodeTextClick">
<template #action>
<a
:href="`https://www.npmjs.com/package/${node.type.split('.')[0]}`"
target="_blank"
>{{ node.type.split('.')[0] }}</a>
</template>
</i18n>
</div>
<n8n-link
:to="COMMUNITY_NODES_INSTALLATION_DOCS_URL"
Expand All @@ -41,14 +44,15 @@
{{ $locale.baseText('nodeSettings.communityNodeUnknown.installLink.text') }}
</n8n-link>
</div>
<span v-else
v-html="
$locale.baseText('nodeSettings.nodeTypeUnknown.description',
{
interpolate: { docURL: CUSTOM_NODES_DOCS_URL }
})
">
</span>
<i18n v-else path="nodeSettings.nodeTypeUnknown.description" tag="span">
<template #action>
<a
:href="CUSTOM_NODES_DOCS_URL"
target="_blank"
v-text="$locale.baseText('nodeSettings.nodeTypeUnknown.description.customNode')"
/>
</template>
</i18n>
</div>
<div class="node-parameters-wrapper" v-if="node && nodeValid">
<div v-show="openPanel === 'params'">
Expand Down
6 changes: 5 additions & 1 deletion packages/editor-ui/src/components/ParameterIssues.vue
@@ -1,17 +1,21 @@
<template>
<div :class="$style['parameter-issues']" v-if="issues.length">
<n8n-tooltip placement="top" >
<div slot="content" v-html="`${$locale.baseText('parameterInput.issues')}:<br />&nbsp;&nbsp;- ` + issues.join('<br />&nbsp;&nbsp;- ')"></div>
<titled-list slot="content" :title="`${$locale.baseText('parameterInput.issues')}:`" :items="issues" />
<font-awesome-icon icon="exclamation-triangle" />
</n8n-tooltip>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
import TitledList from '@/components/TitledList.vue';
export default Vue.extend({
name: 'ParameterIssues',
components: {
TitledList,
},
props: [
'issues',
],
Expand Down
38 changes: 17 additions & 21 deletions packages/editor-ui/src/components/RunDataTable.vue
Expand Up @@ -21,10 +21,10 @@
:disabled="!mappingEnabled || showHintWithDelay"
:open-delay="1000"
>
<div
slot="content"
v-html="$locale.baseText('dataMapping.dragColumnToFieldHint')"
></div>
<div slot="content">
<img src='/static/data-mapping-gif.gif'/>
{{ $locale.baseText('dataMapping.dragColumnToFieldHint') }}
</div>
<Draggable
type="mapping"
:data="getExpression(column)"
Expand All @@ -48,38 +48,34 @@
:class="{
[$style.header]: true,
[$style.draggableHeader]: mappingEnabled,
[$style.activeHeader]:
(i === activeColumn || forceShowGrip) && mappingEnabled,
[$style.activeHeader]: (i === activeColumn || forceShowGrip) && mappingEnabled,
[$style.draggingHeader]: isDragging,
}"
>
<span>
<span>{{ column || '&nbsp;' }}</span>
<n8n-tooltip
v-if="mappingEnabled"
placement="bottom-start"
:manual="true"
:value="i === 0 && showHintWithDelay"
>
<div
v-if="focusedMappableInput"
slot="content"
v-html="
$locale.baseText(
focusedMappableInput
? 'dataMapping.tableHint'
: 'dataMapping.dragColumnToFieldHint',
{
interpolate: { name: focusedMappableInput },
},
)
$locale.baseText('dataMapping.tableHint', {
interpolate: { name: focusedMappableInput },
})
"
></div>
<span>{{ column || '&nbsp;' }}</span>
<div v-else slot="content">
<img src='/static/data-mapping-gif.gif'/>
{{ $locale.baseText('dataMapping.dragColumnToFieldHint') }}
</div>
<div :class="$style.dragButton">
<font-awesome-icon icon="grip-vertical" />
</div>
</n8n-tooltip>
<span v-else>{{ column || '&nbsp;' }}</span>
</span>
<div :class="$style.dragButton">
<font-awesome-icon icon="grip-vertical" />
</div>
</div>
</template>
</Draggable>
Expand Down
39 changes: 39 additions & 0 deletions packages/editor-ui/src/components/TitledList.vue
@@ -0,0 +1,39 @@
<template>
<div class="titled-list">
<p v-text="title" />
<ul>
<li v-for="item in items" class="titled-list-item" :key="item" v-text="item" />
</ul>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: "TitledList",
props: {
title: {
type: String,
},
items: {
type: Array,
default: () => [],
},
},
});
</script>
<style lang="scss" scoped>
.titled-list {
display: flex;
flex-direction: column;
.titled-list-item {
list-style: none;
padding-left: var(--spacing-3xs);
&::before {
content: "- ";
}
}
}
</style>
2 changes: 1 addition & 1 deletion packages/editor-ui/src/components/TriggerPanel.vue
Expand Up @@ -55,7 +55,7 @@
{{ header }}
</n8n-heading>
<n8n-text v-if="subheader">
<span v-html="subheader"></span>
<span v-text="subheader" />
</n8n-text>
</div>

Expand Down
14 changes: 7 additions & 7 deletions packages/editor-ui/src/components/WorkflowSettings.vue
Expand Up @@ -32,7 +32,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.timezone') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.timezone"></div>
<div slot="content" v-text="helpTexts.timezone"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -51,7 +51,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.saveDataErrorExecution') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveDataErrorExecution"></div>
<div slot="content" v-text="helpTexts.saveDataErrorExecution"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -70,7 +70,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.saveDataSuccessExecution') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveDataSuccessExecution"></div>
<div slot="content" v-text="helpTexts.saveDataSuccessExecution"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -89,7 +89,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.saveManualExecutions') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveManualExecutions"></div>
<div slot="content" v-text="helpTexts.saveManualExecutions"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -108,7 +108,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.saveExecutionProgress') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.saveExecutionProgress"></div>
<div slot="content" v-text="helpTexts.saveExecutionProgress"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -127,7 +127,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.timeoutWorkflow') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.executionTimeoutToggle"></div>
<div slot="content" v-text="helpTexts.executionTimeoutToggle"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand All @@ -142,7 +142,7 @@
<el-col :span="10" class="setting-name">
{{ $locale.baseText('workflowSettings.timeoutAfter') + ":" }}
<n8n-tooltip class="setting-info" placement="top" >
<div slot="content" v-html="helpTexts.executionTimeout"></div>
<div slot="content" v-text="helpTexts.executionTimeout"></div>
<font-awesome-icon icon="question-circle" />
</n8n-tooltip>
</el-col>
Expand Down
3 changes: 2 additions & 1 deletion packages/editor-ui/src/main.ts
Expand Up @@ -19,7 +19,7 @@ import router from './router';

import { runExternalHook } from './components/mixins/externalHooks';
import { TelemetryPlugin } from './plugins/telemetry';
import { I18nPlugin } from './plugins/i18n';
import { I18nPlugin, i18nInstance } from './plugins/i18n';

import { store } from './store';

Expand All @@ -32,6 +32,7 @@ Vue.use(TelemetryPlugin);
Vue.use((vue) => I18nPlugin(vue, store));

new Vue({
i18n: i18nInstance,
router,
store,
render: h => h(App),
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/plugins/i18n/index.ts
Expand Up @@ -355,7 +355,7 @@ export class I18nClass {
}
}

const i18nInstance = new VueI18n({
export const i18nInstance = new VueI18n({
locale: 'en',
fallbackLocale: 'en',
messages: { en: englishBaseText },
Expand Down

0 comments on commit 287533e

Please sign in to comment.