mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-30 00:53:14 +00:00
(feat:upload) i18n
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React, { useRef } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDarkTheme } from '../hooks';
|
||||
import { selectToken } from '../preferences/preferenceSlice';
|
||||
|
||||
@@ -24,6 +25,7 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
onDisconnect,
|
||||
errorMessage,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const token = useSelector(selectToken);
|
||||
const [isDarkTheme] = useDarkTheme();
|
||||
const completedRef = useRef(false);
|
||||
@@ -47,12 +49,16 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
cleanup();
|
||||
onSuccess({
|
||||
session_token: event.data.session_token,
|
||||
user_email: event.data.user_email || 'Connected User',
|
||||
user_email:
|
||||
event.data.user_email ||
|
||||
t('modals.uploadDoc.connectors.auth.connectedUser'),
|
||||
});
|
||||
} else if (errorProvider) {
|
||||
completedRef.current = true;
|
||||
cleanup();
|
||||
onError(event.data.error || 'Authentication failed');
|
||||
onError(
|
||||
event.data.error || t('modals.uploadDoc.connectors.auth.authFailed'),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,13 +77,15 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
|
||||
if (!authResponse.ok) {
|
||||
throw new Error(
|
||||
`Failed to get authorization URL: ${authResponse.status}`,
|
||||
`${t('modals.uploadDoc.connectors.auth.authUrlFailed')}: ${authResponse.status}`,
|
||||
);
|
||||
}
|
||||
|
||||
const authData = await authResponse.json();
|
||||
if (!authData.success || !authData.authorization_url) {
|
||||
throw new Error(authData.error || 'Failed to get authorization URL');
|
||||
throw new Error(
|
||||
authData.error || t('modals.uploadDoc.connectors.auth.authUrlFailed'),
|
||||
);
|
||||
}
|
||||
|
||||
const authWindow = window.open(
|
||||
@@ -86,9 +94,7 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
'width=500,height=600,scrollbars=yes,resizable=yes',
|
||||
);
|
||||
if (!authWindow) {
|
||||
throw new Error(
|
||||
'Failed to open authentication window. Please allow popups.',
|
||||
);
|
||||
throw new Error(t('modals.uploadDoc.connectors.auth.popupBlocked'));
|
||||
}
|
||||
|
||||
window.addEventListener('message', handleAuthMessage as any);
|
||||
@@ -98,13 +104,17 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
clearInterval(checkClosed);
|
||||
window.removeEventListener('message', handleAuthMessage as any);
|
||||
if (!completedRef.current) {
|
||||
onError('Authentication was cancelled');
|
||||
onError(t('modals.uploadDoc.connectors.auth.authCancelled'));
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
intervalRef.current = checkClosed;
|
||||
} catch (error) {
|
||||
onError(error instanceof Error ? error.message : 'Authentication failed');
|
||||
onError(
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: t('modals.uploadDoc.connectors.auth.authFailed'),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -147,14 +157,18 @@ const ConnectorAuth: React.FC<ConnectorAuthProps> = ({
|
||||
d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"
|
||||
/>
|
||||
</svg>
|
||||
<span>Connected as {userEmail}</span>
|
||||
<span>
|
||||
{t('modals.uploadDoc.connectors.auth.connectedAs', {
|
||||
email: userEmail,
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
{onDisconnect && (
|
||||
<button
|
||||
onClick={onDisconnect}
|
||||
className="text-xs font-medium text-[#212121] underline hover:text-gray-700"
|
||||
>
|
||||
Disconnect
|
||||
{t('modals.uploadDoc.connectors.auth.disconnect')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useDrivePicker from 'react-google-drive-picker';
|
||||
|
||||
import ConnectorAuth from './ConnectorAuth';
|
||||
@@ -26,6 +27,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
token,
|
||||
onSelectionChange,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedFiles, setSelectedFiles] = useState<PickerFile[]>([]);
|
||||
const [selectedFolders, setSelectedFolders] = useState<PickerFile[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -66,14 +68,19 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
|
||||
if (!validateResponse.ok) {
|
||||
setIsConnected(false);
|
||||
setAuthError('Session expired. Please reconnect to Google Drive.');
|
||||
setAuthError(
|
||||
t('modals.uploadDoc.connectors.googleDrive.sessionExpired'),
|
||||
);
|
||||
setIsValidating(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const validateData = await validateResponse.json();
|
||||
if (validateData.success) {
|
||||
setUserEmail(validateData.user_email || 'Connected User');
|
||||
setUserEmail(
|
||||
validateData.user_email ||
|
||||
t('modals.uploadDoc.connectors.auth.connectedUser'),
|
||||
);
|
||||
setIsConnected(true);
|
||||
setAuthError('');
|
||||
setAccessToken(validateData.access_token || null);
|
||||
@@ -83,14 +90,14 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
setIsConnected(false);
|
||||
setAuthError(
|
||||
validateData.error ||
|
||||
'Session expired. Please reconnect your account.',
|
||||
t('modals.uploadDoc.connectors.googleDrive.sessionExpiredGeneric'),
|
||||
);
|
||||
setIsValidating(false);
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error validating session:', error);
|
||||
setAuthError('Failed to validate session. Please reconnect.');
|
||||
setAuthError(t('modals.uploadDoc.connectors.googleDrive.validateFailed'));
|
||||
setIsConnected(false);
|
||||
setIsValidating(false);
|
||||
return false;
|
||||
@@ -103,15 +110,13 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
const sessionToken = getSessionToken('google_drive');
|
||||
|
||||
if (!sessionToken) {
|
||||
setAuthError('No valid session found. Please reconnect to Google Drive.');
|
||||
setAuthError(t('modals.uploadDoc.connectors.googleDrive.noSession'));
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
setAuthError(
|
||||
'No access token available. Please reconnect to Google Drive.',
|
||||
);
|
||||
setAuthError(t('modals.uploadDoc.connectors.googleDrive.noAccessToken'));
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
@@ -193,7 +198,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error opening picker:', error);
|
||||
setAuthError('Failed to open file picker. Please try again.');
|
||||
setAuthError(t('modals.uploadDoc.connectors.googleDrive.pickerFailed'));
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
@@ -264,9 +269,12 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
<>
|
||||
<ConnectorAuth
|
||||
provider="google_drive"
|
||||
label="Connect to Google Drive"
|
||||
label={t('modals.uploadDoc.connectors.googleDrive.connect')}
|
||||
onSuccess={(data) => {
|
||||
setUserEmail(data.user_email || 'Connected User');
|
||||
setUserEmail(
|
||||
data.user_email ||
|
||||
t('modals.uploadDoc.connectors.auth.connectedUser'),
|
||||
);
|
||||
setIsConnected(true);
|
||||
setAuthError('');
|
||||
|
||||
@@ -289,26 +297,34 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
<div className="rounded-lg border border-[#EEE6FF78] dark:border-[#6A6A6A]">
|
||||
<div className="p-4">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<h3 className="text-sm font-medium">Selected Files</h3>
|
||||
<h3 className="text-sm font-medium">
|
||||
{t('modals.uploadDoc.connectors.googleDrive.selectedFiles')}
|
||||
</h3>
|
||||
<button
|
||||
onClick={() => handleOpenPicker()}
|
||||
className="rounded-md bg-[#A076F6] px-3 py-1 text-sm text-white hover:bg-[#8A5FD4]"
|
||||
disabled={isLoading}
|
||||
>
|
||||
{isLoading ? 'Loading...' : 'Select Files'}
|
||||
{isLoading
|
||||
? t('modals.uploadDoc.connectors.googleDrive.loading')
|
||||
: t(
|
||||
'modals.uploadDoc.connectors.googleDrive.selectFiles',
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{selectedFiles.length === 0 && selectedFolders.length === 0 ? (
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
No files or folders selected
|
||||
{t(
|
||||
'modals.uploadDoc.connectors.googleDrive.noFilesSelected',
|
||||
)}
|
||||
</p>
|
||||
) : (
|
||||
<div className="max-h-60 overflow-y-auto">
|
||||
{selectedFolders.length > 0 && (
|
||||
<div className="mb-2">
|
||||
<h4 className="mb-1 text-xs font-medium text-gray-500">
|
||||
Folders
|
||||
{t('modals.uploadDoc.connectors.googleDrive.folders')}
|
||||
</h4>
|
||||
{selectedFolders.map((folder) => (
|
||||
<div
|
||||
@@ -317,7 +333,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
>
|
||||
<img
|
||||
src={folder.iconUrl}
|
||||
alt="Folder"
|
||||
alt={t(
|
||||
'modals.uploadDoc.connectors.googleDrive.folderAlt',
|
||||
)}
|
||||
className="mr-2 h-5 w-5"
|
||||
/>
|
||||
<span className="flex-1 truncate text-sm">
|
||||
@@ -337,7 +355,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
}}
|
||||
className="ml-2 text-sm text-red-500 hover:text-red-700"
|
||||
>
|
||||
Remove
|
||||
{t(
|
||||
'modals.uploadDoc.connectors.googleDrive.remove',
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
@@ -347,7 +367,7 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
{selectedFiles.length > 0 && (
|
||||
<div>
|
||||
<h4 className="mb-1 text-xs font-medium text-gray-500">
|
||||
Files
|
||||
{t('modals.uploadDoc.connectors.googleDrive.files')}
|
||||
</h4>
|
||||
{selectedFiles.map((file) => (
|
||||
<div
|
||||
@@ -356,7 +376,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
>
|
||||
<img
|
||||
src={file.iconUrl}
|
||||
alt="File"
|
||||
alt={t(
|
||||
'modals.uploadDoc.connectors.googleDrive.fileAlt',
|
||||
)}
|
||||
className="mr-2 h-5 w-5"
|
||||
/>
|
||||
<span className="flex-1 truncate text-sm">
|
||||
@@ -375,7 +397,9 @@ const GoogleDrivePicker: React.FC<GoogleDrivePickerProps> = ({
|
||||
}}
|
||||
className="ml-2 text-sm text-red-500 hover:text-red-700"
|
||||
>
|
||||
Remove
|
||||
{t(
|
||||
'modals.uploadDoc.connectors.googleDrive.remove',
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function UploadToast() {
|
||||
case 'failed':
|
||||
return t('attachments.uploadFailed');
|
||||
default:
|
||||
return 'Preparing upload';
|
||||
return t('modals.uploadDoc.progress.preparing');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -91,8 +91,8 @@ export default function UploadToast() {
|
||||
onClick={() => toggleTaskCollapse(task.id)}
|
||||
aria-label={
|
||||
isCollapsed
|
||||
? 'Expand upload details'
|
||||
: 'Collapse upload details'
|
||||
? t('modals.uploadDoc.progress.expandDetails')
|
||||
: t('modals.uploadDoc.progress.collapseDetails')
|
||||
}
|
||||
className="flex h-8 items-center justify-center p-0 text-black opacity-70 transition-opacity hover:opacity-100 dark:text-white"
|
||||
>
|
||||
@@ -108,7 +108,7 @@ export default function UploadToast() {
|
||||
type="button"
|
||||
onClick={() => dispatch(dismissUploadTask(task.id))}
|
||||
className="flex h-8 items-center justify-center p-0 text-black opacity-70 transition-opacity hover:opacity-100 dark:text-white"
|
||||
aria-label="Dismiss upload toast"
|
||||
aria-label={t('modals.uploadDoc.progress.dismiss')}
|
||||
>
|
||||
<svg
|
||||
width="16"
|
||||
@@ -165,7 +165,12 @@ export default function UploadToast() {
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={formattedProgress}
|
||||
aria-label={`Upload progress ${formattedProgress}%`}
|
||||
aria-label={t(
|
||||
'modals.uploadDoc.progress.uploadProgress',
|
||||
{
|
||||
progress: formattedProgress,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<circle
|
||||
className="text-gray-300 dark:text-gray-700"
|
||||
@@ -231,7 +236,7 @@ export default function UploadToast() {
|
||||
onClick={() => dispatch(clearCompletedTasks())}
|
||||
className="mt-1 mr-1 text-right text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
||||
>
|
||||
Clear
|
||||
{t('modals.uploadDoc.progress.clear')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user