diff options
| author | 2025-07-16 16:11:51 +0200 | |
|---|---|---|
| committer | 2025-07-16 16:11:51 +0200 | |
| commit | f9a42adadec9acd259c205727c95bd6f376dfbc5 (patch) | |
| tree | b576ba4ac948466389de30487c506ae04dd71d24 /cli | |
| parent | 5f61e426dc90b7b697a46da009af2fc88eed3ad0 (diff) | |
Show translation status in README.md (#7715)
* Show translation status in README.md
* Fix colon
* markdownlint: Allow tag `<translations>`
* Use mostly Unicode flags instead
* Only `oc.svg` remains in an image format
* `check.translation.php` still supports `.png` even though there aren't any PNGs as of right now
* Fix CodeSniffer
* Attempt approach with generating local SVGs
* Fixes for local SVG approach
* Cleanup old code
* PHPStan fix
* Remove decimal precision from percentages
* Suggestions + better error messages
* codesniffer fix v2
* Revert `ghSearchUrl` change
* Generate readme
* Fix syntax highlight, maybe
* Regenerate
* Update help message
* Use existing translation files instead of .txt
* Add test against wrong Unicode flag
---------
Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
Diffstat (limited to 'cli')
| -rw-r--r-- | cli/README.md | 3 | ||||
| -rwxr-xr-x | cli/check.translation.php | 113 | ||||
| -rw-r--r-- | cli/i18n/I18nCompletionValidator.php | 8 | ||||
| -rw-r--r-- | cli/i18n/I18nUsageValidator.php | 5 | ||||
| -rw-r--r-- | cli/i18n/I18nValidatorInterface.php | 2 |
5 files changed, 126 insertions, 5 deletions
diff --git a/cli/README.md b/cli/README.md index 155c8938b..4d6ba62fe 100644 --- a/cli/README.md +++ b/cli/README.md @@ -149,12 +149,13 @@ cd /usr/share/FreshRSS # -r, --revert revert the action (only used with ignore action). # -o, --origin-language selects the origin language (only used with add language action). -./cli/check-translation.php [ ---display-result --help --language fr --display-report ] +./cli/check-translation.php [ ---display-result --help --language fr --display-report --generate-readme ] # Check if translation files have missing keys or missing translations. # -d, --display-result display results of check. # -h, --help display help text and exit. # -l, --language set the language check. # -r, --display-report display completion report. +# -g, --generate-readme generate readme for translation status. ``` ## Note about cron diff --git a/cli/check.translation.php b/cli/check.translation.php index ebe665ef7..151a6084f 100755 --- a/cli/check.translation.php +++ b/cli/check.translation.php @@ -14,12 +14,14 @@ $cliOptions = new class extends CliOptionsParser { public bool $displayResult; public bool $help; public bool $displayReport; + public bool $generateReadme; public function __construct() { $this->addOption('language', (new CliOption('language', 'l'))->typeOfArrayOfString()); $this->addOption('displayResult', (new CliOption('display-result', 'd'))->withValueNone()); $this->addOption('help', (new CliOption('help', 'h'))->withValueNone()); $this->addOption('displayReport', (new CliOption('display-report', 'r'))->withValueNone()); + $this->addOption('generateReadme', (new CliOption('generate-readme', 'g'))->withValueNone()); parent::__construct(); } }; @@ -43,6 +45,7 @@ if (isset($cliOptions->language)) { $isValidated = true; $result = []; $report = []; +$percentage = []; foreach ($languages as $language) { if ($language === $i18nData::REFERENCE_LANGUAGE) { @@ -53,6 +56,7 @@ foreach ($languages as $language) { $isValidated = $i18nValidator->validate() && $isValidated; $report[$language] = sprintf('%-5s - %s', $language, $i18nValidator->displayReport()); + $percentage[$language] = $i18nValidator->displayReport(percentage_only: true); $result[$language] = $i18nValidator->displayResult(); } @@ -70,6 +74,114 @@ if ($cliOptions->displayReport) { } } +function writeToReadme(string $readmePath, string $markdownImgStr): void { + $readme = file_get_contents($readmePath); + if ($readme === false) { + echo 'Error: Unable to open ' . $readmePath, PHP_EOL; + exit(1); + } + if (file_put_contents($readmePath, preg_replace('/<translations>(.*?)<\/translations>/s', <<<EOF + <translations> + <!-- This section is automatically generated by `cli/check.translation.php -g` --> + + $markdownImgStr + + </translations> + EOF, $readme)) === false) { + echo 'Error: Fail while writing to ' . $readmePath, PHP_EOL; + exit(1); + } + echo 'Successfully written translation status into ' . $readmePath, PHP_EOL; +} + +function embedSvg(string $contents): string { + return preg_replace( + '/<svg\s+(?:(?:[^>]*?)(xmlns=["\'][^"\']+["\']))?(?:(?:[^>]*?)(viewBox=["\'][^"\']+["\']))?(?:[^>]*?)>/i', + '<svg \1 \2 width="16" height="16" x="9" y="2">', + $contents + ) ?? ''; +} + +if ($cliOptions->generateReadme) { + $supportedFormats = ['txt', 'svg']; + $flagsDir = __DIR__ . '/../docs/i18n/flags'; + + $markdownImgStr = ''; + foreach ($percentage as $lang => $value) { + $percentageInt = intval(rtrim($value, '%')); + $color = 'green'; + if ($percentageInt < 90) { + $color = 'gold'; + } + if ($percentageInt < 70) { + $color = 'darkred'; + } + $svgFile = $flagsDir . '/' . $lang . '.svg'; + $svg = ''; + if (file_exists($svgFile)) { + $svg = file_get_contents($svgFile); + if ($svg === false) { + echo 'Error: Unable to open ' . $svgFile, PHP_EOL; + exit(1); + } + } + + $ghSearchUrl = 'https://github.com/search?q=' . urlencode("repo:FreshRSS/FreshRSS path:app/i18n/$lang /(TODO|DIRTY)$/"); + $genPath = $flagsDir . '/gen/' . $lang . '.svg'; + $template = '<!-- This file is automatically generated by `cli/check.translation.php -g` -->' . "\n"; + + if ($svg === '') { + $i18nGen = include __DIR__ . "/../app/i18n/$lang/gen.php"; + if (!is_array($i18nGen) || !is_string($i18nGen['flag'] ?? null)) { + echo 'Error: No Unicode flag found for language ' . $lang, PHP_EOL; + exit(1); + } + $unicodeFlag = $i18nGen['flag']; + if ($lang !== 'en' && $unicodeFlag === '🇬🇧') { + echo 'Error: Wrong Unicode flag for language ' . $lang, PHP_EOL; + exit(1); + } + $value = $unicodeFlag . ' ' . $percentageInt . '%'; + $template .= <<<EOF + <svg xmlns="http://www.w3.org/2000/svg" width="70" height="20"> + <g fill="white" font-size="12" font-family="Verdana" text-anchor="middle"> + <rect rx="3" width="70" height="20" fill="$color" /> + <text x="34" y="14">$value</text> + </g> + </svg> + EOF; + } else { + // An SVG file is available to override the Unicode flag + $value = $percentageInt . '%'; + $contents = embedSvg($svg); + $template .= <<<EOF + <svg xmlns="http://www.w3.org/2000/svg" width="70" height="20"> + <g fill="white" font-size="12" font-family="Verdana" text-anchor="middle"> + <rect rx="3" width="70" height="20" fill="$color" /> + <!-- embedded SVG --> + $contents + <!-- end of embedded SVG --> + <text x="43" y="14">$value</text> + </g> + </svg> + EOF; + } + if (file_put_contents($genPath, $template) === false) { + echo 'Error: Fail while writing to ' . $genPath, PHP_EOL; + exit(1); + } + $markdownImgStr .= "[]($ghSearchUrl) "; + } + // In case we're located in ./cli/ + if (!file_exists('constants.php')) { + chdir('..'); + } + foreach (array_merge(['README.md'], glob('README.*.md') ?: []) as $readmePath) { + writeToReadme($readmePath, rtrim($markdownImgStr)); + } + exit(); +} + if (!$isValidated) { exit(1); } @@ -121,6 +233,7 @@ DESCRIPTION -h, --help display this help and exit. -l, --language=LANG filter by LANG. -r, --display-report display completion report. + -g, --generate-readme generate readme for translation status. HELP; exit(); diff --git a/cli/i18n/I18nCompletionValidator.php b/cli/i18n/I18nCompletionValidator.php index 28f8abed8..5cdd1ba80 100644 --- a/cli/i18n/I18nCompletionValidator.php +++ b/cli/i18n/I18nCompletionValidator.php @@ -20,14 +20,18 @@ class I18nCompletionValidator implements I18nValidatorInterface { } #[\Override] - public function displayReport(): string { + public function displayReport(bool $percentage_only = false): string { if ($this->passEntries > $this->totalEntries) { throw new \RuntimeException('The number of translated strings cannot be higher than the number of strings'); } if ($this->totalEntries === 0) { return 'There is no data.' . PHP_EOL; } - return sprintf('Translation is %5.1f%% complete.', $this->passEntries / $this->totalEntries * 100) . PHP_EOL; + $percentage = sprintf('%5.1f%%', $this->passEntries / $this->totalEntries * 100); + if ($percentage_only) { + return trim($percentage); + } + return 'Translation is ' . $percentage . ' complete.' . PHP_EOL; } #[\Override] diff --git a/cli/i18n/I18nUsageValidator.php b/cli/i18n/I18nUsageValidator.php index 89c88d222..5551d2df7 100644 --- a/cli/i18n/I18nUsageValidator.php +++ b/cli/i18n/I18nUsageValidator.php @@ -20,13 +20,16 @@ class I18nUsageValidator implements I18nValidatorInterface { } #[\Override] - public function displayReport(): string { + public function displayReport(bool $percentage_only = false): string { if ($this->failedEntries > $this->totalEntries) { throw new \RuntimeException('The number of unused strings cannot be higher than the number of strings'); } if ($this->totalEntries === 0) { return 'There is no data.' . PHP_EOL; } + if ($percentage_only) { + return '100%'; + } return sprintf('%5.1f%% of translation keys are unused.', $this->failedEntries / $this->totalEntries * 100) . PHP_EOL; } diff --git a/cli/i18n/I18nValidatorInterface.php b/cli/i18n/I18nValidatorInterface.php index 9266489f6..8c58f84cb 100644 --- a/cli/i18n/I18nValidatorInterface.php +++ b/cli/i18n/I18nValidatorInterface.php @@ -14,6 +14,6 @@ interface I18nValidatorInterface { /** * Display the validation report. */ - public function displayReport(): string; + public function displayReport(bool $percentage_only = false): string; } |
