Issue with the recursive function in javascript for object modification

I have all the text content for my app stored in a .json file for easy translation. I am trying to create a function that will retrieve the relevant text based on the selected language.

Although I believe this should be a simple task, I seem to be struggling to find the solution.

The object structure I am working with is as follows:

{
  section1: {
    btn: { en: "English", es: "Español" },
    title: {
      en: "Web Frontend Developer",
      es: "Desarrollador Web de Frontend"
    },
    card: {
      title: { en: "Hello!", es: "Hola!" },
      btn: { en: "Get started", es: "Empecemos" },
    }
  }
}

To achieve this, I need to pass this object as the first parameter to a function, and the second parameter should specify the language (e.g., "en" or "es"). The function call should look something like this:

filterObjByLanguage(obj, "es")

The expected output would be:

{
  section1: {
    btn: "Español",
    title: "Desarrollador Web de Frontend",
    card: {
      title: "Hola!",
      btn: "Empecemos"
    }
  }
}

In essence, the function should iterate through each part of the object and select the appropriate text based on the specified language key (

{ en:"text", es: "texto" }
).

I have made an attempt at this, but currently, only the first layer of the object is returned correctly while the rest remains undefined.

const filterObjByLanguage= (obj: any, lang: string): any => {
  const output = Object.assign(obj, {});

  const loop = (obj: any, isRoot: boolean = true): any => {
    for (var k in obj) {
      const value = output[k];
      const valueAtSelected = value?.[lang];

      if (typeof value === "string") {
        continue;
      } else if (valueAtSelected) {
        if (isRoot) output[k] = valueAtSelected;
        else return valueAtSelected;
      } else {
        if (isRoot) output[k] = loop(value, false);
        else return loop(value, false);
      }
    }
  };

  loop(output);

  return output;
};

Answer №1

One challenge we face is distinguishing between language values and collections of them within objects. To address this, I utilize the presence of an 'en' property as a signal. The key steps involve deconstructing and reconstructing objects using Object.entries and Object.fromEntries. In vanilla JavaScript (leaving Typescript for aficionados), the approach may resemble the following:

const filterObjByLanguage = (lang) => (o) =>
  Object (o) === o
    ? 'en' in o
      ? o [lang] || ''
      : Object .fromEntries (
          Object .entries (o) .map (([k, v]) => [k, filterObjByLanguage (lang) (v)])
        )
    : o

const i18n = {section1: {btn: {en: "English", es: "Español"}, title: {en: "Web Frontend Developer", es: "Desarrollador Web de Frontend"}, card: {title: {en: "Hello!", es: "Hola!"}, btn: {en: "Get started", es: "Empecemos"}}}}

console .log ('English', filterObjByLanguage ('en') (i18n))
console .log ('Español', filterObjByLanguage ('es') (i18n))
console .log ('Français', filterObjByLanguage ('fr') (i18n))
.as-console-wrapper {max-height: 100% !important; top: 0}

This implementation assumes that missing language values default to empty strings. If you prefer undefined, simply eliminate || ''. To accommodate arrays when necessary, we can easily expand upon this by making a minor adjustment:

const filterObjByLanguage = (lang) => (o) =>
  Array .isArray (o) 
    ? o .map (filterObjByLanguage (lang)) 
  : Object (o) === o
    ? 'en' in o
      ? o [lang] || ''
      : Object .fromEntries (
          Object .entries (o) .map (([k, v]) => [k, filterObjByLanguage (lang) (v)])
        )
  : o

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Pagination in Datatables

