diff --git a/Classes/Controller/ReadabilityController.php b/Classes/Controller/ReadabilityController.php new file mode 100644 index 0000000..702dcfb --- /dev/null +++ b/Classes/Controller/ReadabilityController.php @@ -0,0 +1,25 @@ +getParsedBody(); + $readabilityCalculator = $this->factory->fromLanguage($data['language']); + $readabilityResult = $readabilityCalculator->calculateReadability(strip_tags($data['text'] ?? '')); + return new JsonResponse($readabilityResult->jsonSerialize()); + } +} diff --git a/Classes/Readability/Calculator/AbstractReadabilityCalculator.php b/Classes/Readability/Calculator/AbstractReadabilityCalculator.php new file mode 100644 index 0000000..7860566 --- /dev/null +++ b/Classes/Readability/Calculator/AbstractReadabilityCalculator.php @@ -0,0 +1,48 @@ +getOptions()->setHyphen('|'); + $result = $hyphenator->hyphenate($text); + $splitted = preg_split(self::HYPHENATED_SPLIT, $result); + return count($splitted); + } + + protected function countCharacters(string $text): int + { + return mb_strlen($text); + } + + public function getLanguage(): string + { + return static::LANGUAGE; + } +} diff --git a/Classes/Readability/Calculator/FleschKincaidEnglish.php b/Classes/Readability/Calculator/FleschKincaidEnglish.php new file mode 100644 index 0000000..cf60d24 --- /dev/null +++ b/Classes/Readability/Calculator/FleschKincaidEnglish.php @@ -0,0 +1,68 @@ +countSentences($text); + $words = $this->countWords($text); + $syllables = $this->countSyllables($text); + $characters = $this->countCharacters($text); + return new ReadabilityResult( + $text, + $sentences, + $words, + $syllables, + $characters, + $this->calculateScore($words, $sentences, $syllables) + ); + } + + private function calculateScore( + int $words, + int $sentences, + int $syllables + ): float { + if ($sentences <= 0) { + $sentences = 1; + } + if ($words <= 0) { + throw new \InvalidArgumentException( + 'The number of words can not be negative or zero!', + 1757680362 + ); + } + + // Too easy sentences and short texts COULD result in calculating a value above 100. In this case + // set the result to 100, as this is the maximum. + // This is a known issue in this formula, but can be ignored for a quick overview, as + // 100 means very easy to read. + $fleschKincaid = 206.835 - 1.015 * ($words/$sentences) - (84.6 * $syllables/$words); + return ($fleschKincaid <= 100.0) ? $fleschKincaid : 100.0; + } +} diff --git a/Classes/Readability/Calculator/FleschKincaidGerman.php b/Classes/Readability/Calculator/FleschKincaidGerman.php new file mode 100644 index 0000000..71ce417 --- /dev/null +++ b/Classes/Readability/Calculator/FleschKincaidGerman.php @@ -0,0 +1,65 @@ +countSentences($text); + $words = $this->countWords($text); + $syllables = $this->countSyllables($text); + $characters = $this->countCharacters($text); + return new ReadabilityResult( + $text, + $sentences, + $words, + $syllables, + $characters, + $this->calculateScore($words, $sentences, $syllables) + ); + } + + private function calculateScore( + int $words, + int $sentences, + int $syllables + ): float { + if ($sentences <= 0) { + $sentences = 1; + } + if ($words <= 0) { + throw new \InvalidArgumentException( + 'The number of words can not be negative or zero!', + 1757679534 + ); + } + return 180 - ($words/$sentences) - (58.5 * $syllables/$words); + } +} diff --git a/Classes/Readability/ReadabilityCalculatorFactory.php b/Classes/Readability/ReadabilityCalculatorFactory.php new file mode 100644 index 0000000..534b416 --- /dev/null +++ b/Classes/Readability/ReadabilityCalculatorFactory.php @@ -0,0 +1,17 @@ +registry->findByLanguage($language); + } +} diff --git a/Classes/Readability/ReadabilityCalculatorInterface.php b/Classes/Readability/ReadabilityCalculatorInterface.php new file mode 100644 index 0000000..e7e7b90 --- /dev/null +++ b/Classes/Readability/ReadabilityCalculatorInterface.php @@ -0,0 +1,13 @@ + + */ + private array $services; + public function __construct(iterable $calculators) + { + foreach ($calculators as $calculator) { + $this->services[] = $calculator; + } + } + + public function findByLanguage(string $language): ReadabilityCalculatorInterface + { + foreach ($this->services as $service) { + if ($service->getLanguage() === $language) { + return $service; + } + } + throw new \InvalidArgumentException( + sprintf('No service found for langauge "%s"', $language), + 1757686580 + ); + } +} diff --git a/Classes/Readability/ReadabilityCalculatorRegistryInterface.php b/Classes/Readability/ReadabilityCalculatorRegistryInterface.php new file mode 100644 index 0000000..99a69b2 --- /dev/null +++ b/Classes/Readability/ReadabilityCalculatorRegistryInterface.php @@ -0,0 +1,10 @@ +words/$this->sentences, 2); + } + + public function getAverageSyllablesPerWord(): float + { + return round($this->syllables/$this->words, 2); + } + + public function jsonSerialize(): array + { + return [ + 'sentences' => $this->sentences, + 'words' => $this->words, + 'syllables' => $this->syllables, + 'characters' => $this->characters, + 'avgSyllables' => $this->getAverageSyllablesPerWord(), + 'avgWords' => $this->getAverageWordsPerSentence(), + 'score' => $this->score, + ]; + } +} diff --git a/Classes/Service/ReadingEaseService.php b/Classes/Service/ReadingEaseService.php new file mode 100644 index 0000000..9f73496 --- /dev/null +++ b/Classes/Service/ReadingEaseService.php @@ -0,0 +1,10 @@ + [ @@ -18,4 +19,9 @@ 'target' => CkEditorController::class . '::getEditMaskAction', 'methods' => ['GET'], ], + 'deeplwrite_readability' => [ + 'path' => '/deepl-write/readability/calculate', + 'target' => ReadabilityController::class . '::calculate', + 'methods' => ['post'], + ], ]; diff --git a/Configuration/Services.php b/Configuration/Services.php new file mode 100644 index 0000000..556c2c3 --- /dev/null +++ b/Configuration/Services.php @@ -0,0 +1,13 @@ +registerForAutoconfiguration(ReadabilityCalculatorInterface::class)->addTag('deepl.readability'); +}; diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index be5b1f0..04625c5 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -12,6 +12,8 @@ services: WebVision\DeeplWrite\Controller\CkEditorController: public: true + WebVision\DeeplWrite\Controller\ReadabilityController: + public: true WebVision\DeeplWrite\Configuration\ConfigurationInterface: class: WebVision\DeeplWrite\Configuration\Configuration @@ -36,3 +38,14 @@ services: identifier: 'deepl-write/translation-dropdown' event: WebVision\Deepl\Base\Event\ViewHelpers\ModifyInjectVariablesViewHelperEvent after: 'deepl-base/default-translation, deepltranslate-core/translation-dropdown' + + WebVision\DeeplWrite\Readability\Calculator\FleschKincaidEnglish: + tags: + - name: deepl.readability + WebVision\DeeplWrite\Readability\Calculator\FleschKincaidGerman: + tags: + - name: deepl.readability + + WebVision\DeeplWrite\Readability\ReadabilityCalculatorRegistry: + arguments: + - !tagged_iterator deepl.readability diff --git a/README.md b/README.md index 6020203..3dd5b25 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,28 @@ configured for both extension in their respective extension configuration. > api key is required for this extension, which can also be used for the > `deepltranslate-core` or using there a free key. +### RTE Styling implementation + +A styling implementation is added to improve your writing directly inside your +RTE. This needs some adjustments to your RTE configuration: + +```yaml +editor: + config: + importModules: + # your already existing modules + - { module: '@web-vision/deepl-write/deeplwrite-plugin.js', exports: [ 'Deeplwrite' ] } + toolbar: + items: + # Your existing configuration + - '|' + - deeplwrite +``` + +This adds a button to the RTE controls, which allows you to use the overlay for +the writing style. The button is shown disabled, if your API key is not allowed +using the DeepL Write API or no API key is set. + ## Sponsors We appreciate very much the sponsorships of the developments and features in diff --git a/Resources/Private/Backend/Templates/CkEditor/Edit.html b/Resources/Private/Backend/Templates/CkEditor/Edit.html index 367031f..af86494 100644 --- a/Resources/Private/Backend/Templates/CkEditor/Edit.html +++ b/Resources/Private/Backend/Templates/CkEditor/Edit.html @@ -4,6 +4,67 @@ xmlns:deeplWrite="http://typo3.org/ns/WebVision/DeeplWrite/ViewHelpers" data-namespace-typo3-fluid="true" > +
@@ -88,12 +149,24 @@