diff --git a/browser_tests/tests/templates.spec.ts b/browser_tests/tests/templates.spec.ts index 295f777ae..68cc7f388 100644 --- a/browser_tests/tests/templates.spec.ts +++ b/browser_tests/tests/templates.spec.ts @@ -86,4 +86,48 @@ test.describe('Templates', () => { // Expect the templates dialog to be shown expect(await comfyPage.templates.content.isVisible()).toBe(true) }) + + test('Uses title field as fallback when the key is not found in locales', async ({ + comfyPage + }) => { + // Capture request for the index.json + await comfyPage.page.route('**/templates/index.json', async (route, _) => { + // Add a new template that won't have a translation pre-generated + const response = [ + { + moduleName: 'default', + title: 'FALLBACK CATEGORY', + type: 'image', + templates: [ + { + name: 'unknown_key_has_no_translation_available', + title: 'FALLBACK TEMPLATE NAME', + mediaType: 'image', + mediaSubtype: 'webp', + description: 'No translations found' + } + ] + } + ] + await route.fulfill({ + status: 200, + body: JSON.stringify(response), + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store' + } + }) + }) + + // Load the templates dialog + await comfyPage.executeCommand('Comfy.BrowseTemplates') + + // Expect the title to be used as fallback for template cards + await expect( + comfyPage.templates.content.getByText('FALLBACK TEMPLATE NAME') + ).toBeVisible() + + // Expect the title to be used as fallback for the template categories + await expect(comfyPage.page.getByLabel('FALLBACK CATEGORY')).toBeVisible() + }) }) diff --git a/src/components/templates/TemplateWorkflowCard.vue b/src/components/templates/TemplateWorkflowCard.vue index 709203793..5ee1ecfc1 100644 --- a/src/components/templates/TemplateWorkflowCard.vue +++ b/src/components/templates/TemplateWorkflowCard.vue @@ -123,12 +123,13 @@ const overlayThumbnailSrc = computed(() => ) const title = computed(() => { + const fallback = template.title ?? template.name ?? `${sourceModule} Template` return sourceModule === 'default' ? st( `templateWorkflows.template.${normalizeI18nKey(categoryTitle)}.${normalizeI18nKey(template.name)}`, - template.name + fallback ) - : template.name ?? `${sourceModule} Template` + : fallback }) const description = computed(() => template.description.replace(/[-_]/g, ' ')) diff --git a/src/stores/workflowTemplatesStore.ts b/src/stores/workflowTemplatesStore.ts index 1aa90838d..e1f33ea31 100644 --- a/src/stores/workflowTemplatesStore.ts +++ b/src/stores/workflowTemplatesStore.ts @@ -1,8 +1,8 @@ import { groupBy } from 'lodash' import { defineStore } from 'pinia' import { computed, ref, shallowRef } from 'vue' -import { useI18n } from 'vue-i18n' +import { st } from '@/i18n' import { api } from '@/scripts/api' import type { TemplateGroup, @@ -13,7 +13,6 @@ import { normalizeI18nKey } from '@/utils/formatUtil' export const useWorkflowTemplatesStore = defineStore( 'workflowTemplates', () => { - const { t } = useI18n() const customTemplates = shallowRef<{ [moduleName: string]: string[] }>({}) const coreTemplates = shallowRef([]) const isLoaded = ref(false) @@ -22,11 +21,9 @@ export const useWorkflowTemplatesStore = defineStore( const allTemplates = [ ...coreTemplates.value.map((template) => ({ ...template, - title: t( + title: st( `templateWorkflows.category.${normalizeI18nKey(template.title)}`, - { - defaultValue: template.title - } + template.title ?? template.moduleName ) })), ...Object.entries(customTemplates.value).map( @@ -46,12 +43,11 @@ export const useWorkflowTemplatesStore = defineStore( return Object.entries( groupBy(allTemplates, (template) => template.moduleName === 'default' - ? t('templateWorkflows.category.ComfyUI Examples', { - defaultValue: 'ComfyUI Examples' - }) - : t('templateWorkflows.category.Custom Nodes', { - defaultValue: 'Custom Nodes' - }) + ? st( + 'templateWorkflows.category.ComfyUI Examples', + 'ComfyUI Examples' + ) + : st('templateWorkflows.category.Custom Nodes', 'Custom Nodes') ) ).map(([label, modules]) => ({ label, modules })) }) diff --git a/src/types/workflowTemplateTypes.ts b/src/types/workflowTemplateTypes.ts index ceb6daf31..4a5116b38 100644 --- a/src/types/workflowTemplateTypes.ts +++ b/src/types/workflowTemplateTypes.ts @@ -1,5 +1,9 @@ export interface TemplateInfo { name: string + /** + * Optional title which is used as the fallback if the name is not in the locales dictionary. + */ + title?: string tutorialUrl?: string mediaType: string mediaSubtype: string