From b5daba90261df41b8d39d98966a48c0a113b416e Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 22 Aug 2019 18:17:08 +0100
Subject: [PATCH 1/3] Iterate over all instances of variable/tag for _t
substitutions
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/languageHandler.js | 78 +++++++++++++++-----------
test/i18n-test/languageHandler-test.js | 11 ++++
2 files changed, 57 insertions(+), 32 deletions(-)
diff --git a/src/languageHandler.js b/src/languageHandler.js
index 474cd2b3cd..9e354cee9e 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -179,12 +179,12 @@ export function replaceByRegexes(text, mapping) {
for (const regexpString in mapping) {
// 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
// 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.
- // 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
for (const outputIndex in output) {
const inputText = output[outputIndex];
@@ -192,44 +192,58 @@ export function replaceByRegexes(text, mapping) {
continue;
}
- const match = inputText.match(regexp);
- if (!match) {
- continue;
- }
+ // process every match in the string
+ // starting with the first
+ let match = regexp.exec(inputText);
+
+ if (!match) continue;
matchFoundSomewhere = true;
- const capturedGroups = match.slice(2);
-
- // The textual part before the match
+ // The textual part before the first match
const head = inputText.substr(0, match.index);
- // The textual part after the match
- const tail = inputText.substr(match.index + match[0].length);
+ const parts = [];
+ // keep track of prevMatch
+ let prevMatch;
+ while (match) {
+ // store prevMatch
+ prevMatch = match;
+ const capturedGroups = match.slice(2);
- let replaced;
- // If substitution is a function, call it
- if (mapping[regexpString] instanceof Function) {
- replaced = mapping[regexpString].apply(null, capturedGroups);
- } else {
- replaced = mapping[regexpString];
+ let replaced;
+ // If substitution is a function, call it
+ if (mapping[regexpString] instanceof Function) {
+ replaced = mapping[regexpString].apply(null, capturedGroups);
+ } else {
+ 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
- if (tail !== '') {
- output.splice(outputIndex, 0, tail);
- }
-
- // 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);
- }
+ // remove the old element at the same time
+ output.splice(outputIndex, 1, ...parts);
if (head !== '') { // Don't push empty nodes, they are of no use
output.splice(outputIndex, 0, head);
diff --git a/test/i18n-test/languageHandler-test.js b/test/i18n-test/languageHandler-test.js
index ce9f8e1684..07e3f2cb8b 100644
--- a/test/i18n-test/languageHandler-test.js
+++ b/test/i18n-test/languageHandler-test.js
@@ -70,4 +70,15 @@ describe('languageHandler', function() {
const text = '%(var1)s %(var2)s';
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 = 'Click here to join the discussion! or here';
+ expect(languageHandler._t(text, {}, { 'a': (sub) => `x${sub}x` }))
+ .toBe('xClick herex to join the discussion! xor herex');
+ });
});
From 310457059b32b0503c8575d8a6093599000e4ade Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 22 Aug 2019 18:31:02 +0100
Subject: [PATCH 2/3] [i18n] only append tail if it is actually needed
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/languageHandler.js | 12 ++++++++++--
test/i18n-test/languageHandler-test.js | 4 ++--
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/src/languageHandler.js b/src/languageHandler.js
index 9e354cee9e..e5656e5f69 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -177,6 +177,10 @@ export function replaceByRegexes(text, mapping) {
// If we insert any components we need to wrap the output in a span. React doesn't like just an array of components.
let shouldWrapInSpan = false;
+ if (text === "You are now ignoring %(userId)s") {
+ debugger;
+ }
+
for (const regexpString in mapping) {
// TODO: Cache regexps
const regexp = new RegExp(regexpString, "g");
@@ -233,11 +237,15 @@ export function replaceByRegexes(text, mapping) {
// add the text between prevMatch and this one
// or the end of the string if prevMatch is the last match
+ let tail;
if (match) {
const startIndex = prevMatch.index + prevMatch[0].length;
- parts.push(inputText.substr(startIndex, match.index - startIndex));
+ tail = inputText.substr(startIndex, match.index - startIndex);
} else {
- parts.push(inputText.substr(prevMatch.index + prevMatch[0].length));
+ tail = inputText.substr(prevMatch.index + prevMatch[0].length);
+ }
+ if (tail) {
+ parts.push(tail);
}
}
diff --git a/test/i18n-test/languageHandler-test.js b/test/i18n-test/languageHandler-test.js
index 07e3f2cb8b..0d96bc15ab 100644
--- a/test/i18n-test/languageHandler-test.js
+++ b/test/i18n-test/languageHandler-test.js
@@ -73,12 +73,12 @@ describe('languageHandler', function() {
it('multiple replacements of the same variable', function() {
const text = '%(var1)s %(var1)s';
- expect(languageHandler._t(text, { var1: 'val1' })).toBe('val1 val1');
+ expect(languageHandler.substitute(text, { var1: 'val1' })).toBe('val1 val1');
});
it('multiple replacements of the same tag', function() {
const text = 'Click here to join the discussion! or here';
- expect(languageHandler._t(text, {}, { 'a': (sub) => `x${sub}x` }))
+ expect(languageHandler.substitute(text, {}, { 'a': (sub) => `x${sub}x` }))
.toBe('xClick herex to join the discussion! xor herex');
});
});
From 7d511fbbc5d0513f8575464cd58d4e0c65bea9f4 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Thu, 22 Aug 2019 18:34:26 +0100
Subject: [PATCH 3/3] remove leftover debugger =)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
src/languageHandler.js | 4 ----
1 file changed, 4 deletions(-)
diff --git a/src/languageHandler.js b/src/languageHandler.js
index e5656e5f69..179bb2d1d0 100644
--- a/src/languageHandler.js
+++ b/src/languageHandler.js
@@ -177,10 +177,6 @@ export function replaceByRegexes(text, mapping) {
// If we insert any components we need to wrap the output in a span. React doesn't like just an array of components.
let shouldWrapInSpan = false;
- if (text === "You are now ignoring %(userId)s") {
- debugger;
- }
-
for (const regexpString in mapping) {
// TODO: Cache regexps
const regexp = new RegExp(regexpString, "g");