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

Tips for resolving SyntaxError: Unable to utilize import when integrating Magic with NextJS in a Typescript configuration

Looking to integrate Magic into NextJS using TypeScript. Following a guide that uses JavaScript instead of TypeScript: https://github.com/magiclabs/example-nextjs Encountering an issue when trying to import Magic as shown below: import { Magic } from &qu ...

Personalize the file button for uploading images

I have a button to upload image files and I want to customize it to allow for uploading more than one image file. What is the logic to achieve this? <input type="file" />, which renders a choose button with text that says `no files chosen` in the sa ...

How to smoothly transition a div from one location to another using animations in an Ionic3-Angular4 application

I'm attempting to incorporate some animation into my Ionic 3 mobile app. Specifically, I want to shift a div from one location to another. In the code snippet provided below, I am looking to move the div with the "upper" class after the timeline-item ...

Having trouble retrieving the table value from an HTML document?

I am trying to retrieve specific information from this source: This information is crucial for fetching data from a database using a primary key. However, extracting this value has proven to be quite challenging. Upon document readiness, I execute the fol ...

I am attempting to code a program but it keeps displaying errors

What is hierarchical inheritance in AngularJS? I have been attempting to implement it, but I keep encountering errors. import {SecondcomponentComponent} from './secondcomponent/secondcomponent.Component'; import {thirdcomponentcomponent} from & ...

Ember Gain a comprehensive understanding of the flow of execution between route and controller

Below is a snippet of my "box" route/controller: export default Ember.Controller.extend({ initialized: false, type: 'P', status: 'done', layouts: null, toggleFltr: null, gridVals: Ember.computed.alias('mode ...

Issue encountered at 'site construction' phase: failure in build script with exit code 2

I am a novice and struggling to solve this error. I have attempted to fix it by adjusting the deploy settings, but I can't seem to resolve this compilation error. The syntax errors are overwhelming, and I'm not sure if there is something crucial ...

Display alternative text dynamically

Trying to gain a deeper understanding of state in react, this is a perfect example to me. When I say dynamic, I mean displaying the output below instantly as it is entered in the form. class Demo extends Component { constructor(props) { super ...

Halt the script if the file has not been successfully loaded

Looking for a way to halt the script until $.get() has completed executing in this code snippet. $.get("assets/data/html/navigation.html", function(response) { $('body').append(response); }); $('body').append('<div class="m ...

Looking for guidance on where to find a functional code sample or comprehensive tutorial on working with ViewMetadata in Angular2

I am currently trying to understand the relationship between viewmetadata and the fundamental use of encapsulation: ViewEncapsulation, including ViewEncapsulation.Emulated and ViewEncapsulation.None. Here is a link for further information: https://angula ...

Steps for storing div content (image) on server

Currently in the process of developing a web application that allows users to crop images. The goal is for users to have the ability to email the URL so others can view the cropped image, ensuring that the URL remains active indefinitely by storing every c ...

Dynamic resizing in NextJs does not trigger a re-render

My goal is to dynamically pass the width value to a component's styles. Everything works fine on initial load, but when I resize the window, the component fails to re-render even though the hook is functioning as intended. I came across some informat ...

Optimizing Midnight UTC+0 Setting in JavaScript Date Functions

I am using an MUI Datepicker that allows me to choose a day without specifying the time. For example, if I select 01.09.1970, in the console log it displays as Tue Sep 01 1970 00:00:00 GMT+0100 (Central European Standard Time). This indicates that even tho ...

Utilizing a Static Image Path Prop in React JS: A Step-by-Step Guide

My Main Component import React from "react"; import TopModal from "./components/topModal"; // Passing productImage to the Child Component import productImage from "../../../../../../assets/images/juices.jpg"; import { makeS ...

Encountered a 'Require() of ES Module' Error while Implementing Visx with Nextjs

Currently, I am utilizing the Visx library for chart creation within Nextjs. The scales provided by Visx are imported in this manner: import { scaleBand, scaleLinear, scaleOrdinal } from "@visx/scale" It is important to note that internally, Vi ...

Discover the significance of a data attribute's value for effective comparisons

I have a loop that generates random numbers and positions to create 4 answer choices for users. Now, I am trying to determine the value of the clicked button and compare it to the position of the correct answer. However, whenever I try to do this, it retu ...

What is the best way to showcase a value in JavaScript using CSS styling?

I'm looking to customize the background, font style, and outline for both open and closed elements in the code snippet below: a.innerHTML = "We are Open now now."; a.innerHTML = "We are Closed, arm."; Additionally, I want to appl ...

Suggestions for this screenplay

I am completely new to the world of coding and computer languages, and I could use some guidance on how to utilize this script for a flash sale. setInterval(function() { var m = Math.floor((new Date).getTime()/1000); if(m == '1476693000000& ...

What is the best way to retrieve the name of a static method within a class?

In my code, I am logging multiple messages in a static method and I want to use the method name as context. However, I do not want to create a separate variable called `context` and assign the function/method name to it. I would like to be able to access ...

What happens when there is no match found while attempting to edit a form with the UI-Bootstrap typeahead directive?

Here is the code that demonstrates how my typeahead input box functions. Users can enter a name, and the relevant information will populate the rest of the form. If no match is found, users should still be able to input the name and related details into th ...