150 lines
3.7 KiB
TypeScript
150 lines
3.7 KiB
TypeScript
import { watch, type Ref } from 'vue'
|
|
import { useRoute, useRouter, type LocationQueryRaw } from 'vue-router'
|
|
import { locale, t } from '@/i18n'
|
|
import { useLocalizedOverlay } from '@/i18n/presentation'
|
|
import AddTranslationDialog, {
|
|
type AddTranslationResult,
|
|
} from '@/components/AddTranslationDialog.vue'
|
|
import type { Article, CoverageEntry } from '@/composables/useArticles'
|
|
import { ADD_TRANSLATION_DIALOG as DIALOG_NAME } from '@/lib/addTranslationLocation'
|
|
import { holds } from '@/lib/editorCapabilities'
|
|
import type { VersionRow } from '@/lib/editorVersions'
|
|
import { languageName, type SiteLanguage } from '@/lib/siteLanguages'
|
|
|
|
interface TranslationOptions {
|
|
article: Ref<Article | null>
|
|
loaded: Ref<boolean>
|
|
languages: () => SiteLanguage[]
|
|
refetchLanguages: () => Promise<SiteLanguage[]>
|
|
switchTo: (row: VersionRow, announcement?: string) => Promise<void>
|
|
onGone: () => void
|
|
}
|
|
|
|
function versionRowFor(id: number, lang: string): VersionRow {
|
|
return {
|
|
key: `version-${id}`,
|
|
lang,
|
|
name: languageName(lang, locale.value),
|
|
code: lang.toUpperCase(),
|
|
articleId: id,
|
|
title: '',
|
|
current: false,
|
|
online: false,
|
|
readOnly: false,
|
|
languageDisabled: false,
|
|
addTranslation: false,
|
|
}
|
|
}
|
|
|
|
function entryOf(created: Article, lang: string): CoverageEntry {
|
|
return {
|
|
id: created.id,
|
|
lang,
|
|
title: created.title,
|
|
is_online: created.is_online,
|
|
language_enabled: true,
|
|
capabilities: created.capabilities,
|
|
}
|
|
}
|
|
|
|
export function useEditorTranslation(options: TranslationOptions) {
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const overlay = useLocalizedOverlay()
|
|
let instance: ReturnType<typeof overlay.create> | null = null
|
|
|
|
function strippedQuery(): LocationQueryRaw {
|
|
const rest = { ...route.query }
|
|
delete rest.dialog
|
|
delete rest.lang
|
|
return rest
|
|
}
|
|
|
|
function stripParameters() {
|
|
if (route.query.dialog !== undefined || route.query.lang !== undefined) {
|
|
return router.replace({ query: strippedQuery() })
|
|
}
|
|
return undefined
|
|
}
|
|
|
|
function open(lang?: string) {
|
|
return router.push({
|
|
query: { ...route.query, dialog: DIALOG_NAME, ...(lang ? { lang } : {}) },
|
|
})
|
|
}
|
|
|
|
async function settle(result: AddTranslationResult | undefined) {
|
|
if (!result) {
|
|
await stripParameters()
|
|
return
|
|
}
|
|
if (result.kind === 'gone') {
|
|
await stripParameters()
|
|
options.onGone()
|
|
return
|
|
}
|
|
await stripParameters()
|
|
if (result.kind === 'open') {
|
|
await options.switchTo(versionRowFor(result.id, result.lang))
|
|
return
|
|
}
|
|
const current = options.article.value
|
|
if (current) {
|
|
options.article.value = {
|
|
...current,
|
|
translations: [
|
|
...(current.translations ?? []),
|
|
entryOf(result.article, result.lang),
|
|
],
|
|
}
|
|
}
|
|
const name = languageName(result.lang, locale.value)
|
|
await options.switchTo(
|
|
versionRowFor(result.article.id, result.lang),
|
|
t('{0} draft created', [name]),
|
|
)
|
|
}
|
|
|
|
async function show(lang: string | undefined) {
|
|
const created = overlay.create(AddTranslationDialog, {
|
|
props: {
|
|
get article() {
|
|
return options.article.value!
|
|
},
|
|
get languages() {
|
|
return options.languages()
|
|
},
|
|
initialLang: lang,
|
|
refetchLanguages: options.refetchLanguages,
|
|
},
|
|
})
|
|
instance = created
|
|
const result = (await created.open()) as AddTranslationResult | undefined
|
|
instance = null
|
|
await settle(result)
|
|
}
|
|
|
|
watch(
|
|
() => [route.query.dialog, route.query.lang, options.loaded.value] as const,
|
|
([dialog, lang, loaded]) => {
|
|
if (!loaded) {
|
|
return
|
|
}
|
|
if (dialog !== DIALOG_NAME) {
|
|
instance?.close()
|
|
return
|
|
}
|
|
if (!holds(options.article.value?.capabilities, 'create_translation')) {
|
|
stripParameters()
|
|
return
|
|
}
|
|
if (!instance) {
|
|
show(typeof lang === 'string' ? lang : undefined)
|
|
}
|
|
},
|
|
{ immediate: true },
|
|
)
|
|
|
|
return { open }
|
|
}
|