420 lines
18 KiB
PHP
420 lines
18 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\User;
|
|
use App\Models\Setting;
|
|
use App\Models\AddOn;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\File;
|
|
use Illuminate\Support\Facades\Cookie;
|
|
use Inertia\Inertia;
|
|
use Illuminate\Support\Facades\Artisan;
|
|
|
|
class TranslationController extends Controller
|
|
{
|
|
private function getAllowedLanguages(): array
|
|
{
|
|
$languagesData = json_decode(File::get(resource_path('lang/language.json')), true);
|
|
return collect($languagesData)->pluck('code')->toArray();
|
|
}
|
|
|
|
public function getTranslations($locale)
|
|
{
|
|
$locale = strtolower($locale);
|
|
if (!in_array($locale, array_map('strtolower', $this->getAllowedLanguages()))) {
|
|
$locale = 'en';
|
|
}
|
|
|
|
$path = resource_path("lang/{$locale}.json");
|
|
|
|
if (!File::exists($path)) {
|
|
$path = resource_path("lang/en.json");
|
|
$locale = 'en';
|
|
}
|
|
|
|
// $layoutDirection = in_array($locale, ['ar', 'he']) ? 'rtl' : 'ltr';
|
|
$layoutDirection = in_array($locale, ['ar', 'he']) ? 'rtl' : 'ltr';
|
|
|
|
$translations = json_decode(File::get($path), true) ?? [];
|
|
|
|
// Merge enabled package translations
|
|
$enabledPackages = AddOn::where('is_enable', true)->pluck('module');
|
|
foreach ($enabledPackages as $packageName) {
|
|
$packageLangFile = base_path("packages/workdo/{$packageName}/src/Resources/lang/{$locale}.json");
|
|
if (File::exists($packageLangFile)) {
|
|
$packageTranslations = json_decode(File::get($packageLangFile), true) ?? [];
|
|
$translations = array_merge($translations, $packageTranslations);
|
|
}
|
|
}
|
|
|
|
if (empty($translations)) {
|
|
return response()->json(['error' => __('Invalid translation file')], 500);
|
|
}
|
|
|
|
app()->setLocale($locale);
|
|
|
|
return response()->json([
|
|
'translations' => $translations,
|
|
'layoutDirection' => null,
|
|
'locale' => $locale
|
|
]);
|
|
}
|
|
|
|
public function manage(Request $request)
|
|
{
|
|
if(auth()->user()->type == 'superadmin') {
|
|
$currentLanguage = $request->get('lang', 'en');
|
|
$search = $request->get('search', '');
|
|
$page = $request->get('page', 1);
|
|
$perPage = 50;
|
|
|
|
if (!in_array($currentLanguage, $this->getAllowedLanguages())) {
|
|
$currentLanguage = 'en';
|
|
}
|
|
|
|
// Load current language translations
|
|
$path = resource_path("lang/{$currentLanguage}.json");
|
|
$allTranslations = [];
|
|
|
|
if (File::exists($path)) {
|
|
$allTranslations = json_decode(File::get($path), true) ?? [];
|
|
}
|
|
|
|
// Filter translations based on search
|
|
$filteredTranslations = $allTranslations;
|
|
if ($search) {
|
|
$filteredTranslations = array_filter($allTranslations, function($value, $key) use ($search) {
|
|
return stripos($key, $search) !== false || stripos($value, $search) !== false;
|
|
}, ARRAY_FILTER_USE_BOTH);
|
|
}
|
|
|
|
// Paginate translations
|
|
$total = count($filteredTranslations);
|
|
$lastPage = $total > 0 ? ceil($total / $perPage) : 1;
|
|
$offset = ($page - 1) * $perPage;
|
|
$paginatedTranslations = array_slice($filteredTranslations, $offset, $perPage, true);
|
|
|
|
$paginationData = [
|
|
'current_page' => (int)$page,
|
|
'data' => $paginatedTranslations,
|
|
'first_page_url' => $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => 1])),
|
|
'from' => $total > 0 ? $offset + 1 : 0,
|
|
'last_page' => $lastPage,
|
|
'last_page_url' => $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $lastPage])),
|
|
'next_page_url' => $page < $lastPage ? $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $page + 1])) : null,
|
|
'path' => $request->url(),
|
|
'per_page' => $perPage,
|
|
'prev_page_url' => $page > 1 ? $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $page - 1])) : null,
|
|
'to' => min($offset + $perPage, $total),
|
|
'total' => $total
|
|
];
|
|
|
|
// Get enabled packages list only
|
|
$enabledPackages = AddOn::where('is_enable', true)->get(['package_name', 'name']);
|
|
|
|
// Get available languages with flags
|
|
$languagesData = json_decode(File::get(resource_path('lang/language.json')), true);
|
|
$availableLanguages = collect($languagesData)
|
|
->filter(fn($lang) => ($lang['enabled'] ?? true))
|
|
->map(function ($lang) {
|
|
return [
|
|
'code' => $lang['code'],
|
|
'name' => $lang['name'],
|
|
'countryCode' => $lang['countryCode'],
|
|
'flag' => $this->getCountryFlag($lang['countryCode'])
|
|
];
|
|
})->values()->toArray();
|
|
|
|
// Get current language status
|
|
$currentLangData = collect($languagesData)->firstWhere('code', $currentLanguage);
|
|
$isCurrentLanguageEnabled = $currentLangData['enabled'] ?? true;
|
|
|
|
return Inertia::render('languages/manage', [
|
|
'currentLanguage' => $currentLanguage,
|
|
'translations' => $paginationData,
|
|
'enabledPackages' => $enabledPackages,
|
|
'availableLanguages' => $availableLanguages,
|
|
'isCurrentLanguageEnabled' => $isCurrentLanguageEnabled,
|
|
'filters' => ['search' => $search]
|
|
]);
|
|
}
|
|
else
|
|
{
|
|
return redirect()->route('dashboard')->with('error', __('Permission denied'));
|
|
}
|
|
}
|
|
|
|
public function updateTranslations(Request $request, $locale)
|
|
{
|
|
|
|
if (!in_array($locale, $this->getAllowedLanguages())) {
|
|
return response()->json(['error' => __('Invalid language')], 400);
|
|
}
|
|
|
|
$request->validate([
|
|
'translations' => 'required|array'
|
|
], [
|
|
'translations.required' => __('Translations are required.'),
|
|
'translations.array' => __('Translations must be a valid array.'),
|
|
]);
|
|
|
|
$translations = $request->input('translations');
|
|
$path = resource_path("lang/{$locale}.json");
|
|
|
|
try {
|
|
// Save new translations
|
|
$currentTranslations = json_decode(File::get($path), true) ?? [];
|
|
$translations = array_merge($currentTranslations, $translations);
|
|
File::put($path, json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
|
|
return response()->json(['success' => true, 'message' => __('The translation details are updated successfully.')]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => __('Failed to save translations: :error', ['error' => $e->getMessage()])], 500);
|
|
}
|
|
}
|
|
|
|
public function getPackageTranslations(Request $request, $locale, $packageName)
|
|
{
|
|
$search = $request->get('search', '');
|
|
$page = $request->get('page', 1);
|
|
$perPage = 50;
|
|
|
|
if (!in_array($locale, $this->getAllowedLanguages())) {
|
|
return response()->json(['error' => __('Invalid language')], 400);
|
|
}
|
|
|
|
$package = AddOn::where('package_name', $packageName)->where('is_enable', true)->first();
|
|
if (!$package) {
|
|
return response()->json(['error' => __('Package not found or disabled')], 404);
|
|
}
|
|
|
|
$packageLangFile = base_path("packages/workdo/{$package->module}/src/Resources/lang/{$locale}.json");
|
|
if (!File::exists($packageLangFile)) {
|
|
$packageLangFile = base_path("packages/workdo/{$package->module}/src/Resources/lang/en.json");
|
|
if (!File::exists($packageLangFile)) {
|
|
return response()->json(['translations' => []]);
|
|
}
|
|
}
|
|
|
|
$translations = json_decode(File::get($packageLangFile), true) ?? [];
|
|
|
|
// Filter translations based on search
|
|
$filteredTranslations = $translations;
|
|
if ($search) {
|
|
$filteredTranslations = array_filter($translations, function($value, $key) use ($search) {
|
|
return stripos($key, $search) !== false || stripos($value, $search) !== false;
|
|
}, ARRAY_FILTER_USE_BOTH);
|
|
}
|
|
|
|
// Paginate translations
|
|
$total = count($filteredTranslations);
|
|
$lastPage = $total > 0 ? ceil($total / $perPage) : 1;
|
|
$offset = ($page - 1) * $perPage;
|
|
$paginatedTranslations = array_slice($filteredTranslations, $offset, $perPage, true);
|
|
|
|
$paginationData = [
|
|
'current_page' => (int)$page,
|
|
'data' => $paginatedTranslations,
|
|
'first_page_url' => $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => 1])),
|
|
'from' => $total > 0 ? $offset + 1 : 0,
|
|
'last_page' => $lastPage,
|
|
'last_page_url' => $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $lastPage])),
|
|
'next_page_url' => $page < $lastPage ? $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $page + 1])) : null,
|
|
'path' => $request->url(),
|
|
'per_page' => $perPage,
|
|
'prev_page_url' => $page > 1 ? $request->url() . '?' . http_build_query(array_merge($request->except('page'), ['page' => $page - 1])) : null,
|
|
'to' => min($offset + $perPage, $total),
|
|
'total' => $total
|
|
];
|
|
return response()->json(['translations' => $paginationData]);
|
|
}
|
|
|
|
public function updatePackageTranslations(Request $request, $locale, $packageName)
|
|
{
|
|
if (!in_array($locale, $this->getAllowedLanguages())) {
|
|
return response()->json(['error' => __('Invalid language')], 400);
|
|
}
|
|
|
|
$package = AddOn::where('package_name', $packageName)->where('is_enable', true)->first();
|
|
if (!$package) {
|
|
return response()->json(['error' => __('Package not found or disabled')], 404);
|
|
}
|
|
|
|
$request->validate([
|
|
'translations' => 'required|array'
|
|
], [
|
|
'translations.required' => __('Package translations are required.'),
|
|
'translations.array' => __('Package translations must be a valid array.'),
|
|
]);
|
|
|
|
$translations = $request->input('translations');
|
|
$packageLangFile = base_path("packages/workdo/{$package->module}/src/Resources/lang/{$locale}.json");
|
|
|
|
try {
|
|
$packageLangDir = dirname($packageLangFile);
|
|
if (!File::exists($packageLangDir)) {
|
|
File::makeDirectory($packageLangDir, 0755, true);
|
|
}
|
|
|
|
if (File::exists($packageLangFile)) {
|
|
$currentTranslations = json_decode(File::get($packageLangFile), true) ?? [];
|
|
$translations = array_merge($currentTranslations, $translations);
|
|
}
|
|
File::put($packageLangFile, json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
return response()->json(['success' => true, 'message' => __('The package translations updated successfully.')]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => __('Failed to save package translations: :error', ['error' => $e->getMessage()])], 500);
|
|
}
|
|
}
|
|
|
|
public function createLanguage(Request $request)
|
|
{
|
|
$request->validate([
|
|
'code' => 'required|string|max:10',
|
|
'name' => 'required|string|max:255',
|
|
'countryCode' => 'required|string|size:2'
|
|
], [
|
|
'code.required' => __('Language code is required.'),
|
|
'code.string' => __('Language code must be a valid string.'),
|
|
'code.max' => __('Language code must not exceed 10 characters.'),
|
|
'name.required' => __('Language name is required.'),
|
|
'name.string' => __('Language name must be a valid string.'),
|
|
'name.max' => __('Language name must not exceed 255 characters.'),
|
|
'countryCode.required' => __('Country code is required.'),
|
|
'countryCode.string' => __('Country code must be a valid string.'),
|
|
'countryCode.size' => __('Country code must be exactly 2 characters.'),
|
|
]);
|
|
|
|
try {
|
|
// Check if language already exists in language.json
|
|
$languagesFile = resource_path('lang/language.json');
|
|
$languages = json_decode(File::get($languagesFile), true);
|
|
|
|
$existingLanguage = collect($languages)->firstWhere('code', $request->code);
|
|
if ($existingLanguage) {
|
|
return response()->json(['error' => __('The language code already exists')], 422);
|
|
}
|
|
$languages[] = [
|
|
'code' => $request->code,
|
|
'name' => $request->name,
|
|
'countryCode' => strtoupper($request->countryCode)
|
|
];
|
|
File::put($languagesFile, json_encode($languages, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
|
|
// Copy en.json to new language
|
|
$enFile = resource_path('lang/en.json');
|
|
$newLangFile = resource_path("lang/{$request->code}.json");
|
|
if (File::exists($enFile)) {
|
|
File::copy($enFile, $newLangFile);
|
|
}
|
|
|
|
// Copy package translations
|
|
$enabledPackages = AddOn::where('is_enable', true)->pluck('module');
|
|
foreach ($enabledPackages as $packageName) {
|
|
$packageEnFile = base_path("packages/workdo/{$packageName}/src/Resources/lang/en.json");
|
|
$packageNewFile = base_path("packages/workdo/{$packageName}/src/Resources/lang/{$request->code}.json");
|
|
if (File::exists($packageEnFile)) {
|
|
$packageDir = dirname($packageNewFile);
|
|
if (!File::exists($packageDir)) {
|
|
File::makeDirectory($packageDir, 0755, true);
|
|
}
|
|
File::copy($packageEnFile, $packageNewFile);
|
|
}
|
|
}
|
|
|
|
return response()->json(['success' => true, 'message' => __('The language has been created successfully.')]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => __('Failed to create language: :error', ['error' => $e->getMessage()])], 500);
|
|
}
|
|
}
|
|
|
|
public function deleteLanguage($languageCode)
|
|
{
|
|
if ($languageCode === 'en') {
|
|
return response()->json(['error' => __('Cannot delete English language')], 422);
|
|
}
|
|
|
|
try {
|
|
// Remove from language.json
|
|
$languagesFile = resource_path('lang/language.json');
|
|
$languages = json_decode(File::get($languagesFile), true);
|
|
$languages = array_filter($languages, fn($lang) => $lang['code'] !== $languageCode);
|
|
File::put($languagesFile, json_encode(array_values($languages), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
|
|
// Delete main language file
|
|
$mainLangFile = resource_path("lang/{$languageCode}.json");
|
|
if (File::exists($mainLangFile)) {
|
|
File::delete($mainLangFile);
|
|
}
|
|
|
|
// Delete package language files
|
|
$enabledPackages = AddOn::where('is_enable', true)->pluck('module');
|
|
foreach ($enabledPackages as $packageName) {
|
|
$packageLangFile = base_path("packages/workdo/{$packageName}/src/Resources/lang/{$languageCode}.json");
|
|
if (File::exists($packageLangFile)) {
|
|
File::delete($packageLangFile);
|
|
}
|
|
}
|
|
|
|
return response()->json(['success' => true, 'message' => __('The language has been deleted.')]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => __('Failed to delete language: :error', ['error' => $e->getMessage()])], 500);
|
|
}
|
|
}
|
|
|
|
public function toggleLanguageStatus($languageCode)
|
|
{
|
|
if ($languageCode === 'en') {
|
|
return response()->json(['error' => __('Cannot disable English language')], 422);
|
|
}
|
|
|
|
try {
|
|
$languagesFile = resource_path('lang/language.json');
|
|
$languages = json_decode(File::get($languagesFile), true);
|
|
|
|
foreach ($languages as &$language) {
|
|
if ($language['code'] === $languageCode) {
|
|
$language['enabled'] = !($language['enabled'] ?? true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
File::put($languagesFile, json_encode($languages, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
return response()->json(['success' => true, 'message' => __('The language status updated successfully.')]);
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => __('Failed to update language status: :error', ['error' => $e->getMessage()])], 500);
|
|
}
|
|
}
|
|
|
|
public function changeLanguage(Request $request)
|
|
{
|
|
if (!auth()->check()) {
|
|
return response()->json(['error' => __('Unauthorized')], 401);
|
|
}
|
|
|
|
$request->validate([
|
|
'lang' => 'required|string'
|
|
]);
|
|
|
|
$locale = strtolower($request->input('lang'));
|
|
// $layoutDirection = in_array($locale, ['ar', 'he']) ? 'rtl' : 'ltr';
|
|
|
|
auth()->user()->update(['lang' => $locale]);
|
|
|
|
// when company's user change then update company setting
|
|
// setSetting('layoutDirection', $layoutDirection);
|
|
}
|
|
|
|
private function getCountryFlag(string $countryCode): string
|
|
{
|
|
if (strlen($countryCode) !== 2) {
|
|
return '🌐'; // Default flag for invalid codes
|
|
}
|
|
|
|
$codePoints = str_split(strtoupper($countryCode));
|
|
$codePoints = array_map(fn($char) => 127397 + ord($char), $codePoints);
|
|
return mb_convert_encoding('&#' . implode(';&#', $codePoints) . ';', 'UTF-8', 'HTML-ENTITIES');
|
|
}
|
|
}
|