scan('filament'); $this->scan('forms'); $this->scan('notifications'); $this->scan('support'); $this->scan('tables'); return self::SUCCESS; } protected function scan(string $package) { $localeRootDirectory = match ($source = $this->option('source')) { 'app' => lang_path("vendor/{$package}"), 'vendor' => base_path("vendor/filament/{$package}/resources/lang"), default => throw new InvalidOptionException("{$source} is not a valid translation source. Must be `vendor` or `app`.") }; $filesystem = app(Filesystem::class); if (! $filesystem->exists($localeRootDirectory)) { return; } collect($filesystem->directories($localeRootDirectory)) ->mapWithKeys(static fn (string $directory): array => [$directory => (string) Str::of($directory)->afterLast(DIRECTORY_SEPARATOR)]) ->when( $locales = $this->argument('locales'), fn (Collection $availableLocales): Collection => $availableLocales->filter(fn (string $locale): bool => in_array($locale, $locales)) ) ->each(function (string $locale, string $localeDir) use ($filesystem, $localeRootDirectory, $package) { $files = $filesystem->allFiles($localeDir); collect($files) ->mapWithKeys(function (SplFileInfo $file) use ($localeDir, $localeRootDirectory) { $expectedKeys = require implode(DIRECTORY_SEPARATOR, [$localeRootDirectory, 'en', $file->getRelativePathname()]); $actualKeys = require $file->getPathname(); return [ (string) Str::of($file->getPathname())->after("{$localeDir}/") => [ 'missing' => array_keys(array_diff_key( Arr::dot($expectedKeys), Arr::dot($actualKeys) )), 'removed' => array_keys(array_diff_key( Arr::dot($actualKeys), Arr::dot($expectedKeys) )), ], ]; }) ->tap(function (Collection $files) use ($locale, $package) { $missingKeysCount = $files->sum(fn ($file): int => count($file['missing'])); $removedKeysCount = $files->sum(fn ($file): int => count($file['removed'])); $locale = locale_get_display_name($locale, 'en'); if ($missingKeysCount == 0 && $removedKeysCount == 0) { $this->info("[✓] Package filament/{$package} has no missing or removed translation keys for {$locale}!\n"); $this->newLine(); } elseif ($missingKeysCount > 0 && $removedKeysCount > 0) { $this->warn("[!] Package filament/{$package} has {$missingKeysCount} missing translation " . Str::plural('key', $missingKeysCount) . " and {$removedKeysCount} removed translation " . Str::plural('key', $removedKeysCount) . " for {$locale}.\n"); } elseif ($missingKeysCount > 0) { $this->warn("[!] Package filament/{$package} has {$missingKeysCount} missing translation " . Str::plural('key', $missingKeysCount) . " for {$locale}.\n"); } elseif ($removedKeysCount > 0) { $this->warn("[!] Package filament/{$package} has {$removedKeysCount} removed translation " . Str::plural('key', $removedKeysCount) . " for {$locale}.\n"); } }) ->filter(static fn ($keys): bool => count($keys['missing']) || count($keys['removed'])) ->each(function ($keys, string $file) { $this->table( [$file, ''], array_merge( array_map(fn (string $key) => [$key, 'Missing'], $keys['missing']), array_map(fn (string $key) => [$key, 'Removed'], $keys['removed']), ), 'box', ); $this->newLine(); }); }); } }