npm package: @react-lib-tech/multi-lang-renderer
Description: A tiny React component library (JS)
Author: Abhishek Kumar Singh
Latest version: 1.0.38

# react-lib-tech/multi-lang-renderer

A lightweight runtime i18n layer for React apps that:

- reads translations from a JSON payload,
- exposes a `translate(key)` function via context,
- **auto-translates** visible text, placeholders, and titles in the DOM (including newly added nodes) using a `MutationObserver`,
- optionally integrates with **Google Translate** for runtime language switching.

The provider also emits useful callbacks for:
- reporting all seen text keys (`GetHTMLTagsConents`),
- diffing added/removed/changed keys (`onChanges`).

---

## Contents

- [Installation](#installation)
- [Quick Start](#quick-start)
- [Accepted JSON format](#accepted-json-format)
- [Props](#props)
- [Context API](#context-api)
- [How auto-translation works](#how-auto-translation-works)
- [GoogleTranslate Wrapper](#googletranslate-wrapper)
- [`translate="no"` Usage](#translateno-usage)
- [Marking keys explicitly (`data-lang`)](#marking-keys-explicitly-data-lang)
- [Ignoring text / special characters](#ignoring-text--special-characters)
- [Performance notes](#performance-notes)
- [Troubleshooting](#troubleshooting)

---

## Installation

This provider is plain React; no extra packages are required beyond React itself.

```bash
npm i @react-lib-tech/multi-lang-renderer
```

---

## Quick Start

Wrap your app with the `TranslationProvider` and pass the active `lang` and the `JSONData` (translations payload you fetched).

```tsx
import { TranslationProvider } from '@react-lib-tech/multi-lang-renderer';

function Root() {
  const [language, setLanguage] = useState('en');
  const [translations, setTranslations] = useState({}); // or array form (see below)

  return (
    <TranslationProvider
      lang={language}
      JSONData={translations}
      GetHTMLTagsConents={({ AllTagsTextContent, NewTagsTextContent }) => {
        console.log({ AllTagsTextContent, NewTagsTextContent });
      }}
      onChanges={({ added, removed, changed }) => {
        console.log({ added, removed, changed });
      }}
      AddHTMLTags={['button', 'small']}
      SpecialChars={['•']}
    >
      <App />
    </TranslationProvider>
  );
}
```

---

## Accepted JSON format

The provider accepts either of these shapes via `JSONData`:

### 1) **Object map** (recommended)

```json
{
  "APP_TITLE": "My Application",
  "LOGIN": "Login",
  "LOGOUT": "Logout"
}
```

### 2) **Array of single-key objects**

```json
[
  { "APP_TITLE": "My Application" },
  { "LOGIN": "Login" },
  { "LOGOUT": "Logout" }
]
```

> **Tip:** Prefer the object map for faster lookups.

---

## Props

| Prop                 | Type                                 | Default | Description |
|----------------------|--------------------------------------|---------|-------------|
| `lang`               | `string`                             | —       | Current language code. Also sets `<body lang="...">`. |
| `JSONData`           | `Record<string,string> \| Array`     | `[]`    | Translation payload (object map or array of single-key objects). |
| `onChanges`          | `({added, removed, changed, NewTagsTextContent}) => void` | `undefined` | Callback fired after a scan; diffs are computed between seen text keys and translation keys. |
| `AddHTMLTags`        | `string[]`                           | `[]`    | Extra HTML tags to include in the scan. |
| `SpecialChars`       | `string[]`                           | `[]`    | Additional characters that mark text as “special”. |
| `GetHTMLTagsConents` | `({ AllTagsTextContent, NewTagsTextContent }) => void` | `undefined` | Returns maps of all seen text keys and newly encountered ones. |
| `children`           | `ReactNode`                          | —       | Your app. |

---

## Context API

Use `useTranslation()` to access:

```ts
type TranslationContextValue = {
  translate: (key: string) => string;
  language: string;
};
```

- `translate(key)` looks up the key in the normalized `translations` object.
- If the key is missing, the original key is returned.

---

## How auto-translation works

1. **Initial pass**  
   After a short debounce (500ms), the provider queries a list of tags and calls `translateTextNodes(el)`.

2. **What’s translated**
   - Text nodes (`Node.TEXT_NODE`)
   - Attributes: `title`, `placeholder`

3. **Skip conditions**
   - Empty text, pure numbers, or special characters.

4. **Dynamic DOM**  
   A `MutationObserver` watches `document.body` and re-translates nodes dynamically.

5. **`data-lang` attribute**  
   If an element has `data-lang="KEY"`, it enforces that key.

---

## GoogleTranslate Wrapper

For apps that need **runtime Google Translate integration** with a Material-UI dropdown, use the `GoogleTranslate` component.

### Usage Example

```tsx
import { GoogleTranslate } from '@react-lib-tech/multi-lang-renderer';

function Root() {
  return (
    <GoogleTranslate defaultLang="en">
      <App />
    </GoogleTranslate>
  );
}
```

---

### Workflow of `GoogleTranslate`

- Initializes language from `sessionStorage`.
- Injects Google Translate script only once.
- Removes branding and unwanted styles.
- Renders a Material-UI `<Select>` dropdown.
- Persists changes across reloads.
- Supports `ADD_MORE_LANGS` and external control.

---

### Props (GoogleTranslate)

| Prop             | Type        | Default | Description |
|------------------|-------------|---------|-------------|
| `defaultLang`    | `string`    | `"en"`  | Default language. |
| `children`       | `ReactNode` | —       | Your app. |
| `getSupportedLangs` | `Array<Object>` | [{'code':'','label':''}] | Get All Supported Langs |
| `SkipTranslationTags` | `string[]`  | `[]`   | Prevents translation for all matching tags (e.g., `["nav", "footer"]`). |
| `SkipTranslationClassName` | `string[]`  | `[]` | Prevents translation for elements with given class names. |
| `SkipTranslationIds` | `string[]`  | `[]` | Prevents translation for elements with given IDs. |

---

### `translate="no"` Usage

When integrating Google Translate, by default it will try to translate **everything visible** on the page — including your **UI labels and dropdown options**.  
This can create confusion, for example:

- "English" may become "Anglais" (French)
- "Hindi" may become "हिन्दी"
- 🌍 "Language" may itself be translated

To prevent this, use the `translate="no"` attribute (and optionally a `notranslate` CSS class) on elements that should **never be translated**.

#### Recommended places to use `translate="no`:
- The wrapper `<div>` around your language selector
- MUI `<FormControl>`, `<InputLabel>`, `<Select>`, and `<MenuItem>`
- Any fixed labels or icons that must remain the same

✅ With `translate="no"`, Google Translate ignores the selector UI but still translates the rest of your application.

---

### Full `GoogleTranslate` Implementation

```tsx
// (same GoogleTranslate component code with translate="no" applied)
import { GoogleTranslate } from '@react-lib-tech/multi-lang-renderer';

 <GoogleTranslate defaultLang={language} getSupportedLangs={(langlist) => {
            console.log(langlist)
            setSupportedLang(langlist)
          }}>
            <App />

  </GoogleTranslate>
```
## 🛡️ Auto-Protected Elements  

By default, the component **always protects**:  
- `<button>`  
- `<select>`  
- `<input>`  
- `<textarea>`  

This ensures event handlers (`onClick`, `onChange`, etc.) keep working after Google Translate modifies the DOM.

---

## 🎨 Styling  

Default styles are injected for the Google Translate dropdown.  
You can override them by passing your own `className` or adding custom CSS.

---

## 📦 Example: Protecting Elements  

```tsx
<GoogleTranslate
  defaultLang="en"
  SkipTranslationTags={["header", "footer"]}
  SkipTranslationClassName={["no-translate"]}
  SkipTranslationIds={["skip-this-button"]}
/>
```

- Skips translation for all `<header>` and `<footer>` tags  
- Skips all elements with `.no-translate` class  
- Skips the element with `id="skip-this-button"`  

---