npm package: @hilma/i18n
Description: Hilma/i18n is a translation module used for React.js client, compatible (and recommended) with typescript.
Latest version: 0.4.0
Deprecated: This package is no longer maintained. For new projects, we recommend using a community-maintained alternative like i18next.


# @hilma/i18n

Hilma/i18n is a translation module used for React.js client, compatible (and recommended) with typescript.  

**Note:**  Most of the examples relates to 0.1.* versions, who uses `react-router-dom@4/5`. If you use `react-router-dom@^6` and you want to use location-based features, check the exmaple in [New version: For Router-V6](#new-version-for-router-v6)
## Table Of Contents:
  - [Installation](#installation)
  - [Implementation](#implementation)
  - [Usage examples](#usage-examples)
  - [Important stuff](#important-stuff)
    - [Router](#router)
    - [Changing Language](#changing-language)
    - [Directions](#directions)
    - [`useTransform` and `useTransformObject`](#usetransform-and-usetransformobject)
    - [`useNoLanguagePathname`](#usenolanguagepathname)
- [New version: For Router-V6](#new-version-for-router-v6)
    - [`router:true`](#routertrue)
    - [`router:false` and `LanguageRoutes` (former `LanguagesSwitch`)](#routerfalse-and-languageroutes-former-languagesswitch)
## Installation

```bash
npm install @hilma/i18n @hilma/tools
```


## Implementation 
First, we create the text functions. We use these functions to apply Typescript on our i18n objects and functions. 

*Note* - if you use no-ts javascript, you can send an object insted of an enum.

```typescript

import { createTextFunctions } from '@hilma/i18n';


export enum Language {
    He = "he",
    En = "en"
}

export const { createI18n, createI18nText } = createTextFunctions(Language)

```
Now, create the texts. You can split the texts to files and separate objects if you need to.
```typescript
import { createI18nText } from './i18n'
export const basicTest = createI18nText({
   he: {
        firstText: "שלום",
        sc: {
            hello: "שלום שוב"
        }
    },
    en: {
        firstText: "hello",
        sc: {
            hello: "hello again"
        }
    }
})
```
After you have the texts, create your `i18n`  object:
```typescript
import { createI18nHooksAndProvider } from '@hilma/i18n';
import { basicTest } from './texts'
import { createI18n, Language } from './i18n'


const i18n = createI18n({ welcome: basicTest }); // Put here all the texts you want to translate

export const {
    I18nProvider,
    contexts,
    useLanguage,
    createI18nHook,
    isLanguage,
    useChangeLanguage,
    useDirection,
    useLanguageEffect,
    useNoLanguagePathname,
    usePathLanguage,
    useSwitchedPath,
    useTransform,
    useTransformObject,
    createTranslateHook,
    LanguageSwitch  // LanguageRoutes in the new version.
} = createI18nHooksAndProvider(Language, i18n);


export type I18n = typeof i18n;
export type Localize<T = any> = LocalizeBase<Language, T> //import {  Localize as LocalizeBase } from "@hilma/i18n";
export const useI18n = createI18nHook<I18n>();
export const useTranslate = createTranslateHook<I18n>()
export const useTranslatedI18n = createTranslatedI18nHook<I18n>();
export const useTranslateTexts = createTranslateTextsHook<I18n>();
export const createI18nRef = () => createRef<TranslatedI18n<I18n>>(); // you can use this if you want to access the translation inside stores.


```
Now apply the `I18nProvider` where you want it in order to use the hooks. If you want to have ref, use the `createI18nRef` function and pass the ref to the provider.

## Usage examples

```typescript
Import {useI18n} from '../i18n'; //import the hook from the createI18nHooksAndProvider results.  

export function BasicExample() {
    const i18n = useI18n(); //no params means that you have all the trans object
    return <div>
        {i18n.welcome.firstText}
    </div>
}

//-----------------------------

export function SelectorExample() {
    const i18n = useI18n(i18n => i18n.welcome); // You can pass a selector in order to take only the needed texts. 
    return <div>
        {i18n.firstText}
    </div>

}

//-----------------------------

export function ChangeLanguage() {
    //2 ways of changing language. Use only one of them!!
    const i18n = useI18n(i18n => i18n.welcome);
    const changeLanguage = useChangeLanguage();

    return <div>
        {i18n.firstText}
        <button onClick={() => changeLanguage()}>toggle language</button>
        <button onClick={() => changeLanguage('he')}>change to Hebrew</button>
    </div>

}

//-----------------------------

export function ChangeLangWithPath() {
//If you take the lang out the url, you can use the useSwitchedPath in order to get the link to the same page in different language.
    const i18n = useI18n(i18n => i18n.welcome);
    const changePath = useSwitchedPath();
    const changeToHe = useSwitchedPath(Language.He)
    return <div>
        {i18n.firstText}
        <Link to={changePath}>toggle language</Link>
        <Link to={changeToHe}>Hebrew</Link>
    </div>
}

//-----------------------------

//example of using I18nSelector type, useTranslateTexts and useTranslate.
interface UsingSelector = {
    name: string;
    alt: I18nSelector<I18n>;
}

const images: UsingSelector[] = [
 { name: "image1.png", alt: i18n => i18n.welcome.firstText },
 { name: "image2.png", alt: i18n => i18n.welcome.sc.hello }
];

export function UseTranslateTextsExample() {
    const alts = useTranslateTexts<string[]>(images.map(item => item.alt));
    const translate = useTranslate();

    
    const exmaple: UsingSelector = {
        alt: i => i.welcome.sc.hello,
        name: "dosent_matter"
    }


    return <div>
        start of images
        <br/>
        {images.map((item, index) => <><img src={item.name} alt={alts[index]} /><br /></>)}
        end of images
        <br/>
        {translate(exmaple.alt)}
    </div>

}

//-----------------------------

//Example of using with router: App.tsx
import React from 'react';
import { provide } from '@hilma/tools';
import { I18nProvider, LanguageSwitch } from './constants/i18n';
import { Hello } from './components/Hello';
import { Route, BrowserRouter as Router } from 'react-router-dom';

function App() {
  return (
    <div className="App">

      <LanguageSwitch>
        <Route path="/hello" component={Hello} />
        <Route path="/*" component={() => (<div>Page not found</div>)} />
      </LanguageSwitch>
    </div>
  );
}

export default provide(
  Router,
  I18nProvider
)(App);



```

## Important stuff

### Router
If you want to get the language from the url, pass to the provider `router:true` and make sure your components can use `useLocation`. 

### Changing Language 
If you have only two languages you can use the change-language functions without params, and the code will toggle them. **But** if you don't have two languages, you will have to send the specific language you want to change to.

If you want to specify the `localStorage` item that will hold the language, you can pass `storage_item_name` to the `Provider`.


### Directions
When you create the hooks and provider, you can provide the text-directions and use them using `useDirection`.
There are default directions in the package, (called `DefaultDirections` enum), and it sould work for you.
```typescript
export enum DefaultDirections {
    He = 'rtl',
    En = 'ltr',
    Ar = 'rtl',
    Am = 'ltr',
    Fr = 'ltr',
    Ru = 'ltr'
}

```
To get the direction just use the hook-
```typescript
const dir:Direction = useDirection();
```

### `useTransform` and `useTransformObject`
The `UseTransform` hooks are used to extract language-specific values from an object.
For exmaple:
```typescript
const obj={
    heName:"אמיגו",
    enName:"Amigo",
    otherData:{...}
}
//---- First exmaple
const transform=useTransformObject()
const newObject=transform(obj);
 
//---- Second exmaple
const newObject2=useTransform(obj);
```
Now, if the langauge is Hebrew so newObject is `{name:"אמיגו", otherData:{...}}`. When the language changes, the value changes too.

`useTransform` takes an object and transforms it, while `useTransformObject` returns a transform function. 


### `useNoLanguagePathname`
`useNoLanguagePathname` returns the current path without the language prefix.


# New version: For Router-V6
The changes relates to router-related features.
 
### `router:true`
First, if you want to use `{router:true}` option, you should wrap the component (probably `App.tsx`) with router from heigher component (`index.tsx` in this case).
You have to wrap your routes with `<Routes/>`, because `{router:true}` wrapps `App` as element, and therefore the `Route` component should be a child of `Routes`.
Usage example:
```typescript
function App() {
  const i18n = useI18n();
  const change = useChangeLanguage();
  const path = useSwitchedPath();
  return (
    <div>
      <p>Some content that will be in all pages</p>
      <Routes>
        <Route path="p/a" element={<NestedPathElements/> } />
        <Route path="hi" element={<Ex />} />
      </Routes>
    </div>
  )
}

export default provide(
  [I18nProvider, { router: true }]
)(App);
``` 
In the example above we don't see the `Router` - but you should place it in `index`.

### `router:false` and `LanguageRoutes` (former `LanguagesSwitch`)
Since `react-router-dom` removed the `Switch` component from thier package, we had to rename this component too.

**Notice-** when you use `LanguageRoutes` don't use `Routes` inside it, only `Route`. Thats' because `LanguageRoutes` render its children as `<Route children={children}/>`, and the only children must be `Route` or `Fragment`.
Example :
```typescript
function App() {
  const i18n = useI18n();
  const change = useChangeLanguage();
  const path = useSwitchedPath();
  return (
    <div>
      <p>Some content that will be in all pages and cannot be inside LanguageRoutes</p>
        <LanguageRoutes>
            <Route path="p/a" element={<NestedPathElements/> } />
            <Route path="hi" element={<Ex />} />
        </LanguageRoutes>
    </div>
  )
}

export default provide(
  [I18nProvider, { router: false }]
)(App);
```
Obviously, `LanguageRoutes` is exported from `createI18nHooksAndProvider` value.