11import { LANGUAGE_STORAGE_KEY , SUPPORTED_LANGUAGES } from '@/src/constants'
2- import hotMemo from 'hot-memo'
32import i18next from 'i18next'
43import I18nextBrowserLanguageDetector from 'i18next-browser-languagedetector'
54import i18nextResourcesToBackend from 'i18next-resources-to-backend'
@@ -25,57 +24,69 @@ const i18n = i18next
2524 )
2625 )
2726 . use ( initReactI18next )
28- . init ( {
29- fallbackLng : 'en' ,
30- supportedLngs : SUPPORTED_LANGUAGES ,
31- defaultNS : 'common' ,
32- fallbackNS : 'common' ,
33-
34- // not needed for react as it escapes by default
35- interpolation : { escapeValue : false } ,
36-
37- // use ssr-side detection in middleware
38- detection : {
39- order : [ 'htmlTag' ] ,
40- caches : [ ] ,
41- } ,
4227
43- react : {
44- bindI18nStore : 'added' , // notify react to rerender when a new key is added
45- } ,
28+ i18n . init ( {
29+ fallbackLng : 'en' ,
30+ supportedLngs : SUPPORTED_LANGUAGES ,
31+ defaultNS : 'common' ,
32+ fallbackNS : 'common' ,
4633
47- saveMissing : true ,
48- missingKeyNoValueFallbackToKey : true ,
49- missingKeyHandler : async ( lngs , ns , key ) => {
50- const lng = i18next . language
51- console . log ( lngs , i18next . language , key )
52- console . log (
53- `Missing translation for key "${ key } " in language "${ lng } "`
54- )
55- // (Experimental) Try use broswer Translator API to handle missing keys
56- // If the Translator API is not available, just return the key
57- if ( typeof globalThis . Translator === 'undefined' ) return
58-
59- // Create a translator instance
60- const Translator = globalThis . Translator as any
61- const translator = await Translator . create ( {
62- sourceLanguage : 'en' ,
63- targetLanguage : lng ,
64- } ) . catch ( ( ) => null )
65- if ( ! translator ) return
66-
67- // Translate the key
68- let tr = ''
69- for await ( const chunk of translator . translateStreaming ( key ) ) {
70- tr += chunk
71- }
72- console . log ( `Translated "${ key } " to "${ tr } " in language "${ lng } "` )
73- // add to i18next resources
74- // how to trigger a re-render in components that use this key?
75- i18next . addResource ( lng , ns , key , tr )
76- i18next . emit ( 'added' , lng , ns , key , tr )
77- } ,
78- } )
34+ // not needed for react as it escapes by default
35+ interpolation : { escapeValue : false } ,
36+
37+ // use ssr-side detection in middleware
38+ detection : {
39+ order : [ 'htmlTag' ] ,
40+ caches : [ ] ,
41+ } ,
42+
43+ react : {
44+ bindI18nStore : 'added' , // notify react to rerender when a new key is added
45+ } ,
46+
47+ // Support dynamic translation
48+ saveMissing : true ,
49+ missingKeyNoValueFallbackToKey : true ,
50+ missingKeyHandler : async ( lngs , ns , key ) => {
51+ const lng = i18next . language
52+ console . log ( lngs , i18next . language , key )
53+ console . log ( `Missing translation for key "${ key } " in language "${ lng } "` )
54+
55+ // (Experimental) Try use browser Translator API to handle missing keys
56+ // If the Translator API is not available, just return the key
57+ if ( typeof globalThis . Translator === 'undefined' ) return
58+
59+ // Create a translator instance
60+ const Translator = globalThis . Translator as any
61+ const translator = await Translator . create ( {
62+ sourceLanguage : 'en' ,
63+ targetLanguage : lng ,
64+ } ) . catch ( ( ) => null )
65+ if ( ! translator ) return
66+
67+ // Translate the key
68+ let tr = ''
69+ for await ( const chunk of translator . translateStreaming ( key ) ) {
70+ tr += chunk
71+ }
72+ console . log ( `Translated "${ key } " to "${ tr } " in language "${ lng } "` )
73+ // add to i18next resources
74+ // how to trigger a re-render in components that use this key?
75+ i18next . addResource ( lng , ns , key , tr )
76+ i18next . emit ( 'added' , lng , ns , key , tr )
77+
78+ // TODO: use ChatGPT to handle missing keys if browser Translator API is not available
79+ //
80+ } ,
81+ } )
82+
83+ export const useDynamicTranslateEnabled = ( ) => {
84+ const [ enabled , setEnabled ] = useLocalStorage (
85+ 'DynamicTranslate' ,
86+ false // default disabled, click the globe icon to enable across the site
87+ )
88+ return { enabled, setEnabled }
89+ }
7990
8091export const useDynamicTranslate = ( ) => {
8192 const { currentLanguage, t } = useNextTranslation ( 'dynamic' )
@@ -86,7 +97,7 @@ export const useDynamicTranslate = () => {
8697 // cons:
8798 // 1. requires network access to the browser's translation service
8899 // 2. not able to use in server-side rendering
89- // 3. not avaliable in china
100+ // 3. not available in china
90101 //
91102 const [ available , availableState ] = useAsyncData ( async ( ) => {
92103 const Translator = globalThis . Translator as any
@@ -97,33 +108,35 @@ export const useDynamicTranslate = () => {
97108 return translator
98109 } )
99110
100- const [ enabled , setEnabled ] = useLocalStorage (
101- 'DynamicTranslate' ,
102- false // default disabled, click the globe icon to enable across the site
103- )
111+ const { enabled, setEnabled } = useDynamicTranslateEnabled ( )
104112 const dt = useCallback (
105113 ( key ?: string ) => {
106114 if ( ! key ) return key
107115 if ( ! available ) return key
108- return < > { enabled ? < > { t ( key ) } </ > : < > { key } </ > } </ >
116+ return enabled ? t ( key ) : key
109117 } ,
110118 [ enabled , available , t ]
111119 )
112- const Switcher = ( ) => (
120+
121+ return { available, enabled, setEnabled, dt }
122+ }
123+
124+ export const DynamicTranslateSwitcher = ( ) => {
125+ const { available, enabled, setEnabled } = useDynamicTranslate ( )
126+ if ( ! available ) return null
127+ return (
113128 < span
114129 role = "img"
115130 aria-label = "translate"
116131 onClick = { ( ) => {
117- setEnabled ( ( e ) => ! e )
132+ setEnabled ( ! enabled ) // toggle the translation statey
118133 } }
119134 >
120135 {
121136 enabled ? '🔄' : '🌐' // use a different icon to indicate translation is disabled
122137 }
123138 </ span >
124139 )
125-
126- return { available, Switcher, enabled, setEnabled, dt }
127140}
128141/**
129142 * Custom hook for translations in the Comfy Registry
0 commit comments