2023-02-15 10:54:48 +00:00
|
|
|
/**
|
|
|
|
* This script is used to build the translations files.
|
|
|
|
*
|
|
|
|
* Indeed, some strings used in plugin settings are not easy to write
|
|
|
|
* in JSON format (contains html, double quotes, line breaks, ...).
|
|
|
|
* So we use YAML files to translates these strings,
|
|
|
|
* including the english version.
|
|
|
|
*
|
|
|
|
* This scripts takes the standard JSON files, the YAML translation files,
|
|
|
|
* and mixes everything up in dist/languages/xx.json.
|
|
|
|
*/
|
|
|
|
const fs = require('fs')
|
|
|
|
const path = require('path')
|
|
|
|
const YAML = require('yaml')
|
|
|
|
|
|
|
|
class BuildLanguages {
|
|
|
|
destinationDir = null
|
|
|
|
langs = []
|
|
|
|
translationsStrings = {}
|
2023-06-09 15:08:39 +00:00
|
|
|
monoLingualReferences = null
|
2023-02-15 10:54:48 +00:00
|
|
|
|
|
|
|
constructor () {
|
|
|
|
this.destinationDir = path.resolve(__dirname, 'dist', 'languages')
|
|
|
|
}
|
|
|
|
|
|
|
|
async generateFiles () {
|
|
|
|
await this.loadLangs()
|
|
|
|
await this.initTranslationStrings()
|
2023-06-09 15:08:39 +00:00
|
|
|
await this.readYamlTranslations()
|
2023-02-15 10:54:48 +00:00
|
|
|
|
|
|
|
await this.ensureDestinationDir()
|
|
|
|
await this.writeJSONTranslations()
|
|
|
|
await this.writeMonoLingualReferences()
|
|
|
|
}
|
|
|
|
|
|
|
|
loadLangs () {
|
|
|
|
const packagejson = require('./package.json')
|
|
|
|
const translations = packagejson.translations || {}
|
|
|
|
this.langs = Object.values(translations).map(filename => {
|
2023-06-09 16:07:48 +00:00
|
|
|
return filename.match(/^.*\/([a-zA-Z-]+)\.json$/)[1]
|
2023-02-15 10:54:48 +00:00
|
|
|
})
|
2023-02-16 05:58:28 +00:00
|
|
|
console.log('Existing languages: ', this.langs)
|
2023-02-15 10:54:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
initTranslationStrings () {
|
|
|
|
console.log('Initializing translations strings...')
|
|
|
|
const translationsStrings = {}
|
|
|
|
for (const l of this.langs) {
|
|
|
|
translationsStrings[l] = {}
|
|
|
|
}
|
|
|
|
this.translationsStrings = translationsStrings
|
|
|
|
}
|
|
|
|
|
2023-06-09 15:08:39 +00:00
|
|
|
async readYamlTranslations () {
|
|
|
|
console.log('Reading Yaml translation strings...')
|
2023-02-15 10:54:48 +00:00
|
|
|
|
|
|
|
// First we must get the english reference file,
|
|
|
|
// that will give us the keys to use in final JSON.
|
|
|
|
|
2023-06-09 15:08:39 +00:00
|
|
|
const reference = await this.getYmlFileContent(path.resolve(__dirname, 'languages', 'en.yml'))
|
|
|
|
this.monoLingualReferences = reference
|
2023-02-15 10:54:48 +00:00
|
|
|
|
|
|
|
const translationsStrings = this.translationsStrings
|
|
|
|
for (const l of this.langs) {
|
2023-06-09 15:08:39 +00:00
|
|
|
if (l === 'en') {
|
|
|
|
console.log('Skipping english, because it is the reference language.')
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const filePath = path.resolve(__dirname, 'languages', l + '.yml')
|
2023-02-15 10:54:48 +00:00
|
|
|
const o = await this.getYmlFileContent(filePath)
|
|
|
|
|
|
|
|
for (const k in o) {
|
|
|
|
if (!(k in reference)) {
|
|
|
|
throw new Error(`File ${filePath} contains unknown keys. Key=${k}.`)
|
|
|
|
}
|
2023-06-09 13:06:25 +00:00
|
|
|
if ((typeof o[k]) !== 'string') {
|
|
|
|
// ignoring untranslated strings.
|
|
|
|
continue
|
|
|
|
}
|
2023-02-15 10:54:48 +00:00
|
|
|
const newKey = reference[k]
|
|
|
|
this.translationsStrings[l][newKey] = o[k]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async getYmlFileContent (filePath) {
|
|
|
|
if (!fs.existsSync(filePath)) {
|
|
|
|
console.warn(`File ${filePath} missing, ignoring.`)
|
|
|
|
return {}
|
|
|
|
}
|
|
|
|
|
|
|
|
const content = await fs.promises.readFile(filePath, 'utf8')
|
|
|
|
const o = YAML.parse(content) || {}
|
|
|
|
for (const k in o) {
|
|
|
|
let v = o[k]
|
|
|
|
if (v === null) {
|
|
|
|
// this value is ok!
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if ((typeof v) !== 'string') {
|
|
|
|
throw new Error(`File ${filePath} contains strings that are not strings! Key=${k}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
// We are normalizing the string, to avoid problems.
|
|
|
|
// As it is supposed to be html, we will strip newlines and multiple adjacent spaces.
|
|
|
|
v = v.replace(/\n/g, ' ')
|
|
|
|
v = v.replace(/\s\s+/g, ' ')
|
|
|
|
v = v.trim()
|
|
|
|
o[k] = v
|
|
|
|
}
|
|
|
|
return o
|
|
|
|
}
|
|
|
|
|
|
|
|
async ensureDestinationDir () {
|
|
|
|
if (!fs.existsSync(this.destinationDir)) {
|
2023-07-14 11:39:34 +00:00
|
|
|
await fs.promises.mkdir(this.destinationDir, { recursive: true })
|
2023-02-15 10:54:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async writeJSONTranslations () {
|
|
|
|
console.log('Writing JSON files...')
|
|
|
|
for (const l of this.langs) {
|
|
|
|
const filePath = path.resolve(this.destinationDir, l + '.json')
|
2023-09-06 15:58:54 +00:00
|
|
|
// Waiting for this to be implemented:
|
|
|
|
// https://github.com/Chocobozzz/PeerTube/issues/5904
|
|
|
|
// (also see https://github.com/JohnXLivingston/peertube-plugin-livechat/issues/224)
|
|
|
|
// we are adding a special entry with the language key, so we can use frontend
|
|
|
|
// translation function to get the path for localized documentation.
|
|
|
|
// See frontend getLangCode and localizedHelpUrl functions.
|
|
|
|
const content = this.translationsStrings[l]
|
|
|
|
content['_language'] = l
|
2023-02-15 10:54:48 +00:00
|
|
|
await fs.promises.writeFile(filePath, JSON.stringify(this.translationsStrings[l]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async writeMonoLingualReferences () {
|
|
|
|
console.log('Writing JSON reference files...')
|
2023-06-09 15:08:39 +00:00
|
|
|
if (!this.monoLingualReferences) {
|
|
|
|
throw new Error('Missing monolingual reference content!')
|
2023-02-15 10:54:48 +00:00
|
|
|
}
|
2023-06-09 15:08:39 +00:00
|
|
|
const filePath = path.resolve(this.destinationDir, 'en.reference.json')
|
|
|
|
await fs.promises.writeFile(filePath, JSON.stringify(this.monoLingualReferences))
|
2023-02-15 10:54:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const bl = new BuildLanguages()
|
|
|
|
bl.generateFiles().then(() => {}, (err) => {
|
|
|
|
console.error(err)
|
|
|
|
throw err
|
|
|
|
})
|