Skip to content
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

chore(deps): update i18next series packages #3733

Merged
merged 3 commits into from
Apr 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/console/package.json
Expand Up @@ -65,8 +65,8 @@
"dnd-core": "^16.0.0",
"eslint": "^8.34.0",
"history": "^5.3.0",
"i18next": "^21.8.16",
"i18next-browser-languagedetector": "^6.1.4",
"i18next": "^22.4.15",
"i18next-browser-languagedetector": "^7.0.1",
"just-kebab-case": "^4.2.0",
"ky": "^0.33.0",
"lint-staged": "^13.0.0",
Expand All @@ -89,7 +89,7 @@
"react-helmet": "^6.1.0",
"react-hook-form": "^7.34.0",
"react-hot-toast": "^2.2.0",
"react-i18next": "^11.18.3",
"react-i18next": "^12.2.0",
"react-markdown": "^8.0.0",
"react-modal": "^3.15.1",
"react-paginate": "^8.1.3",
Expand Down
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import type { TFuncKey } from 'i18next';
import type { MouseEventHandler } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import type { TFuncKey } from 'react-i18next';
import { useTranslation } from 'react-i18next';

import Copy from '@/assets/images/copy.svg';
Expand Down
Expand Up @@ -8,7 +8,7 @@ import * as styles from './DropdownItem.module.scss';
type Props = {
onClick?: (event: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>) => void;
className?: string;
children: ReactNode | Record<string, unknown>;
children: ReactNode;
icon?: ReactNode;
iconClassName?: string;
type?: 'default' | 'danger';
Expand Down
18 changes: 18 additions & 0 deletions packages/console/src/components/DynamicT/index.tsx
@@ -0,0 +1,18 @@
import { type AdminConsoleKey } from '@logto/phrases';
import { useTranslation } from 'react-i18next';

type Props = {
forKey: AdminConsoleKey;
};

/**
* A component to render a dynamic translation key.
* Since `ReactNode` does not include vanilla objects while `JSX.Element` does. It's strange but no better way for now.
*
* @see https://github.com/i18next/i18next/issues/1852
*/
export default function DynamicT({ forKey }: Props) {
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });

return <>{t(forKey)}</>;
}
3 changes: 2 additions & 1 deletion packages/console/src/components/FormCard/index.tsx
Expand Up @@ -3,6 +3,7 @@ import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import Card from '../Card';
import DynamicT from '../DynamicT';
import TextLink from '../TextLink';

