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/server/models/locales.mjs

147 lines
4.6 KiB

import { Model } from 'objection'
import { find } from 'lodash-es'
import { stat, readFile } from 'node:fs/promises'
import path from 'node:path'
import { DateTime } from 'luxon'
/**
* Locales model
*/
export class Locale extends Model {
static get tableName() { return 'locales' }
static get idColumn() { return 'code' }
static get jsonSchema () {
return {
type: 'object',
required: ['code', 'name'],
properties: {
code: {type: 'string'},
isRTL: {type: 'boolean', default: false},
name: {type: 'string'},
nativeName: {type: 'string'},
createdAt: {type: 'string'},
updatedAt: {type: 'string'},
completeness: {type: 'integer'}
}
}
}
static get jsonAttributes() {
return ['strings']
}
$beforeUpdate() {
this.updatedAt = new Date().toISOString()
}
$beforeInsert() {
this.createdAt = new Date().toISOString()
this.updatedAt = new Date().toISOString()
}
static async refreshFromDisk ({ force = false } = {}) {
try {
const localesMeta = (await import(`../locales/metadata.mjs`)).default
WIKI.logger.info(`Found ${localesMeta.languages.length} locales: [ OK ]`)
const dbLocales = await WIKI.db.locales.query().select('code', 'updatedAt')
let localFilesSkipped = 0
for (const lang of localesMeta.languages) {
// -> Build filename
const langFilenameParts = [lang.language]
if (lang.region) {
langFilenameParts.push(lang.region)
}
if (lang.script) {
langFilenameParts.push(lang.script)
}
const langFilename = langFilenameParts.join('-')
// -> Get DB version
const dbLang = find(dbLocales, ['code', langFilename])
// -> Get File version
const flPath = path.join(WIKI.SERVERPATH, `locales/${langFilename}.json`)
try {
const flStat = await stat(flPath)
const flUpdatedAt = DateTime.fromJSDate(flStat.mtime)
// -> Load strings
if (!dbLang || DateTime.fromJSDate(dbLang.updatedAt) < flUpdatedAt || force) {
WIKI.logger.debug(`Loading locale ${langFilename} into DB...`)
const flStrings = JSON.parse(await readFile(flPath, 'utf8'))
await WIKI.db.locales.query().insert({
code: langFilename,
name: lang.name,
nativeName: lang.localizedName,
language: lang.language,
region: lang.region,
script: lang.script,
isRTL: lang.isRtl,
strings: flStrings
}).onConflict('code').merge(['strings', 'updatedAt'])
} else {
WIKI.logger.debug(`Locale ${langFilename} is newer in the DB. Skipping disk version. [ OK ]`)
}
} catch (err) {
localFilesSkipped++
WIKI.logger.debug(`Locale ${langFilename} not found on disk. Missing strings file. [ SKIPPED ]`)
}
}
if (localFilesSkipped > 0) {
WIKI.logger.info(`${localFilesSkipped} locales were defined in the metadata file but not found on disk. [ SKIPPED ]`)
}
} catch (err) {
WIKI.logger.warn(`Failed to load locales from disk: [ FAILED ]`)
WIKI.logger.warn(err)
return false
}
}
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) {
// return []
// }
// if (cache) {
// const navLocalesCached = await WIKI.cache.get('nav:locales')
// if (navLocalesCached) {
// return navLocalesCached
// }
// }
// const navLocales = await WIKI.db.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 []
// }
}
}