Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Locale:* bakery command #992

Merged
merged 60 commits into from
Jan 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
64945e5
Initial commit
amosfolz Jun 3, 2019
0554ae0
Initial Draft
amosfolz Jun 4, 2019
8be4d2d
Fix filename typos..
amosfolz Jun 4, 2019
8842388
Begin restructure
amosfolz Jun 4, 2019
f9f7170
Malou is not going to like this...
amosfolz Jun 5, 2019
5ed640d
try to separate out LocaleMissingKeysCommand
amosfolz Jun 5, 2019
7e07069
Merge pull request #4 from amosfolz/locale-updates
amosfolz Jun 5, 2019
24e8720
updates
amosfolz Jun 6, 2019
423b6d7
Reorganize LocaleMissingKeysCommand
amosfolz Jun 7, 2019
edaaa95
updates
amosfolz Jun 7, 2019
010902d
New draft of LocaleMissingValuesCommand
amosfolz Jun 7, 2019
b3f2226
Merge pull request #5 from amosfolz/locale-updates
amosfolz Jun 7, 2019
1446075
Updates
amosfolz Jun 9, 2019
0dcf2cc
Update LocaleFixKeysCommand.php
amosfolz Jun 9, 2019
7b60426
Update LocaleFixKeysCommand.php
amosfolz Jun 9, 2019
a910dda
updates
amosfolz Jun 11, 2019
286af71
Finished fix-keys command
amosfolz Jun 11, 2019
3ecf85c
Looked over all commands. Finalize fix-keys
amosfolz Jun 12, 2019
f4062d5
Squashed commit of the following:
amosfolz Jun 12, 2019
ddef9b8
StyleCI Fix
amosfolz Jun 12, 2019
feefb4d
Fix error in LocaleMissingKeysCommand
amosfolz Jun 12, 2019
7555311
Fix error in LocaleFixKeysCommand.php
amosfolz Jun 12, 2019
cee7102
Fix broken merge
amosfolz Jun 13, 2019
628dc7f
Retain docblock comments in locale files
amosfolz Jun 13, 2019
a1e3272
update LocaleFixKeysCommand.php
amosfolz Jun 13, 2019
d687d4f
Merge branch 'locale-testing' into locale-updates
amosfolz Jun 13, 2019
6cd4404
Merge pull request #6 from amosfolz/locale-updates
amosfolz Jun 13, 2019
166810e
style CI
amosfolz Jun 13, 2019
4d0aee2
Merge branch 'locale-updates' of https://github.com/amosfolz/UserFros…
amosfolz Jun 13, 2019
4ca900c
Merge pull request #7 from amosfolz/locale-updates
amosfolz Jun 13, 2019
6e82fbf
Merge remote-tracking branch 'upstream/develop' into locale-testing
amosfolz Jun 14, 2019
b7ad20e
fix-keys generates list, change table styling
amosfolz Jun 14, 2019
162336c
Updates
amosfolz Jun 14, 2019
9336991
Adjusted table formatting. Added additional conf prompt for fix-keys
amosfolz Jun 15, 2019
a8b4eeb
Merge remote-tracking branch 'upstream/develop' into locale-updates
amosfolz Jun 27, 2019
a823f7e
fix nested keys error in missing-keys
amosfolz Jun 27, 2019
db35ee9
Update getDifference
amosfolz Jun 27, 2019
dd7201d
Fix keys commands
amosfolz Jun 27, 2019
206cec5
add comment
amosfolz Jun 27, 2019
949f9e2
Updates
amosfolz Jun 27, 2019
082540b
Merge remote-tracking branch 'upstream/develop' into locale-testing
amosfolz Jun 30, 2019
3c2770b
Fix table style
amosfolz Jun 30, 2019
9cf11f2
Remove old code
amosfolz Jun 30, 2019
8f2c316
Update fix-keys command
amosfolz Jun 30, 2019
3ce031a
updates
amosfolz Jul 1, 2019
7504e52
Retain values when creating @translation subkeys
amosfolz Jul 1, 2019
8a5a4d4
Retain values when creating @translation subkeys
amosfolz Jul 1, 2019
8faaab9
Merge branch 'locale-testing' into locale-updates
amosfolz Jul 1, 2019
a2d2542
Merge remote-tracking branch 'upstream/develop' into locale-testing
amosfolz Jul 12, 2019
c81aa2a
Merge branch 'develop' into locale-testing
amosfolz Jul 14, 2019
163be89
Merge remote-tracking branch 'upstream/develop' into locale-testing
amosfolz Jul 19, 2019
8e13cc7
Improved code, applied PHP7 type hint and fixed some styling
lcharette Jul 21, 2019
24567b4
Fix styling
lcharette Jul 21, 2019
56beebd
Fix Issue with `el` locale
lcharette Jul 22, 2019
8f8ca0a
Return empty array when parsing non existing file or file not returni…
lcharette Jul 22, 2019
85210a9
Added first tests for locale:missing-keys
lcharette Jul 24, 2019
a469ed4
Forgot to commit es_ES test locale
lcharette Jul 24, 2019
f88895c
Merge branch 'develop' into pr/992
lcharette Jan 11, 2020
39b650c
Added `locale:info` command
lcharette Jan 12, 2020
22cd1bf
Fix styling
lcharette Jan 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
243 changes: 243 additions & 0 deletions app/sprinkles/core/src/Bakery/LocaleFixKeysCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
<?php

