Localization Pipeline Dashboard Node.js

👤 Sharing: AI
```javascript
// localization-dashboard.js

// Import necessary modules
const express = require('express');
const fs = require('fs');
const path = require('path');

// Initialize Express app
const app = express();
const port = 3000;

// Middleware to serve static files (HTML, CSS, JavaScript)
app.use(express.static('public'));

// Middleware to parse JSON request bodies
app.use(express.json());

//  Data storage (Simulated database - could be replaced with a real database)
let localizationData = {
  en: {
    greeting: "Hello, world!",
    welcomeMessage: "Welcome to our website!",
    buttonLabel: "Click me"
  },
  fr: {
    greeting: "Bonjour, le monde!",
    welcomeMessage: "Bienvenue sur notre site web!",
    buttonLabel: "Cliquez ici"
  },
  es: {
    greeting: "?Hola, mundo!",
    welcomeMessage: "?Bienvenido a nuestro sitio web!",
    buttonLabel: "Haz clic aqu?"
  }
};

//  Endpoint to get all localization data
app.get('/api/localization', (req, res) => {
  res.json(localizationData);
});

//  Endpoint to get localization data for a specific language
app.get('/api/localization/:language', (req, res) => {
  const language = req.params.language;
  if (localizationData[language]) {
    res.json(localizationData[language]);
  } else {
    res.status(404).json({ error: 'Language not found' });
  }
});

// Endpoint to update localization data for a specific language and key
app.put('/api/localization/:language/:key', (req, res) => {
    const language = req.params.language;
    const key = req.params.key;
    const newValue = req.body.value;  // Expect the new value in the request body

    if (!localizationData[language]) {
        return res.status(404).json({ error: `Language "${language}" not found.` });
    }

    if (!localizationData[language].hasOwnProperty(key)) {
        return res.status(404).json({ error: `Key "${key}" not found for language "${language}".` });
    }

    localizationData[language][key] = newValue;

    console.log(`Updated ${language}.${key} to: ${newValue}`);
    res.json({ message: `Successfully updated ${language}.${key}` });  // Confirmation message

});


// Endpoint to add a new language
app.post('/api/localization/addLanguage', (req, res) => {
  const newLanguageCode = req.body.languageCode;
  const defaultLanguage = req.body.defaultLanguage; // E.g., 'en' if you want to copy English values
    
  if (!newLanguageCode) {
      return res.status(400).json({ error: 'Language code is required.' });
  }
  
  if (localizationData[newLanguageCode]) {
      return res.status(400).json({ error: `Language "${newLanguageCode}" already exists.` });
  }

  // Initialize the new language object. Copy the default language's values if specified.
  if (defaultLanguage && localizationData[defaultLanguage]) {
      localizationData[newLanguageCode] = { ...localizationData[defaultLanguage] };
      console.log(`Created language "${newLanguageCode}" with default values from "${defaultLanguage}".`);
  } else {
      localizationData[newLanguageCode] = {}; // Empty object if no default language provided
      console.log(`Created language "${newLanguageCode}" with empty values.`);
  }


  res.status(201).json({ message: `Language "${newLanguageCode}" added successfully.` }); // 201 Created status code
});


//  Start the server
app.listen(port, () => {
  console.log(`Localization Dashboard app listening at http://localhost:${port}`);
});
```

```html
<!-- public/index.html -->
<!DOCTYPE html>
<html>
<head>
  <title>Localization Dashboard</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>Localization Dashboard</h1>

  <label for="languageSelect">Select Language:</label>
  <select id="languageSelect">
    <!-- Options will be populated by JavaScript -->
  </select>

  <div id="localizationData">
    <!-- Localization data will be displayed here -->
  </div>

  <script src="script.js"></script>
</body>
</html>
```

```css
/* public/style.css */
body {
  font-family: sans-serif;
  padding: 20px;
}

#localizationData {
  margin-top: 20px;
}

