mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
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:
@@ -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 ""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -64,7 +64,11 @@
|
||||
});
|
||||
}
|
||||
|
||||
translate(text, ...substitutions) {
|
||||
translate(text) {
|
||||
return this.translateFormatted(text);
|
||||
}
|
||||
|
||||
translateFormatted(text, ...substitutions) {
|
||||
if (text === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user