/*
* UserFrosting (http://www.userfrosting.com)
*
* @link https://github.com/userfrosting/UserFrosting
* @copyright Copyright (c) 2019 Alexander Weissman
* @license https://github.com/userfrosting/UserFrosting/blob/master/LICENSE.md (MIT License)
*/

namespace UserFrosting\Sprinkle\Core\Bakery;

use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use UserFrosting\Support\Repository\Repository;

/**
* locale:fix-keys command.
* Fix missing keys in locale translation files.
*
* @author Amos Folz
*/
class LocaleFixKeysCommand extends LocaleMissingKeysCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('locale:fix-keys')
->setHelp("This command generates missing keys for locale translation files. E.g. running 'locale:fix-keys -b en_US -f es_ES' will compare all es_ES and en_US locale files and populate es_ES with any missing keys from en_US.")
->addOption('base', 'b', InputOption::VALUE_REQUIRED, 'The base locale used to generate values for any keys that are fixed. ', 'en_US')
->addOption('locale', 'l', InputOption::VALUE_REQUIRED, 'One or more specific locales to fix. E.g. "fr_FR,es_ES" ', null)
->addOption('force', 'f', InputOption::VALUE_NONE, 'Do not display confirmation.')
->setDescription('Fix locale missing files and key values');
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->io->title('Fixing Locale Keys');

// The "base" locale to compare other locales against. Defaults to en_US if not set.
$baseLocale = $input->getOption('base');
$baseLocaleFileNames = $this->getFilenames($baseLocale);

// Option -c. Set to compare one or more specific locales.
$locales = $input->getOption('locale');

// Get locales to fix
$localesToFix = $this->getLocales($baseLocale, $locales);

$this->io->note('Locales to be fixed: |' . implode('|', $localesToFix) . '|');

if (!$input->getOption('force') && !$this->io->confirm("All translation files for the locales above will be populated using key|values from | $baseLocale |. Continue?", false)) {
exit;
}

$fixed = [];

$progressBar = new ProgressBar($output);
$progressBar->start(count($localesToFix));

foreach ($localesToFix as $locale) {
$fixed[$locale] = $this->fixFiles($baseLocale, $locale, $baseLocaleFileNames);
$progressBar->advance();
}

$this->io->newLine(2);

$filesFixed = $this->getListValues($fixed);
if (empty($filesFixed)) {
$this->io->success('No file need fixing');
} else {
$this->io->section('Files fixed');
$this->io->listing($filesFixed);
$this->io->success('Files fixed successfully');
}
}

/**
* Build a list of files that were fixed.
*
* @param array $array File paths and missing keys.
*
* @return array A list of fixed files
*/
protected function getListValues(array $array): array
{
$fixed = [];

foreach ($array as $key => $value) {
if (is_array($value)) {
//We need to loop through it.
$fixed = array_merge($fixed, $this->getListValues($value));
} elseif ($value != '0') {
//It is not an array and not '0', so add it to the list.
$fixed[] = $value;
}
}

return $fixed;
}

/**
* Iterate over sprinkle locale files and find the difference for two locales.
*
* @param string $baseLocale Locale being compared against.
* @param string $altLocale Locale to find missing keys for.
* @param array $filenames Sprinkle locale files that will be compared.
*
* @return array Filepaths that were fixed.
*/
protected function fixFiles(string $baseLocale, string $altLocale, array $filenames): array
{
$fixed = [];

foreach ($filenames as $sprinklePath => $files) {
foreach ($files as $key => $file) {
$base = $this->parseFile("$sprinklePath/locale/$baseLocale/$file");
$alt = $this->parseFile("$sprinklePath/locale/$altLocale/$file");
$filePath = "$sprinklePath/locale/$altLocale/$file";
$diff = $this->getDifference($base, $alt);
$missing = $this->arrayFlatten($diff);

// The files with missing keys.
if (!empty($missing)) {
$fixed[] = $this->fix($base, $alt, $filePath, $missing);
}
}
}

return $fixed;
}

