Browse Source

feat: complete IntegrationsContent translation for all languages #69

- Added comprehensive translation keys for integrations in en.json, hu.json, and de.json
- Translated all UI text in IntegrationsContent component including:
  - Page headers and descriptions
  - Platform selection dialog
  - Statistics cards (Connected Shops, With Phone Numbers, Active Stores, Platforms)
  - Connected webshops list (store cards, sync status, phone numbers)
  - Data access badges and auto-sync toggles
  - Action buttons (Sync, AI Config, Phone, Access, Disconnect Store)
  - Quick Setup Wizard (4 steps)
  - Data Access Permissions dialog
  - OAuth callback messages (WooCommerce, Shopify)
  - All toast notifications and error messages
- Updated helper functions (getSyncStatusBadge, getSyncStats, getDataAccessBadges)
- Translated sync completion messages with dynamic item counts
- All user-facing text now supports English, Hungarian, and German

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude 5 months ago
parent
commit
15ae639638

+ 92 - 108
shopcall.ai-main/src/components/IntegrationsContent.tsx

@@ -95,26 +95,26 @@ export function IntegrationsContent() {
               // Show completion notification
               if (store.sync_status === 'completed') {
                 const stats = store.alt_data?.last_sync_stats;
-                let description = `${store.store_name || 'Store'} data synchronized successfully.`;
+                let description = t('integrations.syncCompleteDescription', { storeName: store.store_name || 'Store' });
 
                 if (stats) {
                   const items = [];
-                  if (stats.products?.synced) items.push(`${stats.products.synced} products`);
-                  if (stats.orders?.synced) items.push(`${stats.orders.synced} orders`);
-                  if (stats.customers?.synced) items.push(`${stats.customers.synced} customers`);
+                  if (stats.products?.synced) items.push(`${stats.products.synced} ${t('integrations.products').toLowerCase()}`);
+                  if (stats.orders?.synced) items.push(`${stats.orders.synced} ${t('integrations.orders').toLowerCase()}`);
+                  if (stats.customers?.synced) items.push(`${stats.customers.synced} ${t('integrations.customers').toLowerCase()}`);
                   if (items.length > 0) {
-                    description = `Synced: ${items.join(', ')}`;
+                    description = t('integrations.syncedItems', { items: items.join(', ') });
                   }
                 }
 
                 toast({
-                  title: "Sync Complete",
+                  title: t('integrations.syncComplete'),
                   description,
                 });
               } else if (store.sync_status === 'error') {
                 toast({
-                  title: "Sync Failed",
-                  description: store.sync_error || "An error occurred during synchronization.",
+                  title: t('integrations.syncFailed'),
+                  description: store.sync_error || t('integrations.syncFailedDescription'),
                   variant: "destructive",
                 });
               }
@@ -138,10 +138,10 @@ export function IntegrationsContent() {
     if (params.get('wc_connected') === 'true') {
       const storeName = params.get('store');
       toast({
-        title: "WooCommerce Connected!",
+        title: t('integrations.oauth.woocommerceConnected'),
         description: storeName
-          ? `Successfully connected ${decodeURIComponent(storeName)}`
-          : "Your WooCommerce store has been connected successfully.",
+          ? t('integrations.oauth.woocommerceConnectedDescription', { storeName: decodeURIComponent(storeName) })
+          : t('integrations.oauth.woocommerceConnectedDefault'),
       });
       // Clean up URL
       window.history.replaceState({}, '', '/webshops');
@@ -153,10 +153,10 @@ export function IntegrationsContent() {
     if (params.get('shopify_connected') === 'true') {
       const storeName = params.get('store');
       toast({
-        title: "Shopify Connected!",
+        title: t('integrations.oauth.shopifyConnected'),
         description: storeName
-          ? `Successfully connected ${decodeURIComponent(storeName)}`
-          : "Your Shopify store has been connected successfully.",
+          ? t('integrations.oauth.shopifyConnectedDescription', { storeName: decodeURIComponent(storeName) })
+          : t('integrations.oauth.shopifyConnectedDefault'),
       });
       // Clean up URL
       window.history.replaceState({}, '', '/webshops');
@@ -167,25 +167,9 @@ export function IntegrationsContent() {
     // Handle errors
     const error = params.get('error');
     if (error) {
-      const errorMessages: Record<string, string> = {
-        'woocommerce_oauth_rejected': 'WooCommerce connection was cancelled. Please try again.',
-        'woocommerce_oauth_failed': 'Failed to connect to WooCommerce. Please try again.',
-        'woocommerce_connection_failed': 'Could not connect to your WooCommerce store. Please check your store URL and try again.',
-        'shopify_oauth_failed': 'Failed to connect to Shopify. Please try again.',
-        'shopify_hmac_invalid': 'Security verification failed. Please try again.',
-        'shopify_invalid_state': 'Invalid session. Please try connecting again.',
-        'shopify_state_expired': 'Connection session expired. Please try again.',
-        'shopify_token_exchange_failed': 'Failed to complete Shopify authorization. Please try again.',
-        'shopify_connection_failed': 'Could not connect to your Shopify store. Please check your domain and try again.',
-        'invalid_shop_domain': 'Invalid Shopify domain. Please check the domain and try again.',
-        'invalid_store_url': 'Invalid store URL. Please check the URL and try again.',
-        'failed_to_save': 'Failed to save store connection. Please try again.',
-        'internal_error': 'An internal error occurred. Please try again later.',
-      };
-
       toast({
-        title: "Connection Failed",
-        description: errorMessages[error] || "An unexpected error occurred. Please try again.",
+        title: t('integrations.oauth.connectionFailed'),
+        description: t(`integrations.oauth.errors.${error}`, { defaultValue: t('integrations.oauth.errors.default') }),
         variant: "destructive",
       });
       // Clean up URL
@@ -211,22 +195,22 @@ export function IntegrationsContent() {
   const platforms = [
     {
       id: "shopify",
-      name: "Shopify",
-      description: "Connect your Shopify store",
+      name: t('integrations.dialog.shopify'),
+      description: t('integrations.dialog.shopifyDescription'),
       icon: Store,
       color: "text-green-500"
     },
     {
       id: "woocommerce",
-      name: "WooCommerce",
-      description: "Connect your WooCommerce store",
+      name: t('integrations.dialog.woocommerce'),
+      description: t('integrations.dialog.woocommerceDescription'),
       icon: ShoppingBag,
       color: "text-purple-500"
     },
     {
       id: "shoprenter",
-      name: "ShopRenter",
-      description: "Connect your ShopRenter store",
+      name: t('integrations.dialog.shoprenter'),
+      description: t('integrations.dialog.shoprenterDescription'),
       icon: Store,
       color: "text-blue-500"
     }
@@ -242,7 +226,7 @@ export function IntegrationsContent() {
   };
 
   const handleDisconnectStore = async (storeId: string, storeName: string) => {
-    if (!confirm(`Are you sure you want to disconnect ${storeName}? This action cannot be undone.`)) {
+    if (!confirm(t('integrations.disconnectConfirm', { storeName }))) {
       return;
     }
 
@@ -270,17 +254,17 @@ export function IntegrationsContent() {
       }
 
       toast({
-        title: "Store Disconnected",
-        description: `${storeName} has been disconnected successfully.`,
+        title: t('integrations.storeDisconnected'),
+        description: t('integrations.storeDisconnectedDescription', { storeName }),
       });
 
       // Refresh stores list
       fetchStores();
     } catch (error) {
       console.error('Error disconnecting store:', error);
-      const errorMessage = error instanceof Error ? error.message : 'Failed to disconnect the store. Please try again.';
+      const errorMessage = error instanceof Error ? error.message : t('integrations.disconnectionFailedDescription');
       toast({
-        title: "Disconnection Failed",
+        title: t('integrations.disconnectionFailed'),
         description: errorMessage,
         variant: "destructive",
       });
@@ -308,8 +292,8 @@ export function IntegrationsContent() {
       if (!response.ok) {
         if (response.status === 409) {
           toast({
-            title: "Sync Already Running",
-            description: "A sync is already in progress for this store.",
+            title: t('integrations.syncAlreadyRunning'),
+            description: t('integrations.syncAlreadyRunningDescription'),
             variant: "default",
           });
           return;
@@ -321,8 +305,8 @@ export function IntegrationsContent() {
       setSyncingStores(prev => new Set(prev).add(storeId));
 
       toast({
-        title: "Sync Started",
-        description: `Data synchronization started for ${storeName}`,
+        title: t('integrations.syncStarted'),
+        description: t('integrations.syncStartedDescription', { storeName }),
       });
 
       // Refresh stores list immediately to show syncing status
@@ -330,8 +314,8 @@ export function IntegrationsContent() {
     } catch (error) {
       console.error('Error triggering sync:', error);
       toast({
-        title: "Sync Failed",
-        description: "Failed to start data synchronization. Please try again.",
+        title: t('integrations.syncFailed'),
+        description: t('integrations.syncFailedDescription'),
         variant: "destructive",
       });
     }
@@ -363,10 +347,10 @@ export function IntegrationsContent() {
       }
 
       toast({
-        title: newEnabled ? "Shop Enabled" : "Shop Disabled",
+        title: newEnabled ? t('integrations.shopEnabled') : t('integrations.shopDisabled'),
         description: newEnabled
-          ? `${storeName} is now enabled. Background sync will resume.`
-          : `${storeName} is now disabled. Background sync is paused (manual sync still available).`,
+          ? t('integrations.shopEnabledDescription', { storeName })
+          : t('integrations.shopDisabledDescription', { storeName }),
       });
 
       // Refresh stores list
@@ -374,8 +358,8 @@ export function IntegrationsContent() {
     } catch (error) {
       console.error('Error toggling store enabled status:', error);
       toast({
-        title: "Update Failed",
-        description: "Failed to update shop status. Please try again.",
+        title: t('integrations.updateFailed'),
+        description: t('integrations.updateFailedDescription'),
         variant: "destructive",
       });
     }
@@ -389,15 +373,15 @@ export function IntegrationsContent() {
         return (
           <Badge className="bg-blue-500 text-white animate-pulse">
             <Loader2 className="w-3 h-3 mr-1 animate-spin" />
-            Syncing
+            {t('integrations.syncing')}
           </Badge>
         );
       case 'completed':
-        return <Badge className="bg-green-500 text-white">Synced</Badge>;
+        return <Badge className="bg-green-500 text-white">{t('integrations.synced')}</Badge>;
       case 'error':
-        return <Badge className="bg-red-500 text-white">Error</Badge>;
+        return <Badge className="bg-red-500 text-white">{t('integrations.error')}</Badge>;
       default:
-        return <Badge className="bg-gray-500 text-white">Not Synced</Badge>;
+        return <Badge className="bg-gray-500 text-white">{t('integrations.notSynced')}</Badge>;
     }
   };
 
@@ -407,13 +391,13 @@ export function IntegrationsContent() {
 
     const items = [];
     if (stats.products?.synced !== undefined) {
-      items.push({ label: 'Products', count: stats.products.synced, errors: stats.products.errors || 0 });
+      items.push({ label: t('integrations.products'), count: stats.products.synced, errors: stats.products.errors || 0 });
     }
     if (stats.orders?.synced !== undefined) {
-      items.push({ label: 'Orders', count: stats.orders.synced, errors: stats.orders.errors || 0 });
+      items.push({ label: t('integrations.orders'), count: stats.orders.synced, errors: stats.orders.errors || 0 });
     }
     if (stats.customers?.synced !== undefined) {
-      items.push({ label: 'Customers', count: stats.customers.synced, errors: stats.customers.errors || 0 });
+      items.push({ label: t('integrations.customers'), count: stats.customers.synced, errors: stats.customers.errors || 0 });
     }
 
     if (items.length === 0) return null;
@@ -444,22 +428,22 @@ export function IntegrationsContent() {
       <div className="flex flex-wrap gap-1">
         {permissions.allow_product_access && (
           <Badge variant="outline" className="text-xs border-blue-500 text-blue-400">
-            Products
+            {t('integrations.products')}
           </Badge>
         )}
         {permissions.allow_customer_access && (
           <Badge variant="outline" className="text-xs border-green-500 text-green-400">
-            Customers
+            {t('integrations.customers')}
           </Badge>
         )}
         {permissions.allow_order_access && (
           <Badge variant="outline" className="text-xs border-purple-500 text-purple-400">
-            Orders
+            {t('integrations.orders')}
           </Badge>
         )}
         {!permissions.allow_customer_access && !permissions.allow_order_access && (
           <Badge variant="outline" className="text-xs border-orange-500 text-orange-400">
-            Limited Access
+            {t('integrations.limitedAccess')}
           </Badge>
         )}
       </div>
@@ -489,15 +473,15 @@ export function IntegrationsContent() {
     <div className="flex-1 space-y-6 p-8 bg-slate-900">
       <div className="flex items-center justify-between">
         <div>
-          <h2 className="text-3xl font-bold tracking-tight text-white">Webshops</h2>
-          <p className="text-slate-400">Manage your connected stores and their AI configurations</p>
+          <h2 className="text-3xl font-bold tracking-tight text-white">{t('integrations.title')}</h2>
+          <p className="text-slate-400">{t('integrations.subtitle')}</p>
         </div>
         <Button
           className="bg-cyan-500 hover:bg-cyan-600 text-white"
           onClick={() => setShowConnectDialog(true)}
         >
           <Plus className="w-4 h-4 mr-2" />
-          Connect Webshop
+          {t('integrations.connectWebshop')}
         </Button>
       </div>
 
@@ -507,9 +491,9 @@ export function IntegrationsContent() {
           {!selectedPlatform ? (
             <>
               <DialogHeader>
-                <DialogTitle className="text-white text-2xl">Connect Your E-commerce Platform</DialogTitle>
+                <DialogTitle className="text-white text-2xl">{t('integrations.dialog.title')}</DialogTitle>
                 <DialogDescription className="text-slate-400">
-                  Choose your e-commerce platform to get started with AI-powered customer calls
+                  {t('integrations.dialog.description')}
                 </DialogDescription>
               </DialogHeader>
               <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
@@ -528,7 +512,7 @@ export function IntegrationsContent() {
                           <p className="text-slate-400 text-sm mt-1">{platform.description}</p>
                         </div>
                         <Button className="w-full bg-cyan-500 hover:bg-cyan-600 text-white">
-                          Connect
+                          {t('integrations.dialog.connect')}
                         </Button>
                       </CardContent>
                     </Card>
@@ -545,13 +529,13 @@ export function IntegrationsContent() {
           ) : (
             <div className="text-center py-8">
               <p className="text-white">
-                {platforms.find(p => p.id === selectedPlatform)?.name} integration coming soon!
+                {t('integrations.dialog.comingSoon', { platform: platforms.find(p => p.id === selectedPlatform)?.name })}
               </p>
               <Button
                 onClick={handleCloseDialog}
                 className="mt-4 bg-cyan-500 hover:bg-cyan-600 text-white"
               >
-                Close
+                {t('integrations.dialog.close')}
               </Button>
             </div>
           )}
@@ -579,7 +563,7 @@ export function IntegrationsContent() {
                   <Store className="w-8 h-8 text-cyan-500" />
                   <div>
                     <p className="text-2xl font-bold text-white">{connectedShops.length}</p>
-                    <p className="text-slate-400">Connected Shops</p>
+                    <p className="text-slate-400">{t('integrations.connectedShops')}</p>
                   </div>
                 </div>
               </CardContent>
@@ -591,7 +575,7 @@ export function IntegrationsContent() {
                   <PhoneCall className="w-8 h-8 text-green-500" />
                   <div>
                     <p className="text-2xl font-bold text-white">{connectedShops.filter(s => s.phone_number).length}</p>
-                    <p className="text-slate-400">With Phone Numbers</p>
+                    <p className="text-slate-400">{t('integrations.withPhoneNumbers')}</p>
                   </div>
                 </div>
               </CardContent>
@@ -603,7 +587,7 @@ export function IntegrationsContent() {
                   <Store className="w-8 h-8 text-purple-500" />
                   <div>
                     <p className="text-2xl font-bold text-white">{connectedShops.filter(s => s.is_active).length}</p>
-                    <p className="text-slate-400">Active Stores</p>
+                    <p className="text-slate-400">{t('integrations.activeStores')}</p>
                   </div>
                 </div>
               </CardContent>
@@ -615,7 +599,7 @@ export function IntegrationsContent() {
                   <Globe className="w-8 h-8 text-blue-500" />
                   <div>
                     <p className="text-2xl font-bold text-white">{new Set(connectedShops.map(s => s.platform_name)).size}</p>
-                    <p className="text-slate-400">Platforms</p>
+                    <p className="text-slate-400">{t('integrations.platforms')}</p>
                   </div>
                 </div>
               </CardContent>
@@ -626,8 +610,8 @@ export function IntegrationsContent() {
         <div>
           <div className="flex items-center justify-between mb-4">
             <div>
-              <h3 className="text-xl font-semibold text-white">Connected Webshops</h3>
-              <p className="text-slate-400 text-sm">Manage your connected stores</p>
+              <h3 className="text-xl font-semibold text-white">{t('integrations.connectedWebshops')}</h3>
+              <p className="text-slate-400 text-sm">{t('integrations.manageStores')}</p>
             </div>
           </div>
 
@@ -648,16 +632,16 @@ export function IntegrationsContent() {
               <CardContent className="p-12">
                 <div className="text-center">
                   <Store className="w-16 h-16 text-slate-600 mx-auto mb-4" />
-                  <h3 className="text-lg font-semibold text-white mb-2">No Stores Connected</h3>
+                  <h3 className="text-lg font-semibold text-white mb-2">{t('integrations.noStoresConnected')}</h3>
                   <p className="text-slate-400 mb-6">
-                    Connect your first e-commerce store to get started with AI-powered customer calls
+                    {t('integrations.noStoresDescription')}
                   </p>
                   <Button
                     className="bg-cyan-500 hover:bg-cyan-600 text-white"
                     onClick={() => setShowConnectDialog(true)}
                   >
                     <Plus className="w-4 h-4 mr-2" />
-                    Connect Your First Store
+                    {t('integrations.connectFirstStore')}
                   </Button>
                 </div>
               </CardContent>
@@ -676,12 +660,12 @@ export function IntegrationsContent() {
                             shop.platform_name === 'shoprenter' ? 'text-blue-500' :
                             'text-green-500'
                           }`} />
-                          <h4 className="text-white font-semibold truncate">{shop.store_name || 'Unnamed Store'}</h4>
+                          <h4 className="text-white font-semibold truncate">{shop.store_name || t('integrations.unnamedStore')}</h4>
                         </div>
                         <p className="text-xs text-slate-500 truncate">{shop.store_url || '-'}</p>
                       </div>
                       <Badge className={`${shop.is_active ? "bg-green-500" : "bg-red-500"} text-white text-xs flex-shrink-0 ml-2`}>
-                        {shop.is_active ? "Active" : "Inactive"}
+                        {shop.is_active ? t('integrations.active') : t('integrations.inactive')}
                       </Badge>
                     </div>
 
@@ -710,22 +694,22 @@ export function IntegrationsContent() {
                     <div className="bg-slate-700/50 rounded-lg p-3 mb-3">
                       <div className="flex items-center gap-2 mb-1">
                         <PhoneCall className="w-3 h-3 text-slate-400" />
-                        <span className="text-xs text-slate-400">Phone Number</span>
+                        <span className="text-xs text-slate-400">{t('integrations.phoneNumber')}</span>
                       </div>
                       <div className={`text-sm ${shop.phone_number ? "text-white font-mono" : "text-slate-500 italic"}`}>
-                        {shop.phone_number || "Not assigned"}
+                        {shop.phone_number || t('integrations.notAssigned')}
                       </div>
                     </div>
 
                     {/* Sync Status Section */}
                     <div className="bg-slate-700/50 rounded-lg p-3 mb-3">
                       <div className="flex items-center justify-between mb-2">
-                        <span className="text-xs text-slate-400">Sync Status</span>
+                        <span className="text-xs text-slate-400">{t('integrations.syncStatus')}</span>
                         {getSyncStatusBadge(shop)}
                       </div>
                       {shop.sync_completed_at && shop.sync_status === 'completed' && (
                         <div className="text-xs text-slate-500">
-                          Last: {new Date(shop.sync_completed_at).toLocaleString()}
+                          {t('integrations.lastSync')}: {new Date(shop.sync_completed_at).toLocaleString()}
                         </div>
                       )}
                       {shop.sync_error && (
@@ -739,11 +723,11 @@ export function IntegrationsContent() {
                     {/* Data Access & Background Sync */}
                     <div className="flex items-center justify-between mb-4 pb-3 border-b border-slate-700">
                       <div>
-                        <div className="text-xs text-slate-400 mb-1">Data Access</div>
+                        <div className="text-xs text-slate-400 mb-1">{t('integrations.dataAccess')}</div>
                         {getDataAccessBadges(shop)}
                       </div>
                       <div className="text-right">
-                        <div className="text-xs text-slate-400 mb-1">Auto Sync</div>
+                        <div className="text-xs text-slate-400 mb-1">{t('integrations.autoSync')}</div>
                         <Switch
                           checked={shop.store_sync_config?.[0]?.enabled ?? true}
                           onCheckedChange={() => handleToggleStoreEnabled(
@@ -772,7 +756,7 @@ export function IntegrationsContent() {
                         ) : (
                           <Zap className="w-3 h-3 mr-1" />
                         )}
-                        Sync
+                        {t('integrations.sync')}
                       </Button>
                       <Button
                         size="sm"
@@ -780,7 +764,7 @@ export function IntegrationsContent() {
                         onClick={() => window.location.href = `/ai-config?shop=${shop.id}`}
                       >
                         <Bot className="w-3 h-3 mr-1" />
-                        AI Config
+                        {t('integrations.aiConfig')}
                       </Button>
                       <Button
                         size="sm"
@@ -789,7 +773,7 @@ export function IntegrationsContent() {
                         onClick={() => window.location.href = `/phone-numbers?shop=${shop.id}`}
                       >
                         <PhoneCall className="w-3 h-3 mr-1" />
-                        Phone
+                        {t('integrations.phone')}
                       </Button>
                       <Button
                         size="sm"
@@ -798,7 +782,7 @@ export function IntegrationsContent() {
                         onClick={() => handleOpenPermissions(shop)}
                       >
                         <Shield className="w-3 h-3 mr-1" />
-                        Access
+                        {t('integrations.access')}
                       </Button>
                     </div>
 
@@ -810,7 +794,7 @@ export function IntegrationsContent() {
                       onClick={() => handleDisconnectStore(shop.id, shop.store_name || 'this store')}
                     >
                       <Trash2 className="w-3 h-3 mr-1" />
-                      Disconnect Store
+                      {t('integrations.disconnectStore')}
                     </Button>
                   </CardContent>
                 </Card>
@@ -823,38 +807,38 @@ export function IntegrationsContent() {
           <CardHeader>
             <div className="flex items-center gap-3">
               <Zap className="w-6 h-6 text-cyan-500" />
-              <CardTitle className="text-white">Quick Setup Wizard</CardTitle>
+              <CardTitle className="text-white">{t('integrations.quickSetup.title')}</CardTitle>
             </div>
-            <p className="text-slate-400">Set up AI and phone numbers for new webshops in minutes</p>
+            <p className="text-slate-400">{t('integrations.quickSetup.subtitle')}</p>
           </CardHeader>
           <CardContent className="space-y-4">
             <div className="space-y-4">
               <div className="flex gap-4">
                 <div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">1</div>
                 <div>
-                  <h4 className="text-white font-medium">Connect your webshop</h4>
-                  <p className="text-slate-400">Link your Shopify, WooCommerce, or other e-commerce platform</p>
+                  <h4 className="text-white font-medium">{t('integrations.quickSetup.step1.title')}</h4>
+                  <p className="text-slate-400">{t('integrations.quickSetup.step1.description')}</p>
                 </div>
               </div>
               <div className="flex gap-4">
                 <div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">2</div>
                 <div>
-                  <h4 className="text-white font-medium">Get a phone number</h4>
-                  <p className="text-slate-400">We'll automatically assign a free local number or upgrade to premium</p>
+                  <h4 className="text-white font-medium">{t('integrations.quickSetup.step2.title')}</h4>
+                  <p className="text-slate-400">{t('integrations.quickSetup.step2.description')}</p>
                 </div>
               </div>
               <div className="flex gap-4">
                 <div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">3</div>
                 <div>
-                  <h4 className="text-white font-medium">Configure your AI assistant</h4>
-                  <p className="text-slate-400">Customize voice, language, and behavior for your region and brand</p>
+                  <h4 className="text-white font-medium">{t('integrations.quickSetup.step3.title')}</h4>
+                  <p className="text-slate-400">{t('integrations.quickSetup.step3.description')}</p>
                 </div>
               </div>
               <div className="flex gap-4">
                 <div className="flex-shrink-0 w-8 h-8 bg-cyan-500 text-white rounded-full flex items-center justify-center font-semibold">4</div>
                 <div>
-                  <h4 className="text-white font-medium">Start receiving calls</h4>
-                  <p className="text-slate-400">Your AI will handle customer inquiries with store-specific knowledge</p>
+                  <h4 className="text-white font-medium">{t('integrations.quickSetup.step4.title')}</h4>
+                  <p className="text-slate-400">{t('integrations.quickSetup.step4.description')}</p>
                 </div>
               </div>
             </div>
@@ -868,10 +852,10 @@ export function IntegrationsContent() {
           <DialogHeader>
             <DialogTitle className="text-white text-2xl flex items-center gap-2">
               <Shield className="w-6 h-6 text-cyan-500" />
-              Data Access Permissions
+              {t('integrations.dataAccessDialog.title')}
             </DialogTitle>
             <DialogDescription className="text-slate-400">
-              {selectedStore && `Configure data access permissions for ${selectedStore.store_name || 'this store'}`}
+              {selectedStore && t('integrations.dataAccessDialog.description', { storeName: selectedStore.store_name || 'this store' })}
             </DialogDescription>
           </DialogHeader>
           {selectedStore && (
@@ -892,7 +876,7 @@ export function IntegrationsContent() {
               onClick={handleClosePermissions}
               className="text-slate-400 border-slate-600 hover:bg-slate-700"
             >
-              Close
+              {t('integrations.dialog.close')}
             </Button>
           </div>
         </DialogContent>

+ 118 - 0
shopcall.ai-main/src/i18n/locales/de.json

@@ -500,5 +500,123 @@
   "contact": {
     "title": "Kontakt",
     "subtitle": "Nehmen Sie Kontakt mit unserem Team auf"
+  },
+  "integrations": {
+    "title": "Webshops",
+    "subtitle": "Verwalten Sie Ihre verbundenen Shops und deren AI-Konfigurationen",
+    "connectWebshop": "Webshop Verbinden",
+    "connectedShops": "Verbundene Shops",
+    "withPhoneNumbers": "Mit Telefonnummern",
+    "activeStores": "Aktive Shops",
+    "platforms": "Plattformen",
+    "connectedWebshops": "Verbundene Webshops",
+    "manageStores": "Verwalten Sie Ihre verbundenen Shops",
+    "noStoresConnected": "Keine Shops Verbunden",
+    "noStoresDescription": "Verbinden Sie Ihren ersten E-Commerce-Shop, um mit AI-gestützten Kundenanrufen zu beginnen",
+    "connectFirstStore": "Ersten Shop Verbinden",
+    "active": "Aktiv",
+    "inactive": "Inaktiv",
+    "unnamedStore": "Unbenannter Shop",
+    "phoneNumber": "Telefonnummer",
+    "notAssigned": "Nicht zugewiesen",
+    "syncStatus": "Synchronisierungsstatus",
+    "syncing": "Synchronisierung",
+    "synced": "Synchronisiert",
+    "error": "Fehler",
+    "notSynced": "Nicht Synchronisiert",
+    "lastSync": "Letzte",
+    "dataAccess": "Datenzugriff",
+    "autoSync": "Auto-Sync",
+    "products": "Produkte",
+    "customers": "Kunden",
+    "orders": "Bestellungen",
+    "limitedAccess": "Eingeschränkter Zugriff",
+    "sync": "Sync",
+    "aiConfig": "AI-Konfiguration",
+    "phone": "Telefon",
+    "access": "Zugriff",
+    "disconnectStore": "Shop Trennen",
+    "disconnectConfirm": "Möchten Sie {{storeName}} wirklich trennen? Diese Aktion kann nicht rückgängig gemacht werden.",
+    "storeDisconnected": "Shop Getrennt",
+    "storeDisconnectedDescription": "{{storeName}} wurde erfolgreich getrennt.",
+    "disconnectionFailed": "Trennung Fehlgeschlagen",
+    "disconnectionFailedDescription": "Shop konnte nicht getrennt werden. Bitte versuchen Sie es erneut.",
+    "syncStarted": "Synchronisierung Gestartet",
+    "syncStartedDescription": "Datensynchronisierung gestartet für {{storeName}}",
+    "syncAlreadyRunning": "Synchronisierung Läuft Bereits",
+    "syncAlreadyRunningDescription": "Für diesen Shop läuft bereits eine Synchronisierung.",
+    "syncFailed": "Synchronisierung Fehlgeschlagen",
+    "syncFailedDescription": "Datensynchronisierung konnte nicht gestartet werden. Bitte versuchen Sie es erneut.",
+    "syncComplete": "Synchronisierung Abgeschlossen",
+    "syncCompleteDescription": "{{storeName}} Daten erfolgreich synchronisiert.",
+    "syncedItems": "Synchronisiert: {{items}}",
+    "shopEnabled": "Shop Aktiviert",
+    "shopDisabled": "Shop Deaktiviert",
+    "shopEnabledDescription": "{{storeName}} ist jetzt aktiviert. Hintergrundsynchronisierung wird fortgesetzt.",
+    "shopDisabledDescription": "{{storeName}} ist jetzt deaktiviert. Hintergrundsynchronisierung pausiert (manuelle Synchronisierung weiterhin verfügbar).",
+    "updateFailed": "Aktualisierung Fehlgeschlagen",
+    "updateFailedDescription": "Shop-Status konnte nicht aktualisiert werden. Bitte versuchen Sie es erneut.",
+    "dialog": {
+      "title": "E-Commerce-Plattform Verbinden",
+      "description": "Wählen Sie Ihre E-Commerce-Plattform, um mit AI-gestützten Kundenanrufen zu beginnen",
+      "shopify": "Shopify",
+      "shopifyDescription": "Verbinden Sie Ihren Shopify-Shop",
+      "woocommerce": "WooCommerce",
+      "woocommerceDescription": "Verbinden Sie Ihren WooCommerce-Shop",
+      "shoprenter": "ShopRenter",
+      "shoprenterDescription": "Verbinden Sie Ihren ShopRenter-Shop",
+      "connect": "Verbinden",
+      "comingSoon": "{{platform}}-Integration demnächst verfügbar!",
+      "close": "Schließen"
+    },
+    "quickSetup": {
+      "title": "Schnelleinrichtungs-Assistent",
+      "subtitle": "Richten Sie AI und Telefonnummern für neue Webshops in Minuten ein",
+      "step1": {
+        "title": "Verbinden Sie Ihren Webshop",
+        "description": "Verknüpfen Sie Ihre Shopify-, WooCommerce- oder andere E-Commerce-Plattform"
+      },
+      "step2": {
+        "title": "Erhalten Sie eine Telefonnummer",
+        "description": "Wir weisen automatisch eine kostenlose lokale Nummer zu oder upgraden auf Premium"
+      },
+      "step3": {
+        "title": "Konfigurieren Sie Ihren AI-Assistenten",
+        "description": "Passen Sie Stimme, Sprache und Verhalten für Ihre Region und Marke an"
+      },
+      "step4": {
+        "title": "Beginnen Sie Anrufe zu empfangen",
+        "description": "Ihre AI bearbeitet Kundenanfragen mit shop-spezifischem Wissen"
+      }
+    },
+    "dataAccessDialog": {
+      "title": "Datenzugriffsberechtigungen",
+      "description": "Datenzugriffsberechtigungen für {{storeName}} konfigurieren"
+    },
+    "oauth": {
+      "woocommerceConnected": "WooCommerce Verbunden!",
+      "woocommerceConnectedDescription": "Erfolgreich verbunden: {{storeName}}",
+      "woocommerceConnectedDefault": "Ihr WooCommerce-Shop wurde erfolgreich verbunden.",
+      "shopifyConnected": "Shopify Verbunden!",
+      "shopifyConnectedDescription": "Erfolgreich verbunden: {{storeName}}",
+      "shopifyConnectedDefault": "Ihr Shopify-Shop wurde erfolgreich verbunden.",
+      "connectionFailed": "Verbindung Fehlgeschlagen",
+      "errors": {
+        "woocommerce_oauth_rejected": "WooCommerce-Verbindung wurde abgebrochen. Bitte versuchen Sie es erneut.",
+        "woocommerce_oauth_failed": "WooCommerce-Verbindung fehlgeschlagen. Bitte versuchen Sie es erneut.",
+        "woocommerce_connection_failed": "Verbindung zu Ihrem WooCommerce-Shop konnte nicht hergestellt werden. Bitte überprüfen Sie die Shop-URL und versuchen Sie es erneut.",
+        "shopify_oauth_failed": "Shopify-Verbindung fehlgeschlagen. Bitte versuchen Sie es erneut.",
+        "shopify_hmac_invalid": "Sicherheitsüberprüfung fehlgeschlagen. Bitte versuchen Sie es erneut.",
+        "shopify_invalid_state": "Ungültige Sitzung. Bitte versuchen Sie erneut zu verbinden.",
+        "shopify_state_expired": "Verbindungssitzung abgelaufen. Bitte versuchen Sie es erneut.",
+        "shopify_token_exchange_failed": "Shopify-Autorisierung konnte nicht abgeschlossen werden. Bitte versuchen Sie es erneut.",
+        "shopify_connection_failed": "Verbindung zu Ihrem Shopify-Shop konnte nicht hergestellt werden. Bitte überprüfen Sie Ihre Domain und versuchen Sie es erneut.",
+        "invalid_shop_domain": "Ungültige Shopify-Domain. Bitte überprüfen Sie die Domain und versuchen Sie es erneut.",
+        "invalid_store_url": "Ungültige Shop-URL. Bitte überprüfen Sie die URL und versuchen Sie es erneut.",
+        "failed_to_save": "Shop-Verbindung konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.",
+        "internal_error": "Ein interner Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.",
+        "default": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
+      }
+    }
   }
 }

+ 118 - 0
shopcall.ai-main/src/i18n/locales/en.json

@@ -500,5 +500,123 @@
   "contact": {
     "title": "Contact Us",
     "subtitle": "Get in touch with our team"
+  },
+  "integrations": {
+    "title": "Webshops",
+    "subtitle": "Manage your connected stores and their AI configurations",
+    "connectWebshop": "Connect Webshop",
+    "connectedShops": "Connected Shops",
+    "withPhoneNumbers": "With Phone Numbers",
+    "activeStores": "Active Stores",
+    "platforms": "Platforms",
+    "connectedWebshops": "Connected Webshops",
+    "manageStores": "Manage your connected stores",
+    "noStoresConnected": "No Stores Connected",
+    "noStoresDescription": "Connect your first e-commerce store to get started with AI-powered customer calls",
+    "connectFirstStore": "Connect Your First Store",
+    "active": "Active",
+    "inactive": "Inactive",
+    "unnamedStore": "Unnamed Store",
+    "phoneNumber": "Phone Number",
+    "notAssigned": "Not assigned",
+    "syncStatus": "Sync Status",
+    "syncing": "Syncing",
+    "synced": "Synced",
+    "error": "Error",
+    "notSynced": "Not Synced",
+    "lastSync": "Last",
+    "dataAccess": "Data Access",
+    "autoSync": "Auto Sync",
+    "products": "Products",
+    "customers": "Customers",
+    "orders": "Orders",
+    "limitedAccess": "Limited Access",
+    "sync": "Sync",
+    "aiConfig": "AI Config",
+    "phone": "Phone",
+    "access": "Access",
+    "disconnectStore": "Disconnect Store",
+    "disconnectConfirm": "Are you sure you want to disconnect {{storeName}}? This action cannot be undone.",
+    "storeDisconnected": "Store Disconnected",
+    "storeDisconnectedDescription": "{{storeName}} has been disconnected successfully.",
+    "disconnectionFailed": "Disconnection Failed",
+    "disconnectionFailedDescription": "Failed to disconnect the store. Please try again.",
+    "syncStarted": "Sync Started",
+    "syncStartedDescription": "Data synchronization started for {{storeName}}",
+    "syncAlreadyRunning": "Sync Already Running",
+    "syncAlreadyRunningDescription": "A sync is already in progress for this store.",
+    "syncFailed": "Sync Failed",
+    "syncFailedDescription": "Failed to start data synchronization. Please try again.",
+    "syncComplete": "Sync Complete",
+    "syncCompleteDescription": "{{storeName}} data synchronized successfully.",
+    "syncedItems": "Synced: {{items}}",
+    "shopEnabled": "Shop Enabled",
+    "shopDisabled": "Shop Disabled",
+    "shopEnabledDescription": "{{storeName}} is now enabled. Background sync will resume.",
+    "shopDisabledDescription": "{{storeName}} is now disabled. Background sync is paused (manual sync still available).",
+    "updateFailed": "Update Failed",
+    "updateFailedDescription": "Failed to update shop status. Please try again.",
+    "dialog": {
+      "title": "Connect Your E-commerce Platform",
+      "description": "Choose your e-commerce platform to get started with AI-powered customer calls",
+      "shopify": "Shopify",
+      "shopifyDescription": "Connect your Shopify store",
+      "woocommerce": "WooCommerce",
+      "woocommerceDescription": "Connect your WooCommerce store",
+      "shoprenter": "ShopRenter",
+      "shoprenterDescription": "Connect your ShopRenter store",
+      "connect": "Connect",
+      "comingSoon": "{{platform}} integration coming soon!",
+      "close": "Close"
+    },
+    "quickSetup": {
+      "title": "Quick Setup Wizard",
+      "subtitle": "Set up AI and phone numbers for new webshops in minutes",
+      "step1": {
+        "title": "Connect your webshop",
+        "description": "Link your Shopify, WooCommerce, or other e-commerce platform"
+      },
+      "step2": {
+        "title": "Get a phone number",
+        "description": "We'll automatically assign a free local number or upgrade to premium"
+      },
+      "step3": {
+        "title": "Configure your AI assistant",
+        "description": "Customize voice, language, and behavior for your region and brand"
+      },
+      "step4": {
+        "title": "Start receiving calls",
+        "description": "Your AI will handle customer inquiries with store-specific knowledge"
+      }
+    },
+    "dataAccessDialog": {
+      "title": "Data Access Permissions",
+      "description": "Configure data access permissions for {{storeName}}"
+    },
+    "oauth": {
+      "woocommerceConnected": "WooCommerce Connected!",
+      "woocommerceConnectedDescription": "Successfully connected {{storeName}}",
+      "woocommerceConnectedDefault": "Your WooCommerce store has been connected successfully.",
+      "shopifyConnected": "Shopify Connected!",
+      "shopifyConnectedDescription": "Successfully connected {{storeName}}",
+      "shopifyConnectedDefault": "Your Shopify store has been connected successfully.",
+      "connectionFailed": "Connection Failed",
+      "errors": {
+        "woocommerce_oauth_rejected": "WooCommerce connection was cancelled. Please try again.",
+        "woocommerce_oauth_failed": "Failed to connect to WooCommerce. Please try again.",
+        "woocommerce_connection_failed": "Could not connect to your WooCommerce store. Please check your store URL and try again.",
+        "shopify_oauth_failed": "Failed to connect to Shopify. Please try again.",
+        "shopify_hmac_invalid": "Security verification failed. Please try again.",
+        "shopify_invalid_state": "Invalid session. Please try connecting again.",
+        "shopify_state_expired": "Connection session expired. Please try again.",
+        "shopify_token_exchange_failed": "Failed to complete Shopify authorization. Please try again.",
+        "shopify_connection_failed": "Could not connect to your Shopify store. Please check your domain and try again.",
+        "invalid_shop_domain": "Invalid Shopify domain. Please check the domain and try again.",
+        "invalid_store_url": "Invalid store URL. Please check the URL and try again.",
+        "failed_to_save": "Failed to save store connection. Please try again.",
+        "internal_error": "An internal error occurred. Please try again later.",
+        "default": "An unexpected error occurred. Please try again."
+      }
+    }
   }
 }

+ 118 - 0
shopcall.ai-main/src/i18n/locales/hu.json

@@ -500,5 +500,123 @@
   "contact": {
     "title": "Kapcsolat",
     "subtitle": "Lépjen kapcsolatba csapatunkkal"
+  },
+  "integrations": {
+    "title": "Webáruházak",
+    "subtitle": "Kezelje csatlakoztatott áruházait és azok AI konfigurációit",
+    "connectWebshop": "Webáruház Csatlakoztatása",
+    "connectedShops": "Csatlakoztatott Áruházak",
+    "withPhoneNumbers": "Telefonszámmal",
+    "activeStores": "Aktív Áruházak",
+    "platforms": "Platformok",
+    "connectedWebshops": "Csatlakoztatott Webáruházak",
+    "manageStores": "Csatlakoztatott áruházak kezelése",
+    "noStoresConnected": "Nincsenek Csatlakoztatott Áruházak",
+    "noStoresDescription": "Csatlakoztassa első e-kereskedelmi áruházát az AI-alapú ügyfélhívások használatához",
+    "connectFirstStore": "Első Áruház Csatlakoztatása",
+    "active": "Aktív",
+    "inactive": "Inaktív",
+    "unnamedStore": "Névtelen Áruház",
+    "phoneNumber": "Telefonszám",
+    "notAssigned": "Nincs hozzárendelve",
+    "syncStatus": "Szinkronizálási Állapot",
+    "syncing": "Szinkronizálás",
+    "synced": "Szinkronizálva",
+    "error": "Hiba",
+    "notSynced": "Nincs Szinkronizálva",
+    "lastSync": "Utolsó",
+    "dataAccess": "Adathozzáférés",
+    "autoSync": "Automatikus Szinkronizálás",
+    "products": "Termékek",
+    "customers": "Ügyfelek",
+    "orders": "Rendelések",
+    "limitedAccess": "Korlátozott Hozzáférés",
+    "sync": "Szinkronizálás",
+    "aiConfig": "AI Konfiguráció",
+    "phone": "Telefon",
+    "access": "Hozzáférés",
+    "disconnectStore": "Áruház Lecsatlakoztatása",
+    "disconnectConfirm": "Biztosan le szeretné csatlakoztatni a következőt: {{storeName}}? Ez a művelet nem vonható vissza.",
+    "storeDisconnected": "Áruház Lecsatlakoztatva",
+    "storeDisconnectedDescription": "{{storeName}} sikeresen lecsatlakoztatva.",
+    "disconnectionFailed": "Lecsatlakoztatás Sikertelen",
+    "disconnectionFailedDescription": "Az áruház lecsatlakoztatása sikertelen. Kérjük, próbálja újra.",
+    "syncStarted": "Szinkronizálás Elkezdődött",
+    "syncStartedDescription": "Adatszinkronizálás elindítva: {{storeName}}",
+    "syncAlreadyRunning": "Szinkronizálás Már Folyamatban",
+    "syncAlreadyRunningDescription": "Már folyamatban van egy szinkronizálás ehhez az áruházhoz.",
+    "syncFailed": "Szinkronizálás Sikertelen",
+    "syncFailedDescription": "Az adatszinkronizálás indítása sikertelen. Kérjük, próbálja újra.",
+    "syncComplete": "Szinkronizálás Kész",
+    "syncCompleteDescription": "{{storeName}} adatok sikeresen szinkronizálva.",
+    "syncedItems": "Szinkronizálva: {{items}}",
+    "shopEnabled": "Áruház Engedélyezve",
+    "shopDisabled": "Áruház Letiltva",
+    "shopEnabledDescription": "{{storeName}} most engedélyezve van. A háttérszinkronizálás folytatódik.",
+    "shopDisabledDescription": "{{storeName}} most le van tiltva. A háttérszinkronizálás szünetel (manuális szinkronizálás továbbra is elérhető).",
+    "updateFailed": "Frissítés Sikertelen",
+    "updateFailedDescription": "Az áruház állapotának frissítése sikertelen. Kérjük, próbálja újra.",
+    "dialog": {
+      "title": "Csatlakoztassa E-kereskedelmi Platformját",
+      "description": "Válassza ki e-kereskedelmi platformját az AI-alapú ügyfélhívások megkezdéséhez",
+      "shopify": "Shopify",
+      "shopifyDescription": "Csatlakoztassa Shopify áruházát",
+      "woocommerce": "WooCommerce",
+      "woocommerceDescription": "Csatlakoztassa WooCommerce áruházát",
+      "shoprenter": "ShopRenter",
+      "shoprenterDescription": "Csatlakoztassa ShopRenter áruházát",
+      "connect": "Csatlakoztatás",
+      "comingSoon": "{{platform}} integráció hamarosan!",
+      "close": "Bezárás"
+    },
+    "quickSetup": {
+      "title": "Gyors Beállítási Varázsló",
+      "subtitle": "Állítsa be az AI-t és telefonszámokat új webáruházakhoz percek alatt",
+      "step1": {
+        "title": "Csatlakoztassa webáruházát",
+        "description": "Kösse össze Shopify, WooCommerce vagy más e-kereskedelmi platformját"
+      },
+      "step2": {
+        "title": "Szerezzen telefonszámot",
+        "description": "Automatikusan hozzárendelünk egy ingyenes helyi számot, vagy váltson prémiumra"
+      },
+      "step3": {
+        "title": "Konfigurálja AI asszisztensét",
+        "description": "Testreszabhatja a hangot, nyelvet és viselkedést régiója és márkája számára"
+      },
+      "step4": {
+        "title": "Kezdjen el hívásokat fogadni",
+        "description": "Az AI áruház-specifikus tudással kezeli az ügyfélkérdéseket"
+      }
+    },
+    "dataAccessDialog": {
+      "title": "Adathozzáférési Engedélyek",
+      "description": "Adathozzáférési engedélyek konfigurálása: {{storeName}}"
+    },
+    "oauth": {
+      "woocommerceConnected": "WooCommerce Csatlakoztatva!",
+      "woocommerceConnectedDescription": "Sikeresen csatlakoztatva: {{storeName}}",
+      "woocommerceConnectedDefault": "WooCommerce áruháza sikeresen csatlakoztatva.",
+      "shopifyConnected": "Shopify Csatlakoztatva!",
+      "shopifyConnectedDescription": "Sikeresen csatlakoztatva: {{storeName}}",
+      "shopifyConnectedDefault": "Shopify áruháza sikeresen csatlakoztatva.",
+      "connectionFailed": "Csatlakozás Sikertelen",
+      "errors": {
+        "woocommerce_oauth_rejected": "WooCommerce csatlakoztatás megszakítva. Kérjük, próbálja újra.",
+        "woocommerce_oauth_failed": "WooCommerce csatlakoztatása sikertelen. Kérjük, próbálja újra.",
+        "woocommerce_connection_failed": "Nem sikerült csatlakozni WooCommerce áruházához. Ellenőrizze az áruház URL-jét és próbálja újra.",
+        "shopify_oauth_failed": "Shopify csatlakoztatása sikertelen. Kérjük, próbálja újra.",
+        "shopify_hmac_invalid": "Biztonsági ellenőrzés sikertelen. Kérjük, próbálja újra.",
+        "shopify_invalid_state": "Érvénytelen munkamenet. Kérjük, próbálja meg újra csatlakoztatni.",
+        "shopify_state_expired": "Csatlakozási munkamenet lejárt. Kérjük, próbálja újra.",
+        "shopify_token_exchange_failed": "Shopify engedélyezés befejezése sikertelen. Kérjük, próbálja újra.",
+        "shopify_connection_failed": "Nem sikerült csatlakozni Shopify áruházához. Ellenőrizze a domain nevet és próbálja újra.",
+        "invalid_shop_domain": "Érvénytelen Shopify domain. Ellenőrizze a domain nevet és próbálja újra.",
+        "invalid_store_url": "Érvénytelen áruház URL. Ellenőrizze az URL-t és próbálja újra.",
+        "failed_to_save": "Áruház csatlakozás mentése sikertelen. Kérjük, próbálja újra.",
+        "internal_error": "Belső hiba történt. Kérjük, próbálja újra később.",
+        "default": "Váratlan hiba történt. Kérjük, próbálja újra."
+      }
+    }
   }
 }