@hilma/i18n
v0.4.0
Published
Hilma/i18n is a translation module used for React.js client, compatible (and recommended) with typescript.
Downloads
2,867
Readme
@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.