浏览代码

feat: sideloading + locales nav menu

Nick 6 年之前
父节点
当前提交
28cf67cdaa

+ 14 - 16
client/components/common/nav-header.vue

@@ -137,17 +137,17 @@
             icon
             )
             v-icon(color='grey') search
-          //- v-menu(offset-y, left, transition='slide-y-transition')
-          //-   v-tooltip(bottom, slot='activator')
-          //-     v-btn(icon, slot='activator')
-          //-       v-icon(color='grey') language
-          //-     span Language
-          //-   v-list.py-0
-          //-     template(v-for='(lc, idx) of locales')
-          //-       v-list-tile(@click='changeLocale(lc)')
-          //-         v-list-tile-action: v-chip(:color='lc.code === $i18n.i18next.language ? `blue` : `grey`', small, label, dark) {{lc.code.toUpperCase()}}
-          //-         v-list-tile-title {{lc.name}}
-          //-       v-divider.my-0(v-if='idx < locales.length - 1')
+          v-menu(offset-y, left, transition='slide-y-transition', v-if='mode === `view` && locales.length > 0')
+            v-tooltip(bottom, slot='activator')
+              v-btn(icon, slot='activator')
+                v-icon(color='grey') language
+              span Language
+            v-list.py-0
+              template(v-for='(lc, idx) of locales')
+                v-list-tile(@click='changeLocale(lc)')
+                  v-list-tile-action: v-chip(:color='lc.code === $i18n.i18next.language ? `blue` : `grey`', small, label, dark) {{lc.code.toUpperCase()}}
+                  v-list-tile-title {{lc.name}}
+                v-divider.my-0(v-if='idx < locales.length - 1')
           v-tooltip(bottom, v-if='isAuthenticated && isAdmin')
             v-btn.btn-animate-rotate(icon, href='/a', slot='activator')
               v-icon(color='grey') settings
@@ -196,6 +196,8 @@ import { get, sync } from 'vuex-pathify'
 import _ from 'lodash'
 import Cookies from 'js-cookie'
 
