[Glitch] Fix /share and cleanup and reorganize frontend locale loading
				
					
				
			Port b0780cfeed to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
			
			
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| // @ts-check | ||||
|  | ||||
| import { getLocale } from 'mastodon/locales'; | ||||
| import { getLocale } from 'flavours/glitch/locales'; | ||||
|  | ||||
| import { connectStream } from '../stream'; | ||||
|  | ||||
| @@ -25,8 +25,6 @@ import { | ||||
|   fillListTimelineGaps, | ||||
| } from './timelines'; | ||||
|  | ||||
| const { messages } = getLocale(); | ||||
|  | ||||
| /** | ||||
|  * @param {number} max | ||||
|  * @returns {number} | ||||
| @@ -44,8 +42,10 @@ const randomUpTo = max => | ||||
|  * @param {function(object): boolean} [options.accept] | ||||
|  * @returns {function(): void} | ||||
|  */ | ||||
| export const connectTimelineStream = (timelineId, channelName, params = {}, options = {}) => | ||||
|   connectStream(channelName, params, (dispatch, getState) => { | ||||
| export const connectTimelineStream = (timelineId, channelName, params = {}, options = {}) => { | ||||
|   const { messages } = getLocale(); | ||||
|  | ||||
|   return connectStream(channelName, params, (dispatch, getState) => { | ||||
|     const locale = getState().getIn(['meta', 'locale']); | ||||
|  | ||||
|     // @ts-expect-error | ||||
| @@ -122,6 +122,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti | ||||
|       }, | ||||
|     }; | ||||
|   }); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * @param {Function} dispatch | ||||
|   | ||||
| @@ -1,24 +1,19 @@ | ||||
| import PropTypes from 'prop-types'; | ||||
| import { PureComponent } from 'react'; | ||||
|  | ||||
| import { IntlProvider } from 'react-intl'; | ||||
|  | ||||
| import { getLocale, onProviderError } from 'mastodon/locales'; | ||||
|  | ||||
| const { messages } = getLocale(); | ||||
| import { IntlProvider } from 'flavours/glitch/locales'; | ||||
|  | ||||
| export default class AdminComponent extends PureComponent { | ||||
|  | ||||
|   static propTypes = { | ||||
|     locale: PropTypes.string.isRequired, | ||||
|     children: PropTypes.node.isRequired, | ||||
|   }; | ||||
|  | ||||
|   render () { | ||||
|     const { locale, children } = this.props; | ||||
|     const { children } = this.props; | ||||
|  | ||||
|     return ( | ||||
|       <IntlProvider locale={locale} messages={messages} onError={onProviderError}> | ||||
|       <IntlProvider> | ||||
|         {children} | ||||
|       </IntlProvider> | ||||
|     ); | ||||
|   | ||||
| @@ -1,37 +1,25 @@ | ||||
| import PropTypes from 'prop-types'; | ||||
| import { PureComponent } from 'react'; | ||||
|  | ||||
| import { IntlProvider } from 'react-intl'; | ||||
|  | ||||
| import { Provider } from 'react-redux'; | ||||
|  | ||||
| import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis'; | ||||
| import { hydrateStore } from 'flavours/glitch/actions/store'; | ||||
| import Compose from 'flavours/glitch/features/standalone/compose'; | ||||
| import initialState from 'flavours/glitch/initial_state'; | ||||
| import { IntlProvider } from 'flavours/glitch/locales'; | ||||
| import { store } from 'flavours/glitch/store'; | ||||
|  | ||||
| import { getLocale, onProviderError } from 'mastodon/locales'; | ||||
|  | ||||
| const { messages } = getLocale(); | ||||
|  | ||||
| if (initialState) { | ||||
|   store.dispatch(hydrateStore(initialState)); | ||||
| } | ||||
|  | ||||
| store.dispatch(fetchCustomEmojis()); | ||||
|  | ||||
| export default class TimelineContainer extends PureComponent { | ||||
|  | ||||
|   static propTypes = { | ||||
|     locale: PropTypes.string.isRequired, | ||||
|   }; | ||||
| export default class ComposeContainer extends PureComponent { | ||||
|  | ||||
|   render () { | ||||
|     const { locale } = this.props; | ||||
|  | ||||
|     return ( | ||||
|       <IntlProvider locale={locale} messages={messages} onError={onProviderError}> | ||||
|       <IntlProvider> | ||||
|         <Provider store={store}> | ||||
|           <Compose /> | ||||
|         </Provider> | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| import PropTypes from 'prop-types'; | ||||
| import { PureComponent } from 'react'; | ||||
|  | ||||
| import { IntlProvider } from 'react-intl'; | ||||
|  | ||||
| import { Helmet } from 'react-helmet'; | ||||
| import { BrowserRouter, Route } from 'react-router-dom'; | ||||
|  | ||||
| @@ -17,10 +15,8 @@ import { connectUserStream } from 'flavours/glitch/actions/streaming'; | ||||
| import ErrorBoundary from 'flavours/glitch/components/error_boundary'; | ||||
| import UI from 'flavours/glitch/features/ui'; | ||||
| import initialState, { title as siteTitle } from 'flavours/glitch/initial_state'; | ||||
| import { IntlProvider } from 'flavours/glitch/locales'; | ||||
| import { store } from 'flavours/glitch/store'; | ||||
| import { getLocale, onProviderError } from 'locales'; | ||||
|  | ||||
| const { messages } = getLocale(); | ||||
|  | ||||
| const title = process.env.NODE_ENV === 'production' ? siteTitle : `${siteTitle} (Dev)`; | ||||
|  | ||||
| @@ -44,10 +40,6 @@ const createIdentityContext = state => ({ | ||||
|  | ||||
| export default class Mastodon extends PureComponent { | ||||
|  | ||||
|   static propTypes = { | ||||
|     locale: PropTypes.string.isRequired, | ||||
|   }; | ||||
|  | ||||
|   static childContextTypes = { | ||||
|     identity: PropTypes.shape({ | ||||
|       signedIn: PropTypes.bool.isRequired, | ||||
| @@ -83,10 +75,8 @@ export default class Mastodon extends PureComponent { | ||||
|   } | ||||
|  | ||||
|   render () { | ||||
|     const { locale } = this.props; | ||||
|  | ||||
|     return ( | ||||
|       <IntlProvider locale={locale} messages={messages} onError={onProviderError}> | ||||
|       <IntlProvider> | ||||
|         <ReduxProvider store={store}> | ||||
|           <ErrorBoundary> | ||||
|             <BrowserRouter> | ||||
|   | ||||
| @@ -2,8 +2,6 @@ import PropTypes from 'prop-types'; | ||||
| import { PureComponent } from 'react'; | ||||
| import { createPortal } from 'react-dom'; | ||||
|  | ||||
| import { IntlProvider } from 'react-intl'; | ||||
|  | ||||
| import { fromJS } from 'immutable'; | ||||
|  | ||||
| import { ImmutableHashtag as Hashtag } from 'flavours/glitch/components/hashtag'; | ||||
| @@ -14,18 +12,14 @@ import Audio from 'flavours/glitch/features/audio'; | ||||
| import Card from 'flavours/glitch/features/status/components/card'; | ||||
| import MediaModal from 'flavours/glitch/features/ui/components/media_modal'; | ||||
| import Video from 'flavours/glitch/features/video'; | ||||
| import { IntlProvider } from 'flavours/glitch/locales'; | ||||
| import { getScrollbarWidth } from 'flavours/glitch/utils/scrollbar'; | ||||
|  | ||||
| import { getLocale, onProviderError } from 'mastodon/locales'; | ||||
|  | ||||
| const { messages } = getLocale(); | ||||
|  | ||||
| const MEDIA_COMPONENTS = { MediaGallery, Video, Card, Poll, Hashtag, Audio }; | ||||
|  | ||||
| export default class MediaContainer extends PureComponent { | ||||
|  | ||||
|   static propTypes = { | ||||
|     locale: PropTypes.string.isRequired, | ||||
|     components: PropTypes.object.isRequired, | ||||
|   }; | ||||
|  | ||||
| @@ -74,7 +68,7 @@ export default class MediaContainer extends PureComponent { | ||||
|   }; | ||||
|  | ||||
|   render () { | ||||
|     const { locale, components } = this.props; | ||||
|     const { components } = this.props; | ||||
|  | ||||
|     let handleOpenVideo; | ||||
|  | ||||
| @@ -84,7 +78,7 @@ export default class MediaContainer extends PureComponent { | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|       <IntlProvider locale={locale} messages={messages} onError={onProviderError}> | ||||
|       <IntlProvider> | ||||
|         <> | ||||
|           {[].map.call(components, (component, i) => { | ||||
|             const componentName = component.getAttribute('data-component'); | ||||
|   | ||||
| @@ -1,21 +0,0 @@ | ||||
| import { setLocale } from 'locales'; | ||||
|  | ||||
| export async function loadLocale() { | ||||
|   const locale = document.querySelector('html').lang || 'en'; | ||||
|  | ||||
|   const upstreamLocaleData = await import( | ||||
|     /* webpackMode: "lazy" */ | ||||
|     /* webpackChunkName: "locales/vanilla/[request]" */ | ||||
|     /* webpackInclude: /\.json$/ */ | ||||
|     /* webpackPreload: true */ | ||||
|     `mastodon/locales/${locale}.json`); | ||||
|  | ||||
|   const localeData = await import( | ||||
|     /* webpackMode: "lazy" */ | ||||
|     /* webpackChunkName: "locales/glitch/[request]" */ | ||||
|     /* webpackInclude: /\.json$/ */ | ||||
|     /* webpackPreload: true */ | ||||
|     `flavours/glitch/locales/${locale}.json`); | ||||
|  | ||||
|   setLocale({ messages: {...upstreamLocaleData, ...localeData} }); | ||||
| } | ||||
							
								
								
									
										22
									
								
								app/javascript/flavours/glitch/locales/global_locale.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/javascript/flavours/glitch/locales/global_locale.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| export interface LocaleData { | ||||
|   locale: string; | ||||
|   messages: Record<string, string>; | ||||
| } | ||||
|  | ||||
| let loadedLocale: LocaleData; | ||||
|  | ||||
| export function setLocale(locale: LocaleData) { | ||||
|   loadedLocale = locale; | ||||
| } | ||||
|  | ||||
| export function getLocale() { | ||||
|   if (!loadedLocale && process.env.NODE_ENV === 'development') { | ||||
|     throw new Error('getLocale() called before any locale has been set'); | ||||
|   } | ||||
|  | ||||
|   return loadedLocale; | ||||
| } | ||||
|  | ||||
| export function isLocaleLoaded() { | ||||
|   return !!loadedLocale; | ||||
| } | ||||
							
								
								
									
										5
									
								
								app/javascript/flavours/glitch/locales/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/javascript/flavours/glitch/locales/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| export type { LocaleData } from './global_locale'; | ||||
| export { setLocale, getLocale, isLocaleLoaded } from './global_locale'; | ||||
| export { loadLocale } from './load_locale'; | ||||
|  | ||||
| export { IntlProvider } from './intl_provider'; | ||||
							
								
								
									
										56
									
								
								app/javascript/flavours/glitch/locales/intl_provider.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								app/javascript/flavours/glitch/locales/intl_provider.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| import { useEffect, useState } from 'react'; | ||||
|  | ||||
| import { IntlProvider as BaseIntlProvider } from 'react-intl'; | ||||
|  | ||||
| import { getLocale, isLocaleLoaded } from './global_locale'; | ||||
| import { loadLocale } from './load_locale'; | ||||
|  | ||||
| function onProviderError(error: unknown) { | ||||
|   // Silent the error, like upstream does | ||||
|   if (process.env.NODE_ENV === 'production') return; | ||||
|  | ||||
|   // This browser does not advertise Intl support for this locale, we only print a warning | ||||
|   // As-per the spec, the browser should select the best matching locale | ||||
|   if ( | ||||
|     error && | ||||
|     typeof error === 'object' && | ||||
|     error instanceof Error && | ||||
|     error.message.match('MISSING_DATA') | ||||
|   ) { | ||||
|     console.warn(error.message); | ||||
|   } | ||||
|  | ||||
|   console.error(error); | ||||
| } | ||||
|  | ||||
| export const IntlProvider: React.FC< | ||||
|   Omit<React.ComponentProps<typeof BaseIntlProvider>, 'locale' | 'messages'> | ||||
| > = ({ children, ...props }) => { | ||||
|   const [localeLoaded, setLocaleLoaded] = useState(false); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     async function loadLocaleData() { | ||||
|       if (!isLocaleLoaded()) { | ||||
|         await loadLocale(); | ||||
|       } | ||||
|  | ||||
|       setLocaleLoaded(true); | ||||
|     } | ||||
|     void loadLocaleData(); | ||||
|   }, []); | ||||
|  | ||||
|   if (!localeLoaded) return null; | ||||
|  | ||||
|   const { locale, messages } = getLocale(); | ||||
|  | ||||
|   return ( | ||||
|     <BaseIntlProvider | ||||
|       locale={locale} | ||||
|       messages={messages} | ||||
|       onError={onProviderError} | ||||
|       {...props} | ||||
|     > | ||||
|       {children} | ||||
|     </BaseIntlProvider> | ||||
|   ); | ||||
| }; | ||||
							
								
								
									
										37
									
								
								app/javascript/flavours/glitch/locales/load_locale.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/javascript/flavours/glitch/locales/load_locale.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| import { Semaphore } from 'async-mutex'; | ||||
|  | ||||
| import type { LocaleData } from './global_locale'; | ||||
| import { isLocaleLoaded, setLocale } from './global_locale'; | ||||
|  | ||||
| const localeLoadingSemaphore = new Semaphore(1); | ||||
|  | ||||
| export async function loadLocale() { | ||||
|   const locale = document.querySelector<HTMLElement>('html')?.lang || 'en'; | ||||
|  | ||||
|   // We use a Semaphore here so only one thing can try to load the locales at | ||||
|   // the same time. If one tries to do it while its in progress, it will wait | ||||
|   // for the initial load to finish before it is resumed (and will see that locale | ||||
|   // data is already loaded) | ||||
|   await localeLoadingSemaphore.runExclusive(async () => { | ||||
|     // if the locale is already set, then do nothing | ||||
|     if (isLocaleLoaded()) return; | ||||
|  | ||||
|     const upstreamLocaleData = await import( | ||||
|       /* webpackMode: "lazy" */ | ||||
|       /* webpackChunkName: "locales/vanilla/[request]" */ | ||||
|       /* webpackInclude: /\.json$/ */ | ||||
|       /* webpackPreload: true */ | ||||
|       `mastodon/locales/${locale}.json` | ||||
|     ) as LocaleData['messages']; | ||||
|  | ||||
|     const localeData = await import( | ||||
|       /* webpackMode: "lazy" */ | ||||
|       /* webpackChunkName: "locales/glitch/[request]" */ | ||||
|       /* webpackInclude: /\.json$/ */ | ||||
|       /* webpackPreload: true */ | ||||
|       `flavours/glitch/locales/${locale}.json` | ||||
|     ) as LocaleData['messages']; | ||||
|  | ||||
|     setLocale({ messages: { ...upstreamLocaleData, ...localeData }, locale }); | ||||
|   }); | ||||
| } | ||||
| @@ -6,14 +6,14 @@ import ready from 'flavours/glitch/ready'; | ||||
| ready(() => { | ||||
|   [].forEach.call(document.querySelectorAll('[data-admin-component]'), element => { | ||||
|     const componentName  = element.getAttribute('data-admin-component'); | ||||
|     const { locale, ...componentProps } = JSON.parse(element.getAttribute('data-props')); | ||||
|     const { ...componentProps } = JSON.parse(element.getAttribute('data-props')); | ||||
|  | ||||
|     import('flavours/glitch/containers/admin_component').then(({ default: AdminComponent }) => { | ||||
|       return import('flavours/glitch/components/admin/' + componentName).then(({ default: Component }) => { | ||||
|         const root = createRoot(element); | ||||
|  | ||||
|         root.render ( | ||||
|           <AdminComponent locale={locale}> | ||||
|           <AdminComponent> | ||||
|             <Component {...componentProps} /> | ||||
|           </AdminComponent>, | ||||
|         ); | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| import 'packs/public-path'; | ||||
| import { loadLocale } from 'flavours/glitch/load_locale'; | ||||
| import { loadLocale } from 'flavours/glitch/locales'; | ||||
| import main from "flavours/glitch/main"; | ||||
| import { loadPolyfills } from 'flavours/glitch/polyfills'; | ||||
|  | ||||
| loadPolyfills().then(loadLocale).then(async () => { | ||||
|   const { default: main } = await import('flavours/glitch/main'); | ||||
|  | ||||
|   return main(); | ||||
| }).catch(e => { | ||||
|   console.error(e); | ||||
| }); | ||||
| loadPolyfills() | ||||
|   .then(loadLocale) | ||||
|   .then(main) | ||||
|   .catch(e => { | ||||
|     console.error(e); | ||||
|   }); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import 'packs/public-path'; | ||||
| import { createRoot }  from 'react-dom/client'; | ||||
|  | ||||
| import * as IntlMessageFormat  from 'intl-messageformat'; | ||||
| import { IntlMessageFormat } from 'intl-messageformat'; | ||||
| import { defineMessages } from 'react-intl'; | ||||
|  | ||||
| import { delegate }  from '@rails/ujs'; | ||||
| @@ -12,10 +12,9 @@ import { throttle } from 'lodash'; | ||||
| import { timeAgoString }  from 'flavours/glitch/components/relative_timestamp'; | ||||
| import emojify  from 'flavours/glitch/features/emoji/emoji'; | ||||
| import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions'; | ||||
| import { loadLocale } from 'flavours/glitch/load_locale'; | ||||
| import { loadLocale, getLocale } from 'flavours/glitch/locales'; | ||||
| import { loadPolyfills } from 'flavours/glitch/polyfills'; | ||||
| import ready from 'flavours/glitch/ready'; | ||||
| import { getLocale }  from 'locales'; | ||||
|  | ||||
| const messages = defineMessages({ | ||||
|   usernameTaken: { id: 'username.taken', defaultMessage: 'That username is taken. Try another' }, | ||||
| @@ -24,7 +23,7 @@ const messages = defineMessages({ | ||||
| }); | ||||
|  | ||||
| function main() { | ||||
|   const { localeData } = getLocale(); | ||||
|   const { messages: localeData } = getLocale(); | ||||
|  | ||||
|   const scrollToDetailedStatus = () => { | ||||
|     const history = createBrowserHistory(); | ||||
|   | ||||
| @@ -2,7 +2,6 @@ import 'packs/public-path'; | ||||
| import { createRoot } from 'react-dom/client'; | ||||
|  | ||||
| import ComposeContainer from 'flavours/glitch/containers/compose_container'; | ||||
| import { loadLocale } from 'flavours/glitch/load_locale'; | ||||
| import { loadPolyfills } from 'flavours/glitch/polyfills'; | ||||
| import ready from 'flavours/glitch/ready'; | ||||
|  | ||||
| @@ -23,6 +22,6 @@ function main() { | ||||
|   ready(loaded); | ||||
| } | ||||
|  | ||||
| loadPolyfills().then(loadLocale).then(main).catch(error => { | ||||
| loadPolyfills().then(main).catch(error => { | ||||
|   console.error(error); | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user