Skip to content

Commit

Permalink
v1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianSchoeps committed Nov 26, 2021
1 parent 66affa7 commit 28a2c74
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 128 deletions.
7 changes: 0 additions & 7 deletions CHANGELOG.md

This file was deleted.

80 changes: 10 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,4 @@
# This is my package missing-translation

[![Latest Version on Packagist](https://img.shields.io/packagist/v/nanuc/missing-translation.svg?style=flat-square)](https://packagist.org/packages/nanuc/missing-translation)
[![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/nanuc/missing-translation/run-tests?label=tests)](https://github.com/nanuc/missing-translation/actions?query=workflow%3Arun-tests+branch%3Amain)
[![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/nanuc/missing-translation/Check%20&%20fix%20styling?label=code%20style)](https://github.com/nanuc/missing-translation/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amain)
[![Total Downloads](https://img.shields.io/packagist/dt/nanuc/missing-translation.svg?style=flat-square)](https://packagist.org/packages/nanuc/missing-translation)

---
This repo can be used to scaffold a Laravel package. Follow these steps to get started:

1. Press the "Use template" button at the top of this repo to create a new repo with the contents of this missing-translation
2. Run "php ./configure.php" to run a script that will replace all placeholders throughout all the files
3. Remove this block of text.
4. Have fun creating your package.
5. If you need help creating a package, consider picking up our <a href="https://laravelpackage.training">Laravel Package Training</a> video course.
---

This is where your description should go. Limit it to a paragraph or two. Consider adding a small example.

## Support us

[<img src="https://github-ads.s3.eu-central-1.amazonaws.com/missing-translation.jpg?t=1" width="419px" />](https://spatie.be/github-ad-click/missing-translation)

We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us).

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards).
# Missing translations

## Installation

Expand All @@ -33,60 +8,25 @@ You can install the package via composer:
composer require nanuc/missing-translation
```

You can publish and run the migrations with:

```bash
php artisan vendor:publish --tag="missing-translation_without_prefix-migrations"
php artisan migrate
```
## Usage

You can publish the config file with:
```bash
php artisan vendor:publish --tag="missing-translation_without_prefix-config"
### Find and enter missing translations
```

Optionally, you can publish the views using

```bash
php artisan vendor:publish --tag="example-views"
art missing-translation:find {locale}
```

This is the contents of the published config file:
### Report missing translations
**This is basically copied from https://github.com/barryvdh/laravel-translation-manager with the extension that missing translations are reported to Flare.**

```php
return [
];
```
Most translations can be found by using the Find command (see above), but in case you have dynamic keys (variables/automatic forms etc), it can be helpful to 'listen' to the missing translations. To detect missing translations, we can swap the Laravel TranslationServiceProvider with a custom provider. In your config/app.php, comment out the original TranslationServiceProvider and add the one from this package:

## Usage

```php
$missing-translation = new Nanuc\MissingTranslation();
echo $missing-translation->echoPhrase('Hello, Nanuc!');
```

## Testing

```bash
composer test
//'Illuminate\Translation\TranslationServiceProvider',
'Barryvdh\TranslationManager\TranslationServiceProvider',
```

## Changelog

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

## Contributing

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

## Security Vulnerabilities

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

## Credits
This will extend the Translator and will send a report to Flare, whenever a key is not found, so you have to visit the pages that use them. You shouldn't use this in production, just in development to translate your views, then just switch back.

- [Sebastian Schöps](https://github.com/nanuc)
- [All Contributors](../../contributors)

## License

Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"require": {
"php": "^8.0",
"spatie/laravel-package-tools": "^1.9.2",
"facade/ignition": "^2.5",
"illuminate/contracts": "^8.37"
},
"require-dev": {
Expand Down Expand Up @@ -59,4 +60,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}
141 changes: 141 additions & 0 deletions src/Commands/FindMissingTranslationCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace Nanuc\MissingTranslation\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Symfony\Component\Finder\Finder;

class FindMissingTranslationCommand extends Command
{
public $signature = 'missing-translation:find {language=en : Language to use}';

public $description = 'Find (and correct) missing translations';

public function handle()
{
$path = base_path();

$stringKeys = [];

$functions = [
'trans',
'trans_choice',
'Lang::get',
'Lang::choice',
'Lang::trans',
'Lang::transChoice',
'@lang',
'@choice',
'__',
'$trans.get',
];
$toBeTranslatedMarker = '!E!';

$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
"[\),]"; // Close parentheses or new parameter

$stringPattern =
"[^\w]". // Must not have an alphanum before real method
'('.implode('|', $functions).')'. // Must start with one of the functions
"\(". // Match opening parenthesis
"(?P<quote>['\"])". // Match " or ' and store in {quote}
"(?P<string>(?:\\\k{quote}|(?!\k{quote}).)*)". // Match any string that can be {quote} escaped
"\k{quote}". // Match " or ' previously matched
"[\),]"; // Close parentheses or new parameter

if (! File::exists($this->langFile())) {
File::put($this->langFile(), json_encode([]));
}

// Find all PHP + Twig files in the app folder, except for storage
$finder = new Finder();
$finder->in($path)->exclude('storage')->exclude('vendor')->name('*.php')->name('*.twig')->name('*.vue')->files();

/** @var \Symfony\Component\Finder\SplFileInfo $file */
foreach ($finder as $file) {
if (preg_match_all("/$stringPattern/siU", $file->getContents(), $matches)) {
foreach ($matches['string'] as $key) {
/*
if (preg_match("/(^[a-zA-Z0-9_-]+([.][^\1)\ ]+)+$)/siU", $key, $groupMatches)) {
$this->info(str_replace(base_path(), '', $file->getPathname()).': '.$groupMatches[0]);
// group{.group}.key format, already in $groupKeys but also matched here
// do nothing, it has to be treated as a group
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, ' ')) {
$stringKeys[] = $key;
}

if (Str::contains($key, $toBeTranslatedMarker)) {
$translation = $this->ask('Please enter German translation for "'.str_replace($toBeTranslatedMarker, '', $key).'"');

$content = $file->getContents();
$content = str_replace($key, $translation, $content);
File::put($file->getRealPath(), $content);

$translations = $this->getAvailableStrings();
$translations[$translation] = str_replace($toBeTranslatedMarker, '', $key);
File::put($this->langFile(), json_encode($translations, JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE + JSON_PRETTY_PRINT));
}
}
}
}
$stringKeys = array_unique($stringKeys);
$availableStrings = $this->getAvailableStrings();

$missingTranslations = [];
foreach ($stringKeys as $stringKey) {
if (! in_array($stringKey, array_keys($availableStrings))) {
$missingTranslations[] = $stringKey;
}
}

$this->info('Found ' . count($missingTranslations) . ' missing translations.');

if ($this->confirm('Do you want to display the missing phrases?')) {
foreach ($missingTranslations as $missingTranslation) {
$this->info($missingTranslation);
}
}

if ($this->confirm('Do you want to translate the missing phrases now?')) {
foreach ($missingTranslations as $missingTranslation) {
$translation = $this->ask('Please enter translation (locale: ' . $this->argument('language') . ') for "' . $missingTranslation . '"');

if(strlen($translation) > 0) {
$translations = $this->getAvailableStrings();
$translations[$missingTranslation] = $translation;
File::put($this->langFile(), json_encode($translations, JSON_UNESCAPED_SLASHES + JSON_UNESCAPED_UNICODE + JSON_PRETTY_PRINT));

}
}
}
}

public function getAvailableStrings()
{
return json_decode(File::get($this->langFile()), true);
}

public function langFile()
{
return resource_path('lang/'.$this->argument('language').'.json');
}
}
19 changes: 0 additions & 19 deletions src/Commands/MissingTranslationCommand.php

This file was deleted.

16 changes: 0 additions & 16 deletions src/Facades/MissingTranslation.php

This file was deleted.

7 changes: 0 additions & 7 deletions src/MissingTranslation.php

This file was deleted.

10 changes: 2 additions & 8 deletions src/MissingTranslationServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,18 @@

namespace Nanuc\MissingTranslation;

use Nanuc\MissingTranslation\Commands\FindMissingTranslationCommand;
use Spatie\LaravelPackageTools\Package;
use Spatie\LaravelPackageTools\PackageServiceProvider;
use Nanuc\MissingTranslation\Commands\MissingTranslationCommand;

class MissingTranslationServiceProvider extends PackageServiceProvider
{
public function configurePackage(Package $package): void
{
/*
* This class is a Package Service Provider
*
* More info: https://github.com/spatie/laravel-package-tools
*/
$package
->name('missing-translation')
->hasConfigFile()
->hasViews()
->hasMigration('create_missing-translation_table')
->hasCommand(MissingTranslationCommand::class);
->hasCommand(FindMissingTranslationCommand::class);
}
}
32 changes: 32 additions & 0 deletions src/TranslationServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace Nanuc\MissingTranslation;

use Illuminate\Translation\TranslationServiceProvider as BaseTranslationServiceProvider;

class TranslationServiceProvider extends BaseTranslationServiceProvider {
public function register()
{
$this->registerLoader();

$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.
$locale = $app['config']['app.locale'];

$trans = new Translator($loader, $locale);

$trans->setFallback($app['config']['app.fallback_locale']);

if($app->bound('translation-manager')){
$trans->setTranslationManager($app['translation-manager']);
}

return $trans;
});
}
}
Loading

0 comments on commit 28a2c74

Please sign in to comment.