Implemented project-wide localization plumbing and converted the visible UI/app messages to translation-ready strings.

This commit is contained in:
2026-05-18 00:16:37 +03:30
parent b49b59a056
commit c6606d9602
60 changed files with 1376 additions and 345 deletions

View File

@@ -29,8 +29,8 @@ class AdminChannelCreationController extends Controller
return back()->with(
'success',
$settings->channel_creation_open
? 'All verified users can create channels.'
: 'Channel creation now requires admin approval.',
? __('All verified users can create channels.')
: __('Channel creation now requires admin approval.'),
);
}
@@ -51,8 +51,8 @@ class AdminChannelCreationController extends Controller
return back()->with(
'success',
$user->can_create_channel
? 'User can create a channel.'
: 'User channel creation access removed.',
? __('User can create a channel.')
: __('User channel creation access removed.'),
);
}

View File

@@ -25,7 +25,7 @@ class AdminModerationController extends Controller
$this->audit($request, $channel, 'channel.suspended');
return back()->with('success', 'Channel suspended.');
return back()->with('success', __('Channel suspended.'));
}
public function restoreChannel(Request $request, Channel $channel): RedirectResponse
@@ -34,7 +34,7 @@ class AdminModerationController extends Controller
$this->audit($request, $channel, 'channel.restored');
return back()->with('success', 'Channel restored.');
return back()->with('success', __('Channel restored.'));
}
public function suspendUser(Request $request, User $user, ViewerCountStore $viewerCounts): RedirectResponse
@@ -52,7 +52,7 @@ class AdminModerationController extends Controller
$this->audit($request, $user, 'user.suspended');
return back()->with('success', 'User suspended.');
return back()->with('success', __('User suspended.'));
}
public function stopBroadcast(Request $request, Broadcast $broadcast, ViewerCountStore $viewerCounts): RedirectResponse
@@ -71,7 +71,7 @@ class AdminModerationController extends Controller
$this->audit($request, $broadcast, 'broadcast.stopped');
return back()->with('success', 'Broadcast stopped.');
return back()->with('success', __('Broadcast stopped.'));
}
public function deleteVod(Request $request, Vod $vod): RedirectResponse
@@ -80,7 +80,7 @@ class AdminModerationController extends Controller
$this->audit($request, $vod, 'vod.deleted');
return back()->with('success', 'VOD deleted.');
return back()->with('success', __('VOD deleted.'));
}
private function audit(Request $request, object $subject, string $action): void

View File

@@ -46,7 +46,7 @@ class AdminSupportConversationController extends Controller
public function reply(StoreSupportMessageRequest $request, SupportConversation $conversation, SupportMessageCreator $messages): RedirectResponse
{
abort_unless($conversation->isOpen(), 422, 'Reopen this conversation before replying.');
abort_unless($conversation->isOpen(), 422, __('Reopen this conversation before replying.'));
$validated = $request->validated();
@@ -57,7 +57,7 @@ class AdminSupportConversationController extends Controller
$request->file('attachments', []) ?: [],
);
return back()->with('success', 'Reply sent.');
return back()->with('success', __('Reply sent.'));
}
public function update(UpdateSupportConversationStatusRequest $request, SupportConversation $conversation): RedirectResponse
@@ -68,7 +68,7 @@ class AdminSupportConversationController extends Controller
return back()->with(
'success',
$conversation->isOpen() ? 'Conversation reopened.' : 'Conversation closed.',
$conversation->isOpen() ? __('Conversation reopened.') : __('Conversation closed.'),
);
}
@@ -103,7 +103,7 @@ class AdminSupportConversationController extends Controller
return [
'id' => $conversation->id,
'category' => $conversation->category,
'category_label' => SupportConversation::categoryLabels()[$conversation->category] ?? 'Other',
'category_label' => SupportConversation::categoryLabels()[$conversation->category] ?? __('Other'),
'subject' => $conversation->subject,
'status' => $conversation->status,
'last_message_at' => $conversation->last_message_at?->toIso8601String(),
@@ -144,7 +144,7 @@ class AdminSupportConversationController extends Controller
'created_at' => $message->created_at?->toIso8601String(),
'author' => [
'id' => $message->user?->id,
'name' => $message->user?->name ?? 'Deleted user',
'name' => $message->user?->name ?? __('Deleted user'),
'is_admin' => (bool) $message->user?->is_admin,
],
];

