Skip to content

Hosting Dashboard: Introduce I18nProvider to make translation work correctly #103299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions client/boot/locale.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function getLocaleFromQueryParam() {
return query.get( 'locale' );
}

export const setupLocale = ( currentUser, reduxStore ) => {
export const setupLocale = ( currentUser, reduxStore = null ) => {
if ( config.isEnabled( 'i18n/empathy-mode' ) && currentUser.i18n_empathy_mode ) {
initLanguageEmpathyMode();
}
Expand All @@ -49,34 +49,51 @@ export const setupLocale = ( currentUser, reduxStore ) => {
i18n.setLocale( localeData );
const localeSlug = i18n.getLocaleSlug();
const localeVariant = i18n.getLocaleVariant();
reduxStore.dispatch( { type: LOCALE_SET, localeSlug, localeVariant } );
reduxStore?.dispatch( { type: LOCALE_SET, localeSlug, localeVariant } );
// Propagate the locale to @automattic/number-formatters
setLocaleNumberFormatters( localeVariant || localeSlug );

if ( localeSlug ) {
loadUserUndeployedTranslations( localeSlug );
}
} else if ( currentUser && currentUser.localeSlug ) {
return localeVariant || localeSlug;
}

if ( currentUser && ( currentUser.localeSlug || currentUser.language ) ) {
if ( shouldUseFallbackLocale ) {
// Use user locale fallback slug
reduxStore.dispatch( setLocale( userLocaleSlug ) );
} else {
// Use the current user's and load traslation data with a fetch request
reduxStore.dispatch( setLocale( currentUser.localeSlug, currentUser.localeVariant ) );
reduxStore?.dispatch( setLocale( userLocaleSlug ) );
return userLocaleSlug;
}
} else if ( bootstrappedLocaleSlug ) {

// Use the current user's and load translation data with a fetch request
reduxStore?.dispatch(
setLocale( currentUser.localeSlug || currentUser.language, currentUser.localeVariant )
);
return currentUser.localeVariant || currentUser.localeSlug || currentUser.language;
}

if ( bootstrappedLocaleSlug ) {
// Use locale slug from bootstrapped language manifest object
reduxStore.dispatch( setLocale( bootstrappedLocaleSlug ) );
} else if ( getLocaleFromQueryParam() ) {
reduxStore?.dispatch( setLocale( bootstrappedLocaleSlug ) );
return bootstrappedLocaleSlug;
}

if ( getLocaleFromQueryParam() ) {
// For logged out Calypso pages, set the locale from query param
const pathLocaleSlug = getLocaleFromQueryParam();
pathLocaleSlug && reduxStore.dispatch( setLocale( pathLocaleSlug, '' ) );
} else if ( ! window.hasOwnProperty( 'localeFromRoute' ) ) {
pathLocaleSlug && reduxStore?.dispatch( setLocale( pathLocaleSlug, '' ) );
return pathLocaleSlug;
}

if ( ! window.hasOwnProperty( 'localeFromRoute' ) ) {
// For logged out Calypso pages, set the locale from path if we cannot get the locale from the route on the server side
const pathLocaleSlug = getLocaleFromPathname();
pathLocaleSlug && reduxStore.dispatch( setLocale( pathLocaleSlug, '' ) );
pathLocaleSlug && reduxStore?.dispatch( setLocale( pathLocaleSlug, '' ) );
recordTracksEvent( 'calypso_locale_set', { path: window.location.pathname } );
return pathLocaleSlug;
}

// If user is logged out and translations are not bootstrapped, we assume default locale
return '';
};
7 changes: 7 additions & 0 deletions client/dashboard/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,19 @@ module.exports = {
{
group: [
'calypso/*',
'!calypso/boot',
'calypso/boot/*',
'!calypso/boot/locale',
// Allowed: calypso/lib/wp
'!calypso/lib',
'calypso/lib/*',
'!calypso/lib/wp',
'!calypso/lib/i18n-utils',
'calypso/lib/i18n-utils/*',
'!calypso/lib/i18n-utils/switch-locale',
'!calypso/components',
'calypso/components/*',
'!calypso/components/calypso-i18n-provider',
// Allowed: calypso/assets/icons
'!calypso/assets',
'calypso/assets/*',
Expand Down
26 changes: 26 additions & 0 deletions client/dashboard/app/i18n/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import defaultCalypsoI18n from 'i18n-calypso';
import { useEffect } from 'react';
import { setupLocale } from 'calypso/boot/locale';
import CalypsoI18nProvider from 'calypso/components/calypso-i18n-provider';
import switchLocale from 'calypso/lib/i18n-utils/switch-locale';
import { useAuth } from '../auth';

export function I18nProvider( { children }: { children: React.ReactNode } ) {
const { user } = useAuth();

useEffect( () => {
if ( ! user.language ) {
return;
}

const locale = setupLocale( user );

// The `switchLocale` function is normally called within the `setLocale` action. However,
// since we don't have access to the Redux store in this context, we need to call it manually.
if ( locale ) {
switchLocale( locale );
}
}, [ user.language ] );

return <CalypsoI18nProvider i18n={ defaultCalypsoI18n }>{ children }</CalypsoI18nProvider>;
}
5 changes: 4 additions & 1 deletion client/dashboard/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { RouterProvider } from '@tanstack/react-router';
import { useMemo } from 'react';
import { AuthProvider, useAuth } from './auth';
import { AppProvider, type AppConfig } from './context';
import { I18nProvider } from './i18n';
import { queryClient } from './query-client';
import { getRouter } from './router';

Expand All @@ -17,7 +18,9 @@ function Layout( { config }: { config: AppConfig } ) {
<AppProvider config={ config }>
<QueryClientProvider client={ queryClient }>
<AuthProvider>
<RouterProviderWithAuth config={ config } />
<I18nProvider>
<RouterProviderWithAuth config={ config } />
</I18nProvider>
</AuthProvider>
</QueryClientProvider>
</AppProvider>
Expand Down
1 change: 1 addition & 0 deletions client/dashboard/data/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface User {
username: string;
display_name: string;
avatar_URL?: string;
language: string;
}

export interface SiteDomain {
Expand Down
Loading