feqt(backend): Ported to site prebuild system
This commit is contained in:
parent
cc538e5df2
commit
cf6d30eeee
11 changed files with 33 additions and 156 deletions
|
@ -61,7 +61,7 @@ backend:
|
||||||
rmdb: 'node ./scripts/rmdb.mjs'
|
rmdb: 'node ./scripts/rmdb.mjs'
|
||||||
test: 'npx mocha --require mocha-steps tests/index.mjs'
|
test: 'npx mocha --require mocha-steps tests/index.mjs'
|
||||||
vbuild: *vbuild
|
vbuild: *vbuild
|
||||||
prebuild: 'node scripts/prebuild.mjs'
|
prebuild: &sitePrebuild 'node --conditions=internal --experimental-json-modules ./prebuild.mjs'
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
build: &nextBuild 'next build'
|
build: &nextBuild 'next build'
|
||||||
|
@ -71,7 +71,7 @@ dev:
|
||||||
develop: *nextDev
|
develop: *nextDev
|
||||||
i18n: "SITE=dev node --conditions=internal ../shared/prebuild/i18n-only.mjs"
|
i18n: "SITE=dev node --conditions=internal ../shared/prebuild/i18n-only.mjs"
|
||||||
lint: &nextLint 'next lint'
|
lint: &nextLint 'next lint'
|
||||||
prebuild: &nextPrebuild 'node --conditions=internal --experimental-json-modules ./prebuild.mjs'
|
prebuild: *sitePrebuild
|
||||||
serve: "pm2 start npm --name 'dev' -- run start"
|
serve: "pm2 start npm --name 'dev' -- run start"
|
||||||
start: &nextStart 'yarn prebuild && yarn dev'
|
start: &nextStart 'yarn prebuild && yarn dev'
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ lab:
|
||||||
i18n: 'SITE=lab node --conditions=internal ../shared/prebuild/i18n-only.mjs'
|
i18n: 'SITE=lab node --conditions=internal ../shared/prebuild/i18n-only.mjs'
|
||||||
e2e: &e2e 'yarn playwright test'
|
e2e: &e2e 'yarn playwright test'
|
||||||
lint: *nextLint
|
lint: *nextLint
|
||||||
prebuild: *nextPrebuild
|
prebuild: *sitePrebuild
|
||||||
start: *nextStart
|
start: *nextStart
|
||||||
|
|
||||||
org:
|
org:
|
||||||
|
@ -98,7 +98,7 @@ org:
|
||||||
develop: *nextDev
|
develop: *nextDev
|
||||||
i18n: 'SITE=org node --conditions=internal ../shared/prebuild/i18n-only.mjs'
|
i18n: 'SITE=org node --conditions=internal ../shared/prebuild/i18n-only.mjs'
|
||||||
lint: *nextLint
|
lint: *nextLint
|
||||||
prebuild: *nextPrebuild
|
prebuild: *sitePrebuild
|
||||||
start: *nextStart
|
start: *nextStart
|
||||||
|
|
||||||
sanity:
|
sanity:
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
"rmdb": "node ./scripts/rmdb.mjs",
|
"rmdb": "node ./scripts/rmdb.mjs",
|
||||||
"test": "npx mocha --require mocha-steps tests/index.mjs",
|
"test": "npx mocha --require mocha-steps tests/index.mjs",
|
||||||
"vbuild": "VERBOSE=1 node build.mjs",
|
"vbuild": "VERBOSE=1 node build.mjs",
|
||||||
"prebuild": "node scripts/prebuild.mjs",
|
"prebuild": "node --conditions=internal --experimental-json-modules ./prebuild.mjs",
|
||||||
"wbuild": "node build.mjs",
|
"wbuild": "node build.mjs",
|
||||||
"prewbuild": "node scripts/prebuild.mjs"
|
"prewbuild": "node --conditions=internal --experimental-json-modules ./prebuild.mjs"
|
||||||
},
|
},
|
||||||
"peerDependencies": {},
|
"peerDependencies": {},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
14
sites/backend/prebuild.mjs
Normal file
14
sites/backend/prebuild.mjs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { prebuildRunner } from '../shared/prebuild/runner.mjs'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This handles the prebuild step for the FreeSewing backend
|
||||||
|
* It runs via an NPM run script, so in a pure NodeJS context
|
||||||
|
*
|
||||||
|
* See `sites/org/prebuild.mjs` for an example with inline comments
|
||||||
|
*/
|
||||||
|
prebuildRunner({
|
||||||
|
site: 'backend',
|
||||||
|
prebuild: {
|
||||||
|
i18n: true,
|
||||||
|
},
|
||||||
|
})
|
|
@ -1,142 +0,0 @@
|
||||||
import fs from 'fs'
|
|
||||||
import path from 'path'
|
|
||||||
import rdir from 'recursive-readdir'
|
|
||||||
import yaml from 'js-yaml'
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List of supported languages
|
|
||||||
*/
|
|
||||||
const locales = ['en', 'es', 'de', 'fr', 'nl']
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is where we configure what folders we should check for
|
|
||||||
* code-adjacent translation source files
|
|
||||||
*/
|
|
||||||
const folders = [path.resolve(path.join('.', 'src'))]
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to write out JSON files for translation sources
|
|
||||||
*/
|
|
||||||
const writeJson = async (locale, namespace, content) =>
|
|
||||||
fs.writeFileSync(
|
|
||||||
path.resolve('.', 'public', 'locales', locale, `${namespace}.json`),
|
|
||||||
JSON.stringify(content)
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to get a list of code-adjecent translation files in a folder.
|
|
||||||
* Will traverse recursively to get all files from a given root folder.
|
|
||||||
*/
|
|
||||||
const getI18nFileList = async () => {
|
|
||||||
const allFiles = []
|
|
||||||
for (const dir of folders) {
|
|
||||||
try {
|
|
||||||
const dirFiles = await rdir(dir)
|
|
||||||
allFiles.push(...dirFiles)
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter out the language files
|
|
||||||
return allFiles
|
|
||||||
.filter((file) => locales.map((loc) => `.${loc}.yaml`).includes(file.slice(-8)))
|
|
||||||
.sort()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to get language and namespace from the filename
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
*
|
|
||||||
* - filename: The filename or full path + filename
|
|
||||||
*/
|
|
||||||
const languageAndNamespaceFromFilename = (file) => {
|
|
||||||
const chunks = path.basename(file).split('.')
|
|
||||||
chunks.pop()
|
|
||||||
|
|
||||||
return chunks
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to load a YAML file from disk
|
|
||||||
*/
|
|
||||||
const loadYaml = (file) => {
|
|
||||||
let data
|
|
||||||
try {
|
|
||||||
data = yaml.load(fs.readFileSync(file, 'utf-8'))
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to build an object of namespaces and their values.
|
|
||||||
* Includes providing an EN fallback if something is not available in a language.
|
|
||||||
*
|
|
||||||
* Parameters:
|
|
||||||
*
|
|
||||||
* - files: List of files to process
|
|
||||||
*/
|
|
||||||
const filesAsNamespaces = (files) => {
|
|
||||||
// First build the object
|
|
||||||
const translations = {}
|
|
||||||
for (const file of files) {
|
|
||||||
const [namespace, lang] = languageAndNamespaceFromFilename(file)
|
|
||||||
if (typeof translations[namespace] === 'undefined') {
|
|
||||||
translations[namespace] = {}
|
|
||||||
}
|
|
||||||
translations[namespace][lang] = loadYaml(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
return translations
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to ensure all translations all available in the data
|
|
||||||
*
|
|
||||||
* Parameter:
|
|
||||||
*
|
|
||||||
* - data: The raw data based on loaded YAML files
|
|
||||||
*/
|
|
||||||
const fixData = (rawData) => {
|
|
||||||
const data = {}
|
|
||||||
for (const [namespace, nsdata] of Object.entries(rawData)) {
|
|
||||||
if (typeof nsdata.en === 'undefined') {
|
|
||||||
throw `No English data for namespace ${namespace}. Bailing out`
|
|
||||||
}
|
|
||||||
data[namespace] = { en: nsdata.en }
|
|
||||||
// Complete other locales
|
|
||||||
for (const lang of locales.filter((loc) => loc !== 'en')) {
|
|
||||||
if (typeof nsdata[lang] === 'undefined') data[namespace][lang] = nsdata.en
|
|
||||||
else {
|
|
||||||
for (const key of Object.keys(data[namespace].en)) {
|
|
||||||
if (typeof nsdata[lang][key] === 'undefined') nsdata[lang][key] = nsdata.en[key]
|
|
||||||
}
|
|
||||||
data[namespace][lang] = nsdata[lang]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The method that does the actual work
|
|
||||||
*/
|
|
||||||
export const prebuildI18n = async () => {
|
|
||||||
// Handle new code-adjacent translations
|
|
||||||
const files = await getI18nFileList()
|
|
||||||
const data = filesAsNamespaces(files)
|
|
||||||
const namespaces = fixData(data)
|
|
||||||
// Write out code-adjacent source files
|
|
||||||
for (const locale of locales) {
|
|
||||||
// Fan out into namespaces
|
|
||||||
for (const namespace in namespaces) {
|
|
||||||
writeJson(locale, namespace, namespaces[namespace][locale])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
import { prebuildI18n } from './prebuild-i18n.mjs'
|
|
||||||
|
|
||||||
prebuildI18n()
|
|
|
@ -12,6 +12,7 @@ import { designs } from '../i18n/designs.mjs'
|
||||||
*/
|
*/
|
||||||
const sitesFolder = path.join(fileURLToPath(import.meta.url), '..', '..', '..')
|
const sitesFolder = path.join(fileURLToPath(import.meta.url), '..', '..', '..')
|
||||||
export const folders = {
|
export const folders = {
|
||||||
|
backend: [path.join(sitesFolder, 'backend', 'src', 'templates', 'email')],
|
||||||
org: [path.join(sitesFolder, 'org', 'pages'), path.join(sitesFolder, 'org', 'components')],
|
org: [path.join(sitesFolder, 'org', 'pages'), path.join(sitesFolder, 'org', 'components')],
|
||||||
dev: [path.join(sitesFolder, 'dev', 'pages'), path.join(sitesFolder, 'dev', 'components')],
|
dev: [path.join(sitesFolder, 'dev', 'pages'), path.join(sitesFolder, 'dev', 'components')],
|
||||||
lab: [path.join(sitesFolder, 'lab', 'pages'), path.join(sitesFolder, 'lab', 'components')],
|
lab: [path.join(sitesFolder, 'lab', 'pages'), path.join(sitesFolder, 'lab', 'components')],
|
||||||
|
@ -42,10 +43,11 @@ const writeJson = async (site, locale, namespace, content) => {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const getI18nFileList = async (site, languages) => {
|
const getI18nFileList = async (site, languages) => {
|
||||||
const dirs = [...folders.shared]
|
const dirs = []
|
||||||
if (site === 'org') dirs.push(...folders.org)
|
if (site === 'org') dirs.push(...folders.org, ...folders.shared)
|
||||||
if (site === 'dev') dirs.push(...folders.dev)
|
else if (site === 'dev') dirs.push(...folders.dev, ...folder.shared)
|
||||||
if (site === 'lab') dirs.push(...folders.lab)
|
else if (site === 'lab') dirs.push(...folders.lab, ...folders.shared)
|
||||||
|
else if (site === 'backend') dirs.push(...folders.backend)
|
||||||
|
|
||||||
const allFiles = []
|
const allFiles = []
|
||||||
for (const dir of dirs) {
|
for (const dir of dirs) {
|
||||||
|
@ -181,10 +183,16 @@ export const prebuildI18n = async (store) => {
|
||||||
// Write out code-adjacent source files
|
// Write out code-adjacent source files
|
||||||
for (const language of languages) {
|
for (const language of languages) {
|
||||||
// Fan out into namespaces
|
// Fan out into namespaces
|
||||||
for (const namespace in namespaces)
|
for (const namespace in namespaces) {
|
||||||
writeJson(store.site, language, namespace, namespaces[namespace][language])
|
writeJson(store.site, language, namespace, namespaces[namespace][language])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For backend, this is all we need
|
||||||
|
*/
|
||||||
|
if (store.site === 'backend') return (store.i18n = { namespaces })
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle design translations
|
* Handle design translations
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue