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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,6 +18,7 @@ import { createEventBus } from '@n8n/utils/event-bus';
import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
const props = defineProps<{
modalName: string;
@@ -304,13 +305,13 @@ function getEmail(email: string): string {
>
<template #content>
<n8n-notice v-if="!isAdvancedPermissionsEnabled">
<i18n-t keypath="settings.users.advancedPermissions.warning">
<I18nT keypath="settings.users.advancedPermissions.warning" scope="global">
<template #link>
<n8n-link size="small" @click="goToUpgradeAdvancedPermissions">
{{ i18n.baseText('settings.users.advancedPermissions.warning.link') }}
</n8n-link>
</template>
</i18n-t>
</I18nT>
</n8n-notice>
<div v-if="showInviteUrls">
<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 { useWorkflowSaving } from '@/composables/useWorkflowSaving';
import { sanitizeFilename } from '@/utils/fileUtils';
import { I18nT } from 'vue-i18n';
const props = defineProps<{
readOnly?: boolean;
@@ -798,12 +799,13 @@ const onBreadcrumbsItemSelected = (item: PathItem) => {
{{ i18n.baseText('workflowDetails.share') }}
</N8nButton>
<template #content>
<i18n-t
<I18nT
:keypath="
uiStore.contextBasedTranslationKeys.workflows.sharing.unavailable.description
.tooltip
"
tag="span"
scope="global"
>
<template #action>
<a @click="goToUpgrade">
@@ -815,7 +817,7 @@ const onBreadcrumbsItemSelected = (item: PathItem) => {
}}
</a>
</template>
</i18n-t>
</I18nT>
</template>
</N8nTooltip>
</template>

View File

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

View File

@@ -28,6 +28,7 @@ import { useBecomeTemplateCreatorStore } from '@/components/BecomeTemplateCreato
import Logo from '@/components/Logo/Logo.vue';
import VersionUpdateCTA from '@/components/VersionUpdateCTA.vue';
import { TemplateClickSource, trackTemplatesClick } from '@/utils/experiments';
import { I18nT } from 'vue-i18n';
const becomeTemplateCreatorStore = useBecomeTemplateCreatorStore();
const cloudPlanStore = useCloudPlanStore();
@@ -390,7 +391,7 @@ onClickOutside(createBtn as Ref<VueInstance>, () => {
placement="bottom"
>
<template #content>
<i18n-t keypath="readOnlyEnv.tooltip">
<I18nT keypath="readOnlyEnv.tooltip" scope="global">
<template #link>
<N8nLink
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') }}
</N8nLink>
</template>
</i18n-t>
</I18nT>
</template>
<N8nIcon
data-test-id="read-only-env-icon"

View File

@@ -16,6 +16,7 @@ import { useClipboard } from '@/composables/useClipboard';
import { useI18n } from '@n8n/i18n';
import { useSettingsStore } from '@/stores/settings.store';
import router from '@/router';
import { I18nT } from 'vue-i18n';
// ---------------------------------------------------------------------------
// #region Reactive properties
@@ -178,7 +179,7 @@ onMounted(async () => {
</div>
<div>
<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>
{{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part1') }}
</template>
@@ -190,7 +191,7 @@ onMounted(async () => {
>{{ i18n.baseText('mfa.setup.step1.instruction1.subtitle.part2') }}</a
>
</template>
</i18n-t>
</I18nT>
</n8n-text>
</div>
<div :class="$style.qrContainer">
@@ -235,7 +236,7 @@ onMounted(async () => {
</div>
</div>
<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>
{{ i18n.baseText('mfa.setup.step2.infobox.description.part1') }}
</template>
@@ -244,7 +245,7 @@ onMounted(async () => {
{{ i18n.baseText('mfa.setup.step2.infobox.description.part2') }}
</n8n-text>
</template>
</i18n-t>
</I18nT>
</n8n-info-tip>
<div>
<n8n-button

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
<script lang="ts" setup>
import { useI18n } from '@n8n/i18n';
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
import { I18nT } from 'vue-i18n';
type Props = {
limit: number;
@@ -24,7 +25,7 @@ const goToUpgrade = async () => {
width="500"
>
<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 #limit>
{{
@@ -34,7 +35,7 @@ const goToUpgrade = async () => {
})
}}
</template>
</i18n-t>
</I18nT>
</div>
<template #footer>
<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 { parseAiContent } from '@/utils/aiUtils';
import { usePostHog } from '@/stores/posthog.store';
import { I18nT } from 'vue-i18n';
const LazyRunDataTable = defineAsyncComponent(
async () => await import('@/components/RunDataTable.vue'),
@@ -1758,13 +1759,13 @@ defineExpose({ enterEditMode });
<div v-if="search">
<N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText>
<N8nText>
<i18n-t keypath="ndv.search.noMatch.description" tag="span">
<I18nT keypath="ndv.search.noMatch.description" tag="span" scope="global">
<template #link>
<a href="#" @click="onSearchClear">
{{ i18n.baseText('ndv.search.noMatch.description.link') }}
</a>
</template>
</i18n-t>
</I18nT>
</N8nText>
</div>
<N8nText v-else>
@@ -1832,13 +1833,13 @@ defineExpose({ enterEditMode });
<div v-else-if="showIoSearchNoMatchContent" :class="$style.center">
<N8nText tag="h3" size="large">{{ i18n.baseText('ndv.search.noMatch.title') }}</N8nText>
<N8nText>
<i18n-t keypath="ndv.search.noMatch.description" tag="span">
<I18nT keypath="ndv.search.noMatch.description" tag="span" scope="global">
<template #link>
<a href="#" @click="onSearchClear">
{{ i18n.baseText('ndv.search.noMatch.description.link') }}
</a>
</template>
</i18n-t>
</I18nT>
</N8nText>
</div>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -136,7 +136,7 @@ watch(
:is-deleted="latestInfo?.deleted ?? false"
/>
<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>
<N8nText :color="isError ? 'danger' : undefined" :bold="isError" size="small">
<AnimatedSpinner v-if="isRunning" :class="$style.statusTextIcon" />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,7 @@ import type {
AppCredentials,
BaseNode,
} from '@/views/SetupWorkflowFromTemplateView/useCredentialSetupState';
import { I18nT } from 'vue-i18n';
const i18n = useI18n();
@@ -27,9 +28,9 @@ const appNodeCounts = computed(() => {
<template>
<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" />
</i18n-t>
</I18nT>
</N8nNotice>
</template>

View File

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