You can find a demo react implementation here.
You can find a demo Next.js implementation here.
You can find a demo Expo react-native implementation here.
See here on more information how to set up typesafe-i18n.
npm install typesafe-i18nInitialize typesafe-i18n by running
npx typesafe-i18n --setup-autoYou could configure your development script to run the generator in parallel to react-scripts start by using npm-run-all.
{
"scripts": {
"dev": "npm-run-all --parallel start typesafe-i18n",
"typesafe-i18n": "typesafe-i18n",
"start": "react-scripts start"
}
}The generator will create a custom React component and context inside i18n-react.tsx that you can use inside your application.
Wrap your application root with the TypesafeI18n component:
import { useState, useEffect } from 'react'
import { navigatorDetector } from 'typesafe-i18n/detectors'
import TypesafeI18n from './i18n/i18n-react'
import { detectLocale } from './i18n/i18n-util'
import { loadLocale } from './i18n/i18n-util.sync'
function App() {
// Detect locale
// (Use as advanaced locale detection strategy as you like.
// More info: https://github.com/ivanhofer/typesafe-i18n/tree/main/packages/detectors)
const locale = detectLocale(navigatorDetector)
// Load locales
// (Use a data fetching solution that you prefer)
const [localesLoaded, setLocalesLoaded] = useState(false)
useEffect(() => {
loadLocale(locale).then(() => setLocalesLoaded(true))
}, [locale])
if(!localesLoaded) {
return null
}
return (
<TypesafeI18n locale={locale}>
{/* Your app goes here */}
</TypesafeI18n>
)
}
export default AppThat's it. You can then start using typesafe-i18n inside your React components.
import { useI18nContext } from './i18n/i18n-react'
function Greeting(props) {
const { LL } = useI18nContext()
return <h1>{LL.HI({ name: props.name })}</h1>
}
export default GreetingWhen running the generator, the file i18n-react.tsx will export a React component you can wrap around your application. It requires the prop locale where you need to pass a locale to initialize the context.
import TypesafeI18n from './i18n/i18n-react'
function App() {
// TODO: load locales (https://github.com/ivanhofer/typesafe-i18n/tree/main/packages/generator#loading-locales)
// e.g. take a look at the example implementation (https://github.com/ivanhofer/typesafe-i18n/blob/main/packages/adapter-react/examples/react/src/App.tsx#L15)
return (
<TypesafeI18n locale="en">
<!-- your app goes here -->
</TypesafeI18n>
)
}
export default AppAlso a React context is exported by the generated file i18n-react.tsx. You can use it with the useI18nContext function.
import { useI18nContext } from './i18n/i18n-react'
function MyComponent(props) {
const { LL, locale, setLocale } = useI18nContext()
return // ...
}
export default MyComponentThe context gives you access to following variables:
An initialized i18nObject you can use to translate your app.
import { useI18nContext } from './i18n/i18n-react'
function ProjectOverview() {
const { LL } = useI18nContext()
return LL.NR_OF_PROJECTS(5) // will output e.g => '5 Projects'
}
export default ProjectOverviewA string containing the current selected locale.
A function to set another locale for the context.
import { useI18nContext } from './i18n/i18n-react'
function LanguageSelection() {
const { locale, setLocale } = useI18nContext()
return (
<ul className="language-selection">
<li className={'en' === locale ? 'selected' : ''} onClick={() => setLocale('en')}>
english
</li>
<li className={'de' === locale ? 'selected' : ''} onClick={() => setLocale('de')}>
deutsch
</li>
<li className={'it' === locale ? 'selected' : ''} onClick={() => setLocale('it')}>
italiano
</li>
</ul>
)
}
export default LanguageSelectionFor more information about typesafe-i18n, take a look at the main repository.
By default typesafe-i18n at this time does not provide such a functionality. But you could easily write a function like this:
import { LocalizedString } from 'typesafe-i18n'
// create a component that handles the translated message
interface WrapTranslationPropsType {
message: LocalizedString,
renderComponent: (messagePart: LocalizedString) => JSX.Element
}
export function WrapTranslation({ message, renderComponent }: WrapTranslationPropsType) {
// define a split character, in this case '<>'
let [prefix, infix, postfix] = message.split('<>') as LocalizedString[]
// render infix only if the message doesn't have any split characters
if (!infix && !postfix) {
infix = prefix
prefix = '' as LocalizedString
}
return <>
{prefix}
{renderComponent(infix)}
{prefix}
</>
}Your translations would look something like this
const en = {
'WELCOME': 'Hi {name:string}, click <>here<> to create your first project'
'LOGOUT': 'Logout'
}Use it inside your application
export function App() {
return <>
<header>
<!-- normal usage -->
<button onClick={() => alert('do logout')}>{LL.logout()}</button>} />
</header>
<main>
<!-- usage with a component inside a translation -->
<WrapTranslation
message={LL.WELCOME({ name: 'John' })}
renderComponent={(infix) => <button onClick={() => alert('clicked')}>{infix}</button>} />
</main>
<>
}