View File

@@ -11,7 +11,7 @@ class ChatMessageController extends Controller
public function store(Request $request, Channel $channel): RedirectResponse
{
abort_if($request->user()->isSuspended() || $channel->isSuspended(), 403);
abort_unless($channel->is_live && $channel->live_broadcast_id, 422, 'Chat is available only while the channel is live.');
abort_unless($channel->is_live && $channel->live_broadcast_id, 422, __('Chat is available only while the channel is live.'));
$validated = $request->validate([
'body' => ['required', 'string', 'max:500'],

View File

@@ -58,8 +58,8 @@ class CreatorDashboardController extends Controller
public function storeChannel(Request $request, StreamKeyManager $streamKeys): RedirectResponse
{
abort_if($request->user()->channel()->exists(), 422, 'This account already owns a channel.');
abort_unless($request->user()->canCreateChannel(), 403, 'An admin must enable channel creation for this account.');
abort_if($request->user()->channel()->exists(), 422, __('This account already owns a channel.'));
abort_unless($request->user()->canCreateChannel(), 403, __('An admin must enable channel creation for this account.'));
$validated = $request->validate([
'display_name' => ['required', 'string', 'max:80'],
@@ -79,7 +79,7 @@ class CreatorDashboardController extends Controller
return redirect()
->route('dashboard')
->with('plain_stream_key', $plainStreamKey)
->with('success', 'Channel created. Save the stream key now; it will not be shown again.');
->with('success', __('Channel created. Save the stream key now; it will not be shown again.'));
}
public function updateChannel(Request $request): RedirectResponse
@@ -112,7 +112,7 @@ class CreatorDashboardController extends Controller
'slug' => Str::slug($validated['slug']),
]);
return back()->with('success', 'Channel updated.');
return back()->with('success', __('Channel updated.'));
}
public function rotateStreamKey(Request $request, StreamKeyManager $streamKeys): RedirectResponse
@@ -125,7 +125,7 @@ class CreatorDashboardController extends Controller
return back()
->with('plain_stream_key', $plainStreamKey)
->with('success', 'Stream key rotated. Update OBS before going live again.');
->with('success', __('Stream key rotated. Update OBS before going live again.'));
}
public function storeBroadcast(Request $request): RedirectResponse
@@ -137,7 +137,7 @@ class CreatorDashboardController extends Controller
abort_if(
$channel->broadcasts()->whereIn('status', [Broadcast::STATUS_PENDING, Broadcast::STATUS_LIVE])->exists(),
422,
'Finish the current broadcast before creating another.',
__('Finish the current broadcast before creating another.'),
);
$validated = $request->validate([
@@ -152,7 +152,7 @@ class CreatorDashboardController extends Controller
'mediamtx_path' => $channel->slug,
]);
return back()->with('success', 'Broadcast is ready. Start streaming from OBS.');
return back()->with('success', __('Broadcast is ready. Start streaming from OBS.'));
}
public function stopBroadcast(Request $request, Broadcast $broadcast, ViewerCountStore $viewerCounts): RedirectResponse
@@ -171,7 +171,7 @@ class CreatorDashboardController extends Controller
])->save();
$viewerCounts->forget($broadcast->channel);
return back()->with('success', 'Broadcast ended.');
return back()->with('success', __('Broadcast ended.'));
}
private function channelPayload(Channel $channel): array

View File

