0

I'm making a translation function, and I want to easily add translations inside an object and then change each globally inside the $("body").html(), problem is, when I use new RegExp() inside my for loop it cuts the loop after first iteration.

if (window.location.href.indexOf("sv") > -1) {
    //CUSTOM TRANSLATIONS

    var translations = {
        'All': 'alla',
        'Filter Members': 'Filtrera medlemar',
    }



    for (var key in translations) {
        if (translations.hasOwnProperty(key)) {

            console.log(key + " -> " + translations[key]);
            $body = jQuery("body");
            replaceThis = new RegExp(key, "g");

            alert(replaceThis);

            $body.html($body.html().replace(replaceThis, translations[key]));

        }
    }

}
Googlian
  • 6,077
  • 3
  • 38
  • 44
Carl Papworth
  • 1,282
  • 2
  • 16
  • 35
  • have you tried JQuery foreach? `$.each( translations, function( key, value ) { //your code});` – David Apr 23 '19 at 07:33
  • 2
    Tried you snippet and is working for me. Also, I don't think `if (translations.hasOwnProperty(key))` is useful. – Kévin Bibollet Apr 23 '19 at 07:36
  • Tried and I get the same problem. I do see an error now that says: "VM3774:13 Uncaught TypeError: document.querySelectoralla is not a function" – Carl Papworth Apr 23 '19 at 07:37
  • @CarlPapworth thats another error (not in the code you provided). Try using `querySelectorAll()` instead of `querySelectoralla`. It may be a syntax error – David Apr 23 '19 at 07:40
  • 2
    As far as regex is concerned you need to [escape the literal pattern](https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript). – Wiktor Stribiżew Apr 23 '19 at 07:40
  • I tried and change the order of inside the array, and then it worked ... could it have been some wierd hidden character inside the array? – Carl Papworth Apr 23 '19 at 07:41
  • 2
    You get that error because it will also translate ` – Kévin Bibollet Apr 23 '19 at 07:41
  • I tried to change my keys and values, and it seems that the having the key set to "All" cuts everything after ... does this make sense to anyone? I mean, I can solve it by always having it at the bottom, but ... it's weird right? – Carl Papworth Apr 23 '19 at 07:45

3 Answers3

2

It seems you have script inside your body tag and because of that your script runs into an error. Try adding a html container element on all the html and then perform the operation on that container element instead of body.

var translations = {
  'All': 'alla',
  'Filter Members': 'Filtrera medlemar'
};

for (var key in translations) {
  if (translations.hasOwnProperty(key)) {

    //console.log(key + " -> " + translations[key]);
    $container = jQuery(".container");
    replaceThis = new RegExp(key, "g");

    //alert(replaceThis);

    $container.html($container.html().replace(replaceThis, translations[key]));

  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="container">
  <div>All</div>
  <div>Filter Members</div>
  <div>All</div>
  <div>Filter Members</div>
</div>
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
  • Is there a good away to make sure that only text inside html-tags and nothing else (like url's etc) will be replaced? – Carl Papworth Apr 23 '19 at 07:55
  • 1
    @CarlPapworth - You can improve your regex to cater only text inside tags. For reference - https://stackoverflow.com/questions/6041241/regular-expression-to-replace-html-content – Nikhil Aggarwal Apr 23 '19 at 08:01
1

As you are using a bidimensional array you need to bind 2 params to your function, one for the key and one for the value. This example should work.

jQuery.each( translations, function( key, value ) {
  console.log(key + " -> " + translations[key]);
  $body =  jQuery("body");
  replaceThis = new RegExp(key, "g");
  alert(replaceThis);
  $body.html($body.html().replace(replaceThis, translations[key]));
});
David
  • 614
  • 5
  • 20
0

Issues

  • Do not target <html> or <body> tags, or window or document -- target an element nested within the <body> as Mr. Aggarwal's answer and iArcadia's comment suggests.

  • iArcadia's comments also points out that there is superfluous code: translations.hasOwnProperty(key)

  • A search string passed through a RegExp Object should be escaped as Mr. Stribiżew pointed out in comments. Without escaping a given string, undesired results ensue such as:

    • matching substrings (ex. search string: All matches: Alligator)

    • matching HTML tags (ex. search string: class matches: <div class="...>)

Solution

I just wrote a quick jQuery plugin called .translateWord():

Usage: $(selector).translateWord(matrix)
Param:
selector {string}: CSS/jQuery selector string syntax
matrix {array}: Two dimension array of key/value pairs

It converts a given array of arrays (matrix) to an ES6 Map (dictionary). Each key (keyword) is escaped (escape):

`(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${keyword})\\b`

then passed through a RegExp() Object (regex) that in turn searches and replaces with the dictionary value corresponding to the dictionary key.

let en2sv = [
  ['them', 'dem'],
  ['you', 'du'],
  ["I'm", 'Jag är'],
  ['was', 'var']
];

(function($) {
  $.fn.translateWord = function(matrix) {
    let dictionary = new Map(matrix);
    for (let keyword of dictionary.keys()) {
      let string = $(this).html();
      let escape = `(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${keyword})\\b`;
      let regex = new RegExp(escape, "gi");
      let html = string.replace(regex, `<mark>${dictionary.get(keyword)}</mark>`);
      $(this).html(html);
    }
  }
})(jQuery);

$('main').translateWord(en2sv);
<main>
  <article>
    <h1>HEISENBERG IPSUM</h1>
    <section>
      <h2>I</h2>
      <p>What? What do you want?! No. Don't even tell me you're hungry. Don't go there. Hahaha! Are you mad doggin' them, Tio? What, you don't like them? One ding. That means yes. Tio don't like you. Why don't you like them, Tio? You don't trust them? Why
        don't you trust them, Tio? BULLSHIT! MY TIO DOES NOT LIE!</p>
    </section>
    <section>
      <h2>II</h2>
      <p>You... are trouble. I'm sorry the kid here doesn't see it, but I sure as hell do. You are a time bomb. Tick, tick, ticking. And I have no intention of being around for the boom. Well... you know how they say, it's been a pleasure? It hasn't.</p>
    </section>
    <section>
      <h2>III</h2>
      <p>Walter, I'm your lawyer. Anything you say to me is totally privileged. I'm not in the shakedown racket. I'm a lawyer. Even drug dealers need lawyers, right? Especially drug dealers.</p>
    </section>
    <section>
      <h2>IV</h2>
      <p>My partner was about to get himself shot. I intervened. He was angry because those two dealers of yours had just murdered an eleven year-old boy. Then again, maybe he thought it was you who gave the order. </p>
    </section>
  </article>
</main>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Community
  • 1
  • 1
zer00ne
  • 41,936
  • 6
  • 41
  • 68