diff --git a/frontend/viewer/src/lib/entry-editor/EntryOrSenseItemList.svelte b/frontend/viewer/src/lib/entry-editor/EntryOrSenseItemList.svelte index f23032f8a1..28d4a2ef17 100644 --- a/frontend/viewer/src/lib/entry-editor/EntryOrSenseItemList.svelte +++ b/frontend/viewer/src/lib/entry-editor/EntryOrSenseItemList.svelte @@ -13,12 +13,13 @@ const viewService = useViewService(); const multiWindowService = useMultiWindowService(); - interface Props extends Omit, 'getDisplayName'> { + interface Props extends Omit, 'getDisplayName' | 'menuItems'> { getEntryId: (item: T) => string; getHeadword: (item: T) => string | undefined; + extraMenuItems?: ItemListProps['menuItems']; } - let { items = $bindable(), getEntryId, getHeadword, ...rest }: Props = $props(); + let { items = $bindable(), getEntryId, getHeadword, extraMenuItems, ...rest }: Props = $props(); {/if} + {@render extraMenuItems?.(entry)} {/snippet} diff --git a/frontend/viewer/src/lib/entry-editor/field-editors/VariantOf.svelte b/frontend/viewer/src/lib/entry-editor/field-editors/VariantOf.svelte new file mode 100644 index 0000000000..966da9ac8d --- /dev/null +++ b/frontend/viewer/src/lib/entry-editor/field-editors/VariantOf.svelte @@ -0,0 +1,79 @@ + + + v.mainEntryId} getHeadword={(v) => v.mainHeadword}> + {#snippet extraMenuItems(variant)} + + { value = [...value]; onchange?.(value); }} /> + {/snippet} + {#snippet actions()} + addVariantOf(e)} + {disableEntry} {disableSense}> + {#snippet trigger({ props })} + + {/snippet} + + {/snippet} + diff --git a/frontend/viewer/src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte b/frontend/viewer/src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte new file mode 100644 index 0000000000..ab807a231b --- /dev/null +++ b/frontend/viewer/src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte @@ -0,0 +1,52 @@ + + +{#if !readonly && variantTypes.current.length} + + + + {$t`Variant type`} + + + {#each variantTypes.current as type (type.id)} + toggleType(type.id)}> + {writingSystemService.pickBestAlternative(type.name, 'analysis')} + + {/each} + + +{/if} diff --git a/frontend/viewer/src/lib/entry-editor/field-editors/Variants.svelte b/frontend/viewer/src/lib/entry-editor/field-editors/Variants.svelte new file mode 100644 index 0000000000..4cce2eaf6c --- /dev/null +++ b/frontend/viewer/src/lib/entry-editor/field-editors/Variants.svelte @@ -0,0 +1,73 @@ + + + v.variantEntryId} getHeadword={(v) => v.variantHeadword}> + {#snippet extraMenuItems(variant)} + + { value = [...value]; onchange?.(value); }} /> + {/snippet} + {#snippet actions()} + addVariant(e)} + {disableEntry}> + {#snippet trigger({ props })} + + {/snippet} + + {/snippet} + diff --git a/frontend/viewer/src/lib/entry-editor/object-editors/EntryEditorPrimitive.svelte b/frontend/viewer/src/lib/entry-editor/object-editors/EntryEditorPrimitive.svelte index 187dbb0e0a..70d81d3714 100644 --- a/frontend/viewer/src/lib/entry-editor/object-editors/EntryEditorPrimitive.svelte +++ b/frontend/viewer/src/lib/entry-editor/object-editors/EntryEditorPrimitive.svelte @@ -9,6 +9,8 @@ import {MultiSelect, MultiWsInput, RichMultiWsInput} from '$lib/components/field-editors'; import ComplexFormComponents from '../field-editors/ComplexFormComponents.svelte'; import ComplexForms from '../field-editors/ComplexForms.svelte'; + import VariantOf from '../field-editors/VariantOf.svelte'; + import Variants from '../field-editors/Variants.svelte'; import type {EditorSubGridProps} from '$lib/components/editor/editor-sub-grid.svelte'; import {mergeProps} from 'bits-ui'; import {initSubjectContext} from '$lib/entry-editor/object-editors/subject-context'; @@ -94,6 +96,26 @@ + + + + onFieldChanged('variantOf')} + bind:value={entry.variantOf} + {readonly} + {entry} /> + + + + + + + onFieldChanged('variants')} + bind:value={entry.variants} + {readonly} + {entry} /> + + + diff --git a/frontend/viewer/src/lib/views/entity-config.ts b/frontend/viewer/src/lib/views/entity-config.ts index 311dfc8635..8081e7fdf7 100644 --- a/frontend/viewer/src/lib/views/entity-config.ts +++ b/frontend/viewer/src/lib/views/entity-config.ts @@ -34,6 +34,15 @@ export const entityConfig = { label: msg`Components`, helpId: 'User_Interface/Field_Descriptions/Lexicon/Lexicon_Edit_fields/Entry_level_fields/Components_field.htm', }, + variantOf: { + label: msg`Variant of`, + helpId: 'User_Interface/Field_Descriptions/Lexicon/Lexicon_Edit_fields/Entry_level_fields/Variant_of_field.htm', + }, + variants: { + label: msg`Variants`, + //there's no dedicated help topic for the variants back-reference; this one explains the relationship + helpId: 'User_Interface/Field_Descriptions/Lexicon/Lexicon_Edit_fields/Entry_level_fields/Variant_of_field.htm', + }, literalMeaning: { label: msg`Literal meaning`, helpId: 'User_Interface/Field_Descriptions/Lexicon/Lexicon_Edit_fields/Entry_level_fields/Literal_Meaning_field.htm', diff --git a/frontend/viewer/src/lib/views/view-data.ts b/frontend/viewer/src/lib/views/view-data.ts index 094571043f..1b2f9cba5d 100644 --- a/frontend/viewer/src/lib/views/view-data.ts +++ b/frontend/viewer/src/lib/views/view-data.ts @@ -52,9 +52,11 @@ export const FW_LITE_VIEW: RootView = { complexForms: {show: true, order: 3}, complexFormTypes: {show: false, order: 4}, components: {show: true, order: 5}, - literalMeaning: {show: false, order: 6}, - note: {show: true, order: 7}, - publishIn: {show: false, order: 8}, + variantOf: {show: true, order: 6}, + variants: {show: true, order: 7}, + literalMeaning: {show: false, order: 8}, + note: {show: true, order: 9}, + publishIn: {show: false, order: 10}, }, sense: { gloss: {show: true, order: 1}, diff --git a/frontend/viewer/src/locales/en.po b/frontend/viewer/src/locales/en.po index b420b6f859..c1f20f86d3 100644 --- a/frontend/viewer/src/locales/en.po +++ b/frontend/viewer/src/locales/en.po @@ -182,6 +182,16 @@ msgstr "Add Sense" msgid "Add to dictionary" msgstr "Add to dictionary" +#. Dialog title: picker for adding an entry as a variant of the current entry (fills the "Variants" field) +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "Add variant" + +#. Dialog title: picker for marking the current entry as a variant of another entry/sense (fills the "Variant of" field) +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "Add variant of" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -528,6 +538,8 @@ msgstr "Create View" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Current Entry" @@ -541,6 +553,8 @@ msgstr "Current version" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Current Word" @@ -900,7 +914,7 @@ msgstr "FieldWorks Lite version" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2142,10 +2156,7 @@ msgid "Unable to open in FieldWorks" msgstr "Unable to open in FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2245,6 +2256,32 @@ msgstr "Updates" msgid "Uses components as" msgstr "Uses components as" +#. Used two ways: (1) button label for adding an entry to the "Variants" field, and (2) disable-reason shown in the entry picker when an entry is already linked as a variant, so it can't be picked again +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "Variant" + +#. Used three ways: (1) field label for the "Variant of" relationship (this entry is a variant of another entry/sense), (2) button label in that field's entry picker, and (3) disable-reason shown when an entry is already linked, so it can't be picked again +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "Variant of" + +#. Dropdown submenu label in a variant's context menu, for assigning its variant type (a user-configurable classification, e.g. dialectal or spelling variant) +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "Variant type" + +#. Field label: other entries that are variants of this entry (the reverse of "Variant of") +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "Variants" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/es.po b/frontend/viewer/src/locales/es.po index e4049b6109..876426c2ce 100644 --- a/frontend/viewer/src/locales/es.po +++ b/frontend/viewer/src/locales/es.po @@ -187,6 +187,14 @@ msgstr "Añadir acepción" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Crear vista" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Entrada actual" @@ -546,6 +556,8 @@ msgstr "Versión actual" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Palabra actual" @@ -905,7 +917,7 @@ msgstr "Versión de FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "No se puede abrir en FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Actualizaciones" msgid "Uses components as" msgstr "Utiliza componentes como" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/fr.po b/frontend/viewer/src/locales/fr.po index 13b01dd9d2..6e6513a3dd 100644 --- a/frontend/viewer/src/locales/fr.po +++ b/frontend/viewer/src/locales/fr.po @@ -187,6 +187,14 @@ msgstr "Ajouter du sens" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Créer une vue" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Entrée actuelle" @@ -546,6 +556,8 @@ msgstr "Version actuelle" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Mot actuel" @@ -905,7 +917,7 @@ msgstr "Version de FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "Impossible d'ouvrir FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Mises à jour" msgid "Uses components as" msgstr "Utilise des composants comme" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/id.po b/frontend/viewer/src/locales/id.po index d749849c0f..2b4ceb7a9e 100644 --- a/frontend/viewer/src/locales/id.po +++ b/frontend/viewer/src/locales/id.po @@ -187,6 +187,14 @@ msgstr "Tambahkan Pengertian" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Buat Tampilan" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Entri Saat Ini" @@ -546,6 +556,8 @@ msgstr "Versi saat ini" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Kata saat ini" @@ -905,7 +917,7 @@ msgstr "Versi FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "Tidak dapat dibuka di FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Pembaruan" msgid "Uses components as" msgstr "Menggunakan komponen sebagai" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/ko.po b/frontend/viewer/src/locales/ko.po index cddd9828d6..509e9dbe01 100644 --- a/frontend/viewer/src/locales/ko.po +++ b/frontend/viewer/src/locales/ko.po @@ -187,6 +187,14 @@ msgstr "센스 추가" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "보기 만들기" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "현재 항목" @@ -546,6 +556,8 @@ msgstr "현재 버전" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "현재 단어" @@ -905,7 +917,7 @@ msgstr "FieldWorks Lite 버전" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "FieldWorks에서 열 수 없음" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "업데이트" msgid "Uses components as" msgstr "구성 요소를 다음과 같이 사용합니다." +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/ms.po b/frontend/viewer/src/locales/ms.po index 5f0ed57320..25f94be128 100644 --- a/frontend/viewer/src/locales/ms.po +++ b/frontend/viewer/src/locales/ms.po @@ -187,6 +187,14 @@ msgstr "Tambah Makna" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Buat Pandangan" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Entri Semasa" @@ -546,6 +556,8 @@ msgstr "Versi semasa" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Perkataan Semasa" @@ -905,7 +917,7 @@ msgstr "Versi FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "Tidak dapat membuka dalam FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Kemas kini" msgid "Uses components as" msgstr "Menggunakan komponen sebagai" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/sw.po b/frontend/viewer/src/locales/sw.po index aacc4c2529..572068adf9 100644 --- a/frontend/viewer/src/locales/sw.po +++ b/frontend/viewer/src/locales/sw.po @@ -187,6 +187,14 @@ msgstr "Ongeza Maana" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Tengeneza Mtazamo" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Ingizo Sasa" @@ -546,6 +556,8 @@ msgstr "Toleo Sasa" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Neno Sasa" @@ -905,7 +917,7 @@ msgstr "Toleo la FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "Haiwezi kufungua katika FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Masasisho" msgid "Uses components as" msgstr "Inatumia sehemu kama" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/locales/vi.po b/frontend/viewer/src/locales/vi.po index 08eccb0489..05b4a6196d 100644 --- a/frontend/viewer/src/locales/vi.po +++ b/frontend/viewer/src/locales/vi.po @@ -187,6 +187,14 @@ msgstr "Thêm Ý nghĩa (sense)" msgid "Add to dictionary" msgstr "" +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Add variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +msgid "Add variant of" +msgstr "" + #. Dialog title #: src/lib/entry-editor/NewEntryDialog.svelte msgid "Add Word" @@ -533,6 +541,8 @@ msgstr "Tạo chế độ xem" #. Label in picker: marks the entry that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Entry" msgstr "Mục hiện tại" @@ -546,6 +556,8 @@ msgstr "Phiên bản hiện tại" #. Label in picker: marks the word that is currently being edited #: src/lib/entry-editor/field-editors/ComplexFormComponents.svelte #: src/lib/entry-editor/field-editors/ComplexForms.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte msgid "Current Word" msgstr "Từ hiện tại" @@ -905,7 +917,7 @@ msgstr "Phiên bản FieldWorks Lite" #. Alt text for FieldWorks logo image #: src/home/HomeView.svelte -#: src/lib/activity/ActivityFilter.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/components/OpenInFieldWorksButton.svelte #: src/project/ProjectDropdown.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2147,10 +2159,7 @@ msgid "Unable to open in FieldWorks" msgstr "Không thể mở trong FieldWorks" #. Fallback value shown when author name or last-change date is unavailable (e.g., in activity history or the sync panel). -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityFilter.svelte -#: src/lib/activity/ActivityItem.svelte -#: src/lib/activity/ActivityView.svelte +#: src/lib/activity/AuthorLabel.svelte #: src/lib/activity/utils.ts #: src/project/sync/FwLiteToFwMergeDetails.svelte #: src/project/sync/FwLiteToFwMergeDetails.svelte @@ -2250,6 +2259,28 @@ msgstr "Cập nhật" msgid "Uses components as" msgstr "Sử dụng các thành phần như" +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +msgid "Variant" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/VariantOf.svelte +#: src/lib/entry-editor/field-editors/Variants.svelte +#: src/lib/views/entity-config.ts +msgid "Variant of" +msgstr "" + +#: src/lib/entry-editor/field-editors/VariantTypesMenuItems.svelte +msgid "Variant type" +msgstr "" + +#: src/lib/views/entity-config.ts +msgid "Variants" +msgstr "" + #. Section heading in custom view writing system picker. #. Labels the vernacular language writing systems (the language being documented). #: src/lib/views/custom/CustomViewWritingSystems.svelte diff --git a/frontend/viewer/src/project/data/variant-types.ts b/frontend/viewer/src/project/data/variant-types.ts index 3e8d88b11c..7e39299da5 100644 --- a/frontend/viewer/src/project/data/variant-types.ts +++ b/frontend/viewer/src/project/data/variant-types.ts @@ -3,7 +3,9 @@ import {useProjectContext} from '$project/project-context.svelte'; const variantTypesSymbol = Symbol.for('fw-lite-variant-types'); export function useVariantTypes() { const projectContext = useProjectContext(); - return projectContext.getOrAddAsync(variantTypesSymbol, [], api => api.getVariantTypes()); + // eager: adding a variant defaults its type to Unspecified Variant, so the list + // must already be loaded when the user picks an entry (nothing reads it before then) + return projectContext.getOrAddAsync(variantTypesSymbol, [], api => api.getVariantTypes(), {eager: true}); } /** Unspecified Variant — the type FLEx assigns when none is chosen (well-known guid) */ diff --git a/frontend/viewer/tests/variants.test.ts b/frontend/viewer/tests/variants.test.ts new file mode 100644 index 0000000000..e1600ebe90 --- /dev/null +++ b/frontend/viewer/tests/variants.test.ts @@ -0,0 +1,80 @@ +import {expect, test} from '@playwright/test'; +import {BrowsePage} from './browse-page'; + +const UNSPECIFIED_VARIANT_TYPE_ID = '3942addb-99fd-43e9-ab7d-99025ceb0d4e'; +const DIALECTAL_VARIANT_TYPE_ID = '024b62c9-93b3-41a0-ab19-587a0030219a'; + +type VariantLink = {mainEntryId: string, variantEntryId: string, types: {id: string}[]}; + +test.describe('Variants', () => { + + test('adding a variant-of link via UI is saved to backend', async ({page}) => { + const browsePage = new BrowsePage(page); + await browsePage.goto(); + + const timestamp = Date.now().toString().slice(-6); + const main = await browsePage.api.createEntryWithHeadword(`mainentry${timestamp}`); + const variant = await browsePage.api.createEntryWithHeadword(`variantentry${timestamp}`); + + await browsePage.selectEntryByFilter(variant.headword); + + // add the link via the Variant of field's picker + const variantOfField = page.locator('[style*="grid-area: variantOf"]'); + await variantOfField.getByRole('button', {name: 'Variant of'}).click(); + const dialog = page.getByRole('dialog'); + await dialog.getByPlaceholder(/find (entry|word)/i).fill(main.headword); + await dialog.getByText(main.headword).first().click(); + await dialog.getByRole('button', {name: /select (entry|word)/i}).click(); + + // the link shows in the field and lands in the backend with FLEx's default type + await expect(variantOfField.getByText(main.headword)).toBeVisible(); + await expect(async () => { + const entry = await browsePage.api.getEntry(variant.id) as {variantOf: VariantLink[]}; + expect(entry.variantOf).toHaveLength(1); + expect(entry.variantOf[0].mainEntryId).toBe(main.id); + expect(entry.variantOf[0].types.map(t => t.id)).toContain(UNSPECIFIED_VARIANT_TYPE_ID); + }).toPass({timeout: 5000}); + + // toggle a variant type through the link's menu + await variantOfField.getByText(main.headword).click(); + await page.getByRole('menuitem', {name: 'Variant type'}).click(); + await page.getByRole('menuitemcheckbox', {name: 'Dialectal Variant'}).click(); + await page.keyboard.press('Escape'); + + await expect(async () => { + const entry = await browsePage.api.getEntry(variant.id) as {variantOf: VariantLink[]}; + expect(entry.variantOf[0].types.map(t => t.id)).toContain(DIALECTAL_VARIANT_TYPE_ID); + }).toPass({timeout: 5000}); + + // the menu reflects the toggle when reopened (guards the nested-state re-render) + await variantOfField.getByText(main.headword).click(); + await page.getByRole('menuitem', {name: 'Variant type'}).click(); + await expect(page.getByRole('menuitemcheckbox', {name: 'Dialectal Variant'})).toHaveAttribute('aria-checked', 'true'); + await page.keyboard.press('Escape'); + }); + + test('adding a variant via the main entry saves the reverse link', async ({page}) => { + const browsePage = new BrowsePage(page); + await browsePage.goto(); + + const timestamp = Date.now().toString().slice(-6); + const main = await browsePage.api.createEntryWithHeadword(`mainentryb${timestamp}`); + const variant = await browsePage.api.createEntryWithHeadword(`variantentryb${timestamp}`); + + await browsePage.selectEntryByFilter(main.headword); + + const variantsField = page.locator('[style*="grid-area: variants"]'); + await variantsField.getByRole('button', {name: 'Variant', exact: true}).click(); + const dialog = page.getByRole('dialog'); + await dialog.getByPlaceholder(/find (entry|word)/i).fill(variant.headword); + await dialog.getByText(variant.headword).first().click(); + await dialog.getByRole('button', {name: /select (entry|word)/i}).click(); + + await expect(variantsField.getByText(variant.headword)).toBeVisible(); + await expect(async () => { + const entry = await browsePage.api.getEntry(main.id) as {variants: VariantLink[]}; + expect(entry.variants).toHaveLength(1); + expect(entry.variants[0].variantEntryId).toBe(variant.id); + }).toPass({timeout: 5000}); + }); +});