diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 8bd8f2d59..60ed1fc00 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -941,6 +941,7 @@ "__TOOLS_TRANSLATE_TOAST_LANGUAGE_SUCCESS_MESSAGE": "Preferred language updated", "__TOOLS_TRANSLATE_TOAST_SUCCESS_MESSAGE": "Translation completed", "__TOOLS_TRANSLATE_TOGGLE_TEXT": "Set as preferred language", + "__TOOLS_TRANSLATE_PROGRESS_BAR_LABEL": "Translation in progress...", "__UX_CAMPAIGN_PAGE_NAVIGATION_DASHBOARD_TOOLTIP": "Dashboard", "__UX_CAMPAIGN_PAGE_NAVIGATION_INSIGHTS_TOOLTIP": "Topics & insights", "__UX_CAMPAIGN_PAGE_NAVIGATION_VIDEO_LIST_TOOLTIP": "Playlist", diff --git a/src/locales/it/translation.json b/src/locales/it/translation.json index 06e57237c..6251eb15d 100644 --- a/src/locales/it/translation.json +++ b/src/locales/it/translation.json @@ -970,6 +970,7 @@ "__TOOLS_TRANSLATE_TOAST_LANGUAGE_SUCCESS_MESSAGE": "", "__TOOLS_TRANSLATE_TOAST_SUCCESS_MESSAGE": "", "__TOOLS_TRANSLATE_TOGGLE_TEXT": "", + "__TOOLS_TRANSLATE_PROGRESS_BAR_LABEL": "Traduzione in corso...", "__UX_CAMPAIGN_PAGE_NAVIGATION_DASHBOARD_TOOLTIP": "Dashboard", "__UX_CAMPAIGN_PAGE_NAVIGATION_INSIGHTS_TOOLTIP": "Temi e scoperte", "__UX_CAMPAIGN_PAGE_NAVIGATION_VIDEO_LIST_TOOLTIP": "Lista Video", diff --git a/src/pages/Video/components/Transcript/TranslationLoader.tsx b/src/pages/Video/components/Transcript/TranslationLoader.tsx index 36db11bdc..2fa131ebf 100644 --- a/src/pages/Video/components/Transcript/TranslationLoader.tsx +++ b/src/pages/Video/components/Transcript/TranslationLoader.tsx @@ -1,34 +1,18 @@ import { Skeleton, SM } from '@appquality/unguess-design-system'; -import { useParams } from 'react-router-dom'; import { appTheme } from 'src/app/theme'; -import { useFeatureFlag } from 'src/hooks/useFeatureFlag'; -import { useGetVideosByVidTranslationQuery } from 'src/features/api'; import styled from 'styled-components'; -import { FEATURE_FLAG_AI_TRANSLATION } from 'src/constants'; -import { useToolsContext } from '../tools/context/ToolsContext'; -import { usePreferredLanguage } from '../tools/usePreferredLanguage'; +import { useTranslation } from 'react-i18next'; +import { useTranslationTools } from '../tools/hooks/useTranslationTools'; const LoaderWrapper = styled.div` margin-top: ${appTheme.space.xs}; `; export const TranslationLoader = () => { - const { videoId } = useParams(); - const { language } = useToolsContext(); - const { hasFeatureFlag } = useFeatureFlag(); - const hasAIFeatureFlag = hasFeatureFlag(FEATURE_FLAG_AI_TRANSLATION); - const preferredLanguage = usePreferredLanguage(); - const { data } = useGetVideosByVidTranslationQuery( - { - vid: videoId || '', - ...(language && { lang: language }), - }, - { - skip: !hasAIFeatureFlag || !language || !preferredLanguage, - } - ); + const { isProcessing } = useTranslationTools(); + const { t } = useTranslation(); - if (!data?.processing) return null; + if (!isProcessing) return null; return ( @@ -37,7 +21,7 @@ export const TranslationLoader = () => { color={appTheme.palette.grey[700]} style={{ marginBottom: appTheme.space.xxs }} > - Translation in progress.... + {t('__TOOLS_TRANSLATE_PROGRESS_BAR_LABEL')} void; }) => { - const { language } = useToolsContext(); - - const { hasFeatureFlag } = useFeatureFlag(); - const hasAIFeatureFlag = hasFeatureFlag(FEATURE_FLAG_AI_TRANSLATION); - const handleAddObservation = useAddObservation({ videoId: videoId || '' }); - const { data: content, speakers } = useContent(videoId || ''); - const { data: observations } = useObservations(videoId || ''); - - const { data: translation } = useGetVideosByVidTranslationQuery( - { - vid: videoId || '', - ...(language && { lang: language }), - }, - { - skip: !hasAIFeatureFlag || !language, - } - ); + const { data: translationData } = useTranslationTools(); const editor = TranscriptComponent.useEditor( { currentTime: currentTime * 1000, onSetCurrentTime: (time) => setCurrentTime(time), content, - translations: translation?.sentences, + translations: translationData.translation?.sentences, themeExtension: TranscriptTheme, observations, // @ts-ignore numberOfSpeakers: speakers, }, - [observations, translation?.sentences] + [observations, translationData.translation?.sentences] ); return ( diff --git a/src/pages/Video/components/tools/ToolsTranslate.tsx b/src/pages/Video/components/tools/ToolsTranslate.tsx index 04183aad0..29282234f 100644 --- a/src/pages/Video/components/tools/ToolsTranslate.tsx +++ b/src/pages/Video/components/tools/ToolsTranslate.tsx @@ -62,13 +62,9 @@ const ToolsTranslate = ({ currentLanguage }: { currentLanguage?: string }) => { (preference) => preference?.name === 'translations_language' ); - // Remove videoLanguage and current translation language from allowedLanguages - const filteredLanguages = allowedLanguages.filter( - (lang) => lang !== videoLanguage && lang !== currentLanguage - ); - useEffect(() => { - if (languagePreference?.value) { + const lang = languagePreference?.value; + if (lang && lang !== videoLanguage && lang !== currentLanguage) { setInternalLanguage(languagePreference.value); } }, [languagePreference]); @@ -101,13 +97,16 @@ const ToolsTranslate = ({ currentLanguage }: { currentLanguage?: string }) => { label={t('__TOOLS_TRANSLATE_LANGUAGE_DROPDOWN_LABEL')} startIcon={} placeholder={t('__TOOLS_TRANSLATE_LANGUAGE_DROPDOWN_PLACEHOLDER')} + onSelect={(value) => setInternalLanguage(value)} + selectionValue={internalLanguage} + inputValue={getLanguageNameByFullTag(internalLanguage) ?? ''} > - {filteredLanguages.map((lang) => ( + {allowedLanguages.map((lang) => ( ))} diff --git a/src/pages/Video/components/tools/hooks/useTranslationTools.tsx b/src/pages/Video/components/tools/hooks/useTranslationTools.tsx new file mode 100644 index 000000000..36dfbff68 --- /dev/null +++ b/src/pages/Video/components/tools/hooks/useTranslationTools.tsx @@ -0,0 +1,83 @@ +import { useParams } from 'react-router-dom'; +import { FEATURE_FLAG_AI_TRANSLATION } from 'src/constants'; +import { useFeatureFlag } from 'src/hooks/useFeatureFlag'; +import { + GetVideosByVidTranslationApiResponse, + useGetVideosByVidQuery, + useGetVideosByVidTranslationQuery, +} from 'src/features/api'; +import { useEffect, useState } from 'react'; +import { usePreferredLanguage } from '../usePreferredLanguage'; +import { useToolsContext } from '../context/ToolsContext'; + +export const useTranslationTools = () => { + const { videoId } = useParams(); + const [data, setData] = useState<{ + hasQuickTranslate?: boolean; + preferredLanguage?: string; + translation?: GetVideosByVidTranslationApiResponse; + canQuickTranslate?: boolean; + }>({ + hasQuickTranslate: false, + canQuickTranslate: true, + }); + + const { hasFeatureFlag } = useFeatureFlag(); + const hasAIFeatureFlag = hasFeatureFlag(FEATURE_FLAG_AI_TRANSLATION); + const preferredLanguage = usePreferredLanguage(); + const { language } = useToolsContext(); + + const { + data: video, + isLoading: isLoadingVideo, + isError: isErrorVideo, + } = useGetVideosByVidQuery( + { + vid: videoId || '', + }, + { + skip: !videoId, + } + ); + + const { + data: translation, + isLoading: isLoadingTranslation, + isError: isErrorTranslation, + } = useGetVideosByVidTranslationQuery( + { + vid: videoId || '', + ...(language && { lang: language }), + }, + { + skip: !hasAIFeatureFlag || !videoId || !language, + } + ); + + useEffect(() => { + if (video) { + const hasQuickTranslate = + !!preferredLanguage && // Exists a preferred language + video.language.localeCompare(preferredLanguage) !== 0; // Video language is different from preferred language + + const isPrefTranslated = !!( + preferredLanguage && + translation?.language.localeCompare(preferredLanguage) === 0 + ); + + setData({ + hasQuickTranslate, + preferredLanguage, + canQuickTranslate: hasQuickTranslate && !isPrefTranslated, + translation, + }); + } + }, [video, translation, preferredLanguage]); + + return { + isError: !hasAIFeatureFlag || isErrorVideo || isErrorTranslation, + isProcessing: + isLoadingVideo || isLoadingTranslation || translation?.processing === 1, + data, + }; +}; diff --git a/src/pages/Video/components/tools/index.tsx b/src/pages/Video/components/tools/index.tsx index 10e39d59d..45eccd046 100644 --- a/src/pages/Video/components/tools/index.tsx +++ b/src/pages/Video/components/tools/index.tsx @@ -12,78 +12,40 @@ import { ReactComponent as SettingsIcon } from '@zendeskgarden/svg-icons/src/16/ import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; import { appTheme } from 'src/app/theme'; -import { FEATURE_FLAG_AI_TRANSLATION } from 'src/constants'; -import { - useGetVideosByVidQuery, - useGetVideosByVidTranslationQuery, - usePostVideosByVidTranslationMutation, -} from 'src/features/api'; -import { useFeatureFlag } from 'src/hooks/useFeatureFlag'; +import { usePostVideosByVidTranslationMutation } from 'src/features/api'; import { ToolsTranslate } from './ToolsTranslate'; import { useToolsContext } from './context/ToolsContext'; -import { usePreferredLanguage } from './usePreferredLanguage'; +import { useTranslationTools } from './hooks/useTranslationTools'; export const Tools = () => { const { t } = useTranslation(); const { videoId } = useParams(); - const { isOpen, setIsOpen, language, setLanguage } = useToolsContext(); - const { hasFeatureFlag } = useFeatureFlag(); - const hasAIFeatureFlag = hasFeatureFlag(FEATURE_FLAG_AI_TRANSLATION); - const { addToast } = useToast(); - const [requestTranslation, { isLoading: isLoadingRequestTranslation }] = - usePostVideosByVidTranslationMutation(); - - const preferredLanguage = usePreferredLanguage(); - - const { data: translation, isLoading: isLoadingTranslation } = - useGetVideosByVidTranslationQuery( - { - vid: videoId || '', - ...(language && { lang: language }), - }, - { - skip: !hasAIFeatureFlag || !language || !preferredLanguage, - } - ); + const { isError, isProcessing, data } = useTranslationTools(); + const { isOpen, setIsOpen, setLanguage } = useToolsContext(); + const [requestTranslation] = usePostVideosByVidTranslationMutation(); - const { data: video } = useGetVideosByVidQuery({ - vid: videoId || '', - }); + if (isError) return null; - if (!hasAIFeatureFlag || isLoadingTranslation) return null; - const canTranslate = - !!preferredLanguage && - video && - video.language.localeCompare(preferredLanguage) !== 0 && - (!translation || - translation.language.localeCompare(preferredLanguage) !== 0); - const isTranslating = - translation && - translation.language === preferredLanguage && - translation.processing === 1; + if (data.hasQuickTranslate && data.preferredLanguage) { + // 2 buttons + return ( +
+ - {isOpen && ( - - )} - {(preferredLanguage && - video?.language.localeCompare(preferredLanguage) !== 0) || - isTranslating ? ( + + {isOpen && ( + + )} { }} > { setIsOpen(!isOpen); @@ -146,7 +99,32 @@ export const Tools = () => { - ) : null} +
+ ); + } + + // 1 button + return ( +
+ + {isOpen && ( + + )}
); };