/**
* Fixes locale files by adding missing keys.
*
* @param array $base
* @param array $alt
* @param string $filePath The path of fixed file.
* @param array $missing
*
* @return string The path of the fixed file
*/
protected function fix(array $base, array $alt, string $filePath, array $missing): string
{
//If the directory does not exist we need to create it recursively.
if (!file_exists(dirname($filePath))) {
mkdir(dirname($filePath), 0777, true);
}

// Build the respository and then merge in each locale file.
// Any keys not in the $alt locale will be the original left from the $base locales value.
$repository = new Repository();
$repository->mergeItems(null, $base);
$repository->mergeItems(null, $alt);

foreach ($missing as $key => $value) {
if (!$repository->has($key)) {
if (strpos($key, '@TRANSLATION') !== false) {
$val = $repository->get(str_replace('.@TRANSLATION', '', $key));
$repository->set($key, $val);
} else {
$repository->set($key, $value);
}
}
}

// Check if this is an existing locale file with docblock.
$temp = file_get_contents($filePath);

if (strpos($temp, '@author') !== false || strpos($temp, '/**') !== false) {
// Save existing docblock temporarily.
$start = strpos($temp, '/**');
$end = strpos(substr($temp, $start), '*/');
$docblock = file_get_contents($filePath, null, null, $start, $end + 2);

passthru("echo \<?php > $filePath");

// We have to add the comment header prior to docblock or php-cs-fixer will overwrite it.
$this->fixFileWithPhpCs($filePath);

// Append the docblock after the header comment.
file_put_contents($filePath, $docblock, FILE_APPEND);
passthru("echo '\r\n' >> $filePath");
} else {
passthru("echo \<?php > $filePath");
}

file_put_contents($filePath, var_export($repository->all(), true), FILE_APPEND);

passthru("echo \; >> $filePath");

// Final check with php-cs-fixer
$this->fixFileWithPhpCs($filePath);

// Insert 'return' into the file.
file_put_contents($filePath, preg_replace('/\[/', 'return [', file_get_contents($filePath), 1));

return $filePath;
}

/**
* Fix a file using php-cs-fixer.
*
* @param string $file path of file to fix
*/
public function fixFileWithPhpCs(string $file): void
{
// Fix the file with php-cs-fixer
passthru("php ./app/vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix $file --quiet --using-cache no --config ./.php_cs");
}

/**
* {@inheritdoc}
*/
protected function getLocales(string $baseLocale, ?string $localesToCheck): array
{
$configuredLocales = array_diff(array_keys($this->ci->config['site']['locales']['available']), [$baseLocale]);

// If set, use the locale(s) from the -f option.
if ($localesToCheck) {
$locales = explode(',', $localesToCheck);
foreach ($locales as $key => $value) {
if (!in_array($value, $configuredLocales)) {
$this->io->warning("The |$value| locale was not found in your current configuration. Proceeding may results in a large number of files being created. Are you sure you want to continue?");
if (!$this->io->confirm('Continue?', false)) {
exit;
}
}
}

return $locales;
} else {
return $configuredLocales;
}
}
}
69 changes: 69 additions & 0 deletions app/sprinkles/core/src/Bakery/LocaleInfoCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* UserFrosting (http://www.userfrosting.com)
*
* @link https://github.com/userfrosting/UserFrosting
* @copyright Copyright (c) 2019 Alexander Weissman
* @license https://github.com/userfrosting/UserFrosting/blob/master/LICENSE.md (MIT License)
*/

namespace UserFrosting\Sprinkle\Core\Bakery;

use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use UserFrosting\System\Bakery\BaseCommand;

/**
* locale:info command.
* List all available locales.
*
* @author Louis Charette
*/
class LocaleInfoCommand extends BaseCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('locale:info')
->setHelp('This command list all available locale as well as the defaut locale.')
->setDescription('Informations about available locales');
}

/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->io->title('Available locales');

/** @var \UserFrosting\Sprinkle\Core\I18n\SiteLocale */
$localeService = $this->ci->locale;

// Get available locales
/** @var \UserFrosting\I18n\Locale[] $available */
$available = $localeService->getAvailable();

// Prepare table headers and lines array
$table = new Table($output);
$table->setHeaders(['Identifier', 'Name', 'Regional', 'Parents', 'Default']);

foreach ($available as $locale) {
$table->addRow([
$locale->getIdentifier(),
$locale->getName(),
$locale->getRegionalName(),
implode(', ', $locale->getDependentLocalesIdentifier()),
($locale->getIdentifier() === $localeService->getDefaultLocale()) ? 'Yes' : '',
]);
}

$table->render();

// Everything went fine, return 0 exit code
return 0;
}
}
Loading