Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/components/auth-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as Sentry from '@sentry/electron/renderer';
import { createContext, useState, useEffect, useMemo, useCallback, ReactNode } from 'react';
import WPCOM from 'wpcom';
import { useI18nData } from '../hooks/use-i18n-data';
import { useIpcListener } from '../hooks/use-ipc-listener';
import { getAppGlobals } from '../lib/app-globals';
import { getIpcApi } from '../lib/get-ipc-api';

export interface AuthContextType {
Expand Down Expand Up @@ -33,6 +33,7 @@ const AuthProvider: React.FC< AuthProviderProps > = ( { children } ) => {
const [ isAuthenticated, setIsAuthenticated ] = useState( false );
const [ client, setClient ] = useState< WPCOM | undefined >( undefined );
const [ user, setUser ] = useState< AuthContextType[ 'user' ] >( undefined );
const { locale } = useI18nData();

const authenticate = getIpcApi().authenticate;
useIpcListener( 'auth-updated', ( _event, { token, error } ) => {
Expand All @@ -41,7 +42,7 @@ const AuthProvider: React.FC< AuthProviderProps > = ( { children } ) => {
return;
}
setIsAuthenticated( true );
setClient( createWpcomClient( token.accessToken ) );
setClient( createWpcomClient( token.accessToken, locale ) );
if ( token.id || token.email || token.displayName ) {
setUser( {
id: token.id || null,
Expand Down Expand Up @@ -73,7 +74,7 @@ const AuthProvider: React.FC< AuthProviderProps > = ( { children } ) => {
if ( ! token ) {
return;
}
setClient( createWpcomClient( token.accessToken ) );
setClient( createWpcomClient( token.accessToken, locale ) );
if ( token.id || token.email || token.displayName ) {
setUser( {
id: token.id || null,
Expand All @@ -88,7 +89,7 @@ const AuthProvider: React.FC< AuthProviderProps > = ( { children } ) => {
}
}
run();
}, [] );
}, [ locale ] );

// Memoize the context value to avoid unnecessary renders
const contextValue: AuthContextType = useMemo(
Expand All @@ -105,8 +106,7 @@ const AuthProvider: React.FC< AuthProviderProps > = ( { children } ) => {
return <AuthContext.Provider value={ contextValue }>{ children }</AuthContext.Provider>;
};

function createWpcomClient( token?: string ): WPCOM {
const locale = getAppGlobals().locale;
function createWpcomClient( token?: string, locale?: string ): WPCOM {
const wpcom = new WPCOM( token );

if ( ! locale || locale === 'en' ) {
Expand Down
3 changes: 2 additions & 1 deletion src/components/default-error-fallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
__experimentalHStack as HStack,
} from '@wordpress/components';
import { useI18n } from '@wordpress/react-i18n';
import { useI18nData } from '../hooks/use-i18n-data';
import { isMac, isWindows } from '../lib/app-globals';
import { cx } from '../lib/cx';
import { getIpcApi } from '../lib/get-ipc-api';
Expand Down Expand Up @@ -47,8 +48,8 @@ const GravatarSkeleton = () => {

const RightPanel = () => {
const { __ } = useI18n();
const { locale } = useI18nData();
const openLocalizedSupport = async () => {
const { locale } = await getIpcApi().getAppGlobals();
await getIpcApi().openURL( `https://wordpress.com/${ locale }/support` );
};
return (
Expand Down
22 changes: 22 additions & 0 deletions src/components/language-picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { SelectControl } from '@wordpress/components';
import { useI18n } from '@wordpress/react-i18n';
import { useI18nData } from '../hooks/use-i18n-data';
import { SupportedLocale, supportedLocaleNames } from '../lib/locale';

export const LanguagePicker = () => {
const { __ } = useI18n();
const { locale, setLocale } = useI18nData();
return (
<div className="flex gap-5 flex-col">
<h2 className="a8c-subtitle-small">{ __( 'Language' ) }</h2>
<SelectControl
value={ locale || 'en' }
onChange={ ( value ) => setLocale( value as SupportedLocale ) }
options={ Object.entries( supportedLocaleNames ).map( ( [ locale, label ] ) => ( {
value: locale as SupportedLocale,
label,
} ) ) }
/>
</div>
);
};
49 changes: 26 additions & 23 deletions src/components/root.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChatProvider } from '../hooks/use-chat-context';
import { InstalledAppsProvider } from '../hooks/use-check-installed-apps';
import { FeatureFlagsProvider } from '../hooks/use-feature-flags';
import { I18nDataProvider } from '../hooks/use-i18n-data';
import { ImportExportProvider } from '../hooks/use-import-export';
import { OnboardingProvider } from '../hooks/use-onboarding';
import { PromptUsageProvider } from '../hooks/use-prompt-usage';
Expand All @@ -17,29 +18,31 @@ const Root = () => {
return (
<ErrorBoundary>
<CrashTester />
<AuthProvider>
<SnapshotProvider>
<SiteDetailsProvider>
<FeatureFlagsProvider>
<DemoSiteUpdateProvider>
<ThemeDetailsProvider>
<InstalledAppsProvider>
<OnboardingProvider>
<PromptUsageProvider>
<ChatProvider>
<ImportExportProvider>
<App />
</ImportExportProvider>
</ChatProvider>
</PromptUsageProvider>
</OnboardingProvider>
</InstalledAppsProvider>
</ThemeDetailsProvider>
</DemoSiteUpdateProvider>
</FeatureFlagsProvider>
</SiteDetailsProvider>
</SnapshotProvider>
</AuthProvider>
<I18nDataProvider>
<AuthProvider>
<SnapshotProvider>
<SiteDetailsProvider>
<FeatureFlagsProvider>
<DemoSiteUpdateProvider>
<ThemeDetailsProvider>
<InstalledAppsProvider>
<OnboardingProvider>
<PromptUsageProvider>
<ChatProvider>
<ImportExportProvider>
<App />
</ImportExportProvider>
</ChatProvider>
</PromptUsageProvider>
</OnboardingProvider>
</InstalledAppsProvider>
</ThemeDetailsProvider>
</DemoSiteUpdateProvider>
</FeatureFlagsProvider>
</SiteDetailsProvider>
</SnapshotProvider>
</AuthProvider>
</I18nDataProvider>
</ErrorBoundary>
);
};
Expand Down
40 changes: 23 additions & 17 deletions src/components/user-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { cx } from '../lib/cx';
import { getIpcApi } from '../lib/get-ipc-api';
import Button from './button';
import { Gravatar } from './gravatar';
import { LanguagePicker } from './language-picker';
import Modal from './modal';
import offlineIcon from './offline-icon';
import ProgressBar from './progress-bar';
Expand Down Expand Up @@ -240,30 +241,35 @@ export default function UserSettings() {
{ needsToOpenUserSettings && (
<Modal title={ __( 'Settings' ) } isDismissible onRequestClose={ resetLocalState }>
{ ! isAuthenticated && (
<div className="justify-between items-center w-full h-auto flex">
<WordPressLogo width={ 110 } />
<Tooltip disabled={ ! isOffline } icon={ offlineIcon } text={ offlineMessage }>
<Button
aria-description={ isOffline ? offlineMessage : '' }
aria-disabled={ isOffline }
variant="primary"
onClick={ () => {
if ( isOffline ) {
return;
}
authenticate();
} }
>
{ __( 'Log in' ) }
</Button>
</Tooltip>
<div className="flex flex-col gap-6">
<div className="justify-between items-center w-full h-auto flex">
<WordPressLogo width={ 110 } />
<Tooltip disabled={ ! isOffline } icon={ offlineIcon } text={ offlineMessage }>
<Button
aria-description={ isOffline ? offlineMessage : '' }
aria-disabled={ isOffline }
variant="primary"
onClick={ () => {
if ( isOffline ) {
return;
}
authenticate();
} }
>
{ __( 'Log in' ) }
</Button>
</Tooltip>
</div>
<div className="border border-[#F0F0F0] w-full"></div>
<LanguagePicker />
</div>
) }
{ isAuthenticated && (
<div className="gap-6 flex flex-col">
<UserInfo onLogout={ logout } user={ user } />
<div className="border border-[#F0F0F0] w-full"></div>
<div className="flex flex-col gap-6">
<LanguagePicker />
<SnapshotInfo
isDeleting={ loadingDeletingAllSnapshots }
isDisabled={
Expand Down
2 changes: 0 additions & 2 deletions src/hooks/tests/use-chat-context.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ beforeEach( () => {
window.appGlobals = window.appGlobals ?? {};
jest.replaceProperty( window, 'appGlobals', {
platform: 'darwin',
locale: 'en',
localeData: undefined,
appName: '',
arm64Translation: false,
assistantEnabled: false,
Expand Down
8 changes: 5 additions & 3 deletions src/hooks/use-expiration-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { useI18n } from '@wordpress/react-i18n';
import { intervalToDuration, formatDuration, addDays, Duration, addHours } from 'date-fns';
import { HOUR_MS, DAY_MS } from '../constants';
import { formatDistance } from '../lib/date';
import { SupportedLocale } from '../lib/locale';
import { useI18nData } from './use-i18n-data';

function formatStringDate( ms: number ): string {
const { locale = 'en' } = window?.appGlobals || {};
function formatStringDate( ms: number, locale: SupportedLocale ): string {
const formatter = new Intl.DateTimeFormat( locale, {
day: 'numeric',
month: 'long',
Expand All @@ -15,6 +16,7 @@ function formatStringDate( ms: number ): string {

export function useExpirationDate( snapshotDate: number ) {
const { __ } = useI18n();
const { locale } = useI18nData();
const MAX_DAYS = 7;
const now = new Date();
const endDate = addDays( snapshotDate, MAX_DAYS );
Expand Down Expand Up @@ -45,6 +47,6 @@ export function useExpirationDate( snapshotDate: number ) {
return {
isExpired,
countDown: isExpired ? __( 'Expired' ) : countDown,
dateString: formatStringDate( snapshotDate ),
dateString: formatStringDate( snapshotDate, locale ),
};
}
62 changes: 62 additions & 0 deletions src/hooks/use-i18n-data.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { createI18n, I18n } from '@wordpress/i18n';
import { I18nProvider } from '@wordpress/react-i18n';
import { createContext, useContext, useEffect, useMemo, useState, useCallback } from 'react';
import { getIpcApi } from '../lib/get-ipc-api';
import { SupportedLocale, getLocaleData } from '../lib/locale';

interface I18nDataContext {
setLocale: ( localeKey: SupportedLocale ) => void;
locale: SupportedLocale;
}

const I18nDataContext = createContext< I18nDataContext >( {
locale: 'en',
// eslint-disable-next-line @typescript-eslint/no-empty-function
setLocale: () => {},
} );

export const I18nDataProvider = ( { children }: { children: React.ReactNode } ) => {
const [ initialized, setInitialized ] = useState< boolean >( false );
const [ i18n, setI18n ] = useState< I18n | null >( null );
const [ locale, setLocale ] = useState< SupportedLocale >( 'en' );

const initI18n = useCallback( async ( localeKey: SupportedLocale ) => {
const newI18n = createI18n( getLocaleData( localeKey )?.messages );
setI18n( newI18n );
}, [] );

useEffect( () => {
if ( initialized ) {
initI18n( locale );
getIpcApi().saveUserLocale( locale );
return;
}

async function setUserLocale() {
const userLocale = await getIpcApi().getUserLocale();
setLocale( userLocale );
setInitialized( true );
}
setUserLocale();
}, [ initI18n, locale, initialized ] );

const contextValue = useMemo(
() => ( {
setLocale,
locale,
} ),
[ locale ]
);

if ( ! i18n ) {
return null;
}

return (
<I18nDataContext.Provider value={ contextValue }>
<I18nProvider i18n={ i18n }>{ children }</I18nProvider>
</I18nDataContext.Provider>
);
};

export const useI18nData = () => useContext( I18nDataContext );
4 changes: 2 additions & 2 deletions src/hooks/use-localization-support.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useI18n } from '@wordpress/react-i18n';
import { useEffect } from 'react';
import { getAppGlobals } from '../lib/app-globals';
import { useI18nData } from './use-i18n-data';

export function useLocalizationSupport() {
const { __, _x, isRTL } = useI18n();
const locale = getAppGlobals().locale;
const { locale } = useI18nData();

// Some languages may need to set an html lang attribute that is different from their slug
let lang = __( 'html_lang_attribute' );
Expand Down
9 changes: 3 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from 'electron';
import path from 'path';
import * as Sentry from '@sentry/electron/main';
import { __, defaultI18n } from '@wordpress/i18n';
import { __ } from '@wordpress/i18n';
import packageJson from '../package.json';
import { PROTOCOL_PREFIX } from './constants';
import * as ipcHandlers from './ipc-handlers';
Expand All @@ -22,7 +22,7 @@ import {
processCLICommand,
executeCLICommand,
} from './lib/cli';
import { getLocaleData, getSupportedLocale } from './lib/locale';
import { getUserLocaleWithFallback } from './lib/locale-node';
import { handleAuthCallback, setUpAuthCallbackHandler } from './lib/oauth';
import { setupLogging } from './logging';
import { createMainWindow, withMainWindow } from './main-window';
Expand Down Expand Up @@ -197,10 +197,7 @@ async function appBoot() {
}

app.on( 'ready', async () => {
// Set translations based on supported locale
const locale = getSupportedLocale();
const localeData = getLocaleData( locale );
defaultI18n.setLocaleData( localeData?.locale_data?.messages );
const locale = await getUserLocaleWithFallback();

console.log( `App version: ${ app.getVersion() }` );
console.log( `Built from commit: ${ COMMIT_HASH ?? 'undefined' }` );
Expand Down
Loading