@@ -45,7 +45,7 @@ class SupportConversationController extends Controller
return redirect()
->route('support.show', $conversation)
->with('success', 'Message sent to admin.');
->with('success', __('Message sent to admin.'));
}
public function show(Request $request, SupportConversation $conversation): Response
@@ -65,7 +65,7 @@ class SupportConversationController extends Controller
public function reply(StoreSupportMessageRequest $request, SupportConversation $conversation, SupportMessageCreator $messages): RedirectResponse
{
$this->authorizeUserConversation($request, $conversation);
abort_unless($conversation->isOpen(), 422, 'This conversation is closed.');
abort_unless($conversation->isOpen(), 422, __('This conversation is closed.'));
$validated = $request->validated();
@@ -76,7 +76,7 @@ class SupportConversationController extends Controller
$request->file('attachments', []) ?: [],
);
return back()->with('success', 'Reply sent.');
return back()->with('success', __('Reply sent.'));
}
private function authorizeUserConversation(Request $request, SupportConversation $conversation): void
@@ -117,7 +117,7 @@ class SupportConversationController extends Controller
return [
'id' => $conversation->id,
'category' => $conversation->category,
'category_label' => SupportConversation::categoryLabels()[$conversation->category] ?? 'Other',
'category_label' => SupportConversation::categoryLabels()[$conversation->category] ?? __('Other'),
'subject' => $conversation->subject,
'status' => $conversation->status,
'last_message_at' => $conversation->last_message_at?->toIso8601String(),
@@ -153,7 +153,7 @@ class SupportConversationController extends Controller
'created_at' => $message->created_at?->toIso8601String(),
'author' => [
'id' => $message->user?->id,
'name' => $message->user?->name ?? 'Deleted user',
'name' => $message->user?->name ?? __('Deleted user'),
'is_admin' => (bool) $message->user?->is_admin,
],
];

View File

@@ -41,7 +41,40 @@ class HandleInertiaRequests extends Middleware
'auth' => [
'user' => $request->user(),
],
'fallbackLocale' => (string) config('app.fallback_locale'),
'locale' => app()->getLocale(),
'sidebarOpen' => ! $request->hasCookie('sidebar_state') || $request->cookie('sidebar_state') === 'true',
'translations' => fn () => $this->translations(),
];
}
/**
* @return array<string, string>
*/
private function translations(): array
{
$fallbackLocale = (string) config('app.fallback_locale');
$locale = app()->getLocale();
return [
...$this->jsonTranslations($fallbackLocale),
...$this->jsonTranslations($locale),
];
}
/**
* @return array<string, string>
*/
private function jsonTranslations(string $locale): array
{
$path = lang_path("{$locale}.json");
if (! is_file($path)) {
return [];
}
$translations = json_decode((string) file_get_contents($path), true);
return is_array($translations) ? $translations : [];
}
}

View File

@@ -34,10 +34,10 @@ class SupportConversation extends Model
public static function categoryLabels(): array
{
return [
self::CATEGORY_BUG => 'Bug report',
self::CATEGORY_SUGGESTION => 'Suggestion',
self::CATEGORY_CHANNEL_REQUEST => 'Channel request',
self::CATEGORY_OTHER => 'Other',
self::CATEGORY_BUG => (string) __('Bug report'),
self::CATEGORY_SUGGESTION => (string) __('Suggestion'),
self::CATEGORY_CHANNEL_REQUEST => (string) __('Channel request'),
self::CATEGORY_OTHER => (string) __('Other'),
];
}

View File

@@ -64,9 +64,9 @@ class SupportAttachmentFile implements ValidationRule
],
],
[
'attachment.file' => 'Attachment upload failed. Try the file again or choose a different file.',
'attachment.max' => 'Attachments must be 200 MB or smaller.',
'attachment.mimetypes' => 'Unsupported attachment type. Upload media, PDF, text/data, Office, OpenDocument, or archive files.',
'attachment.file' => __('Attachment upload failed. Try the file again or choose a different file.'),
'attachment.max' => __('Attachments must be 200 MB or smaller.'),
'attachment.mimetypes' => __('Unsupported attachment type. Upload media, PDF, text/data, Office, OpenDocument, or archive files.'),
],
);