chore(editor): Suppress warnings from vue-i18n (#17325)

This commit is contained in:
Suguru Inoue
2025-07-16 15:18:16 +02:00
committed by GitHub
parent c4ba31ef62
commit f2581effa4
38 changed files with 200 additions and 137 deletions

View File

@@ -14,10 +14,11 @@ import {
export * from './types'; export * from './types';
export const i18nInstance = createI18n({ export const i18nInstance = createI18n({
legacy: false,
locale: 'en', locale: 'en',
fallbackLocale: 'en', fallbackLocale: 'en',
messages: { en: englishBaseText }, messages: { en: englishBaseText },
warnHtmlInMessage: 'off', warnHtmlMessage: false,
}); });
type BaseTextOptions = { type BaseTextOptions = {
@@ -45,7 +46,7 @@ export class I18nClass {
} }
get locale() { get locale() {
return i18nInstance.global.locale; return i18nInstance.global.locale.value;
} }
// ---------------------------------- // ----------------------------------
@@ -377,14 +378,14 @@ export class I18nClass {
const loadedLanguages = ['en']; const loadedLanguages = ['en'];
async function setLanguage(language: string) { async function setLanguage(language: string) {
i18nInstance.global.locale = language as 'en'; i18nInstance.global.locale.value = language as 'en';
document.querySelector('html')!.setAttribute('lang', language); document.querySelector('html')!.setAttribute('lang', language);
return language; return language;
} }
export async function loadLanguage(language: string) { export async function loadLanguage(language: string) {
if (i18nInstance.global.locale === language) { if (i18nInstance.global.locale.value === language) {
return await setLanguage(language); return await setLanguage(language);
} }

View File

@@ -5,6 +5,7 @@ import { ElSelect, ElOption, ElOptionGroup } from 'element-plus';
import { capitalCase } from 'change-case'; import { capitalCase } from 'change-case';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
// Define props // Define props
const props = defineProps({ const props = defineProps({
@@ -116,13 +117,13 @@ function goToUpgradeApiKeyScopes() {
</ElSelect> </ElSelect>
</N8nInputLabel> </N8nInputLabel>
<N8nNotice v-if="!enabled"> <N8nNotice v-if="!enabled">
<i18n-t keypath="settings.api.scopes.upgrade"> <I18nT keypath="settings.api.scopes.upgrade" scope="global">
<template #link> <template #link>
<n8n-link size="small" @click="goToUpgradeApiKeyScopes"> <n8n-link size="small" @click="goToUpgradeApiKeyScopes">
{{ i18n.baseText('settings.api.scopes.upgrade.link') }} {{ i18n.baseText('settings.api.scopes.upgrade.link') }}
</n8n-link> </n8n-link>
</template> </template>
</i18n-t> </I18nT>
</N8nNotice> </N8nNotice>
</div> </div>
</template> </template>

View File

@@ -9,6 +9,7 @@ import { useWorkflowsStore } from '@/stores/workflows.store';
import HtmlEditor from '@/components/HtmlEditor/HtmlEditor.vue'; import HtmlEditor from '@/components/HtmlEditor/HtmlEditor.vue';
import JsEditor from '@/components/JsEditor/JsEditor.vue'; import JsEditor from '@/components/JsEditor/JsEditor.vue';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { I18nT } from 'vue-i18n';
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -161,11 +162,11 @@ function closeDialog() {
<div class="mb-s"> <div class="mb-s">
<n8n-text> <n8n-text>
<i18n-t :keypath="`chatEmbed.paste.${currentTab}`"> <I18nT :keypath="`chatEmbed.paste.${currentTab}`" scope="global">
<template #code> <template #code>
<code>{{ i18n.baseText(`chatEmbed.paste.${currentTab}.file`) }}</code> <code>{{ i18n.baseText(`chatEmbed.paste.${currentTab}.file`) }}</code>
</template> </template>
</i18n-t> </I18nT>
</n8n-text> </n8n-text>
</div> </div>

View File

@@ -8,6 +8,7 @@ import type { BaseTextKey } from '@n8n/i18n';
import TestTableBase from '../shared/TestTableBase.vue'; import TestTableBase from '../shared/TestTableBase.vue';
import { statusDictionary } from '../shared/statusDictionary'; import { statusDictionary } from '../shared/statusDictionary';
import { getErrorBaseKey } from '@/components/Evaluations.ee/shared/errorCodes'; import { getErrorBaseKey } from '@/components/Evaluations.ee/shared/errorCodes';
import { I18nT } from 'vue-i18n';
const emit = defineEmits<{ const emit = defineEmits<{
rowClick: [run: TestRunRecord & { index: number }]; rowClick: [run: TestRunRecord & { index: number }];
}>(); }>();
@@ -88,7 +89,7 @@ const runSummaries = computed(() => {
<template v-else-if="row.status === 'error'"> <template v-else-if="row.status === 'error'">
<N8nTooltip placement="top" :show-after="300"> <N8nTooltip placement="top" :show-after="300">
<template #content> <template #content>
<i18n-t :keypath="`${getErrorBaseKey(row.errorCode)}`"> <I18nT :keypath="`${getErrorBaseKey(row.errorCode)}`" scope="global">
<template <template
v-if=" v-if="
locale.exists(`${getErrorBaseKey(row.errorCode)}.description` as BaseTextKey) locale.exists(`${getErrorBaseKey(row.errorCode)}.description` as BaseTextKey)
@@ -106,11 +107,11 @@ const runSummaries = computed(() => {
) )
}} }}
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<N8nText :class="[$style.alertText, $style.errorText]"> <N8nText :class="[$style.alertText, $style.errorText]">
<i18n-t :keypath="`${getErrorBaseKey(row.errorCode)}`"> <I18nT :keypath="`${getErrorBaseKey(row.errorCode)}`" scope="global">
<template <template
v-if=" v-if="
locale.exists(`${getErrorBaseKey(row.errorCode)}.description` as BaseTextKey) locale.exists(`${getErrorBaseKey(row.errorCode)}.description` as BaseTextKey)
@@ -125,7 +126,7 @@ const runSummaries = computed(() => {
}} }}
</p> </p>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</N8nTooltip> </N8nTooltip>
</template> </template>

View File

@@ -9,6 +9,7 @@ import StepHeader from '../shared/StepHeader.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useUsageStore } from '@/stores/usage.store'; import { useUsageStore } from '@/stores/usage.store';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
defineEmits<{ defineEmits<{
runTest: []; runTest: [];
@@ -209,13 +210,13 @@ function onSeePlans() {
:class="$style.quotaNote" :class="$style.quotaNote"
> >
<N8nText size="xsmall" color="text-base"> <N8nText size="xsmall" color="text-base">
<i18n-t keypath="evaluations.setupWizard.step3.notice"> <I18nT keypath="evaluations.setupWizard.step3.notice" scope="global">
<template #link> <template #link>
<a style="text-decoration: underline; color: inherit" @click="onSeePlans" <a style="text-decoration: underline; color: inherit" @click="onSeePlans"
>{{ locale.baseText('evaluations.setupWizard.step3.notice.link') }} >{{ locale.baseText('evaluations.setupWizard.step3.notice.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</div> </div>
</div> </div>

View File

@@ -18,6 +18,7 @@ import type { IParameterLabel } from 'n8n-workflow';
import ExternalSecretsProviderImage from '@/components/ExternalSecretsProviderImage.ee.vue'; import ExternalSecretsProviderImage from '@/components/ExternalSecretsProviderImage.ee.vue';
import ExternalSecretsProviderConnectionSwitch from '@/components/ExternalSecretsProviderConnectionSwitch.ee.vue'; import ExternalSecretsProviderConnectionSwitch from '@/components/ExternalSecretsProviderConnectionSwitch.ee.vue';
import { createEventBus } from '@n8n/utils/event-bus'; import { createEventBus } from '@n8n/utils/event-bus';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
data: { eventBus: EventBus; name: string }; data: { eventBus: EventBus; name: string };
@@ -226,13 +227,14 @@ async function onConnectionStateChange() {
}} }}
<span v-if="provider.connected"> <span v-if="provider.connected">
<br /> <br />
<i18n-t <I18nT
keypath="settings.externalSecrets.provider.testConnection.success.connected.usage" keypath="settings.externalSecrets.provider.testConnection.success.connected.usage"
scope="global"
> >
<template #code> <template #code>
<code>{{ `\{\{ \$secrets\.${provider.name}\.secret_name \}\}` }}</code> <code>{{ `\{\{ \$secrets\.${provider.name}\.secret_name \}\}` }}</code>
</template> </template>
</i18n-t> </I18nT>
<n8n-link :href="i18n.baseText('settings.externalSecrets.docs.use')" size="small"> <n8n-link :href="i18n.baseText('settings.externalSecrets.docs.use')" size="small">
{{ {{
i18n.baseText( i18n.baseText(

View File

@@ -22,6 +22,7 @@ import { getResourcePermissions } from '@n8n/permissions';
import MoveToFolderDropdown from './MoveToFolderDropdown.vue'; import MoveToFolderDropdown from './MoveToFolderDropdown.vue';
import { ResourceType, getTruncatedProjectName } from '@/utils/projects.utils'; import { ResourceType, getTruncatedProjectName } from '@/utils/projects.utils';
import { useWorkflowsStore } from '@/stores/workflows.store'; import { useWorkflowsStore } from '@/stores/workflows.store';
import { I18nT } from 'vue-i18n';
/** /**
* This modal is used to move a resource (folder or workflow) to a different folder. * This modal is used to move a resource (folder or workflow) to a different folder.
@@ -364,14 +365,14 @@ onMounted(async () => {
<div v-if="isTransferringOwnership" :class="$style.block"> <div v-if="isTransferringOwnership" :class="$style.block">
<N8nText> <N8nText>
<i18n-t keypath="projects.move.resource.modal.message.sharingNote"> <I18nT keypath="projects.move.resource.modal.message.sharingNote" scope="global">
<template #note <template #note
><strong>{{ ><strong>{{
i18n.baseText('projects.move.resource.modal.message.note') i18n.baseText('projects.move.resource.modal.message.note')
}}</strong></template }}</strong></template
> >
<template #resourceTypeLabel>{{ resourceTypeLabel }}</template> <template #resourceTypeLabel>{{ resourceTypeLabel }}</template>
</i18n-t> </I18nT>
<span <span
v-if="props.data.resource.sharedWithProjects?.length ?? 0 > 0" v-if="props.data.resource.sharedWithProjects?.length ?? 0 > 0"
:class="$style.textBlock" :class="$style.textBlock"
@@ -411,12 +412,13 @@ onMounted(async () => {
:class="$style.textBlock" :class="$style.textBlock"
data-test-id="move-modal-share-credentials-checkbox" data-test-id="move-modal-share-credentials-checkbox"
> >
<i18n-t <I18nT
:keypath=" :keypath="
data.resourceType === 'workflow' data.resourceType === 'workflow'
? 'folders.move.modal.message.usedCredentials.workflow' ? 'folders.move.modal.message.usedCredentials.workflow'
: 'folders.move.modal.message.usedCredentials.folder' : 'folders.move.modal.message.usedCredentials.folder'
" "
scope="global"
> >
<template #usedCredentials> <template #usedCredentials>
<N8nTooltip placement="top"> <N8nTooltip placement="top">
@@ -436,7 +438,7 @@ onMounted(async () => {
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>
</i18n-t> </I18nT>
</N8nCheckbox> </N8nCheckbox>
<N8nCallout <N8nCallout
v-if="shareableCredentials.length && !shareUsedCredentials" v-if="shareableCredentials.length && !shareUsedCredentials"
@@ -447,7 +449,10 @@ onMounted(async () => {
{{ i18n.baseText('folders.move.modal.message.usedCredentials.warning') }} {{ i18n.baseText('folders.move.modal.message.usedCredentials.warning') }}
</N8nCallout> </N8nCallout>
<span v-if="unShareableCredentials.length" :class="$style.textBlock"> <span v-if="unShareableCredentials.length" :class="$style.textBlock">
<i18n-t keypath="projects.move.resource.modal.message.unAccessibleCredentials.note"> <I18nT
keypath="projects.move.resource.modal.message.unAccessibleCredentials.note"
scope="global"
>
<template #credentials> <template #credentials>
<N8nTooltip placement="top"> <N8nTooltip placement="top">
<span :class="$style.tooltipText">{{ <span :class="$style.tooltipText">{{
@@ -461,7 +466,7 @@ onMounted(async () => {
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>
</i18n-t> </I18nT>
</span> </span>
</template> </template>
<template #footer="{ close }"> <template #footer="{ close }">

View File

@@ -29,6 +29,7 @@ import RunData from './RunData.vue';
import WireMeUp from './WireMeUp.vue'; import WireMeUp from './WireMeUp.vue';
import { usePostHog } from '@/stores/posthog.store'; import { usePostHog } from '@/stores/posthog.store';
import { type IRunDataDisplayMode } from '@/Interface'; import { type IRunDataDisplayMode } from '@/Interface';
import { I18nT } from 'vue-i18n';
type MappingMode = 'debugging' | 'mapping'; type MappingMode = 'debugging' | 'mapping';
@@ -463,7 +464,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
<N8nIcon icon="arrow-right-to-line" size="xlarge" /> <N8nIcon icon="arrow-right-to-line" size="xlarge" />
</template> </template>
<template #description> <template #description>
<i18n-t tag="span" keypath="ndv.input.noOutputData.v2.description"> <I18nT tag="span" keypath="ndv.input.noOutputData.v2.description" scope="global">
<template #link> <template #link>
<NodeExecuteButton <NodeExecuteButton
hide-icon hide-icon
@@ -479,7 +480,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
/> />
<br /> <br />
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</NDVEmptyState> </NDVEmptyState>
<NDVEmptyState v-else :title="i18n.baseText('ndv.input.rootNodeHasNotRun.title')"> <NDVEmptyState v-else :title="i18n.baseText('ndv.input.rootNodeHasNotRun.title')">
@@ -493,7 +494,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
</template> </template>
<template #description> <template #description>
<i18n-t tag="span" keypath="ndv.input.rootNodeHasNotRun.description"> <I18nT tag="span" keypath="ndv.input.rootNodeHasNotRun.description" scope="global">
<template #link> <template #link>
<a <a
href="#" href="#"
@@ -503,7 +504,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
{{ i18n.baseText('ndv.input.rootNodeHasNotRun.description.link') }} {{ i18n.baseText('ndv.input.rootNodeHasNotRun.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</NDVEmptyState> </NDVEmptyState>
</template> </template>
@@ -519,7 +520,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
i18n.baseText('ndv.input.rootNodeHasNotRun.title') i18n.baseText('ndv.input.rootNodeHasNotRun.title')
}}</N8nText> }}</N8nText>
<N8nText tag="div" color="text-dark" size="medium"> <N8nText tag="div" color="text-dark" size="medium">
<i18n-t tag="span" keypath="ndv.input.rootNodeHasNotRun.description"> <I18nT tag="span" keypath="ndv.input.rootNodeHasNotRun.description" scope="global">
<template #link> <template #link>
<a <a
href="#" href="#"
@@ -528,7 +529,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
>{{ i18n.baseText('ndv.input.rootNodeHasNotRun.description.link') }}</a >{{ i18n.baseText('ndv.input.rootNodeHasNotRun.description.link') }}</a
> >
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</template> </template>
<N8nTooltip v-if="!readOnly" :visible="showDraggableHint && showDraggableHintWithDelay"> <N8nTooltip v-if="!readOnly" :visible="showDraggableHint && showDraggableHintWithDelay">
@@ -554,7 +555,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
/> />
</N8nTooltip> </N8nTooltip>
<N8nText v-if="!readOnly" tag="div" size="small"> <N8nText v-if="!readOnly" tag="div" size="small">
<i18n-t keypath="ndv.input.noOutputData.hint"> <I18nT keypath="ndv.input.noOutputData.hint" scope="global">
<template #info> <template #info>
<N8nTooltip placement="bottom"> <N8nTooltip placement="bottom">
<template #content> <template #content>
@@ -563,7 +564,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
<N8nIcon icon="circle-help" /> <N8nIcon icon="circle-help" />
</N8nTooltip> </N8nTooltip>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</template> </template>
</div> </div>
@@ -573,7 +574,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
<WireMeUp /> <WireMeUp />
</template> </template>
<template #description> <template #description>
<i18n-t tag="span" keypath="ndv.input.notConnected.v2.description"> <I18nT tag="span" keypath="ndv.input.notConnected.v2.description" scope="global">
<template #link> <template #link>
<a <a
href="https://docs.n8n.io/workflows/connections/" href="https://docs.n8n.io/workflows/connections/"
@@ -583,7 +584,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
{{ i18n.baseText('ndv.input.notConnected.learnMore') }} {{ i18n.baseText('ndv.input.notConnected.learnMore') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</NDVEmptyState> </NDVEmptyState>

View File

@@ -18,6 +18,7 @@ import { createEventBus } from '@n8n/utils/event-bus';
import { useClipboard } from '@/composables/useClipboard'; import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
modalName: string; modalName: string;
@@ -304,13 +305,13 @@ function getEmail(email: string): string {
> >
<template #content> <template #content>
<n8n-notice v-if="!isAdvancedPermissionsEnabled"> <n8n-notice v-if="!isAdvancedPermissionsEnabled">
<i18n-t keypath="settings.users.advancedPermissions.warning"> <I18nT keypath="settings.users.advancedPermissions.warning" scope="global">
<template #link> <template #link>
<n8n-link size="small" @click="goToUpgradeAdvancedPermissions"> <n8n-link size="small" @click="goToUpgradeAdvancedPermissions">
{{ i18n.baseText('settings.users.advancedPermissions.warning.link') }} {{ i18n.baseText('settings.users.advancedPermissions.warning.link') }}
</n8n-link> </n8n-link>
</template> </template>
</i18n-t> </I18nT>
</n8n-notice> </n8n-notice>
<div v-if="showInviteUrls"> <div v-if="showInviteUrls">
<n8n-users-list :users="invitedUsers"> <n8n-users-list :users="invitedUsers">

View File

@@ -61,6 +61,7 @@ import { type BaseTextKey, useI18n } from '@n8n/i18n';
import { ProjectTypes } from '@/types/projects.types'; import { ProjectTypes } from '@/types/projects.types';
import { useWorkflowSaving } from '@/composables/useWorkflowSaving'; import { useWorkflowSaving } from '@/composables/useWorkflowSaving';
import { sanitizeFilename } from '@/utils/fileUtils'; import { sanitizeFilename } from '@/utils/fileUtils';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
readOnly?: boolean; readOnly?: boolean;
@@ -798,12 +799,13 @@ const onBreadcrumbsItemSelected = (item: PathItem) => {
{{ i18n.baseText('workflowDetails.share') }} {{ i18n.baseText('workflowDetails.share') }}
</N8nButton> </N8nButton>
<template #content> <template #content>
<i18n-t <I18nT
:keypath=" :keypath="
uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description
.tooltip .tooltip
" "
tag="span" tag="span"
scope="global"
> >
<template #action> <template #action>
<a @click="goToUpgrade"> <a @click="goToUpgrade">
@@ -815,7 +817,7 @@ const onBreadcrumbsItemSelected = (item: PathItem) => {
}} }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>

View File

@@ -2,6 +2,7 @@
import { computed } from 'vue'; import { computed } from 'vue';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { I18nT } from 'vue-i18n';
const locale = useI18n(); const locale = useI18n();
@@ -42,13 +43,13 @@ const workflowHistoryRoute = computed<{ name: string; params: { workflowId: stri
<span v-else-if="isFeatureEnabled">{{ <span v-else-if="isFeatureEnabled">{{
locale.baseText('workflowHistory.button.tooltip.enabled') locale.baseText('workflowHistory.button.tooltip.enabled')
}}</span> }}</span>
<i18n-t v-else keypath="workflowHistory.button.tooltip.disabled"> <I18nT v-else keypath="workflowHistory.button.tooltip.disabled" scope="global">
<template #link> <template #link>
<N8nLink size="small" @click="emit('upgrade')"> <N8nLink size="small" @click="emit('upgrade')">
{{ locale.baseText('workflowHistory.button.tooltip.disabled.link') }} {{ locale.baseText('workflowHistory.button.tooltip.disabled.link') }}
</N8nLink> </N8nLink>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>

View File

@@ -28,6 +28,7 @@ import { useBecomeTemplateCreatorStore } from '@/components/BecomeTemplateCreato
import Logo from '@/components/Logo/Logo.vue'; import Logo from '@/components/Logo/Logo.vue';
import VersionUpdateCTA from '@/components/VersionUpdateCTA.vue'; import VersionUpdateCTA from '@/components/VersionUpdateCTA.vue';
import { TemplateClickSource, trackTemplatesClick } from '@/utils/experiments'; import { TemplateClickSource, trackTemplatesClick } from '@/utils/experiments';
import { I18nT } from 'vue-i18n';
const becomeTemplateCreatorStore = useBecomeTemplateCreatorStore(); const becomeTemplateCreatorStore = useBecomeTemplateCreatorStore();
const cloudPlanStore = useCloudPlanStore(); const cloudPlanStore = useCloudPlanStore();
@@ -390,7 +391,7 @@ onClickOutside(createBtn as Ref<VueInstance>, () => {
placement="bottom" placement="bottom"
> >
<template #content> <template #content>
<i18n-t keypath="readOnlyEnv.tooltip"> <I18nT keypath="readOnlyEnv.tooltip" scope="global">
<template #link> <template #link>
<N8nLink <N8nLink
to="https://docs.n8n.io/source-control-environments/setup/#step-4-connect-n8n-and-configure-your-instance" to="https://docs.n8n.io/source-control-environments/setup/#step-4-connect-n8n-and-configure-your-instance"
@@ -399,7 +400,7 @@ onClickOutside(createBtn as Ref<VueInstance>, () => {
{{ i18n.baseText('readOnlyEnv.tooltip.link') }} {{ i18n.baseText('readOnlyEnv.tooltip.link') }}
</N8nLink> </N8nLink>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<N8nIcon <N8nIcon
data-test-id="read-only-env-icon" data-test-id="read-only-env-icon"

View File

@@ -16,6 +16,7 @@ import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { useSettingsStore } from '@/stores/settings.store'; import { useSettingsStore } from '@/stores/settings.store';
import router from '@/router'; import router from '@/router';
import { I18nT } from 'vue-i18n';
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// #region Reactive properties // #region Reactive properties
@@ -178,7 +179,7 @@ onMounted(async () => {
</div> </div>
<div> <div>
<n8n-text size="medium" :bold="false"> <n8n-text size="medium" :bold="false">
<i18n-t keypath="mfa.setup.step1.instruction1.subtitle" tag="span"> <I18nT keypath="mfa.setup.step1.instruction1.subtitle" tag="span" scope="global">
<template #part1> <template #part1>
{{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part1') }} {{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part1') }}
</template> </template>
@@ -190,7 +191,7 @@ onMounted(async () => {
>{{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part2') }}</a >{{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part2') }}</a
> >
</template> </template>
</i18n-t> </I18nT>
</n8n-text> </n8n-text>
</div> </div>
<div :class="$style.qrContainer"> <div :class="$style.qrContainer">
@@ -235,7 +236,7 @@ onMounted(async () => {
</div> </div>
</div> </div>
<n8n-info-tip :bold="false" :class="$style['edit-mode-footer-infotip']"> <n8n-info-tip :bold="false" :class="$style['edit-mode-footer-infotip']">
<i18n-t keypath="mfa.setup.step2.infobox.description" tag="span"> <I18nT keypath="mfa.setup.step2.infobox.description" tag="span" scope="global">
<template #part1> <template #part1>
{{ i18n.baseText('mfa.setup.step2.infobox.description.part1') }} {{ i18n.baseText('mfa.setup.step2.infobox.description.part1') }}
</template> </template>
@@ -244,7 +245,7 @@ onMounted(async () => {
{{ i18n.baseText('mfa.setup.step2.infobox.description.part2') }} {{ i18n.baseText('mfa.setup.step2.infobox.description.part2') }}
</n8n-text> </n8n-text>
</template> </template>
</i18n-t> </I18nT>
</n8n-info-tip> </n8n-info-tip>
<div> <div>
<n8n-button <n8n-button

View File

@@ -51,6 +51,7 @@ import { usePostHog } from '@/stores/posthog.store';
import { shouldShowParameter } from './canvas/experimental/experimentalNdv.utils'; import { shouldShowParameter } from './canvas/experimental/experimentalNdv.utils';
import { useResizeObserver } from '@vueuse/core'; import { useResizeObserver } from '@vueuse/core';
import { useNodeSettingsParameters } from '@/composables/useNodeSettingsParameters'; import { useNodeSettingsParameters } from '@/composables/useNodeSettingsParameters';
import { I18nT } from 'vue-i18n';
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
@@ -876,9 +877,10 @@ function handleWheelEvent(event: WheelEvent) {
</div> </div>
<div v-if="isCommunityNode" :class="$style.descriptionContainer"> <div v-if="isCommunityNode" :class="$style.descriptionContainer">
<div class="mb-l"> <div class="mb-l">
<i18n-t <I18nT
keypath="nodeSettings.communityNodeUnknown.description" keypath="nodeSettings.communityNodeUnknown.description"
tag="span" tag="span"
scope="global"
@click="onMissingNodeTextClick" @click="onMissingNodeTextClick"
> >
<template #action> <template #action>
@@ -888,7 +890,7 @@ function handleWheelEvent(event: WheelEvent) {
>{{ node.type.split('.')[0] }}</a >{{ node.type.split('.')[0] }}</a
> >
</template> </template>
</i18n-t> </I18nT>
</div> </div>
<n8n-link <n8n-link
:to="COMMUNITY_NODES_INSTALLATION_DOCS_URL" :to="COMMUNITY_NODES_INSTALLATION_DOCS_URL"
@@ -897,7 +899,7 @@ function handleWheelEvent(event: WheelEvent) {
{{ i18n.baseText('nodeSettings.communityNodeUnknown.installLink.text') }} {{ i18n.baseText('nodeSettings.communityNodeUnknown.installLink.text') }}
</n8n-link> </n8n-link>
</div> </div>
<i18n-t v-else keypath="nodeSettings.nodeTypeUnknown.description" tag="span"> <I18nT v-else keypath="nodeSettings.nodeTypeUnknown.description" tag="span" scope="global">
<template #action> <template #action>
<a <a
:href="CUSTOM_NODES_DOCS_URL" :href="CUSTOM_NODES_DOCS_URL"
@@ -905,7 +907,7 @@ function handleWheelEvent(event: WheelEvent) {
v-text="i18n.baseText('nodeSettings.nodeTypeUnknown.description.customNode')" v-text="i18n.baseText('nodeSettings.nodeTypeUnknown.description.customNode')"
/> />
</template> </template>
</i18n-t> </I18nT>
</div> </div>
<div <div
v-if="node && nodeValid" v-if="node && nodeValid"

View File

@@ -25,6 +25,7 @@ import { CanvasNodeDirtiness } from '@/types';
import { NDV_UI_OVERHAUL_EXPERIMENT } from '@/constants'; import { NDV_UI_OVERHAUL_EXPERIMENT } from '@/constants';
import { usePostHog } from '@/stores/posthog.store'; import { usePostHog } from '@/stores/posthog.store';
import { type IRunDataDisplayMode } from '@/Interface'; import { type IRunDataDisplayMode } from '@/Interface';
import { I18nT } from 'vue-i18n';
// Types // Types
@@ -412,13 +413,14 @@ function handleChangeCollapsingColumn(columnName: string | null) {
<N8nIcon icon="arrow-right-from-line" size="xlarge" /> <N8nIcon icon="arrow-right-from-line" size="xlarge" />
</template> </template>
<template #description> <template #description>
<i18n-t <I18nT
tag="span" tag="span"
:keypath=" :keypath="
isSubNodeType isSubNodeType
? 'ndv.output.runNodeHintSubNode' ? 'ndv.output.runNodeHintSubNode'
: 'ndv.output.noOutputData.v2.description' : 'ndv.output.noOutputData.v2.description'
" "
scope="global"
> >
<template #link> <template #link>
<NodeExecuteButton <NodeExecuteButton
@@ -438,7 +440,7 @@ function handleChangeCollapsingColumn(columnName: string | null) {
/> />
<br /> <br />
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</NDVEmptyState> </NDVEmptyState>
</template> </template>

View File

@@ -23,6 +23,7 @@ import type { EventBus } from '@n8n/utils/event-bus';
import { sortByProperty } from '@n8n/utils/sort/sortByProperty'; import { sortByProperty } from '@n8n/utils/sort/sortByProperty';
import { truncate } from '@n8n/utils/string/truncate'; import { truncate } from '@n8n/utils/string/truncate';
import { computed, h, onMounted, ref } from 'vue'; import { computed, h, onMounted, ref } from 'vue';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
modalName: string; modalName: string;
@@ -201,25 +202,25 @@ onMounted(async () => {
}} }}
</N8nHeading> </N8nHeading>
<N8nText> <N8nText>
<i18n-t keypath="projects.move.resource.modal.message"> <I18nT keypath="projects.move.resource.modal.message" scope="global">
<template #resourceName <template #resourceName
><strong>{{ resourceName }}</strong></template ><strong>{{ resourceName }}</strong></template
> >
<template v-if="isResourceInTeamProject" #inTeamProject> <template v-if="isResourceInTeamProject" #inTeamProject>
<i18n-t keypath="projects.move.resource.modal.message.team"> <I18nT keypath="projects.move.resource.modal.message.team" scope="global">
<template #resourceHomeProjectName <template #resourceHomeProjectName
><strong>{{ homeProjectName }}</strong></template ><strong>{{ homeProjectName }}</strong></template
> >
</i18n-t> </I18nT>
</template> </template>
<template v-else #inPersonalProject> <template v-else #inPersonalProject>
<i18n-t keypath="projects.move.resource.modal.message.personal"> <I18nT keypath="projects.move.resource.modal.message.personal" scope="global">
<template #resourceHomeProjectName <template #resourceHomeProjectName
><strong>{{ homeProjectName }}</strong></template ><strong>{{ homeProjectName }}</strong></template
> >
</i18n-t> </I18nT>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</template> </template>
<template #content> <template #content>
@@ -244,14 +245,14 @@ onMounted(async () => {
></N8nOption> ></N8nOption>
</N8nSelect> </N8nSelect>
<N8nText> <N8nText>
<i18n-t keypath="projects.move.resource.modal.message.sharingNote"> <I18nT keypath="projects.move.resource.modal.message.sharingNote" scope="global">
<template #note <template #note
><strong>{{ ><strong>{{
i18n.baseText('projects.move.resource.modal.message.note') i18n.baseText('projects.move.resource.modal.message.note')
}}</strong></template }}</strong></template
> >
<template #resourceTypeLabel>{{ props.data.resourceTypeLabel }}</template> <template #resourceTypeLabel>{{ props.data.resourceTypeLabel }}</template>
</i18n-t> </I18nT>
<span <span
v-if="props.data.resource.sharedWithProjects?.length ?? 0 > 0" v-if="props.data.resource.sharedWithProjects?.length ?? 0 > 0"
:class="$style.textBlock" :class="$style.textBlock"
@@ -271,7 +272,7 @@ onMounted(async () => {
:class="$style.textBlock" :class="$style.textBlock"
data-test-id="project-move-resource-modal-checkbox-all" data-test-id="project-move-resource-modal-checkbox-all"
> >
<i18n-t keypath="projects.move.resource.modal.message.usedCredentials"> <I18nT keypath="projects.move.resource.modal.message.usedCredentials" scope="global">
<template #usedCredentials> <template #usedCredentials>
<N8nTooltip placement="top"> <N8nTooltip placement="top">
<span :class="$style.tooltipText"> <span :class="$style.tooltipText">
@@ -290,10 +291,13 @@ onMounted(async () => {
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>
</i18n-t> </I18nT>
</N8nCheckbox> </N8nCheckbox>
<span v-if="unShareableCredentials.length" :class="$style.textBlock"> <span v-if="unShareableCredentials.length" :class="$style.textBlock">
<i18n-t keypath="projects.move.resource.modal.message.unAccessibleCredentials.note"> <I18nT
keypath="projects.move.resource.modal.message.unAccessibleCredentials.note"
scope="global"
>
<template #credentials> <template #credentials>
<N8nTooltip placement="top"> <N8nTooltip placement="top">
<span :class="$style.tooltipText">{{ <span :class="$style.tooltipText">{{
@@ -307,7 +311,7 @@ onMounted(async () => {
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>
</i18n-t> </I18nT>
</span> </span>
</N8nText> </N8nText>
</div> </div>

View File

@@ -1,6 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
type Props = { type Props = {
limit: number; limit: number;
@@ -24,7 +25,7 @@ const goToUpgrade = async () => {
width="500" width="500"
> >
<div class="pt-l"> <div class="pt-l">
<i18n-t keypath="projects.settings.role.upgrade.message"> <I18nT keypath="projects.settings.role.upgrade.message" scope="global">
<template #planName>{{ props.planName }}</template> <template #planName>{{ props.planName }}</template>
<template #limit> <template #limit>
{{ {{
@@ -34,7 +35,7 @@ const goToUpgrade = async () => {
}) })
}} }}
</template> </template>
</i18n-t> </I18nT>
</div> </div>
<template #footer> <template #footer>
<N8nButton type="secondary" native-type="button" @click="visible = false">{{ <N8nButton type="secondary" native-type="button" @click="visible = false">{{

View File

@@ -97,6 +97,7 @@ import RunDataDisplayModeSelect from '@/components/RunDataDisplayModeSelect.vue'
import RunDataPaginationBar from '@/components/RunDataPaginationBar.vue'; import RunDataPaginationBar from '@/components/RunDataPaginationBar.vue';
import { parseAiContent } from '@/utils/aiUtils'; import { parseAiContent } from '@/utils/aiUtils';
import { usePostHog } from '@/stores/posthog.store'; import { usePostHog } from '@/stores/posthog.store';
import { I18nT } from 'vue-i18n';
const LazyRunDataTable = defineAsyncComponent( const LazyRunDataTable = defineAsyncComponent(
async () => await import('@/components/RunDataTable.vue'), async () => await import('@/components/RunDataTable.vue'),
@@ -1758,13 +1759,13 @@ defineExpose({ enterEditMode });
<div v-if="search"> <div v-if="search">
<N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText> <N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText>
<N8nText> <N8nText>
<i18n-t keypath="ndv.search.noMatch.description" tag="span"> <I18nT keypath="ndv.search.noMatch.description" tag="span" scope="global">
<template #link> <template #link>
<a href="#" @click="onSearchClear"> <a href="#" @click="onSearchClear">
{{ i18n.baseText('ndv.search.noMatch.description.link') }} {{ i18n.baseText('ndv.search.noMatch.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</div> </div>
<N8nText v-else> <N8nText v-else>
@@ -1832,13 +1833,13 @@ defineExpose({ enterEditMode });
<div v-else-if="showIoSearchNoMatchContent" :class="$style.center"> <div v-else-if="showIoSearchNoMatchContent" :class="$style.center">
<N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText> <N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText>
<N8nText> <N8nText>
<i18n-t keypath="ndv.search.noMatch.description" tag="span"> <I18nT keypath="ndv.search.noMatch.description" tag="span" scope="global">
<template #link> <template #link>
<a href="#" @click="onSearchClear"> <a href="#" @click="onSearchClear">
{{ i18n.baseText('ndv.search.noMatch.description.link') }} {{ i18n.baseText('ndv.search.noMatch.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</div> </div>

View File

@@ -16,6 +16,7 @@ import { useTelemetry } from '@/composables/useTelemetry';
import { N8nIconButton, N8nInfoTip, N8nTooltip, N8nTree } from '@n8n/design-system'; import { N8nIconButton, N8nInfoTip, N8nTooltip, N8nTree } from '@n8n/design-system';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { useExecutionHelpers } from '@/composables/useExecutionHelpers'; import { useExecutionHelpers } from '@/composables/useExecutionHelpers';
import { I18nT } from 'vue-i18n';
const MAX_COLUMNS_LIMIT = 40; const MAX_COLUMNS_LIMIT = 40;
@@ -628,14 +629,18 @@ watch(
<N8nTooltip placement="bottom-end"> <N8nTooltip placement="bottom-end">
<template #content> <template #content>
<div> <div>
<i18n-t tag="span" keypath="dataMapping.tableView.tableColumnsExceeded.tooltip"> <I18nT
tag="span"
keypath="dataMapping.tableView.tableColumnsExceeded.tooltip"
scope="global"
>
<template #columnLimit>{{ columnLimit }}</template> <template #columnLimit>{{ columnLimit }}</template>
<template #link> <template #link>
<a @click="switchToJsonView">{{ <a @click="switchToJsonView">{{
i18n.baseText('dataMapping.tableView.tableColumnsExceeded.tooltip.link') i18n.baseText('dataMapping.tableView.tableColumnsExceeded.tooltip.link')
}}</a> }}</a>
</template> </template>
</i18n-t> </I18nT>
</div> </div>
</template> </template>
<span> <span>

View File

@@ -2,16 +2,17 @@
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { RouterLink } from 'vue-router'; import { RouterLink } from 'vue-router';
import { VIEWS } from '@/constants'; import { VIEWS } from '@/constants';
import { I18nT } from 'vue-i18n';
const i18n = useI18n(); const i18n = useI18n();
</script> </script>
<template> <template>
<i18n-t keypath="settings.sourceControl.connection.error.message" tag="div"> <I18nT keypath="settings.sourceControl.connection.error.message" tag="div" scope="global">
<template #link> <template #link>
<RouterLink :to="{ name: VIEWS.SOURCE_CONTROL }"> <RouterLink :to="{ name: VIEWS.SOURCE_CONTROL }">
{{ i18n.baseText('settings.sourceControl.connection.error.link') }} {{ i18n.baseText('settings.sourceControl.connection.error.link') }}
</RouterLink> </RouterLink>
</template> </template>
</i18n-t> </I18nT>
</template> </template>

View File

@@ -45,6 +45,7 @@ import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
import pick from 'lodash/pick'; import pick from 'lodash/pick';
import { DateTime } from 'luxon'; import { DateTime } from 'luxon';
import NodeExecuteButton from './NodeExecuteButton.vue'; import NodeExecuteButton from './NodeExecuteButton.vue';
import { I18nT } from 'vue-i18n';
type Props = { type Props = {
nodes?: IConnectedNode[]; nodes?: IConnectedNode[];
@@ -417,13 +418,13 @@ const onDragEnd = (el: HTMLElement) => {
<div v-if="noSearchResults" class="no-results"> <div v-if="noSearchResults" class="no-results">
<N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noNodeMatch.title') }}</N8nText> <N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noNodeMatch.title') }}</N8nText>
<N8nText> <N8nText>
<i18n-t keypath="ndv.search.noMatchSchema.description" tag="span"> <I18nT keypath="ndv.search.noMatchSchema.description" tag="span" scope="global">
<template #link> <template #link>
<a href="#" @click="emit('clear:search')"> <a href="#" @click="emit('clear:search')">
{{ i18n.baseText('ndv.search.noMatchSchema.description.link') }} {{ i18n.baseText('ndv.search.noMatchSchema.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</N8nText> </N8nText>
</div> </div>
@@ -488,10 +489,11 @@ const onDragEnd = (el: HTMLElement) => {
:style="{ '--schema-level': item.level }" :style="{ '--schema-level': item.level }"
> >
<N8nText tag="div" size="small"> <N8nText tag="div" size="small">
<i18n-t <I18nT
v-if="item.key === 'executeSchema'" v-if="item.key === 'executeSchema'"
tag="span" tag="span"
keypath="dataMapping.schemaView.executeSchema" keypath="dataMapping.schemaView.executeSchema"
scope="global"
> >
<template #link> <template #link>
<NodeExecuteButton <NodeExecuteButton
@@ -505,8 +507,13 @@ const onDragEnd = (el: HTMLElement) => {
:class="$style.executeButton" :class="$style.executeButton"
/> />
</template> </template>
</i18n-t> </I18nT>
<i18n-t v-else tag="span" :keypath="`dataMapping.schemaView.${item.key}`" /> <I18nT
v-else
tag="span"
:keypath="`dataMapping.schemaView.${item.key}`"
scope="global"
/>
</N8nText> </N8nText>
</div> </div>
</DynamicScrollerItem> </DynamicScrollerItem>

View File

@@ -54,13 +54,13 @@ const emit = defineEmits<{
data-test-id="schema-preview-warning" data-test-id="schema-preview-warning"
@click.stop @click.stop
> >
<i18n-t keypath="dataMapping.schemaView.preview"> <I18nT keypath="dataMapping.schemaView.preview" scope="global">
<template #link> <template #link>
<N8nLink :to="SCHEMA_PREVIEW_DOCS_URL" size="small" bold> <N8nLink :to="SCHEMA_PREVIEW_DOCS_URL" size="small" bold>
{{ i18n.baseText('generic.learnMore') }} {{ i18n.baseText('generic.learnMore') }}
</N8nLink> </N8nLink>
</template> </template>
</i18n-t> </I18nT>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -10,6 +10,7 @@ import type {
} from '@n8n/rest-api-client/api/workflowHistory'; } from '@n8n/rest-api-client/api/workflowHistory';
import WorkflowHistoryListItem from '@/components/WorkflowHistory/WorkflowHistoryListItem.vue'; import WorkflowHistoryListItem from '@/components/WorkflowHistory/WorkflowHistoryListItem.vue';
import type { IUser } from 'n8n-workflow'; import type { IUser } from 'n8n-workflow';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
items: WorkflowHistory[]; items: WorkflowHistory[];
@@ -142,13 +143,13 @@ const onItemMounted = ({
}) })
}} }}
</span> </span>
<i18n-t keypath="workflowHistory.upgrade" tag="span"> <I18nT keypath="workflowHistory.upgrade" tag="span" scope="global">
<template #link> <template #link>
<a href="#" @click="emit('upgrade')"> <a href="#" @click="emit('upgrade')">
{{ i18n.baseText('workflowHistory.upgrade.link') }} {{ i18n.baseText('workflowHistory.upgrade.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</li> </li>
</ul> </ul>
</template> </template>

View File

@@ -3,6 +3,7 @@ import { useI18n } from '@n8n/i18n';
import Modal from '@/components/Modal.vue'; import Modal from '@/components/Modal.vue';
import { useUIStore } from '@/stores/ui.store'; import { useUIStore } from '@/stores/ui.store';
import type { ButtonType } from '@n8n/design-system'; import type { ButtonType } from '@n8n/design-system';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
modalName: string; modalName: string;
@@ -36,24 +37,25 @@ const closeModal = () => {
<template #content> <template #content>
<div> <div>
<n8n-text> <n8n-text>
<i18n-t keypath="workflowHistory.action.restore.modal.subtitle" tag="span"> <I18nT keypath="workflowHistory.action.restore.modal.subtitle" tag="span" scope="global">
<template #date> <template #date>
<strong>{{ props.data.formattedCreatedAt }}</strong> <strong>{{ props.data.formattedCreatedAt }}</strong>
</template> </template>
</i18n-t> </I18nT>
<br /> <br />
<br /> <br />
<i18n-t <I18nT
v-if="props.data.isWorkflowActivated" v-if="props.data.isWorkflowActivated"
keypath="workflowHistory.action.restore.modal.text" keypath="workflowHistory.action.restore.modal.text"
tag="span" tag="span"
scope="global"
> >
<template #buttonText> <template #buttonText>
&ldquo;{{ &ldquo;{{
i18n.baseText('workflowHistory.action.restore.modal.button.deactivateAndRestore') i18n.baseText('workflowHistory.action.restore.modal.button.deactivateAndRestore')
}}&rdquo; }}&rdquo;
</template> </template>
</i18n-t> </I18nT>
</n8n-text> </n8n-text>
</div> </div>
</template> </template>

View File

@@ -28,6 +28,7 @@ import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { telemetry } from '@/plugins/telemetry'; import { telemetry } from '@/plugins/telemetry';
import { useWorkflowSaving } from '@/composables/useWorkflowSaving'; import { useWorkflowSaving } from '@/composables/useWorkflowSaving';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
data: { data: {
@@ -274,7 +275,7 @@ watch(
@project-removed="onProjectRemoved" @project-removed="onProjectRemoved"
/> />
<n8n-info-tip v-if="isHomeTeamProject" :bold="false" class="mt-s"> <n8n-info-tip v-if="isHomeTeamProject" :bold="false" class="mt-s">
<i18n-t keypath="workflows.shareModal.info.members" tag="span"> <I18nT keypath="workflows.shareModal.info.members" tag="span" scope="global">
<template #projectName> <template #projectName>
{{ workflow.homeProject?.name }} {{ workflow.homeProject?.name }}
</template> </template>
@@ -290,20 +291,21 @@ watch(
}} }}
</strong> </strong>
</template> </template>
</i18n-t> </I18nT>
</n8n-info-tip> </n8n-info-tip>
</div> </div>
<template #fallback> <template #fallback>
<n8n-text> <n8n-text>
<i18n-t <I18nT
:keypath=" :keypath="
uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description
.tooltip .tooltip
" "
tag="span" tag="span"
scope="global"
> >
<template #action /> <template #action />
</i18n-t> </I18nT>
</n8n-text> </n8n-text>
</template> </template>
</enterprise-edition> </enterprise-edition>

View File

@@ -7,6 +7,7 @@ import { useI18n } from '@n8n/i18n';
import { type INodeTypeDescription } from 'n8n-workflow'; import { type INodeTypeDescription } from 'n8n-workflow';
import { computed } from 'vue'; import { computed } from 'vue';
import { isChatNode } from '@/utils/aiUtils'; import { isChatNode } from '@/utils/aiUtils';
import { I18nT } from 'vue-i18n';
const emit = defineEmits<{ const emit = defineEmits<{
mouseenter: [event: MouseEvent]; mouseenter: [event: MouseEvent];
@@ -93,7 +94,7 @@ function getNodeTypeByName(name: string): INodeTypeDescription | null {
<span :class="$style.buttonContent"> <span :class="$style.buttonContent">
{{ label }} {{ label }}
<N8nText v-if="isSplitButton" :class="$style.subText" :bold="false"> <N8nText v-if="isSplitButton" :class="$style.subText" :bold="false">
<I18nT keypath="nodeView.runButtonText.from"> <I18nT keypath="nodeView.runButtonText.from" scope="global">
<template #nodeName> <template #nodeName>
<N8nText bold size="mini"> <N8nText bold size="mini">
{{ truncateBeforeLast(props.selectedTriggerNodeName ?? '', 25) }} {{ truncateBeforeLast(props.selectedTriggerNodeName ?? '', 25) }}
@@ -127,7 +128,7 @@ function getNodeTypeByName(name: string): INodeTypeDescription | null {
<div :class="[$style.menuItem, item.disabled ? $style.disabled : '']"> <div :class="[$style.menuItem, item.disabled ? $style.disabled : '']">
<NodeIcon :class="$style.menuIcon" :size="16" :node-type="getNodeTypeByName(item.id)" /> <NodeIcon :class="$style.menuIcon" :size="16" :node-type="getNodeTypeByName(item.id)" />
<span> <span>
<I18nT keypath="nodeView.runButtonText.from"> <I18nT keypath="nodeView.runButtonText.from" scope="global">
<template #nodeName> <template #nodeName>
<N8nText bold size="small">{{ item.label }}</N8nText> <N8nText bold size="small">{{ item.label }}</N8nText>
</template> </template>

View File

@@ -15,6 +15,7 @@ import { useSettingsStore } from '@/stores/settings.store';
import { getObjectKeys, isEmpty } from '@/utils/typesUtils'; import { getObjectKeys, isEmpty } from '@/utils/typesUtils';
import type { Placement } from '@floating-ui/core'; import type { Placement } from '@floating-ui/core';
import { computed, onBeforeMount, reactive, ref } from 'vue'; import { computed, onBeforeMount, reactive, ref } from 'vue';
import { I18nT } from 'vue-i18n';
export type ExecutionFilterProps = { export type ExecutionFilterProps = {
workflows?: Array<IWorkflowDb | IWorkflowShortResponse>; workflows?: Array<IWorkflowDb | IWorkflowShortResponse>;
@@ -303,7 +304,7 @@ onBeforeMount(() => {
<div :class="$style.group"> <div :class="$style.group">
<n8n-tooltip placement="right"> <n8n-tooltip placement="right">
<template #content> <template #content>
<i18n-t tag="span" keypath="executionsFilter.customData.docsTooltip" /> <I18nT tag="span" keypath="executionsFilter.customData.docsTooltip" scope="global" />
</template> </template>
<span :class="[$style.label, $style.savedDataLabel]"> <span :class="[$style.label, $style.savedDataLabel]">
<span>{{ locale.baseText('executionsFilter.savedData') }}</span> <span>{{ locale.baseText('executionsFilter.savedData') }}</span>
@@ -316,7 +317,7 @@ onBeforeMount(() => {
}}</label> }}</label>
<n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top"> <n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top">
<template #content> <template #content>
<i18n-t tag="span" keypath="executionsFilter.customData.inputTooltip"> <I18nT tag="span" keypath="executionsFilter.customData.inputTooltip" scope="global">
<template #link> <template #link>
<a <a
href="#" href="#"
@@ -325,7 +326,7 @@ onBeforeMount(() => {
>{{ locale.baseText('executionsFilter.customData.inputTooltip.link') }}</a >{{ locale.baseText('executionsFilter.customData.inputTooltip.link') }}</a
> >
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<n8n-input <n8n-input
id="execution-filter-saved-data-key" id="execution-filter-saved-data-key"
@@ -341,13 +342,13 @@ onBeforeMount(() => {
<div :class="$style.checkboxWrapper"> <div :class="$style.checkboxWrapper">
<n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top"> <n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top">
<template #content> <template #content>
<i18n-t tag="span" keypath="executionsFilter.customData.inputTooltip"> <I18nT tag="span" keypath="executionsFilter.customData.inputTooltip" scope="global">
<template #link> <template #link>
<a href="#" @click.prevent="goToUpgrade">{{ <a href="#" @click.prevent="goToUpgrade">{{
locale.baseText('executionsFilter.customData.inputTooltip.link') locale.baseText('executionsFilter.customData.inputTooltip.link')
}}</a> }}</a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<n8n-checkbox <n8n-checkbox
:label="locale.baseText('executionsFilter.savedDataExactMatch')" :label="locale.baseText('executionsFilter.savedDataExactMatch')"
@@ -363,13 +364,13 @@ onBeforeMount(() => {
}}</label> }}</label>
<n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top"> <n8n-tooltip :disabled="isAdvancedExecutionFilterEnabled" placement="top">
<template #content> <template #content>
<i18n-t tag="span" keypath="executionsFilter.customData.inputTooltip"> <I18nT tag="span" keypath="executionsFilter.customData.inputTooltip" scope="global">
<template #link> <template #link>
<a href="#" @click.prevent="goToUpgrade">{{ <a href="#" @click.prevent="goToUpgrade">{{
locale.baseText('executionsFilter.customData.inputTooltip.link') locale.baseText('executionsFilter.customData.inputTooltip.link')
}}</a> }}</a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<n8n-input <n8n-input
id="execution-filter-saved-data-value" id="execution-filter-saved-data-value"

View File

@@ -1,6 +1,7 @@
<script lang="ts" setup=""> <script lang="ts" setup="">
import type { ExecutionStatus } from 'n8n-workflow'; import type { ExecutionStatus } from 'n8n-workflow';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
status: ExecutionStatus; status: ExecutionStatus;
@@ -18,18 +19,21 @@ const i18n = useI18n();
<template> <template>
<N8nTooltip placement="top"> <N8nTooltip placement="top">
<template #content> <template #content>
<i18n-t <I18nT
v-if="props.status === 'waiting'" v-if="props.status === 'waiting'"
keypath="executionsList.statusTooltipText.theWorkflowIsWaitingIndefinitely" keypath="executionsList.statusTooltipText.theWorkflowIsWaitingIndefinitely"
scope="global"
/> />
<i18n-t <I18nT
v-if="props.status === 'new'" v-if="props.status === 'new'"
keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity" keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity"
scope="global"
> >
<template #instance> <template #instance>
<i18n-t <I18nT
v-if="props.isCloudDeployment" v-if="props.isCloudDeployment"
keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity.cloud" keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity.cloud"
scope="global"
> >
<template #concurrencyCap>{{ props.concurrencyCap }}</template> <template #concurrencyCap>{{ props.concurrencyCap }}</template>
<template #link> <template #link>
@@ -37,10 +41,11 @@ const i18n = useI18n();
{{ i18n.baseText('generic.upgradeNow') }} {{ i18n.baseText('generic.upgradeNow') }}
</N8nLink> </N8nLink>
</template> </template>
</i18n-t> </I18nT>
<i18n-t <I18nT
v-else v-else
keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity.self" keypath="executionsList.statusTooltipText.waitingForConcurrencyCapacity.self"
scope="global"
> >
<template #concurrencyCap>{{ props.concurrencyCap }}</template> <template #concurrencyCap>{{ props.concurrencyCap }}</template>
<template #link> <template #link>
@@ -51,9 +56,9 @@ const i18n = useI18n();
>{{ i18n.baseText('generic.viewDocs') }}</N8nLink >{{ i18n.baseText('generic.viewDocs') }}</N8nLink
> >
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<slot /> <slot />
</N8nTooltip> </N8nTooltip>

View File

@@ -12,6 +12,7 @@ import type { InsightsDateRange, InsightsSummary } from '@n8n/api-types';
import { smartDecimal } from '@n8n/utils/number/smartDecimal'; import { smartDecimal } from '@n8n/utils/number/smartDecimal';
import { computed, useCssModule } from 'vue'; import { computed, useCssModule } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { I18nT } from 'vue-i18n';
const props = defineProps<{ const props = defineProps<{
summary: InsightsSummaryDisplay; summary: InsightsSummaryDisplay;
@@ -75,13 +76,13 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
> >
<N8nTooltip placement="top" :disabled="!(summaryHasNoData && id === 'total')"> <N8nTooltip placement="top" :disabled="!(summaryHasNoData && id === 'total')">
<template #content> <template #content>
<i18n-t keypath="insights.banner.noData.tooltip"> <I18nT keypath="insights.banner.noData.tooltip" scope="global">
<template #link> <template #link>
<a :href="i18n.baseText('insights.banner.noData.tooltip.link.url')" target="_blank"> <a :href="i18n.baseText('insights.banner.noData.tooltip.link.url')" target="_blank">
{{ i18n.baseText('insights.banner.noData.tooltip.link') }} {{ i18n.baseText('insights.banner.noData.tooltip.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
<router-link :to="to" :exact-active-class="$style.activeTab" @click="trackTabClick(id)"> <router-link :to="to" :exact-active-class="$style.activeTab" @click="trackTabClick(id)">
<strong> <strong>
@@ -100,11 +101,11 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
<small> <small>
<N8nTooltip placement="bottom"> <N8nTooltip placement="bottom">
<template #content> <template #content>
<i18n-t keypath="insights.banner.timeSaved.tooltip"> <I18nT keypath="insights.banner.timeSaved.tooltip" scope="global">
<template #link>{{ <template #link>{{
i18n.baseText('insights.banner.timeSaved.tooltip.link.text') i18n.baseText('insights.banner.timeSaved.tooltip.link.text')
}}</template> }}</template>
</i18n-t> </I18nT>
</template> </template>
<N8nIcon :class="$style.icon" icon="info" size="medium" /> <N8nIcon :class="$style.icon" icon="info" size="medium" />
</N8nTooltip> </N8nTooltip>

View File

@@ -136,7 +136,7 @@ watch(
:is-deleted="latestInfo?.deleted ?? false" :is-deleted="latestInfo?.deleted ?? false"
/> />
<N8nText v-if="!isCompact" tag="div" color="text-light" size="small" :class="$style.timeTook"> <N8nText v-if="!isCompact" tag="div" color="text-light" size="small" :class="$style.timeTook">
<I18nT v-if="timeText !== undefined" :keypath="statusTextKeyPath"> <I18nT v-if="timeText !== undefined" :keypath="statusTextKeyPath" scope="global">
<template #status> <template #status>
<N8nText :color="isError ? 'danger' : undefined" :bold="isError" size="small"> <N8nText :color="isError ? 'danger' : undefined" :bold="isError" size="small">
<AnimatedSpinner v-if="isRunning" :class="$style.statusTextIcon" /> <AnimatedSpinner v-if="isRunning" :class="$style.statusTextIcon" />

View File

@@ -118,7 +118,7 @@ function handleChangeDisplayMode(value: IRunDataDisplayMode) {
</template> </template>
<template v-if="isMultipleInput" #callout-message> <template v-if="isMultipleInput" #callout-message>
<I18nT keypath="logs.details.body.multipleInputs"> <I18nT keypath="logs.details.body.multipleInputs" scope="global">
<template #button> <template #button>
<N8nLink size="small" @click="handleClickOpenNdv"> <N8nLink size="small" @click="handleClickOpenNdv">
{{ locale.baseText('logs.details.body.multipleInputs.openingTheNode') }} {{ locale.baseText('logs.details.body.multipleInputs.openingTheNode') }}

View File

@@ -118,7 +118,7 @@ function onEdit(id: string) {
</div> </div>
<p v-if="isPublicApiEnabled && apiKeysSortByCreationDate.length" :class="$style.topHint"> <p v-if="isPublicApiEnabled && apiKeysSortByCreationDate.length" :class="$style.topHint">
<n8n-text> <n8n-text>
<i18n-t keypath="settings.api.view.info" tag="span"> <I18nT keypath="settings.api.view.info" tag="span" scope="global">
<template #apiAction> <template #apiAction>
<a <a
data-test-id="api-docs-link" data-test-id="api-docs-link"
@@ -135,7 +135,7 @@ function onEdit(id: string) {
v-text="i18n.baseText('settings.api.view.info.webhook')" v-text="i18n.baseText('settings.api.view.info.webhook')"
/> />
</template> </template>
</i18n-t> </I18nT>
</n8n-text> </n8n-text>
</p> </p>

View File

@@ -7,6 +7,7 @@ import { computed, onMounted } from 'vue';
import ExternalSecretsProviderCard from '@/components/ExternalSecretsProviderCard.ee.vue'; import ExternalSecretsProviderCard from '@/components/ExternalSecretsProviderCard.ee.vue';
import type { ExternalSecretsProvider } from '@/Interface'; import type { ExternalSecretsProvider } from '@/Interface';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
const i18n = useI18n(); const i18n = useI18n();
const externalSecretsStore = useExternalSecretsStore(); const externalSecretsStore = useExternalSecretsStore();
@@ -66,13 +67,13 @@ function goToUpgrade() {
<span>{{ i18n.baseText('settings.externalSecrets.actionBox.title') }}</span> <span>{{ i18n.baseText('settings.externalSecrets.actionBox.title') }}</span>
</template> </template>
<template #description> <template #description>
<i18n-t keypath="settings.externalSecrets.actionBox.description"> <I18nT keypath="settings.externalSecrets.actionBox.description" scope="global">
<template #link> <template #link>
<a :href="i18n.baseText('settings.externalSecrets.docs')" target="_blank"> <a :href="i18n.baseText('settings.externalSecrets.docs')" target="_blank">
{{ i18n.baseText('settings.externalSecrets.actionBox.description.link') }} {{ i18n.baseText('settings.externalSecrets.actionBox.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</n8n-action-box> </n8n-action-box>
</div> </div>

View File

@@ -13,6 +13,7 @@ import type { Rule, RuleGroup } from '@n8n/design-system/types';
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import type { Validatable } from '@n8n/design-system'; import type { Validatable } from '@n8n/design-system';
import { computed, onMounted, reactive, ref } from 'vue'; import { computed, onMounted, reactive, ref } from 'vue';
import { I18nT } from 'vue-i18n';
const locale = useI18n(); const locale = useI18n();
const sourceControlStore = useSourceControlStore(); const sourceControlStore = useSourceControlStore();
@@ -200,13 +201,13 @@ const onSelectSshKeyType = (value: Validatable) => {
data-test-id="source-control-content-licensed" data-test-id="source-control-content-licensed"
> >
<n8n-callout theme="secondary" icon="info" class="mt-2xl mb-l"> <n8n-callout theme="secondary" icon="info" class="mt-2xl mb-l">
<i18n-t keypath="settings.sourceControl.description" tag="span"> <I18nT keypath="settings.sourceControl.description" tag="span" scope="global">
<template #link> <template #link>
<a :href="locale.baseText('settings.sourceControl.docs.url')" target="_blank"> <a :href="locale.baseText('settings.sourceControl.docs.url')" target="_blank">
{{ locale.baseText('settings.sourceControl.description.link') }} {{ locale.baseText('settings.sourceControl.description.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</n8n-callout> </n8n-callout>
<n8n-heading size="xlarge" tag="h2" class="mb-s">{{ <n8n-heading size="xlarge" tag="h2" class="mb-s">{{
locale.baseText('settings.sourceControl.gitConfig') locale.baseText('settings.sourceControl.gitConfig')
@@ -275,7 +276,7 @@ const onSelectSshKeyType = (value: Validatable) => {
</n8n-button> </n8n-button>
</div> </div>
<n8n-notice type="info" class="mt-s"> <n8n-notice type="info" class="mt-s">
<i18n-t keypath="settings.sourceControl.sshKeyDescription" tag="span"> <I18nT keypath="settings.sourceControl.sshKeyDescription" tag="span" scope="global">
<template #link> <template #link>
<a <a
:href="locale.baseText('settings.sourceControl.docs.setup.ssh.url')" :href="locale.baseText('settings.sourceControl.docs.setup.ssh.url')"
@@ -283,7 +284,7 @@ const onSelectSshKeyType = (value: Validatable) => {
>{{ locale.baseText('settings.sourceControl.sshKeyDescriptionLink') }}</a >{{ locale.baseText('settings.sourceControl.sshKeyDescriptionLink') }}</a
> >
</template> </template>
</i18n-t> </I18nT>
</n8n-notice> </n8n-notice>
</div> </div>
<n8n-button <n8n-button
@@ -338,11 +339,11 @@ const onSelectSshKeyType = (value: Validatable) => {
v-model="sourceControlStore.preferences.branchReadOnly" v-model="sourceControlStore.preferences.branchReadOnly"
:class="$style.readOnly" :class="$style.readOnly"
> >
<i18n-t keypath="settings.sourceControl.protected" tag="span"> <I18nT keypath="settings.sourceControl.protected" tag="span" scope="global">
<template #bold> <template #bold>
<strong>{{ locale.baseText('settings.sourceControl.protected.bold') }}</strong> <strong>{{ locale.baseText('settings.sourceControl.protected.bold') }}</strong>
</template> </template>
</i18n-t> </I18nT>
</n8n-checkbox> </n8n-checkbox>
</div> </div>
<div :class="$style.group"> <div :class="$style.group">

View File

@@ -14,6 +14,7 @@ import { COMMUNITY_PLUS_ENROLLMENT_MODAL } from '@/constants';
import { useUsersStore } from '@/stores/users.store'; import { useUsersStore } from '@/stores/users.store';
import { getResourcePermissions } from '@n8n/permissions'; import { getResourcePermissions } from '@n8n/permissions';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
const usageStore = useUsageStore(); const usageStore = useUsageStore();
const route = useRoute(); const route = useRoute();
@@ -164,7 +165,7 @@ const openCommunityRegisterModal = () => {
}}</n8n-heading> }}</n8n-heading>
<div v-if="!usageStore.isLoading"> <div v-if="!usageStore.isLoading">
<n8n-heading tag="h3" :class="$style.title" size="large"> <n8n-heading tag="h3" :class="$style.title" size="large">
<i18n-t keypath="settings.usageAndPlan.description" tag="span"> <I18nT keypath="settings.usageAndPlan.description" tag="span" scope="global">
<template #name>{{ badgedPlanName.name ?? usageStore.planName }}</template> <template #name>{{ badgedPlanName.name ?? usageStore.planName }}</template>
<template #type> <template #type>
<span v-if="usageStore.planId">{{ <span v-if="usageStore.planId">{{
@@ -172,15 +173,16 @@ const openCommunityRegisterModal = () => {
}}</span> }}</span>
<span v-else>{{ locale.baseText('settings.usageAndPlan.edition') }}</span> <span v-else>{{ locale.baseText('settings.usageAndPlan.edition') }}</span>
</template> </template>
</i18n-t> </I18nT>
<span v-if="badgedPlanName.badge && badgedPlanName.name" :class="$style.titleTooltip"> <span v-if="badgedPlanName.badge && badgedPlanName.name" :class="$style.titleTooltip">
<N8nTooltip placement="top"> <N8nTooltip placement="top">
<template #content> <template #content>
<i18n-t <I18nT
v-if="isCommunityEditionRegistered" v-if="isCommunityEditionRegistered"
keypath="settings.usageAndPlan.license.communityRegistered.tooltip" keypath="settings.usageAndPlan.license.communityRegistered.tooltip"
scope="global"
> >
</i18n-t> </I18nT>
</template> </template>
<N8nBadge>{{ badgedPlanName.badge }}</N8nBadge> <N8nBadge>{{ badgedPlanName.badge }}</N8nBadge>
</N8nTooltip> </N8nTooltip>
@@ -188,7 +190,7 @@ const openCommunityRegisterModal = () => {
</n8n-heading> </n8n-heading>
<N8nNotice v-if="isCommunity && canUserRegisterCommunityPlus" class="mt-0" theme="warning"> <N8nNotice v-if="isCommunity && canUserRegisterCommunityPlus" class="mt-0" theme="warning">
<i18n-t keypath="settings.usageAndPlan.callOut"> <I18nT keypath="settings.usageAndPlan.callOut" scope="global">
<template #link> <template #link>
<N8nButton <N8nButton
class="pl-0 pr-0" class="pl-0 pr-0"
@@ -197,7 +199,7 @@ const openCommunityRegisterModal = () => {
@click="openCommunityRegisterModal" @click="openCommunityRegisterModal"
/> />
</template> </template>
</i18n-t> </I18nT>
</N8nNotice> </N8nNotice>
<div :class="$style.quota"> <div :class="$style.quota">
@@ -211,10 +213,11 @@ const openCommunityRegisterModal = () => {
:style="{ width: `${usageStore.executionPercentage}%` }" :style="{ width: `${usageStore.executionPercentage}%` }"
></span> ></span>
</span> </span>
<i18n-t <I18nT
tag="span" tag="span"
:class="$style.count" :class="$style.count"
keypath="settings.usageAndPlan.activeWorkflows.count" keypath="settings.usageAndPlan.activeWorkflows.count"
scope="global"
> >
<template #count>{{ usageStore.activeWorkflowTriggersCount }}</template> <template #count>{{ usageStore.activeWorkflowTriggersCount }}</template>
<template #limit> <template #limit>
@@ -223,7 +226,7 @@ const openCommunityRegisterModal = () => {
}}</span> }}</span>
<span v-else>{{ usageStore.activeWorkflowTriggersLimit }}</span> <span v-else>{{ usageStore.activeWorkflowTriggersLimit }}</span>
</template> </template>
</i18n-t> </I18nT>
</div> </div>
</div> </div>

View File

@@ -27,6 +27,7 @@ import { useI18n } from '@n8n/i18n';
import { useDocumentTitle } from '@/composables/useDocumentTitle'; import { useDocumentTitle } from '@/composables/useDocumentTitle';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper'; import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import SettingsUsersTable from '@/components/SettingsUsers/SettingsUsersTable.vue'; import SettingsUsersTable from '@/components/SettingsUsers/SettingsUsersTable.vue';
import { I18nT } from 'vue-i18n';
const clipboard = useClipboard(); const clipboard = useClipboard();
const { showToast, showError } = useToast(); const { showToast, showError } = useToast();
@@ -367,7 +368,7 @@ async function onUpdateMfaEnforced(value: boolean) {
/> />
</div> </div>
<n8n-notice v-if="!isAdvancedPermissionsEnabled"> <n8n-notice v-if="!isAdvancedPermissionsEnabled">
<i18n-t keypath="settings.users.advancedPermissions.warning"> <I18nT keypath="settings.users.advancedPermissions.warning" scope="global">
<template #link> <template #link>
<n8n-link <n8n-link
data-test-id="upgrade-permissions-link" data-test-id="upgrade-permissions-link"
@@ -377,7 +378,7 @@ async function onUpdateMfaEnforced(value: boolean) {
{{ i18n.baseText('settings.users.advancedPermissions.warning.link') }} {{ i18n.baseText('settings.users.advancedPermissions.warning.link') }}
</n8n-link> </n8n-link>
</template> </template>
</i18n-t> </I18nT>
</n8n-notice> </n8n-notice>
<div :class="$style.settingsContainer"> <div :class="$style.settingsContainer">
<div :class="$style.settingsContainerInfo"> <div :class="$style.settingsContainerInfo">
@@ -403,13 +404,13 @@ async function onUpdateMfaEnforced(value: boolean) {
@update:model-value="onUpdateMfaEnforced" @update:model-value="onUpdateMfaEnforced"
/> />
<template #content> <template #content>
<i18n-t :keypath="tooltipKey" tag="span"> <I18nT :keypath="tooltipKey" tag="span" scope="global">
<template #action> <template #action>
<a @click="goToUpgrade"> <a @click="goToUpgrade">
{{ i18n.baseText('settings.personal.mfa.enforce.unlicensed_tooltip.link') }} {{ i18n.baseText('settings.personal.mfa.enforce.unlicensed_tooltip.link') }}
</a> </a>
</template> </template>
</i18n-t> </I18nT>
</template> </template>
</N8nTooltip> </N8nTooltip>
</template> </template>

View File

@@ -7,6 +7,7 @@ import type {
AppCredentials, AppCredentials,
BaseNode, BaseNode,
} from '@/views/SetupWorkflowFromTemplateView/useCredentialSetupState'; } from '@/views/SetupWorkflowFromTemplateView/useCredentialSetupState';
import { I18nT } from 'vue-i18n';
const i18n = useI18n(); const i18n = useI18n();
@@ -27,9 +28,9 @@ const appNodeCounts = computed(() => {
<template> <template>
<N8nNotice :class="$style.notice" theme="info"> <N8nNotice :class="$style.notice" theme="info">
<i18n-t tag="span" keypath="templateSetup.instructions" scope="global"> <I18nT tag="span" keypath="templateSetup.instructions" scope="global">
<span v-n8n-html="appNodeCounts" /> <span v-n8n-html="appNodeCounts" />
</i18n-t> </I18nT>
</N8nNotice> </N8nNotice>
</template> </template>

View File

@@ -14,6 +14,7 @@ import type {
import { useI18n } from '@n8n/i18n'; import { useI18n } from '@n8n/i18n';
import { useTelemetry } from '@/composables/useTelemetry'; import { useTelemetry } from '@/composables/useTelemetry';
import type { TemplateCredentialKey } from '@/utils/templates/templateTransforms'; import type { TemplateCredentialKey } from '@/utils/templates/templateTransforms';
import { I18nT } from 'vue-i18n';
// Props // Props
const props = withDefaults( const props = withDefaults(
@@ -83,14 +84,14 @@ const onCredentialModalOpened = () => {
</N8nHeading> </N8nHeading>
<p :class="$style.description" data-test-id="credential-step-description"> <p :class="$style.description" data-test-id="credential-step-description">
<i18n-t <I18nT
tag="span" tag="span"
keypath="templateSetup.credential.description" keypath="templateSetup.credential.description"
:plural="credentials.usedBy.length" :plural="credentials.usedBy.length"
scope="global" scope="global"
> >
<span v-n8n-html="nodeNames" /> <span v-n8n-html="nodeNames" />
</i18n-t> </I18nT>
</p> </p>
<div :class="$style.credentials"> <div :class="$style.credentials">