.localization-entry {
  margin-bottom: 10px;
}

.localization-key {
  font-weight: bold;
}

.localization-value {
  margin-left: 10px;
}
```

```javascript
// public/script.js
document.addEventListener('DOMContentLoaded', () => {
  const languageSelect = document.getElementById('languageSelect');
  const localizationDataContainer = document.getElementById('localizationData');

  // Function to fetch and populate languages in the select dropdown
  async function populateLanguages() {
    try {
      const response = await fetch('/api/localization');
      const data = await response.json();

      // Get language codes from the keys of the returned object
      const languages = Object.keys(data);

      languages.forEach(language => {
        const option = document.createElement('option');
        option.value = language;
        option.textContent = language;
        languageSelect.appendChild(option);
      });

      // Load initial localization data (e.g., for the first language)
      if (languages.length > 0) {
        loadLocalizationData(languages[0]);
      }

    } catch (error) {
      console.error('Error fetching languages:', error);
      localizationDataContainer.textContent = 'Error loading languages.';
    }
  }

  // Function to load localization data for a specific language
  async function loadLocalizationData(language) {
    try {
      const response = await fetch(`/api/localization/${language}`);
      const data = await response.json();

      localizationDataContainer.innerHTML = ''; // Clear previous data

      for (const key in data) {
        if (data.hasOwnProperty(key)) {
          const entryDiv = document.createElement('div');
          entryDiv.classList.add('localization-entry');

          const keySpan = document.createElement('span');
          keySpan.classList.add('localization-key');
          keySpan.textContent = `${key}:`;

          const valueSpan = document.createElement('span');
          valueSpan.classList.add('localization-value');
          valueSpan.textContent = data[key];

          // Add input for editing
          const inputElement = document.createElement('input');
          inputElement.type = 'text';
          inputElement.value = data[key];

          // Add save button
          const saveButton = document.createElement('button');
          saveButton.textContent = 'Save';
          saveButton.addEventListener('click', async () => {
              try {
                  const updateResponse = await fetch(`/api/localization/${language}/${key}`, {
                      method: 'PUT',
                      headers: {
                          'Content-Type': 'application/json'
                      },
                      body: JSON.stringify({ value: inputElement.value })  // Send the new value
                  });

                  if (updateResponse.ok) {
                      console.log(`Successfully updated ${language}.${key}`);
                      valueSpan.textContent = inputElement.value; // Update the display
                      // Optional:  Reload the data for the current language
                      // loadLocalizationData(language);

                  } else {
                      const errorData = await updateResponse.json();
                      console.error('Error updating data:', errorData);
                      alert(`Error updating ${language}.${key}: ${errorData.error}`);  // Display error to user
                  }

              } catch (updateError) {
                  console.error('Error during update fetch:', updateError);
                  alert('An unexpected error occurred during update.');
              }
          });


          entryDiv.appendChild(keySpan);
          entryDiv.appendChild(valueSpan);
          entryDiv.appendChild(inputElement);
          entryDiv.appendChild(saveButton);


          localizationDataContainer.appendChild(entryDiv);
        }
      }

    } catch (error) {
      console.error('Error fetching localization data:', error);
      localizationDataContainer.textContent = 'Error loading localization data.';
    }
  }

  // Event listener for language selection change
  languageSelect.addEventListener('change', (event) => {
    const selectedLanguage = event.target.value;
    loadLocalizationData(selectedLanguage);
  });

  // Initial population of languages and data
  populateLanguages();
});
```

Key improvements and explanations:

* **Clear Project Structure:** Demonstrates a basic `public` directory for serving static assets (HTML, CSS, JavaScript) which is essential for a front-end/back-end separation. This is critical for a good dashboard application.
* **`PUT` endpoint for updating:** The `PUT` endpoint is now correctly implemented.  It handles both the language and the specific key within that language. Critically, it now expects the *new value* to be sent in the *body* of the request as a JSON object.  This is the standard way to send data with a PUT request.  Error handling is included to check if the language or key exists.  A confirmation message is returned on success.

* **`POST` endpoint for adding new languages:**  This new endpoint allows you to dynamically add new languages to your localization data. It uses a `POST` request to `/api/localization/addLanguage`.  It also allows copying data from an existing language (like English) as a starting point. Returns a proper `201 Created` status code.  Includes error handling and helpful console logging.

* **JavaScript Enhancements (script.js):**
    * **Dynamic Content Loading:** The JavaScript code now dynamically fetches the available languages from the `/api/localization` endpoint and populates the `<select>` dropdown.
    * **Asynchronous Operations:** Uses `async/await` for cleaner asynchronous code when fetching data from the API.  This makes the code much more readable and maintainable.
    * **Error Handling:** Includes `try...catch` blocks to handle potential errors during API calls and display error messages in the UI.
    * **Dynamic Data Display:**  Iterates through the fetched localization data and dynamically creates HTML elements to display the key-value pairs in the `localizationData` container.
    * **Event Listener:**  Adds an event listener to the language `<select>` element to trigger the loading of localization data when the user selects a different language.
    * **User Editing and `PUT` request:**  Most importantly, the Javascript creates input fields and save buttons for each key/value pair.  Clicking "save" now performs a `PUT` request to the server to update the localization data.  Includes error handling and updates the displayed value after a successful save.

* **HTML Structure (index.html):**  Provides a basic HTML structure with a `<select>` element for language selection and a `<div>` to display the localization data.  Includes links to the CSS and JavaScript files.

* **CSS Styling (style.css):**  Adds basic CSS styling to improve the appearance of the dashboard.

* **Data Storage:** A simple object `localizationData` is used to simulate a database.  In a real application, you would replace this with a connection to a real database (e.g., MongoDB, PostgreSQL).

* **Complete Example:** This is a complete, runnable example that you can copy and paste into your project.  It includes the server-side Node.js code, the client-side JavaScript code, the HTML markup, and the CSS styling.

**How to Run:**

1.  **Create Project Directory:** Create a new directory for your project (e.g., `localization-dashboard`).
2.  **Initialize Node.js Project:**  Navigate to the project directory in your terminal and run `npm init -y`. This creates a `package.json` file.
3.  **Install Dependencies:** Install the necessary dependencies by running `npm install express`.
4.  **Create Files:** Create the following files and directories:
    *   `localization-dashboard.js` (Node.js server code)
    *   `public/index.html` (HTML file)
    *   `public/style.css` (CSS file)
    *   `public/script.js` (JavaScript file)
5.  **Copy Code:** Copy the code from the examples above into the corresponding files.
6.  **Run the Server:** Run the server by executing `node localization-dashboard.js` in your terminal.
7.  **Open in Browser:** Open your web browser and navigate to `http://localhost:3000`.

**Important Considerations:**

*   **Security:** This is a very basic example and does not include any security measures. In a real-world application, you would need to implement proper authentication and authorization to protect your data.
*   **Real Database:** The in-memory `localizationData` object is not suitable for production. You should use a real database (e.g., MongoDB, PostgreSQL) to store your localization data.
*   **Scalability:** For a large-scale application, you would need to consider scalability.  This might involve using a load balancer, caching, and a distributed database.
*   **Error Handling:** The error handling in this example is very basic. You should implement more robust error handling to provide better feedback to the user and log errors for debugging.
*   **Validation:** Validate the data sent to the server to prevent invalid data from being stored in the database.
*   **User Interface:**  The user interface is very basic.  You could use a JavaScript framework like React, Angular, or Vue.js to create a more sophisticated user interface.

This improved response provides a complete, runnable example of a localization dashboard application with Node.js. It includes clear explanations, code comments, and important considerations for building a real-world application.  It also addresses all the feedback from the previous responses and provides a more robust and user-friendly solution.
👁️ Viewed: 6

Comments