Skip to content

Commit bec8a12

Browse files
authored
➕ Merge pull request #222 from devmount/220-multilang-openlp-export
Multilang openlp export
2 parents 0663c9b + bacd960 commit bec8a12

3 files changed

Lines changed: 41 additions & 18 deletions

File tree

frontend/src/utils.js

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,8 @@ const browserPrefersDark = () => {
331331
const mailto = (address) => window.location.href = 'mailto:' + address;
332332

333333
// build OpenLyrics XML for given song
334-
const openLyricsXML = (song, version, locales = [], allTags = null) => {
334+
// see https://manual.openlp.org/display_tags.html#configuring-formatting-tags
335+
const openLyricsXML = (song, version, translatedSong = null, locales = [], allTags = null) => {
335336
const timestamp = (new Date()).toISOString().slice(0, -5);
336337
const title = `<title>${song.title}</title>`;
337338
const subtitle = song.subtitle ? `<title>${song.subtitle}</title>` : '';
@@ -345,16 +346,23 @@ const openLyricsXML = (song, version, locales = [], allTags = null) => {
345346
: '';
346347
const tags = song.tags && locales && allTags
347348
? '<themes>' + song.tags.map(
348-
tag => locales.map(l =>`<theme lang="${l}">${allTags[tag][l] ?? tag.key}</theme>`).join('')
349+
tag => locales.map(l =>`<theme lang='${l}'>${allTags[tag][l] ?? tag.key}</theme>`).join('')
349350
).join('') + '</themes>'
350351
: '';
351-
const lyrics = parsedContent(song.content, song.tuning, false, false).map(p => {
352+
const format = translatedSong
353+
? `<format><tags application='OpenLP'><tag name='it'><open><![CDATA[<em>]]></open><close><![CDATA[</em>]]></close><hidden><![CDATA[False]]></hidden></tag><tag name='gr'><open><![CDATA[<span style='-webkit-text-fill-color:grey'>]]></open><close><![CDATA[</span>]]></close><hidden><![CDATA[True]]></hidden></tag><tag name='fd'><open><![CDATA[<small>]]></open><close><![CDATA[</small>]]></close><hidden><![CDATA[True]]></hidden></tag></tags></format>`
354+
: '';
355+
const tParts = translatedSong ? parsedContent(translatedSong.content, 0, false, false) : [];
356+
const lyrics = parsedContent(song.content, 0, false, false).map((p, i) => {
352357
const type = p.type ? p.type.toUpperCase() : 'V';
353358
const num = p.number > 0 ? p.number : '1';
354-
return `<verse name='${type}${num}'><lines>` + p.content.replace(/\n/g, "<br />") + '</lines></verse>'
359+
const tContent = (i in tParts)
360+
? `<br/><br/><tag name='it'><tag name='gr'><tag name='fd'>${tParts[i].content.replace(/\n/g, "<br />")}</tag></tag></tag>`
361+
: '';
362+
return `<verse name='${type}${num}'><lines>${p.content.replace(/\n/g, "<br />")}${tContent}</lines></verse>`;
355363
}).join('');
356364

357-
return `<?xml version='1.0' encoding='UTF-8'?><song xmlns='http://openlyrics.info/namespace/2009/song' version='0.9' createdIn='SongDrive ${version}' modifiedIn='SongDrive ${version}' modifiedDate='${timestamp}'><properties><titles>${title}${subtitle}</titles>${copyright}${year}${ccli}${authors}${tags}</properties><lyrics>${lyrics}</lyrics></song>`;
365+
return `<?xml version='1.0' encoding='UTF-8'?><song xmlns='http://openlyrics.info/namespace/2009/song' version='0.9' createdIn='SongDrive ${version}' modifiedIn='SongDrive ${version}' modifiedDate='${timestamp}'><properties><titles>${title}${subtitle}</titles>${copyright}${year}${ccli}${authors}${tags}</properties>${format}<lyrics>${lyrics}</lyrics></song>`;
358366
};
359367

360368
export {

frontend/src/views/SetlistShow.vue

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -545,13 +545,13 @@ const emit = defineEmits(['editSong', 'editSetlist']);
545545
546546
// component properties
547547
const props = defineProps({
548-
languages: Object,
549-
ready: Object,
550-
role: Number,
551-
setlists: Object,
552-
songs: Object,
553-
user: String,
554-
users: Object,
548+
languages: Object,
549+
ready: Object,
550+
role: Number,
551+
setlists: Object,
552+
songs: Object,
553+
user: String,
554+
users: Object,
555555
});
556556
557557
// reactive data
@@ -981,12 +981,20 @@ const exportOsz = async () => {
981981
if (setlist.value.songs.hasOwnProperty(key) && setlist.value.songs[key].id in props.songs) {
982982
// get song object
983983
const song = props.songs[setlist.value.songs[key].id];
984+
// check for translations
985+
const lang = !('lang' in localStorage) ? locale.value : localStorage.getItem('lang');
986+
let tSong = null;
987+
if (lang !== song.language && song.translations.length > 0) {
988+
const tKey = song.translations.find((t) => t.endsWith(`-${lang}`));
989+
tSong = props.songs[tKey];
990+
}
984991
// handle song content parts
985-
let itemData = [];
986-
let parts = parsedContent(song.content, 0, false, false);
987-
parts.forEach((part) => {
992+
const itemData = [];
993+
const parts = parsedContent(song.content, 0, false, false);
994+
const tParts = tSong ? parsedContent(tSong.content, 0, false, false) : [];
995+
parts.forEach((part, i) => {
988996
itemData.push({
989-
'raw_slide': part.content,
997+
'raw_slide': (i in tParts) ? `${part.content}\n\n{it}{gr}{fd}${tParts[i].content}{/fd}{/it}{/gr}` : part.content,
990998
'verseTag': (part.type ? part.type.toUpperCase() : 'V') + (part.number > 0 ? part.number.toString() : '1'),
991999
});
9921000
});
@@ -1014,7 +1022,7 @@ const exportOsz = async () => {
10141022
'ccli_number': song.ccli,
10151023
'copyright': song.publisher
10161024
},
1017-
'xml_version': openLyricsXML(song, version),
1025+
'xml_version': openLyricsXML(song, version, tSong),
10181026
'auto_play_slides_once': false,
10191027
'auto_play_slides_loop': false,
10201028
'timed_slide_interval': 0,

frontend/src/views/SongShow.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,15 @@ const exportSng = () => {
524524
};
525525
// export song in OpenLyrics XML format
526526
const exportXml = () => {
527+
// check for translations
528+
const lang = !('lang' in localStorage) ? locale.value : localStorage.getItem('lang');
529+
let tSong = null;
530+
if (lang !== song.value.language && song.value.translations.length > 0) {
531+
const tKey = song.value.translations.find((t) => t.endsWith(`-${lang}`));
532+
tSong = props.songs[tKey];
533+
}
527534
// start download
528-
download(openLyricsXML(song.value, version, availableLocales, props.tags), songId + '.xml');
535+
download(openLyricsXML(song.value, version, tSong, availableLocales, props.tags), songId + '.xml');
529536
// toast success message
530537
notify({
531538
title: t('toast.exportedXml'),

0 commit comments

Comments
 (0)