Skip to content
2 changes: 1 addition & 1 deletion config/backstage/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
'navigation_icon' => 'heroicon-o-photo',
'navigation_sort' => null,
'navigation_count_badge' => false,
'resource' => \Backstage\Media\Resources\MediaResource::class,
'resource' => \Backstage\Resources\MediaResource::class,
],

'file_upload' => [
Expand Down
6 changes: 6 additions & 0 deletions config/backstage/translations.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@
'navigation' => [
'group' => 'Manage',
],

'eloquent' => [
'translatable-models' => [
\Backstage\Models\Media::class,
],
],
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up()
{
Schema::create('translated_attributes', function (Blueprint $table) {
$table->id();
$table->string('code', 5);

$table->foreign('code')
->references('code')
->on('languages')
->onDelete('cascade');

$table->ulidMorphs('translatable');

$table->longText('attribute');
$table->longText('translated_attribute')->nullable();
$table->timestamp('translated_at')->nullable();

$table->timestamps();
$table->softDeletes();
});
}

public function down()
{
Schema::dropIfExists('translated_attributes');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
$model = config('backstage.media.model');
Schema::table((new $model)->getTable(), function (Blueprint $table) {
$table->text('alt')->after('height');
});
}

public function down(): void
{
$model = config('backstage.media.model');
Schema::table((new $model)->getTable(), function (Blueprint $table) {
$table->dropColumn('alt');
});
}
};
91 changes: 88 additions & 3 deletions src/BackstageServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use Backstage\Events\FormSubmitted;
use Backstage\Http\Middleware\SetLocale;
use Backstage\Listeners\ExecuteFormActions;
use Backstage\Media\Resources\MediaResource;
use Backstage\Models\Block;
use Backstage\Models\Media;
use Backstage\Models\Menu;
Expand Down Expand Up @@ -88,6 +87,8 @@ public function configurePackage(Package $package): void

$this->writeMediaPickerConfig();

$this->writeTranslationsConfig();

$command->callSilently('vendor:publish', [
'--tag' => 'backstage-migrations',
'--force' => true,
Expand Down Expand Up @@ -307,7 +308,7 @@ private function generateMediaPickerConfig(): array
'navigation_icon' => 'heroicon-o-photo',
'navigation_sort' => null,
'navigation_count_badge' => false,
'resource' => MediaResource::class,
'resource' => \Backstage\Resources\MediaResource::class,
],
];

Expand Down Expand Up @@ -392,14 +393,98 @@ private function writeMediaPickerConfig(?string $path = null): void
$configContent .= "use Backstage\Models\Site;\n";
$configContent .= "use Backstage\Models\User;\n";
$configContent .= "use Backstage\Models\Media;\n\n";
$configContent .= "use Backstage\Media\Resources\MediaResource;\n\n";
$configContent .= "use Backstage\Resources\MediaResource;\n\n";

// Custom export function to create more readable output
$configContent .= 'return ' . $this->customVarExport($this->generateMediaPickerConfig()) . ";\n";

file_put_contents($path, $configContent);
}

private function generateTranslationsConfig(): array
{
$config = [
'scan' => [
'paths' => [
app_path(),
resource_path('views'),
base_path(''),
],

'extensions' => [
'*.php',
'*.blade.php',
'*.json',
],

'functions' => [
'trans',
'trans_choice',
'Lang::transChoice',
'Lang::trans',
'Lang::get',
'Lang::choice',
'@lang',
'@choice',
'__',
],
],

'eloquent' => [
'translatable-models' => [
\Backstage\Models\ContentFieldValue::class,
\Backstage\Models\Tag::class,
],
],

'translators' => [
'default' => env('TRANSLATION_DRIVER', 'google-translate'),

'drivers' => [
'google-translate' => [
// no options
],

'ai' => [
'provider' => \Prism\Prism\Enums\Provider::OpenAI,
'model' => 'gpt-5',
'system_prompt' => 'You are an expert mathematician who explains concepts simply. The only thing you do it output what i ask. No comments, no extra information. Just the answer.',
],

'deep-l' => [
//
],
],
],
];

config(['translations' => $config]);

return $config;
}

private function writeTranslationsConfig(?string $path = null): void
{
$path ??= config_path('translations.php');

// Ensure directory exists
$directory = dirname($path);
if (! is_dir($directory)) {
mkdir($directory, 0755, true);
}

// Generate the config file content
$configContent = "<?php\n\n";
$configContent .= "use Backstage\Models\Tag;\n";
$configContent .= "use Prism\Prism\Enums\Provider;\n";
$configContent .= "use Backstage\Models\ContentFieldValue;\n\n";

// Custom export function to create more readable output
$configContent .= 'return ' . $this->customVarExport($this->generateTranslationsConfig()) . ";\n";

file_put_contents($path, $configContent);
}

private function customVarExport($var, $indent = ''): string
{
switch (gettype($var)) {
Expand Down
16 changes: 14 additions & 2 deletions src/Models/Media.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
namespace Backstage\Models;

use Backstage\Shared\HasPackageFactory;
use Backstage\Translations\Laravel\Contracts\TranslatesAttributes;
use Backstage\Translations\Laravel\Models\Concerns\HasTranslatableAttributes;
use Illuminate\Database\Eloquent\Concerns\HasUlids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Media extends Model
class Media extends Model implements TranslatesAttributes
{
use HasPackageFactory;
use HasTranslatableAttributes;
use HasUlids;

protected $primaryKey = 'ulid';
Expand All @@ -20,7 +23,16 @@ class Media extends Model

protected function casts(): array
{
return [];
return [
'alt' => 'string',
];
}

public function getTranslatableAttributes(): array
{
return [
'alt',
];
}

public function site(): BelongsTo
Expand Down
Loading