diff --git a/src/gui/html/index.html b/src/gui/html/index.html index ecbd6486..a3a9873b 100644 --- a/src/gui/html/index.html +++ b/src/gui/html/index.html @@ -315,9 +315,10 @@ - + + diff --git a/src/gui/html/js/events.js b/src/gui/html/js/events.js index ba492c46..e9bf8bf8 100644 --- a/src/gui/html/js/events.js +++ b/src/gui/html/js/events.js @@ -53,7 +53,7 @@ function onChangeGame(evt) { } /* Send off a CEF query with the folder name of the new game. */ - showProgress(l10n.jed.translate('Loading game data...').fetch()); + showProgress(loot.l10n.translate('Loading game data...')); var request = JSON.stringify({ name: 'changeGame', args: [ @@ -123,14 +123,14 @@ function updateMasterlistNoProgress() { /* Hack to stop cards overlapping. */ document.getElementById('main').lastElementChild.updateSize(); - toast(l10n.jed.translate('Masterlist updated to revision %s.').fetch(loot.game.masterlist.revision)); + toast(loot.l10n.translate('Masterlist updated to revision %s.', loot.game.masterlist.revision)); } else { - toast(l10n.jed.translate('No masterlist update was necessary.').fetch()); + toast(loot.l10n.translate('No masterlist update was necessary.')); } }).catch(processCefError); } function onUpdateMasterlist(evt) { - showProgress(l10n.jed.translate('Updating masterlist...').fetch()); + showProgress(loot.l10n.translate('Updating masterlist...')); updateMasterlistNoProgress().then(function(result){ closeProgressDialog(); }).catch(processCefError); @@ -154,7 +154,7 @@ function onSortPlugins(evt) { promise = promise.then(updateMasterlistNoProgress()); } promise.then(function(){ - showProgress(l10n.jed.translate('Sorting plugins...').fetch()); + showProgress(loot.l10n.translate('Sorting plugins...')); loot.query('sortPlugins').then(JSON.parse).then(function(result){ if (result) { loot.game.oldLoadOrder = loot.game.plugins; @@ -256,7 +256,7 @@ function onRedatePlugins(evt) { return; } - showMessageDialog(l10n.jed.translate('Redate Plugins?').fetch(), l10n.jed.translate('This feature is provided so that modders using the Creation Kit may set the load order it uses. A side-effect is that any subscribed Steam Workshop mods will be re-downloaded by Steam. Do you wish to continue?').fetch(), l10n.jed.translate('Redate').fetch(), function(result){ + showMessageDialog(loot.l10n.translate('Redate Plugins?'), loot.l10n.translate('This feature is provided so that modders using the Creation Kit may set the load order it uses. A side-effect is that any subscribed Steam Workshop mods will be re-downloaded by Steam. Do you wish to continue?'), loot.l10n.translate('Redate'), function(result){ if (result) { loot.query('redatePlugins').then(function(response){ toast('Plugins were successfully redated.'); @@ -265,7 +265,7 @@ function onRedatePlugins(evt) { }); } function onClearAllMetadata(evt) { - showMessageDialog('', l10n.jed.translate('Are you sure you want to clear all existing user-added metadata from all plugins?').fetch(), l10n.jed.translate('Clear').fetch(), function(result){ + showMessageDialog('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from all plugins?'), loot.l10n.translate('Clear'), function(result){ if (result) { loot.query('clearAllMetadata').then(JSON.parse).then(function(result){ if (result) { @@ -287,7 +287,7 @@ function onClearAllMetadata(evt) { } }); - toast(l10n.jed.translate('All user-added metadata has been cleared.').fetch()); + toast(loot.l10n.translate('All user-added metadata has been cleared.')); } }).catch(processCefError); } @@ -344,7 +344,7 @@ function onCopyContent(evt) { }); loot.query(request).then(function(){ - toast(l10n.jed.translate("LOOT's content has been copied to the clipboard.").fetch()); + toast(loot.l10n.translate("LOOT's content has been copied to the clipboard.")); }).catch(processCefError); } function onCopyLoadOrder(evt) { @@ -366,7 +366,7 @@ function onCopyLoadOrder(evt) { }); loot.query(request).then(function(){ - toast(l10n.jed.translate("The load order has been copied to the clipboard.").fetch()); + toast(loot.l10n.translate("The load order has been copied to the clipboard.")); }).catch(processCefError); } function onSwitchSidebarTab(evt) { @@ -577,11 +577,11 @@ function onCopyMetadata(evt) { }); loot.query(request).then(function(){ - toast(l10n.jed.translate('The metadata for "%s" has been copied to the clipboard.').fetch(evt.target.getName())); + toast(loot.l10n.translate('The metadata for "%s" has been copied to the clipboard.', evt.target.getName())); }).catch(processCefError); } function onClearMetadata(evt) { - showMessageDialog('', l10n.jed.translate('Are you sure you want to clear all existing user-added metadata from "%s"?').fetch(evt.target.getName()), l10n.jed.translate('Clear').fetch(), function(result){ + showMessageDialog('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from "%s"?', evt.target.getName()), loot.l10n.translate('Clear'), function(result){ if (result) { var request = JSON.stringify({ name: 'clearPluginMetadata', @@ -607,7 +607,7 @@ function onClearMetadata(evt) { break; } } - toast(l10n.jed.translate('The user-added metadata for "%s" has been cleared.').fetch(evt.target.getName())); + toast(loot.l10n.translate('The user-added metadata for "%s" has been cleared.', evt.target.getName())); /* Now perform search again. If there is no current search, this won't do anything. */ document.getElementById('searchBar').search(); @@ -630,9 +630,9 @@ function onSidebarClick(evt) { } function onQuit(evt) { if (!document.getElementById('applySortButton').classList.contains('hidden')) { - handleUnappliedChangesClose(l10n.jed.translate('sorted load order').fetch()); + handleUnappliedChangesClose(loot.l10n.translate('sorted load order')); } else if (document.body.hasAttribute('data-editors')) { - handleUnappliedChangesClose(l10n.jed.translate('metadata edits').fetch()); + handleUnappliedChangesClose(loot.l10n.translate('metadata edits')); } else { window.close(); } @@ -643,7 +643,7 @@ function onJumpToGeneralInfo(evt) { } function onContentRefresh(evt) { /* Send a query for updated load order and plugin header info. */ - showProgress(l10n.jed.translate('Refreshing data...').fetch()); + showProgress(loot.l10n.translate('Refreshing data...')); loot.query('getGameData').then(function(result){ /* Parse the data sent from C++. */ try { diff --git a/src/gui/html/js/filters.js b/src/gui/html/js/filters.js index febd8971..dcebfc87 100644 --- a/src/gui/html/js/filters.js +++ b/src/gui/html/js/filters.js @@ -118,7 +118,7 @@ var filters = { doNotCleanFilter: function(message) { if (document.getElementById('hideDoNotCleanMessages').checked) { - return message.content[0].str.indexOf(l10n.jed.translate("Do not clean").fetch()) == -1; + return message.content[0].str.indexOf(loot.l10n.translate("Do not clean")) == -1; } else { return true; } @@ -157,7 +157,7 @@ function getConflictingPluginsFromFilter() { ] }); - showProgress(l10n.jed.translate('Checking if plugins have been loaded...').fetch()); + showProgress(loot.l10n.translate('Checking if plugins have been loaded...')); return loot.query(request).then(JSON.parse).then(function(result){ if (result) { diff --git a/src/gui/html/js/helpers.js b/src/gui/html/js/helpers.js index d5231983..086f3f5d 100644 --- a/src/gui/html/js/helpers.js +++ b/src/gui/html/js/helpers.js @@ -4,7 +4,7 @@ function processCefError(err) { promise errors, not just CEF errors. */ console.log(err.stack); closeProgressDialog(); - showMessageBox(l10n.jed.translate('Error').fetch(), err.message); + showMessageBox(loot.l10n.translate('Error'), err.message); } function showElement(element) { @@ -24,13 +24,13 @@ function toast(text) { } function showMessageDialog(title, text, positiveText, closeCallback) { var dialog = document.createElement('loot-message-dialog'); - dialog.setButtonText(positiveText, l10n.jed.translate('Cancel').fetch()); + dialog.setButtonText(positiveText, loot.l10n.translate('Cancel')); dialog.showModal(title, text, closeCallback); document.body.appendChild(dialog); } function showMessageBox(title, text) { var dialog = document.createElement('loot-message-dialog'); - dialog.setButtonText(l10n.jed.translate('OK').fetch()); + dialog.setButtonText(loot.l10n.translate('OK')); dialog.showModal(title, text); document.body.appendChild(dialog); } @@ -51,7 +51,7 @@ function closeProgressDialog() { } } function handleUnappliedChangesClose(change) { - showMessageDialog('', l10n.jed.translate('You have not yet applied or cancelled your %s. Are you sure you want to quit?').fetch(change), l10n.jed.translate('Quit').fetch(), function(result){ + showMessageDialog('', loot.l10n.translate('You have not yet applied or cancelled your %s. Are you sure you want to quit?', change), loot.l10n.translate('Quit'), function(result){ if (result) { /* Cancel any sorting and close any editors. Cheat by sending a cancelSort query for as many times as necessary. */ @@ -70,4 +70,3 @@ function handleUnappliedChangesClose(change) { } }); } - diff --git a/src/gui/html/js/init.js b/src/gui/html/js/init.js index dc650cb0..0b8d618e 100644 --- a/src/gui/html/js/init.js +++ b/src/gui/html/js/init.js @@ -35,7 +35,7 @@ function initVars() { if (loot.version.length > pos + 1) { document.getElementById('LOOTBuild').textContent = loot.version.substring(pos + 1); } else { - document.getElementById('LOOTBuild').textContent = l10n.jed.translate('unknown').fetch(); + document.getElementById('LOOTBuild').textContent = loot.l10n.translate('unknown'); } loot.version = loot.version.substring(0, pos); @@ -139,12 +139,12 @@ function initVars() { console.log('getSettings response: ' + results[2]); } }).then(function(){ - return l10n.getJedInstance(loot.settings.language).then(function(jed){ - l10n.translateStaticText(jed); - l10n.jed = jed; - - /* Also need to update the settings UI. */ - loot.updateSettingsUI(); + /* Translate static text. */ + loot.l10n = new loot.Translator(loot.settings.language); + loot.l10n.load().then(() => { + loot.translateStaticText(loot.l10n); + /* Also need to update the settings UI. */ + loot.updateSettingsUI(); }).catch(processCefError); }).then(function(){ if (result) { diff --git a/src/gui/html/js/l10n.js b/src/gui/html/js/l10n.js index 65aa32dc..80eeebb7 100644 --- a/src/gui/html/js/l10n.js +++ b/src/gui/html/js/l10n.js @@ -1,334 +1,331 @@ 'use strict'; -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(['bower_components/Jed/jed', 'bower_components/jed-gettext-parser/jedGettextParser'], factory); +(function exportModule(root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define([], factory); + } else { + // Browser globals + root.loot = root.loot || {}; + root.loot.translateStaticText = factory(); + } +}(this, () => { + function translatePluginCardTemplate(l10n) { + /* Plugin card template. */ + let pluginCard = document.querySelector('link[rel="import"][href$="loot-plugin-card.html"]'); + if (pluginCard) { + pluginCard = pluginCard.import.querySelector('template').content; } else { - // Browser globals - root.l10n = factory(root.Jed, root.jedGettextParser); + pluginCard = document.querySelector('polymer-element[name="loot-plugin-card"]').querySelector('template').content; } -}(this, function (jed, jedGettextParser) { - var defaultData = { - "messages": { - "": { - "domain" : "messages", - "lang" : "en", - "plural_forms" : "nplurals=2; plural=(n != 1);" - } - } - }; + pluginCard.getElementById('activeTick').setAttribute('label', l10n.translate('Active Plugin')); + pluginCard.getElementById('isMaster').setAttribute('label', l10n.translate('Master File')); + pluginCard.getElementById('emptyPlugin').setAttribute('label', l10n.translate('Empty Plugin')); + pluginCard.getElementById('loadsArchive').setAttribute('label', l10n.translate('Loads Archive')); + pluginCard.getElementById('hasUserEdits').setAttribute('label', l10n.translate('Has User Metadata')); - return { + pluginCard.getElementById('showOnlyConflicts').previousElementSibling.textContent = l10n.translate('Show Only Conflicts'); + pluginCard.getElementById('editMetadata').lastChild.textContent = l10n.translate('Edit Metadata'); + pluginCard.getElementById('copyMetadata').lastChild.textContent = l10n.translate('Copy Metadata'); + pluginCard.getElementById('clearMetadata').lastChild.textContent = l10n.translate('Clear User Metadata'); + } - loadLocaleData: function(locale) { - if (locale == 'en') { - return new Promise(function(resolve, reject){ - resolve(defaultData); - }); - } + function translatePluginEditorTemplate(l10n) { + /* Plugin editor template. */ + let pluginEditor = document.querySelector('link[rel="import"][href$="loot-plugin-card.html"]'); + if (pluginEditor) { + pluginEditor = pluginEditor.import.querySelector('link[rel="import"][href$="loot-plugin-editor.html"]').import.querySelector('template').content; + } else { + pluginEditor = document.querySelector('polymer-element[name="loot-plugin-editor"]').querySelector('template').content; + } - var url = 'loot://l10n/' + locale + '/LC_MESSAGES/loot.mo'; + pluginEditor.getElementById('activeTick').setAttribute('label', l10n.translate('Active Plugin')); + pluginEditor.getElementById('isMaster').setAttribute('label', l10n.translate('Master File')); + pluginEditor.getElementById('emptyPlugin').setAttribute('label', l10n.translate('Empty Plugin')); + pluginEditor.getElementById('loadsArchive').setAttribute('label', l10n.translate('Loads Archive')); - return new Promise(function(resolve, reject){ - var xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.responseType = 'arraybuffer'; - xhr.addEventListener('readystatechange', function(evt){ - if (evt.target.readyState == 4) { - /* Status is 0 for local file URL loading. */ - if (evt.target.status >= 200 && evt.target.status < 400) { - resolve(jedGettextParser.mo.parse(evt.target.response)); - } else { - reject(new Error('XHR Error')); - } - } - }, false); - xhr.send(); - }); - }, + pluginEditor.getElementById('enableEdits').previousElementSibling.textContent = l10n.translate('Enable Edits'); + pluginEditor.getElementById('globalPriority').parentElement.parentElement.setAttribute('label', l10n.translate('Global priorities are compared against all other plugins. Normal priorities are compared against only conflicting plugins.')); + pluginEditor.getElementById('globalPriority').previousElementSibling.textContent = l10n.translate('Global Priority'); + pluginEditor.getElementById('priorityValue').parentElement.previousElementSibling.textContent = l10n.translate('Priority Value'); - translateStaticText: function(l10n) { - /* Plugin card template. */ - var pluginCard = document.querySelector('link[rel="import"][href$="loot-plugin-card.html"]'); - if (pluginCard) { - pluginCard = pluginCard.import.querySelector('template').content; - } else { - pluginCard = document.querySelector('polymer-element[name="loot-plugin-card"]').querySelector('template').content; - } + pluginEditor.getElementById('tableTabs').querySelector('[data-for=main]').textContent = l10n.translate('Main'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=loadAfter]').textContent = l10n.translate('Load After'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=req]').textContent = l10n.translate('Requirements'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=inc]').textContent = l10n.translate('Incompatibilities'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=message]').textContent = l10n.translate('Messages'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=tags]').textContent = l10n.translate('Bash Tags'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=dirty]').textContent = l10n.translate('Dirty Info'); + pluginEditor.getElementById('tableTabs').querySelector('[data-for=locations]').textContent = l10n.translate('Locations'); - pluginCard.getElementById('activeTick').setAttribute('label', l10n.translate("Active Plugin").fetch()); - pluginCard.getElementById('isMaster').setAttribute('label', l10n.translate("Master File").fetch()); - pluginCard.getElementById('emptyPlugin').setAttribute('label', l10n.translate("Empty Plugin").fetch()); - pluginCard.getElementById('loadsArchive').setAttribute('label', l10n.translate("Loads Archive").fetch()); - pluginCard.getElementById('hasUserEdits').setAttribute('label', l10n.translate("Has User Metadata").fetch()); + pluginEditor.getElementById('loadAfter').querySelector('th:first-child').textContent = l10n.translate('Filename'); + pluginEditor.getElementById('loadAfter').querySelector('th:nth-child(2)').textContent = l10n.translate('Display Name'); + pluginEditor.getElementById('loadAfter').querySelector('th:nth-child(3)').textContent = l10n.translate('Condition'); - pluginCard.getElementById('showOnlyConflicts').previousElementSibling.textContent = l10n.translate("Show Only Conflicts").fetch(); - pluginCard.getElementById('editMetadata').lastChild.textContent = l10n.translate("Edit Metadata").fetch(); - pluginCard.getElementById('copyMetadata').lastChild.textContent = l10n.translate("Copy Metadata").fetch(); - pluginCard.getElementById('clearMetadata').lastChild.textContent = l10n.translate("Clear User Metadata").fetch(); + pluginEditor.getElementById('req').querySelector('th:first-child').textContent = l10n.translate('Filename'); + pluginEditor.getElementById('req').querySelector('th:nth-child(2)').textContent = l10n.translate('Display Name'); + pluginEditor.getElementById('req').querySelector('th:nth-child(3)').textContent = l10n.translate('Condition'); - /* Plugin editor template. */ - var pluginEditor = document.querySelector('link[rel="import"][href$="loot-plugin-card.html"]'); - if (pluginEditor) { - pluginEditor = pluginEditor.import.querySelector('link[rel="import"][href$="loot-plugin-editor.html"]').import.querySelector('template').content; - } else { - pluginEditor = document.querySelector('polymer-element[name="loot-plugin-editor"]').querySelector('template').content; - } + pluginEditor.getElementById('inc').querySelector('th:first-child').textContent = l10n.translate('Filename'); + pluginEditor.getElementById('inc').querySelector('th:nth-child(2)').textContent = l10n.translate('Display Name'); + pluginEditor.getElementById('inc').querySelector('th:nth-child(3)').textContent = l10n.translate('Condition'); - pluginEditor.getElementById('activeTick').setAttribute('label', l10n.translate("Active Plugin").fetch()); - pluginEditor.getElementById('isMaster').setAttribute('label', l10n.translate("Master File").fetch()); - pluginEditor.getElementById('emptyPlugin').setAttribute('label', l10n.translate("Empty Plugin").fetch()); - pluginEditor.getElementById('loadsArchive').setAttribute('label', l10n.translate("Loads Archive").fetch()); + pluginEditor.getElementById('message').querySelector('th:first-child').textContent = l10n.translate('Type'); + pluginEditor.getElementById('message').querySelector('th:nth-child(2)').textContent = l10n.translate('Content'); + pluginEditor.getElementById('message').querySelector('th:nth-child(3)').textContent = l10n.translate('Condition'); + pluginEditor.getElementById('message').querySelector('th:nth-child(4)').textContent = l10n.translate('Language'); - pluginEditor.getElementById('enableEdits').previousElementSibling.textContent = l10n.translate("Enable Edits").fetch(); - pluginEditor.getElementById('globalPriority').parentElement.parentElement.setAttribute('label', l10n.translate("Global priorities are compared against all other plugins. Normal priorities are compared against only conflicting plugins.").fetch()); - pluginEditor.getElementById('globalPriority').previousElementSibling.textContent = l10n.translate("Global Priority").fetch(); - pluginEditor.getElementById('priorityValue').parentElement.previousElementSibling.textContent = l10n.translate("Priority Value").fetch(); + pluginEditor.getElementById('tags').querySelector('th:first-child').textContent = l10n.translate('Add/Remove'); + pluginEditor.getElementById('tags').querySelector('th:nth-child(2)').textContent = l10n.translate('Bash Tag'); + pluginEditor.getElementById('tags').querySelector('th:nth-child(3)').textContent = l10n.translate('Condition'); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=main]').textContent = l10n.translate("Main").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=loadAfter]').textContent = l10n.translate("Load After").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=req]').textContent = l10n.translate("Requirements").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=inc]').textContent = l10n.translate("Incompatibilities").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=message]').textContent = l10n.translate("Messages").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=tags]').textContent = l10n.translate("Bash Tags").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=dirty]').textContent = l10n.translate("Dirty Info").fetch(); - pluginEditor.getElementById('tableTabs').querySelector('[data-for=locations]').textContent = l10n.translate("Locations").fetch(); + pluginEditor.getElementById('dirty').querySelector('th:first-child').textContent = l10n.translate('CRC'); + pluginEditor.getElementById('dirty').querySelector('th:nth-child(2)').textContent = l10n.translate('ITM Count'); + pluginEditor.getElementById('dirty').querySelector('th:nth-child(3)').textContent = l10n.translate('Deleted References'); + pluginEditor.getElementById('dirty').querySelector('th:nth-child(4)').textContent = l10n.translate('Deleted Navmeshes'); + pluginEditor.getElementById('dirty').querySelector('th:nth-child(5)').textContent = l10n.translate('Cleaning Utility'); - pluginEditor.getElementById('loadAfter').querySelector('th:first-child').textContent = l10n.translate("Filename").fetch(); - pluginEditor.getElementById('loadAfter').querySelector('th:nth-child(2)').textContent = l10n.translate("Display Name").fetch(); - pluginEditor.getElementById('loadAfter').querySelector('th:nth-child(3)').textContent = l10n.translate("Condition").fetch(); + pluginEditor.getElementById('locations').querySelector('th:first-child').textContent = l10n.translate('URL'); + pluginEditor.getElementById('locations').querySelector('th:nth-child(2)').textContent = l10n.translate('Name'); - pluginEditor.getElementById('req').querySelector('th:first-child').textContent = l10n.translate("Filename").fetch(); - pluginEditor.getElementById('req').querySelector('th:nth-child(2)').textContent = l10n.translate("Display Name").fetch(); - pluginEditor.getElementById('req').querySelector('th:nth-child(3)').textContent = l10n.translate("Condition").fetch(); + pluginEditor.getElementById('accept').parentElement.setAttribute('label', l10n.translate('Apply')); + pluginEditor.getElementById('cancel').parentElement.setAttribute('label', l10n.translate('Cancel')); + } - pluginEditor.getElementById('inc').querySelector('th:first-child').textContent = l10n.translate("Filename").fetch(); - pluginEditor.getElementById('inc').querySelector('th:nth-child(2)').textContent = l10n.translate("Display Name").fetch(); - pluginEditor.getElementById('inc').querySelector('th:nth-child(3)').textContent = l10n.translate("Condition").fetch(); + function translatePluginListItemTemplate(l10n) { + /* Plugin List Item Template */ + let pluginItem = document.querySelector('link[rel="import"][href$="loot-plugin-item.html"]'); + if (pluginItem) { + pluginItem = pluginItem.import.querySelector('template').content; + } else { + pluginItem = document.querySelector('polymer-element[name="loot-plugin-item"]').querySelector('template').content; + } + pluginItem.querySelector('#secondary core-tooltip').setAttribute('label', l10n.translate('Global Priority')); + pluginItem.getElementById('hasUserEditsTooltip').textContent = l10n.translate('Has User Metadata'); + pluginItem.getElementById('editorIsOpenTooltip').textContent = l10n.translate('Editor Is Open'); + } - pluginEditor.getElementById('message').querySelector('th:first-child').textContent = l10n.translate("Type").fetch(); - pluginEditor.getElementById('message').querySelector('th:nth-child(2)').textContent = l10n.translate("Content").fetch(); - pluginEditor.getElementById('message').querySelector('th:nth-child(3)').textContent = l10n.translate("Condition").fetch(); - pluginEditor.getElementById('message').querySelector('th:nth-child(4)').textContent = l10n.translate("Language").fetch(); + function translateFileRowTemplate(l10n) { + /* File row template */ + let fileRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (fileRow) { + fileRow = fileRow.import.querySelector('#fileRow').content; + } else { + fileRow = document.querySelector('#fileRow').content; + } + fileRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate('A filename is required.')); + fileRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - pluginEditor.getElementById('tags').querySelector('th:first-child').textContent = l10n.translate("Add/Remove").fetch(); - pluginEditor.getElementById('tags').querySelector('th:nth-child(2)').textContent = l10n.translate("Bash Tag").fetch(); - pluginEditor.getElementById('tags').querySelector('th:nth-child(3)').textContent = l10n.translate("Condition").fetch(); + function translateMessageRowTemplate(l10n) { + /* Message row template */ + let messageRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (messageRow) { + messageRow = messageRow.import.querySelector('#messageRow').content; + } else { + messageRow = document.querySelector('#messageRow').content; + } + messageRow.querySelector('.type').children[0].textContent = l10n.translate('Note'); + messageRow.querySelector('.type').children[1].textContent = l10n.translate('Warning'); + messageRow.querySelector('.type').children[2].textContent = l10n.translate('Error'); + messageRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate('A content string is required.')); + messageRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - pluginEditor.getElementById('dirty').querySelector('th:first-child').textContent = l10n.translate("CRC").fetch(); - pluginEditor.getElementById('dirty').querySelector('th:nth-child(2)').textContent = l10n.translate("ITM Count").fetch(); - pluginEditor.getElementById('dirty').querySelector('th:nth-child(3)').textContent = l10n.translate("Deleted References").fetch(); - pluginEditor.getElementById('dirty').querySelector('th:nth-child(4)').textContent = l10n.translate("Deleted Navmeshes").fetch(); - pluginEditor.getElementById('dirty').querySelector('th:nth-child(5)').textContent = l10n.translate("Cleaning Utility").fetch(); + function translateTagRowTemplate(l10n) { + /* Tag row template */ + let tagRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (tagRow) { + tagRow = tagRow.import.querySelector('#tagRow').content; + } else { + tagRow = document.querySelector('#tagRow').content; + } + tagRow.querySelector('.type').children[0].textContent = l10n.translate('Add'); + tagRow.querySelector('.type').children[1].textContent = l10n.translate('Remove'); + tagRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate('A name is required.')); + tagRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - pluginEditor.getElementById('locations').querySelector('th:first-child').textContent = l10n.translate("URL").fetch(); - pluginEditor.getElementById('locations').querySelector('th:nth-child(2)').textContent = l10n.translate("Name").fetch(); + function translateDirtyInfoRowTemplate(l10n) { + /* Dirty Info row template */ + let dirtyInfoRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (dirtyInfoRow) { + dirtyInfoRow = dirtyInfoRow.import.querySelector('#dirtyInfoRow').content; + } else { + dirtyInfoRow = document.querySelector('#dirtyInfoRow').content; + } - pluginEditor.getElementById('accept').parentElement.setAttribute('label', l10n.translate("Apply").fetch()); - pluginEditor.getElementById('cancel').parentElement.setAttribute('label', l10n.translate("Cancel").fetch()); + dirtyInfoRow.querySelector('loot-validated-input.crc').setAttribute('error', l10n.translate('A CRC is required.')); + dirtyInfoRow.querySelector('loot-validated-input.itm').setAttribute('error', l10n.translate('Values must be integers.')); + dirtyInfoRow.querySelector('loot-validated-input.udr').setAttribute('error', l10n.translate('Values must be integers.')); + dirtyInfoRow.querySelector('loot-validated-input.nav').setAttribute('error', l10n.translate('Values must be integers.')); + dirtyInfoRow.querySelector('loot-validated-input.util').setAttribute('error', l10n.translate('A utility name is required.')); + dirtyInfoRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - /* Plugin List Item Template */ - var pluginItem = document.querySelector('link[rel="import"][href$="loot-plugin-item.html"]'); - if (pluginItem) { - pluginItem = pluginItem.import.querySelector('template').content; - } else { - pluginItem = document.querySelector('polymer-element[name="loot-plugin-item"]').querySelector('template').content; - } - pluginItem.querySelector('#secondary core-tooltip').setAttribute('label', l10n.translate("Global Priority").fetch()); - pluginItem.getElementById('hasUserEditsTooltip').textContent = l10n.translate("Has User Metadata").fetch(); - pluginItem.getElementById('editorIsOpenTooltip').textContent = l10n.translate("Editor Is Open").fetch(); + function translateLocationRowTemplate(l10n) { + /* Location row template */ + let locationRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (locationRow) { + locationRow = locationRow.import.querySelector('#locationRow').content; + } else { + locationRow = document.querySelector('#locationRow').content; + } + locationRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate('A link is required.')); + locationRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - /* File row template */ - var fileRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (fileRow) { - fileRow = fileRow.import.querySelector('#fileRow').content; - } else { - fileRow = document.querySelector('#fileRow').content; - } - fileRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate("A filename is required.").fetch()); - fileRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + function translateGameRowTemplate(l10n) { + /* Game row template */ + let gameRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (gameRow) { + gameRow = gameRow.import.querySelector('#gameRow').content; + } else { + gameRow = document.querySelector('#gameRow').content; + } + gameRow.querySelector('loot-validated-input.name').setAttribute('error', l10n.translate('A name is required.')); + gameRow.querySelector('loot-validated-input.folder').setAttribute('error', l10n.translate('A folder is required.')); + gameRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Delete Row')); + } - /* Message row template */ - var messageRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (messageRow) { - messageRow = messageRow.import.querySelector('#messageRow').content; - } else { - messageRow = document.querySelector('#messageRow').content; - } - messageRow.querySelector('.type').children[0].textContent = l10n.translate("Note").fetch(); - messageRow.querySelector('.type').children[1].textContent = l10n.translate("Warning").fetch(); - messageRow.querySelector('.type').children[2].textContent = l10n.translate("Error").fetch(); - messageRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate("A content string is required.").fetch()); - messageRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + function translateNewRowTemplate(l10n) { + /* New row template */ + let newRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); + if (newRow) { + newRow = newRow.import.querySelector('#newRow').content; + } else { + newRow = document.querySelector('#newRow').content; + } + newRow.querySelector('core-tooltip').setAttribute('label', l10n.translate('Add New Row')); + } - /* Tag row template */ - var tagRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (tagRow) { - tagRow = tagRow.import.querySelector('#tagRow').content; - } else { - tagRow = document.querySelector('#tagRow').content; - } - tagRow.querySelector('.type').children[0].textContent = l10n.translate("Add").fetch(); - tagRow.querySelector('.type').children[1].textContent = l10n.translate("Remove").fetch(); - tagRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate("A name is required.").fetch()); - tagRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + function translateMainToolbar(l10n) { + /* Main toolbar */ + document.getElementById('jumpToGeneralInfo').parentElement.label = l10n.translate('Jump To General Information'); + document.getElementById('sortButton').parentElement.label = l10n.translate('Sort Plugins'); + document.getElementById('updateMasterlistButton').parentElement.label = l10n.translate('Update Masterlist'); + document.getElementById('applySortButton').textContent = l10n.translate('Apply'); + document.getElementById('cancelSortButton').textContent = l10n.translate('Cancel'); + document.getElementById('showSearch').parentElement.label = l10n.translate('Search Cards'); - /* Dirty Info row template */ - var dirtyInfoRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (dirtyInfoRow) { - dirtyInfoRow = dirtyInfoRow.import.querySelector('#dirtyInfoRow').content; - } else { - dirtyInfoRow = document.querySelector('#dirtyInfoRow').content; - } - dirtyInfoRow.querySelector('loot-validated-input.crc').setAttribute('error', l10n.translate("A CRC is required.").fetch()); - dirtyInfoRow.querySelector('loot-validated-input.itm').setAttribute('error', l10n.translate("Values must be integers.").fetch()); - dirtyInfoRow.querySelector('loot-validated-input.udr').setAttribute('error', l10n.translate("Values must be integers.").fetch()); - dirtyInfoRow.querySelector('loot-validated-input.nav').setAttribute('error', l10n.translate("Values must be integers.").fetch()); - dirtyInfoRow.querySelector('loot-validated-input.util').setAttribute('error', l10n.translate("A utility name is required.").fetch()); - dirtyInfoRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + /* Toolbar menu */ + document.getElementById('redatePluginsButton').lastElementChild.textContent = l10n.translate('Redate Plugins'); + document.getElementById('openLogButton').lastElementChild.textContent = l10n.translate('Open Debug Log Location'); + document.getElementById('wipeUserlistButton').lastElementChild.textContent = l10n.translate('Clear All User Metadata'); + document.getElementById('copyLoadOrderButton').lastElementChild.textContent = l10n.translate('Copy Load Order'); + document.getElementById('copyContentButton').lastElementChild.textContent = l10n.translate('Copy Content'); + document.getElementById('refreshContentButton').lastElementChild.textContent = l10n.translate('Refresh Content'); + document.getElementById('helpButton').lastElementChild.textContent = l10n.translate('View Documentation'); + document.getElementById('aboutButton').lastElementChild.textContent = l10n.translate('About'); + document.getElementById('settingsButton').lastElementChild.textContent = l10n.translate('Settings'); + document.getElementById('quitButton').lastElementChild.textContent = l10n.translate('Quit'); - /* Location row template */ - var locationRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (locationRow) { - locationRow = locationRow.import.querySelector('#locationRow').content; - } else { - locationRow = document.querySelector('#locationRow').content; - } - locationRow.querySelector('loot-validated-input').setAttribute('error', l10n.translate("A link is required.").fetch()); - locationRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + /* Search bar */ + document.getElementById('searchBar').shadowRoot.getElementById('search').label = l10n.translate('Search cards'); + } - /* Game row template */ - var gameRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (gameRow) { - gameRow = gameRow.import.querySelector('#gameRow').content; - } else { - gameRow = document.querySelector('#gameRow').content; - } - gameRow.querySelector('loot-validated-input.name').setAttribute('error', l10n.translate("A name is required.").fetch()); - gameRow.querySelector('loot-validated-input.folder').setAttribute('error', l10n.translate("A folder is required.").fetch()); - gameRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Delete Row").fetch()); + function translateSidebar(l10n) { + /* Nav items */ + document.getElementById('sidebarTabs').firstElementChild.textContent = l10n.translate('Plugins'); + document.getElementById('sidebarTabs').firstElementChild.nextElementSibling.textContent = l10n.translate('Filters'); + document.getElementById('contentFilter').parentElement.label = l10n.translate('Press Enter or click outside the input to set the filter.'); + document.getElementById('contentFilter').label = l10n.translate('Filter content'); - /* New row template */ - var newRow = document.querySelector('link[rel="import"][href$="editable-table.html"]'); - if (newRow) { - newRow = newRow.import.querySelector('#newRow').content; - } else { - newRow = document.querySelector('#newRow').content; - } - newRow.querySelector('core-tooltip').setAttribute('label', l10n.translate("Add New Row").fetch()); + /* Filters */ + document.getElementById('hideVersionNumbers').label = l10n.translate('Hide version numbers'); + document.getElementById('hideCRCs').label = l10n.translate('Hide CRCs'); + document.getElementById('hideBashTags').label = l10n.translate('Hide Bash Tags'); + document.getElementById('hideNotes').label = l10n.translate('Hide notes'); + document.getElementById('hideDoNotCleanMessages').label = l10n.translate('Hide \'Do not clean\' messages'); + document.getElementById('hideAllPluginMessages').label = l10n.translate('Hide all plugin messages'); + document.getElementById('hideInactivePlugins').label = l10n.translate('Hide inactive plugins'); + document.getElementById('hideMessagelessPlugins').label = l10n.translate('Hide messageless plugins'); + document.getElementById('hiddenPluginsTxt').textContent = l10n.translate('Hidden plugins:'); + document.getElementById('hiddenMessagesTxt').textContent = l10n.translate('Hidden messages:'); + } - /* Main toolbar */ - document.getElementById('jumpToGeneralInfo').parentElement.label = l10n.translate("Jump To General Information").fetch(); - document.getElementById('sortButton').parentElement.label = l10n.translate("Sort Plugins").fetch(); - document.getElementById('updateMasterlistButton').parentElement.label = l10n.translate("Update Masterlist").fetch(); - document.getElementById('applySortButton').textContent = l10n.translate("Apply").fetch(); - document.getElementById('cancelSortButton').textContent = l10n.translate("Cancel").fetch(); - document.getElementById('showSearch').parentElement.label = l10n.translate("Search Cards").fetch(); + function translateSummaryCard(l10n) { + /* Summary */ + document.getElementById('summary').firstElementChild.textContent = l10n.translate('General Information'); + document.getElementById('masterlistRevision').previousElementSibling.textContent = l10n.translate('Masterlist Revision'); + document.getElementById('masterlistDate').previousElementSibling.textContent = l10n.translate('Masterlist Date'); + document.getElementById('totalWarningNo').previousElementSibling.textContent = l10n.translate('Warnings'); + document.getElementById('totalErrorNo').previousElementSibling.textContent = l10n.translate('Errors'); + document.getElementById('totalMessageNo').previousElementSibling.textContent = l10n.translate('Total Messages'); + document.getElementById('activePluginNo').previousElementSibling.textContent = l10n.translate('Active Plugins'); + document.getElementById('dirtyPluginNo').previousElementSibling.textContent = l10n.translate('Dirty Plugins'); + document.getElementById('totalPluginNo').previousElementSibling.textContent = l10n.translate('Total Plugins'); + } - /* Toolbar menu */ - document.getElementById('redatePluginsButton').lastElementChild.textContent = l10n.translate("Redate Plugins").fetch(); - document.getElementById('openLogButton').lastElementChild.textContent = l10n.translate("Open Debug Log Location").fetch(); - document.getElementById('wipeUserlistButton').lastElementChild.textContent = l10n.translate("Clear All User Metadata").fetch(); - document.getElementById('copyLoadOrderButton').lastElementChild.textContent = l10n.translate("Copy Load Order").fetch(); - document.getElementById('copyContentButton').lastElementChild.textContent = l10n.translate("Copy Content").fetch(); - document.getElementById('refreshContentButton').lastElementChild.textContent = l10n.translate("Refresh Content").fetch(); - document.getElementById('helpButton').lastElementChild.textContent = l10n.translate("View Documentation").fetch(); - document.getElementById('aboutButton').lastElementChild.textContent = l10n.translate("About").fetch(); - document.getElementById('settingsButton').lastElementChild.textContent = l10n.translate("Settings").fetch(); - document.getElementById('quitButton').lastElementChild.textContent = l10n.translate("Quit").fetch(); + function translateSettingsDialog(l10n) { + /* Settings dialog */ + document.getElementById('settingsDialog').heading = l10n.translate('Settings'); - /* Search bar */ - document.getElementById('searchBar').shadowRoot.getElementById('search').label = l10n.translate("Search cards").fetch(); + const defaultGameSelect = document.getElementById('defaultGameSelect'); + defaultGameSelect.previousElementSibling.textContent = l10n.translate('Default Game'); + defaultGameSelect.firstElementChild.textContent = l10n.translate('Autodetect'); + /* The selected text doesn't update, so force that translation. */ + defaultGameSelect.shadowRoot.querySelector('paper-dropdown-menu').selectedItemLabel = defaultGameSelect.shadowRoot.querySelector('core-menu').selectedItem.textContent; - /* Nav items */ - document.getElementById('sidebarTabs').firstElementChild.textContent = l10n.translate("Plugins").fetch(); - document.getElementById('sidebarTabs').firstElementChild.nextElementSibling.textContent = l10n.translate("Filters").fetch(); - document.getElementById('contentFilter').parentElement.label = l10n.translate("Press Enter or click outside the input to set the filter.").fetch(); - document.getElementById('contentFilter').label = l10n.translate("Filter content").fetch(); + document.getElementById('languageSelect').previousElementSibling.textContent = l10n.translate('Language'); + document.getElementById('languageSelect').previousElementSibling.label = l10n.translate('Language changes will be applied after LOOT is restarted.'); - /* Filters */ - document.getElementById('hideVersionNumbers').label = l10n.translate("Hide version numbers").fetch(); - document.getElementById('hideCRCs').label = l10n.translate("Hide CRCs").fetch(); - document.getElementById('hideBashTags').label = l10n.translate("Hide Bash Tags").fetch(); - document.getElementById('hideNotes').label = l10n.translate("Hide notes").fetch(); - document.getElementById('hideDoNotCleanMessages').label = l10n.translate("Hide 'Do not clean' messages").fetch(); - document.getElementById('hideAllPluginMessages').label = l10n.translate("Hide all plugin messages").fetch(); - document.getElementById('hideInactivePlugins').label = l10n.translate("Hide inactive plugins").fetch(); - document.getElementById('hideMessagelessPlugins').label = l10n.translate("Hide messageless plugins").fetch(); - document.getElementById('hiddenPluginsTxt').textContent = l10n.translate("Hidden plugins:").fetch(); - document.getElementById('hiddenMessagesTxt').textContent = l10n.translate("Hidden messages:").fetch(); + document.getElementById('enableDebugLogging').previousElementSibling.textContent = l10n.translate('Enable debug logging'); + document.getElementById('enableDebugLogging').parentElement.label = l10n.translate('The output is logged to the LOOTDebugLog.txt file.'); - /* Summary */ - document.getElementById('summary').firstElementChild.textContent = l10n.translate("General Information").fetch(); - document.getElementById('masterlistRevision').previousElementSibling.textContent = l10n.translate("Masterlist Revision").fetch(); - document.getElementById('masterlistDate').previousElementSibling.textContent = l10n.translate("Masterlist Date").fetch(); - document.getElementById('totalWarningNo').previousElementSibling.textContent = l10n.translate("Warnings").fetch(); - document.getElementById('totalErrorNo').previousElementSibling.textContent = l10n.translate("Errors").fetch(); - document.getElementById('totalMessageNo').previousElementSibling.textContent = l10n.translate("Total Messages").fetch(); - document.getElementById('activePluginNo').previousElementSibling.textContent = l10n.translate("Active Plugins").fetch(); - document.getElementById('dirtyPluginNo').previousElementSibling.textContent = l10n.translate("Dirty Plugins").fetch(); - document.getElementById('totalPluginNo').previousElementSibling.textContent = l10n.translate("Total Plugins").fetch(); + document.getElementById('updateMasterlist').previousElementSibling.textContent = l10n.translate('Update masterlist before sorting'); - /* Settings dialog */ - document.getElementById('settingsDialog').heading = l10n.translate("Settings").fetch(); + const gameTable = document.getElementById('gameTable'); + gameTable.querySelector('th:first-child').textContent = l10n.translate('Name'); + gameTable.querySelector('th:nth-child(2)').textContent = l10n.translate('Base Game'); + gameTable.querySelector('th:nth-child(3)').textContent = l10n.translate('LOOT Folder'); + gameTable.querySelector('th:nth-child(4)').textContent = l10n.translate('Master File'); + gameTable.querySelector('th:nth-child(5)').textContent = l10n.translate('Masterlist Repository URL'); + gameTable.querySelector('th:nth-child(6)').textContent = l10n.translate('Masterlist Repository Branch'); + gameTable.querySelector('th:nth-child(7)').textContent = l10n.translate('Install Path'); + gameTable.querySelector('th:nth-child(8)').textContent = l10n.translate('Install Path Registry Key'); - var defaultGameSelect = document.getElementById('defaultGameSelect'); - defaultGameSelect.previousElementSibling.textContent = l10n.translate("Default Game").fetch(); - defaultGameSelect.firstElementChild.textContent = l10n.translate("Autodetect").fetch(); - /* The selected text doesn't update, so force that translation. */ - defaultGameSelect.shadowRoot.querySelector('paper-dropdown-menu').selectedItemLabel = defaultGameSelect.shadowRoot.querySelector('core-menu').selectedItem.textContent; + /* As the game table is attached on launch, its "Add New Row" + tooltip doesn't benefit from the template translation above. */ + gameTable.querySelector('tr:last-child core-tooltip').setAttribute('label', l10n.translate('Add New Row')); - document.getElementById('languageSelect').previousElementSibling.textContent = l10n.translate("Language").fetch(); - document.getElementById('languageSelect').previousElementSibling.label = l10n.translate("Language changes will be applied after LOOT is restarted.").fetch(); + document.getElementById('settingsDialog').getElementsByClassName('accept')[0].textContent = l10n.translate('Apply'); + document.getElementById('settingsDialog').getElementsByClassName('cancel')[0].textContent = l10n.translate('Cancel'); + } - document.getElementById('enableDebugLogging').previousElementSibling.textContent = l10n.translate("Enable debug logging").fetch(); - document.getElementById('enableDebugLogging').parentElement.label = l10n.translate("The output is logged to the LOOTDebugLog.txt file.").fetch(); + function translateFirstRunDialog(l10n) { + /* First-run dialog */ + const firstRun = document.getElementById('firstRun'); + firstRun.heading = l10n.translate('First-Time Tips'); - document.getElementById('updateMasterlist').previousElementSibling.textContent = l10n.translate("Update masterlist before sorting").fetch(); + firstRun.querySelector('li:nth-child(3)').textContent = l10n.translate('CRCs are only displayed after plugins have been loaded, either by conflict filtering, or by sorting.'); + firstRun.querySelector('li:nth-child(4)').textContent = l10n.translate('Double-click a plugin in the sidebar to quickly open its metadata editor. Multiple metadata editors can be opened at once.'); + firstRun.querySelector('li:nth-child(5)').textContent = l10n.translate('Plugins can be drag and dropped from the sidebar into editors\' "load after", "requirements" and "incompatibility" tables.'); + firstRun.querySelector('li:nth-child(6)').textContent = l10n.translate('Some features are disabled while there is an editor open, or while there is a sorted load order that has not been applied or discarded.'); + firstRun.querySelector('li:last-child').textContent = l10n.translate('Many interface elements have tooltips. If you don\'t know what something is, try hovering your mouse over it to find out. Otherwise, LOOT\'s documentation can be accessed through the main menu.'); - var gameTable = document.getElementById('gameTable'); - gameTable.querySelector('th:first-child').textContent = l10n.translate("Name").fetch(); - gameTable.querySelector('th:nth-child(2)').textContent = l10n.translate("Base Game").fetch(); - gameTable.querySelector('th:nth-child(3)').textContent = l10n.translate("LOOT Folder").fetch(); - gameTable.querySelector('th:nth-child(4)').textContent = l10n.translate("Master File").fetch(); - gameTable.querySelector('th:nth-child(5)').textContent = l10n.translate("Masterlist Repository URL").fetch(); - gameTable.querySelector('th:nth-child(6)').textContent = l10n.translate("Masterlist Repository Branch").fetch(); - gameTable.querySelector('th:nth-child(7)').textContent = l10n.translate("Install Path").fetch(); - gameTable.querySelector('th:nth-child(8)').textContent = l10n.translate("Install Path Registry Key").fetch(); + firstRun.getElementsByTagName('paper-button')[0].textContent = l10n.translate('OK'); + } - /* As the game table is attached on launch, its "Add New Row" - tooltip doesn't benefit from the template translation above. */ - gameTable.querySelector('tr:last-child core-tooltip').setAttribute('label', l10n.translate("Add New Row").fetch()); + return (l10n) => { + translatePluginCardTemplate(l10n); + translatePluginEditorTemplate(l10n); + translatePluginListItemTemplate(l10n); - document.getElementById('settingsDialog').getElementsByClassName('accept')[0].textContent = l10n.translate("Apply").fetch(); - document.getElementById('settingsDialog').getElementsByClassName('cancel')[0].textContent = l10n.translate("Cancel").fetch(); + translateFileRowTemplate(l10n); + translateMessageRowTemplate(l10n); + translateTagRowTemplate(l10n); + translateDirtyInfoRowTemplate(l10n); + translateLocationRowTemplate(l10n); + translateGameRowTemplate(l10n); + translateNewRowTemplate(l10n); - /* First-run dialog */ - var firstRun = document.getElementById('firstRun'); - firstRun.heading = l10n.translate("First-Time Tips").fetch(); + translateMainToolbar(l10n); + translateSidebar(l10n); - firstRun.querySelector('li:nth-child(3)').textContent = l10n.translate("CRCs are only displayed after plugins have been loaded, either by conflict filtering, or by sorting.").fetch(); - firstRun.querySelector('li:nth-child(4)').textContent = l10n.translate("Double-click a plugin in the sidebar to quickly open its metadata editor. Multiple metadata editors can be opened at once.").fetch(); - firstRun.querySelector('li:nth-child(5)').textContent = l10n.translate("Plugins can be drag and dropped from the sidebar into editors' \"load after\", \"requirements\" and \"incompatibility\" tables.").fetch(); - firstRun.querySelector('li:nth-child(6)').textContent = l10n.translate("Some features are disabled while there is an editor open, or while there is a sorted load order that has not been applied or discarded.").fetch(); - firstRun.querySelector('li:last-child').textContent = l10n.translate("Many interface elements have tooltips. If you don't know what something is, try hovering your mouse over it to find out. Otherwise, LOOT's documentation can be accessed through the main menu.").fetch(); - - firstRun.getElementsByTagName('paper-button')[0].textContent = l10n.translate("OK").fetch(); - }, - - getJedInstance: function(locale) { - return this.loadLocaleData(locale).catch(function(error){ - console.log(error); - return defaultData; - }).then(function(result){ - return new jed({ - 'locale_data': result, - 'domain': 'messages' - }); - }); - } - - }; + translateSummaryCard(l10n); + translateSettingsDialog(l10n); + translateFirstRunDialog(l10n); + }; })); diff --git a/src/gui/html/js/loot.js b/src/gui/html/js/loot.js index 183ce78a..6cb6d401 100644 --- a/src/gui/html/js/loot.js +++ b/src/gui/html/js/loot.js @@ -180,12 +180,12 @@ var loot = { if (change.object[change.name] && change.object[change.name].revision) { document.getElementById('masterlistRevision').textContent = change.object[change.name].revision; } else { - document.getElementById('masterlistRevision').textContent = l10n.jed.translate("N/A").fetch(); + document.getElementById('masterlistRevision').textContent = loot.l10n.translate("N/A"); } if (change.object[change.name] && change.object[change.name].date) { document.getElementById('masterlistDate').textContent = change.object[change.name].date; } else { - document.getElementById('masterlistDate').textContent = l10n.jed.translate("N/A").fetch(); + document.getElementById('masterlistDate').textContent = loot.l10n.translate("N/A"); } } else if (change.name == 'globalMessages') { /* For the messages, they don't have a JS 'class' so need to everything diff --git a/src/gui/html/js/translator.js b/src/gui/html/js/translator.js new file mode 100644 index 00000000..bfd01567 --- /dev/null +++ b/src/gui/html/js/translator.js @@ -0,0 +1,74 @@ +'use strict'; + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['bower_components/Jed/jed', 'bower_components/jed-gettext-parser/jedGettextParser'], factory); + } else { + // Browser globals + root.loot = root.loot || {}; + root.loot.Translator = factory(root.Jed, root.jedGettextParser); + } +}(this, (Jed, jedGettextParser) => { + return class Translator { + /* Returns a Promise */ + constructor(locale) { + this.locale = locale || 'en'; + this.jed = undefined; + } + + load() { + const defaultTranslationData = { + 'messages': { + '': { + 'domain': 'messages', + 'lang': 'en', + 'plural_forms': 'nplurals=2; plural=(n != 1);', + }, + }, + }; + + let translationDataPromise; + if (this.locale === 'en') { + /* Just resolve to an empty data set. */ + translationDataPromise = Promise.resolve(defaultTranslationData); + } else { + translationDataPromise = new Promise((resolve, reject) => { + const url = 'loot://l10n/' + this.locale + '/LC_MESSAGES/loot.mo'; + const xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'arraybuffer'; + xhr.addEventListener('readystatechange', (evt) => { + if (evt.target.readyState === 4) { + /* Status is 0 for local file URL loading. */ + if (evt.target.status >= 200 && evt.target.status < 400) { + resolve(jedGettextParser.mo.parse(evt.target.response)); + } else { + reject(new Error(evt.target.statusText)); + } + } + }, false); + xhr.send(); + }); + } + + return translationDataPromise.catch((error) => { + console.log('Error loading translation data: ' + error.message); + return defaultTranslationData; + }).then((result) => { + this.jed = new Jed({ + 'locale_data': result, + 'domain': 'messages', + }); + }); + } + + translate(text, ...substitutions) { + if (text === undefined) { + return ''; + } + const func = this.jed.translate(text); + return func.fetch.apply(func, substitutions); + } + }; +})); diff --git a/src/tests/gui/html/js/test.html b/src/tests/gui/html/js/test.html index 7d52378c..f8068dff 100644 --- a/src/tests/gui/html/js/test.html +++ b/src/tests/gui/html/js/test.html @@ -7,9 +7,14 @@ + + + + +