Added settings for translation into other languages ​​in the project.

This commit is contained in:
2025-02-09 18:53:08 +05:00
parent c4817a675a
commit 25faa3d62b
28 changed files with 2716 additions and 799 deletions

View File

@@ -0,0 +1,29 @@
<?php declare(strict_types=1);
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
use App\Dto\Service\Dto;
final readonly class Translation extends Dto
{
public function __construct(
private int $languageId,
private ?int $sourceLanguageId,
private ?string $code,
) { }
public function getLanguageId(): int
{
return $this->languageId;
}
public function getSourceLanguageId(): ?int
{
return $this->sourceLanguageId;
}
public function getCode(): ?string
{
return $this->code;
}
}

View File

@@ -0,0 +1,18 @@
<?php declare(strict_types=1);
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
final class Translations
{
private array $translations;
public function add(Translation $translation): void
{
$this->translations[] = $translation;
}
public function getTranslations(): array
{
return $this->translations;
}
}

View File

@@ -0,0 +1,17 @@
<?php declare(strict_types=1);
namespace App\Dto\Service\Admin\Project\ServiceTranslate;
use App\Dto\Service\Dto;
final readonly class Update extends Dto
{
public function __construct(
private Translations $translations,
) { }
public function getTranslations(): Translations
{
return $this->translations;
}
}

View File

@@ -21,6 +21,9 @@ enum Permission: string
self::AdminPanel => [
'view' => __('permissions.Administrative panel allowed'),
],
self::Project => array_merge($this->getBasePermissions(), [
'Setting up automatic translation' => __('permissions.Setting up automatic translation'),
]),
self::ProjectContent => [
'view' => __('permissions.Allowed to watch'),
'create' => __('permissions.Allowed to create'),

View File

@@ -0,0 +1,41 @@
<?php declare(strict_types=1);
namespace App\Http\Controllers\Admin\Projects;
use App\Http\Controllers\Admin\Controller;
use App\Http\Requests\Admin\Projects\ServiceTranslate\UpdateRequest;
use App\Services\Admin\Project\ServiceTranslateService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
final class ServiceTranslateController extends Controller
{
public function __construct(
private readonly ServiceTranslateService $serviceTranslateService,
) { }
public function view(int $projectId, Request $request): View
{
$user = $request->user();
$result = $this->serviceTranslateService->view($projectId, $user);
if ($result->isError()) {
$this->errors($result);
}
return view('admin.projects.service-translate.view', $result->getData());
}
public function update(int $projectId, UpdateRequest $request): RedirectResponse
{
$data = $request->getDto();
$user = $request->user();
$result = $this->serviceTranslateService->update($projectId, $data, $user);
if ($result->isError()) {
return redirect()->back()->withInput()->withErrors($result->getErrorsOrMessage());
}
return redirect()->route('admin.projects.service-translate.view', ['project' => $projectId])->withSuccess($result->getMessage());
}
}

View File

@@ -0,0 +1,56 @@
<?php declare(strict_types=1);
namespace App\Http\Requests\Admin\Projects\ServiceTranslate;
use App\Contracts\FormRequestDto;
use App\Dto\Service\Admin\Project\ServiceTranslate\Translation;
use App\Dto\Service\Admin\Project\ServiceTranslate\Translations;
use App\Dto\Service\Admin\Project\ServiceTranslate\Update;
use Illuminate\Foundation\Http\FormRequest;
final class UpdateRequest extends FormRequest implements FormRequestDto
{
public function attributes(): array
{
return [
'language.*.id' => __('validation.attributes.language_id'),
'language.*.code' => __('validation.attributes.code'),
'language.*.source_language_id' => __('validation.attributes.source_language_id'),
];
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'language.*.id' => ['required', 'numeric', 'min:1'],
'language.*.code' => ['nullable', 'string', 'min:2', 'max:50'],
'language.*.source_language_id' => ['nullable', 'numeric', 'min:1', 'different:language.*.id'],
];
}
public function getDto(): Update
{
$translations = new Translations();
foreach ($this->input('language', []) as $language) {
$sourceLanguageId = $language['source_language_id'] ?? null;
if ($sourceLanguageId) {
$sourceLanguageId = (int) $sourceLanguageId;
}
$translation = new Translation(
languageId: (int) $language['id'],
sourceLanguageId: $sourceLanguageId,
code: $language['code'] ?? null,
);
$translations->add($translation);
}
return new Update(
translations: $translations,
);
}
}

