xliff
Version:
xliff2js and js2xliff converter xliff utils
144 lines (127 loc) • 5.38 kB
JavaScript
import convert from 'xml-js'
import ElementTypes2 from './inline-elements/ElementTypes2.js'
import { makeElement, makeText, makeValue } from './xml-js/objectToXml.js'
import escape from './util/escape.js'
const js2xliffClb = (obj, opt, cb) => {
if (!cb && typeof opt === 'function') {
cb = opt
opt = { indent: ' ' }
}
opt = opt || { indent: ' ' }
const targetXliffVersion = opt.targetXliffVersion || '2.0'
const options = {
spaces: opt.indent !== undefined ? opt.indent : ' ',
targetXliffVersion
}
const rootAttributes = {
xmlns: 'urn:oasis:names:tc:xliff:document:' + targetXliffVersion,
version: targetXliffVersion,
srcLang: obj.sourceLanguage,
trgLang: obj.targetLanguage
}
const hasSizeRestriction = !!Object.keys(obj.resources).find((nsName) => Object.keys(obj.resources[nsName]).find((k) => obj.resources[nsName][k].additionalAttributes && (obj.resources[nsName][k].additionalAttributes.sizeRestriction !== undefined || obj.resources[nsName][k].additionalAttributes['slr:sizeRestriction'] !== undefined)))
if (hasSizeRestriction) rootAttributes['xmlns:slr'] = 'urn:oasis:names:tc:xliff:sizerestriction:2.0'
const root = makeElement('xliff', rootAttributes, true)
// Insert headerExtras before <file> elements for round-trip preservation
if (Array.isArray(obj.headerExtras) && obj.headerExtras.length) {
obj.headerExtras.forEach(extra => {
const clone = JSON.parse(JSON.stringify(extra))
if (clone.type === 'element' && clone.attributes == null) {
clone.attributes = {}
}
root.elements.push(clone)
})
}
Object.keys(obj.resources).forEach((nsName) => {
const fileChildren = createUnitTags(obj.resources[nsName], options)
const f = makeElement('file', { id: nsName }, fileChildren)
root.elements.push(f)
})
const xmlJs = {
elements: [root]
}
const xml = convert.js2xml(xmlJs, options)
if (cb) cb(null, xml)
return xml
}
function createUnitTags (unitElements, options) {
const hasSizeRestriction = !!Object.keys(unitElements).find((k) => unitElements[k].additionalAttributes && (unitElements[k].additionalAttributes.sizeRestriction !== undefined || unitElements[k].additionalAttributes['slr:sizeRestriction'] !== undefined))
const preElements = []
if (hasSizeRestriction) {
preElements.push({
type: 'element',
name: 'slr:profiles',
attributes: { generalProfile: 'xliff:codepoints', storageProfile: 'xliff:utf8' },
elements: [{
type: 'element',
name: 'slr:normalization',
attributes: { general: 'nfc', storage: 'nfc' }
}]
})
}
return preElements.concat(Object.keys(unitElements).map((key) => {
if (unitElements[key].groupUnits) {
return createGroupUnitTag(key, unitElements[key], options)
} else {
return createUnitTag(key, unitElements[key], options)
}
}))
}
function createGroupUnitTag (id, group, options) {
const additionalAttributes = group.additionalAttributes != null ? group.additionalAttributes : {}
const groupUnits = createUnitTags(group.groupUnits, options)
const attrs = { id: escape(id) }
Object.keys(additionalAttributes).forEach(k => {
const v = additionalAttributes[k]
if (v !== undefined && v !== null) attrs[k] = String(v)
})
return makeElement('group', attrs, groupUnits)
}
function createUnitTag (id, unit, options) {
const segment = makeElement('segment', null, true)
const srcVal = (unit.source === undefined && unit.target !== undefined) ? '' : unit.source
if (srcVal !== undefined) segment.elements.push(makeElement('source', null, makeValue(srcVal, ElementTypes2, options && options.targetXliffVersion)))
if (unit.target !== undefined) segment.elements.push(makeElement('target', null, makeValue(unit.target, ElementTypes2, options && options.targetXliffVersion)))
const subEle = [segment]
if ('note' in unit) {
const noteElms = []
createNoteObjects(unit.note).forEach(noteObj => {
noteElms.push(makeElement('note', null, [noteObj]))
})
subEle.unshift(makeElement('notes', null, noteElms))
}
const additionalAttributes = unit.additionalAttributes != null ? { ...unit.additionalAttributes } : {}
if (additionalAttributes.sizeRestriction) {
additionalAttributes['slr:sizeRestriction'] = additionalAttributes.sizeRestriction + ''
delete additionalAttributes.sizeRestriction
}
const attrs = { id: escape(id) }
Object.keys(additionalAttributes).forEach(k => {
const v = additionalAttributes[k]
if (v !== undefined && v !== null) attrs[k] = String(v)
})
return makeElement('unit', attrs, subEle)
}
function createNoteObjects (note) {
const arrNote = []
const baseNote = makeText(note)
if (Array.isArray(baseNote.text)) {
baseNote.text.forEach(text => {
arrNote.push({ type: baseNote.type, text })
})
} else {
arrNote.push(baseNote)
}
return arrNote
}
const js2xliff = (obj, opt, cb) => {
if (!cb && opt === undefined) {
return new Promise((resolve, reject) => js2xliffClb(obj, opt, (err, ret) => err ? reject(err) : resolve(ret)))
}
if (!cb && typeof opt !== 'function') {
return new Promise((resolve, reject) => js2xliffClb(obj, opt, (err, ret) => err ? reject(err) : resolve(ret)))
}
return js2xliffClb(obj, opt, cb)
}
js2xliff.js2xliffClb = js2xliffClb
export default js2xliff