0.4.0 • Published 7 months ago

@hilma/i18n v0.4.0

Weekly downloads
-
License
MIT
Repository
-
Last release
7 months ago

@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

Table Of Contents:

Installation

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.

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.

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:

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

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.

export enum DefaultDirections {
    He = 'rtl',
    En = 'ltr',
    Ar = 'rtl',
    Am = 'ltr',
    Fr = 'ltr',
    Ru = 'ltr'
}

To get the direction just use the hook-

const dir:Direction = useDirection();

useTransform and useTransformObject

The UseTransform hooks are used to extract language-specific values from an object. For exmaple:

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:

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 :

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.

0.4.0

7 months ago

0.3.1

1 year ago

0.3.1-beta.0

1 year ago

0.3.0

1 year ago

0.2.2-beta.10

1 year ago

0.2.2-beta.9

2 years ago

0.2.2-beta.8

2 years ago

0.1.4-beta.2

2 years ago

0.1.4-beta.3

2 years ago

0.1.4-beta.4

2 years ago

0.1.4-beta.5

2 years ago

0.1.4-beta.6

2 years ago

0.1.4-beta.0

2 years ago

0.1.4-beta.1

2 years ago

0.2.2-beta.0

2 years ago

0.2.2-beta.2

2 years ago

0.2.0-beta.2

2 years ago

0.2.2-beta.1

2 years ago

0.2.0-beta.1

2 years ago

0.2.2-beta.4

2 years ago

0.2.1-beta.0

2 years ago

0.2.0-beta.0

2 years ago

0.2.2-beta.3

2 years ago

0.2.2-beta.6

2 years ago

0.2.0-beta.6

2 years ago

0.2.2-beta.5

2 years ago

0.2.0-beta.5

2 years ago

0.2.0-beta.4

2 years ago

0.2.2-beta.7

2 years ago

0.2.0-beta.3

2 years ago

0.2.0-beta.9

2 years ago

0.2.1

2 years ago

0.2.0-beta.8

2 years ago

0.2.0

2 years ago

0.2.0-beta.7

2 years ago

0.2.0-beta.10

2 years ago

0.2.0-beta.11

2 years ago

0.2.0-beta.12

2 years ago

0.2.0-beta.13

2 years ago

0.1.4

2 years ago

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1-beta.1

3 years ago

0.1.0

3 years ago

0.1.1

3 years ago

0.1.0-beta.7

3 years ago

0.1.0-beta.6

3 years ago

0.1.0-beta.8

3 years ago

0.1.0-beta.3

3 years ago

0.1.0-beta.2

3 years ago

0.1.0-beta.5

3 years ago

0.1.0-beta.4

3 years ago

0.1.0-beta.1

3 years ago