refactor: complete JS i18n migration for confirm dialogs and toast messages
Migrate 34 hardcoded user-facing strings to use I18n.t() for translation: - CMS: media file operations (5 strings) - Marketplace: Letzshop integration (16 strings) - Messaging: notifications, messages, email templates (5 strings) - Tenancy: platform modules, menu config, theme (5 strings) - Core: menu config, settings, storefront cart (5 strings) - Catalog: product creation (3 strings) - Utils: clipboard operations (2 strings) Added confirmations and messages keys to module locale files. Added I18n.loadModule() calls to JS files that were missing them. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,49 +1,82 @@
|
|||||||
{
|
{
|
||||||
"title": "Product Catalog",
|
|
||||||
"description": "Product catalog management for vendors",
|
|
||||||
"products": {
|
"products": {
|
||||||
"title": "Products",
|
"title": "Products",
|
||||||
"subtitle": "Manage your product catalog",
|
"product": "Product",
|
||||||
"create": "Create Product",
|
"add_product": "Add Product",
|
||||||
"edit": "Edit Product",
|
"edit_product": "Edit Product",
|
||||||
"delete": "Delete Product",
|
"delete_product": "Delete Product",
|
||||||
"empty": "No products found",
|
"product_name": "Product Name",
|
||||||
"empty_search": "No products match your search"
|
"product_code": "Product Code",
|
||||||
},
|
|
||||||
"product": {
|
|
||||||
"name": "Product Name",
|
|
||||||
"description": "Description",
|
|
||||||
"sku": "SKU",
|
"sku": "SKU",
|
||||||
"price": "Price",
|
"price": "Price",
|
||||||
|
"sale_price": "Sale Price",
|
||||||
|
"cost": "Cost",
|
||||||
"stock": "Stock",
|
"stock": "Stock",
|
||||||
"status": "Status",
|
"in_stock": "In Stock",
|
||||||
"active": "Active",
|
"out_of_stock": "Out of Stock",
|
||||||
"inactive": "Inactive"
|
"low_stock": "Low Stock",
|
||||||
},
|
"availability": "Availability",
|
||||||
"media": {
|
"available": "Available",
|
||||||
"title": "Product Media",
|
"unavailable": "Unavailable",
|
||||||
"upload": "Upload Image",
|
"brand": "Brand",
|
||||||
"delete": "Delete Image",
|
"category": "Category",
|
||||||
"primary": "Set as Primary",
|
"categories": "Categories",
|
||||||
"error": "Media upload failed"
|
"image": "Image",
|
||||||
},
|
"images": "Images",
|
||||||
"validation": {
|
"main_image": "Main Image",
|
||||||
"name_required": "Product name is required",
|
"gallery": "Gallery",
|
||||||
"price_required": "Price is required",
|
"weight": "Weight",
|
||||||
"invalid_sku": "Invalid SKU format",
|
"dimensions": "Dimensions",
|
||||||
"duplicate_sku": "SKU already exists"
|
"color": "Color",
|
||||||
|
"size": "Size",
|
||||||
|
"material": "Material",
|
||||||
|
"condition": "Condition",
|
||||||
|
"new": "New",
|
||||||
|
"used": "Used",
|
||||||
|
"refurbished": "Refurbished",
|
||||||
|
"no_products": "No products found",
|
||||||
|
"search_products": "Search products...",
|
||||||
|
"filter_by_category": "Filter by category",
|
||||||
|
"filter_by_status": "Filter by status",
|
||||||
|
"sort_by": "Sort by",
|
||||||
|
"sort_newest": "Newest",
|
||||||
|
"sort_oldest": "Oldest",
|
||||||
|
"sort_price_low": "Price: Low to High",
|
||||||
|
"sort_price_high": "Price: High to Low",
|
||||||
|
"sort_name_az": "Name: A-Z",
|
||||||
|
"sort_name_za": "Name: Z-A"
|
||||||
},
|
},
|
||||||
"messages": {
|
"messages": {
|
||||||
"created": "Product created successfully",
|
"product_deleted_successfully": "Product deleted successfully",
|
||||||
"updated": "Product updated successfully",
|
"product_created_successfully": "Product created successfully",
|
||||||
"deleted": "Product deleted successfully",
|
"product_updated_successfully": "Product updated successfully",
|
||||||
"not_found": "Product not found",
|
"product_activated": "Product activated",
|
||||||
"cannot_delete": "Cannot delete product",
|
"product_deactivated": "Product deactivated",
|
||||||
"error_loading": "Error loading products"
|
"product_marked_as_featured": "Product marked as featured",
|
||||||
},
|
"product_unmarked_as_featured": "Product unmarked as featured",
|
||||||
"filters": {
|
"products_activated": "{count} product(s) activated",
|
||||||
"all_products": "All Products",
|
"products_deactivated": "{count} product(s) deactivated",
|
||||||
"active_only": "Active Only",
|
"products_marked_as_featured": "{count} product(s) marked as featured",
|
||||||
"search_placeholder": "Search products..."
|
"products_unmarked_as_featured": "{count} product(s) unmarked as featured",
|
||||||
|
"products_deleted": "{count} product(s) deleted",
|
||||||
|
"failed_to_save_product": "Failed to save product",
|
||||||
|
"failed_to_create_product": "Failed to create product",
|
||||||
|
"failed_to_update_product": "Failed to update product",
|
||||||
|
"failed_to_delete_product": "Failed to delete product",
|
||||||
|
"failed_to_load_products": "Failed to load products",
|
||||||
|
"failed_to_activate_products": "Failed to activate products",
|
||||||
|
"failed_to_deactivate_products": "Failed to deactivate products",
|
||||||
|
"failed_to_upload_image": "Failed to upload image",
|
||||||
|
"product_removed_from_vendor_catalog": "Product removed from vendor catalog.",
|
||||||
|
"please_fill_in_all_required_fields": "Please fill in all required fields",
|
||||||
|
"failed_to_load_media_library": "Failed to load media library",
|
||||||
|
"no_vendor_associated_with_this_product": "No vendor associated with this product",
|
||||||
|
"please_select_an_image_file": "Please select an image file",
|
||||||
|
"image_must_be_less_than_10mb": "Image must be less than 10MB",
|
||||||
|
"image_uploaded_successfully": "Image uploaded successfully",
|
||||||
|
"please_select_a_vendor": "Please select a vendor",
|
||||||
|
"please_enter_a_product_title_english": "Please enter a product title (English)",
|
||||||
|
"please_select_a_vendor_first": "Please select a vendor first",
|
||||||
|
"title_and_price_required": "Title and price are required"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ function vendorProductCreate() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('catalog');
|
||||||
|
|
||||||
// Guard against duplicate initialization
|
// Guard against duplicate initialization
|
||||||
if (window._vendorProductCreateInitialized) return;
|
if (window._vendorProductCreateInitialized) return;
|
||||||
window._vendorProductCreateInitialized = true;
|
window._vendorProductCreateInitialized = true;
|
||||||
@@ -66,7 +69,7 @@ function vendorProductCreate() {
|
|||||||
|
|
||||||
async createProduct() {
|
async createProduct() {
|
||||||
if (!this.form.title || !this.form.price) {
|
if (!this.form.title || !this.form.price) {
|
||||||
this.showToast('Title and price are required', 'error');
|
Utils.showToast(I18n.t('catalog.messages.title_and_price_required'), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +96,7 @@ function vendorProductCreate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vendorProductCreateLog.info('Product created:', response.data);
|
vendorProductCreateLog.info('Product created:', response.data);
|
||||||
this.showToast('Product created successfully', 'success');
|
Utils.showToast(I18n.t('catalog.messages.product_created_successfully'), 'success');
|
||||||
|
|
||||||
// Navigate back to products list
|
// Navigate back to products list
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -102,8 +105,8 @@ function vendorProductCreate() {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
vendorProductCreateLog.error('Failed to create product:', err);
|
vendorProductCreateLog.error('Failed to create product:', err);
|
||||||
this.error = err.message || 'Failed to create product';
|
this.error = err.message || I18n.t('catalog.messages.failed_to_create_product');
|
||||||
this.showToast(this.error, 'error');
|
Utils.showToast(this.error, 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +1,213 @@
|
|||||||
{
|
{
|
||||||
"title": "Content Management",
|
"platform": {
|
||||||
"description": "Manage content pages, media library, and vendor themes",
|
"nav": {
|
||||||
"pages": {
|
"pricing": "Pricing",
|
||||||
"title": "Content Pages",
|
"find_shop": "Find Your Shop",
|
||||||
"subtitle": "Manage platform and vendor content pages",
|
"start_trial": "Start Free Trial",
|
||||||
"create": "Create Page",
|
"admin_login": "Admin Login",
|
||||||
"edit": "Edit Page",
|
"vendor_login": "Vendor Login",
|
||||||
"delete": "Delete Page",
|
"toggle_menu": "Toggle menu",
|
||||||
"list": "All Pages",
|
"toggle_dark_mode": "Toggle dark mode"
|
||||||
"empty": "No pages found",
|
|
||||||
"empty_search": "No pages match your search",
|
|
||||||
"create_first": "Create First Page"
|
|
||||||
},
|
|
||||||
"page": {
|
|
||||||
"title": "Page Title",
|
|
||||||
"slug": "Slug",
|
|
||||||
"slug_help": "URL-safe identifier (lowercase, numbers, hyphens only)",
|
|
||||||
"content": "Content",
|
|
||||||
"content_format": "Content Format",
|
|
||||||
"format_html": "HTML",
|
|
||||||
"format_markdown": "Markdown",
|
|
||||||
"platform": "Platform",
|
|
||||||
"vendor_override": "Vendor Override",
|
|
||||||
"vendor_override_none": "None (Platform Default)",
|
|
||||||
"vendor_override_help_default": "This is a platform-wide default page",
|
|
||||||
"vendor_override_help_vendor": "This page overrides the default for selected vendor only"
|
|
||||||
},
|
|
||||||
"tiers": {
|
|
||||||
"platform": "Platform Marketing",
|
|
||||||
"vendor_default": "Vendor Default",
|
|
||||||
"vendor_override": "Vendor Override"
|
|
||||||
},
|
|
||||||
"seo": {
|
|
||||||
"title": "SEO & Metadata",
|
|
||||||
"meta_description": "Meta Description",
|
|
||||||
"meta_description_help": "characters (150-160 recommended)",
|
|
||||||
"meta_keywords": "Meta Keywords",
|
|
||||||
"meta_keywords_placeholder": "keyword1, keyword2, keyword3"
|
|
||||||
},
|
|
||||||
"navigation": {
|
|
||||||
"title": "Navigation & Display",
|
|
||||||
"display_order": "Display Order",
|
|
||||||
"display_order_help": "Lower = first",
|
|
||||||
"show_in_header": "Show in Header",
|
|
||||||
"show_in_footer": "Show in Footer",
|
|
||||||
"show_in_legal": "Show in Legal",
|
|
||||||
"show_in_legal_help": "Bottom bar next to copyright"
|
|
||||||
},
|
|
||||||
"publishing": {
|
|
||||||
"published": "Published",
|
|
||||||
"draft": "Draft",
|
|
||||||
"publish_help": "Make this page visible to the public"
|
|
||||||
},
|
|
||||||
"homepage": {
|
|
||||||
"title": "Homepage Sections",
|
|
||||||
"subtitle": "Multi-language content",
|
|
||||||
"loading": "Loading sections...",
|
|
||||||
"hero": {
|
|
||||||
"title": "Hero Section",
|
|
||||||
"badge_text": "Badge Text",
|
|
||||||
"main_title": "Title",
|
|
||||||
"subtitle": "Subtitle",
|
|
||||||
"buttons": "Buttons",
|
|
||||||
"add_button": "Add Button"
|
|
||||||
},
|
},
|
||||||
"features": {
|
"hero": {
|
||||||
"title": "Features Section",
|
"badge": "{trial_days}-Day Free Trial - No Credit Card Required to Start",
|
||||||
"section_title": "Section Title",
|
"title": "Lightweight OMS for Letzshop Sellers",
|
||||||
"cards": "Feature Cards",
|
"subtitle": "Order management, inventory, and invoicing built for Luxembourg e-commerce. Stop juggling spreadsheets. Start running your business.",
|
||||||
"add_card": "Add Feature Card",
|
"cta_trial": "Start Free Trial",
|
||||||
"icon": "Icon name",
|
"cta_find_shop": "Find Your Letzshop Shop"
|
||||||
"feature_title": "Title",
|
|
||||||
"feature_description": "Description"
|
|
||||||
},
|
},
|
||||||
"pricing": {
|
"pricing": {
|
||||||
"title": "Pricing Section",
|
"title": "Simple, Transparent Pricing",
|
||||||
"section_title": "Section Title",
|
"subtitle": "Choose the plan that fits your business. All plans include a {trial_days}-day free trial.",
|
||||||
"use_tiers": "Use subscription tiers from database",
|
"monthly": "Monthly",
|
||||||
"use_tiers_help": "When enabled, pricing cards are dynamically pulled from your subscription tier configuration."
|
"annual": "Annual",
|
||||||
|
"save_months": "Save 2 months!",
|
||||||
|
"most_popular": "MOST POPULAR",
|
||||||
|
"recommended": "RECOMMENDED",
|
||||||
|
"contact_sales": "Contact Sales",
|
||||||
|
"start_trial": "Start Free Trial",
|
||||||
|
"per_month": "/month",
|
||||||
|
"per_year": "/year",
|
||||||
|
"custom": "Custom",
|
||||||
|
"orders_per_month": "{count} orders/month",
|
||||||
|
"unlimited_orders": "Unlimited orders",
|
||||||
|
"products_limit": "{count} products",
|
||||||
|
"unlimited_products": "Unlimited products",
|
||||||
|
"team_members": "{count} team members",
|
||||||
|
"unlimited_team": "Unlimited team",
|
||||||
|
"letzshop_sync": "Letzshop order sync",
|
||||||
|
"eu_vat_invoicing": "EU VAT invoicing",
|
||||||
|
"analytics_dashboard": "Analytics dashboard",
|
||||||
|
"api_access": "API access",
|
||||||
|
"multi_channel": "Multi-channel integration",
|
||||||
|
"products": "products",
|
||||||
|
"team_member": "team member",
|
||||||
|
"unlimited": "Unlimited",
|
||||||
|
"order_history": "months order history",
|
||||||
|
"trial_note": "All plans include a {trial_days}-day free trial. No credit card required.",
|
||||||
|
"back_home": "Back to Home"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"letzshop_sync": "Letzshop order sync",
|
||||||
|
"inventory_basic": "Basic inventory management",
|
||||||
|
"inventory_locations": "Warehouse locations",
|
||||||
|
"inventory_purchase_orders": "Purchase orders",
|
||||||
|
"invoice_lu": "Luxembourg VAT invoicing",
|
||||||
|
"invoice_eu_vat": "EU VAT invoicing",
|
||||||
|
"invoice_bulk": "Bulk invoicing",
|
||||||
|
"customer_view": "Customer list",
|
||||||
|
"customer_export": "Customer export",
|
||||||
|
"analytics_dashboard": "Analytics dashboard",
|
||||||
|
"accounting_export": "Accounting export",
|
||||||
|
"api_access": "API access",
|
||||||
|
"automation_rules": "Automation rules",
|
||||||
|
"team_roles": "Team roles & permissions",
|
||||||
|
"white_label": "White-label option",
|
||||||
|
"multi_vendor": "Multi-vendor support",
|
||||||
|
"custom_integrations": "Custom integrations",
|
||||||
|
"sla_guarantee": "SLA guarantee",
|
||||||
|
"dedicated_support": "Dedicated account manager"
|
||||||
|
},
|
||||||
|
"addons": {
|
||||||
|
"title": "Enhance Your Platform",
|
||||||
|
"subtitle": "Add custom branding, professional email, and enhanced security.",
|
||||||
|
"per_year": "/year",
|
||||||
|
"per_month": "/month",
|
||||||
|
"custom_domain": "Custom Domain",
|
||||||
|
"custom_domain_desc": "Use your own domain (mydomain.com)",
|
||||||
|
"premium_ssl": "Premium SSL",
|
||||||
|
"premium_ssl_desc": "EV certificate for trust badges",
|
||||||
|
"email_package": "Email Package",
|
||||||
|
"email_package_desc": "Professional email addresses"
|
||||||
|
},
|
||||||
|
"find_shop": {
|
||||||
|
"title": "Find Your Letzshop Shop",
|
||||||
|
"subtitle": "Already selling on Letzshop? Enter your shop URL to get started.",
|
||||||
|
"placeholder": "Enter your Letzshop URL (e.g., letzshop.lu/vendors/my-shop)",
|
||||||
|
"button": "Find My Shop",
|
||||||
|
"claim_shop": "Claim This Shop",
|
||||||
|
"already_claimed": "Already Claimed",
|
||||||
|
"no_account": "Don't have a Letzshop account?",
|
||||||
|
"signup_letzshop": "Sign up with Letzshop first",
|
||||||
|
"then_connect": ", then come back to connect your shop.",
|
||||||
|
"search_placeholder": "Enter Letzshop URL or shop name...",
|
||||||
|
"search_button": "Search",
|
||||||
|
"examples": "Examples:",
|
||||||
|
"claim_button": "Claim This Shop & Start Free Trial",
|
||||||
|
"not_found": "We could not find a Letzshop shop with that URL. Please check and try again.",
|
||||||
|
"or_signup": "Or sign up without a Letzshop connection",
|
||||||
|
"need_help": "Need Help?",
|
||||||
|
"no_account_yet": "Don't have a Letzshop account yet? No problem!",
|
||||||
|
"create_letzshop": "Create a Letzshop Account",
|
||||||
|
"signup_without": "Sign Up Without Letzshop",
|
||||||
|
"looking_up": "Looking up your shop...",
|
||||||
|
"found": "Found:",
|
||||||
|
"claimed_badge": "Already Claimed"
|
||||||
|
},
|
||||||
|
"signup": {
|
||||||
|
"step_plan": "Select Plan",
|
||||||
|
"step_shop": "Claim Shop",
|
||||||
|
"step_account": "Account",
|
||||||
|
"step_payment": "Payment",
|
||||||
|
"choose_plan": "Choose Your Plan",
|
||||||
|
"save_percent": "Save {percent}%",
|
||||||
|
"trial_info": "We'll collect your payment info, but you won't be charged until the trial ends.",
|
||||||
|
"connect_shop": "Connect Your Letzshop Shop",
|
||||||
|
"connect_optional": "Optional: Link your Letzshop account to sync orders automatically.",
|
||||||
|
"connect_continue": "Connect & Continue",
|
||||||
|
"skip_step": "Skip This Step",
|
||||||
|
"create_account": "Create Your Account",
|
||||||
|
"first_name": "First Name",
|
||||||
|
"last_name": "Last Name",
|
||||||
|
"company_name": "Company Name",
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Password",
|
||||||
|
"password_hint": "Minimum 8 characters",
|
||||||
|
"continue": "Continue",
|
||||||
|
"continue_payment": "Continue to Payment",
|
||||||
|
"back": "Back",
|
||||||
|
"add_payment": "Add Payment Method",
|
||||||
|
"no_charge_note": "You won't be charged until your {trial_days}-day trial ends.",
|
||||||
|
"processing": "Processing...",
|
||||||
|
"start_trial": "Start Free Trial",
|
||||||
|
"creating_account": "Creating your account..."
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"title": "Welcome to Wizamart!",
|
||||||
|
"subtitle": "Your account has been created and your {trial_days}-day free trial has started.",
|
||||||
|
"what_next": "What's Next?",
|
||||||
|
"step_connect": "Connect Letzshop:",
|
||||||
|
"step_connect_desc": "Add your API key to start syncing orders automatically.",
|
||||||
|
"step_invoicing": "Set Up Invoicing:",
|
||||||
|
"step_invoicing_desc": "Configure your invoice settings for Luxembourg compliance.",
|
||||||
|
"step_products": "Import Products:",
|
||||||
|
"step_products_desc": "Sync your product catalog from Letzshop.",
|
||||||
|
"go_to_dashboard": "Go to Dashboard",
|
||||||
|
"login_dashboard": "Login to Dashboard",
|
||||||
|
"need_help": "Need help getting started?",
|
||||||
|
"contact_support": "Contact our support team"
|
||||||
},
|
},
|
||||||
"cta": {
|
"cta": {
|
||||||
"title": "Call to Action Section",
|
"title": "Ready to Streamline Your Orders?",
|
||||||
"main_title": "Title",
|
"subtitle": "Join Letzshop vendors who trust Wizamart for their order management. Start your {trial_days}-day free trial today.",
|
||||||
"subtitle": "Subtitle",
|
"button": "Start Free Trial"
|
||||||
"buttons": "Buttons",
|
},
|
||||||
"add_button": "Add Button"
|
"footer": {
|
||||||
|
"tagline": "Lightweight OMS for Letzshop sellers. Manage orders, inventory, and invoicing.",
|
||||||
|
"quick_links": "Quick Links",
|
||||||
|
"platform": "Platform",
|
||||||
|
"contact": "Contact",
|
||||||
|
"copyright": "© {year} Wizamart. Built for Luxembourg e-commerce.",
|
||||||
|
"privacy": "Privacy Policy",
|
||||||
|
"terms": "Terms of Service",
|
||||||
|
"about": "About Us",
|
||||||
|
"faq": "FAQ",
|
||||||
|
"contact_us": "Contact Us"
|
||||||
|
},
|
||||||
|
"modern": {
|
||||||
|
"badge_integration": "Official Integration",
|
||||||
|
"badge_connect": "Connect in 2 minutes",
|
||||||
|
"hero_title_1": "Built for Luxembourg E-Commerce",
|
||||||
|
"hero_title_2": "The Back-Office Letzshop Doesn't Give You",
|
||||||
|
"hero_subtitle": "Sync orders, manage inventory, generate invoices with correct VAT, and own your customer data. All in one place.",
|
||||||
|
"cta_trial": "Start {trial_days}-Day Free Trial",
|
||||||
|
"cta_how": "See How It Works",
|
||||||
|
"hero_note": "No credit card required. Setup in 5 minutes. Cancel anytime.",
|
||||||
|
"pain_title": "Sound Familiar?",
|
||||||
|
"pain_subtitle": "These are the daily frustrations of Letzshop sellers",
|
||||||
|
"pain_manual": "Manual Order Entry",
|
||||||
|
"pain_manual_desc": "Copy-pasting orders from Letzshop to spreadsheets. Every. Single. Day.",
|
||||||
|
"pain_inventory": "Inventory Chaos",
|
||||||
|
"pain_inventory_desc": "Stock in Letzshop doesn't match reality. Overselling happens.",
|
||||||
|
"pain_vat": "Wrong VAT Invoices",
|
||||||
|
"pain_vat_desc": "EU customers need correct VAT. Your accountant keeps complaining.",
|
||||||
|
"pain_customers": "Lost Customers",
|
||||||
|
"pain_customers_desc": "Letzshop owns your customer data. You can't retarget or build loyalty.",
|
||||||
|
"how_title": "How It Works",
|
||||||
|
"how_subtitle": "From Chaos to Control in 4 Steps",
|
||||||
|
"how_step1": "Connect Letzshop",
|
||||||
|
"how_step1_desc": "Enter your Letzshop API credentials. Done in 2 minutes, no technical skills needed.",
|
||||||
|
"how_step2": "Orders Flow In",
|
||||||
|
"how_step2_desc": "Orders sync automatically. Confirm and add tracking directly from Wizamart.",
|
||||||
|
"how_step3": "Generate Invoices",
|
||||||
|
"how_step3_desc": "One click to create compliant PDF invoices with correct VAT for any EU country.",
|
||||||
|
"how_step4": "Grow Your Business",
|
||||||
|
"how_step4_desc": "Export customers for marketing. Track inventory. Focus on selling, not spreadsheets.",
|
||||||
|
"features_title": "Everything a Letzshop Seller Needs",
|
||||||
|
"features_subtitle": "The operational tools Letzshop doesn't provide",
|
||||||
|
"cta_final_title": "Ready to Take Control of Your Letzshop Business?",
|
||||||
|
"cta_final_subtitle": "Join Luxembourg vendors who've stopped fighting spreadsheets and started growing their business.",
|
||||||
|
"cta_final_note": "No credit card required. Setup in 5 minutes. Full Professional features during trial."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"media": {
|
|
||||||
"title": "Media Library",
|
|
||||||
"upload": "Upload",
|
|
||||||
"upload_file": "Upload File",
|
|
||||||
"delete": "Delete",
|
|
||||||
"empty": "No media files",
|
|
||||||
"upload_first": "Upload your first file"
|
|
||||||
},
|
|
||||||
"themes": {
|
|
||||||
"title": "Vendor Themes",
|
|
||||||
"subtitle": "Manage vendor theme customizations"
|
|
||||||
},
|
|
||||||
"actions": {
|
|
||||||
"save": "Save",
|
|
||||||
"saving": "Saving...",
|
|
||||||
"update": "Update Page",
|
|
||||||
"create": "Create Page",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"back_to_list": "Back to List",
|
|
||||||
"preview": "Preview",
|
|
||||||
"revert_to_default": "Revert to Default"
|
|
||||||
},
|
|
||||||
"messages": {
|
"messages": {
|
||||||
"created": "Page created successfully",
|
"failed_to_delete_page": "Failed to delete page: {error}",
|
||||||
"updated": "Page updated successfully",
|
"media_updated_successfully": "Media updated successfully",
|
||||||
"deleted": "Page deleted successfully",
|
"media_deleted_successfully": "Media deleted successfully",
|
||||||
"reverted": "Reverted to default page",
|
"url_copied_to_clipboard": "URL copied to clipboard",
|
||||||
"error_loading": "Error loading page",
|
"failed_to_copy_url": "Failed to copy URL"
|
||||||
"error_saving": "Error saving page",
|
|
||||||
"confirm_delete": "Are you sure you want to delete this page?"
|
|
||||||
},
|
},
|
||||||
"filters": {
|
"confirmations": {
|
||||||
"all_pages": "All Pages",
|
"delete_file": "Are you sure you want to delete this file? This cannot be undone."
|
||||||
"all_platforms": "All Platforms",
|
|
||||||
"search_placeholder": "Search pages..."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
app/modules/cms/static/vendor/js/media.js
vendored
13
app/modules/cms/static/vendor/js/media.js
vendored
@@ -119,6 +119,9 @@ function vendorMedia() {
|
|||||||
uploadingFiles: [],
|
uploadingFiles: [],
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('cms');
|
||||||
|
|
||||||
// Guard against duplicate initialization
|
// Guard against duplicate initialization
|
||||||
if (window._vendorMediaInitialized) return;
|
if (window._vendorMediaInitialized) return;
|
||||||
window._vendorMediaInitialized = true;
|
window._vendorMediaInitialized = true;
|
||||||
@@ -233,7 +236,7 @@ function vendorMedia() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.showToast('Media updated successfully', 'success');
|
Utils.showToast(I18n.t('cms.messages.media_updated_successfully'), 'success');
|
||||||
this.showDetailModal = false;
|
this.showDetailModal = false;
|
||||||
await this.loadMedia();
|
await this.loadMedia();
|
||||||
} else {
|
} else {
|
||||||
@@ -250,7 +253,7 @@ function vendorMedia() {
|
|||||||
async deleteMedia() {
|
async deleteMedia() {
|
||||||
if (!this.selectedMedia) return;
|
if (!this.selectedMedia) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to delete this file? This cannot be undone.')) {
|
if (!confirm(I18n.t('cms.confirmations.delete_file'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +263,7 @@ function vendorMedia() {
|
|||||||
const response = await apiClient.delete(`/vendor/media/${this.selectedMedia.id}`);
|
const response = await apiClient.delete(`/vendor/media/${this.selectedMedia.id}`);
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
this.showToast('Media deleted successfully', 'success');
|
Utils.showToast(I18n.t('cms.messages.media_deleted_successfully'), 'success');
|
||||||
this.showDetailModal = false;
|
this.showDetailModal = false;
|
||||||
this.selectedMedia = null;
|
this.selectedMedia = null;
|
||||||
await this.loadMedia();
|
await this.loadMedia();
|
||||||
@@ -351,9 +354,9 @@ function vendorMedia() {
|
|||||||
copyToClipboard(text) {
|
copyToClipboard(text) {
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
navigator.clipboard.writeText(text).then(() => {
|
navigator.clipboard.writeText(text).then(() => {
|
||||||
this.showToast('URL copied to clipboard', 'success');
|
Utils.showToast(I18n.t('cms.messages.url_copied_to_clipboard'), 'success');
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.showToast('Failed to copy URL', 'error');
|
Utils.showToast(I18n.t('cms.messages.failed_to_copy_url'), 'error');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
79
app/modules/core/locales/en.json
Normal file
79
app/modules/core/locales/en.json
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
{
|
||||||
|
"dashboard": {
|
||||||
|
"title": "Dashboard",
|
||||||
|
"welcome": "Welcome back",
|
||||||
|
"overview": "Overview",
|
||||||
|
"quick_stats": "Quick Stats",
|
||||||
|
"recent_activity": "Recent Activity",
|
||||||
|
"total_products": "Total Products",
|
||||||
|
"total_orders": "Total Orders",
|
||||||
|
"total_customers": "Total Customers",
|
||||||
|
"total_revenue": "Total Revenue",
|
||||||
|
"active_products": "Active Products",
|
||||||
|
"pending_orders": "Pending Orders",
|
||||||
|
"new_customers": "New Customers",
|
||||||
|
"today": "Today",
|
||||||
|
"this_week": "This Week",
|
||||||
|
"this_month": "This Month",
|
||||||
|
"this_year": "This Year",
|
||||||
|
"error_loading": "Error loading dashboard",
|
||||||
|
"no_data": "No data available"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"title": "Settings",
|
||||||
|
"general": "General",
|
||||||
|
"store": "Store",
|
||||||
|
"store_name": "Store Name",
|
||||||
|
"store_description": "Store Description",
|
||||||
|
"contact_email": "Contact Email",
|
||||||
|
"contact_phone": "Contact Phone",
|
||||||
|
"business_address": "Business Address",
|
||||||
|
"tax_number": "Tax Number",
|
||||||
|
"currency": "Currency",
|
||||||
|
"timezone": "Timezone",
|
||||||
|
"language": "Language",
|
||||||
|
"language_settings": "Language Settings",
|
||||||
|
"default_language": "Default Language",
|
||||||
|
"dashboard_language": "Dashboard Language",
|
||||||
|
"storefront_language": "Storefront Language",
|
||||||
|
"enabled_languages": "Enabled Languages",
|
||||||
|
"notifications": "Notifications",
|
||||||
|
"email_notifications": "Email Notifications",
|
||||||
|
"integrations": "Integrations",
|
||||||
|
"api_keys": "API Keys",
|
||||||
|
"webhooks": "Webhooks",
|
||||||
|
"save_settings": "Save Settings",
|
||||||
|
"settings_saved": "Settings saved successfully"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"title": "Profile",
|
||||||
|
"my_profile": "My Profile",
|
||||||
|
"edit_profile": "Edit Profile",
|
||||||
|
"personal_info": "Personal Information",
|
||||||
|
"first_name": "First Name",
|
||||||
|
"last_name": "Last Name",
|
||||||
|
"email": "Email",
|
||||||
|
"phone": "Phone",
|
||||||
|
"avatar": "Avatar",
|
||||||
|
"change_avatar": "Change Avatar",
|
||||||
|
"security": "Security",
|
||||||
|
"two_factor": "Two-Factor Authentication",
|
||||||
|
"sessions": "Active Sessions",
|
||||||
|
"preferences": "Preferences",
|
||||||
|
"language_preference": "Language Preference",
|
||||||
|
"save_profile": "Save Profile",
|
||||||
|
"profile_updated": "Profile updated successfully"
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"failed_to_load_dashboard_data": "Failed to load dashboard data",
|
||||||
|
"dashboard_refreshed": "Dashboard refreshed",
|
||||||
|
"item_removed_from_cart": "Item removed from cart",
|
||||||
|
"cart_cleared": "Cart cleared"
|
||||||
|
},
|
||||||
|
"confirmations": {
|
||||||
|
"show_all_menu_items": "This will show all menu items. Continue?",
|
||||||
|
"hide_all_menu_items": "This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?",
|
||||||
|
"reset_email_settings": "This will reset all email settings to use .env defaults. Continue?",
|
||||||
|
"cleanup_logs": "This will delete all logs older than {days} days. Continue?"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,9 @@ function adminMyMenuConfig() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('core');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminMyMenuConfigInitialized) {
|
if (window._adminMyMenuConfigInitialized) {
|
||||||
myMenuConfigLog.warn('Already initialized, skipping');
|
myMenuConfigLog.warn('Already initialized, skipping');
|
||||||
@@ -141,7 +144,7 @@ function adminMyMenuConfig() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async showAll() {
|
async showAll() {
|
||||||
if (!confirm('This will show all menu items. Continue?')) {
|
if (!confirm(I18n.t('core.confirmations.show_all_menu_items'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +166,7 @@ function adminMyMenuConfig() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async resetToDefaults() {
|
async resetToDefaults() {
|
||||||
if (!confirm('This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?')) {
|
if (!confirm(I18n.t('core.confirmations.hide_all_menu_items'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ function adminSettings() {
|
|||||||
testEmailSuccess: null,
|
testEmailSuccess: null,
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('core');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminSettingsInitialized) return;
|
if (window._adminSettingsInitialized) return;
|
||||||
window._adminSettingsInitialized = true;
|
window._adminSettingsInitialized = true;
|
||||||
@@ -434,7 +437,7 @@ function adminSettings() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async resetEmailSettings() {
|
async resetEmailSettings() {
|
||||||
if (!confirm('This will reset all email settings to use .env defaults. Continue?')) {
|
if (!confirm(I18n.t('core.confirmations.reset_email_settings'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,13 +153,13 @@ function shopLayoutData() {
|
|||||||
removeFromCart(productId) {
|
removeFromCart(productId) {
|
||||||
this.cart = this.cart.filter(item => item.id !== productId);
|
this.cart = this.cart.filter(item => item.id !== productId);
|
||||||
this.saveCart();
|
this.saveCart();
|
||||||
this.showToast('Item removed from cart', 'info');
|
this.showToast(I18n.t('core.messages.item_removed_from_cart'), 'info');
|
||||||
},
|
},
|
||||||
|
|
||||||
clearCart() {
|
clearCart() {
|
||||||
this.cart = [];
|
this.cart = [];
|
||||||
this.saveCart();
|
this.saveCart();
|
||||||
this.showToast('Cart cleared', 'info');
|
this.showToast(I18n.t('core.messages.cart_cleared'), 'info');
|
||||||
},
|
},
|
||||||
|
|
||||||
saveCart() {
|
saveCart() {
|
||||||
|
|||||||
@@ -1,122 +1,75 @@
|
|||||||
{
|
{
|
||||||
"title": "Marketplace Integration",
|
"marketplace": {
|
||||||
"description": "Letzshop product and order synchronization",
|
"title": "Marketplace",
|
||||||
"products": {
|
"import": "Import",
|
||||||
"title": "Marketplace Products",
|
"export": "Export",
|
||||||
"subtitle": "Products imported from marketplaces",
|
"sync": "Sync",
|
||||||
"empty": "No products found",
|
"source": "Source",
|
||||||
"empty_search": "No products match your search",
|
"source_url": "Source URL",
|
||||||
"import": "Import Products"
|
"import_products": "Import Products",
|
||||||
},
|
|
||||||
"import": {
|
|
||||||
"title": "Import Products",
|
|
||||||
"subtitle": "Import products from marketplace feeds",
|
|
||||||
"source_url": "Feed URL",
|
|
||||||
"source_url_help": "URL to the marketplace CSV feed",
|
|
||||||
"marketplace": "Marketplace",
|
|
||||||
"language": "Language",
|
|
||||||
"language_help": "Language for product translations",
|
|
||||||
"batch_size": "Batch Size",
|
|
||||||
"start_import": "Start Import",
|
"start_import": "Start Import",
|
||||||
"cancel": "Cancel"
|
"importing": "Importing...",
|
||||||
},
|
"import_complete": "Import Complete",
|
||||||
"import_jobs": {
|
"import_failed": "Import Failed",
|
||||||
"title": "Import History",
|
"import_history": "Import History",
|
||||||
"subtitle": "Past and current import jobs",
|
|
||||||
"empty": "No import jobs",
|
|
||||||
"job_id": "Job ID",
|
"job_id": "Job ID",
|
||||||
"marketplace": "Marketplace",
|
"started_at": "Started At",
|
||||||
"vendor": "Vendor",
|
"completed_at": "Completed At",
|
||||||
"status": "Status",
|
"duration": "Duration",
|
||||||
"imported": "Imported",
|
"imported_count": "Imported",
|
||||||
"updated": "Updated",
|
"error_count": "Errors",
|
||||||
"errors": "Errors",
|
"total_processed": "Total Processed",
|
||||||
"created": "Created",
|
"progress": "Progress",
|
||||||
"completed": "Completed",
|
"no_import_jobs": "No import jobs yet",
|
||||||
"statuses": {
|
"start_first_import": "Start your first import using the form above"
|
||||||
"pending": "Pending",
|
|
||||||
"processing": "Processing",
|
|
||||||
"completed": "Completed",
|
|
||||||
"completed_with_errors": "Completed with Errors",
|
|
||||||
"failed": "Failed"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"letzshop": {
|
"letzshop": {
|
||||||
"title": "Letzshop Integration",
|
"title": "Letzshop Integration",
|
||||||
"subtitle": "Manage Letzshop connection and sync",
|
"connection": "Connection",
|
||||||
"credentials": {
|
"credentials": "Credentials",
|
||||||
"title": "API Credentials",
|
"api_key": "API Key",
|
||||||
"api_key": "API Key",
|
"api_endpoint": "API Endpoint",
|
||||||
"api_key_help": "Your Letzshop API key",
|
"auto_sync": "Auto Sync",
|
||||||
"endpoint": "API Endpoint",
|
"sync_interval": "Sync Interval",
|
||||||
"test_mode": "Test Mode",
|
"every_hour": "Every hour",
|
||||||
"test_mode_help": "When enabled, no changes are made to Letzshop"
|
"every_day": "Every day",
|
||||||
},
|
"test_connection": "Test Connection",
|
||||||
"sync": {
|
"save_credentials": "Save Credentials",
|
||||||
"title": "Synchronization",
|
"connection_success": "Connection successful",
|
||||||
"auto_sync": "Auto Sync",
|
"connection_failed": "Connection failed",
|
||||||
"auto_sync_help": "Automatically sync orders from Letzshop",
|
"last_sync": "Last Sync",
|
||||||
"interval": "Sync Interval",
|
"sync_status": "Sync Status",
|
||||||
"interval_help": "Minutes between syncs",
|
"import_orders": "Import Orders",
|
||||||
"last_sync": "Last Sync",
|
"export_products": "Export Products",
|
||||||
"last_status": "Last Status",
|
"no_credentials": "Configure your API key in Settings to get started",
|
||||||
"sync_now": "Sync Now"
|
"carriers": {
|
||||||
},
|
"dhl": "DHL",
|
||||||
"carrier": {
|
"ups": "UPS",
|
||||||
"title": "Carrier Settings",
|
"fedex": "FedEx",
|
||||||
"default_carrier": "Default Carrier",
|
"dpd": "DPD",
|
||||||
"greco": "Greco",
|
"gls": "GLS",
|
||||||
"colissimo": "Colissimo",
|
"post_luxembourg": "Post Luxembourg",
|
||||||
"xpresslogistics": "XpressLogistics",
|
"other": "Other"
|
||||||
"label_url": "Label URL Prefix"
|
|
||||||
},
|
|
||||||
"historical": {
|
|
||||||
"title": "Historical Import",
|
|
||||||
"subtitle": "Import past orders from Letzshop",
|
|
||||||
"start_import": "Start Historical Import",
|
|
||||||
"phase": "Phase",
|
|
||||||
"confirmed": "Confirmed Orders",
|
|
||||||
"unconfirmed": "Unconfirmed Orders",
|
|
||||||
"fetching": "Fetching...",
|
|
||||||
"processing": "Processing...",
|
|
||||||
"page": "Page",
|
|
||||||
"fetched": "Fetched",
|
|
||||||
"processed": "Processed",
|
|
||||||
"imported": "Imported",
|
|
||||||
"updated": "Updated",
|
|
||||||
"skipped": "Skipped"
|
|
||||||
},
|
|
||||||
"vendors": {
|
|
||||||
"title": "Vendor Directory",
|
|
||||||
"subtitle": "Browse Letzshop vendors",
|
|
||||||
"claim": "Claim",
|
|
||||||
"claimed": "Claimed",
|
|
||||||
"unclaimed": "Unclaimed",
|
|
||||||
"last_synced": "Last synced"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"export": {
|
|
||||||
"title": "Export Products",
|
|
||||||
"subtitle": "Export products to marketplace format",
|
|
||||||
"format": "Format",
|
|
||||||
"format_csv": "CSV",
|
|
||||||
"format_xml": "XML",
|
|
||||||
"download": "Download Export"
|
|
||||||
},
|
|
||||||
"messages": {
|
"messages": {
|
||||||
"import_started": "Import started successfully",
|
"no_error_details_available": "No error details available",
|
||||||
"import_completed": "Import completed",
|
"failed_to_load_error_details": "Failed to load error details",
|
||||||
"import_failed": "Import failed",
|
"copied_to_clipboard": "Copied to clipboard",
|
||||||
"credentials_saved": "Credentials saved successfully",
|
"failed_to_copy_to_clipboard": "Failed to copy to clipboard",
|
||||||
"sync_started": "Sync started",
|
"please_configure_api_key_first": "Please configure your API key first",
|
||||||
"sync_completed": "Sync completed",
|
"please_enter_api_key": "Please enter an API key",
|
||||||
"sync_failed": "Sync failed",
|
"please_fill_in_all_fields": "Please fill in all fields"
|
||||||
"export_ready": "Export ready for download",
|
|
||||||
"error_loading": "Error loading data"
|
|
||||||
},
|
},
|
||||||
"filters": {
|
"confirmations": {
|
||||||
"all_marketplaces": "All Marketplaces",
|
"remove_letzshop_credentials": "Are you sure you want to remove your Letzshop credentials?",
|
||||||
"all_vendors": "All Vendors",
|
"confirm_order": "Confirm this order?",
|
||||||
"search_placeholder": "Search products..."
|
"reject_order": "Reject this order? This action cannot be undone.",
|
||||||
|
"remove_letzshop_config_vendor": "Are you sure you want to remove Letzshop configuration for this vendor?",
|
||||||
|
"decline_order": "Are you sure you want to decline this order? All items will be marked as unavailable.",
|
||||||
|
"confirm_all_items": "Are you sure you want to confirm all items in this order?",
|
||||||
|
"decline_all_items": "Are you sure you want to decline all items in this order?",
|
||||||
|
"remove_letzshop_config": "Are you sure you want to remove the Letzshop configuration? This will disable all Letzshop features for this vendor.",
|
||||||
|
"ignore_exception": "Are you sure you want to ignore this exception? The order will still be blocked from confirmation."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ function adminLetzshop() {
|
|||||||
vendorOrders: [],
|
vendorOrders: [],
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('marketplace');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminLetzshopInitialized) {
|
if (window._adminLetzshopInitialized) {
|
||||||
return;
|
return;
|
||||||
@@ -188,7 +191,7 @@ function adminLetzshop() {
|
|||||||
* Delete vendor configuration
|
* Delete vendor configuration
|
||||||
*/
|
*/
|
||||||
async deleteVendorConfig() {
|
async deleteVendorConfig() {
|
||||||
if (!confirm('Are you sure you want to remove Letzshop configuration for this vendor?')) {
|
if (!confirm(I18n.t('marketplace.confirmations.remove_letzshop_config_vendor'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,9 @@ function adminMarketplaceLetzshop() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('marketplace');
|
||||||
|
|
||||||
marketplaceLetzshopLog.info('init() called');
|
marketplaceLetzshopLog.info('init() called');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
@@ -1007,7 +1010,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
async declineOrder(order) {
|
async declineOrder(order) {
|
||||||
if (!this.selectedVendor) return;
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to decline this order? All items will be marked as unavailable.')) return;
|
if (!confirm(I18n.t('marketplace.confirmations.decline_order'))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/reject`);
|
await apiClient.post(`/admin/letzshop/vendors/${this.selectedVendor.id}/orders/${order.id}/reject`);
|
||||||
@@ -1125,7 +1128,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
async confirmAllItems(order) {
|
async confirmAllItems(order) {
|
||||||
if (!this.selectedVendor) return;
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to confirm all items in this order?')) return;
|
if (!confirm(I18n.t('marketplace.confirmations.confirm_all_items'))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(
|
await apiClient.post(
|
||||||
@@ -1146,7 +1149,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
async declineAllItems(order) {
|
async declineAllItems(order) {
|
||||||
if (!this.selectedVendor) return;
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to decline all items in this order?')) return;
|
if (!confirm(I18n.t('marketplace.confirmations.decline_all_items'))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(
|
await apiClient.post(
|
||||||
@@ -1238,7 +1241,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
async deleteCredentials() {
|
async deleteCredentials() {
|
||||||
if (!this.selectedVendor) return;
|
if (!this.selectedVendor) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to remove the Letzshop configuration? This will disable all Letzshop features for this vendor.')) {
|
if (!confirm(I18n.t('marketplace.confirmations.remove_letzshop_config'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1456,7 +1459,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
* Ignore an exception
|
* Ignore an exception
|
||||||
*/
|
*/
|
||||||
async ignoreException(exception) {
|
async ignoreException(exception) {
|
||||||
if (!confirm('Are you sure you want to ignore this exception? The order will still be blocked from confirmation.')) {
|
if (!confirm(I18n.t('marketplace.confirmations.ignore_exception'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1540,7 +1543,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
if (job.type === 'import') {
|
if (job.type === 'import') {
|
||||||
const errors = response.errors || [];
|
const errors = response.errors || [];
|
||||||
if (errors.length === 0) {
|
if (errors.length === 0) {
|
||||||
Utils.showToast('No error details available', 'info');
|
Utils.showToast(I18n.t('marketplace.messages.no_error_details_available'), 'info');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Store errors and show in job details modal
|
// Store errors and show in job details modal
|
||||||
@@ -1553,7 +1556,7 @@ function adminMarketplaceLetzshop() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
marketplaceLetzshopLog.error('Failed to load job errors:', error);
|
marketplaceLetzshopLog.error('Failed to load job errors:', error);
|
||||||
Utils.showToast('Failed to load error details', 'error');
|
Utils.showToast(I18n.t('marketplace.messages.failed_to_load_error_details'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ function vendorLetzshop() {
|
|||||||
exporting: false,
|
exporting: false,
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('marketplace');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._vendorLetzshopInitialized) {
|
if (window._vendorLetzshopInitialized) {
|
||||||
return;
|
return;
|
||||||
@@ -196,7 +199,7 @@ function vendorLetzshop() {
|
|||||||
*/
|
*/
|
||||||
async importOrders() {
|
async importOrders() {
|
||||||
if (!this.status.is_configured) {
|
if (!this.status.is_configured) {
|
||||||
this.error = 'Please configure your API key first';
|
this.error = I18n.t('marketplace.messages.please_configure_api_key_first');
|
||||||
this.activeTab = 'settings';
|
this.activeTab = 'settings';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -229,7 +232,7 @@ function vendorLetzshop() {
|
|||||||
*/
|
*/
|
||||||
async saveCredentials() {
|
async saveCredentials() {
|
||||||
if (!this.credentialsForm.api_key && !this.credentials) {
|
if (!this.credentialsForm.api_key && !this.credentials) {
|
||||||
this.error = 'Please enter an API key';
|
this.error = I18n.t('marketplace.messages.please_enter_api_key');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +291,7 @@ function vendorLetzshop() {
|
|||||||
* Delete credentials
|
* Delete credentials
|
||||||
*/
|
*/
|
||||||
async deleteCredentials() {
|
async deleteCredentials() {
|
||||||
if (!confirm('Are you sure you want to remove your Letzshop credentials?')) {
|
if (!confirm(I18n.t('marketplace.confirmations.remove_letzshop_credentials'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +316,7 @@ function vendorLetzshop() {
|
|||||||
* Confirm order
|
* Confirm order
|
||||||
*/
|
*/
|
||||||
async confirmOrder(order) {
|
async confirmOrder(order) {
|
||||||
if (!confirm('Confirm this order?')) {
|
if (!confirm(I18n.t('marketplace.confirmations.confirm_order'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +340,7 @@ function vendorLetzshop() {
|
|||||||
* Reject order
|
* Reject order
|
||||||
*/
|
*/
|
||||||
async rejectOrder(order) {
|
async rejectOrder(order) {
|
||||||
if (!confirm('Reject this order? This action cannot be undone.')) {
|
if (!confirm(I18n.t('marketplace.confirmations.reject_order'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +377,7 @@ function vendorLetzshop() {
|
|||||||
*/
|
*/
|
||||||
async submitTracking() {
|
async submitTracking() {
|
||||||
if (!this.trackingForm.tracking_number || !this.trackingForm.tracking_carrier) {
|
if (!this.trackingForm.tracking_number || !this.trackingForm.tracking_carrier) {
|
||||||
this.error = 'Please fill in all fields';
|
this.error = I18n.t('marketplace.messages.please_fill_in_all_fields');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,49 @@
|
|||||||
{}
|
{
|
||||||
|
"notifications": {
|
||||||
|
"title": "Notifications",
|
||||||
|
"mark_read": "Mark as Read",
|
||||||
|
"mark_all_read": "Mark All as Read",
|
||||||
|
"no_notifications": "No notifications",
|
||||||
|
"new_order": "New Order",
|
||||||
|
"order_updated": "Order Updated",
|
||||||
|
"low_stock": "Low Stock Alert",
|
||||||
|
"import_complete": "Import Complete",
|
||||||
|
"import_failed": "Import Failed"
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"failed_to_load_template": "Failed to load template",
|
||||||
|
"template_saved_successfully": "Template saved successfully",
|
||||||
|
"reverted_to_platform_default": "Reverted to platform default",
|
||||||
|
"failed_to_load_preview": "Failed to load preview",
|
||||||
|
"failed_to_send_test_email": "Failed to send test email",
|
||||||
|
"failed_to_load_conversations": "Failed to load conversations",
|
||||||
|
"failed_to_load_conversation": "Failed to load conversation",
|
||||||
|
"conversation_closed": "Conversation closed",
|
||||||
|
"failed_to_close_conversation": "Failed to close conversation",
|
||||||
|
"conversation_reopened": "Conversation reopened",
|
||||||
|
"failed_to_reopen_conversation": "Failed to reopen conversation",
|
||||||
|
"conversation_created": "Conversation created",
|
||||||
|
"notification_marked_as_read": "Notification marked as read",
|
||||||
|
"all_notifications_marked_as_read": "All notifications marked as read",
|
||||||
|
"notification_deleted": "Notification deleted",
|
||||||
|
"notification_settings_saved": "Notification settings saved",
|
||||||
|
"failed_to_load_templates": "Failed to load templates",
|
||||||
|
"failed_to_load_recipients": "Failed to load recipients",
|
||||||
|
"failed_to_load_notifications": "Failed to load notifications",
|
||||||
|
"failed_to_mark_notification_as_read": "Failed to mark notification as read",
|
||||||
|
"failed_to_mark_all_as_read": "Failed to mark all as read",
|
||||||
|
"failed_to_delete_notification": "Failed to delete notification",
|
||||||
|
"failed_to_load_alerts": "Failed to load alerts",
|
||||||
|
"alert_resolved_successfully": "Alert resolved successfully",
|
||||||
|
"failed_to_resolve_alert": "Failed to resolve alert",
|
||||||
|
"no_template_for_language": "No template for {language} - create one by saving",
|
||||||
|
"failed_to_save_template": "Failed to save template",
|
||||||
|
"test_email_sent": "Test email sent to {email}"
|
||||||
|
},
|
||||||
|
"confirmations": {
|
||||||
|
"delete_notification": "Are you sure you want to delete this notification?",
|
||||||
|
"close_conversation": "Close this conversation?",
|
||||||
|
"close_conversation_admin": "Are you sure you want to close this conversation?",
|
||||||
|
"delete_customization": "Are you sure you want to delete your customization and revert to the platform default?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ function adminMessages(initialConversationId = null) {
|
|||||||
* Initialize component
|
* Initialize component
|
||||||
*/
|
*/
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('messaging');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminMessagesInitialized) return;
|
if (window._adminMessagesInitialized) return;
|
||||||
window._adminMessagesInitialized = true;
|
window._adminMessagesInitialized = true;
|
||||||
@@ -141,7 +144,7 @@ function adminMessages(initialConversationId = null) {
|
|||||||
messagesLog.debug(`Loaded ${this.conversations.length} conversations`);
|
messagesLog.debug(`Loaded ${this.conversations.length} conversations`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to load conversations:', error);
|
messagesLog.error('Failed to load conversations:', error);
|
||||||
Utils.showToast('Failed to load conversations', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_conversations'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingConversations = false;
|
this.loadingConversations = false;
|
||||||
}
|
}
|
||||||
@@ -197,7 +200,7 @@ function adminMessages(initialConversationId = null) {
|
|||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to load conversation:', error);
|
messagesLog.error('Failed to load conversation:', error);
|
||||||
Utils.showToast('Failed to load conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_conversation'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingMessages = false;
|
this.loadingMessages = false;
|
||||||
}
|
}
|
||||||
@@ -301,7 +304,7 @@ function adminMessages(initialConversationId = null) {
|
|||||||
* Close conversation
|
* Close conversation
|
||||||
*/
|
*/
|
||||||
async closeConversation() {
|
async closeConversation() {
|
||||||
if (!confirm('Are you sure you want to close this conversation?')) return;
|
if (!confirm(I18n.t('messaging.confirmations.close_conversation_admin'))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(`/admin/messages/${this.selectedConversationId}/close`);
|
await apiClient.post(`/admin/messages/${this.selectedConversationId}/close`);
|
||||||
@@ -316,10 +319,10 @@ function adminMessages(initialConversationId = null) {
|
|||||||
conv.is_closed = true;
|
conv.is_closed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.showToast('Conversation closed', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_closed'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to close conversation:', error);
|
messagesLog.error('Failed to close conversation:', error);
|
||||||
Utils.showToast('Failed to close conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_close_conversation'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -340,10 +343,10 @@ function adminMessages(initialConversationId = null) {
|
|||||||
conv.is_closed = false;
|
conv.is_closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.showToast('Conversation reopened', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_reopened'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to reopen conversation:', error);
|
messagesLog.error('Failed to reopen conversation:', error);
|
||||||
Utils.showToast('Failed to reopen conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_reopen_conversation'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -367,7 +370,7 @@ function adminMessages(initialConversationId = null) {
|
|||||||
messagesLog.debug(`Loaded ${this.recipients.length} recipients`);
|
messagesLog.debug(`Loaded ${this.recipients.length} recipients`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to load recipients:', error);
|
messagesLog.error('Failed to load recipients:', error);
|
||||||
Utils.showToast('Failed to load recipients', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_recipients'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingRecipients = false;
|
this.loadingRecipients = false;
|
||||||
}
|
}
|
||||||
@@ -416,7 +419,7 @@ function adminMessages(initialConversationId = null) {
|
|||||||
await this.loadConversations();
|
await this.loadConversations();
|
||||||
await this.selectConversation(response.id);
|
await this.selectConversation(response.id);
|
||||||
|
|
||||||
Utils.showToast('Conversation created', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_created'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to create conversation:', error);
|
messagesLog.error('Failed to create conversation:', error);
|
||||||
Utils.showToast(error.message || 'Failed to create conversation', 'error');
|
Utils.showToast(error.message || 'Failed to create conversation', 'error');
|
||||||
|
|||||||
@@ -71,6 +71,9 @@ function adminNotifications() {
|
|||||||
* Initialize component
|
* Initialize component
|
||||||
*/
|
*/
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('messaging');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminNotificationsInitialized) return;
|
if (window._adminNotificationsInitialized) return;
|
||||||
window._adminNotificationsInitialized = true;
|
window._adminNotificationsInitialized = true;
|
||||||
@@ -114,7 +117,7 @@ function adminNotifications() {
|
|||||||
notificationsLog.debug(`Loaded ${this.notifications.length} notifications`);
|
notificationsLog.debug(`Loaded ${this.notifications.length} notifications`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to load notifications:', error);
|
notificationsLog.error('Failed to load notifications:', error);
|
||||||
Utils.showToast('Failed to load notifications', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_notifications'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingNotifications = false;
|
this.loadingNotifications = false;
|
||||||
}
|
}
|
||||||
@@ -131,10 +134,10 @@ function adminNotifications() {
|
|||||||
notification.is_read = true;
|
notification.is_read = true;
|
||||||
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
||||||
|
|
||||||
Utils.showToast('Notification marked as read', 'success');
|
Utils.showToast(I18n.t('messaging.messages.notification_marked_as_read'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to mark as read:', error);
|
notificationsLog.error('Failed to mark as read:', error);
|
||||||
Utils.showToast('Failed to mark notification as read', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_mark_notification_as_read'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -149,10 +152,10 @@ function adminNotifications() {
|
|||||||
this.notifications.forEach(n => n.is_read = true);
|
this.notifications.forEach(n => n.is_read = true);
|
||||||
this.stats.unread_count = 0;
|
this.stats.unread_count = 0;
|
||||||
|
|
||||||
Utils.showToast('All notifications marked as read', 'success');
|
Utils.showToast(I18n.t('messaging.messages.all_notifications_marked_as_read'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to mark all as read:', error);
|
notificationsLog.error('Failed to mark all as read:', error);
|
||||||
Utils.showToast('Failed to mark all as read', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_mark_all_as_read'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -160,7 +163,7 @@ function adminNotifications() {
|
|||||||
* Delete notification
|
* Delete notification
|
||||||
*/
|
*/
|
||||||
async deleteNotification(notificationId) {
|
async deleteNotification(notificationId) {
|
||||||
if (!confirm('Are you sure you want to delete this notification?')) {
|
if (!confirm(I18n.t('messaging.confirmations.delete_notification'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,10 +178,10 @@ function adminNotifications() {
|
|||||||
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.showToast('Notification deleted', 'success');
|
Utils.showToast(I18n.t('messaging.messages.notification_deleted'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to delete notification:', error);
|
notificationsLog.error('Failed to delete notification:', error);
|
||||||
Utils.showToast('Failed to delete notification', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_delete_notification'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -225,7 +228,7 @@ function adminNotifications() {
|
|||||||
notificationsLog.debug(`Loaded ${this.alerts.length} alerts`);
|
notificationsLog.debug(`Loaded ${this.alerts.length} alerts`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to load alerts:', error);
|
notificationsLog.error('Failed to load alerts:', error);
|
||||||
Utils.showToast('Failed to load alerts', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_alerts'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingAlerts = false;
|
this.loadingAlerts = false;
|
||||||
}
|
}
|
||||||
@@ -272,10 +275,10 @@ function adminNotifications() {
|
|||||||
}
|
}
|
||||||
this.alertStats.resolved_today++;
|
this.alertStats.resolved_today++;
|
||||||
|
|
||||||
Utils.showToast('Alert resolved successfully', 'success');
|
Utils.showToast(I18n.t('messaging.messages.alert_resolved_successfully'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notificationsLog.error('Failed to resolve alert:', error);
|
notificationsLog.error('Failed to resolve alert:', error);
|
||||||
Utils.showToast('Failed to resolve alert', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_resolve_alert'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,9 @@ function vendorEmailTemplates() {
|
|||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('messaging');
|
||||||
|
|
||||||
if (window._vendorEmailTemplatesInitialized) return;
|
if (window._vendorEmailTemplatesInitialized) return;
|
||||||
window._vendorEmailTemplatesInitialized = true;
|
window._vendorEmailTemplatesInitialized = true;
|
||||||
|
|
||||||
@@ -134,7 +137,7 @@ function vendorEmailTemplates() {
|
|||||||
Utils.showToast(`No template available for ${this.editLanguage.toUpperCase()}`, 'info');
|
Utils.showToast(`No template available for ${this.editLanguage.toUpperCase()}`, 'info');
|
||||||
} else {
|
} else {
|
||||||
vendorEmailTemplatesLog.error('Failed to load template:', error);
|
vendorEmailTemplatesLog.error('Failed to load template:', error);
|
||||||
Utils.showToast('Failed to load template', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_template'), 'error');
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingTemplate = false;
|
this.loadingTemplate = false;
|
||||||
@@ -166,7 +169,7 @@ function vendorEmailTemplates() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Utils.showToast('Template saved successfully', 'success');
|
Utils.showToast(I18n.t('messaging.messages.template_saved_successfully'), 'success');
|
||||||
this.templateSource = 'vendor_override';
|
this.templateSource = 'vendor_override';
|
||||||
// Refresh list to show updated status
|
// Refresh list to show updated status
|
||||||
await this.loadData();
|
await this.loadData();
|
||||||
@@ -181,7 +184,7 @@ function vendorEmailTemplates() {
|
|||||||
async revertToDefault() {
|
async revertToDefault() {
|
||||||
if (!this.editingTemplate) return;
|
if (!this.editingTemplate) return;
|
||||||
|
|
||||||
if (!confirm('Are you sure you want to delete your customization and revert to the platform default?')) {
|
if (!confirm(I18n.t('messaging.confirmations.delete_customization'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,7 +195,7 @@ function vendorEmailTemplates() {
|
|||||||
`/vendor/email-templates/${this.editingTemplate.code}/${this.editLanguage}`
|
`/vendor/email-templates/${this.editingTemplate.code}/${this.editLanguage}`
|
||||||
);
|
);
|
||||||
|
|
||||||
Utils.showToast('Reverted to platform default', 'success');
|
Utils.showToast(I18n.t('messaging.messages.reverted_to_platform_default'), 'success');
|
||||||
// Reload the template to show platform version
|
// Reload the template to show platform version
|
||||||
await this.loadTemplateLanguage();
|
await this.loadTemplateLanguage();
|
||||||
// Refresh list
|
// Refresh list
|
||||||
@@ -222,7 +225,7 @@ function vendorEmailTemplates() {
|
|||||||
this.showPreviewModal = true;
|
this.showPreviewModal = true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorEmailTemplatesLog.error('Failed to preview template:', error);
|
vendorEmailTemplatesLog.error('Failed to preview template:', error);
|
||||||
Utils.showToast('Failed to load preview', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_preview'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -255,7 +258,7 @@ function vendorEmailTemplates() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorEmailTemplatesLog.error('Failed to send test email:', error);
|
vendorEmailTemplatesLog.error('Failed to send test email:', error);
|
||||||
Utils.showToast('Failed to send test email', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_send_test_email'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.sendingTest = false;
|
this.sendingTest = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
* Initialize component
|
* Initialize component
|
||||||
*/
|
*/
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('messaging');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._vendorMessagesInitialized) return;
|
if (window._vendorMessagesInitialized) return;
|
||||||
window._vendorMessagesInitialized = true;
|
window._vendorMessagesInitialized = true;
|
||||||
@@ -143,7 +146,7 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
messagesLog.debug(`Loaded ${this.conversations.length} conversations`);
|
messagesLog.debug(`Loaded ${this.conversations.length} conversations`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to load conversations:', error);
|
messagesLog.error('Failed to load conversations:', error);
|
||||||
Utils.showToast('Failed to load conversations', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_conversations'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingConversations = false;
|
this.loadingConversations = false;
|
||||||
}
|
}
|
||||||
@@ -192,7 +195,7 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
this.scrollToBottom();
|
this.scrollToBottom();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to load conversation:', error);
|
messagesLog.error('Failed to load conversation:', error);
|
||||||
Utils.showToast('Failed to load conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_load_conversation'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.loadingMessages = false;
|
this.loadingMessages = false;
|
||||||
}
|
}
|
||||||
@@ -276,7 +279,7 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
* Close conversation
|
* Close conversation
|
||||||
*/
|
*/
|
||||||
async closeConversation() {
|
async closeConversation() {
|
||||||
if (!confirm('Close this conversation?')) return;
|
if (!confirm(I18n.t('messaging.confirmations.close_conversation'))) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await apiClient.post(`/vendor/messages/${this.selectedConversationId}/close`);
|
await apiClient.post(`/vendor/messages/${this.selectedConversationId}/close`);
|
||||||
@@ -288,10 +291,10 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
const conv = this.conversations.find(c => c.id === this.selectedConversationId);
|
const conv = this.conversations.find(c => c.id === this.selectedConversationId);
|
||||||
if (conv) conv.is_closed = true;
|
if (conv) conv.is_closed = true;
|
||||||
|
|
||||||
Utils.showToast('Conversation closed', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_closed'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to close conversation:', error);
|
messagesLog.error('Failed to close conversation:', error);
|
||||||
Utils.showToast('Failed to close conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_close_conversation'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -309,10 +312,10 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
const conv = this.conversations.find(c => c.id === this.selectedConversationId);
|
const conv = this.conversations.find(c => c.id === this.selectedConversationId);
|
||||||
if (conv) conv.is_closed = false;
|
if (conv) conv.is_closed = false;
|
||||||
|
|
||||||
Utils.showToast('Conversation reopened', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_reopened'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to reopen conversation:', error);
|
messagesLog.error('Failed to reopen conversation:', error);
|
||||||
Utils.showToast('Failed to reopen conversation', 'error');
|
Utils.showToast(I18n.t('messaging.messages.failed_to_reopen_conversation'), 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -356,7 +359,7 @@ function vendorMessages(initialConversationId = null) {
|
|||||||
await this.loadConversations();
|
await this.loadConversations();
|
||||||
await this.selectConversation(response.id);
|
await this.selectConversation(response.id);
|
||||||
|
|
||||||
Utils.showToast('Conversation created', 'success');
|
Utils.showToast(I18n.t('messaging.messages.conversation_created'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
messagesLog.error('Failed to create conversation:', error);
|
messagesLog.error('Failed to create conversation:', error);
|
||||||
Utils.showToast(error.message || 'Failed to create conversation', 'error');
|
Utils.showToast(error.message || 'Failed to create conversation', 'error');
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ function vendorNotifications() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('messaging');
|
||||||
|
|
||||||
vendorNotificationsLog.info('Notifications init() called');
|
vendorNotificationsLog.info('Notifications init() called');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
@@ -121,7 +124,7 @@ function vendorNotifications() {
|
|||||||
notification.is_read = true;
|
notification.is_read = true;
|
||||||
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
||||||
|
|
||||||
Utils.showToast('Notification marked as read', 'success');
|
Utils.showToast(I18n.t('messaging.messages.notification_marked_as_read'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorNotificationsLog.error('Failed to mark as read:', error);
|
vendorNotificationsLog.error('Failed to mark as read:', error);
|
||||||
Utils.showToast(error.message || 'Failed to mark notification as read', 'error');
|
Utils.showToast(error.message || 'Failed to mark notification as read', 'error');
|
||||||
@@ -139,7 +142,7 @@ function vendorNotifications() {
|
|||||||
this.notifications.forEach(n => n.is_read = true);
|
this.notifications.forEach(n => n.is_read = true);
|
||||||
this.stats.unread_count = 0;
|
this.stats.unread_count = 0;
|
||||||
|
|
||||||
Utils.showToast('All notifications marked as read', 'success');
|
Utils.showToast(I18n.t('messaging.messages.all_notifications_marked_as_read'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorNotificationsLog.error('Failed to mark all as read:', error);
|
vendorNotificationsLog.error('Failed to mark all as read:', error);
|
||||||
Utils.showToast(error.message || 'Failed to mark all as read', 'error');
|
Utils.showToast(error.message || 'Failed to mark all as read', 'error');
|
||||||
@@ -150,7 +153,7 @@ function vendorNotifications() {
|
|||||||
* Delete notification
|
* Delete notification
|
||||||
*/
|
*/
|
||||||
async deleteNotification(notificationId) {
|
async deleteNotification(notificationId) {
|
||||||
if (!confirm('Are you sure you want to delete this notification?')) {
|
if (!confirm(I18n.t('messaging.confirmations.delete_notification'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +168,7 @@ function vendorNotifications() {
|
|||||||
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
this.stats.unread_count = Math.max(0, this.stats.unread_count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils.showToast('Notification deleted', 'success');
|
Utils.showToast(I18n.t('messaging.messages.notification_deleted'), 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorNotificationsLog.error('Failed to delete notification:', error);
|
vendorNotificationsLog.error('Failed to delete notification:', error);
|
||||||
Utils.showToast(error.message || 'Failed to delete notification', 'error');
|
Utils.showToast(error.message || 'Failed to delete notification', 'error');
|
||||||
@@ -195,7 +198,7 @@ function vendorNotifications() {
|
|||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
try {
|
try {
|
||||||
await apiClient.put(`/vendor/notifications/settings`, this.settingsForm);
|
await apiClient.put(`/vendor/notifications/settings`, this.settingsForm);
|
||||||
Utils.showToast('Notification settings saved', 'success');
|
Utils.showToast(I18n.t('messaging.messages.notification_settings_saved'), 'success');
|
||||||
this.showSettingsModal = false;
|
this.showSettingsModal = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
vendorNotificationsLog.error('Failed to save settings:', error);
|
vendorNotificationsLog.error('Failed to save settings:', error);
|
||||||
|
|||||||
88
app/modules/tenancy/locales/en.json
Normal file
88
app/modules/tenancy/locales/en.json
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
{
|
||||||
|
"team": {
|
||||||
|
"title": "Team",
|
||||||
|
"members": "Members",
|
||||||
|
"add_member": "Add Member",
|
||||||
|
"invite_member": "Invite Member",
|
||||||
|
"remove_member": "Remove Member",
|
||||||
|
"role": "Role",
|
||||||
|
"owner": "Owner",
|
||||||
|
"manager": "Manager",
|
||||||
|
"editor": "Editor",
|
||||||
|
"viewer": "Viewer",
|
||||||
|
"permissions": "Permissions",
|
||||||
|
"pending_invitations": "Pending Invitations",
|
||||||
|
"invitation_sent": "Invitation Sent",
|
||||||
|
"invitation_accepted": "Invitation Accepted"
|
||||||
|
},
|
||||||
|
"messages": {
|
||||||
|
"business_info_saved": "Business info saved",
|
||||||
|
"marketplace_settings_saved": "Marketplace settings saved",
|
||||||
|
"please_enter_a_url_first": "Please enter a URL first",
|
||||||
|
"could_not_validate_url_it_may_still_work": "Could not validate URL - it may still work",
|
||||||
|
"localization_settings_saved": "Localization settings saved",
|
||||||
|
"failed_to_load_email_settings": "Failed to load email settings",
|
||||||
|
"from_email_and_from_name_are_required": "From Email and From Name are required",
|
||||||
|
"email_settings_saved": "Email settings saved",
|
||||||
|
"please_enter_a_test_email_address": "Please enter a test email address",
|
||||||
|
"please_save_your_email_settings_first": "Please save your email settings first",
|
||||||
|
"test_email_sent_check_your_inbox": "Test email sent! Check your inbox.",
|
||||||
|
"please_fix_the_errors_before_saving": "Please fix the errors before saving",
|
||||||
|
"profile_updated_successfully": "Profile updated successfully",
|
||||||
|
"email_is_required": "Email is required",
|
||||||
|
"invitation_sent_successfully": "Invitation sent successfully",
|
||||||
|
"team_member_updated": "Team member updated",
|
||||||
|
"team_member_removed": "Team member removed",
|
||||||
|
"invalid_company_url": "Invalid company URL",
|
||||||
|
"failed_to_load_company_details": "Failed to load company details",
|
||||||
|
"company_deleted_successfully": "Company deleted successfully",
|
||||||
|
"company_details_refreshed": "Company details refreshed",
|
||||||
|
"invalid_admin_user_url": "Invalid admin user URL",
|
||||||
|
"failed_to_load_admin_user_details": "Failed to load admin user details",
|
||||||
|
"you_cannot_deactivate_your_own_account": "You cannot deactivate your own account",
|
||||||
|
"you_cannot_delete_your_own_account": "You cannot delete your own account",
|
||||||
|
"admin_user_deleted_successfully": "Admin user deleted successfully",
|
||||||
|
"admin_user_details_refreshed": "Admin user details refreshed",
|
||||||
|
"failed_to_initialize_page": "Failed to initialize page",
|
||||||
|
"failed_to_load_company": "Failed to load company",
|
||||||
|
"company_updated_successfully": "Company updated successfully",
|
||||||
|
"ownership_transferred_successfully": "Ownership transferred successfully",
|
||||||
|
"theme_saved_successfully": "Theme saved successfully",
|
||||||
|
"failed_to_apply_preset": "Failed to apply preset",
|
||||||
|
"theme_reset_to_default": "Theme reset to default",
|
||||||
|
"failed_to_reset_theme": "Failed to reset theme",
|
||||||
|
"failed_to_load_vendors": "Failed to load vendors",
|
||||||
|
"vendor_deleted_successfully": "Vendor deleted successfully",
|
||||||
|
"vendors_list_refreshed": "Vendors list refreshed",
|
||||||
|
"invalid_user_url": "Invalid user URL",
|
||||||
|
"failed_to_load_user_details": "Failed to load user details",
|
||||||
|
"user_deleted_successfully": "User deleted successfully",
|
||||||
|
"user_details_refreshed": "User details refreshed",
|
||||||
|
"invalid_vendor_url": "Invalid vendor URL",
|
||||||
|
"failed_to_load_vendor_details": "Failed to load vendor details",
|
||||||
|
"no_vendor_loaded": "No vendor loaded",
|
||||||
|
"subscription_created_successfully": "Subscription created successfully",
|
||||||
|
"vendor_details_refreshed": "Vendor details refreshed",
|
||||||
|
"failed_to_load_users": "Failed to load users",
|
||||||
|
"failed_to_delete_user": "Failed to delete user",
|
||||||
|
"failed_to_load_admin_users": "Failed to load admin users",
|
||||||
|
"failed_to_load_admin_user": "Failed to load admin user",
|
||||||
|
"you_cannot_demote_yourself_from_super_ad": "You cannot demote yourself from super admin",
|
||||||
|
"platform_assigned_successfully": "Platform assigned successfully",
|
||||||
|
"platform_admin_must_be_assigned_to_at_le": "Platform admin must be assigned to at least one platform",
|
||||||
|
"platform_removed_successfully": "Platform removed successfully",
|
||||||
|
"please_fix_the_errors_before_submitting": "Please fix the errors before submitting",
|
||||||
|
"failed_to_load_vendor": "Failed to load vendor",
|
||||||
|
"vendor_updated_successfully": "Vendor updated successfully",
|
||||||
|
"all_contact_fields_reset_to_company_defa": "All contact fields reset to company defaults",
|
||||||
|
"failed_to_load_user": "Failed to load user",
|
||||||
|
"user_updated_successfully": "User updated successfully"
|
||||||
|
},
|
||||||
|
"confirmations": {
|
||||||
|
"enable_all_modules": "This will enable all modules. Continue?",
|
||||||
|
"disable_optional_modules": "This will disable all optional modules, keeping only core modules. Continue?",
|
||||||
|
"reset_theme": "Reset theme to default? This cannot be undone.",
|
||||||
|
"show_all_menu_items": "This will show all menu items. Continue?",
|
||||||
|
"hide_all_menu_items": "This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,9 @@ function adminPlatformMenuConfig(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('tenancy');
|
||||||
|
|
||||||
// Guard against duplicate initialization
|
// Guard against duplicate initialization
|
||||||
if (window._platformMenuConfigInitialized) {
|
if (window._platformMenuConfigInitialized) {
|
||||||
menuConfigLog.warn('Already initialized, skipping');
|
menuConfigLog.warn('Already initialized, skipping');
|
||||||
@@ -158,7 +161,7 @@ function adminPlatformMenuConfig(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async showAll() {
|
async showAll() {
|
||||||
if (!confirm('This will show all menu items. Continue?')) {
|
if (!confirm(I18n.t('tenancy.confirmations.show_all_menu_items'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +187,7 @@ function adminPlatformMenuConfig(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async resetToDefaults() {
|
async resetToDefaults() {
|
||||||
if (!confirm('This will hide all menu items (except mandatory ones). You can then enable the ones you want. Continue?')) {
|
if (!confirm(I18n.t('tenancy.confirmations.hide_all_menu_items'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,9 @@ function adminPlatformModules(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('tenancy');
|
||||||
|
|
||||||
// Guard against duplicate initialization
|
// Guard against duplicate initialization
|
||||||
if (window._platformModulesInitialized) {
|
if (window._platformModulesInitialized) {
|
||||||
moduleConfigLog.warn('Already initialized, skipping');
|
moduleConfigLog.warn('Already initialized, skipping');
|
||||||
@@ -173,7 +176,7 @@ function adminPlatformModules(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async enableAll() {
|
async enableAll() {
|
||||||
if (!confirm('This will enable all modules. Continue?')) {
|
if (!confirm(I18n.t('tenancy.confirmations.enable_all_modules'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +207,7 @@ function adminPlatformModules(platformCode) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async disableOptional() {
|
async disableOptional() {
|
||||||
if (!confirm('This will disable all optional modules, keeping only core modules. Continue?')) {
|
if (!confirm(I18n.t('tenancy.confirmations.disable_optional_modules'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ function adminVendorTheme() {
|
|||||||
// ====================================================================
|
// ====================================================================
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
|
// Load i18n translations
|
||||||
|
await I18n.loadModule('tenancy');
|
||||||
|
|
||||||
// Guard against multiple initialization
|
// Guard against multiple initialization
|
||||||
if (window._adminVendorThemeInitialized) return;
|
if (window._adminVendorThemeInitialized) return;
|
||||||
window._adminVendorThemeInitialized = true;
|
window._adminVendorThemeInitialized = true;
|
||||||
@@ -225,7 +228,7 @@ function adminVendorTheme() {
|
|||||||
window.LogConfig.logPerformance('Save Theme', duration);
|
window.LogConfig.logPerformance('Save Theme', duration);
|
||||||
|
|
||||||
themeLog.info('Theme saved successfully');
|
themeLog.info('Theme saved successfully');
|
||||||
Utils.showToast('Theme saved successfully', 'success');
|
Utils.showToast(I18n.t('tenancy.messages.theme_saved_successfully'), 'success');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.LogConfig.logError(error, 'Save Theme');
|
window.LogConfig.logError(error, 'Save Theme');
|
||||||
@@ -262,14 +265,14 @@ function adminVendorTheme() {
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.LogConfig.logError(error, 'Apply Preset');
|
window.LogConfig.logError(error, 'Apply Preset');
|
||||||
Utils.showToast('Failed to apply preset', 'error');
|
Utils.showToast(I18n.t('tenancy.messages.failed_to_apply_preset'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
async resetTheme() {
|
async resetTheme() {
|
||||||
if (!confirm('Reset theme to default? This cannot be undone.')) {
|
if (!confirm(I18n.t('tenancy.confirmations.reset_theme'))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,11 +291,11 @@ function adminVendorTheme() {
|
|||||||
await this.loadTheme();
|
await this.loadTheme();
|
||||||
|
|
||||||
themeLog.info('Theme reset successfully');
|
themeLog.info('Theme reset successfully');
|
||||||
Utils.showToast('Theme reset to default', 'success');
|
Utils.showToast(I18n.t('tenancy.messages.theme_reset_to_default'), 'success');
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
window.LogConfig.logError(error, 'Reset Theme');
|
window.LogConfig.logError(error, 'Reset Theme');
|
||||||
Utils.showToast('Failed to reset theme', 'error');
|
Utils.showToast(I18n.t('tenancy.messages.failed_to_reset_theme'), 'error');
|
||||||
} finally {
|
} finally {
|
||||||
this.saving = false;
|
this.saving = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,257 +135,6 @@
|
|||||||
"account": "Account",
|
"account": "Account",
|
||||||
"wishlist": "Wishlist"
|
"wishlist": "Wishlist"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
|
||||||
"title": "Dashboard",
|
|
||||||
"welcome": "Welcome back",
|
|
||||||
"overview": "Overview",
|
|
||||||
"quick_stats": "Quick Stats",
|
|
||||||
"recent_activity": "Recent Activity",
|
|
||||||
"total_products": "Total Products",
|
|
||||||
"total_orders": "Total Orders",
|
|
||||||
"total_customers": "Total Customers",
|
|
||||||
"total_revenue": "Total Revenue",
|
|
||||||
"active_products": "Active Products",
|
|
||||||
"pending_orders": "Pending Orders",
|
|
||||||
"new_customers": "New Customers",
|
|
||||||
"today": "Today",
|
|
||||||
"this_week": "This Week",
|
|
||||||
"this_month": "This Month",
|
|
||||||
"this_year": "This Year",
|
|
||||||
"error_loading": "Error loading dashboard",
|
|
||||||
"no_data": "No data available"
|
|
||||||
},
|
|
||||||
"products": {
|
|
||||||
"title": "Products",
|
|
||||||
"product": "Product",
|
|
||||||
"add_product": "Add Product",
|
|
||||||
"edit_product": "Edit Product",
|
|
||||||
"delete_product": "Delete Product",
|
|
||||||
"product_name": "Product Name",
|
|
||||||
"product_code": "Product Code",
|
|
||||||
"sku": "SKU",
|
|
||||||
"price": "Price",
|
|
||||||
"sale_price": "Sale Price",
|
|
||||||
"cost": "Cost",
|
|
||||||
"stock": "Stock",
|
|
||||||
"in_stock": "In Stock",
|
|
||||||
"out_of_stock": "Out of Stock",
|
|
||||||
"low_stock": "Low Stock",
|
|
||||||
"availability": "Availability",
|
|
||||||
"available": "Available",
|
|
||||||
"unavailable": "Unavailable",
|
|
||||||
"brand": "Brand",
|
|
||||||
"category": "Category",
|
|
||||||
"categories": "Categories",
|
|
||||||
"image": "Image",
|
|
||||||
"images": "Images",
|
|
||||||
"main_image": "Main Image",
|
|
||||||
"gallery": "Gallery",
|
|
||||||
"weight": "Weight",
|
|
||||||
"dimensions": "Dimensions",
|
|
||||||
"color": "Color",
|
|
||||||
"size": "Size",
|
|
||||||
"material": "Material",
|
|
||||||
"condition": "Condition",
|
|
||||||
"new": "New",
|
|
||||||
"used": "Used",
|
|
||||||
"refurbished": "Refurbished",
|
|
||||||
"no_products": "No products found",
|
|
||||||
"search_products": "Search products...",
|
|
||||||
"filter_by_category": "Filter by category",
|
|
||||||
"filter_by_status": "Filter by status",
|
|
||||||
"sort_by": "Sort by",
|
|
||||||
"sort_newest": "Newest",
|
|
||||||
"sort_oldest": "Oldest",
|
|
||||||
"sort_price_low": "Price: Low to High",
|
|
||||||
"sort_price_high": "Price: High to Low",
|
|
||||||
"sort_name_az": "Name: A-Z",
|
|
||||||
"sort_name_za": "Name: Z-A"
|
|
||||||
},
|
|
||||||
"orders": {
|
|
||||||
"title": "Orders",
|
|
||||||
"order": "Order",
|
|
||||||
"order_id": "Order ID",
|
|
||||||
"order_number": "Order Number",
|
|
||||||
"order_date": "Order Date",
|
|
||||||
"order_status": "Order Status",
|
|
||||||
"order_details": "Order Details",
|
|
||||||
"order_items": "Order Items",
|
|
||||||
"order_total": "Order Total",
|
|
||||||
"subtotal": "Subtotal",
|
|
||||||
"shipping": "Shipping",
|
|
||||||
"tax": "Tax",
|
|
||||||
"discount": "Discount",
|
|
||||||
"customer": "Customer",
|
|
||||||
"shipping_address": "Shipping Address",
|
|
||||||
"billing_address": "Billing Address",
|
|
||||||
"payment_method": "Payment Method",
|
|
||||||
"payment_status": "Payment Status",
|
|
||||||
"tracking": "Tracking",
|
|
||||||
"tracking_number": "Tracking Number",
|
|
||||||
"carrier": "Carrier",
|
|
||||||
"no_orders": "No orders found",
|
|
||||||
"search_orders": "Search orders...",
|
|
||||||
"filter_by_status": "Filter by status",
|
|
||||||
"status_pending": "Pending",
|
|
||||||
"status_processing": "Processing",
|
|
||||||
"status_shipped": "Shipped",
|
|
||||||
"status_delivered": "Delivered",
|
|
||||||
"status_cancelled": "Cancelled",
|
|
||||||
"status_refunded": "Refunded",
|
|
||||||
"status_confirmed": "Confirmed",
|
|
||||||
"status_rejected": "Rejected",
|
|
||||||
"confirm_order": "Confirm Order",
|
|
||||||
"reject_order": "Reject Order",
|
|
||||||
"set_tracking": "Set Tracking",
|
|
||||||
"view_details": "View Details"
|
|
||||||
},
|
|
||||||
"customers": {
|
|
||||||
"title": "Customers",
|
|
||||||
"customer": "Customer",
|
|
||||||
"add_customer": "Add Customer",
|
|
||||||
"edit_customer": "Edit Customer",
|
|
||||||
"customer_name": "Customer Name",
|
|
||||||
"customer_email": "Customer Email",
|
|
||||||
"customer_phone": "Customer Phone",
|
|
||||||
"customer_number": "Customer Number",
|
|
||||||
"first_name": "First Name",
|
|
||||||
"last_name": "Last Name",
|
|
||||||
"company": "Company",
|
|
||||||
"total_orders": "Total Orders",
|
|
||||||
"total_spent": "Total Spent",
|
|
||||||
"last_order": "Last Order",
|
|
||||||
"registered": "Registered",
|
|
||||||
"no_customers": "No customers found",
|
|
||||||
"search_customers": "Search customers..."
|
|
||||||
},
|
|
||||||
"inventory": {
|
|
||||||
"title": "Inventory",
|
|
||||||
"stock_level": "Stock Level",
|
|
||||||
"quantity": "Quantity",
|
|
||||||
"reorder_point": "Reorder Point",
|
|
||||||
"adjust_stock": "Adjust Stock",
|
|
||||||
"stock_in": "Stock In",
|
|
||||||
"stock_out": "Stock Out",
|
|
||||||
"transfer": "Transfer",
|
|
||||||
"history": "History",
|
|
||||||
"low_stock_alert": "Low Stock Alert",
|
|
||||||
"out_of_stock_alert": "Out of Stock Alert"
|
|
||||||
},
|
|
||||||
"marketplace": {
|
|
||||||
"title": "Marketplace",
|
|
||||||
"import": "Import",
|
|
||||||
"export": "Export",
|
|
||||||
"sync": "Sync",
|
|
||||||
"source": "Source",
|
|
||||||
"source_url": "Source URL",
|
|
||||||
"import_products": "Import Products",
|
|
||||||
"start_import": "Start Import",
|
|
||||||
"importing": "Importing...",
|
|
||||||
"import_complete": "Import Complete",
|
|
||||||
"import_failed": "Import Failed",
|
|
||||||
"import_history": "Import History",
|
|
||||||
"job_id": "Job ID",
|
|
||||||
"started_at": "Started At",
|
|
||||||
"completed_at": "Completed At",
|
|
||||||
"duration": "Duration",
|
|
||||||
"imported_count": "Imported",
|
|
||||||
"error_count": "Errors",
|
|
||||||
"total_processed": "Total Processed",
|
|
||||||
"progress": "Progress",
|
|
||||||
"no_import_jobs": "No import jobs yet",
|
|
||||||
"start_first_import": "Start your first import using the form above"
|
|
||||||
},
|
|
||||||
"letzshop": {
|
|
||||||
"title": "Letzshop Integration",
|
|
||||||
"connection": "Connection",
|
|
||||||
"credentials": "Credentials",
|
|
||||||
"api_key": "API Key",
|
|
||||||
"api_endpoint": "API Endpoint",
|
|
||||||
"auto_sync": "Auto Sync",
|
|
||||||
"sync_interval": "Sync Interval",
|
|
||||||
"every_hour": "Every hour",
|
|
||||||
"every_day": "Every day",
|
|
||||||
"test_connection": "Test Connection",
|
|
||||||
"save_credentials": "Save Credentials",
|
|
||||||
"connection_success": "Connection successful",
|
|
||||||
"connection_failed": "Connection failed",
|
|
||||||
"last_sync": "Last Sync",
|
|
||||||
"sync_status": "Sync Status",
|
|
||||||
"import_orders": "Import Orders",
|
|
||||||
"export_products": "Export Products",
|
|
||||||
"no_credentials": "Configure your API key in Settings to get started",
|
|
||||||
"carriers": {
|
|
||||||
"dhl": "DHL",
|
|
||||||
"ups": "UPS",
|
|
||||||
"fedex": "FedEx",
|
|
||||||
"dpd": "DPD",
|
|
||||||
"gls": "GLS",
|
|
||||||
"post_luxembourg": "Post Luxembourg",
|
|
||||||
"other": "Other"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"team": {
|
|
||||||
"title": "Team",
|
|
||||||
"members": "Members",
|
|
||||||
"add_member": "Add Member",
|
|
||||||
"invite_member": "Invite Member",
|
|
||||||
"remove_member": "Remove Member",
|
|
||||||
"role": "Role",
|
|
||||||
"owner": "Owner",
|
|
||||||
"manager": "Manager",
|
|
||||||
"editor": "Editor",
|
|
||||||
"viewer": "Viewer",
|
|
||||||
"permissions": "Permissions",
|
|
||||||
"pending_invitations": "Pending Invitations",
|
|
||||||
"invitation_sent": "Invitation Sent",
|
|
||||||
"invitation_accepted": "Invitation Accepted"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"title": "Settings",
|
|
||||||
"general": "General",
|
|
||||||
"store": "Store",
|
|
||||||
"store_name": "Store Name",
|
|
||||||
"store_description": "Store Description",
|
|
||||||
"contact_email": "Contact Email",
|
|
||||||
"contact_phone": "Contact Phone",
|
|
||||||
"business_address": "Business Address",
|
|
||||||
"tax_number": "Tax Number",
|
|
||||||
"currency": "Currency",
|
|
||||||
"timezone": "Timezone",
|
|
||||||
"language": "Language",
|
|
||||||
"language_settings": "Language Settings",
|
|
||||||
"default_language": "Default Language",
|
|
||||||
"dashboard_language": "Dashboard Language",
|
|
||||||
"storefront_language": "Storefront Language",
|
|
||||||
"enabled_languages": "Enabled Languages",
|
|
||||||
"notifications": "Notifications",
|
|
||||||
"email_notifications": "Email Notifications",
|
|
||||||
"integrations": "Integrations",
|
|
||||||
"api_keys": "API Keys",
|
|
||||||
"webhooks": "Webhooks",
|
|
||||||
"save_settings": "Save Settings",
|
|
||||||
"settings_saved": "Settings saved successfully"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"title": "Profile",
|
|
||||||
"my_profile": "My Profile",
|
|
||||||
"edit_profile": "Edit Profile",
|
|
||||||
"personal_info": "Personal Information",
|
|
||||||
"first_name": "First Name",
|
|
||||||
"last_name": "Last Name",
|
|
||||||
"email": "Email",
|
|
||||||
"phone": "Phone",
|
|
||||||
"avatar": "Avatar",
|
|
||||||
"change_avatar": "Change Avatar",
|
|
||||||
"security": "Security",
|
|
||||||
"two_factor": "Two-Factor Authentication",
|
|
||||||
"sessions": "Active Sessions",
|
|
||||||
"preferences": "Preferences",
|
|
||||||
"language_preference": "Language Preference",
|
|
||||||
"save_profile": "Save Profile",
|
|
||||||
"profile_updated": "Profile updated successfully"
|
|
||||||
},
|
|
||||||
"errors": {
|
"errors": {
|
||||||
"generic": "An error occurred",
|
"generic": "An error occurred",
|
||||||
"not_found": "Not Found",
|
"not_found": "Not Found",
|
||||||
@@ -414,35 +163,6 @@
|
|||||||
"logout_title": "Confirm Logout",
|
"logout_title": "Confirm Logout",
|
||||||
"logout_message": "Are you sure you want to log out?"
|
"logout_message": "Are you sure you want to log out?"
|
||||||
},
|
},
|
||||||
"notifications": {
|
|
||||||
"title": "Notifications",
|
|
||||||
"mark_read": "Mark as Read",
|
|
||||||
"mark_all_read": "Mark All as Read",
|
|
||||||
"no_notifications": "No notifications",
|
|
||||||
"new_order": "New Order",
|
|
||||||
"order_updated": "Order Updated",
|
|
||||||
"low_stock": "Low Stock Alert",
|
|
||||||
"import_complete": "Import Complete",
|
|
||||||
"import_failed": "Import Failed"
|
|
||||||
},
|
|
||||||
"shop": {
|
|
||||||
"welcome": "Welcome to our store",
|
|
||||||
"browse_products": "Browse Products",
|
|
||||||
"add_to_cart": "Add to Cart",
|
|
||||||
"buy_now": "Buy Now",
|
|
||||||
"view_cart": "View Cart",
|
|
||||||
"checkout": "Checkout",
|
|
||||||
"continue_shopping": "Continue Shopping",
|
|
||||||
"start_shopping": "Start Shopping",
|
|
||||||
"empty_cart": "Your cart is empty",
|
|
||||||
"cart_total": "Cart Total",
|
|
||||||
"proceed_checkout": "Proceed to Checkout",
|
|
||||||
"payment": "Payment",
|
|
||||||
"place_order": "Place Order",
|
|
||||||
"order_placed": "Order Placed Successfully",
|
|
||||||
"thank_you": "Thank you for your order",
|
|
||||||
"order_confirmation": "Order Confirmation"
|
|
||||||
},
|
|
||||||
"footer": {
|
"footer": {
|
||||||
"all_rights_reserved": "All rights reserved",
|
"all_rights_reserved": "All rights reserved",
|
||||||
"powered_by": "Powered by"
|
"powered_by": "Powered by"
|
||||||
@@ -472,205 +192,8 @@
|
|||||||
"datetime": "MM/DD/YYYY HH:mm",
|
"datetime": "MM/DD/YYYY HH:mm",
|
||||||
"currency": "{symbol}{amount}"
|
"currency": "{symbol}{amount}"
|
||||||
},
|
},
|
||||||
"platform": {
|
"clipboard": {
|
||||||
"nav": {
|
"copied": "Copied to clipboard",
|
||||||
"pricing": "Pricing",
|
"failed": "Failed to copy"
|
||||||
"find_shop": "Find Your Shop",
|
|
||||||
"start_trial": "Start Free Trial",
|
|
||||||
"admin_login": "Admin Login",
|
|
||||||
"vendor_login": "Vendor Login",
|
|
||||||
"toggle_menu": "Toggle menu",
|
|
||||||
"toggle_dark_mode": "Toggle dark mode"
|
|
||||||
},
|
|
||||||
"hero": {
|
|
||||||
"badge": "{trial_days}-Day Free Trial - No Credit Card Required to Start",
|
|
||||||
"title": "Lightweight OMS for Letzshop Sellers",
|
|
||||||
"subtitle": "Order management, inventory, and invoicing built for Luxembourg e-commerce. Stop juggling spreadsheets. Start running your business.",
|
|
||||||
"cta_trial": "Start Free Trial",
|
|
||||||
"cta_find_shop": "Find Your Letzshop Shop"
|
|
||||||
},
|
|
||||||
"pricing": {
|
|
||||||
"title": "Simple, Transparent Pricing",
|
|
||||||
"subtitle": "Choose the plan that fits your business. All plans include a {trial_days}-day free trial.",
|
|
||||||
"monthly": "Monthly",
|
|
||||||
"annual": "Annual",
|
|
||||||
"save_months": "Save 2 months!",
|
|
||||||
"most_popular": "MOST POPULAR",
|
|
||||||
"recommended": "RECOMMENDED",
|
|
||||||
"contact_sales": "Contact Sales",
|
|
||||||
"start_trial": "Start Free Trial",
|
|
||||||
"per_month": "/month",
|
|
||||||
"per_year": "/year",
|
|
||||||
"custom": "Custom",
|
|
||||||
"orders_per_month": "{count} orders/month",
|
|
||||||
"unlimited_orders": "Unlimited orders",
|
|
||||||
"products_limit": "{count} products",
|
|
||||||
"unlimited_products": "Unlimited products",
|
|
||||||
"team_members": "{count} team members",
|
|
||||||
"unlimited_team": "Unlimited team",
|
|
||||||
"letzshop_sync": "Letzshop order sync",
|
|
||||||
"eu_vat_invoicing": "EU VAT invoicing",
|
|
||||||
"analytics_dashboard": "Analytics dashboard",
|
|
||||||
"api_access": "API access",
|
|
||||||
"multi_channel": "Multi-channel integration",
|
|
||||||
"products": "products",
|
|
||||||
"team_member": "team member",
|
|
||||||
"unlimited": "Unlimited",
|
|
||||||
"order_history": "months order history",
|
|
||||||
"trial_note": "All plans include a {trial_days}-day free trial. No credit card required.",
|
|
||||||
"back_home": "Back to Home"
|
|
||||||
},
|
|
||||||
"features": {
|
|
||||||
"letzshop_sync": "Letzshop order sync",
|
|
||||||
"inventory_basic": "Basic inventory management",
|
|
||||||
"inventory_locations": "Warehouse locations",
|
|
||||||
"inventory_purchase_orders": "Purchase orders",
|
|
||||||
"invoice_lu": "Luxembourg VAT invoicing",
|
|
||||||
"invoice_eu_vat": "EU VAT invoicing",
|
|
||||||
"invoice_bulk": "Bulk invoicing",
|
|
||||||
"customer_view": "Customer list",
|
|
||||||
"customer_export": "Customer export",
|
|
||||||
"analytics_dashboard": "Analytics dashboard",
|
|
||||||
"accounting_export": "Accounting export",
|
|
||||||
"api_access": "API access",
|
|
||||||
"automation_rules": "Automation rules",
|
|
||||||
"team_roles": "Team roles & permissions",
|
|
||||||
"white_label": "White-label option",
|
|
||||||
"multi_vendor": "Multi-vendor support",
|
|
||||||
"custom_integrations": "Custom integrations",
|
|
||||||
"sla_guarantee": "SLA guarantee",
|
|
||||||
"dedicated_support": "Dedicated account manager"
|
|
||||||
},
|
|
||||||
"addons": {
|
|
||||||
"title": "Enhance Your Platform",
|
|
||||||
"subtitle": "Add custom branding, professional email, and enhanced security.",
|
|
||||||
"per_year": "/year",
|
|
||||||
"per_month": "/month",
|
|
||||||
"custom_domain": "Custom Domain",
|
|
||||||
"custom_domain_desc": "Use your own domain (mydomain.com)",
|
|
||||||
"premium_ssl": "Premium SSL",
|
|
||||||
"premium_ssl_desc": "EV certificate for trust badges",
|
|
||||||
"email_package": "Email Package",
|
|
||||||
"email_package_desc": "Professional email addresses"
|
|
||||||
},
|
|
||||||
"find_shop": {
|
|
||||||
"title": "Find Your Letzshop Shop",
|
|
||||||
"subtitle": "Already selling on Letzshop? Enter your shop URL to get started.",
|
|
||||||
"placeholder": "Enter your Letzshop URL (e.g., letzshop.lu/vendors/my-shop)",
|
|
||||||
"button": "Find My Shop",
|
|
||||||
"claim_shop": "Claim This Shop",
|
|
||||||
"already_claimed": "Already Claimed",
|
|
||||||
"no_account": "Don't have a Letzshop account?",
|
|
||||||
"signup_letzshop": "Sign up with Letzshop first",
|
|
||||||
"then_connect": ", then come back to connect your shop.",
|
|
||||||
"search_placeholder": "Enter Letzshop URL or shop name...",
|
|
||||||
"search_button": "Search",
|
|
||||||
"examples": "Examples:",
|
|
||||||
"claim_button": "Claim This Shop & Start Free Trial",
|
|
||||||
"not_found": "We could not find a Letzshop shop with that URL. Please check and try again.",
|
|
||||||
"or_signup": "Or sign up without a Letzshop connection",
|
|
||||||
"need_help": "Need Help?",
|
|
||||||
"no_account_yet": "Don't have a Letzshop account yet? No problem!",
|
|
||||||
"create_letzshop": "Create a Letzshop Account",
|
|
||||||
"signup_without": "Sign Up Without Letzshop",
|
|
||||||
"looking_up": "Looking up your shop...",
|
|
||||||
"found": "Found:",
|
|
||||||
"claimed_badge": "Already Claimed"
|
|
||||||
},
|
|
||||||
"signup": {
|
|
||||||
"step_plan": "Select Plan",
|
|
||||||
"step_shop": "Claim Shop",
|
|
||||||
"step_account": "Account",
|
|
||||||
"step_payment": "Payment",
|
|
||||||
"choose_plan": "Choose Your Plan",
|
|
||||||
"save_percent": "Save {percent}%",
|
|
||||||
"trial_info": "We'll collect your payment info, but you won't be charged until the trial ends.",
|
|
||||||
"connect_shop": "Connect Your Letzshop Shop",
|
|
||||||
"connect_optional": "Optional: Link your Letzshop account to sync orders automatically.",
|
|
||||||
"connect_continue": "Connect & Continue",
|
|
||||||
"skip_step": "Skip This Step",
|
|
||||||
"create_account": "Create Your Account",
|
|
||||||
"first_name": "First Name",
|
|
||||||
"last_name": "Last Name",
|
|
||||||
"company_name": "Company Name",
|
|
||||||
"email": "Email",
|
|
||||||
"password": "Password",
|
|
||||||
"password_hint": "Minimum 8 characters",
|
|
||||||
"continue": "Continue",
|
|
||||||
"continue_payment": "Continue to Payment",
|
|
||||||
"back": "Back",
|
|
||||||
"add_payment": "Add Payment Method",
|
|
||||||
"no_charge_note": "You won't be charged until your {trial_days}-day trial ends.",
|
|
||||||
"processing": "Processing...",
|
|
||||||
"start_trial": "Start Free Trial",
|
|
||||||
"creating_account": "Creating your account..."
|
|
||||||
},
|
|
||||||
"success": {
|
|
||||||
"title": "Welcome to Wizamart!",
|
|
||||||
"subtitle": "Your account has been created and your {trial_days}-day free trial has started.",
|
|
||||||
"what_next": "What's Next?",
|
|
||||||
"step_connect": "Connect Letzshop:",
|
|
||||||
"step_connect_desc": "Add your API key to start syncing orders automatically.",
|
|
||||||
"step_invoicing": "Set Up Invoicing:",
|
|
||||||
"step_invoicing_desc": "Configure your invoice settings for Luxembourg compliance.",
|
|
||||||
"step_products": "Import Products:",
|
|
||||||
"step_products_desc": "Sync your product catalog from Letzshop.",
|
|
||||||
"go_to_dashboard": "Go to Dashboard",
|
|
||||||
"login_dashboard": "Login to Dashboard",
|
|
||||||
"need_help": "Need help getting started?",
|
|
||||||
"contact_support": "Contact our support team"
|
|
||||||
},
|
|
||||||
"cta": {
|
|
||||||
"title": "Ready to Streamline Your Orders?",
|
|
||||||
"subtitle": "Join Letzshop vendors who trust Wizamart for their order management. Start your {trial_days}-day free trial today.",
|
|
||||||
"button": "Start Free Trial"
|
|
||||||
},
|
|
||||||
"footer": {
|
|
||||||
"tagline": "Lightweight OMS for Letzshop sellers. Manage orders, inventory, and invoicing.",
|
|
||||||
"quick_links": "Quick Links",
|
|
||||||
"platform": "Platform",
|
|
||||||
"contact": "Contact",
|
|
||||||
"copyright": "© {year} Wizamart. Built for Luxembourg e-commerce.",
|
|
||||||
"privacy": "Privacy Policy",
|
|
||||||
"terms": "Terms of Service",
|
|
||||||
"about": "About Us",
|
|
||||||
"faq": "FAQ",
|
|
||||||
"contact_us": "Contact Us"
|
|
||||||
},
|
|
||||||
"modern": {
|
|
||||||
"badge_integration": "Official Integration",
|
|
||||||
"badge_connect": "Connect in 2 minutes",
|
|
||||||
"hero_title_1": "Built for Luxembourg E-Commerce",
|
|
||||||
"hero_title_2": "The Back-Office Letzshop Doesn't Give You",
|
|
||||||
"hero_subtitle": "Sync orders, manage inventory, generate invoices with correct VAT, and own your customer data. All in one place.",
|
|
||||||
"cta_trial": "Start {trial_days}-Day Free Trial",
|
|
||||||
"cta_how": "See How It Works",
|
|
||||||
"hero_note": "No credit card required. Setup in 5 minutes. Cancel anytime.",
|
|
||||||
"pain_title": "Sound Familiar?",
|
|
||||||
"pain_subtitle": "These are the daily frustrations of Letzshop sellers",
|
|
||||||
"pain_manual": "Manual Order Entry",
|
|
||||||
"pain_manual_desc": "Copy-pasting orders from Letzshop to spreadsheets. Every. Single. Day.",
|
|
||||||
"pain_inventory": "Inventory Chaos",
|
|
||||||
"pain_inventory_desc": "Stock in Letzshop doesn't match reality. Overselling happens.",
|
|
||||||
"pain_vat": "Wrong VAT Invoices",
|
|
||||||
"pain_vat_desc": "EU customers need correct VAT. Your accountant keeps complaining.",
|
|
||||||
"pain_customers": "Lost Customers",
|
|
||||||
"pain_customers_desc": "Letzshop owns your customer data. You can't retarget or build loyalty.",
|
|
||||||
"how_title": "How It Works",
|
|
||||||
"how_subtitle": "From Chaos to Control in 4 Steps",
|
|
||||||
"how_step1": "Connect Letzshop",
|
|
||||||
"how_step1_desc": "Enter your Letzshop API credentials. Done in 2 minutes, no technical skills needed.",
|
|
||||||
"how_step2": "Orders Flow In",
|
|
||||||
"how_step2_desc": "Orders sync automatically. Confirm and add tracking directly from Wizamart.",
|
|
||||||
"how_step3": "Generate Invoices",
|
|
||||||
"how_step3_desc": "One click to create compliant PDF invoices with correct VAT for any EU country.",
|
|
||||||
"how_step4": "Grow Your Business",
|
|
||||||
"how_step4_desc": "Export customers for marketing. Track inventory. Focus on selling, not spreadsheets.",
|
|
||||||
"features_title": "Everything a Letzshop Seller Needs",
|
|
||||||
"features_subtitle": "The operational tools Letzshop doesn't provide",
|
|
||||||
"cta_final_title": "Ready to Take Control of Your Letzshop Business?",
|
|
||||||
"cta_final_subtitle": "Join Luxembourg vendors who've stopped fighting spreadsheets and started growing their business.",
|
|
||||||
"cta_final_note": "No credit card required. Setup in 5 minutes. Full Professional features during trial."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,10 +140,13 @@ const Utils = {
|
|||||||
async copyToClipboard(text) {
|
async copyToClipboard(text) {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(text);
|
await navigator.clipboard.writeText(text);
|
||||||
this.showToast('Copied to clipboard', 'success');
|
// Use I18n if available, fallback to hardcoded string
|
||||||
|
const message = typeof I18n !== 'undefined' ? I18n.t('clipboard.copied') : 'Copied to clipboard';
|
||||||
|
this.showToast(message, 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to copy:', error);
|
console.error('Failed to copy:', error);
|
||||||
this.showToast('Failed to copy', 'error');
|
const message = typeof I18n !== 'undefined' ? I18n.t('clipboard.failed') : 'Failed to copy';
|
||||||
|
this.showToast(message, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user