Ver código fonte

feat: switch site locale

NGPixel 2 anos atrás
pai
commit
2587778e52

+ 1 - 0
server/core/kernel.mjs

@@ -82,6 +82,7 @@ export default {
 
     await WIKI.auth.activateStrategies()
     await WIKI.db.commentProviders.initProvider()
+    await WIKI.db.locales.reloadCache()
     await WIKI.db.sites.reloadCache()
     await WIKI.db.storage.initTargets()
 

+ 1 - 11
server/graph/resolvers/localization.mjs

@@ -4,17 +4,7 @@ import _ from 'lodash-es'
 export default {
   Query: {
     async locales(obj, args, context, info) {
-      let remoteLocales = await WIKI.cache.get('locales')
-      let localLocales = await WIKI.db.locales.query().select('code', 'isRTL', 'language', 'name', 'nativeName', 'createdAt', 'updatedAt', 'completeness')
-      remoteLocales = remoteLocales || localLocales
-      return _.map(remoteLocales, rl => {
-        let isInstalled = _.some(localLocales, ['code', rl.code])
-        return {
-          ...rl,
-          isInstalled,
-          installDate: isInstalled ? _.find(localLocales, ['code', rl.code]).updatedAt : null
-        }
-      })
+      return WIKI.db.locales.getLocales({ cache: false })
     },
     localeStrings (obj, args, context, info) {
       return WIKI.db.locales.getStrings(args.locale)

+ 5 - 0
server/graph/resolvers/site.mjs

@@ -323,5 +323,10 @@ export default {
         return generateError(err)
       }
     }
+  },
+  SiteLocales: {
+    async active (obj, args, context) {
+      return obj.active.map(l => WIKI.cache.get(`locale:${l}`))
+    }
   }
 }

+ 0 - 2
server/graph/schemas/localization.graphql

@@ -28,8 +28,6 @@ type LocalizationLocale {
   completeness: Int
   code: String
   createdAt: Date
-  installDate: Date
-  isInstalled: Boolean
   isRTL: Boolean
   language: String
   name: String

+ 1 - 1
server/graph/schemas/site.graphql

@@ -99,7 +99,7 @@ type SiteUploads {
 
 type SiteLocales {
   primary: String
-  active: [String]
+  active: [LocalizationLocale]
 }
 
 type SiteEditors {

+ 15 - 0
server/models/locales.mjs

@@ -100,11 +100,26 @@ export class Locale extends Model {
     }
   }
 
+  static async getLocales ({ cache = true } = {}) {
+    if (!WIKI.cache.has('locales') || !cache) {
+      const locales = await WIKI.db.locales.query().select('code', 'isRTL', 'language', 'name', 'nativeName', 'createdAt', 'updatedAt', 'completeness')
+      WIKI.cache.set('locales', locales)
+      for (const locale of locales) {
+        WIKI.cache.set(`locale:${locale.code}`, locale)
+      }
+    }
+    return WIKI.cache.get('locales')
+  }
+
   static async getStrings (locale) {
     const { strings } = await WIKI.db.locales.query().findOne('code', locale).column('strings')
     return strings
   }
 
+  static async reloadCache () {
+    await WIKI.db.locales.getLocales({ cache: false })
+  }
+
   static async getNavLocales({ cache = false } = {}) {
     return []
     // if (!WIKI.config.lang.namespacing) {

+ 1 - 1
ux/src/App.vue

@@ -143,7 +143,7 @@ router.beforeEach(async (to, from) => {
   }
 
   // -> Locale
-  if (!commonStore.desiredLocale || !siteStore.locales.active.includes(commonStore.desiredLocale)) {
+  if (!commonStore.desiredLocale || !siteStore.locales.active.some(l => l.code === commonStore.desiredLocale)) {
     commonStore.setLocale(siteStore.locales.primary)
   } else {
     applyLocale(commonStore.desiredLocale)

+ 43 - 0
ux/src/components/LocaleSelectorMenu.vue

@@ -0,0 +1,43 @@
+<template lang="pug">
+q-menu.translucent-menu(
+  auto-close
+  anchor='top right'
+  self='top left'
+  )
+  q-list(padding, style='min-width: 200px;')
+    q-item(
+      v-for='lang of siteStore.locales.active'
+      clickable
+      @click='commonStore.setLocale(lang.code)'
+      )
+      q-item-section(side)
+        q-avatar(rounded, :color='lang.code === commonStore.locale ? `secondary` : `primary`', text-color='white', size='sm')
+          .text-caption.text-uppercase: strong {{ lang.language }}
+      q-item-section
+        q-item-label {{ lang.nativeName }}
+        q-item-label(caption) {{ lang.name }}
+</template>
+
+<script setup>
+import { useI18n } from 'vue-i18n'
+import { useQuasar } from 'quasar'
+
+import { useCommonStore } from 'src/stores/common'
+import { useSiteStore } from 'src/stores/site'
+
+// QUASAR
+
+const $q = useQuasar()
+
+// STORES
+
+const commonStore = useCommonStore()
+const siteStore = useSiteStore()
+
+// I18N
+
+const { t } = useI18n()
+
+// METHODS
+
+</script>

+ 3 - 3
ux/src/layouts/AdminLayout.vue

@@ -25,7 +25,7 @@ q-layout.admin(view='hHh Lpr lff')
         q-btn.q-ml-md(flat, dense, icon='las la-times-circle', :label='t(`common.actions.exit`)' color='pink', to='/')
         q-btn.q-ml-md(flat, dense, icon='las la-language', :label='commonStore.locale' color='grey-4')
           q-menu.translucent-menu(auto-close, anchor='bottom right', self='top right')
-            q-list(separator)
+            q-list(separator, padding)
               q-item(
                 v-for='lang of adminStore.locales'
                 clickable
@@ -35,8 +35,8 @@ q-layout.admin(view='hHh Lpr lff')
                   q-avatar(rounded, :color='lang.code === commonStore.locale ? `secondary` : `primary`', text-color='white', size='sm')
                     .text-caption.text-uppercase: strong {{ lang.language }}
                 q-item-section
-                  q-item-label {{ lang.name }}
-                  q-item-label(caption) {{ lang.nativeName }}
+                  q-item-label {{ lang.nativeName }}
+                  q-item-label(caption) {{ lang.name }}
         account-menu
   q-drawer.admin-sidebar(v-model='leftDrawerOpen', show-if-above, bordered)
     q-scroll-area.admin-nav(

+ 6 - 2
ux/src/layouts/MainLayout.vue

@@ -14,10 +14,11 @@ q-layout(view='hHh Lpr lff')
         icon='las la-globe'
         color='blue-7'
         text-color='blue-2'
-        label='EN'
-        aria-label='EN'
+        :label='commonStore.locale'
+        :aria-label='commonStore.locale'
         size='sm'
         )
+        locale-selector-menu
       q-separator(vertical)
       q-btn.q-px-sm.col(
         flat
@@ -87,6 +88,7 @@ import { computed, onMounted, reactive, ref, watch } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { useI18n } from 'vue-i18n'
 
+import { useCommonStore } from 'src/stores/common'
 import { useEditorStore } from 'src/stores/editor'
 import { useFlagsStore } from 'src/stores/flags'
 import { useSiteStore } from 'src/stores/site'
@@ -96,6 +98,7 @@ import { useUserStore } from 'src/stores/user'
 
 import FooterNav from 'src/components/FooterNav.vue'
 import HeaderNav from 'src/components/HeaderNav.vue'
+import LocaleSelectorMenu from 'src/components/LocaleSelectorMenu.vue'
 import MainOverlayDialog from 'src/components/MainOverlayDialog.vue'
 
 // QUASAR
@@ -104,6 +107,7 @@ const $q = useQuasar()
 
 // STORES
 
+const commonStore = useCommonStore()
 const editorStore = useEditorStore()
 const flagsStore = useFlagsStore()
 const siteStore = useSiteStore()

+ 2 - 2
ux/src/stores/admin.js

@@ -1,6 +1,6 @@
 import { defineStore } from 'pinia'
 import gql from 'graphql-tag'
-import { clone, cloneDeep } from 'lodash-es'
+import { clone, cloneDeep, sortBy } from 'lodash-es'
 import semverGte from 'semver/functions/gte'
 
 /* global APOLLO_CLIENT */
@@ -48,7 +48,7 @@ export const useAdminStore = defineStore('admin', {
           }
         `
       })
-      this.locales = cloneDeep(resp?.data?.locales ?? [])
+      this.locales = sortBy(cloneDeep(resp?.data?.locales ?? []), ['nativeName', 'name'])
     },
     async fetchInfo () {
       const resp = await APOLLO_CLIENT.query({

+ 14 - 4
ux/src/stores/site.js

@@ -1,6 +1,6 @@
 import { defineStore } from 'pinia'
 import gql from 'graphql-tag'
-import { clone } from 'lodash-es'
+import { clone, sortBy } from 'lodash-es'
 
 import { useUserStore } from './user'
 
@@ -39,7 +39,12 @@ export const useSiteStore = defineStore('site', {
     },
     locales: {
       primary: 'en',
-      active: ['en']
+      active: [{
+        code: 'en',
+        language: 'en',
+        name: 'English',
+        nativeName: 'English'
+      }]
     },
     theme: {
       dark: false,
@@ -134,7 +139,12 @@ export const useSiteStore = defineStore('site', {
                 id
                 locales {
                   primary
-                  active
+                  active {
+                    code
+                    language
+                    name
+                    nativeName
+                  }
                 }
                 logoText
                 theme {
@@ -182,7 +192,7 @@ export const useSiteStore = defineStore('site', {
             },
             locales: {
               primary: clone(siteInfo.locales.primary),
-              active: clone(siteInfo.locales.active)
+              active: sortBy(clone(siteInfo.locales.active), ['nativeName', 'name'])
             },
             theme: {
               ...this.theme,