Skip to content

Commit beec2cf

Browse files
authored
feat: provides pseudo-locale command for testing (#25)
1 parent a36bde1 commit beec2cf

38 files changed

Lines changed: 1212 additions & 45 deletions

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99

1010
### Added
1111

12+
- Add `pseudo-locale` console command to allow conversion of a locale to one of the supported pseudo-locales (`en-XA`, `en-XB`, `xx-AC`, `xx-HA`, and `xx-LS`).
1213
- Provide `--flatten` extraction option to tell the extractor to hoist selectors and flatten sentences as much as possible. For example, `I have {count, plural, one{a dog} other{many dogs}}` becomes `{count, plural, one{I have a dog} other{I have many dogs}}`. The goal is to provide as many full sentences as possible, since fragmented sentences are not translator-friendly.
1314
- Provide `--add-missing-ids` extraction option to update source code with auto-generated identifiers
1415
- Add `Util\FormatHelper` that provides `getReader()` and `getWriter()` methods
@@ -32,7 +33,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
3233

3334
### Fixed
3435

35-
- Nothing.
36+
- Support rich text formatting in the [same manner as FormatJS](https://formatjs.io/docs/core-concepts/icu-syntax#rich-text-formatting). Previously, we allowed HTML tags with attributes, etc., but this limits our ability to provide pseudo-locales and validation.
3637

3738
## 0.2.2 - 2021-11-18
3839

src/Console/Application.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
namespace FormatPHP\Console;
2424

2525
use FormatPHP\Console\Command\ExtractCommand;
26+
use FormatPHP\Console\Command\PseudoLocaleCommand;
2627
use Symfony\Component\Console\Application as SymfonyConsoleApplication;
28+
use Symfony\Component\Console\Exception\LogicException;
2729

2830
/**
2931
* FormatPHP console application
@@ -32,10 +34,14 @@ class Application extends SymfonyConsoleApplication
3234
{
3335
public const NAME = 'formatphp';
3436

37+
/**
38+
* @throws LogicException
39+
*/
3540
public function __construct()
3641
{
3742
parent::__construct(self::NAME);
3843

3944
$this->add(new ExtractCommand());
45+
$this->add(new PseudoLocaleCommand());
4046
}
4147
}

src/Console/Command/AbstractCommand.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,30 @@
2222

2323
namespace FormatPHP\Console\Command;
2424

25+
use Psr\Log\LogLevel;
26+
use Psr\Log\LoggerInterface;
2527
use Symfony\Component\Console\Command\Command as SymfonyConsoleCommand;
28+
use Symfony\Component\Console\Logger\ConsoleLogger;
29+
use Symfony\Component\Console\Output\OutputInterface;
2630

2731
/**
2832
* Common command functionality for FormatPHP console commands
2933
*/
3034
abstract class AbstractCommand extends SymfonyConsoleCommand
3135
{
36+
private const LOG_FORMAT_MAPPING = [
37+
LogLevel::WARNING => ConsoleLogger::ERROR,
38+
LogLevel::NOTICE => ConsoleLogger::ERROR,
39+
LogLevel::INFO => ConsoleLogger::ERROR,
40+
LogLevel::DEBUG => ConsoleLogger::ERROR,
41+
];
42+
43+
private const LOG_VERBOSITY_MAPPING = [
44+
LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
45+
];
46+
47+
protected function getConsoleLogger(OutputInterface $output): LoggerInterface
48+
{
49+
return new ConsoleLogger($output, self::LOG_VERBOSITY_MAPPING, self::LOG_FORMAT_MAPPING);
50+
}
3251
}

src/Console/Command/ExtractCommand.php

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,11 @@
3333
use FormatPHP\Util\FormatHelper;
3434
use FormatPHP\Util\Globber;
3535
use LogicException;
36-
use Psr\Log\LogLevel;
36+
use Ramsey\Collection\Exception\CollectionMismatchException;
3737
use Symfony\Component\Console\Exception\InvalidArgumentException as SymfonyInvalidArgumentException;
3838
use Symfony\Component\Console\Input\InputArgument;
3939
use Symfony\Component\Console\Input\InputInterface;
4040
use Symfony\Component\Console\Input\InputOption;
41-
use Symfony\Component\Console\Logger\ConsoleLogger;
4241
use Symfony\Component\Console\Output\OutputInterface;
4342

4443
use function array_map;
@@ -68,17 +67,6 @@ class ExtractCommand extends AbstractCommand
6867
'vendor',
6968
];
7069