Here is the code snippet I am working with: $('#ldap-users, #audit-users').dataTable({ "sDom": "<'row'<'span6'l><'span6'f>r>t<'row'<'span6'i><'span6'p& ...

I've encountered some issues with importing pagination from modules after installing SwiperJs

Having some issues with importing pagination from modules in SwiperJs for my nextjs project. The error message "Module not found: Package path ./modules is not exported from package" keeps popping up. I have tried updating the module to the latest version ...

Having Trouble Displaying Material UI Icons in Your React App? Here's Why: "Invalid Objects as React Children"

I have been working on a basic app that showcases information about a patient. In this specific component, I am only displaying the name, occupation, and a symbol from Material UI to indicate whether the patient is male or female. However, when I attempt ...

Adjust rankings based on the number of upvotes received by a project

I'm facing a challenge with ranking projects based on the number of votes they receive. No matter the vote count, the project always ends up getting ranked as 1. To address this issue, I developed a function to manage the rank count and a return hand ...

Changing HTML dynamically does not trigger the ng-click event within ng-bind-html

I have developed a custom directive that can display messages along with rendering HTML content that may contain Angular attributes like buttons, anchor tags with ng-click attribute, and more. index.html: <ir-error-panel status="status"></ir-err ...

Removing HTML DOM elements from a string using JavaScript: A step-by-step guide

Hey there, I'm currently working on my angular application. When it comes to inserting the first 100 characters of content into the "description" meta tag for Facebook sharing, I've run into an issue. The description ends up including the HTML el ...

`How can I enable the download attribute feature on Safari browser?`

Is there a workaround for saving files with a specified name in Safari? The following HTML code does not work properly in Safari, as it saves the file as 'unknown' without an extension name. <a href="data:application/csv;charset=utf-8,Col1%2C ...

Use vue.js to add a block of content after every sixth iteration in a loop

Currently, I have a list of offer cards rendering through a loop. I am adding a row div every 3rd column (bootstrap) element. Now, I need to also add another column element (banner block) for every 6th element in order to achieve a layout like the one show ...

Update the user information by using its unique identifier at a specific location

I am currently working on editing user data with a specific MongoDB instance. When I click on the user's details, a modal popup appears with an update button below it. My goal is to have the user data updated when this button is clicked for the partic ...

Retrieving information from a JSON document in IONIC with the help of AngularJS

Issue After using the ionic tabs template to create my first project with the ionic framework, I noticed that the data for friends and friend details is being pulled from an array list in the services.js file. However, I would like to instead fetch this d ...

Problems with importing modules in Apollo Server

I've encountered a never-ending stream of error messages post importing Apollo Server into my Typescript-based Node.js application. (Check out the screenshot below) It appears that Apollo is unable to locate anything in the graphql dependency. Could ...

Looking to transform a list into JSON format using JavaScript?

I have a collection that looks like this: <ol class="BasketballPlayers"> <li id="1">Player: LeBron, TotalPoints: 28753, MVP: true</li> <li id="2">Player: Steph, TotalPoints: 17670, MVP: true< ...

Develop a custom JavaScript code block in Selenium WebDriver using Java

Recently, I came across a JavaScript code snippet that I executed in the Chrome console to calculate the sum of values in a specific column of a web table: var iRow = document.getElementById("DataTable").rows.length var sum = 0 var column = 5 for (i=1; i& ...

Having difficulty retrieving the Area and Range information in ChartJS

I am new to working with HTML5 and ChartJS. I have noticed two different types of declarations when attaching JS Chart Versions 1.0.1 and 2.1.1. Can you please provide some insight into this? Additionally, I am facing an issue where the stripes behind the ...

"Troubleshooting IE-specific problem: Loading dropdown options dynamically with AJAX on change

Struggling with a particular issue lately. I'm attempting to populate a second dropdown menu based on the selection made in the first one using jquery ajax. Surprisingly, it works flawlessly on all browsers except for IE 11. Below is the ajax functio ...

It is not possible for AngularJS to retrieve values using ng-model when ng-repeat is being used

Is there a way to capture dynamically generated data using ng-model (data created with ng-repeat) so that I can send it as an object to Firebase, my flat database? Currently, the ng-model is only retrieving empty strings as values. Any ideas for a solution ...

What could be the reason for my onChange event not functioning properly?

The issue I'm experiencing involves my onchange event not properly copying the text from the current span to the hidden field. Any ideas on why this might be happening? Check out my code at this link. ...

What is the best way to refresh the slick jQuery plugin for sliders and carousels?

I am currently facing an issue with two buttons that have the same function. The purpose of these buttons is to retrieve data from an API, convert it to HTML, and then append it to a <div> using jQuery. Finally, the data is displayed using the slick ...

After using `setAttribute`, React is unable to produce any audio

Currently, I am facing an issue with a React component where it should play sound from an array of IDs stored in the database by setting the ID to the src attribute for the source tag. However, this functionality is not working as expected. Interestingly, ...

When using Ajax in Jquery and expecting data of type JSON, the response always seems

Looking to create a basic jQuery Ajax script that checks a user's discount code when the "Check Discount Code" button is clicked? Check out this prototype: <script> jQuery(function($) { $("#btn-check-discount").click(function() { c ...