From b56ebc30fd6eb69085f46c9cecbb52c4c0f0aa99 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Thu, 21 Oct 2021 22:39:27 +0200 Subject: [PATCH 1/4] Read/Write to fs, removing remote module Signed-off-by: Jonas Rittershofer --- lib/challenge-sidebar-handler.js | 6 ++-- lib/challenge-verify-handler.js | 22 ++++++------- lib/index-challenge-handler.js | 6 ++-- lib/ipcMainHandlers.js | 35 +++++++++++++++++++++ lib/user-data.js | 53 +++++++++++++++++++++----------- 5 files changed, 87 insertions(+), 35 deletions(-) diff --git a/lib/challenge-sidebar-handler.js b/lib/challenge-sidebar-handler.js index 29fd415d..2308c813 100644 --- a/lib/challenge-sidebar-handler.js +++ b/lib/challenge-sidebar-handler.js @@ -6,8 +6,8 @@ const path = require('path') const userData = require(path.normalize(path.join(__dirname, 'user-data.js'))) // Execute after DOM loaded. -document.addEventListener('DOMContentLoaded', () => { - const challengeUserData = userData.getChallengeData() +document.addEventListener('DOMContentLoaded', async () => { + const challengeUserData = await userData.getChallengeData() Object.keys(challengeUserData).forEach((challengeKey) => { if (challengeUserData[challengeKey].challengeComplete) { @@ -19,7 +19,7 @@ document.addEventListener('DOMContentLoaded', () => { /* * Show a challenge as complete/incomplete in sidebar */ -function showChallengeComplete (challengeKey, isComplete) { +async function showChallengeComplete (challengeKey, isComplete) { if (isComplete) { document.getElementById('sidebar__list__item--' + challengeKey).classList.add('complete') } else { diff --git a/lib/challenge-verify-handler.js b/lib/challenge-verify-handler.js index c961040f..6f2098ee 100644 --- a/lib/challenge-verify-handler.js +++ b/lib/challenge-verify-handler.js @@ -25,7 +25,7 @@ const selectedDirDiv = document.getElementById('div-selected-dir') * Execute after DOM loaded. * Register Button-Handlers */ -document.addEventListener('DOMContentLoaded', () => { +document.addEventListener('DOMContentLoaded', async () => { verifyButton.addEventListener('click', () => { handleVerifyClick() }) @@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', () => { // Only if button exists. // Before enableVerifyButtons, due to checked selectedDirPath there. if (selectDirButton) { - const savedDir = userData.getSavedDir(currentChallenge) + const savedDir = await userData.getSavedDir(currentChallenge) if (!savedDir) { showSelectedDirDiv(false) @@ -52,7 +52,7 @@ document.addEventListener('DOMContentLoaded', () => { } } - const challengeUserData = userData.getChallengeData(currentChallenge) + const challengeUserData = await userData.getChallengeData(currentChallenge) if (challengeUserData.challengeComplete) { enableVerifyButtons(false) enableClearStatusButton(true) @@ -97,7 +97,7 @@ async function handleVerifyClick () { // In js it is possible to call with more parameters, than defined, not all challenges need the path-parameter const result = await verifyChallengeScript(selectedDirPath?.innerText) - clearVerifyList() + await clearVerifyList() printOutVerifyList(result.verifyList) if (result.challengeComplete) { @@ -129,7 +129,7 @@ async function clearChallengeStatus () { /* * Write out the list to the DOM */ -function printOutVerifyList (list) { +async function printOutVerifyList (list) { showVerifyList(true) list.forEach(listItem => { const li = document.createElement('li') @@ -150,14 +150,14 @@ function printOutVerifyList (list) { /* * Small helper for readable code */ -function clearVerifyList () { +async function clearVerifyList () { verifyList.innerHTML = '' } /* * clearStatusButton gets shown or not on enabled */ -function enableClearStatusButton (enabled) { +async function enableClearStatusButton (enabled) { if (enabled) { clearStatusButton.style.display = 'block' } else { @@ -169,7 +169,7 @@ function enableClearStatusButton (enabled) { * VerifyButtons get disabled or not. * This includes the verify-button, as well as the select-dir button if available. */ -function enableVerifyButtons (enabled) { +async function enableVerifyButtons (enabled) { verifyButton.disabled = !enabled if (selectDirButton) { @@ -185,7 +185,7 @@ function enableVerifyButtons (enabled) { * Either show selectedDirDiv or show PathRequiredWarning * If selectedDir is shown, the button should say 'Change Directory', else 'Select Directory' */ -function showSelectedDirDiv (show) { +async function showSelectedDirDiv (show) { if (show) { selectedDirDiv.style.display = 'inline' pathRequiredWarning.style.display = 'none' @@ -202,7 +202,7 @@ function showSelectedDirDiv (show) { /* * Show the verifySpinner or not */ -function showSpinner (show) { +async function showSpinner (show) { if (show) { verifySpinner.style.display = 'inline-block' } else { @@ -213,7 +213,7 @@ function showSpinner (show) { /* * Show verifyList or not */ -function showVerifyList (show) { +async function showVerifyList (show) { if (show) { verifyList.style.display = 'block' } else { diff --git a/lib/index-challenge-handler.js b/lib/index-challenge-handler.js index 88bef8ff..259fedd7 100644 --- a/lib/index-challenge-handler.js +++ b/lib/index-challenge-handler.js @@ -18,9 +18,9 @@ const IndexSectionWip = document.getElementById('pgIndex__section--wip') const IndexSectionFinished = document.getElementById('pgIndex__section--finished') // Execute after DOM loaded. -document.addEventListener('DOMContentLoaded', () => { +document.addEventListener('DOMContentLoaded', async () => { // Get stored challengeUserData & store Key-Array as often used - const challengeUserData = userData.getChallengeData() + const challengeUserData = await userData.getChallengeData() const challengeUserDataKeys = Object.keys(challengeUserData) // Go through the challenges in challengeUserData to see which are complete @@ -77,7 +77,7 @@ ipc.on('confirm-clearAll', () => { * Show exclusively the specified section. * section = 'start'|'wip'|'finished' */ -function showSection (section) { +async function showSection (section) { // Only accept specific section-keywords const accept = ['start', 'wip', 'finished'] diff --git a/lib/ipcMainHandlers.js b/lib/ipcMainHandlers.js index 3732021d..53b0a870 100644 --- a/lib/ipcMainHandlers.js +++ b/lib/ipcMainHandlers.js @@ -4,6 +4,7 @@ * Done in extra-file to keep main.js neat. */ +const fs = require('fs') const electron = require('electron') const ipcMain = electron.ipcMain const dialog = electron.dialog @@ -44,6 +45,40 @@ function registerIpcHandlers (mainWindow, userDataPath) { event.sender.send('confirm-clearAll') } }) + + /************************ + * JSON File Operations + ************************/ + + /** + * Async write Data as JSON to file + */ + ipcMain.handle('fs-writeAsJson', async (event, file, data) => { + return new Promise((resolve, reject) => { + fs.writeFile(file, JSON.stringify(data, null, 2), (err) => { + if (err) { + reject(err) + return + } + resolve() + }) + }) + }) + + /** + * Async read of JSON Data + */ + ipcMain.handle('fs-readFromJson', async (event, file) => { + return new Promise((resolve, reject) => { + fs.readFile(file, (err, data) => { + if (err) { + reject(err) + return + } + resolve(JSON.parse(data)) + }) + }) + }) } exports.registerIpcHandlers = registerIpcHandlers diff --git a/lib/user-data.js b/lib/user-data.js index 98cfabd5..64deb5e8 100644 --- a/lib/user-data.js +++ b/lib/user-data.js @@ -3,7 +3,6 @@ * This file handles the user-data.json and saved-dir.json files * Uses electron-remote fs-module to still write out async, even when function gets terminated. */ -const fs = require('electron').remote.require('fs') const ipc = require('electron').ipcRenderer const path = require('path') @@ -26,30 +25,30 @@ const verifyDir = { * user-data.json */ // Returns either an object out of all challengesData-objects or if called with parameter the object to the given challenge. -function getChallengeData (challenge = null) { - const fileContent = JSON.parse(fs.readFileSync(userDataFile)) +async function getChallengeData (challenge = null) { + const fileContent = await readData(userDataFile) if (challenge) { return fileContent[challenge] } return fileContent } // Store challenge verify-data -function storeChallengeResult (challenge, challengeComplete, verifyList) { - const fileContent = getChallengeData() +async function storeChallengeResult (challenge, challengeComplete, verifyList) { + const fileContent = await getChallengeData() fileContent[challenge].challengeComplete = challengeComplete fileContent[challenge].verifyList = verifyList writeData(userDataFile, fileContent) } // Clear challenge verify-data -function clearChallengeResult (challenge) { - const fileContent = getChallengeData() +async function clearChallengeResult (challenge) { + const fileContent = await getChallengeData() fileContent[challenge].challengeComplete = false fileContent[challenge].verifyList = [] writeData(userDataFile, fileContent) } // Clear all challenges - Set all challenges as incomplete and clear verifyLists -function clearAllChallenges () { - const fileContent = getChallengeData() +async function clearAllChallenges () { + const fileContent = await getChallengeData() Object.keys(fileContent).forEach(challenge => { fileContent[challenge].challengeComplete = false fileContent[challenge].verifyList = [] @@ -60,16 +59,16 @@ function clearAllChallenges () { /**** * saved-dir.json */ -function getSavedDir (currentChallenge = null) { - const fileContent = JSON.parse(fs.readFileSync(savedDirFile)) +async function getSavedDir (currentChallenge = null) { + const fileContent = await readData(savedDirFile) if (currentChallenge) { return fileContent[verifyDir[currentChallenge]] } return fileContent } // Store directory -function updateSavedDir (currentChallenge, path) { - const fileContent = getSavedDir() +async function updateSavedDir (currentChallenge, path) { + const fileContent = await getSavedDir() fileContent[verifyDir[currentChallenge]] = path writeData(savedDirFile, fileContent) } @@ -79,12 +78,30 @@ function updateSavedDir (currentChallenge, path) { * Write out data to file * Writes out asynchronously. */ -function writeData (file, data) { - fs.writeFile(file, JSON.stringify(data, null, 2), (err) => { - if (err) { - console.error(err) +async function writeData (file, data) { + ipc.invoke('fs-writeAsJson', file, data).then( + // Resolved + () => { + // Silent Handle, everything as expected. + }, + // Rejected, sth. went wrong. + (rejectErr) => { + console.error('Some error occured while writing into', file, rejectErr) } - }) + ) +} + +/**** + * Common function + * Read Data from File asynchronously, but wait for returned data. + */ +async function readData (file) { + try { + return await ipc.invoke('fs-readFromJson', file) + } catch (err) { + console.debug('Some error occured while reading from ', file, err) + return {} + } } exports.getChallengeData = getChallengeData From 4fa226ced27cae07a13dd39bffff3ca1d9a241fe Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Tue, 26 Oct 2021 23:21:17 +0200 Subject: [PATCH 2/4] Improve some Comments Signed-off-by: Jonas Rittershofer --- lib/ipcMainHandlers.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/ipcMainHandlers.js b/lib/ipcMainHandlers.js index 53b0a870..d0d37221 100644 --- a/lib/ipcMainHandlers.js +++ b/lib/ipcMainHandlers.js @@ -10,16 +10,24 @@ const ipcMain = electron.ipcMain const dialog = electron.dialog function registerIpcHandlers (mainWindow, userDataPath) { - /* - * Provide userDataPath to Renderer (resp. to lib/user-data.js) - */ + /************************ + * Provide Data to Renderer + ************************/ + + /** + * Provide userDataPath to Renderer (resp. to lib/user-data.js) + */ ipcMain.on('getUserDataPath', event => { event.returnValue = userDataPath }) - /* - * Select-Directory Window if called - */ + /************************ + * Show User Dialogs + ************************/ + + /** + * Show Directory-select window if called + */ ipcMain.on('dialog-selectDir', event => { const path = dialog.showOpenDialogSync(mainWindow, { properties: ['openDirectory'] }) if (path) { @@ -27,9 +35,9 @@ function registerIpcHandlers (mainWindow, userDataPath) { } }) - /* - * ClearAll Dialog - */ + /** + * ClearAll Dialog + */ ipcMain.on('dialog-clearAll', event => { const dialogOptions = { type: 'info', From 5929e52f80a12a799063b29cbf9098aa65d87d98 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Tue, 26 Oct 2021 23:53:05 +0200 Subject: [PATCH 3/4] Do translations through ipc, remove remote module. Signed-off-by: Jonas Rittershofer --- config/i18next.config.js | 18 +++++++++++++ lib/challenge-verify-handler.js | 7 +++-- lib/i18n-translate.js | 45 ++++++++++----------------------- lib/ipcMainHandlers.js | 30 ++++++++++++++++++++++ main.js | 1 - 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/config/i18next.config.js b/config/i18next.config.js index 3315eecf..aa94e42c 100644 --- a/config/i18next.config.js +++ b/config/i18next.config.js @@ -25,6 +25,23 @@ const usedNamespaces = [ 'ch01', 'ch02', 'ch03', 'ch04', 'ch05', 'ch06', 'ch07', 'ch08', 'ch09', 'ch10', 'ch11' ] +// defaultOptions for interpolation +const i18nDefaultOptions = { + cde: '', + cde_e: '', + em: '', + em_e: '', + lnk_e: '', + str: '', + str_e: '', + + // Simple Text, no HTML-Content + dqm: '"', // double quotation mark + gt: '>', + lt: '<', + smc: ';' // semicolon +} + const i18nextConfig = { // debug: true, @@ -55,3 +72,4 @@ const i18nextConfig = { exports.i18nextConfig = i18nextConfig exports.appLanguages = appLanguages +exports.i18nDefaultOptions = i18nDefaultOptions diff --git a/lib/challenge-verify-handler.js b/lib/challenge-verify-handler.js index 6f2098ee..08f1d3b3 100644 --- a/lib/challenge-verify-handler.js +++ b/lib/challenge-verify-handler.js @@ -4,7 +4,6 @@ */ const path = require('path') const ipc = require('electron').ipcRenderer -const i18n = require('electron').remote.getGlobal('i18n') const userData = require(path.normalize(path.join(__dirname, 'user-data.js'))) const sidebarHandler = require(path.normalize(path.join(__dirname, 'challenge-sidebar-handler.js'))) @@ -135,7 +134,7 @@ async function printOutVerifyList (list) { const li = document.createElement('li') li.appendChild(document.createTextNode( - i18n.t(listItem.message, listItem.data) + ipc.sendSync('i18n.t', listItem.message, listItem.data) )) if (listItem.pass) { li.classList.add('verify__list__elem--pass') @@ -189,12 +188,12 @@ async function showSelectedDirDiv (show) { if (show) { selectedDirDiv.style.display = 'inline' pathRequiredWarning.style.display = 'none' - selectDirButton.innerText = i18n.t('verify~Change Directory') + selectDirButton.innerText = ipc.sendSync('i18n.t', 'verify~Change Directory') selectDirButton.setAttribute('i18n-data', 'verify~Change Directory') } else { selectedDirDiv.style.display = 'none' pathRequiredWarning.style.display = 'inline' - selectDirButton.innerText = i18n.t('verify~Select directory') + selectDirButton.innerText = ipc.sendSync('i18n.t', 'verify~Select directory') selectDirButton.setAttribute('i18n-data', 'verify~Select directory') } } diff --git a/lib/i18n-translate.js b/lib/i18n-translate.js index 38297c5f..6be847a5 100644 --- a/lib/i18n-translate.js +++ b/lib/i18n-translate.js @@ -7,26 +7,9 @@ * - Listen for Language Dropdown Change */ -const i18n = require('electron').remote.getGlobal('i18n') +const ipc = require('electron').ipcRenderer const { appLanguages } = require('../config/i18next.config') -// defaultOptions for interpolation -const defaultOptions = { - cde: '', - cde_e: '', - em: '', - em_e: '', - lnk_e: '', - str: '', - str_e: '', - - // Simple Text, no HTML-Content - dqm: '"', // double quotation mark - gt: '>', - lt: '<', - smc: ';' // semicolon -} - /* * Insert translated Content after loading page. */ @@ -41,22 +24,22 @@ document.addEventListener('DOMContentLoaded', () => { * When changeLanguage is done, the main process will reload the window therefore executing translation-insert from scratch. */ const languageSelector = document.getElementById('header__lang__select') -languageSelector.addEventListener('change', () => { - i18n.changeLanguage(languageSelector.value) +languageSelector.addEventListener('change', async () => { + ipc.send('i18n.changeLanguage', languageSelector.value) }) /* * Select current Language in Dropdown-Element */ -function setDropdownLanguage () { +async function setDropdownLanguage () { const languageSelector = document.getElementById('header__lang__select') - languageSelector.value = i18n.language + languageSelector.value = ipc.sendSync('i18n.language') } /* * Insert Translations into HTML */ -function insertDataTranslations () { +async function insertDataTranslations () { const i18nElements = document.querySelectorAll('[i18n-data]') i18nElements.forEach(element => { @@ -75,9 +58,9 @@ function insertDataTranslations () { } if (type === 'html' || type === 'standard_html') { - element.innerHTML = i18n.t(data, { ...defaultOptions, ...options }) + element.innerHTML = ipc.sendSync('i18n.t', data, options) } else { - element.innerText = i18n.t(data, { ...defaultOptions, ...options }) + element.innerText = ipc.sendSync('i18n.t', data, options) } }) } @@ -87,12 +70,12 @@ function insertDataTranslations () { * Box Titles are done with CSS ::before, so the styles need to be inserted dynamically. * Here always removing old styles and adding new ones into the specific Stylesheet (see challenges.hbs). */ -function insertTranslationStyles () { +async function insertTranslationStyles () { const sheetTitle = 'jsTranslationStylesheet' const sheetIndex = [...document.styleSheets].findIndex(sheet => sheet.title === sheetTitle) // Insert Style for right-to-left languages - if (appLanguages[i18n.language].direction === 'rtl') { + if (appLanguages[ipc.sendSync('i18n.language')].direction === 'rtl') { document.getElementById('wrapper__content').classList.add('rtl') } else { document.getElementById('wrapper__content').classList.remove('rtl') @@ -108,9 +91,9 @@ function insertTranslationStyles () { } // Append rules for box-titles if (document.styleSheets[sheetIndex].ownerNode.id === 'challenge-translation-style') { - document.styleSheets[sheetIndex].insertRule('.box--goal::before {content: "' + i18n.t('Goal') + '";}') - document.styleSheets[sheetIndex].insertRule('.box--fail::before {content: "' + i18n.t("Didn't Pass?") + '";}') - document.styleSheets[sheetIndex].insertRule('.box--tip::before {content: "' + i18n.t('Tip') + '";}') - document.styleSheets[sheetIndex].insertRule('.box--step::before {content: "' + i18n.t('Step') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--goal::before {content: "' + ipc.sendSync('i18n.t', 'Goal') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--fail::before {content: "' + ipc.sendSync('i18n.t', "Didn't Pass?") + '";}') + document.styleSheets[sheetIndex].insertRule('.box--tip::before {content: "' + ipc.sendSync('i18n.t', 'Tip') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--step::before {content: "' + ipc.sendSync('i18n.t', 'Step') + '";}') } } diff --git a/lib/ipcMainHandlers.js b/lib/ipcMainHandlers.js index d0d37221..e111656e 100644 --- a/lib/ipcMainHandlers.js +++ b/lib/ipcMainHandlers.js @@ -9,6 +9,12 @@ const electron = require('electron') const ipcMain = electron.ipcMain const dialog = electron.dialog +// i18n-defaultOptions for Interpolation +const { i18nDefaultOptions } = require('../config/i18next.config.js') + +/** + * Register Handlers for IPC + */ function registerIpcHandlers (mainWindow, userDataPath) { /************************ * Provide Data to Renderer @@ -21,6 +27,30 @@ function registerIpcHandlers (mainWindow, userDataPath) { event.returnValue = userDataPath }) + /************************ + * Provide I18n-Data to Renderer + * Some kind of a strange construct, but such there is only one i18n-Object on the main process no remote module is necesssary. + ************************/ + + /** + * Provide translated text + */ + ipcMain.on('i18n.t', (event, data, options) => { + event.returnValue = global.i18n.t(data, { ...i18nDefaultOptions, ...options }) + }) + /** + * Provide current language + */ + ipcMain.on('i18n.language', (event) => { + event.returnValue = global.i18n.language + }) + /** + * Change current language + */ + ipcMain.on('i18n.changeLanguage', (event, newLang) => { + global.i18n.changeLanguage(newLang) + }) + /************************ * Show User Dialogs ************************/ diff --git a/main.js b/main.js index 33f3cffb..f08e55bd 100644 --- a/main.js +++ b/main.js @@ -33,7 +33,6 @@ app.on('ready', () => { icon: GititIcon, webPreferences: { nodeIntegration: true, - enableRemoteModule: true, contextIsolation: false } }) From 2bfb7106f216ce12db00852ab0546af224a79083 Mon Sep 17 00:00:00 2001 From: Jonas Rittershofer Date: Wed, 27 Oct 2021 22:36:39 +0200 Subject: [PATCH 4/4] Move t to helper function for proper extractions Signed-off-by: Jonas Rittershofer --- config/i18next-parser.config.js | 2 +- lib/challenge-verify-handler.js | 7 ++++--- lib/i18n-translate.js | 13 +++++++------ lib/renderer-helpers.js | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 lib/renderer-helpers.js diff --git a/config/i18next-parser.config.js b/config/i18next-parser.config.js index 7472d6a5..e92fe5d9 100644 --- a/config/i18next-parser.config.js +++ b/config/i18next-parser.config.js @@ -46,7 +46,7 @@ module.exports = { // mjs: ['JavascriptLexer'], js: [{ lexer: 'JavascriptLexer', - functions: ['t', 'addToVerifyList'], // Array of functions to match + functions: ['t', 'translate', 'addToVerifyList'], // Array of functions to match }], // ts: ['JavascriptLexer'], // jsx: ['JsxLexer'], diff --git a/lib/challenge-verify-handler.js b/lib/challenge-verify-handler.js index 08f1d3b3..bc82b10b 100644 --- a/lib/challenge-verify-handler.js +++ b/lib/challenge-verify-handler.js @@ -6,6 +6,7 @@ const path = require('path') const ipc = require('electron').ipcRenderer const userData = require(path.normalize(path.join(__dirname, 'user-data.js'))) const sidebarHandler = require(path.normalize(path.join(__dirname, 'challenge-sidebar-handler.js'))) +const { translate } = require('./renderer-helpers.js') const currentChallenge = document.head.querySelector('meta[name="currentChallenge"]').getAttribute('content') const verifyButton = document.getElementById('btn-verify-challenge') @@ -134,7 +135,7 @@ async function printOutVerifyList (list) { const li = document.createElement('li') li.appendChild(document.createTextNode( - ipc.sendSync('i18n.t', listItem.message, listItem.data) + translate(listItem.message, listItem.data) )) if (listItem.pass) { li.classList.add('verify__list__elem--pass') @@ -188,12 +189,12 @@ async function showSelectedDirDiv (show) { if (show) { selectedDirDiv.style.display = 'inline' pathRequiredWarning.style.display = 'none' - selectDirButton.innerText = ipc.sendSync('i18n.t', 'verify~Change Directory') + selectDirButton.innerText = translate('verify~Change Directory') selectDirButton.setAttribute('i18n-data', 'verify~Change Directory') } else { selectedDirDiv.style.display = 'none' pathRequiredWarning.style.display = 'inline' - selectDirButton.innerText = ipc.sendSync('i18n.t', 'verify~Select directory') + selectDirButton.innerText = translate('verify~Select directory') selectDirButton.setAttribute('i18n-data', 'verify~Select directory') } } diff --git a/lib/i18n-translate.js b/lib/i18n-translate.js index 6be847a5..f5a7f484 100644 --- a/lib/i18n-translate.js +++ b/lib/i18n-translate.js @@ -9,6 +9,7 @@ const ipc = require('electron').ipcRenderer const { appLanguages } = require('../config/i18next.config') +const { translate } = require('./renderer-helpers.js') /* * Insert translated Content after loading page. @@ -58,9 +59,9 @@ async function insertDataTranslations () { } if (type === 'html' || type === 'standard_html') { - element.innerHTML = ipc.sendSync('i18n.t', data, options) + element.innerHTML = translate(data, options) } else { - element.innerText = ipc.sendSync('i18n.t', data, options) + element.innerText = translate(data, options) } }) } @@ -91,9 +92,9 @@ async function insertTranslationStyles () { } // Append rules for box-titles if (document.styleSheets[sheetIndex].ownerNode.id === 'challenge-translation-style') { - document.styleSheets[sheetIndex].insertRule('.box--goal::before {content: "' + ipc.sendSync('i18n.t', 'Goal') + '";}') - document.styleSheets[sheetIndex].insertRule('.box--fail::before {content: "' + ipc.sendSync('i18n.t', "Didn't Pass?") + '";}') - document.styleSheets[sheetIndex].insertRule('.box--tip::before {content: "' + ipc.sendSync('i18n.t', 'Tip') + '";}') - document.styleSheets[sheetIndex].insertRule('.box--step::before {content: "' + ipc.sendSync('i18n.t', 'Step') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--goal::before {content: "' + translate('Goal') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--fail::before {content: "' + translate("Didn't Pass?") + '";}') + document.styleSheets[sheetIndex].insertRule('.box--tip::before {content: "' + translate('Tip') + '";}') + document.styleSheets[sheetIndex].insertRule('.box--step::before {content: "' + translate('Step') + '";}') } } diff --git a/lib/renderer-helpers.js b/lib/renderer-helpers.js new file mode 100644 index 00000000..a79f3293 --- /dev/null +++ b/lib/renderer-helpers.js @@ -0,0 +1,14 @@ +/* + * Runs in: Renderer-Process + * + * Helpers to be used within renderer-process. + */ + +const ipc = require('electron').ipcRenderer + +// Just a small wrapper to ease translation-extraction. +function translate (data, options = {}) { + return ipc.sendSync('i18n.t', data, options) +} + +exports.translate = translate