You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wiki/ux/src/pages/AdminLocale.vue

367 lines
9.6 KiB

<template lang='pug'>
q-page.admin-locale
.row.q-pa-md.items-center
.col-auto
img.admin-icon.animated.fadeInLeft(src='/_assets/icons/fluent-language.svg')
.col.q-pl-md
.text-h5.text-primary.animated.fadeInLeft {{ t('admin.locale.title') }}
.text-subtitle1.text-grey.animated.fadeInLeft.wait-p2s {{ t('admin.locale.subtitle') }}
.col-auto.flex
q-btn.q-mr-md(
icon='las la-download'
:label='t(`admin.locale.downloadNew`)'
unelevated
color='primary'
:disabled='state.loading > 0'
@click='installNewLocale'
)
q-separator.q-mr-md(vertical)
q-btn.q-mr-sm.acrylic-btn(
icon='las la-question-circle'
flat
color='grey'
:aria-label='t(`common.actions.viewDocs`)'
:href='siteStore.docsBase + `/admin/localisation`'
target='_blank'
type='a'
)
q-tooltip {{ t(`common.actions.viewDocs`) }}
q-btn.q-mr-sm.acrylic-btn(
icon='las la-redo-alt'
flat
color='secondary'
:loading='state.loading > 0'
:aria-label='t(`common.actions.refresh`)'
@click='load'
)
q-tooltip {{ t(`common.actions.refresh`) }}
q-btn(
unelevated
icon='mdi-check'
:label='t(`common.actions.apply`)'
color='secondary'
@click='save'
:disabled='state.loading > 0'
)
q-separator(inset)
.row.q-pa-md.q-col-gutter-md
.col-12.col-lg-7
//- -----------------------
//- Locale Options
//- -----------------------
q-card.q-pb-sm
q-card-section
.text-subtitle1 {{t('admin.locale.settings')}}
q-item
blueprint-icon(icon='translation')
q-item-section
q-item-label {{state.namespacing ? t(`admin.locale.base.labelWithNS`) : t(`admin.locale.base.label`)}}
q-item-label(caption) {{t(`admin.locale.base.hint`)}}
q-item-section
q-select(
outlined
v-model='state.selectedLocale'
:options='installedLocales'
option-value='code'
option-label='name'
emit-value
map-options
dense
:aria-label='t(`admin.locale.base.label`)'
)
q-separator.q-my-sm(inset)
q-item(tag='label')
blueprint-icon(icon='unit')
q-item-section
q-item-label {{t(`admin.locale.namespaces.label`)}}
q-item-label(caption) {{t(`admin.locale.namespaces.hint`)}}
q-item-section(avatar)
q-toggle(
v-model='state.namespacing'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='t(`admin.locale.namespaces.label`)'
)
q-item
q-item-section
q-card.bg-info.text-white.rounded-borders(flat)
q-card-section.items-center(horizontal)
q-card-section.col-auto.q-pr-none
q-icon(name='las la-info-circle', size='sm')
q-card-section
span {{ t('admin.locale.namespacingPrefixWarning.title', { langCode: state.selectedLocale }) }}
.text-caption.text-yellow-1 {{ t('admin.locale.namespacingPrefixWarning.subtitle') }}
.col-12.col-lg-5
//- -----------------------
//- Namespacing
//- -----------------------
q-card.q-pb-sm(v-if='state.namespacing')
q-card-section
.text-subtitle1 {{t('admin.locale.activeNamespaces')}}
q-item(
v-for='(lc, idx) of installedLocales'
:key='lc.code'
:tag='lc.code !== state.selectedLocale ? `label` : null'
)
blueprint-icon(:text='lc.code')
q-item-section
q-item-label {{lc.name}}
q-item-label(caption) {{lc.nativeName}}
q-item-section(avatar)
q-toggle(
:disable='lc.code === state.selectedLocale'
v-model='state.namespaces'
:val='lc.code'
color='primary'
checked-icon='las la-check'
unchecked-icon='las la-times'
:aria-label='lc.name'
)
.q-pa-md.text-center.gt-md(v-else)
img(src='/_assets/illustrations/undraw_world.svg', style='width: 80%;')
//- q-separator.q-my-sm(inset)
//- q-item
//- blueprint-icon(icon='test-passed')
//- q-item-section
//- q-item-label {{t(`admin.locale.activeNamespaces.label`)}}
//- q-item-label(caption) {{t(`admin.locale.activeNamespaces.hint`)}}
//- q-item-section
//- q-select(
//- outlined
//- :disable='!namespacing'
//- v-model='namespaces'
//- :options='installedLocales'
//- multiple
//- use-chips
//- option-value='code'
//- option-label='name'
//- emit-value
//- map-options
//- dense
//- :aria-label='t(`admin.locale.activeNamespaces.label`)'
//- )
</template>
<script setup>
import gql from 'graphql-tag'
import { cloneDeep, filter } from 'lodash-es'
import LocaleInstallDialog from '../components/LocaleInstallDialog.vue'
import { useI18n } from 'vue-i18n'
import { useMeta, useQuasar } from 'quasar'
import { computed, onMounted, reactive, watch } from 'vue'
import { useAdminStore } from 'src/stores/admin'
import { useSiteStore } from 'src/stores/site'
// QUASAR
const $q = useQuasar()
// STORES
const adminStore = useAdminStore()
const siteStore = useSiteStore()
// I18N
const { t } = useI18n()
// META
useMeta({
title: t('admin.locale.title')
})
// DATA
const state = reactive({
loading: 0,
locales: [],
selectedLocale: 'en',
namespacing: false,
namespaces: []
})
// COMPUTED
const installedLocales = computed(() => {
return filter(state.locales, ['isInstalled', true])
})
// WATCHERS
watch(() => adminStore.currentSiteId, (newValue) => {
load()
})
watch(() => state.selectedLocale, (newValue) => {
if (!state.namespaces.includes(newValue)) {
state.namespaces.push(newValue)
}
})
// METHODS
function installNewLocale () {
$q.dialog({
component: LocaleInstallDialog
}).onOk(() => {
this.load()
})
}
async function load () {
state.loading++
$q.loading.show()
const resp = await APOLLO_CLIENT.query({
query: gql`
query getLocales ($siteId: UUID!) {
locales {
availability
code
createdAt
isInstalled
installDate
isRTL
name
nativeName
updatedAt
}
siteById(
id: $siteId
) {
id
locale
localeNamespacing
localeNamespaces
}
}
`,
variables: {
siteId: adminStore.currentSiteId
},
fetchPolicy: 'network-only'
})
state.locales = cloneDeep(resp?.data?.locales)
state.selectedLocale = cloneDeep(resp?.data?.siteById?.locale)
state.namespacing = cloneDeep(resp?.data?.siteById?.localeNamespacing)
state.namespaces = cloneDeep(resp?.data?.siteById?.localeNamespaces)
if (!state.namespaces.includes(state.selectedLocale)) {
state.namespaces.push(state.selectedLocale)
}
$q.loading.hide()
state.loading--
}
async function download (lc) {
lc.isDownloading = true
const respRaw = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation downloadLocale ($locale: String!) {
localization {
downloadLocale (locale: $locale) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
locale: lc.code
}
})
const resp = respRaw?.data?.localization?.downloadLocale?.responseResult || {}
if (resp.succeeded) {
lc.isDownloading = false
lc.isInstalled = true
lc.updatedAt = new Date().toISOString()
lc.installDate = lc.updatedAt
$q.notify({
message: `Locale ${lc.name} has been installed successfully.`,
type: 'positive'
})
} else {
$q.notify({
type: 'negative',
message: resp.message
})
}
state.isDownloading = false
}
async function save () {
state.loading = true
const respRaw = await APOLLO_CLIENT.mutate({
mutation: gql`
mutation saveLocaleSettings (
$locale: String!
$autoUpdate: Boolean!
$namespacing: Boolean!
$namespaces: [String]!
) {
localization {
updateLocale(
locale: $locale
autoUpdate: $autoUpdate
namespacing: $namespacing
namespaces: $namespaces
) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`,
variables: {
locale: state.selectedLocale,
autoUpdate: state.autoUpdate,
namespacing: state.namespacing,
namespaces: state.namespaces
}
})
const resp = respRaw?.data?.localization?.updateLocale?.responseResult || {}
if (resp.succeeded) {
// Change UI language
this.$i18n.locale = state.selectedLocale
$q.notify({
type: 'positive',
message: 'Locale settings updated successfully.'
})
setTimeout(() => {
window.location.reload(true)
}, 1000)
} else {
$q.notify({
type: 'negative',
message: resp.message
})
}
state.loading = false
}
// MOUNTED
onMounted(() => {
if (adminStore.currentSiteId) {
load()
}
})
</script>