From e2005780a39fa7b5f5c5e406f37805913b684c18 Mon Sep 17 00:00:00 2001 From: Charles Zhao Date: Wed, 7 Sep 2022 12:11:00 +0800 Subject: [PATCH] fix(console,ui): fix locale guard issue in settings page --- .../pages/Connectors/components/Guide/index.tsx | 8 ++------ packages/console/src/pages/Settings/index.tsx | 4 ++-- packages/shared/src/language.ts | 6 ++++++ packages/shared/src/utilities/zod.ts | 15 +++++++++++++++ .../SocialSignIn/SocialSignInDropdown/index.tsx | 4 ++-- 5 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 packages/shared/src/utilities/zod.ts diff --git a/packages/console/src/pages/Connectors/components/Guide/index.tsx b/packages/console/src/pages/Connectors/components/Guide/index.tsx index 01c9f6a93..d5e7db246 100644 --- a/packages/console/src/pages/Connectors/components/Guide/index.tsx +++ b/packages/console/src/pages/Connectors/components/Guide/index.tsx @@ -1,5 +1,5 @@ import { ConnectorDto, ConnectorType } from '@logto/schemas'; -import { languageKeyGuard } from '@logto/shared'; +import { getDefaultLanguage } from '@logto/shared'; import { conditional } from '@silverhand/essentials'; import i18next from 'i18next'; import { Controller, useForm } from 'react-hook-form'; @@ -31,11 +31,7 @@ const Guide = ({ connector, onClose }: Props) => { const { updateSettings } = useSettings(); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { id: connectorId, type: connectorType, name, configTemplate, readme } = connector; - - const localeRaw = i18next.language; - const result = languageKeyGuard.safeParse(localeRaw); - const connectorName = result.success ? name[result.data] : name.en; - + const connectorName = name[getDefaultLanguage(i18next.language)]; const isSocialConnector = connectorType !== ConnectorType.Sms && connectorType !== ConnectorType.Email; const methods = useForm({ reValidateMode: 'onBlur' }); diff --git a/packages/console/src/pages/Settings/index.tsx b/packages/console/src/pages/Settings/index.tsx index 30c7c859c..e573d6c18 100644 --- a/packages/console/src/pages/Settings/index.tsx +++ b/packages/console/src/pages/Settings/index.tsx @@ -1,6 +1,6 @@ import { languageOptions } from '@logto/phrases'; import { AppearanceMode } from '@logto/schemas'; -import { languageKeyGuard } from '@logto/shared'; +import { getDefaultLanguage } from '@logto/shared'; import classNames from 'classnames'; import { Controller, useForm } from 'react-hook-form'; import { toast } from 'react-hot-toast'; @@ -25,7 +25,7 @@ const Settings = () => { i18n: { language }, } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const defaultLanguage = languageKeyGuard.default('en').parse(language); + const defaultLanguage = getDefaultLanguage(language); const { data, error, update, isLoading, isLoaded } = useUserPreferences(); const { diff --git a/packages/shared/src/language.ts b/packages/shared/src/language.ts index 56b7afc03..e5913d3ca 100644 --- a/packages/shared/src/language.ts +++ b/packages/shared/src/language.ts @@ -1,5 +1,11 @@ import { z } from 'zod'; +import { fallback } from './utilities/zod'; + export const languageKeys = ['en', 'fr', 'pt-PT', 'zh-CN', 'tr-TR', 'ko-KR'] as const; export const languageKeyGuard = z.enum(languageKeys); export type LanguageKey = z.infer; + +export const getDefaultLanguage = (language: string): LanguageKey => { + return languageKeyGuard.or(fallback('en')).parse(language); +}; diff --git a/packages/shared/src/utilities/zod.ts b/packages/shared/src/utilities/zod.ts new file mode 100644 index 000000000..ddcdab684 --- /dev/null +++ b/packages/shared/src/utilities/zod.ts @@ -0,0 +1,15 @@ +import { any } from 'zod'; + +/** + * https://github.com/colinhacks/zod/issues/316#issuecomment-850906479 + * Create a schema matches anything and returns a value. Use it with `or`: + * + * const schema = zod.number(); + * const tolerant = schema.or(fallback(-1)); + * + * schema.parse('foo') // => ZodError + * tolerant.parse('foo') // -1 + */ +export function fallback(value: T) { + return any().transform(() => value); +} diff --git a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx index 552d59b0e..e3effc860 100644 --- a/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx +++ b/packages/ui/src/containers/SocialSignIn/SocialSignInDropdown/index.tsx @@ -1,4 +1,4 @@ -import { languageKeyGuard } from '@logto/shared'; +import { getDefaultLanguage } from '@logto/shared'; import { useState, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -47,7 +47,7 @@ const SocialSignInDropdown = ({ isOpen, onClose, connectors, anchorRef }: Props) > {connectors.map((connector) => { const { id, name, logo, logoDark } = connector; - const localName = name[languageKeyGuard.default('en').parse(language)]; + const localName = name[getDefaultLanguage(language)]; return (