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]));

        }
    }

}
8
  • have you tried JQuery foreach? $.each( translations, function( key, value ) { //your code}); Commented Apr 23, 2019 at 7:33
  • 2
    Tried you snippet and is working for me. Also, I don't think if (translations.hasOwnProperty(key)) is useful. Commented Apr 23, 2019 at 7: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" Commented Apr 23, 2019 at 7:37
  • 2
    As far as regex is concerned you need to escape the literal pattern. Commented Apr 23, 2019 at 7:40
  • 2
    You get that error because it will also translate <script> since you try to alter <body>'s html. So querySelectorAll => querySelectoralla. (My comment is true only if your scripts are inside your <body>) Commented Apr 23, 2019 at 7:41

3 Answers 3

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Is there a good away to make sure that only text inside html-tags and nothing else (like url's etc) will be replaced?
@CarlPapworth - You can improve your regex to cater only text inside tags. For reference - stackoverflow.com/questions/6041241/…
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]));
});

Comments

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.