View File

@@ -7,6 +7,7 @@ use App\Models\Scopes\SortScope;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Attributes\ScopedBy;
@@ -70,4 +71,9 @@ final class ProjectLanguage extends Model
},
)->shouldCache();
}
public function serviceTranslate(): HasOne
{
return $this->hasOne(ProjectTranslationService::class, 'language_id', 'id');
}
}

View File

@@ -0,0 +1,24 @@
<?php declare(strict_types=1);
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
final class ProjectTranslationService extends Model
{
use HasFactory;
protected $table = 'project_translation_service';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'code',
'language_id',
'source_language_id',
];
}

View File

@@ -32,6 +32,11 @@ final readonly class ProjectPolicy extends Policy
return $user->hasPermission('project.delete');
}
public function settingUpAutomaticTranslation(User $user, Project $project): bool
{
return $user->hasPermission('project.setting-up-automatic-translation');
}
public function upload(User $user): bool
{
if ($user->hasPermission('project.create') || $user->hasPermission('project.update')) {

View File

@@ -0,0 +1,35 @@
<?php declare(strict_types=1);
namespace App\Repositories;
use App\Models\ProjectTranslationService;
use App\Services\Search\CreateSearchInstanceCommand;
use App\Services\Search\Search;
use Illuminate\Database\Eloquent\Builder;
final readonly class ProjectTranslationServiceRepository
{
public function __construct(
private CreateSearchInstanceCommand $createSearchInstanceCommand,
) { }
public function getLanguagesBySourceLanguage(int $sourceLanguage, ?array $excludeLanguages = null): Search
{
$query = ProjectTranslationService::query()
->select('language_id', 'code')
->where('source_language_id', $sourceLanguage)
->when($excludeLanguages, function (Builder $query) use ($excludeLanguages) {
$query->whereNotIn('language_id', $excludeLanguages);
});
return $this->createSearchInstanceCommand->execute($query);
}
public function getLanguageCodeByLanguageId(int $languageId): ?string
{
return ProjectTranslationService::query()
->select('code')
->where('language_id', $languageId)
->first()?->code ?? null;
}
}

View File

@@ -0,0 +1,67 @@
<?php declare(strict_types=1);
namespace App\Services\Admin\Project;
use App\Dto\Service\Admin\Project\ServiceTranslate\Update;
use App\Models\User;
use App\Repositories\ProjectRepository;
use App\ServiceResults\ServiceResultArray;
use App\ServiceResults\ServiceResultError;
use App\ServiceResults\ServiceResultSuccess;
use App\Services\ProjectTranslationService\ModelSyncCommand as TranslationServiceModelSyncCommand;
use App\Services\Service;
use Illuminate\Support\Facades\DB;
final class ServiceTranslateService extends Service
{
public function __construct(
private readonly ProjectRepository $projectRepository,
private readonly TranslationServiceModelSyncCommand $translationServiceModelSyncCommand,
) { }
public function view(int $projectId, User $user): ServiceResultError | ServiceResultArray
{
$project = $this->projectRepository->getProjectById($projectId);
if (\is_null($project)) {
return $this->errNotFound(__('Not Found'));
}
if (
config('translation_service.enable', false) === false
|| $user->cannot('settingUpAutomaticTranslation', $project)
) {
return $this->errFobidden(__('Access is denied'));
}
return $this->result([
'project' => $project,
'languages' => $project->languages()->with(['serviceTranslate'])->get(),
]);
}
public function update(int $projectId, Update $data, User $user): ServiceResultError | ServiceResultSuccess
{
$project = $this->projectRepository->getProjectById($projectId);
if (\is_null($project)) {
return $this->errNotFound(__('Not Found'));
}
if (
config('translation_service.enable', false) === false
|| $user->cannot('settingUpAutomaticTranslation', $project)
) {
return $this->errFobidden(__('Access is denied'));
}
try {
DB::transaction(function () use ($data, $project) {
$this->translationServiceModelSyncCommand->execute($project, $data->getTranslations());
});
} catch (\Throwable $e) {
report($e);
return $this->errService(__('Server Error'));
}
return $this->ok(__('The settings were saved successfully'));
}
}

View File

@@ -50,6 +50,7 @@ final class ProjectService extends Service
return $this->result([
'projects' => $projects,
'serviceTranslationEnable' => config('translation_service.enable', false),
]);
}