71-
private const LOG_FORMAT_MAPPING = [
72-
LogLevel::WARNING => ConsoleLogger::ERROR,
73-
LogLevel::NOTICE => ConsoleLogger::ERROR,
74-
LogLevel::INFO => ConsoleLogger::ERROR,
75-
LogLevel::DEBUG => ConsoleLogger::ERROR,
76-
];
77-
78-
private const LOG_VERBOSITY_MAPPING = [
79-
LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL,
80-
];
81-
8270
/**
8371
* @throws SymfonyInvalidArgumentException
8472
*/
@@ -194,6 +182,7 @@ protected function configure(): void
194182
* @throws InvalidArgumentException
195183
* @throws ImproperContextException
196184
* @throws LogicException
185+
* @throws CollectionMismatchException
197186
*/
198187
protected function execute(InputInterface $input, OutputInterface $output): int
199188
{
@@ -204,7 +193,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
204193

205194
$extractor = new MessageExtractor(
206195
$options,
207-
new ConsoleLogger($output, self::LOG_VERBOSITY_MAPPING, self::LOG_FORMAT_MAPPING),
196+
$this->getConsoleLogger($output),
208197
new Globber($fileSystemHelper),
209198
$fileSystemHelper,
210199
new FormatHelper($fileSystemHelper),
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
/**
4+
* This file is part of skillshare/formatphp
5+
*
6+
* skillshare/formatphp is open source software: you can distribute
7+
* it and/or modify it under the terms of the MIT License
8+
* (the "License"). You may not use this file except in
9+
* compliance with the License.
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14+
* implied. See the License for the specific language governing
15+
* permissions and limitations under the License.
16+
*
17+
* @copyright Copyright (c) Skillshare, Inc. <https://www.skillshare.com>
18+
* @license https://opensource.org/licenses/MIT MIT License
19+
*/
20+
21+
declare(strict_types=1);
22+
23+
namespace FormatPHP\Console\Command;
24+
25+
use FormatPHP\Exception;
26+
use FormatPHP\PseudoLocale\Converter;
27+
use FormatPHP\PseudoLocale\ConverterOptions;
28+
use FormatPHP\PseudoLocale\PseudoLocale;
29+
use FormatPHP\Util\FileSystemHelper;
30+
use FormatPHP\Util\FormatHelper;
31+
use Symfony\Component\Console\Exception\InvalidArgumentException as SymfonyInvalidArgumentException;
32+
use Symfony\Component\Console\Input\InputArgument;
33+
use Symfony\Component\Console\Input\InputInterface;
34+
use Symfony\Component\Console\Input\InputOption;
35+
use Symfony\Component\Console\Output\OutputInterface;
36+
37+
use function implode;
38+
39+
use const PHP_EOL;
40+
41+
/**
42+
* Provides the `formatphp pseudo-locale` command
43+
*/
44+
class PseudoLocaleCommand extends AbstractCommand
45+
{
46+
/**
47+
* @throws SymfonyInvalidArgumentException
48+
*/
49+
protected function configure(): void
50+
{
51+
$this
52+
->setName('pseudo-locale')
53+
->setDescription('Convert a locale file into a pseudo locale, for testing')
54+
->addArgument(
55+
'file',
56+
InputArgument::REQUIRED,
57+
'The locale file to convert.',
58+
)
59+
->addArgument(
60+
'pseudo-locale',
61+
InputArgument::REQUIRED,
62+
'The pseudo-locale tag.' . PHP_EOL
63+
. 'One of: ' . implode(', ', PseudoLocale::LOCALES),
64+
)
65+
->addOption(
66+
'in-format',
67+
null,
68+
InputOption::VALUE_REQUIRED,
69+
'Formatter name or path to a formatter script that' . PHP_EOL
70+
. 'controls the shape of the JSON read from `file`.' . PHP_EOL
71+
. 'Defaults to "formatphp".',
72+
)
73+
->addOption(
74+
'out-format',
75+
null,
76+
InputOption::VALUE_REQUIRED,
77+
'Formatter name or path to a formatter script that' . PHP_EOL
78+
. 'controls the shape of the JSON produced as output.',
79+
)
80+
->addOption(
81+
'out-file',
82+
null,
83+
InputOption::VALUE_REQUIRED,
84+
'Target file path to save the JSON output.',
85+
);
86+
}
87+
88+
/**
89+
* @throws Exception\InvalidArgumentException
90+
* @throws Exception\UnableToWriteFileException
91+
* @throws Exception\UnableToProcessFileException
92+
* @throws Exception\ImproperContextException
93+
* @throws SymfonyInvalidArgumentException
94+
*/
95+
protected function execute(InputInterface $input, OutputInterface $output): int
96+
{
97+
/** @var string $file */
98+
$file = $input->getArgument('file');
99+
100+
/** @var string $pseudoLocale */
101+
$pseudoLocale = $input->getArgument('pseudo-locale');
102+
103+
$options = $this->buildOptions($input);
104+
$fileSystemHelper = new FileSystemHelper();
105+
106+
$converter = new Converter(
107+
$options,
108+
$fileSystemHelper,
109+
new FormatHelper($fileSystemHelper),
110+
$this->getConsoleLogger($output),
111+
);
112+
113+
$converter->convert($file, $pseudoLocale);
114+
115+
return self::SUCCESS;
116+
}
117+
118+
/**
119+
* @throws SymfonyInvalidArgumentException
120+
*/
121+
private function buildOptions(InputInterface $input): ConverterOptions
122+
{
123+
$options = new ConverterOptions();
124+
125+
/** @var string | null $inFormat */
126+
$inFormat = $input->getOption('in-format');
127+
$options->inFormat = $inFormat;
128+
129+
/** @var string | null $outFormat */
130+
$outFormat = $input->getOption('out-format');
131+
$options->outFormat = $outFormat;
132+
133+
/** @var string | null $outFile */
134+
$outFile = $input->getOption('out-file');
135+
$options->outFile = $outFile;
136+
137+
return $options;
138+
}
139+
}

src/Format/Format.php

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,9 @@
2525
/**
2626
* Constant values for formats
2727
*/
28-
final class Format
28+
class Format
2929
{
3030
public const FORMATPHP = 'formatphp';
3131
public const SIMPLE = 'simple';
3232
public const SMARTLING = 'smartling';
33-
34-
/**
35-
* Disallow instantiation of this class.
36-
*
37-
* @codeCoverageIgnore This is reported as uncovered in code coverage reports, so let's ignore it.
38-
*/
39-
private function __construct()
40-
{
41-
}
4233
}

src/MessageLoader.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
/**
4242
* Loads messages for a given locale from the file system or cache
4343
*/
44-
final class MessageLoader
44+
class MessageLoader
4545
{
4646
private ConfigInterface $config;
4747
private FileSystemHelper $fileSystemHelper;

0 commit comments

Comments
 (0)