Fix l10n of JS strings with format args

The translate() function with a variable number of parameters couldn't
be used in conjunction with plural forms support in Boost.Locale, and
wasn't getting picked up by the pre-commit hook.

Also detect l10n strings in the query handling header files, though
someone else had already added them to the POT file.
This commit is contained in:
Oliver Hamlet
2016-11-24 17:58:39 +00:00
parent c582b5e971
commit 5b7e74c02e
7 changed files with 98 additions and 13 deletions
+39 -2
View File
@@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: LOOT 0.10.0\n"
"Project-Id-Version: LOOT 0.10.1\n"
"Report-Msgid-Bugs-To: https://github.com/loot/loot/issues\n"
"POT-Creation-Date: 2016-11-22 18:27+0000\n"
"POT-Creation-Date: 2016-11-22 19:11+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -25,10 +25,20 @@ msgstr ""
msgid "Updating and parsing masterlist..."
msgstr ""
#: src/gui/html/js/events.js:97
#, javascript-format
msgid "Masterlist updated to revision %s."
msgstr ""
#: src/gui/html/js/events.js:100
msgid "No masterlist update was necessary."
msgstr ""
#: src/gui/html/js/events.js:130
#, javascript-format
msgid "Failed to sort plugins. Details: %s"
msgstr ""
#: src/gui/html/js/events.js:150
msgid "Sorting made no changes to the load order."
msgstr ""
@@ -75,6 +85,12 @@ msgstr ""
msgid "The load order has been copied to the clipboard."
msgstr ""
#: src/gui/html/js/events.js:267
#, javascript-format
msgid ""
"You have not yet applied or cancelled your %s. Are you sure you want to quit?"
msgstr ""
#: src/gui/html/js/events.js:267 src/gui/html/js/translateStaticText.js:214
msgid "Quit"
msgstr ""
@@ -87,6 +103,22 @@ msgstr ""
msgid "metadata edits"
msgstr ""
#: src/gui/html/js/events.js:395
#, javascript-format
msgid "The metadata for \"%s\" has been copied to the clipboard."
msgstr ""
#: src/gui/html/js/events.js:399
#, javascript-format
msgid ""
"Are you sure you want to clear all existing user-added metadata from \"%s\"?"
msgstr ""
#: src/gui/html/js/events.js:414
#, javascript-format
msgid "The user-added metadata for \"%s\" has been cleared."
msgstr ""
#: src/gui/html/js/filters.js:28
msgid "Do not clean"
msgstr ""
@@ -100,6 +132,11 @@ msgstr ""
msgid "Error"
msgstr ""
#: src/gui/html/js/initialise.js:250
#, javascript-format
msgid "A [new release](%s) of LOOT is available."
msgstr ""
#: src/gui/html/js/translateStaticText.js:36
msgid "Active Plugin"
msgstr ""
+1 -1
View File
@@ -5,7 +5,7 @@
# commit if more than one line in it has changed, otherwise discard any changes
# to it.
xgettext -k"translate:1,1t" -k"translate:1c,2,t" --add-location=full --from-code=utf-8 --package-name=LOOT --package-version=0.10.1 --copyright-holder="WrinklyNinja" --msgid-bugs-address="https://github.com/loot/loot/issues" -o resources/l10n/template.pot src/gui/html/js/*.* src/gui/*.cpp src/backend/*/*.* src/backend/*.*
xgettext -k"translate:1,1t" -k"translateFormatted:1" --add-location=full --from-code=utf-8 --package-name=LOOT --package-version=0.10.1 --copyright-holder="WrinklyNinja" --msgid-bugs-address="https://github.com/loot/loot/issues" -o resources/l10n/template.pot src/gui/html/js/*.* src/gui/*.cpp src/gui/query/*.h src/backend/*/*.* src/backend/*.*
sed -i 's|charset=CHARSET|charset=UTF-8|' resources/l10n/template.pot
+1 -1
View File
@@ -240,7 +240,7 @@
updateIsCleanIcon() {
this.$.isClean.hidden = !this.data.cleanedWith;
this.$.isCleanTooltip.textContent = loot.l10n.translate('Verified clean by %s', this.data.cleanedWith);
this.$.isCleanTooltip.textContent = loot.l10n.translateFormatted('Verified clean by %s', this.data.cleanedWith);
},
updateStyling() {
+6 -6
View File
@@ -94,7 +94,7 @@ function updateMasterlist() {
}
});
loot.Dialog.showNotification(loot.l10n.translate('Masterlist updated to revision %s.',
loot.Dialog.showNotification(loot.l10n.translateFormatted('Masterlist updated to revision %s.',
loot.game.masterlist.revision));
} else {
loot.Dialog.showNotification(loot.l10n.translate('No masterlist update was necessary.'));
@@ -127,7 +127,7 @@ function onSortPlugins() {
const message = result.globalMessages.find(item => (
item.text.startsWith('Cyclic interaction detected'
))).text;
throw new Error(loot.l10n.translate('Failed to sort plugins. Details: %s', message));
throw new Error(loot.l10n.translateFormatted('Failed to sort plugins. Details: %s', message));
}
/* Check if sorted load order differs from current load order. */
@@ -264,7 +264,7 @@ function onOpenLogLocation() {
loot.query('openLogLocation').catch(loot.handlePromiseError);
}
function handleUnappliedChangesClose(change) {
loot.Dialog.askQuestion('', loot.l10n.translate('You have not yet applied or cancelled your %s. Are you sure you want to quit?', change), loot.l10n.translate('Quit'), (result) => {
loot.Dialog.askQuestion('', loot.l10n.translateFormatted('You have not yet applied or cancelled your %s. Are you sure you want to quit?', change), loot.l10n.translate('Quit'), (result) => {
if (!result) {
return;
}
@@ -392,11 +392,11 @@ function onEditorClose(evt) {
}
function onCopyMetadata(evt) {
loot.query('copyMetadata', evt.target.getName()).then(() => {
loot.Dialog.showNotification(loot.l10n.translate('The metadata for "%s" has been copied to the clipboard.', evt.target.getName()));
loot.Dialog.showNotification(loot.l10n.translateFormatted('The metadata for "%s" has been copied to the clipboard.', evt.target.getName()));
}).catch(loot.handlePromiseError);
}
function onClearMetadata(evt) {
loot.Dialog.askQuestion('', loot.l10n.translate('Are you sure you want to clear all existing user-added metadata from "%s"?', evt.target.getName()), loot.l10n.translate('Clear'), (result) => {
loot.Dialog.askQuestion('', loot.l10n.translateFormatted('Are you sure you want to clear all existing user-added metadata from "%s"?', evt.target.getName()), loot.l10n.translate('Clear'), (result) => {
if (!result) {
return;
}
@@ -411,7 +411,7 @@ function onClearMetadata(evt) {
existingPlugin.update(plugin);
}
loot.Dialog.showNotification(loot.l10n.translate('The user-added metadata for "%s" has been cleared.', evt.target.getName()));
loot.Dialog.showNotification(loot.l10n.translateFormatted('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();
+1 -1
View File
@@ -247,7 +247,7 @@
dom.appendGeneralMessages([{
type: 'warn',
content: loot.l10n.translate('A [new release](%s) of LOOT is available.', 'https://github.com/loot/loot/releases/latest'),
content: loot.l10n.translateFormatted('A [new release](%s) of LOOT is available.', 'https://github.com/loot/loot/releases/latest'),
}]);
})
.catch(handlePromiseError);
+5 -1
View File
@@ -64,7 +64,11 @@
});
}
translate(text, ...substitutions) {
translate(text) {
return this.translateFormatted(text);
}
translateFormatted(text, ...substitutions) {
if (text === undefined) {
return '';
}
+45 -1
View File
@@ -72,6 +72,50 @@ describe('Translator', () => {
l10n.translate('foo').should.equal('bar');
});
});
describe('#translateFormatted()', () => {
let l10n;
beforeEach(() => {
l10n = new loot.Translator();
});
it('should return original string if the translator has not been loaded', () => {
l10n.translateFormatted('foo').should.equal('foo');
});
it('should return an empty string if nothing is passed', () =>
l10n.load().then(() => {
l10n.translateFormatted().should.equal('');
})
);
it('should return the input string if the current locale is "en"', () =>
l10n.load().then(() => {
l10n.translateFormatted('foo').should.equal('foo');
})
);
it('should return the translated string if locale data has been loaded', () => {
/* Since loading data doesn't work in the browser, hack it by setting some
data manually. */
l10n.jed = new window.Jed({
locale_data: {
messages: {
'': {
domain: 'messages',
lang: 'en',
plural_forms: 'nplurals=2; plural=(n != 1);',
},
foo: ['bar'],
},
},
domain: 'messages',
});
l10n.translateFormatted('foo').should.equal('bar');
});
it('should subsitute additional arguments into string', () => {
/* Since loading data doesn't work in the browser, hack it by setting some
@@ -90,7 +134,7 @@ describe('Translator', () => {
domain: 'messages',
});
l10n.translate('foo %1$s %2$s', 'is not', 'bar').should.equal('bar is bar');
l10n.translateFormatted('foo %1$s %2$s', 'is not', 'bar').should.equal('bar is bar');
});
});
});