diff --git a/.gitignore b/.gitignore index 07773269..a096cfbc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ composer.phar composer.lock .DS_Store .idea -.phpunit.result.cache \ No newline at end of file +.phpunit.result.cache +.php-cs-fixer.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 00000000..1ded18c2 --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,53 @@ + true, + '@PHP71Migration' => true, + 'array_push' => true, + 'ordered_imports' => [ + 'imports_order' => [ + 'class', 'function', 'const', + ], + 'sort_algorithm' => 'length', + ], + 'no_leading_import_slash' => true, + 'return_assignment' => true, + 'phpdoc_no_empty_return' => true, + 'no_blank_lines_after_phpdoc' => true, + 'general_phpdoc_tag_rename' => true, + 'phpdoc_inline_tag_normalizer' => true, + + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'no_useless_else' => true, + 'lowercase_keywords' => true, + 'modernize_types_casting' => true, + 'no_short_bool_cast' => true, + 'no_php4_constructor' => true, + 'php_unit_construct' => [ + 'assertions' => ['assertSame', 'assertEquals', 'assertNotEquals', 'assertNotSame'], + ], +]; + +$finder = Finder::create() + ->in([ + __DIR__.'/config', + __DIR__.'/database', + __DIR__.'/resources', + __DIR__.'/src', + __DIR__.'/tests', + ]) + ->name('*.php') + ->notName('*.blade.php') + ->ignoreDotFiles(true) + ->ignoreVCS(true); + +$config = new Config(); + +return $config->setFinder($finder) + ->setRules($rules) + ->setRiskyAllowed(true) + ->setUsingCache(true); diff --git a/composer.json b/composer.json index 3edb320f..fb92b3a1 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,10 @@ { "name": "Barry vd. Heuvel", "email": "barryvdh@gmail.com" + }, + { + "name": "Jose Vicente Orts Romero", + "email": "jvortsromero@gmail.com" } ], "require": { diff --git a/config/translation-manager.php b/config/translation-manager.php index 8768907a..221846e3 100644 --- a/config/translation-manager.php +++ b/config/translation-manager.php @@ -1,7 +1,6 @@ [ - 'prefix' => 'translations', + 'route' => [ + 'prefix' => 'translations', 'middleware' => 'auth', ], - /** + /* * Enable deletion of translations * * @type boolean */ 'delete_enabled' => true, - /** + /* * Exclude specific groups from Laravel Translation Manager. * This is useful if, for example, you want to avoid editing the official Laravel language files. * @@ -36,7 +35,7 @@ */ 'exclude_groups' => [], - /** + /* * Exclude specific languages from Laravel Translation Manager. * * @type array @@ -46,12 +45,12 @@ * 'de', * ) */ - 'exclude_langs' => [], + 'exclude_langs' => [], - /** + /* * Export translations with keys output alphabetically. */ - 'sort_keys' => false, + 'sort_keys' => false, 'trans_functions' => [ 'trans', @@ -66,9 +65,41 @@ '$trans.get', ], - /** + 'models' => [ +// \App\Models\Post::class, +// \App\Models\Category::class, + ], + + 'model-field-source' => 'translatable', + + /* * Database connection name to allow for different db connection for the translations table. */ 'db_connection' => env('TRANSLATION_MANAGER_DB_CONNECTION', null), + /* + * Enable pagination of translations + * + * @type boolean + */ + 'pagination_enabled' => false, + + /* + * Define number of translations per page + * + * @type integer + */ + 'per_page' => 40, + + /* ------------------------------------------------------------------------------------------------ + | Set Views options + | --------------------------å---------------------------------------------------------------------- + | Here you can set The "extends" blade of index.blade.php + */ + 'layout' => 'translation-manager::layout', + + /* + * Choose which template to use [bootstrap3, bootstrap4, bootstrap5, tailwind3 ] + */ + 'template' => 'tailwind3', ]; diff --git a/database/migrations/2014_04_02_193005_create_translations_table.php b/database/migrations/2014_04_02_193005_create_translations_table.php index 053d09c2..90adad60 100644 --- a/database/migrations/2014_04_02_193005_create_translations_table.php +++ b/database/migrations/2014_04_02_193005_create_translations_table.php @@ -3,18 +3,15 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; -class CreateTranslationsTable extends Migration { - - /** - * Run the migrations. - * - * @return void - */ - public function up() - { - Schema::create('ltm_translations', function(Blueprint $table) - { - $table->collation = 'utf8mb4_bin'; +class CreateTranslationsTable extends Migration +{ + /** + * Run the migrations. + */ + public function up(): void + { + Schema::create('ltm_translations', static function (Blueprint $table) { + $table->collation = 'utf8mb4_bin'; $table->bigIncrements('id'); $table->integer('status')->default(0); $table->string('locale'); @@ -23,16 +20,13 @@ public function up() $table->text('value')->nullable(); $table->timestamps(); }); - } + } - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { + /** + * Reverse the migrations. + */ + public function down(): void + { Schema::drop('ltm_translations'); - } - + } } diff --git a/resources/views/bootstrap3/index.blade.php b/resources/views/bootstrap3/index.blade.php new file mode 100644 index 00000000..dc17516f --- /dev/null +++ b/resources/views/bootstrap3/index.blade.php @@ -0,0 +1,276 @@ +@extends(config('translation-manager.layout')) +@php($controller = \Barryvdh\TranslationManager\Controller::class) + +@push('documentTitle') + Translation Manager +@endpush + +@push('styles') + + +@endpush + +@push('scripts') + + @include('translation-manager::jsScript') + +@endpush + +@section('content') + +
+

Warning, translations are not visible until they are exported back to the app/lang file, using php artisan translation:export command or publish button.

+ + + + + @if(Session::has('successPublish')) +
+ {{ Session::get('successPublish') }} +
+ @endif +

+ @if(!isset($group)) +

+ +
+
+
+ +
+
+ +
+
+
+
+
+
+ + +
+
+ @else +
+ + + Back +
+ @endif + @if(!$selectedModel) +
+ +
+

Choose a group to display the group translations. If no groups are visible, make sure you have run the migrations and imported the translations.

+ +
+
+ + +
+
+ +
+
+ @endif + @if($group) +
+ +
+ + +
+
+ +
+
+
+

Total: {{ $numTranslations }}, changed: {{ $numChanged }}

+ + + + + @foreach ($locales as $locale) + + @endforeach + @if ($deleteEnabled) + + @endif + + + + + @foreach ($translations as $key => $translation) + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + + @endforeach + @if ($deleteEnabled) + + @endif + + @endforeach + +
Key{{ $locale }} 
{{ htmlentities($key, ENT_QUOTES, 'UTF-8', false) }} + {{ $t ? htmlentities($t->value, ENT_QUOTES, 'UTF-8', false) : '' }} + + + + +
+ @elseif($selectedModel) +
+

Choose a model to display the translations.

+ +
+

Models: {{ $numModelTranslations }}. Total: {{ $numTranslations }}

+ + + + + + @foreach ($locales as $locale) + + @endforeach + + + + + @foreach ($translations as $key => $translationModel) + @foreach($translationModel as $field => $translation) + + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + + @endforeach + + @endforeach + @endforeach + +
KeyField{{ $locale }}
{{ htmlentities($key, ENT_QUOTES, 'UTF-8', false) }}{{ htmlentities($field, ENT_QUOTES, 'UTF-8', false) }} + {{ $t ? htmlentities($t, ENT_QUOTES, 'UTF-8', false) : '' }} +
+ @else +
+

Choose a model to display the translations.

+ +
+
+ Supported locales +

+ Current supported locales: +

+
+ +
    + @foreach($locales as $locale) +
  • +
    + + {{ $locale }} +
    +
  • + @endforeach +
+
+
+ +
+

+ Enter new locale key: +

+
+
+ +
+
+ +
+
+
+
+
+
+ Export all translations +
+ + +
+
+ @endif +
+@stop diff --git a/resources/views/bootstrap4/_notifications.blade.php b/resources/views/bootstrap4/_notifications.blade.php new file mode 100644 index 00000000..0ebf010b --- /dev/null +++ b/resources/views/bootstrap4/_notifications.blade.php @@ -0,0 +1,21 @@ +@push('notifications') + + + + + + @if(Session::has('successPublish')) +
+ {!! Session::get('successPublish') !!} +
+ @endif +@endpush diff --git a/resources/views/bootstrap4/blocks/_addEditGroupKeys.blade.php b/resources/views/bootstrap4/blocks/_addEditGroupKeys.blade.php new file mode 100644 index 00000000..be0c8eac --- /dev/null +++ b/resources/views/bootstrap4/blocks/_addEditGroupKeys.blade.php @@ -0,0 +1,23 @@ +
+
+
+ @csrf() +
+

Choose a group to display the group translations. If no groups are visible, make sure you have run + the migrations and imported the translations.

+ +
+
+ + +
+
+ +
+
+
+
diff --git a/resources/views/bootstrap4/blocks/_edit.blade.php b/resources/views/bootstrap4/blocks/_edit.blade.php new file mode 100644 index 00000000..0d0274f9 --- /dev/null +++ b/resources/views/bootstrap4/blocks/_edit.blade.php @@ -0,0 +1,57 @@ +
+
+
+ @csrf() +
+ + +
+
+ +
+
+
+

Total: {{ $numTranslations }}, changed: {{ $numChanged }}

+ + + + + @foreach ($locales as $locale) + + @endforeach + @if ($deleteEnabled) + + @endif + + + + + @foreach ($translations as $key => $translation) + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + @if ($deleteEnabled) + + @endif + + @endforeach + +
Key{{ $locale }} 
{{ $key }} + {{ $t ? htmlentities($t->value, ENT_QUOTES, 'UTF-8', false) : '' }} + + + + +
+
+
diff --git a/resources/views/bootstrap4/blocks/_editModel.blade.php b/resources/views/bootstrap4/blocks/_editModel.blade.php new file mode 100644 index 00000000..370045f7 --- /dev/null +++ b/resources/views/bootstrap4/blocks/_editModel.blade.php @@ -0,0 +1,37 @@ +
+
+

Models: {{ $numModelTranslations }}. Total: {{ $numTranslations }}

+ + + + + + @foreach ($locales as $locale) + + @endforeach + + + + @foreach ($translations as $key => $translationModel) + @foreach($translationModel as $field => $translation) + + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + + @endforeach + @endforeach + +
KeyField{{ $locale }}
{{ $key }}{{ $field }} + {{ $t ? htmlentities($t, ENT_QUOTES, 'UTF-8', false) : '' }} +
+
+
diff --git a/resources/views/bootstrap4/blocks/_mainBlock.blade.php b/resources/views/bootstrap4/blocks/_mainBlock.blade.php new file mode 100644 index 00000000..3656333c --- /dev/null +++ b/resources/views/bootstrap4/blocks/_mainBlock.blade.php @@ -0,0 +1,42 @@ +
+
+

Warning, translations are not visible until they are exported back to the app/lang file, using php artisan translation:export command or publish button.

+ + @if(!isset($group)) +
+ @csrf() +
+
+ +
+
+ +
+
+
+
+ @csrf() + +
+ + @if($selectedModel) + Back + @endif +
+
+ @else +
+ @csrf() +
+ + Back +
+
+ @endif +
+
diff --git a/resources/views/bootstrap4/blocks/_publishAll.blade.php b/resources/views/bootstrap4/blocks/_publishAll.blade.php new file mode 100644 index 00000000..6c72cc1d --- /dev/null +++ b/resources/views/bootstrap4/blocks/_publishAll.blade.php @@ -0,0 +1,13 @@ +
+
+
+ Export all translations +
+ @csrf() + +
+
+
+
diff --git a/resources/views/bootstrap4/blocks/_selectEditModel.blade.php b/resources/views/bootstrap4/blocks/_selectEditModel.blade.php new file mode 100644 index 00000000..dd8d0c7a --- /dev/null +++ b/resources/views/bootstrap4/blocks/_selectEditModel.blade.php @@ -0,0 +1,14 @@ +@if(!empty($models)) +
+
+
+

Choose a model to display the translations.

+ +
+
+
+@endif diff --git a/resources/views/bootstrap4/blocks/_supportedLocales.blade.php b/resources/views/bootstrap4/blocks/_supportedLocales.blade.php new file mode 100644 index 00000000..f1c239f9 --- /dev/null +++ b/resources/views/bootstrap4/blocks/_supportedLocales.blade.php @@ -0,0 +1,41 @@ +
+
+
+ Supported locales +

+ Current supported locales: +

+
+ @csrf() +
    + @foreach($locales as $locale) +
  • + {{ $locale }} + +
  • + @endforeach +
+
+
+ @csrf() +
+

+ Enter new locale key: +

+
+
+ +
+
+ +
+
+
+
+
+
+
diff --git a/resources/views/bootstrap4/index.blade.php b/resources/views/bootstrap4/index.blade.php new file mode 100644 index 00000000..1b83a82a --- /dev/null +++ b/resources/views/bootstrap4/index.blade.php @@ -0,0 +1,36 @@ +@extends(config('translation-manager.layout')) +@php($controller = \Barryvdh\TranslationManager\Controller::class) + +@section('documentTitle') + Translation Manager +@stop +@include('translation-manager::bootstrap4._notifications') +@section('content') + + @include('translation-manager::bootstrap4.blocks._mainBlock') + @if(!$selectedModel) + @include('translation-manager::bootstrap4.blocks._addEditGroupKeys') + @else + @include('translation-manager::bootstrap4.blocks._selectEditModel') + @endif + @if($group) + @include('translation-manager::bootstrap4.blocks._edit') + @elseif($selectedModel) + @include('translation-manager::bootstrap4.blocks._editModel') + @else + @include('translation-manager::bootstrap4.blocks._selectEditModel') + @include('translation-manager::bootstrap4.blocks._supportedLocales') + @include('translation-manager::bootstrap4.blocks._publishAll') + @endif +@stop + +@push('styles') + {{----}} + +@endpush + +@push('scripts') + {{----}} + + @include('translation-manager::jsScript') +@endpush diff --git a/resources/views/bootstrap5/_notifications.blade.php b/resources/views/bootstrap5/_notifications.blade.php new file mode 100644 index 00000000..32772f33 --- /dev/null +++ b/resources/views/bootstrap5/_notifications.blade.php @@ -0,0 +1,48 @@ +@push('notifications') + + + + + + @if(Session::has('successPublish')) + + @endif +@endpush diff --git a/resources/views/bootstrap5/blocks/_addEditGroupKeys.blade.php b/resources/views/bootstrap5/blocks/_addEditGroupKeys.blade.php new file mode 100644 index 00000000..085aa914 --- /dev/null +++ b/resources/views/bootstrap5/blocks/_addEditGroupKeys.blade.php @@ -0,0 +1,20 @@ +
+
+
+ @csrf() +
+

Choose a group to display the group translations. If no groups are visible, make sure you have run the migrations and imported the translations.

+ +
+
+ + +
+ +
+
+
diff --git a/resources/views/bootstrap5/blocks/_edit.blade.php b/resources/views/bootstrap5/blocks/_edit.blade.php new file mode 100644 index 00000000..33ac0166 --- /dev/null +++ b/resources/views/bootstrap5/blocks/_edit.blade.php @@ -0,0 +1,56 @@ +
+
+
+ @csrf() +
Add new keys to this group:
+
+ + +
+ +
+
+

Total: {{ $numTranslations }}, changed: {{ $numChanged }}

+ + + + + @foreach ($locales as $locale) + + @endforeach + @if ($deleteEnabled) + + @endif + + + + + @foreach ($translations as $key => $translation) + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + @if ($deleteEnabled) + + @endif + + @endforeach + +
Key{{ $locale }} 
{{ $key }} + {{ $t ? htmlentities($t->value, ENT_QUOTES, 'UTF-8', false) : '' }} + + + + +
+
+
diff --git a/resources/views/bootstrap5/blocks/_editModel.blade.php b/resources/views/bootstrap5/blocks/_editModel.blade.php new file mode 100644 index 00000000..00302673 --- /dev/null +++ b/resources/views/bootstrap5/blocks/_editModel.blade.php @@ -0,0 +1,37 @@ +
+
+

Models: {{ $numModelTranslations }}. Total: {{ $numTranslations }}

+ + + + + + @foreach ($locales as $locale) + + @endforeach + + + + @foreach ($translations as $key => $translationModel) + @foreach($translationModel as $field => $translation) + + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + + @endforeach + @endforeach + +
KeyField{{ $locale }}
{{ $key }}{{ $field }} + {{ $t ? htmlentities($t, ENT_QUOTES, 'UTF-8', false) : '' }} +
+
+
diff --git a/resources/views/bootstrap5/blocks/_mainBlock.blade.php b/resources/views/bootstrap5/blocks/_mainBlock.blade.php new file mode 100644 index 00000000..38fed0fe --- /dev/null +++ b/resources/views/bootstrap5/blocks/_mainBlock.blade.php @@ -0,0 +1,45 @@ +
+
+

Warning, translations are not visible until they are exported back to the app/lang file, using php artisan translation:export command or publish button.

+ + @if(!isset($group)) +
+ @csrf() +
+
+ +
+
+ +
+
+
+
+ @csrf() +
+ + @if($selectedModel) + Back + @endif +
+
+ @else +
+ @csrf() +
+ + Back +
+
+ @endif +
+
diff --git a/resources/views/bootstrap5/blocks/_publishAll.blade.php b/resources/views/bootstrap5/blocks/_publishAll.blade.php new file mode 100644 index 00000000..6c72cc1d --- /dev/null +++ b/resources/views/bootstrap5/blocks/_publishAll.blade.php @@ -0,0 +1,13 @@ +
+
+
+ Export all translations +
+ @csrf() + +
+
+
+
diff --git a/resources/views/bootstrap5/blocks/_selectEditModel.blade.php b/resources/views/bootstrap5/blocks/_selectEditModel.blade.php new file mode 100644 index 00000000..466a6c63 --- /dev/null +++ b/resources/views/bootstrap5/blocks/_selectEditModel.blade.php @@ -0,0 +1,14 @@ +@if(!empty($models)) +
+
+
+

Choose a model to display the translations.

+ +
+
+
+@endif diff --git a/resources/views/bootstrap5/blocks/_supportedLocales.blade.php b/resources/views/bootstrap5/blocks/_supportedLocales.blade.php new file mode 100644 index 00000000..ef06ec7f --- /dev/null +++ b/resources/views/bootstrap5/blocks/_supportedLocales.blade.php @@ -0,0 +1,42 @@ +
+
+
+ Supported locales +

+ Current supported locales: +

+
+ @csrf() +
    + @foreach($locales as $locale) +
  • + {{ $locale }} + +
  • + @endforeach +
+
+
+ @csrf() +
+

+ Enter new locale key: +

+
+
+ +
+
+ +
+
+
+
+
+
+
diff --git a/resources/views/bootstrap5/index.blade.php b/resources/views/bootstrap5/index.blade.php new file mode 100644 index 00000000..0a80953d --- /dev/null +++ b/resources/views/bootstrap5/index.blade.php @@ -0,0 +1,37 @@ +@extends(config('translation-manager.layout')) +@php($controller = \Barryvdh\TranslationManager\Controller::class) + +@section('documentTitle') + Translation Manager +@stop + +@include('translation-manager::bootstrap5._notifications') + +@section('content') + @include('translation-manager::bootstrap5.blocks._mainBlock') + @if(!$selectedModel) + @include('translation-manager::bootstrap5.blocks._addEditGroupKeys') + @else + @include('translation-manager::bootstrap5.blocks._selectEditModel') + @endif + @if($group) + @include('translation-manager::bootstrap5.blocks._edit') + @elseif($selectedModel) + @include('translation-manager::bootstrap5.blocks._editModel') + @else + @include('translation-manager::bootstrap5.blocks._selectEditModel') + @include('translation-manager::bootstrap5.blocks._supportedLocales') + @include('translation-manager::bootstrap5.blocks._publishAll') + @endif +@stop + +@push('styles') + {{----}} + +@endpush + +@push('scripts') + {{----}} + + @include('translation-manager::jsScript') +@endpush diff --git a/resources/views/index.php b/resources/views/index.php deleted file mode 100644 index d2c69103..00000000 --- a/resources/views/index.php +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - Translation Manager - - - - - - - - - - - - -
-

Warning, translations are not visible until they are exported back to the app/lang file, using php artisan translation:export command or publish button.

- - - - - -
- -
- -

- -

- -
-
-
- -
-
- -
-
-
-
-
-
- - -
-
- - -
- - - Back -
- -

-
- -
-

Choose a group to display the group translations. If no groups are visisble, make sure you have run the migrations and imported the translations.

- -
-
- - -
-
- -
-
- -
- -
- - -
-
- -
-
-
-
- Use Auto Translate -
-
- -
-

Total: , changed:

- - - - - - - - - - - - - - - $translation): ?> - - - - - - - - - - - - - -
Key 
- " - id="username" data-type="textarea" data-pk="id : 0 ?>" - data-url="" - data-title="Enter translation">value, ENT_QUOTES, 'UTF-8', false) : '' ?> - - -
- -
- Supported locales -

- Current supported locales: -

-
- -
    - -
  • -
    - - - -
    -
  • - -
-
-
- -
-

- Enter new locale key: -

-
-
- -
-
- -
-
-
-
-
-
- Export all translations -
- - -
-
- - -
- - - diff --git a/resources/views/jsScript.blade.php b/resources/views/jsScript.blade.php new file mode 100644 index 00000000..ae7084c3 --- /dev/null +++ b/resources/views/jsScript.blade.php @@ -0,0 +1,382 @@ + + + diff --git a/resources/views/layout.blade.php b/resources/views/layout.blade.php new file mode 100644 index 00000000..94b2ebbc --- /dev/null +++ b/resources/views/layout.blade.php @@ -0,0 +1,121 @@ + + + + + + + + @yield('documentTitle') + + @switch(config('translation-manager.template')) + @case('bootstrap3') + + @break + @case('bootstrap4') + + + @break + @case('bootstrap5') + + + @break + @case('tailwind3') + + + + @break + @default + @endswitch + @stack('styles') + + +
+

@yield('documentTitle')

+ @stack('notifications') +
+ @yield('content') + + @if ($paginationEnabled) {!! $translations->links()->toHtml() !!} @endif +
+
+ + @switch(config('translation-manager.template')) + @case('bootstrap3') + + + + @break + @case('bootstrap4') + + + @break + @case('bootstrap5') + + + @break + @case('tailwind3') + + @break + @default + @endswitch + @stack('scripts') + + + + + diff --git a/resources/views/tailwind3/_notifications.blade.php b/resources/views/tailwind3/_notifications.blade.php new file mode 100644 index 00000000..87e86a6e --- /dev/null +++ b/resources/views/tailwind3/_notifications.blade.php @@ -0,0 +1,48 @@ +@push('notifications') + + + + + + @if(Session::has('successPublish')) + + @endif +@endpush diff --git a/resources/views/tailwind3/blocks/_addEditGroupKeys.blade.php b/resources/views/tailwind3/blocks/_addEditGroupKeys.blade.php new file mode 100644 index 00000000..1f5aabe3 --- /dev/null +++ b/resources/views/tailwind3/blocks/_addEditGroupKeys.blade.php @@ -0,0 +1,20 @@ +
+
+
+ @csrf() +
+ + +
+
+ + +
+ +
+
+
diff --git a/resources/views/tailwind3/blocks/_edit.blade.php b/resources/views/tailwind3/blocks/_edit.blade.php new file mode 100644 index 00000000..2dfa864e --- /dev/null +++ b/resources/views/tailwind3/blocks/_edit.blade.php @@ -0,0 +1,57 @@ +
+
+
+ @csrf() +
Add new keys to this group:
+
+ + +
+ +
+
+

Total: {{ $numTranslations }}, changed: {{ $numChanged }}

+ + + + + @foreach ($locales as $locale) + + @endforeach + @if ($deleteEnabled) + + @endif + + + + @foreach ($translations as $key => $translation) + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + @if ($deleteEnabled) + + @endif + + @endforeach + +
Key{{ $locale }} 
{{ $key }} + {{ $t ? htmlentities($t->value, ENT_QUOTES, 'UTF-8', false) : '' }} + + + + + + +
+
+
diff --git a/resources/views/tailwind3/blocks/_editModel.blade.php b/resources/views/tailwind3/blocks/_editModel.blade.php new file mode 100644 index 00000000..1ee2de9b --- /dev/null +++ b/resources/views/tailwind3/blocks/_editModel.blade.php @@ -0,0 +1,37 @@ +
+
+

Models: {{ $numModelTranslations }}. Total: {{ $numTranslations }}

+ + + + + + @foreach ($locales as $locale) + + @endforeach + + + + @foreach ($translations as $key => $translationModel) + @foreach($translationModel as $field => $translation) + + + + @foreach ($locales as $locale) + @php($t = isset($translation[$locale]) ? $translation[$locale] : null) + + @endforeach + + @endforeach + @endforeach + +
KeyField{{ $locale }}
{{ $key }}{{ $field }} + {{ $t ? htmlentities($t, ENT_QUOTES, 'UTF-8', false) : '' }} +
+
+
diff --git a/resources/views/tailwind3/blocks/_mainBlock.blade.php b/resources/views/tailwind3/blocks/_mainBlock.blade.php new file mode 100644 index 00000000..0b3e1e75 --- /dev/null +++ b/resources/views/tailwind3/blocks/_mainBlock.blade.php @@ -0,0 +1,46 @@ +
+
+

Warning, translations are not visible until they are exported back to the app/lang file, using php artisan translation:export command or publish button.

+ + @if(!isset($group)) +
+ @csrf() +
+
+ +
+
+ +
+
+
+
+ @csrf() + +
+ + @if($selectedModel) + Back + @endif +
+
+ @else +
+ @csrf() +
+ + Back +
+
+ @endif +
+
diff --git a/resources/views/tailwind3/blocks/_publishAll.blade.php b/resources/views/tailwind3/blocks/_publishAll.blade.php new file mode 100644 index 00000000..1c79f1c7 --- /dev/null +++ b/resources/views/tailwind3/blocks/_publishAll.blade.php @@ -0,0 +1,13 @@ +
+
+
+ Export all translations +
+ @csrf() + +
+
+
+
diff --git a/resources/views/tailwind3/blocks/_selectEditModel.blade.php b/resources/views/tailwind3/blocks/_selectEditModel.blade.php new file mode 100644 index 00000000..cf8b1f68 --- /dev/null +++ b/resources/views/tailwind3/blocks/_selectEditModel.blade.php @@ -0,0 +1,14 @@ +@if(!empty($models)) +
+
+
+ + +
+
+
+@endif diff --git a/resources/views/tailwind3/blocks/_supportedLocales.blade.php b/resources/views/tailwind3/blocks/_supportedLocales.blade.php new file mode 100644 index 00000000..2dcdd2fc --- /dev/null +++ b/resources/views/tailwind3/blocks/_supportedLocales.blade.php @@ -0,0 +1,39 @@ +
+
+
+ Supported locales + + +
+ @csrf() +
    + @foreach($locales as $locale) +
  • + {{ $locale }} + +
  • + @endforeach +
+
+
+ @csrf() +
+ +
+
+ +
+
+ +
+
+
+
+
+
+
diff --git a/resources/views/tailwind3/index.blade.php b/resources/views/tailwind3/index.blade.php new file mode 100644 index 00000000..c295b6d1 --- /dev/null +++ b/resources/views/tailwind3/index.blade.php @@ -0,0 +1,39 @@ +@extends(config('translation-manager.layout')) +@php($controller = \Barryvdh\TranslationManager\Controller::class) + +@section('documentTitle') + Translation Manager +@stop + +@include('translation-manager::tailwind3._notifications') + +@section('content') + @include('translation-manager::tailwind3.blocks._mainBlock') + @if(!$selectedModel) + @include('translation-manager::tailwind3.blocks._addEditGroupKeys') + @else + @include('translation-manager::tailwind3.blocks._selectEditModel') + @endif + @if($group) + @include('translation-manager::tailwind3.blocks._edit') + @elseif($selectedModel) + @include('translation-manager::tailwind3.blocks._editModel') + @else + @include('translation-manager::tailwind3.blocks._selectEditModel') + @include('translation-manager::tailwind3.blocks._supportedLocales') + @include('translation-manager::tailwind3.blocks._publishAll') + @endif +@stop + +@push('styles') + {{----}} + +@endpush + +@push('scripts') + {{----}} + + + + @include('translation-manager::jsScript') +@endpush diff --git a/src/Console/CleanCommand.php b/src/Console/CleanCommand.php index c23c5c56..4ce02fa6 100644 --- a/src/Console/CleanCommand.php +++ b/src/Console/CleanCommand.php @@ -2,8 +2,8 @@ namespace Barryvdh\TranslationManager\Console; -use Barryvdh\TranslationManager\Manager; use Illuminate\Console\Command; +use Barryvdh\TranslationManager\Manager; class CleanCommand extends Command { @@ -21,7 +21,9 @@ class CleanCommand extends Command */ protected $description = 'Clean empty translations'; - /** @var \Barryvdh\TranslationManager\Manager */ + /** + * @var \Barryvdh\TranslationManager\Manager + */ protected $manager; public function __construct(Manager $manager) @@ -33,7 +35,7 @@ public function __construct(Manager $manager) /** * Execute the console command. */ - public function handle() + public function handle(): void { $this->manager->cleanTranslations(); $this->info('Done cleaning translations'); diff --git a/src/Console/ExportCommand.php b/src/Console/ExportCommand.php index ee0e63db..af7a935b 100644 --- a/src/Console/ExportCommand.php +++ b/src/Console/ExportCommand.php @@ -2,10 +2,10 @@ namespace Barryvdh\TranslationManager\Console; -use Barryvdh\TranslationManager\Manager; use Illuminate\Console\Command; -use Symfony\Component\Console\Input\InputArgument; +use Barryvdh\TranslationManager\Manager; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Input\InputArgument; class ExportCommand extends Command { @@ -23,7 +23,9 @@ class ExportCommand extends Command */ protected $description = 'Export translations to PHP files'; - /** @var \Barryvdh\TranslationManager\Manager */ + /** + * @var \Barryvdh\TranslationManager\Manager + */ protected $manager; public function __construct(Manager $manager) @@ -35,7 +37,7 @@ public function __construct(Manager $manager) /** * Execute the console command. */ - public function handle() + public function handle(): void { $group = $this->option('all') ? '*' : $this->argument('group'); $json = $this->option('json'); @@ -52,15 +54,14 @@ public function handle() return; } - if ( $group == '*' ) { + if ('*' === $group) { $this->manager->exportAllTranslations(); - } - else { + } else { $this->manager->exportTranslations($group, $json); } if (!is_null($group)) { - $this->info('Done writing language files for '.(($group == '*') ? 'ALL groups' : $group.' group')); + $this->info('Done writing language files for '.(('*' === $group) ? 'ALL groups' : $group.' group')); } elseif ($json) { $this->info('Done writing JSON language files for translation strings'); } @@ -68,10 +69,8 @@ public function handle() /** * Get the console command arguments. - * - * @return array */ - protected function getArguments() + protected function getArguments(): array { return [ ['group', InputArgument::OPTIONAL, 'The group to export (--all for all).'], @@ -80,10 +79,8 @@ protected function getArguments() /** * Get the console command options. - * - * @return array */ - protected function getOptions() + protected function getOptions(): array { return [ ['json', 'J', InputOption::VALUE_NONE, 'Export anonymous strings to JSON'], diff --git a/src/Console/FindCommand.php b/src/Console/FindCommand.php index 1c49d421..2958dd67 100644 --- a/src/Console/FindCommand.php +++ b/src/Console/FindCommand.php @@ -2,8 +2,8 @@ namespace Barryvdh\TranslationManager\Console; -use Barryvdh\TranslationManager\Manager; use Illuminate\Console\Command; +use Barryvdh\TranslationManager\Manager; class FindCommand extends Command { @@ -21,7 +21,9 @@ class FindCommand extends Command */ protected $description = 'Find translations in php/twig files'; - /** @var \Barryvdh\TranslationManager\Manager */ + /** + * @var \Barryvdh\TranslationManager\Manager + */ protected $manager; public function __construct(Manager $manager) @@ -33,7 +35,7 @@ public function __construct(Manager $manager) /** * Execute the console command. */ - public function handle() + public function handle(): void { $counter = $this->manager->findTranslations(null); $this->info('Done importing, processed '.$counter.' items!'); diff --git a/src/Console/ImportCommand.php b/src/Console/ImportCommand.php index d2e4fc05..88ef731b 100644 --- a/src/Console/ImportCommand.php +++ b/src/Console/ImportCommand.php @@ -2,8 +2,8 @@ namespace Barryvdh\TranslationManager\Console; -use Barryvdh\TranslationManager\Manager; use Illuminate\Console\Command; +use Barryvdh\TranslationManager\Manager; use Symfony\Component\Console\Input\InputOption; class ImportCommand extends Command @@ -22,7 +22,9 @@ class ImportCommand extends Command */ protected $description = 'Import translations from the PHP sources'; - /** @var \Barryvdh\TranslationManager\Manager */ + /** + * @var \Barryvdh\TranslationManager\Manager + */ protected $manager; public function __construct(Manager $manager) @@ -34,7 +36,7 @@ public function __construct(Manager $manager) /** * Execute the console command. */ - public function handle() + public function handle(): void { $replace = $this->option('replace'); $counter = $this->manager->importTranslations($replace); @@ -43,10 +45,8 @@ public function handle() /** * Get the console command options. - * - * @return array */ - protected function getOptions() + protected function getOptions(): array { return [ ['replace', 'R', InputOption::VALUE_NONE, 'Replace existing keys'], diff --git a/src/Console/ResetCommand.php b/src/Console/ResetCommand.php index fbc76e3c..37777eb7 100644 --- a/src/Console/ResetCommand.php +++ b/src/Console/ResetCommand.php @@ -21,7 +21,9 @@ class ResetCommand extends Command */ protected $description = 'Delete all translations from the database'; - /** @var \Barryvdh\TranslationManager\Manager */ + /** + * @var \Barryvdh\TranslationManager\Manager + */ protected $manager; public function __construct(Manager $manager) @@ -33,7 +35,7 @@ public function __construct(Manager $manager) /** * Execute the console command. */ - public function handle() + public function handle(): void { $this->manager->truncateTranslations(); $this->info('All translations are deleted'); diff --git a/src/Controller.php b/src/Controller.php index 31ab43c0..f6d65f16 100644 --- a/src/Controller.php +++ b/src/Controller.php @@ -1,14 +1,18 @@ -manager = $manager; } + /** + * @param string $group + * + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + * + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ + public function getView($group = null) + { + return $this->getIndex($group); + } + + /** + * @param string $group + * + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + * + * @throws \Psr\Container\ContainerExceptionInterface + * @throws \Psr\Container\NotFoundExceptionInterface + */ public function getIndex($group = null) { $locales = $this->manager->getLocales(); $groups = Translation::groupBy('group'); $excludedGroups = $this->manager->getConfig('exclude_groups'); - if($excludedGroups){ + if ($excludedGroups) { $groups->whereNotIn('group', $excludedGroups); } @@ -29,36 +54,131 @@ public function getIndex($group = null) if ($groups instanceof Collection) { $groups = $groups->all(); } - $groups = [''=>'Choose a group'] + $groups; - $numChanged = Translation::where('group', $group)->where('status', Translation::STATUS_CHANGED)->count(); + $groups = ['' => 'Choose a group'] + $groups; + $models = []; + foreach (config('translation-manager.models') as $modelClass) { + $modelTable = (new $modelClass())->getTable(); + $models[$modelTable] = $modelClass; + } + $models = ['' => 'Choose a model'] + $models; + $numChanged = Translation::where('group', $group)->where('status', Translation::STATUS_CHANGED)->count(); $allTranslations = Translation::where('group', $group)->orderBy('key', 'asc')->get(); $numTranslations = count($allTranslations); $translations = []; - foreach($allTranslations as $translation){ + foreach ($allTranslations as $translation) { $translations[$translation->key][$translation->locale] = $translation; } - return view('translation-manager::index') + if ($this->manager->getConfig('pagination_enabled')) { + $total = count($translations); + $page = request()->get('page', 1); + $perPage = $this->manager->getConfig('per_page'); + $offSet = ($page * $perPage) - $perPage; + $itemsForCurrentPage = array_slice($translations, $offSet, $perPage, true); + $prefix = $this->manager->getConfig('route')['prefix']; + $path = url("$prefix/view/$group"); + + if ('bootstrap3' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrapThree(); + } elseif ('bootstrap4' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrap(); + } elseif ('bootstrap5' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrap(); + } + + $paginator = new LengthAwarePaginator($itemsForCurrentPage, $total, $perPage, $page); + $translations = $paginator->withPath($path); + } + + return view('translation-manager::'.$this->manager->getConfig('template').'.index') ->with('translations', $translations) ->with('locales', $locales) ->with('groups', $groups) + ->with('models', $models) ->with('group', $group) + ->with('selectedModel', null) ->with('numTranslations', $numTranslations) ->with('numChanged', $numChanged) ->with('editUrl', $group ? action('\Barryvdh\TranslationManager\Controller@postEdit', [$group]) : null) + ->with('paginationEnabled', $this->manager->getConfig('pagination_enabled')) ->with('deleteEnabled', $this->manager->getConfig('delete_enabled')); } - public function getView($group = null) + /** + * @param string $selectedModel + * + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View + */ + public function getModelView($selectedModel = null) { - return $this->getIndex($group); + if (empty($selectedModel)) { + return $this->getIndex(); + } + + $locales = $this->manager->getLocales(); + $models = []; + foreach (config('translation-manager.models') as $modelClass) { + $modelTable = (new $modelClass())->getTable(); + $models[$modelTable] = $modelClass; + } + $models = empty($models) ? [] : ['' => 'Choose a model'] + $models; + + $allTranslationModels = (new $models[$selectedModel]())->newQuery()->get(); + $translations = []; + $numModelTranslations = count($allTranslationModels); + $numTranslations = 0; + $translatableSource = config('translation-manager.model-field-source'); + foreach ($allTranslationModels as $translationModel) { + /* @var \Illuminate\Database\Eloquent\Model $translationModel */ + foreach ((new $models[$selectedModel]())->$translatableSource as $field) { + foreach ($locales as $locale) { + $translationValues = json_decode($translationModel->getAttributes()[$field] ?? '' ?: '{}', true) ?: []; + + $translations[$translationModel->getKey()][$field][$locale] = empty($translationValues[$locale]) ? '' : $translationValues[$locale]; + } + ++$numTranslations; + } + } + + if ($this->manager->getConfig('pagination_enabled')) { + $total = count($translations); + $page = request()->get('page', 1); + $perPage = $this->manager->getConfig('per_page'); + $offSet = ($page * $perPage) - $perPage; + $itemsForCurrentPage = array_slice($translations, $offSet, $perPage, true); + $prefix = $this->manager->getConfig('route')['prefix']; + $path = url("$prefix/model/$selectedModel"); + + if ('bootstrap3' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrapThree(); + } elseif ('bootstrap4' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrap(); + } elseif ('bootstrap5' === $this->manager->getConfig('template')) { + LengthAwarePaginator::useBootstrap(); + } + + $paginator = new LengthAwarePaginator($itemsForCurrentPage, $total, $perPage, $page); + $translations = $paginator->withPath($path); + } + + return view('translation-manager::'.$this->manager->getConfig('template').'.index') + ->with('translations', $translations) + ->with('locales', $locales) + ->with('models', $models) + ->with('group', null) + ->with('selectedModel', $selectedModel) + ->with('numModelTranslations', $numModelTranslations) + ->with('numTranslations', $numTranslations) + ->with('editUrl', action('\Barryvdh\TranslationManager\Controller@postEditModel', [$selectedModel])) + ->with('paginationEnabled', $this->manager->getConfig('pagination_enabled')) + ->with('deleteEnabled', $this->manager->getConfig('delete_enabled')); } - protected function loadLocales() + protected function loadLocales(): array { - //Set the default locale as the first one. + // Set the default locale as the first one. $locales = Translation::groupBy('locale') ->select('locale') ->get() @@ -68,29 +188,31 @@ protected function loadLocales() $locales = $locales->all(); } $locales = array_merge([config('app.locale')], $locales); + return array_unique($locales); } - public function postAdd($group = null) + public function postAdd($group = null): RedirectResponse { $keys = explode("\n", request()->get('keys')); - foreach($keys as $key){ + foreach ($keys as $key) { $key = trim($key); - if($group && $key){ + if ($group && $key) { $this->manager->missingKey('*', $group, $key); } } + return redirect()->back(); } public function postEdit($group = null) { - if(!in_array($group, $this->manager->getConfig('exclude_groups'))) { + if (!in_array($group, $this->manager->getConfig('exclude_groups'), true)) { $name = request()->get('name'); $value = request()->get('value'); - list($locale, $key) = explode('|', $name, 2); + [$locale, $key] = explode('|', $name, 2); $translation = Translation::firstOrNew([ 'locale' => $locale, 'group' => $group, @@ -99,19 +221,49 @@ public function postEdit($group = null) $translation->value = (string) $value ?: null; $translation->status = Translation::STATUS_CHANGED; $translation->save(); - return array('status' => 'ok'); + + return ['status' => 'ok']; + } + } + + public function postEditModel($selectedModel) + { + $models = []; + foreach (config('translation-manager.models') as $modelClass) { + $modelTable = (new $modelClass())->getTable(); + $models[$modelTable] = $modelClass; + } + + if (array_key_exists($selectedModel, $models)) { + $name = request()->get('name'); + $value = request()->get('value'); + + [$locale, $field, $key] = explode('|', $name, 3); + + /* @var \Illuminate\Database\Eloquent\Model $model */ + $model = (new $models[$selectedModel]())->findOrFail($key); + $translationValues = json_decode($model->getAttributes()[$field] ?? '' ?: '{}', true) ?: []; + $translationValues[$locale] = $value ? (string) $value : null; + + $model->setRawAttributes([ + $field => json_encode($translationValues), + ]); + $model->save(); + + return ['status' => 'ok']; } } public function postDelete($group, $key) { - if(!in_array($group, $this->manager->getConfig('exclude_groups')) && $this->manager->getConfig('delete_enabled')) { + if ($this->manager->getConfig('delete_enabled') && !in_array($group, $this->manager->getConfig('exclude_groups'), true)) { Translation::where('group', $group)->where('key', $key)->delete(); + return ['status' => 'ok']; } } - public function postImport(Request $request) + public function postImport(Request $request): array { $replace = $request->get('replace', false); $counter = $this->manager->importTranslations($replace); @@ -119,18 +271,18 @@ public function postImport(Request $request) return ['status' => 'ok', 'counter' => $counter]; } - public function postFind() + public function postFind(): array { $numFound = $this->manager->findTranslations(); return ['status' => 'ok', 'counter' => (int) $numFound]; } - public function postPublish($group = null) + public function postPublish($group = null): array { - $json = false; + $json = false; - if($group === '_json'){ + if ('_json' === $group) { $json = true; } @@ -139,42 +291,48 @@ public function postPublish($group = null) return ['status' => 'ok']; } - public function postAddGroup(Request $request) + public function postAddGroup(Request $request): RedirectResponse { - $group = str_replace(".", '', $request->input('new-group')); - if ($group) - { - return redirect()->action('\Barryvdh\TranslationManager\Controller@getView',$group); - } - else - { - return redirect()->back(); + $group = str_replace('.', '', $request->input('new-group')); + if ($group) { + return redirect()->action('\Barryvdh\TranslationManager\Controller@getView', $group); } + + return redirect()->back(); } - public function postAddLocale(Request $request) + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function postAddLocale(Request $request): RedirectResponse { $locales = $this->manager->getLocales(); $newLocale = str_replace([], '-', trim($request->input('new-locale'))); - if (!$newLocale || in_array($newLocale, $locales)) { + if (!$newLocale || in_array($newLocale, $locales, true)) { return redirect()->back(); } $this->manager->addLocale($newLocale); + return redirect()->back(); } - public function postRemoveLocale(Request $request) + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function postRemoveLocale(Request $request): RedirectResponse { foreach ($request->input('remove-locale', []) as $locale => $val) { $this->manager->removeLocale($locale); } + return redirect()->back(); } - public function postTranslateMissing(Request $request){ + public function postTranslateMissing(Request $request): RedirectResponse + { $locales = $this->manager->getLocales(); $newLocale = str_replace([], '-', trim($request->input('new-locale'))); - if($request->has('with-translations') && $request->has('base-locale') && in_array($request->input('base-locale'),$locales) && $request->has('file') && in_array($newLocale, $locales)){ + if ($request->has('with-translations') && $request->has('base-locale') && in_array($request->input('base-locale'), $locales) && $request->has('file') && in_array($newLocale, $locales)) { $base_locale = $request->get('base-locale'); $group = $request->get('file'); $base_strings = Translation::where('group', $group)->where('locale', $base_locale)->get(); @@ -187,17 +345,19 @@ public function postTranslateMissing(Request $request){ $translated_text = Str::apiTranslateWithAttributes($base_string->value, $newLocale, $base_locale); request()->replace([ 'value' => $translated_text, - 'name' => $newLocale . '|' . $base_string->key, + 'name' => $newLocale.'|'.$base_string->key, ]); app()->call( 'Barryvdh\TranslationManager\Controller@postEdit', [ - 'group' => $group + 'group' => $group, ] ); } + return redirect()->back(); } + return redirect()->back(); } } diff --git a/src/Events/TranslationsExportedEvent.php b/src/Events/TranslationsExportedEvent.php index 3acc978c..a9df682e 100644 --- a/src/Events/TranslationsExportedEvent.php +++ b/src/Events/TranslationsExportedEvent.php @@ -3,22 +3,17 @@ * Created by PhpStorm. * User: kgbot * Date: 5/29/18 - * Time: 12:40 PM + * Time: 12:40 PM. */ namespace Barryvdh\TranslationManager\Events; - class TranslationsExportedEvent { - /** * Create a new event instance. - * - * @return void */ public function __construct() { - } -} \ No newline at end of file +} diff --git a/src/Manager.php b/src/Manager.php index b33530a3..5a2c3226 100644 --- a/src/Manager.php +++ b/src/Manager.php @@ -2,6 +2,7 @@ namespace Barryvdh\TranslationManager; +use Lang; use Illuminate\Support\Arr; use Illuminate\Support\Str; use Symfony\Component\Finder\Finder; @@ -13,23 +14,46 @@ class Manager { - const JSON_GROUP = '_json'; + public const JSON_GROUP = '_json'; - /** @var \Illuminate\Contracts\Foundation\Application */ + /** + * @var \Illuminate\Contracts\Foundation\Application + */ protected $app; - /** @var \Illuminate\Filesystem\Filesystem */ + + /** + * @var \Illuminate\Filesystem\Filesystem + */ protected $files; - /** @var \Illuminate\Contracts\Events\Dispatcher */ + + /** + * @var \Illuminate\Contracts\Events\Dispatcher + */ protected $events; + /** + * @var array + */ protected $config; + /** + * @var array + */ protected $locales; + /** + * @var mixed + */ protected $ignoreLocales; + /** + * @var string + */ protected $ignoreFilePath; + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ public function __construct(Application $app, Filesystem $files, Dispatcher $events) { $this->app = $app; @@ -41,22 +65,25 @@ public function __construct(Application $app, Filesystem $files, Dispatcher $eve $this->ignoreLocales = $this->getIgnoredLocales(); } + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ protected function getIgnoredLocales() { - if (! $this->files->exists($this->ignoreFilePath)) { + if (!$this->files->exists($this->ignoreFilePath)) { return []; } - $result = json_decode($this->files->get($this->ignoreFilePath)); + $result = json_decode($this->files->get($this->ignoreFilePath), false, 512); return ($result && is_array($result)) ? $result : []; } - public function importTranslations($replace = false, $base = null, $import_group = false) + public function importTranslations($replace = false, $base = null, $import_group = false): int { $counter = 0; - //allows for vendor lang files to be properly recorded through recursion. + // allows for vendor lang files to be properly recorded through recursion. $vendor = true; - if ($base == null) { + if (null === $base) { $base = $this->app['path.lang']; $vendor = false; } @@ -64,8 +91,8 @@ public function importTranslations($replace = false, $base = null, $import_group foreach ($this->files->directories($base) as $langPath) { $locale = basename($langPath); - //import langfiles for each vendor - if ($locale == 'vendor') { + // import langfiles for each vendor + if ('vendor' === $locale) { foreach ($this->files->directories($langPath) as $vendor) { $counter += $this->importTranslations($replace, $vendor); } @@ -76,25 +103,23 @@ public function importTranslations($replace = false, $base = null, $import_group foreach ($this->files->allfiles($langPath) as $file) { $info = pathinfo($file); $group = $info['filename']; - if ($import_group) { - if ($import_group !== $group) { - continue; - } + if ($import_group && $import_group !== $group) { + continue; } - if (in_array($group, $this->config['exclude_groups'])) { + if (in_array($group, $this->config['exclude_groups'], true)) { continue; } $subLangPath = str_replace($langPath.DIRECTORY_SEPARATOR, '', $info['dirname']); $subLangPath = str_replace(DIRECTORY_SEPARATOR, '/', $subLangPath); $langPath = str_replace(DIRECTORY_SEPARATOR, '/', $langPath); - if ($subLangPath != $langPath) { + if ($subLangPath !== $langPath) { $group = $subLangPath.'/'.$group; } - if (! $vendor) { - $translations = \Lang::getLoader()->load($locale, $group); + if (!$vendor) { + $translations = Lang::getLoader()->load($locale, $group); } else { $translations = include $file; $group = 'vendor/'.$vendorName; @@ -110,13 +135,13 @@ public function importTranslations($replace = false, $base = null, $import_group } foreach ($this->files->files($this->app['path.lang']) as $jsonTranslationFile) { - if (strpos($jsonTranslationFile, '.json') === false) { + if (!str_contains($jsonTranslationFile, '.json')) { continue; } $locale = basename($jsonTranslationFile, '.json'); $group = self::JSON_GROUP; $translations = - \Lang::getLoader()->load($locale, '*', '*'); // Retrieves JSON entries of the given locale only + Lang::getLoader()->load($locale, '*', '*'); // Retrieves JSON entries of the given locale only if ($translations && is_array($translations)) { foreach ($translations as $key => $value) { $importedTranslation = $this->importTranslation($key, $value, $locale, $group, $replace); @@ -128,9 +153,8 @@ public function importTranslations($replace = false, $base = null, $import_group return $counter; } - public function importTranslation($key, $value, $locale, $group, $replace = false) + public function importTranslation($key, $value, $locale, $group, $replace = false): bool { - // process only string values if (is_array($value)) { return false; @@ -138,18 +162,18 @@ public function importTranslation($key, $value, $locale, $group, $replace = fals $value = (string) $value; $translation = Translation::firstOrNew([ 'locale' => $locale, - 'group' => $group, - 'key' => $key, + 'group' => $group, + 'key' => $key, ]); - // Check if the database is different then the files + // Check if the database is different from the files $newStatus = $translation->value === $value ? Translation::STATUS_SAVED : Translation::STATUS_CHANGED; if ($newStatus !== (int) $translation->status) { $translation->status = $newStatus; } // Only replace when empty, or explicitly told so - if ($replace || ! $translation->value) { + if ($replace || !$translation->value) { $translation->value = $value; } @@ -158,7 +182,7 @@ public function importTranslation($key, $value, $locale, $group, $replace = fals return true; } - public function findTranslations($path = null) + public function findTranslations($path = null): int { $path = $path ?: base_path(); $groupKeys = []; @@ -166,15 +190,15 @@ public function findTranslations($path = null) $functions = $this->config['trans_functions']; $groupPattern = // See https://regex101.com/r/WEJqdL/6 - "[^\w|>]" . // Must not have an alphanum or _ or > before real method - '(' . implode('|', $functions) . ')' . // Must start with one of the functions - "\(" . // Match opening parenthesis - "[\'\"]" . // Match " or ' - '(' . // Start a new group to match: - '[\/a-zA-Z0-9_-]+' . // Must start with group - "([.](?! )[^\1)]+)+" . // Be followed by one or more items/keys - ')' . // Close group - "[\'\"]" . // Closing quote + "[^\w|>]". // Must not have an alphanum or _ or > before real method + '('.implode('|', $functions).')'. // Must start with one of the functions + "\(". // Match opening parenthesis + "[\'\"]". // Match " or ' + '('. // Start a new group to match: + '[\/a-zA-Z0-9_-]+'. // Must start with group + "([.](?! )[^\1)]+)+". // Be followed by one or more items/keys + ')'. // Close group + "[\'\"]". // Closing quote "[\),]"; // Close parentheses or new parameter $stringPattern = @@ -208,11 +232,10 @@ public function findTranslations($path = null) continue; } - //TODO: This can probably be done in the regex, but I couldn't do it. - //skip keys which contain namespacing characters, unless they also contain a - //space, which makes it JSON. - if (! (Str::contains($key, '::') && Str::contains($key, '.')) - || Str::contains($key, ' ')) { + // TODO: This can probably be done in the regex, but I couldn't do it. + // skip keys which contain namespacing characters, unless they also contain a + // space, which makes it JSON. + if (Str::contains($key, ' ') || !(Str::contains($key, '::') && Str::contains($key, '.'))) { $stringKeys[] = $key; } } @@ -225,7 +248,7 @@ public function findTranslations($path = null) // Add the translations to the database, if not existing. foreach ($groupKeys as $key) { // Split the group and item - list($group, $item) = explode('.', $key, 2); + [$group, $item] = explode('.', $key, 2); $this->missingKey('', $group, $item); } @@ -239,36 +262,38 @@ public function findTranslations($path = null) return count($groupKeys + $stringKeys); } - public function missingKey($namespace, $group, $key) + public function missingKey($namespace, $group, $key): void { - if (! in_array($group, $this->config['exclude_groups'])) { + if (!in_array($group, $this->config['exclude_groups'], true)) { Translation::firstOrCreate([ 'locale' => $this->app['config']['app.locale'], - 'group' => $group, - 'key' => $key, + 'group' => $group, + 'key' => $key, ]); } } - public function exportTranslations($group = null, $json = false) + public function exportTranslations($group = null, $json = false): void { $group = basename($group); $basePath = $this->app['path.lang']; - if (! is_null($group) && ! $json) { - if (! in_array($group, $this->config['exclude_groups'])) { + if (!is_null($group) && !$json) { + if (!in_array($group, $this->config['exclude_groups'], true)) { $vendor = false; - if ($group == '*') { - return $this->exportAllTranslations(); - } else { - if (Str::startsWith($group, 'vendor')) { - $vendor = true; - } + if ('*' === $group) { + $this->exportAllTranslations(); + + return; + } + + if (Str::startsWith($group, 'vendor')) { + $vendor = true; } $tree = $this->makeTree(Translation::ofTranslatedGroup($group) - ->orderByGroupKeys(Arr::get($this->config, 'sort_keys', false)) - ->get()); + ->orderByGroupKeys(Arr::get($this->config, 'sort_keys', false)) + ->get()); foreach ($tree as $locale => $groups) { $locale = basename($locale); @@ -281,15 +306,15 @@ public function exportTranslations($group = null, $json = false) $path = $basePath.'/'.$group.'/'.$locale; $locale_path = Str::after($group, '/'); } - $subfolders = explode(DIRECTORY_SEPARATOR, $locale_path); - array_pop($subfolders); + $subFolders = explode(DIRECTORY_SEPARATOR, $locale_path); + array_pop($subFolders); - $subfolder_level = ''; - foreach ($subfolders as $subfolder) { - $subfolder_level = $subfolder_level.$subfolder.DIRECTORY_SEPARATOR; + $subFolder_level = ''; + foreach ($subFolders as $subFolder) { + $subFolder_level .= $subFolder.DIRECTORY_SEPARATOR; - $temp_path = rtrim($path.DIRECTORY_SEPARATOR.$subfolder_level, DIRECTORY_SEPARATOR); - if (! is_dir($temp_path)) { + $temp_path = rtrim($path.DIRECTORY_SEPARATOR.$subFolder_level, DIRECTORY_SEPARATOR); + if (!is_dir($temp_path)) { mkdir($temp_path, 0777, true); } } @@ -317,7 +342,7 @@ public function exportTranslations($group = null, $json = false) if (isset($groups[self::JSON_GROUP])) { $translations = $groups[self::JSON_GROUP]; $path = $this->app['path.lang'].'/'.$locale.'.json'; - $output = json_encode($translations, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_UNICODE); + $output = json_encode($translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); $this->files->put($path, $output); } } @@ -328,12 +353,12 @@ public function exportTranslations($group = null, $json = false) $this->events->dispatch(new TranslationsExportedEvent()); } - public function exportAllTranslations() + public function exportAllTranslations(): void { $groups = Translation::whereNotNull('value')->selectDistinctGroup()->get('group'); foreach ($groups as $group) { - if ($group->group == self::JSON_GROUP) { + if (self::JSON_GROUP === $group->group) { $this->exportTranslations(null, true); } else { $this->exportTranslations($group->group); @@ -343,7 +368,7 @@ public function exportAllTranslations() $this->events->dispatch(new TranslationsExportedEvent()); } - protected function makeTree($translations, $json = false) + protected function makeTree($translations, $json = false): array { $array = []; foreach ($translations as $translation) { @@ -352,8 +377,11 @@ protected function makeTree($translations, $json = false) $this->jsonSet($array[$translation->locale][$translation->group], $translation->key, $translation->value); } else { - Arr::set($array[$translation->locale][$translation->group], $translation->key, - $translation->value); + Arr::set( + $array[$translation->locale][$translation->group], + $translation->key, + $translation->value + ); } } @@ -370,23 +398,25 @@ public function jsonSet(&$array, $key, $value) return $array; } - public function cleanTranslations() + public function cleanTranslations(): void { Translation::whereNull('value')->delete(); } - public function truncateTranslations() + public function truncateTranslations(): void { Translation::truncate(); } - public function getLocales() + public function getLocales(): array { if (empty($this->locales)) { - $locales = array_merge([config('app.locale')], - Translation::groupBy('locale')->pluck('locale')->toArray()); + $locales = array_merge( + [config('app.locale')], + Translation::groupBy('locale')->pluck('locale')->toArray() + ); foreach ($this->files->directories($this->app->langPath()) as $localeDir) { - if (($name = $this->files->name($localeDir)) != 'vendor') { + if (($name = $this->files->name($localeDir)) !== 'vendor') { $locales[] = $name; } } @@ -398,7 +428,10 @@ public function getLocales() return array_diff($this->locales, $this->ignoreLocales); } - public function addLocale($locale) + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ + public function addLocale($locale): bool { $localeDir = $this->app->langPath().'/'.basename($locale); @@ -406,21 +439,27 @@ public function addLocale($locale) $this->saveIgnoredLocales(); $this->ignoreLocales = $this->getIgnoredLocales(); - if (! $this->files->exists($localeDir) || ! $this->files->isDirectory($localeDir)) { + if (!$this->files->exists($localeDir) || !$this->files->isDirectory($localeDir)) { return $this->files->makeDirectory($localeDir); } return true; } + /** + * @return bool|int + */ protected function saveIgnoredLocales() { return $this->files->put($this->ignoreFilePath, json_encode($this->ignoreLocales)); } + /** + * @throws \Illuminate\Contracts\Filesystem\FileNotFoundException + */ public function removeLocale($locale) { - if (! $locale) { + if (!$locale) { return false; } $this->ignoreLocales = array_merge($this->ignoreLocales, [$locale]); @@ -432,10 +471,10 @@ public function removeLocale($locale) public function getConfig($key = null) { - if ($key == null) { + if (null === $key) { return $this->config; - } else { - return $this->config[$key]; } + + return $this->config[$key]; } } diff --git a/src/ManagerServiceProvider.php b/src/ManagerServiceProvider.php index daef4bd4..e9054bc2 100644 --- a/src/ManagerServiceProvider.php +++ b/src/ManagerServiceProvider.php @@ -1,31 +1,28 @@ -mergeConfigFrom($configPath, 'translation-manager'); $this->publishes([$configPath => config_path('translation-manager.php')], 'config'); $this->app->singleton('translation-manager', function ($app) { - $manager = $app->make('Barryvdh\TranslationManager\Manager'); - return $manager; + return $app->make(Manager::class); }); $this->app->singleton('command.translation-manager.reset', function ($app) { @@ -52,15 +49,13 @@ public function register() return new Console\CleanCommand($app['translation-manager']); }); $this->commands('command.translation-manager.clean'); - } + } /** - * Bootstrap the application events. - * - * @return void - */ - public function boot() - { + * Bootstrap the application events. + */ + public function boot(): void + { $viewPath = __DIR__.'/../resources/views'; $this->loadViewsFrom($viewPath, 'translation-manager'); $this->publishes([ @@ -73,22 +68,20 @@ public function boot() ], 'migrations'); $this->loadRoutesFrom(__DIR__.'/routes.php'); - } + } - /** - * Get the services provided by the provider. - * - * @return array - */ - public function provides() - { - return array('translation-manager', + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return [ + 'translation-manager', 'command.translation-manager.reset', 'command.translation-manager.import', 'command.translation-manager.find', 'command.translation-manager.export', - 'command.translation-manager.clean' - ); - } - + 'command.translation-manager.clean', + ]; + } } diff --git a/src/Models/Translation.php b/src/Models/Translation.php index 63d915a4..48ced908 100644 --- a/src/Models/Translation.php +++ b/src/Models/Translation.php @@ -1,34 +1,37 @@ -where('group', $group)->whereNotNull('value'); } - public function scopeOrderByGroupKeys($query, $ordered) { + public function scopeOrderByGroupKeys($query, $ordered) + { if ($ordered) { $query->orderBy('group')->orderBy('key'); } @@ -40,7 +43,7 @@ public function scopeSelectDistinctGroup($query) { $select = ''; - switch (DB::getDriverName()){ + switch (DB::getDriverName()) { case 'mysql': $select = 'DISTINCT `group`'; break; @@ -59,11 +62,10 @@ public function scopeSelectDistinctGroup($query) */ public function getConnectionName() { - if ($connection = config('translation-manager.db_connection')){ + if ($connection = config('translation-manager.db_connection')) { return $connection; } return parent::getConnectionName(); } - } diff --git a/src/TranslationServiceProvider.php b/src/TranslationServiceProvider.php index dd3ccc8e..ab574fe1 100644 --- a/src/TranslationServiceProvider.php +++ b/src/TranslationServiceProvider.php @@ -1,41 +1,35 @@ -registerLoader(); - $this->app->singleton('translator', function($app) - { + $this->app->singleton('translator', function ($app) { $loader = $app['translation.loader']; // When registering the translator component, we'll need to set the default // locale as well as the fallback locale. So, we'll grab the application - // configuration so we can easily get both of these values from there. + // configuration, so we can easily get both of these values from there. $locale = $app['config']['app.locale']; $trans = new Translator($loader, $locale); $trans->setFallback($app['config']['app.fallback_locale']); - if($app->bound('translation-manager')){ + if ($app->bound('translation-manager')) { $trans->setTranslationManager($app['translation-manager']); } return $trans; }); - } - - } diff --git a/src/Translator.php b/src/Translator.php index 28ed72f6..22c641bb 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -1,47 +1,50 @@ -notifyMissingKey($key); // Reget with fallback $result = parent::get($key, $replace, $locale, $fallback); - } return $result; } - public function setTranslationManager(Manager $manager) + public function setTranslationManager(Manager $manager): void { $this->manager = $manager; } - protected function notifyMissingKey($key) + protected function notifyMissingKey($key): void { - list($namespace, $group, $item) = $this->parseKey($key); - if($this->manager && $namespace === '*' && $group && $item ){ + [$namespace, $group, $item] = $this->parseKey($key); + if ($this->manager && '*' === $namespace && $group && $item) { $this->manager->missingKey($namespace, $group, $item); } } - } diff --git a/src/routes.php b/src/routes.php index fefb399d..b6e08ee4 100644 --- a/src/routes.php +++ b/src/routes.php @@ -2,19 +2,22 @@ declare(strict_types=1); -$config = array_merge(config('translation-manager.route'), ['namespace' => 'Barryvdh\TranslationManager']); -Route::group($config, function($router) -{ - $router->get('view/{groupKey?}', 'Controller@getView')->where('groupKey', '.*'); - $router->get('/{groupKey?}', 'Controller@getIndex')->where('groupKey', '.*'); - $router->post('/add/{groupKey}', 'Controller@postAdd')->where('groupKey', '.*'); - $router->post('/edit/{groupKey}', 'Controller@postEdit')->where('groupKey', '.*'); - $router->post('/groups/add', 'Controller@postAddGroup'); - $router->post('/delete/{groupKey}/{translationKey}', 'Controller@postDelete')->where('groupKey', '.*'); - $router->post('/import', 'Controller@postImport'); - $router->post('/find', 'Controller@postFind'); - $router->post('/locales/add', 'Controller@postAddLocale'); - $router->post('/locales/remove', 'Controller@postRemoveLocale'); - $router->post('/publish/{groupKey}', 'Controller@postPublish')->where('groupKey', '.*'); - $router->post('/translate-missing', 'Controller@postTranslateMissing'); +use Barryvdh\TranslationManager\Controller; + +$config = array_merge(config('translation-manager.route'), ['namespace' => '\Barryvdh\TranslationManager']); +Route::group($config, function ($router) { + $router->get('/model/{selectedModel?}', [Controller::class, 'getModelView'])->where('selectedModel', '.*'); + $router->get('/view/{groupKey?}', [Controller::class, 'getView'])->where('groupKey', '.*'); + $router->get('/{groupKey?}', [Controller::class, 'getIndex'])->where('groupKey', '.*'); + $router->post('/add/{groupKey}', [Controller::class, 'postAdd'])->where('groupKey', '.*'); + $router->post('/model/edit/{selectedModel}', [Controller::class, 'postEditModel'])->where('selectedModel', '.*'); + $router->post('/edit/{groupKey}', [Controller::class, 'postEdit'])->where('groupKey', '.*'); + $router->post('/groups/add', [Controller::class, 'postAddGroup']); + $router->post('/delete/{groupKey}/{translationKey}', [Controller::class, 'postDelete'])->where('groupKey', '.*'); + $router->post('/import', [Controller::class, 'postImport']); + $router->post('/find', [Controller::class, 'postFind']); + $router->post('/locales/add', [Controller::class, 'postAddLocale']); + $router->post('/locales/remove', [Controller::class, 'postRemoveLocale']); + $router->post('/publish/{groupKey}', [Controller::class, 'postPublish'])->where('groupKey', '.*'); + $router->post('/translate-missing', [Controller::class, 'postTranslateMissing']); }); diff --git a/tests/TestCase.php b/tests/TestCase.php index adb54888..480c554e 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -8,9 +8,10 @@ abstract class TestCase extends \Orchestra\Testbench\TestCase { /** * @param \Illuminate\Foundation\Application $app + * * @return string[] */ - protected function getPackageProviders($app) + protected function getPackageProviders($app): array { return [ManagerServiceProvider::class]; }