@voerkai18n/react
Version:
React支持,提供语言切换等功能
1 lines • 13.5 kB
Source Map (JSON)
{"version":3,"sources":["../src/component.tsx","../src/hooks.ts","../src/provider.tsx"],"names":["createTranslateComponent","options","tagName","attrs","className","gStyle","LoadingComponent","hasLoading","scope","props","paragraphId","message","vars","tOptions","tDefault","isParagraph","result","setResult","useState","isFirst","useRef","loading","setLoading","tag","msgId","showLoading","loadMessage","useCallback","language","loader","loadParagraph","paragraphText","loadAsyncModule","e","refresh","useEffect","listener","createElement","jsx","Fragment","useVoerkaI18n","manager","curScope","activeLanguage","setActiveLanguage","newLangauge","getInitReady","VoerkaI18nProvider","fallback","children","ready","setReady"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\r\n * \r\n * 翻译组件\r\n * \r\n * import { createTranslateComponent } from '@voerkai18n/react'\r\n * \r\n * const scope = new VoerkaI18nScope({\r\n * component: createTranslateComponent(({message,vars,options,language})=>{\r\n * return <span>{message}</span>\r\n * },\r\n * {\r\n * loading: <Loading/> // 自定义加载中组件\r\n * default: \"\" // 默认文本\r\n * }\r\n * })\r\n * \r\n * <Translate message=\"I am {}\" vars={['fisher']} options={{...}} />\r\n * \r\n * <Translate \r\n * message={\r\n * async (language,vars,options)=>{ \r\n * const remoteMessage = await fetch(`https://example.com/api/translate?language=${language}&message=1001`).then((res)=>res.text())\r\n * return remoteMessage // = \"I am {}\"\r\n * }\r\n * } \r\n * default=\"I am {}\"\r\n * vars={['fisher']} \r\n * options={{...}} // 传递给翻译器的参数\r\n * />\r\n * \r\n * <Translate id=\"aaa\">\r\n * 段落内容\r\n * </Translate>\r\n * \r\n */\r\n\r\nimport { createElement,useState, useEffect, useCallback, useRef } from 'react';\r\nimport { type VoerkaI18nTranslateProps, type VoerkaI18nScope, type VoerkaI18nTranslateComponentBuilder, loadAsyncModule } from \"@voerkai18n/runtime\" \r\nimport React from 'react';\r\n\r\n \r\nexport type CreateTranslateComponentOptions = {\r\n tagName? : string\r\n attrs? : Record<string,string> \r\n class? : string\r\n style? : React.CSSProperties\r\n loading? : React.ReactNode \r\n}\r\n \r\n\r\nexport type ReactTranslateComponentType = React.FC<VoerkaI18nTranslateProps>\r\n\r\nexport type VoerkaI18nReactTranslateComponentBuilder = VoerkaI18nTranslateComponentBuilder<ReactTranslateComponentType>\r\n\r\n\r\nexport function createTranslateComponent(options?:CreateTranslateComponentOptions):VoerkaI18nReactTranslateComponentBuilder{ \r\n const { tagName,attrs={}, class:className = 'vt-msg' ,style:gStyle, loading:LoadingComponent } = Object.assign({ },options) as CreateTranslateComponentOptions\r\n const hasLoading:boolean = !!LoadingComponent\r\n\r\n return function(scope:VoerkaI18nScope){\r\n return (props:VoerkaI18nTranslateProps)=>{ \r\n const { id:paragraphId, message, vars, options:tOptions,default:tDefault = '' } = props \r\n\r\n const isParagraph: boolean = typeof(paragraphId) === 'string' && paragraphId.length > 0 \r\n\r\n const [ result, setResult ] = useState(()=>{\r\n if(isParagraph){\r\n return props.children\r\n }else{\r\n return typeof(message)==='function' ? tDefault : scope.translate(message!,vars,tOptions)\r\n } \r\n })\r\n \r\n const isFirst = useRef(false) \r\n // 仅当是段落时才显示加载中\r\n const [ loading, setLoading ] = useState<boolean>(false) \r\n const tag = props.tag || tagName\r\n const msgId = scope.getMessageId(props.message)\r\n const showLoading = isParagraph || typeof(message)==='function' \r\n \r\n const loadMessage = useCallback(async (language:string) => {\r\n const loader = typeof(message)==='function' ? ()=>message(language,vars,tOptions) : ()=>message\r\n return Promise.resolve(loader()).then((result)=>{ \r\n setResult(scope.translate(result!,vars,tOptions))\r\n })\r\n },[message,vars,tOptions]) \r\n\r\n const loadParagraph = async () => {\r\n if(paragraphId){\r\n const loader = scope.activeParagraphs[paragraphId]\r\n if(!loader) return\r\n if(hasLoading) setLoading(true)\r\n try{ \r\n const paragraphText = await loadAsyncModule(loader)\r\n setResult(paragraphText)\r\n }catch(e:any){\r\n console.error(e)\r\n }finally{\r\n if(hasLoading) setLoading(false)\r\n } \r\n } \r\n }\r\n\r\n const refresh = useCallback((language: string) => {\r\n if(isParagraph){ \r\n loadParagraph()\r\n }else{\r\n loadMessage(language)\r\n }\r\n },[]) \r\n\r\n // 第一次渲染时执行函数进行加载\r\n if(!isFirst.current && (typeof(message)==='function' || isParagraph)){\r\n refresh(scope.activeLanguage)\r\n isFirst.current = true \r\n }\r\n\r\n useEffect(()=>{ \r\n const listener = scope.on(\"change\",refresh) as any\r\n return ()=>listener.off()\r\n },[]) \r\n \r\n if(msgId) attrs['data-id'] = msgId\r\n if(paragraphId) attrs['data-id'] = paragraphId\r\n if(scope.library) attrs['data-scope'] = String(scope.$id)\r\n \r\n if(tag || isParagraph){\r\n return createElement(tag || 'div',{\r\n ...attrs,\r\n className,\r\n suppressHydrationWarning:true,\r\n style:Object.assign({\"position\":\"relative\"},gStyle,props.style)\r\n },\r\n result,\r\n showLoading && hasLoading && loading ? LoadingComponent : null,\r\n )\r\n }else{\r\n return <>{result}</>\r\n } \r\n } \r\n }\r\n\r\n}\r\n","import type { VoerkaI18nManager,VoerkaI18nScope } from \"@voerkai18n/runtime\";\r\nimport { useEffect, useRef, useState } from \"react\";\r\n\r\nexport function useVoerkaI18n(scope?:VoerkaI18nScope) {\r\n const manager:VoerkaI18nManager = globalThis.VoerkaI18n;\r\n const curScope = scope || manager.scope\r\n if (!manager || !curScope) {\r\n throw new Error('VoerkaI18n is not defined');\r\n }\r\n const [ activeLanguage, setActiveLanguage ] = useState(curScope.activeLanguage);\r\n const isFirst = useRef(true)\r\n \r\n useEffect(() => {\r\n if(isFirst.current){\r\n curScope.ready(()=>{\r\n setActiveLanguage(curScope.activeLanguage)\r\n })\r\n isFirst.current = false\r\n }\r\n const listener:any = manager.on(\"change\", (newLangauge:string)=>{\r\n setActiveLanguage(newLangauge)\r\n });\r\n return () => listener && listener.off()\r\n },[]);\r\n\r\n\r\n return {\r\n scope : curScope,\r\n manager ,\r\n activeLanguage, \r\n defaultLanguage: curScope.defaultLanguage,\r\n languages : curScope.languages,\r\n changeLanguage : curScope.change.bind(curScope),\r\n t : curScope.t\r\n };\r\n} ","'use client'\r\n\r\nimport { useEffect, useState } from \"react\";\r\nimport { useVoerkaI18n } from \"./hooks\";\r\nimport { VoerkaI18nManager } from \"@voerkai18n/runtime\";\r\n\r\nfunction getInitReady(manager:VoerkaI18nManager){\r\n return manager.activeLanguage === manager.defaultLanguage\r\n || typeof(manager.scope.messages[manager.activeLanguage])!=='function'\r\n} \r\n/**\r\n * \r\n */\r\nexport type VoerkaI18nProviderProps= React.PropsWithChildren<{\r\n fallback?: React.ReactNode;\r\n}>\r\n\r\nexport function VoerkaI18nProvider(props: VoerkaI18nProviderProps){\r\n const { fallback, children } = props\r\n const { manager } = useVoerkaI18n()\r\n const [ ready,setReady ] = useState(getInitReady(manager))\r\n useEffect(()=>{\r\n const listener = manager.on('ready',()=>{\r\n setReady(true)\r\n })\r\n return ()=> { typeof(listener)==='object' && listener.off() }\r\n },[])\r\n return <>\r\n { ready || (!ready && !fallback) ? children : fallback }\r\n </> \r\n}"]}