Iterate over all instances of variable/tag for _t substitutions

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2019-08-22 18:17:08 +01:00
parent efe8254985
commit b5daba9026
2 changed files with 57 additions and 32 deletions

View file

@ -179,12 +179,12 @@ export function replaceByRegexes(text, mapping) {
for (const regexpString in mapping) { for (const regexpString in mapping) {
// TODO: Cache regexps // TODO: Cache regexps
const regexp = new RegExp(regexpString); const regexp = new RegExp(regexpString, "g");
// Loop over what output we have so far and perform replacements // Loop over what output we have so far and perform replacements
// We look for matches: if we find one, we get three parts: everything before the match, the replaced part, // We look for matches: if we find one, we get three parts: everything before the match, the replaced part,
// and everything after the match. Insert all three into the output. We need to do this because we can insert objects. // and everything after the match. Insert all three into the output. We need to do this because we can insert objects.
// Otherwise there would be no need for the splitting and we could do simple replcement. // Otherwise there would be no need for the splitting and we could do simple replacement.
let matchFoundSomewhere = false; // If we don't find a match anywhere we want to log it let matchFoundSomewhere = false; // If we don't find a match anywhere we want to log it
for (const outputIndex in output) { for (const outputIndex in output) {
const inputText = output[outputIndex]; const inputText = output[outputIndex];
@ -192,44 +192,58 @@ export function replaceByRegexes(text, mapping) {
continue; continue;
} }
const match = inputText.match(regexp); // process every match in the string
if (!match) { // starting with the first
continue; let match = regexp.exec(inputText);
}
if (!match) continue;
matchFoundSomewhere = true; matchFoundSomewhere = true;
const capturedGroups = match.slice(2); // The textual part before the first match
// The textual part before the match
const head = inputText.substr(0, match.index); const head = inputText.substr(0, match.index);
// The textual part after the match const parts = [];
const tail = inputText.substr(match.index + match[0].length); // keep track of prevMatch
let prevMatch;
while (match) {
// store prevMatch
prevMatch = match;
const capturedGroups = match.slice(2);
let replaced; let replaced;
// If substitution is a function, call it // If substitution is a function, call it
if (mapping[regexpString] instanceof Function) { if (mapping[regexpString] instanceof Function) {
replaced = mapping[regexpString].apply(null, capturedGroups); replaced = mapping[regexpString].apply(null, capturedGroups);
} else { } else {
replaced = mapping[regexpString]; replaced = mapping[regexpString];
}
if (typeof replaced === 'object') {
shouldWrapInSpan = true;
}
// Here we also need to check that it actually is a string before comparing against one
// The head and tail are always strings
if (typeof replaced !== 'string' || replaced !== '') {
parts.push(replaced);
}
// try the next match
match = regexp.exec(inputText);
// add the text between prevMatch and this one
// or the end of the string if prevMatch is the last match
if (match) {
const startIndex = prevMatch.index + prevMatch[0].length;
parts.push(inputText.substr(startIndex, match.index - startIndex));
} else {
parts.push(inputText.substr(prevMatch.index + prevMatch[0].length));
}
} }
if (typeof replaced === 'object') {
shouldWrapInSpan = true;
}
output.splice(outputIndex, 1); // Remove old element
// Insert in reverse order as splice does insert-before and this way we get the final order correct // Insert in reverse order as splice does insert-before and this way we get the final order correct
if (tail !== '') { // remove the old element at the same time
output.splice(outputIndex, 0, tail); output.splice(outputIndex, 1, ...parts);
}
// Here we also need to check that it actually is a string before comparing against one
// The head and tail are always strings
if (typeof replaced !== 'string' || replaced !== '') {
output.splice(outputIndex, 0, replaced);
}
if (head !== '') { // Don't push empty nodes, they are of no use if (head !== '') { // Don't push empty nodes, they are of no use
output.splice(outputIndex, 0, head); output.splice(outputIndex, 0, head);

View file

@ -70,4 +70,15 @@ describe('languageHandler', function() {
const text = '%(var1)s %(var2)s'; const text = '%(var1)s %(var2)s';
expect(languageHandler._t(text, { var2: 'val2', var1: 'val1' })).toBe('val1 val2'); expect(languageHandler._t(text, { var2: 'val2', var1: 'val1' })).toBe('val1 val2');
}); });
it('multiple replacements of the same variable', function() {
const text = '%(var1)s %(var1)s';
expect(languageHandler._t(text, { var1: 'val1' })).toBe('val1 val1');
});
it('multiple replacements of the same tag', function() {
const text = '<a>Click here</a> to join the discussion! <a>or here</a>';
expect(languageHandler._t(text, {}, { 'a': (sub) => `x${sub}x` }))
.toBe('xClick herex to join the discussion! xor herex');
});
}); });