24 changed files with 426 additions and 167 deletions
+2 -2
View File
@@ -2,6 +2,7 @@
namespace App\CMS\Helpers;
use App\CMS\Repositories\Settings\Settings as SettingsRepository;
use App\Models\Settings as SettingsModel;
use Illuminate\Support\Facades\Cache;
@@ -78,8 +79,7 @@ class Settings
{
if (!self::$initialized) {
self::$settings = Cache::remember('settings', config('cache.settingCacheLifetime'), function () {
$model = new SettingsModel();
return $model->getAll();
app(SettingsRepository::class)->getAll();
});
}
}
@@ -1,27 +1,26 @@
<?php
namespace App\Models\ModelTraits;
namespace App\CMS\Repositories\Settings;
use App\Models\Settings as SettingsModel;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
trait Settings
class Settings
{
/**
* Prepares common query for selecting settings
*
* @return mixed
*/
protected function getSettingsQuery()
{
return SettingsModel::select(['key', 'value', 'language'])
->where('language', LaravelLocalization::getCurrentLocale())
->orWhere('language', null)
->orderBy('language', 'ASC');
->where('language', LaravelLocalization::getCurrentLocale())
->orWhere('language', null)
->orderBy('language', 'ASC');
}
/**
* Load all settings
*
* @return \stdClass
*/
public function getAll()
@@ -34,7 +33,6 @@ trait Settings
/**
* Get all settings with language info
*
* @return \stdClass
*/
public function getAllWithLanguage()
@@ -55,7 +53,6 @@ trait Settings
/**
* Load only config for views
*
* @return \stdClass
*/
public function getForView()
@@ -83,4 +80,29 @@ trait Settings
return $data;
}
/**
* Save settings
*
* @param array $data
*/
public function save(array $data)
{
$commonSettings = isset($data['commonSettings']) ? $data['commonSettings'] : [];
unset($data['commonSettings']);
foreach ($data as $key => $value) {
// select language for this setting key
$language = isset($commonSettings[$key]) ? null : LaravelLocalization::getCurrentLocale();
$setting = SettingsModel::firstOrNew(['language' => $language, 'key' => $key]);
if ($setting->value == $value) {
continue;
}
// set value and save or delete
$setting->value = $value;
empty($value) ? $setting->delete() : $setting->save();
}
}
}
@@ -0,0 +1,44 @@
<?php
namespace App\Console\Commands\Modules;
use App\Models\Module;
use Illuminate\Console\Command;
class DisableModule extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'module:disable {module}';
/**
* The console command description.
* @var string
*/
protected $description = 'Disable module';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$moduleName = $this->argument('module');
$module = Module::where('static_name', $moduleName)
->firstOrFail();
if ($module->has_submodules) {
$submodules = $module->submodules;
foreach ($submodules as $submodule) {
$this->call('module:disable', ['module' => $submodule->static_name]);
}
}
$module->enabled = false;
$module->save();
$this->line('Module ' . $module->static_name . ' disabled.');
}
}
@@ -0,0 +1,48 @@
<?php
namespace App\Console\Commands\Modules;
use App\Models\Module;
use Illuminate\Console\Command;
class EnableModule extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'module:enable {module}';
/**
* The console command description.
* @var string
*/
protected $description = 'Enable module';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$moduleName = $this->argument('module');
$module = Module::where('static_name', $moduleName)
->firstOrFail();
if ($module->has_submodules) {
$submodules = $module->submodules;
foreach ($submodules as $submodule) {
$this->call('module:enable', ['module' => $submodule->static_name]);
}
}
if ($module->parent_id) {
$module->parent->update(['enabled' => true]);
}
$module->enabled = true;
$module->save();
$this->line('Module ' . $module->static_name . ' enabled.');
}
}
@@ -155,13 +155,12 @@ class InstallModule extends Command
if (is_null($module)) {
// insert module into database
$settings = [
'staticName' => $this->moduleName,
'providers' => $providers,
'order' => isset($config['order']) ? $config['order'] : 0,
'files' => isset($config['files']) ? $config['files'] : []
];
$module = Installer::install($name, $alias, $description, $handler, $this->parentModuleId, $settings);
$module = Installer::install($name, $alias, $this->moduleName, $description, $handler, $this->parentModuleId, $settings);
}
// try to install submodules
@@ -0,0 +1,42 @@
<?php
namespace App\Console\Commands\Modules;
use App\Models\Module;
use Illuminate\Console\Command;
class ModuleMigrate extends Command
{
/**
* The name and signature of the console command.
* @var string
*/
protected $signature = 'module:migrate {module}';
/**
* The console command description.
* @var string
*/
protected $description = 'Run migrations in specified module';
/**
* Execute the console command.
* @return mixed
*/
public function handle()
{
$moduleName = $this->argument('module');
$module = Module::where('static_name', $moduleName)
->firstOrFail();
if ($module->has_submodules) {
$submodules = $module->submodules;
foreach ($submodules as $submodule) {
$this->call('module:migrate', ['module' => $submodule->static_name]);
}
}
$this->line('Migrating ' . $module->static_name);
$this->call('migrate', ['--path' => config('modules.paths.modules').'/'.$moduleName.'/Database']);
}
}
+2 -2
View File
@@ -45,7 +45,7 @@ class SetTemplate extends Command
$config['staticName'] = $template;
if ($current) {
$this->line('Template is already installed. Currently using template ' . trans($current->name) . ' located in /templates/' . $current->module_settings['staticName'] . '.');
$this->line('Template is already installed. Currently using template ' . trans($current->name) . ' located in /templates/' . $current->static_name . '.');
$confirm = $this->confirm('Uninstall it and install *' . trans($config['name']) . '*? All data associated with installed template will be lost!');
if ($confirm) {
@@ -59,7 +59,7 @@ class SetTemplate extends Command
}
try {
Installer::install($config['name'], $config['alias'], $config['description'], $config['handler'], false, $config);
Installer::install($config['name'], $config['alias'], $current->static_name, $config['description'], $config['handler'], false, $config);
} catch (\Exception $e) {
$this->error('Cannot install template ' . $template . '. Message: ' . $e->getMessage());
return;
+42
View File
@@ -0,0 +1,42 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class UninstallModule extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'command:name';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
//
}
}
+6 -1
View File
@@ -3,6 +3,9 @@
namespace App\Console;
use App\Console\Commands\Modules\CreateNew;
use App\Console\Commands\Modules\DisableModule;
use App\Console\Commands\Modules\EnableModule;
use App\Console\Commands\Modules\ModuleMigrate;
use App\Console\Commands\PublishTemplateResources;
use App\Console\Commands\TemplateInfo;
use Illuminate\Console\Scheduling\Schedule;
@@ -12,13 +15,15 @@ class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\NewUser::class,
Commands\ChangePassword::class,
CreateNew::class,
ModuleMigrate::class,
EnableModule::class,
DisableModule::class,
Commands\Modules\InstallModule::class,
Commands\Modules\InstallAllModules::class,
Commands\TranslateDirectory::class,
+9 -13
View File
@@ -2,37 +2,33 @@
namespace App\Events;
use App\Models\FileManager\File as FileModel;
use Illuminate\Queue\SerializesModels;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class UploadFile extends Event
{
use SerializesModels;
/**
* @var UploadedFile
*/
public $uploadedFile;
/**
* @var
* @var FileModel
*/
public $id;
public $file;
/**
* Create a new event instance.
*
* @param File $uploadedFile
* @param $id
* @param FileModel $file
* @param $id
*
* @internal param File $uploadedFile
*/
public function __construct(File $uploadedFile, $id)
public function __construct(FileModel $file)
{
$this->uploadedFile = $uploadedFile;
$this->id = $id;
$this->file = $file;
}
/**
* Get the channels the event should be broadcast on.
*
* @return array
*/
public function broadcastOn()
@@ -47,7 +47,7 @@ class UploadFile extends Controller
*/
private function internalUpload(Request $request)
{
try {
// try {
$uploadedFiles = [];
$files = $request->all()['files'];
@@ -62,9 +62,9 @@ class UploadFile extends Controller
return redirect()
->back()
->with('success', trans_choice('admin/fileManager.uploadSuccessfull', $successfullUploads));
} catch (FileException $e) {
return $this->invalidUpload('invalidFile');
}
// } catch (FileException $e) {
// return $this->invalidUpload('invalidFile');
// }
}
/**
+4 -24
View File
@@ -2,15 +2,15 @@
namespace App\Http\Controllers\Admin;
use App\CMS\Repositories\Settings\Settings as SettingsRepository;
use App\Http\Requests;
use App\Models\Settings as SettingsModel;
use Illuminate\Support\Facades\App;
use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class Settings extends Controller
{
/**
* @var SettingsModel
* @var SettingsRepository
*/
protected $settings;
@@ -19,14 +19,13 @@ class Settings extends Controller
*
* @param SettingsModel $settings
*/
public function __construct(SettingsModel $settings)
public function __construct(SettingsRepository $settings)
{
$this->settings = $settings;
}
/**
* Get overview (with form) for editing settings
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function getOverview()
@@ -45,7 +44,6 @@ class Settings extends Controller
/**
* Save all settings (ignore empty ones)
*
* When settings used to be non-empty string and user deletes it, key is also deleted from database
*
* @param Requests\SaveSettingsRequest $request
@@ -54,25 +52,7 @@ class Settings extends Controller
*/
public function saveSettings(Requests\SaveSettingsRequest $request)
{
$data = $request->all();
$commonSettings = isset($data['commonSettings']) ? $data['commonSettings'] : [];
// remove CSRF token field
unset($data['_token'], $data['commonSettings']);
foreach ($data as $key => $value) {
// select language for this setting key
$language = isset($commonSettings[$key]) ? null : LaravelLocalization::getCurrentLocale();
$setting = SettingsModel::firstOrNew(['language' => $language, 'key' => $key]);
if ($setting->value == $value) {
continue;
}
// set value and save or delete
$setting->value = $value;
empty($value) ? $setting->delete() : $setting->save();
}
$this->settings->save($request->except(['_token']));
return redirect()
->route('settings.overview')
+9 -14
View File
@@ -3,23 +3,16 @@
namespace App\Listeners;
use App\Events\UploadFile;
use App\Models\FileManager\File;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\File as FileFacade;
use Illuminate\Support\Str;
use Intervention\Image\Constraint;
use Intervention\Image\Facades\Image;
use Symfony\Component\HttpFoundation\File\File as SymphonyFile;
class CreateImageThumbnail
class CreateImageThumbnail implements ShouldQueue
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
}
/**
* Handle the event.
*
@@ -29,10 +22,10 @@ class CreateImageThumbnail
*/
public function handle(UploadFile $event)
{
$uploadedFile = $event->uploadedFile;
$uploadedFile = $event->file;
// is uploaded file an image?
if (!Str::startsWith($uploadedFile->getMimeType(), 'image')) {
if (!Str::startsWith($uploadedFile->mime_type, 'image')) {
return;
}
// yes, create thumbnail
@@ -42,10 +35,12 @@ class CreateImageThumbnail
/**
* Create thumbnail of given image
*
* @param SymphonyFile $file
* @param File $uploadedFile
*/
private function createThumbnail(SymphonyFile $file)
private function createThumbnail(File $uploadedFile)
{
$file = new SymphonyFile(config('app.upload_path') . '/' . $uploadedFile->filename);
// does thumbnail directory exist?
if (!is_dir(config('app.thumbnail_path'))) {
FileFacade::makeDirectory(config('app.thumbnail_path'));
+20 -17
View File
@@ -2,30 +2,33 @@
namespace App\Listeners\Loggers;
use App\Events\Uploadfile;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Events\UploadFile;
class LogUploadFile
class LogUploadFile extends Logger
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param Uploadfile $event
* @param CreateNewWidget $event
*
* @return void
*/
public function handle(Uploadfile $event)
public function handle(UploadFile $event)
{
//
$parameters = [
'name' => $event->file->filename,
'mime' => $event->file->mime_type,
];
$this->saveLog($parameters);
}
/**
* Getter for action name. Used only internally
* @return mixed
*/
protected function getName()
{
return 'newFile';
}
}
+13 -10
View File
@@ -6,6 +6,7 @@ use App\CMS\Contracts\Repositories\Content as ContentContract;
use App\CMS\Helpers\Traits\Nullable;
use App\CMS\Observers\Content as ContentObserver;
use App\Models\FileManager\File;
use App\Models\Module;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
@@ -55,7 +56,6 @@ class Content extends Model
/**
* Mark relationship with its historical records
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function history()
@@ -65,7 +65,6 @@ class Content extends Model
/**
* Mark relationship with users table
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function author()
@@ -75,7 +74,6 @@ class Content extends Model
/**
* Related files to content page
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function files()
@@ -85,7 +83,6 @@ class Content extends Model
/**
* Category of content page
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function category()
@@ -95,7 +92,6 @@ class Content extends Model
/**
* Subpages assigned to page
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function subpages()
@@ -103,9 +99,17 @@ class Content extends Model
return $this->hasMany(Content::class, 'parentId');
}
/**
* Module relationship
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function module()
{
return $this->belongsTo(Module::class, 'moduleHandler', 'handler');
}
/**
* Parent page
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function parentPage()
@@ -115,7 +119,6 @@ class Content extends Model
/**
* Is current content draft?
*
* @return bool
*/
public function isDraft()
@@ -125,7 +128,6 @@ class Content extends Model
/**
* Is current content visible for all visitors?
*
* @return bool
*/
public function isPublic()
@@ -135,7 +137,6 @@ class Content extends Model
/**
* Is current content visible only for logged users?
*
* @return bool
*/
public function isProtected()
@@ -145,7 +146,6 @@ class Content extends Model
/**
* Is current content visible for logged user OR for everyone?
*
* @return bool
*/
public function isVisible()
@@ -164,6 +164,9 @@ class Content extends Model
return parent::save($options);
}
/**
* Increment number of viewed content
*/
public function view()
{
$this->timestamps = false;
+4 -4
View File
@@ -45,15 +45,15 @@ trait File
$uploadedFile = $file->move($destination, $filename);
// insert record into database
$id = $this->saveIntoDatabase($uploadedFile, $data, $file->getClientOriginalName());
$fileInDB = $this->saveIntoDatabase($uploadedFile, $data, $file->getClientOriginalName());
// fire event about new file
Event::fire(new UploadFile($uploadedFile, $id));
Event::fire(new UploadFile($fileInDB));
return [
'filename' => $filename,
'file' => $file,
'id' => $id
'id' => $fileInDB->id
];
}
@@ -89,6 +89,6 @@ trait File
'keywords' => isset($request->keyword) ? $request->keyword : ''
]);
return $newFile->id;
return $newFile;
}
}
+11 -1
View File
@@ -15,6 +15,7 @@ class Module extends Model
'parent_id',
'name',
'description',
'static_name', // @todo instalace potrebuje naplnit tento sloupec!
'alias',
'module_settings',
'enabled',
@@ -30,6 +31,15 @@ class Module extends Model
public function getRouteKeyName()
{
return 'alias';
return 'alias';
}
public function submodules()
{
return $this->hasMany(Module::class, 'parent_id');
}
public function parent() {
return $this->belongsTo(Module::class, 'parent_id');
}
}
-2
View File
@@ -7,8 +7,6 @@ use Mcamara\LaravelLocalization\Facades\LaravelLocalization;
class Settings extends Model
{
use ModelTraits\Settings;
protected $table = 'settings';
public $timestamps = false;
protected $fillable = ['key', 'value', 'language'];
+16 -13
View File
@@ -1,4 +1,5 @@
<?php
namespace App\ModuleManager;
use App\CMS\Contracts\Modules\AppHandler;
@@ -6,7 +7,8 @@ use App\CMS\Contracts\Modules\TemplateHandler;
use App\Models\Module;
use Illuminate\Support\Facades\App;
class Installer {
class Installer
{
/**
* Create new module in database
*
@@ -20,7 +22,7 @@ class Installer {
* @return Module
* @throws \ErrorException
*/
public static function install($name, $alias, $description, $handler, $parentModuleId, $settings)
public static function install($name, $alias, $staticName, $description, $handler, $parentModuleId, $settings)
{
// check if user does not want to install module in runtime
if (!App::runningInConsole()) {
@@ -39,17 +41,18 @@ class Installer {
// insert module into database
$module = Module::create([
'name' => $name,
'description' => $description,
'handler' => $handler,
'manages_content' => $managesContent,
'support_categories' => $supportCategories,
'alias' => $alias,
'module_settings' => $settings,
'parent_id' => $parentModuleId ? $parentModuleId : null,
'enabled' => 1,
'is_template' => $isTemplate
]);
'name' => $name,
'description' => $description,
'handler' => $handler,
'static_name' => $staticName,
'manages_content' => $managesContent,
'support_categories' => $supportCategories,
'alias' => $alias,
'module_settings' => $settings,
'parent_id' => $parentModuleId ? $parentModuleId : null,
'enabled' => 1,
'is_template' => $isTemplate
]);
// install something module-specific
if ($handler && is_callable([$handler, 'install'])) {
@@ -32,7 +32,7 @@ class ModuleManager extends ServiceProvider
// include files (if any)
if (isset($module->module_settings['files']) && !empty($module->module_settings['files'])) {
foreach ($module->module_settings['files'] as $file) {
include config('modules.paths.modules') . '/' . $module->module_settings['staticName'] . '/' . $file;
include config('modules.paths.modules') . '/' . $module->static_name . '/' . $file;
}
}
}
+1 -1
View File
@@ -94,7 +94,7 @@ class TemplateServiceProvider extends ServiceProvider
return;
}
$templateDir = base_path('templates/' . $template->module_settings['staticName']. '/Resources');
$templateDir = base_path('templates/' . $template->static_name. '/Resources');
$assetsDir = $templateDir . '/' . TemplateContract::ASSETS_DIRECTORY;
$viewsDir = $templateDir . '/views';
@@ -0,0 +1,38 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddStaticNameToModulesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('modules', function (Blueprint $table) {
$table->string('static_name')->after('description');
});
$modules = \App\Models\Module::all();
foreach ($modules as $module) {
$module->update(['static_name' => $module->static_name]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('modules', function (Blueprint $table) {
$table->dropColumn('static_name');
});
}
}
@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
class AddNewActionLogType extends Migration
{
/**
* Run the migrations.
* @return void
*/
public function up()
{
\App\Models\ActionLog\ActionLogType::create([
'string_id' => 'newFile',
'name' => 'admin/actionLog.nameNewFile',
'value' => 'admin/actionLog.newFile'
]);
}
/**
* Reverse the migrations.
* @return void
*/
public function down()
{
\App\Models\ActionLog\ActionLogType::where('string_id', 'newFile')
->delete();
}
}
+49 -47
View File
@@ -1,51 +1,53 @@
<?php
return [
"assignWidget" => "Přiřadil widget :widgetName (#:widgetId) do plochy :widgetAreaName (#:widgetAreaId)",
"changeSettings" => "Změna nastavení",
"createNewContent" => "Vytvořena nová obsahová stránka. Titulek <strong>:title</strong>, url :url a ID #:id",
"createUser" => "Vytvořen nový uživatel :name s e-mailem :email.",
"deleteContent" => 'Smazána stránka ":title", url "url a ID #:id. Tato změna je zaznamenána v revizi :revision.',
"deleteCustomField" => "a",
"deleteWidgetArea" => "Smazal plochu pro widget :name",
"displayingUsersActions" => "Zobrazuji všechny akce od uživatele :name (:email).",
"draftFromContent" => "Upraven widget :name (#:id)",
"editContent" => 'Editace stránky - nový titulek je ":title", url :url a ID #:id. Revize změny: :revision.',
"editCustomField" => "a",
"editWidget" => "Upraven widget :name (#:id)",
"editWidgetArea" => 'Upravena plocha pro widgety :name (#:id) s popisem ":description"',
"invalidEditContentAttempt" => "Pokus o editaci obsahu s ID :contentId",
"ip" => "IP adresa",
"login" => "Přihlášen",
"logout" => "Odhlášen",
"nameAssignWidget" => "Přiřazení widgetu",
"nameChangeSettings" => "Změna nastavení",
"nameCreateNewContent" => "Vytvoření nové stránky",
"nameCreateUser" => "Vytvořen uživatel",
"nameDeleteContent" => "Smazání stránky",
"nameDeleteCustomField" => "Smazání uživatelského pole",
"nameDeleteWidgetArea" => "Smazání plochy pro widgety",
"nameDraftFromContent" => "Vytvoření konceptu z publikované stránky",
"nameEditContent" => "Úprava obsahu",
"nameEditCustomField" => "Editace uživatelského pole",
"nameEditWidget" => "Úprava widgetu",
"nameEditWidgetArea" => "Úprava plochy pro widgety",
"assignWidget" => "Přiřadil widget :widgetName (#:widgetId) do plochy :widgetAreaName (#:widgetAreaId)",
"changeSettings" => "Změna nastavení",
"createNewContent" => "Vytvořena nová obsahová stránka. Titulek <strong>:title</strong>, url :url a ID #:id",
"createUser" => "Vytvořen nový uživatel :name s e-mailem :email.",
"deleteContent" => 'Smazána stránka ":title", url "url a ID #:id. Tato změna je zaznamenána v revizi :revision.',
"deleteCustomField" => "a",
"deleteWidgetArea" => "Smazal plochu pro widget :name",
"displayingUsersActions" => "Zobrazuji všechny akce od uživatele :name (:email).",
"draftFromContent" => "Upraven widget :name (#:id)",
"editContent" => 'Editace stránky - nový titulek je ":title", url :url a ID #:id. Revize změny: :revision.',
"editCustomField" => "a",
"editWidget" => "Upraven widget :name (#:id)",
"editWidgetArea" => 'Upravena plocha pro widgety :name (#:id) s popisem ":description"',
"invalidEditContentAttempt" => "Pokus o editaci obsahu s ID :contentId",
"ip" => "IP adresa",
"login" => "Přihlášen",
"logout" => "Odhlášen",
"nameAssignWidget" => "Přiřazení widgetu",
"nameChangeSettings" => "Změna nastavení",
"nameCreateNewContent" => "Vytvoření nové stránky",
"nameCreateUser" => "Vytvořen uživatel",
"nameDeleteContent" => "Smazání stránky",
"nameDeleteCustomField" => "Smazání uživatelského pole",
"nameDeleteWidgetArea" => "Smazání plochy pro widgety",
"nameDraftFromContent" => "Vytvoření konceptu z publikované stránky",
"nameEditContent" => "Úprava obsahu",
"nameEditCustomField" => "Editace uživatelského pole",
"nameEditWidget" => "Úprava widgetu",
"nameEditWidgetArea" => "Úprava plochy pro widgety",
"nameInvalidEditContentAttempt" => "Pokus o editaci neexistující/neplatné stránky",
"nameLogin" => "Login",
"nameLogout" => "Odhlášení",
"nameNewCustomField" => "Vytvoření uživatelského pole",
"nameNewWidget" => "Nový widget",
"nameNewWidgetArea" => "Vytoření plochy pro widgety",
"namePublishContent" => "Publikace stránky",
"nameRemoveWidgetFromArea" => "Odebrání widgetu z plochy",
"nameSetHomepage" => "Nastavení domovské stránky",
"nameUserEdit" => "Editace uživatele",
"newCustomField" => 'Přidal nové uživatelské pole s ID #:id a jménem ":name"',
"newWidget" => 'Vytvořen nový widget :type se jménem :name (#:id) a popisem ":description".',
"newWidgetArea" => 'Vytvořil plochu pro widgety :name (#:id) s popisem ":description"',
"overview" => "Seznam všech akcí",
"publishContent" => 'Publikována stránka ":title" (url :url, ID #:id). Revize :revision.',
"removeWidgetFromArea" => "Odebrán widget :widgetName z oblasti :widgetAreaName (#widgetAreaId)",
"setHomepage" => "Nastavena nová domovská stránka: :title, URL: :url a ID #:id. Revize :revision.",
"userAgent" => "Prohlížeč",
"userEdit" => "Upravil uživatele :name (:email)",
"nameLogin" => "Login",
"nameLogout" => "Odhlášení",
"nameNewCustomField" => "Vytvoření uživatelského pole",
"nameNewWidget" => "Nový widget",
"nameNewWidgetArea" => "Vytoření plochy pro widgety",
"namePublishContent" => "Publikace stránky",
"nameRemoveWidgetFromArea" => "Odebrání widgetu z plochy",
"nameSetHomepage" => "Nastavení domovské stránky",
"nameUserEdit" => "Editace uživatele",
"newCustomField" => 'Přidal nové uživatelské pole s ID #:id a jménem ":name"',
"newWidget" => 'Vytvořen nový widget :type se jménem :name (#:id) a popisem ":description".',
"newWidgetArea" => 'Vytvořil plochu pro widgety :name (#:id) s popisem ":description"',
"overview" => "Seznam všech akcí",
"publishContent" => 'Publikována stránka ":title" (url :url, ID #:id). Revize :revision.',
"removeWidgetFromArea" => "Odebrán widget :widgetName z oblasti :widgetAreaName (#widgetAreaId)",
"setHomepage" => "Nastavena nová domovská stránka: :title, URL: :url a ID #:id. Revize :revision.",
"userAgent" => "Prohlížeč",
"userEdit" => "Upravil uživatele :name (:email)",
'newFile' => 'Nahrál soubor :name (typ :mime)',
'nameNewFile' => 'Nahrání souboru'
];