Tldraw/packages/ui/src/lib/hooks/useTranslation/useTranslation.tsx

110 wiersze
2.5 KiB
TypeScript

import { useApp } from '@tldraw/editor'
import * as React from 'react'
import { track } from 'signia-react'
import { useAssetUrls } from '../useAssetUrls'
import { TLTranslationKey } from './TLTranslationKey'
import { DEFAULT_TRANSLATION } from './defaultTranslation'
import { TLTranslation, getTranslation } from './translations'
/** @public */
export interface TranslationProviderProps {
children: any
/**
* (optional) A collection of overrides different locales.
*
* @example
*
* ```ts
* <TranslationProvider overrides={{ en: { 'style-panel.styles': 'Properties' } }} />
* ```
*/
overrides?: Record<string, Record<string, string>>
}
const TranslationsContext = React.createContext<TLTranslation>({} as TLTranslation)
const useCurrentTranslation = () => React.useContext(TranslationsContext)
/**
* Provides a translation context to the app.
*
* @public
*/
export const TranslationProvider = track(function TranslationProvider({
overrides,
children,
}: TranslationProviderProps) {
const app = useApp()
const locale = app.userSettings.locale
const getAssetUrl = useAssetUrls()
const [currentTranslation, setCurrentTranslation] = React.useState<TLTranslation>(() => {
if (overrides && overrides['en']) {
return {
locale: 'en',
label: 'English',
messages: { ...DEFAULT_TRANSLATION, ...overrides['en'] },
}
}
return {
locale: 'en',
label: 'English',
messages: DEFAULT_TRANSLATION,
}
})
React.useEffect(() => {
let isCancelled = false
async function loadTranslation() {
const translation = await getTranslation(locale, getAssetUrl)
if (translation && !isCancelled) {
if (overrides && overrides[locale]) {
setCurrentTranslation({
...translation,
messages: { ...translation.messages, ...overrides[locale] },
})
} else {
setCurrentTranslation(translation)
}
}
}
loadTranslation()
return () => {
isCancelled = true
}
}, [getAssetUrl, locale, overrides])
return (
<TranslationsContext.Provider value={currentTranslation}>
{children}
</TranslationsContext.Provider>
)
})
/**
* Returns a function to translate a translation key into a string based on the current translation.
*
* @example
*
* ```ts
* const msg = useTranslation()
* const label = msg('style-panel.styles')
* ```
*
* @public
*/
export function useTranslation() {
const translation = useCurrentTranslation()
return React.useCallback(
function msg(id: TLTranslationKey) {
return translation.messages[id] ?? id
},
[translation]
)
}