+/* global siteLangs */
+
 export default {
   components: {
     PageDelete: () => import('./page-delete.vue')
@@ -217,11 +219,7 @@ export default {
       searchAdvMenuShown: false,
       newPageModal: false,
       deletePageModal: false,
-      locales: [
-        { code: 'en', name: 'English' },
-        { code: 'fr', name: 'Français' },
-        { code: 'es', name: 'Español' }
-      ]
+      locales: siteLangs
     }
   },
   computed: {

+ 8 - 0
config.sample.yml

@@ -105,3 +105,11 @@ uploads:
   maxFileSize: 5242880
   # Maximum file uploads per request (default: 20)
   maxFiles: 10
+
+# ---------------------------------------------------------------------
+# Offline Mode
+# ---------------------------------------------------------------------
+# If your server cannot access the internet. Set to true and manually
+# download the offline files for sideloading.
+
+offline: false

+ 1 - 1
dev/templates/master.pug

@@ -29,7 +29,7 @@ html
 
     //- Site Properties
     script.
-      var siteConfig = !{JSON.stringify({ title: config.title, theme: config.theming.theme, darkMode: config.theming.darkMode, lang: config.lang.code, rtl: config.lang.rtl, company: config.company })}
+      var siteConfig = !{JSON.stringify(siteConfig)}; var siteLangs = !{JSON.stringify(langs)}
 
     //- CSS
     <% for (var index in htmlWebpackPlugin.files.css) { %>

+ 4 - 0
server/app/data.yml

@@ -24,6 +24,7 @@ defaults:
     uploads:
       maxFileSize: 5242880
       maxFiles: 10
+    offline: false
     # DB defaults
     graphEndpoint: 'https://graph.requarks.io'
     lang:
@@ -63,12 +64,15 @@ jobs:
   purgeUploads:
     onInit: true
     schedule: PT15M
+    offlineSkip: false
   syncGraphLocales:
     onInit: true
     schedule: P1D
+    offlineSkip: true
   syncGraphUpdates:
     onInit: true
     schedule: P1D
+    offlineSkip: true
 groups:
   defaultPermissions:
     - 'read:pages'

+ 1 - 0
server/core/kernel.js

@@ -34,6 +34,7 @@ module.exports = {
       await this.initTelemetry()
       WIKI.cache = require('./cache').init()
       WIKI.scheduler = require('./scheduler').init()
+      WIKI.sideloader = require('./sideloader').init()
       WIKI.events = new EventEmitter()
     } catch (err) {
       WIKI.logger.error(err)

+ 5 - 1
server/core/scheduler.js

@@ -87,7 +87,6 @@ class Job {
   }
 }
 
-
 module.exports = {
   jobs: [],
   init() {
@@ -95,6 +94,11 @@ module.exports = {
   },
   start() {
     _.forOwn(WIKI.data.jobs, (queueParams, queueName) => {
+      if (WIKI.config.offline && queueParams.offlineSkip) {
+        WIKI.logger.warn(`Skipping job ${queueName} because offline mode is enabled. [SKIPPED]`)
+        return
+      }
+
       const schedule = (configHelper.isValidDurationString(queueParams.schedule)) ? queueParams.schedule : _.get(WIKI.config, queueParams.schedule)
       this.registerJob({
         name: _.kebabCase(queueName),

+ 76 - 0
server/core/sideloader.js

@@ -0,0 +1,76 @@
+const fs = require('fs-extra')
+const path = require('path')
+const _ = require('lodash')
+
+/* global WIKI */
+
+module.exports = {
+  async init () {
+    if (!WIKI.config.offline) {
+      return
+    }
+
+    const sideloadExists = await fs.pathExists(path.join(WIKI.ROOTPATH, 'data/sideload'))
+
+    if (!sideloadExists) {
+      return
+    }
+
+    WIKI.logger.info('Sideload directory detected. Looking for packages...')
+
+    try {
+      await this.importLocales()
+    } catch (err) {
+      WIKI.logger.warn(err)
+    }
+  },
+  async importLocales() {
+    const localeExists = await fs.pathExists(path.join(WIKI.ROOTPATH, 'data/sideload/locales.json'))
+    if (localeExists) {
+      WIKI.logger.info('Found locales master file. Importing locale packages...')
+      let importedLocales = 0
+
+      const locales = await fs.readJson(path.join(WIKI.ROOTPATH, 'data/sideload/locales.json'))
+      if (locales && _.has(locales, 'data.localization.locales')) {
+        for (const locale of locales.data.localization.locales) {
+          try {
+            const localeData = await fs.readJson(path.join(WIKI.ROOTPATH, `data/sideload/${locale.code}.json`))
+            if (localeData) {
+              WIKI.logger.info(`Importing ${locale.name} locale package...`)
+
+              let lcObj = {}
+              _.forOwn(localeData, (value, key) => {
+                if (_.includes(key, '::')) { return }
+                if (_.isEmpty(value)) { value = key }
+                _.set(lcObj, key.replace(':', '.'), value)
+              })
+
+              const localeExists = await WIKI.models.locales.query().select('code').where('code', locale.code).first()
+              if (localeExists) {
+                await WIKI.models.locales.query().update({
+                  code: locale.code,
+                  strings: lcObj,
+                  isRTL: locale.isRTL,
+                  name: locale.name,
+                  nativeName: locale.nativeName
+                }).where('code', locale.code)
+              } else {
+                await WIKI.models.locales.query().insert({
+                  code: locale.code,
+                  strings: lcObj,
+                  isRTL: locale.isRTL,
+                  name: locale.name,
+                  nativeName: locale.nativeName
+                })
+              }
+              importedLocales++
+            }
+          } catch (err) {
+            // skip
+          }
+        }
+        WIKI.logger.info(`Imported ${importedLocales} locale packages: [COMPLETED]`)
+      }
+    }
+  }
+}

+ 1 - 1
server/core/telemetry.js

@@ -28,7 +28,7 @@ module.exports = {
     })
     WIKI.telemetry = this
 
-    if (_.get(WIKI.config, 'telemetry.isEnabled', false) === true) {
+    if (_.get(WIKI.config, 'telemetry.isEnabled', false) === true && WIKI.config.offline !== true) {
       this.enabled = true
       this.sendOSInfo()
     }

+ 2 - 0
server/graph/resolvers/localization.js

@@ -66,6 +66,8 @@ module.exports = {
         await WIKI.lang.setCurrentLocale(args.locale)
         await WIKI.lang.refreshNamespaces()
 
+        await WIKI.cache.del('nav:locales')
+
         return {
           responseResult: graphHelper.generateSuccess('Locale config updated')
         }

+ 13 - 3
server/master.js

@@ -105,9 +105,6 @@ module.exports = async () => {
   // ----------------------------------------
 
   app.locals.basedir = WIKI.ROOTPATH
-  app.locals._ = require('lodash')
-  app.locals.moment = require('moment')
-  app.locals.moment.locale(WIKI.config.lang.code)
   app.locals.config = WIKI.config
   app.locals.pageMeta = {
     title: '',
@@ -146,6 +143,19 @@ module.exports = async () => {
   // Routing
   // ----------------------------------------
 
+  app.use(async (req, res, next) => {
+    res.locals.siteConfig = {
+      title: WIKI.config.title,
+      theme: WIKI.config.theming.theme,
+      darkMode: WIKI.config.theming.darkMode,
+      lang: WIKI.config.lang.code,
+      rtl: WIKI.config.lang.rtl,
+      company: WIKI.config.company
+    }
+    res.locals.langs = await WIKI.models.locales.getNavLocales({ cache: true })
+    next()
+  })
+
   app.use('/', ctrl.auth)
   app.use('/', ctrl.upload)
   app.use('/', ctrl.common)

+ 25 - 0
server/models/locales.js

@@ -1,5 +1,7 @@
 const Model = require('objection').Model
 
+/* global WIKI */
+
 /**
  * Locales model
  */
@@ -34,4 +36,27 @@ module.exports = class Locale extends Model {
     this.createdAt = new Date().toISOString()
     this.updatedAt = new Date().toISOString()
   }
+
+  static async getNavLocales({ cache = false } = {}) {
+    if (!WIKI.config.lang.namespacing) {
+      return []
+    }
+
+    if (cache) {
+      const navLocalesCached = await WIKI.cache.get('nav:locales')
+      if (navLocalesCached) {
+        return navLocalesCached
+      }
+    }
+    const navLocales = await WIKI.models.locales.query().select('code', 'nativeName AS name').whereIn('code', WIKI.config.lang.namespaces).orderBy('code')
+    if (navLocales) {
+      if (cache) {
+        await WIKI.cache.set('nav:locales', navLocales, 300)
+      }
+      return navLocales
+    } else {
+      WIKI.logger.warn('Site Locales for navigation are missing or corrupted.')
+      return []
+    }
+  }
 }

+ 1 - 1
server/views/master.pug

@@ -29,7 +29,7 @@ html
     
     //- Site Properties
     script.
-      var siteConfig = !{JSON.stringify({ title: config.title, theme: config.theming.theme, darkMode: config.theming.darkMode, lang: config.lang.code, rtl: config.lang.rtl, company: config.company })}
+      var siteConfig = !{JSON.stringify(siteConfig)}; var siteLangs = !{JSON.stringify(langs)}
     
     //- CSS