import * as styles from './index.module.scss';
Expand All @@ -23,7 +24,7 @@ function FormCard({ title, description, learnMoreLink, children }: Props) {
<div className={styles.title}>{t(title)}</div>
{description && (
<div className={styles.description}>
{t(description)}
<DynamicT forKey={description} />
gao-sun marked this conversation as resolved.
Show resolved Hide resolved
{learnMoreLink && (
<>
{' '}
Expand Down
3 changes: 2 additions & 1 deletion packages/console/src/components/FormField/index.tsx
Expand Up @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
import Tip from '@/assets/images/tip.svg';

import type DangerousRaw from '../DangerousRaw';
import DynamicT from '../DynamicT';
import IconButton from '../IconButton';
import Spacer from '../Spacer';
import { ToggleTip } from '../Tip';
Expand Down Expand Up @@ -38,7 +39,7 @@ function FormField({
<div className={classNames(styles.field, className)}>
<div className={classNames(styles.headline, headlineClassName)}>
<div className={styles.title}>
{typeof title === 'string' ? t(title) : title}
{typeof title === 'string' ? <DynamicT forKey={title} /> : title}
{isMultiple && (
<span className={styles.multiple}>{t('general.multiple_form_field')}</span>
)}
Expand Down
3 changes: 2 additions & 1 deletion packages/console/src/components/RadioGroup/Radio.tsx
Expand Up @@ -5,6 +5,7 @@ import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';

import type DangerousRaw from '../DangerousRaw';
import DynamicT from '../DynamicT';

import * as styles from './Radio.module.scss';

Expand Down Expand Up @@ -89,7 +90,7 @@ function Radio({
{children}
{type === 'plain' && <div className={styles.indicator} />}
{icon && <span className={styles.icon}>{icon}</span>}
{title && (typeof title === 'string' ? t(title) : title)}
{title && (typeof title === 'string' ? <DynamicT forKey={title} /> : title)}
{isDisabled && disabledLabel && (
<div className={classNames(styles.indicator, styles.disabledLabel)}>
{t(disabledLabel)}
Expand Down
Expand Up @@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';

import useTheme from '@/hooks/use-theme';

import DynamicT from '../DynamicT';
import TextLink from '../TextLink';

import * as styles from './TablePlaceholder.module.scss';
Expand All @@ -27,7 +28,7 @@ function TablePlaceholder({ image, imageDark, title, description, learnMoreLink,
<div className={styles.image}>{theme === Theme.Light ? image : imageDark}</div>
<div className={styles.title}>{t(title)}</div>
<div className={styles.description}>
{t(description)}
<DynamicT forKey={description} />
{learnMoreLink && (
<>
{' '}
Expand Down
Expand Up @@ -46,7 +46,7 @@ function UserAccountInformation({
primaryEmail && `${t('user_details.created_email')} ${primaryEmail}`,
primaryPhone && `${t('user_details.created_phone')} ${primaryPhone}`,
username && `${t('user_details.created_username')} ${username}`,
`${passwordLabel ?? t('user_details.created_password')} ${password}`
`${passwordLabel ?? t('user_details.created_username')} ${password}`
gao-sun marked this conversation as resolved.
Show resolved Hide resolved
).join('\n');

await navigator.clipboard.writeText(content);
Expand Down
10 changes: 5 additions & 5 deletions packages/console/src/consts/connectors.ts
Expand Up @@ -9,21 +9,21 @@ type TitlePlaceHolder = {
[key in ConnectorType]: AdminConsoleKey;
};

export const connectorTitlePlaceHolder: TitlePlaceHolder = Object.freeze({
export const connectorTitlePlaceHolder = Object.freeze({
[ConnectorType.Sms]: 'connectors.type.sms',
[ConnectorType.Email]: 'connectors.type.email',
[ConnectorType.Social]: 'connectors.type.social',
});
}) satisfies TitlePlaceHolder;

type ConnectorPlatformLabel = {
[key in ConnectorPlatform]: AdminConsoleKey;
};

export const connectorPlatformLabel: ConnectorPlatformLabel = Object.freeze({
export const connectorPlatformLabel = Object.freeze({
[ConnectorPlatform.Native]: 'connectors.platform.native',
[ConnectorPlatform.Universal]: 'connectors.platform.universal',
[ConnectorPlatform.Web]: 'connectors.platform.web',
});
}) satisfies ConnectorPlatformLabel;

type ConnectorPlaceholderIcon = {
[key in ConnectorType]?: SvgComponent;
Expand All @@ -32,7 +32,7 @@ type ConnectorPlaceholderIcon = {
export const connectorPlaceholderIcon: ConnectorPlaceholderIcon = Object.freeze({
[ConnectorType.Sms]: SmsConnectorIcon,
[ConnectorType.Email]: EmailConnector,
} as const);
});

export const defaultSmsConnectorGroup: ConnectorGroup = {
id: 'default-sms-connector',
Expand Down
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import type { ReactChild, ReactNode } from 'react';
import type { TFuncKey } from 'i18next';
import type { ReactNode } from 'react';
import { useMemo, useState } from 'react';
import type { TFuncKey } from 'react-i18next';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';

Expand All @@ -10,7 +10,7 @@ import { getPath } from '../../utils';
import * as styles from './index.module.scss';

type Props = {
icon?: ReactChild;
icon?: ReactNode;
titleKey: TFuncKey<'translation', 'admin_console.tabs'>;
isActive?: boolean;
modal?: (isOpen: boolean, onCancel: () => void) => ReactNode;
Expand Down
@@ -1,6 +1,6 @@
import type { Optional } from '@silverhand/essentials';
import type { TFuncKey } from 'i18next';
import type { FC, ReactNode } from 'react';
import type { TFuncKey } from 'react-i18next';

import Role from '@/assets/images/role.svg';
import useDocumentationUrl from '@/hooks/use-documentation-url';
Expand Down
5 changes: 3 additions & 2 deletions packages/console/src/hooks/use-me-custom-data.ts
@@ -1,7 +1,7 @@
import { useLogto } from '@logto/react';
import { t } from 'i18next';
import { useCallback } from 'react';
import { toast } from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import useSWR from 'swr';

import { adminTenantEndpoint, meApi } from '@/consts';
Expand All @@ -13,6 +13,7 @@ import useSwrFetcher from './use-swr-fetcher';

const useMeCustomData = () => {
const { isAuthenticated, error: authError } = useLogto();
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
const userId = useLogtoUserId();
const shouldFetch = isAuthenticated && !authError && userId;
const api = useStaticApi({ prefixUrl: adminTenantEndpoint, resourceIndicator: meApi.indicator });
Expand All @@ -38,7 +39,7 @@ const useMeCustomData = () => {
.json();
await mutate(updated);
},
[api, mutate, userId]
[api, mutate, t, userId]
);

return {
Expand Down
Expand Up @@ -2,8 +2,9 @@

import type { LocalePhrase } from '@logto/phrases';

declare module 'react-i18next' {
declare module 'i18next' {
interface CustomTypeOptions {
returnNull: false;
allowObjectInHTMLChildren: true;
resources: LocalePhrase;
}
Expand Down
Expand Up @@ -2,6 +2,7 @@ import { conditional } from '@silverhand/essentials';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';

import DynamicT from '@/components/DynamicT';
import { Tooltip } from '@/components/Tip';
import { onKeyDownHandler } from '@/utils/a11y';

Expand Down Expand Up @@ -52,7 +53,7 @@ function CardItem({
{icon && <span className={styles.icon}>{icon}</span>}
<div className={styles.content}>
<div>
{typeof title === 'string' ? t(title) : title}
{typeof title === 'string' ? <DynamicT forKey={title} /> : title}
{trailingTag && (
<span className={classNames(styles.tag, styles.trailingTag)}>{t(trailingTag)}</span>
)}
Expand Down
Expand Up @@ -3,6 +3,7 @@ import classNames from 'classnames';
import type { ReactNode } from 'react';
import { useTranslation } from 'react-i18next';

import DynamicT from '@/components/DynamicT';
import type { PreviewPlatform } from '@/components/SignInExperiencePreview/types';
import { onKeyDownHandler } from '@/utils/a11y';

Expand Down Expand Up @@ -32,7 +33,7 @@ function PlatformTab({ isSelected, icon, title, tab, onClick }: Props) {
})}
>
<span className={styles.icon}>{icon}</span>
{t(title)}
<DynamicT forKey={title} />
</div>
);
}
Expand Down
Expand Up @@ -73,7 +73,7 @@ function ConnectorName({ connectorGroup, isDemo = false }: Props) {
platform && (
<div key={id} className={styles.platform}>
<ConnectorPlatformIcon platform={platform} />
{t(`${connectorPlatformLabel[platform]}`)}
{t(connectorPlatformLabel[platform])}
</div>
)
)}
Expand Down
3 changes: 2 additions & 1 deletion packages/console/src/pages/Dashboard/components/Block.tsx
Expand Up @@ -7,6 +7,7 @@ import ArrowDown from '@/assets/images/arrow-down.svg';
import ArrowUp from '@/assets/images/arrow-up.svg';
import Tip from '@/assets/images/tip.svg';
import Card from '@/components/Card';
import DynamicT from '@/components/DynamicT';
import IconButton from '@/components/IconButton';
import { ToggleTip } from '@/components/Tip';
import type { Props as ToggleTipProps } from '@/components/Tip/ToggleTip';
Expand All @@ -30,7 +31,7 @@ function Block({ variant = 'default', count, delta, title, tip }: Props) {
return (
<Card className={classNames(styles.block, styles[variant])}>
<div className={styles.title}>
{t(title)}
<DynamicT forKey={title} />
{tip && (
<ToggleTip anchorClassName={styles.toggleTipButton} content={tip}>
<IconButton size="small">
Expand Down
Expand Up @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
import TadaDark from '@/assets/images/tada-dark.svg';
import Tada from '@/assets/images/tada.svg';
import Dropdown, { DropdownItem } from '@/components/Dropdown';
import DynamicT from '@/components/DynamicT';
import Index from '@/components/Index';
import useTheme from '@/hooks/use-theme';
import useUserPreferences from '@/hooks/use-user-preferences';
Expand Down Expand Up @@ -77,7 +78,7 @@ function GetStartedProgress() {
icon={<Index className={styles.index} index={index + 1} isComplete={isComplete} />}
onClick={onClick}
>
{t(title)}
<DynamicT forKey={title} />
</DropdownItem>
))}
</div>
Expand Down
Expand Up @@ -5,6 +5,7 @@ import { cloneElement } from 'react';
import { useTranslation } from 'react-i18next';

import Button from '@/components/Button';
import DynamicT from '@/components/DynamicT';

import NotSet from '../NotSet';

Expand Down Expand Up @@ -56,7 +57,7 @@ function CardContent<T extends Nullable<boolean | string | Record<string, unknow
cloneElement(icon, {
className: styles.icon,
})}
{typeof label === 'string' ? t(label) : label}
{typeof label === 'string' ? <DynamicT forKey={label} /> : label}
</div>
</td>
<td>{renderer(value)}</td>
Expand Down
Expand Up @@ -44,7 +44,7 @@ function MainFlowLikeModal({ title, subtitle, subtitleProps, children, onClose,
{subtitle && (
<span className={styles.subtitle}>
<Trans components={{ strong: <span className={styles.strong} /> }}>
{t(subtitle, subtitleProps)}
{t(subtitle, subtitleProps ?? {})}
</Trans>
</span>
)}
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { getSafe } from '@silverhand/essentials';
import { detailedDiff } from 'deep-object-diff';
import { useTranslation } from 'react-i18next';

import DynamicT from '@/components/DynamicT';
import { signInIdentifierPhrase } from '@/pages/SignInExperience/constants';
import type { SignInMethod, SignInMethodsObject } from '@/pages/SignInExperience/types';

Expand Down Expand Up @@ -55,7 +56,7 @@ function SignInDiffSection({ before, after, isAfter = false }: Props) {
return (
<li key={identifierKey}>
<DiffSegment hasChanged={hasIdentifierChanged(identifierKey)} isAfter={isAfter}>
{String(t(signInIdentifierPhrase[identifierKey]))}
<DynamicT forKey={signInIdentifierPhrase[identifierKey]} />
{hasAuthentication && ' ('}
{password && (
<DiffSegment
Expand All @@ -65,7 +66,7 @@ function SignInDiffSection({ before, after, isAfter = false }: Props) {
{t('sign_in_exp.sign_up_and_sign_in.sign_in.password_auth')}
</DiffSegment>
)}
{needDisjunction && ` ${String(t('sign_in_exp.sign_up_and_sign_in.or'))} `}
{needDisjunction && ` ${t('sign_in_exp.sign_up_and_sign_in.or')} `}
{verificationCode && (
<DiffSegment
hasChanged={hasAuthenticationChanged(identifierKey, 'verificationCode')}
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { getSafe } from '@silverhand/essentials';
import { diff } from 'deep-object-diff';
import { useTranslation } from 'react-i18next';

import DynamicT from '@/components/DynamicT';
import { signUpIdentifierPhrase } from '@/pages/SignInExperience/constants';
import type { SignUpForm } from '@/pages/SignInExperience/types';
import { signInExperienceParser } from '@/pages/SignInExperience/utils/form';
Expand Down Expand Up @@ -34,15 +35,15 @@ function SignUpDiffSection({ before, after, isAfter = false }: Props) {
<ul className={styles.list}>
<li>
<DiffSegment hasChanged={hasChanged('identifier')} isAfter={isAfter}>
{String(t(signUpIdentifierPhrase[identifier]))}
<DynamicT forKey={signUpIdentifierPhrase[identifier]} />
</DiffSegment>
{hasAuthentication && ' ('}
{password && (
<DiffSegment hasChanged={hasChanged('password')} isAfter={isAfter}>
{t('sign_in_exp.sign_up_and_sign_in.sign_up.set_a_password_option')}
</DiffSegment>
)}
{needConjunction && ` ${String(t('sign_in_exp.sign_up_and_sign_in.and'))} `}
{needConjunction && ` ${t('sign_in_exp.sign_up_and_sign_in.and')} `}
{verify && (
<DiffSegment hasChanged={hasChanged('verify')} isAfter={isAfter}>
{needConjunction
Expand Down