From 922add1b6f1b78913fefd66a20ea0598fe3da711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Wed, 31 Dec 2025 00:23:16 +0300 Subject: [PATCH] Add Import and Export Functionality for Site Translations: Implemented SiteTranslationImporter and SiteTranslationExporter classes to facilitate the import and export of site translations. Enhanced the SiteTranslationsTable with import and export actions, allowing for efficient management of translation data. Updated the migration files to create necessary tables for handling imports and exports, improving the overall localization workflow in the admin panel. --- .../Tables/SiteTranslationsTable.php | 43 ++++- .../Exports/SiteTranslationExporter.php | 46 ++++++ .../Imports/SiteTranslationImporter.php | 84 ++++++++++ ...2025_12_30_211920_create_imports_table.php | 35 ++++ ...2025_12_30_211921_create_exports_table.php | 35 ++++ ...211922_create_failed_import_rows_table.php | 30 ++++ resources/views/templates/home.blade.php | 152 +++++++++--------- 7 files changed, 348 insertions(+), 77 deletions(-) create mode 100644 app/Filament/Exports/SiteTranslationExporter.php create mode 100644 app/Filament/Imports/SiteTranslationImporter.php create mode 100644 database/migrations/2025_12_30_211920_create_imports_table.php create mode 100644 database/migrations/2025_12_30_211921_create_exports_table.php create mode 100644 database/migrations/2025_12_30_211922_create_failed_import_rows_table.php diff --git a/app/Filament/Admin/Resources/SiteTranslations/Tables/SiteTranslationsTable.php b/app/Filament/Admin/Resources/SiteTranslations/Tables/SiteTranslationsTable.php index 62cf299..9389205 100644 --- a/app/Filament/Admin/Resources/SiteTranslations/Tables/SiteTranslationsTable.php +++ b/app/Filament/Admin/Resources/SiteTranslations/Tables/SiteTranslationsTable.php @@ -8,6 +8,14 @@ use Filament\Actions\BulkActionGroup; use Filament\Actions\DeleteBulkAction; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; +use App\Models\Language; +use Filament\Forms\Components\Textarea; +use Filament\Schemas\Components\Group; +use Filament\Schemas\Components\Section; +use Filament\Actions\ImportAction; +use Filament\Actions\ExportAction; +use App\Filament\Imports\SiteTranslationImporter; +use App\Filament\Exports\SiteTranslationExporter; class SiteTranslationsTable { @@ -16,6 +24,12 @@ class SiteTranslationsTable $defaultLocale = app()->getLocale(); return $table + ->headerActions([ + ImportAction::make() + ->importer(SiteTranslationImporter::class), + ExportAction::make() + ->exporter(SiteTranslationExporter::class) + ]) ->columns([ TextColumn::make('key') ->searchable() @@ -39,7 +53,34 @@ class SiteTranslationsTable // ]) ->recordActions([ - EditAction::make(), + EditAction::make() + ->modalWidth('xl') + ->form(function () { + $languages = Language::where('is_active', true)->get(); + + $translationFields = []; + foreach ($languages as $language) { + $translationFields[] = Textarea::make($language->code) + ->label($language->name . " ({$language->code})") + ->rows(2); + } + + return [ + Section::make() + ->schema([ + Textarea::make('key') + ->label('Key / Original Text') + ->required() + ->columnSpanFull() + ->helperText('The original text to be translated. Use this exact text in t() helper.'), + + Group::make() + ->schema($translationFields) + ->statePath('translations') + ->columnSpanFull(), + ]) + ]; + }), DeleteAction::make(), ]) ->toolbarActions([ diff --git a/app/Filament/Exports/SiteTranslationExporter.php b/app/Filament/Exports/SiteTranslationExporter.php new file mode 100644 index 0000000..19ffec7 --- /dev/null +++ b/app/Filament/Exports/SiteTranslationExporter.php @@ -0,0 +1,46 @@ +label('Key'), + ]; + + // Veritabanı bağlantısı yoksa veya tablo yoksa hata vermemesi için try-catch veya kontrol + try { + $languages = Language::where('is_active', true)->get(); + foreach ($languages as $language) { + $columns[] = ExportColumn::make("translations.{$language->code}") + ->label($language->name . " ({$language->code})"); + } + } catch (\Exception $e) { + // Migration henüz çalışmadıysa + } + + return $columns; + } + + public static function getCompletedNotificationBody(Export $export): string + { + $body = 'Your site translation export has completed and ' . number_format($export->successful_rows) . ' ' . str('row')->plural($export->successful_rows) . ' exported.'; + + if ($failedRowsCount = $export->getFailedRowsCount()) { + $body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to export.'; + } + + return $body; + } +} + diff --git a/app/Filament/Imports/SiteTranslationImporter.php b/app/Filament/Imports/SiteTranslationImporter.php new file mode 100644 index 0000000..9c3cf0c --- /dev/null +++ b/app/Filament/Imports/SiteTranslationImporter.php @@ -0,0 +1,84 @@ +requiredMapping() + ->rules(['required', 'max:255']), + ]; + + try { + $languages = Language::where('is_active', true)->get(); + foreach ($languages as $language) { + $columns[] = ImportColumn::make($language->code) + ->label($language->name . " ({$language->code})"); + } + } catch (\Exception $e) { + // + } + + return $columns; + } + + public function resolveRecord(): ?SiteTranslation + { + return SiteTranslation::firstOrNew([ + 'key' => $this->data['key'], + ]); + } + + protected function beforeSave(): void + { + $translations = $this->record->translations ?? []; + + // CSV'den gelen verileri al (data array içinde mapped column adları ile gelir) + // getColumns'da column adlarını dil kodu olarak verdik: $language->code + + $languages = Language::where('is_active', true)->pluck('code')->toArray(); + + foreach ($languages as $code) { + if (isset($this->data[$code])) { + // Boş string gelse bile güncelleyelim mi? Evet, çeviri silinmiş olabilir. + // Ancak null gelirse (CSV'de sütun yoksa) dokunmayalım. + // ImportColumn boş hücreleri null veya boş string olarak getirebilir. + + $value = $this->data[$code]; + + if ($value !== null) { + $translations[$code] = $value; + } + } + } + + $this->record->translations = $translations; + + if (!$this->record->exists && empty($this->record->hash)) { + $this->record->hash = md5($this->record->key); + } + } + + public static function getCompletedNotificationBody(Import $import): string + { + $body = 'Your site translation import has completed and ' . number_format($import->successful_rows) . ' ' . str('row')->plural($import->successful_rows) . ' imported.'; + + if ($failedRowsCount = $import->getFailedRowsCount()) { + $body .= ' ' . number_format($failedRowsCount) . ' ' . str('row')->plural($failedRowsCount) . ' failed to import.'; + } + + return $body; + } +} + diff --git a/database/migrations/2025_12_30_211920_create_imports_table.php b/database/migrations/2025_12_30_211920_create_imports_table.php new file mode 100644 index 0000000..1d9c09d --- /dev/null +++ b/database/migrations/2025_12_30_211920_create_imports_table.php @@ -0,0 +1,35 @@ +id(); + $table->timestamp('completed_at')->nullable(); + $table->string('file_name'); + $table->string('file_path'); + $table->string('importer'); + $table->unsignedInteger('processed_rows')->default(0); + $table->unsignedInteger('total_rows'); + $table->unsignedInteger('successful_rows')->default(0); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('imports'); + } +}; diff --git a/database/migrations/2025_12_30_211921_create_exports_table.php b/database/migrations/2025_12_30_211921_create_exports_table.php new file mode 100644 index 0000000..6a87ac3 --- /dev/null +++ b/database/migrations/2025_12_30_211921_create_exports_table.php @@ -0,0 +1,35 @@ +id(); + $table->timestamp('completed_at')->nullable(); + $table->string('file_disk'); + $table->string('file_name')->nullable(); + $table->string('exporter'); + $table->unsignedInteger('processed_rows')->default(0); + $table->unsignedInteger('total_rows'); + $table->unsignedInteger('successful_rows')->default(0); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('exports'); + } +}; diff --git a/database/migrations/2025_12_30_211922_create_failed_import_rows_table.php b/database/migrations/2025_12_30_211922_create_failed_import_rows_table.php new file mode 100644 index 0000000..2f77805 --- /dev/null +++ b/database/migrations/2025_12_30_211922_create_failed_import_rows_table.php @@ -0,0 +1,30 @@ +id(); + $table->json('data'); + $table->foreignId('import_id')->constrained()->cascadeOnDelete(); + $table->text('validation_error')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('failed_import_rows'); + } +}; diff --git a/resources/views/templates/home.blade.php b/resources/views/templates/home.blade.php index 4d999b8..94ffb27 100644 --- a/resources/views/templates/home.blade.php +++ b/resources/views/templates/home.blade.php @@ -21,14 +21,14 @@ -
image
+
image
-

What We Do?

-

The full service we are offering is specifically designed to meet your business needs.

+

{!! t('What We Do?') !!}

+

{!! t('The full service we are offering is specifically designed to meet your business needs.') !!}

@@ -36,37 +36,37 @@
- -

SEO Services

-

Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.

- Learn More + +

{!! t('SEO Services') !!}

+

{!! t('Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.') !!}

+ {!! t('Learn More') !!}
- -

Web Design

-

Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.

- Learn More + +

{!! t('Web Design') !!}

+

{!! t('Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.') !!}

+ {!! t('Learn More') !!}
- -

Social Engagement

-

Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.

- Learn More + +

{!! t('Social Engagement') !!}

+

{!! t('Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.') !!}

+ {!! t('Learn More') !!}
- -

App Development

-

Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.

- Learn More + +

{!! t('App Development') !!}

+

{!! t('Nulla vitae elit libero, a pharetra augue. Donec id elit non mi porta gravida eget metus cras justo.') !!}

+ {!! t('Learn More') !!}
@@ -74,21 +74,21 @@
-
image
+
image
-

Why Choose Us?

-

So here a few reasons why our valued customers choose us.

+

{!! t('Why Choose Us?') !!}

+

{!! t('So here a few reasons why our valued customers choose us.') !!}

- +
-

Creativity

-

Curabitur blandit lacus porttitor ridiculus mus.

+

{!! t('Creativity') !!}

+

{!! t('Curabitur blandit lacus porttitor ridiculus mus.') !!}

@@ -96,11 +96,11 @@
- +
-

Innovative Thinking

-

Curabitur blandit lacus porttitor ridiculus mus.

+

{!! t('Innovative Thinking') !!}

+

{!! t('Curabitur blandit lacus porttitor ridiculus mus.') !!}

@@ -108,11 +108,11 @@
- +
-

Rapid Solutions

-

Curabitur blandit lacus porttitor ridiculus mus.

+

{!! t('Rapid Solutions') !!}

+

{!! t('Curabitur blandit lacus porttitor ridiculus mus.') !!}

@@ -120,11 +120,11 @@
- +
-

Top-Notch Support

-

Curabitur blandit lacus porttitor ridiculus mus.

+

{!! t('Top-Notch Support') !!}

+

{!! t('Curabitur blandit lacus porttitor ridiculus mus.') !!}

@@ -137,23 +137,23 @@
-
image
+
image
-

Our Solutions

-

Just sit & relax while we take care of your business needs.

-

Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Praesent commodo cursus. Maecenas sed diam eget risus varius blandit sit amet non magna. Praesent commodo cursus magna.

+

{!! t('Our Solutions') !!}

+

{!! t('Just sit & relax while we take care of your business needs.') !!}

+

{!! t('Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Praesent commodo cursus. Maecenas sed diam eget risus varius blandit sit amet non magna. Praesent commodo cursus magna.') !!}

99.7%

-
Customer Satisfaction
+
{!! t('Customer Satisfaction') !!}

4x

-
New Visitors
+
{!! t('New Visitors') !!}
@@ -167,15 +167,15 @@
-

Happy Customers

-

Don't take our word for it. See what customers are saying about us.

+

{!! t('Happy Customers') !!}

+

{!! t('Don\'t take our word for it. See what customers are saying about us.') !!}

@@ -185,7 +185,7 @@
-

“Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.”

+

“{!! t('Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.') !!}”

Coriss Ambady
@@ -198,7 +198,7 @@
-

“Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.”

+

“{!! t('Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.') !!}”

Cory Zamora
@@ -211,7 +211,7 @@
-

“Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.”

+

“{!! t('Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Vestibulum ligula porta felis euismod semper. Cras justo odio consectetur nulla dapibus curabitur blandit faucibus.') !!}”

Nikolas Brooten
@@ -237,21 +237,21 @@
-

Our Pricing

-

We offer great and premium prices.

-

Enjoy a free 30-day trial and experience the full service. No credit card required!

- See All Prices +

{!! t('Our Pricing') !!}

+

{!! t('We offer great and premium prices.') !!}

+

{!! t('Enjoy a free 30-day trial and experience the full service. No credit card required!') !!}

+ {!! t('See All Prices') !!}
-

Monthly

+

{!! t('Monthly') !!}

-

Yearly (Save 30%)

+

{!! t('Yearly (Save 30%)') !!}

@@ -262,15 +262,15 @@
$199 yr
-

Premium Plan

+

{!! t('Premium Plan') !!}

    -
  • 5 Projects
  • -
  • 100K API Access
  • -
  • 200MB Storage
  • -
  • Weekly Reports
  • -
  • 7/24 Support
  • +
  • {!! t('5 Projects') !!}
  • +
  • {!! t('100K API Access') !!}
  • +
  • {!! t('200MB Storage') !!}
  • +
  • {!! t('Weekly Reports') !!}
  • +
  • {!! t('7/24 Support') !!}
- Choose Plan + {!! t('Choose Plan') !!}
@@ -285,15 +285,15 @@
$499 yr
-

Corporate Plan

+

{!! t('Corporate Plan') !!}

    -
  • 20 Projects
  • -
  • 300K API Access
  • -
  • 500MB Storage
  • -
  • Weekly Reports
  • -
  • 7/24 Support
  • +
  • {!! t('20 Projects') !!}
  • +
  • {!! t('300K API Access') !!}
  • +
  • {!! t('500MB Storage') !!}
  • +
  • {!! t('Weekly Reports') !!}
  • +
  • {!! t('7/24 Support') !!}
- Choose Plan + {!! t('Choose Plan') !!}
@@ -308,14 +308,14 @@
-
image
+
image
-

Let’s Talk

-

Let's make something great together. We are trusted by over 5000+ clients.

-

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Maecenas faucibus mollis interdum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

- Join Us +

{!! t('Let’s Talk') !!}

+

{!! t('Let\'s make something great together. We are trusted by over 5000+ clients.') !!}

+

{!! t('Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Maecenas faucibus mollis interdum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.') !!}

+ {!! t('Join Us') !!}
@@ -327,8 +327,8 @@
-

Analyze Now

-

Wonder how much faster your website can go? Easily check your SEO Score now.

+

{!! t('Analyze Now') !!}

+

{!! t('Wonder how much faster your website can go? Easily check your SEO Score now.') !!}

@@ -338,8 +338,8 @@
- - + +
@@ -348,6 +348,6 @@
-
image
+
image
@endsection