Switch to php-gettext 5.x:

- Don't use compiled PHP translations, switch back to gettext .mo compiled files
 - Bring npm easygettext back for JS parsing and generation
This commit is contained in:
Buster "Silver Eagle" Neece 2022-04-27 12:50:39 -05:00
parent f109600159
commit fec35a2432
No known key found for this signature in database
GPG Key ID: 9FC8B9E008872109
46 changed files with 7234 additions and 122660 deletions

View File

@ -74,14 +74,17 @@ jobs:
- name: Clear existing locales.
if: github.event_name == 'push' || github.event_name == 'schedule'
run: |
rm -rf resources/locale/compiled
rm -rf resources/locale/compiled_js
rm -rf resources/locale/*.UTF-8
mkdir -p resources/locale/compiled
- name: Generate new translations from existing code.
if: github.event_name == 'push' || github.event_name == 'schedule'
run: bin/console locale:generate
run: |
cd frontend
npm ci
npm run generate-locales
cd ..
bin/console locale:generate
- name: Pull latest translations.
if: github.event_name == 'push' || github.event_name == 'schedule'
@ -103,7 +106,7 @@ jobs:
bin/console locale:import
cd frontend
npm ci
npm run import-locales
npm run build
- name: Build OpenAPI Docs
@ -149,8 +152,7 @@ jobs:
name: assets
if-no-files-found: error
path: |
resources/locale/compiled
resources/locale/translations.json
resources/locale
web/static/dist
web/static/webpack_dist
web/static/webpack.json

View File

@ -46,5 +46,15 @@ frontend-bash:
frontend-build:
docker-compose -p azuracast_frontend -f frontend/docker-compose.yml build
docker-compose -p azuracast_frontend --env-file=.env -f frontend/docker-compose.yml run -e NODE_ENV=development --rm frontend npm run dev-build
docker-compose -p azuracast_frontend --env-file=.env -f frontend/docker-compose.yml run -e NODE_ENV=development --rm frontend npm run build
generate-locales:
docker-compose -p azuracast_frontend -f frontend/docker-compose.yml build
docker-compose -p azuracast_frontend --env-file=.env -f frontend/docker-compose.yml run -e NODE_ENV=development --rm frontend npm run generate-locales
docker-compose exec --user=azuracast web azuracast_cli locale:generate
import-locales:
docker-compose -p azuracast_frontend -f frontend/docker-compose.yml build
docker-compose -p azuracast_frontend --env-file=.env -f frontend/docker-compose.yml run -e NODE_ENV=development --rm frontend npm run import-locales
docker-compose exec --user=azuracast web azuracast_cli locale:import

View File

@ -40,7 +40,9 @@
"doctrine/migrations": "^3.0",
"doctrine/orm": "^2.6",
"dragonmantank/cron-expression": "^3.1",
"gettext/gettext": "^4.4",
"gettext/gettext": "^5",
"gettext/php-scanner": "^1.3",
"gettext/translator": "^1.1",
"guzzlehttp/guzzle": "^7.0",
"guzzlehttp/oauth-subscriber": "^0.6.0",
"http-interop/http-factory-guzzle": "^1.0",
@ -105,9 +107,6 @@
"symfony/polyfill-php80": "1.99",
"symfony/polyfill-php81": "1.99"
},
"conflict": {
"gettext/gettext": ">=5"
},
"require-dev": {
"codeception/codeception": "^5.0.0-RC1",
"codeception/module-asserts": "^3",

282
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "82acd00082268f9690add5cfab77425a",
"content-hash": "7c8e1da340da4f9fd035df272403daf9",
"packages": [
{
"name": "aws/aws-crt-php",
@ -2434,35 +2434,28 @@
},
{
"name": "gettext/gettext",
"version": "v4.8.6",
"version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/php-gettext/Gettext.git",
"reference": "bbeb8f4d3077663739aecb4551b22e720c0e9efe"
"reference": "017e249601d32b9a88c2eb4c10eac89bf582a7d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-gettext/Gettext/zipball/bbeb8f4d3077663739aecb4551b22e720c0e9efe",
"reference": "bbeb8f4d3077663739aecb4551b22e720c0e9efe",
"url": "https://api.github.com/repos/php-gettext/Gettext/zipball/017e249601d32b9a88c2eb4c10eac89bf582a7d3",
"reference": "017e249601d32b9a88c2eb4c10eac89bf582a7d3",
"shasum": ""
},
"require": {
"gettext/languages": "^2.3",
"php": ">=5.4.0"
"php": "^7.2|^8.0"
},
"require-dev": {
"illuminate/view": "^5.0.x-dev",
"phpunit/phpunit": "^4.8|^5.7|^6.5",
"squizlabs/php_codesniffer": "^3.0",
"symfony/yaml": "~2",
"twig/extensions": "*",
"twig/twig": "^1.31|^2.0"
},
"suggest": {
"illuminate/view": "Is necessary if you want to use the Blade extractor",
"symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator",
"twig/extensions": "Is necessary if you want to use the Twig extractor",
"twig/twig": "Is necessary if you want to use the Twig extractor"
"brick/varexporter": "^0.3.5",
"friendsofphp/php-cs-fixer": "^3.2",
"oscarotero/php-cs-fixer-config": "^2.0",
"phpunit/phpunit": "^8.0|^9.0",
"squizlabs/php_codesniffer": "^3.0"
},
"type": "library",
"autoload": {
@ -2483,7 +2476,7 @@
}
],
"description": "PHP gettext manager",
"homepage": "https://github.com/oscarotero/Gettext",
"homepage": "https://github.com/php-gettext/Gettext",
"keywords": [
"JS",
"gettext",
@ -2494,8 +2487,8 @@
],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/oscarotero/Gettext/issues",
"source": "https://github.com/php-gettext/Gettext/tree/v4.8.6"
"issues": "https://github.com/php-gettext/Gettext/issues",
"source": "https://github.com/php-gettext/Gettext/tree/v5.6.1"
},
"funding": [
{
@ -2511,7 +2504,7 @@
"type": "patreon"
}
],
"time": "2021-10-19T10:44:53+00:00"
"time": "2021-12-04T11:33:21+00:00"
},
{
"name": "gettext/languages",
@ -2587,6 +2580,139 @@
],
"time": "2021-11-11T17:30:39+00:00"
},
{
"name": "gettext/php-scanner",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/php-gettext/PHP-Scanner.git",
"reference": "989a2cffa1d0f43d13b14c83a50429119b5eb8e4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-gettext/PHP-Scanner/zipball/989a2cffa1d0f43d13b14c83a50429119b5eb8e4",
"reference": "989a2cffa1d0f43d13b14c83a50429119b5eb8e4",
"shasum": ""
},
"require": {
"gettext/gettext": "^5.5.0",
"nikic/php-parser": "^4.2",
"php": ">=7.2"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.15",
"oscarotero/php-cs-fixer-config": "^1.0",
"phpunit/phpunit": "^8.0",
"squizlabs/php_codesniffer": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Gettext\\Scanner\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oscar Otero",
"email": "oom@oscarotero.com",
"homepage": "http://oscarotero.com",
"role": "Developer"
}
],
"description": "PHP scanner for gettext",
"homepage": "https://github.com/php-gettext/PHP-Scanner",
"keywords": [
"gettext",
"i18n",
"php",
"scanner",
"translation"
],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/php-gettext/PHP-Scanner/issues",
"source": "https://github.com/php-gettext/PHP-Scanner/tree/v1.3.1"
},
"time": "2022-03-18T11:47:55+00:00"
},
{
"name": "gettext/translator",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/php-gettext/Translator.git",
"reference": "b18ff33e8203de623854561f5e47e992fc5c50bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-gettext/Translator/zipball/b18ff33e8203de623854561f5e47e992fc5c50bb",
"reference": "b18ff33e8203de623854561f5e47e992fc5c50bb",
"shasum": ""
},
"require": {
"php": "^7.2|^8.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.15",
"gettext/gettext": "^5.0.0",
"oscarotero/php-cs-fixer-config": "^1.0",
"phpunit/phpunit": "^8.0",
"squizlabs/php_codesniffer": "^3.0"
},
"suggest": {
"gettext/gettext": "Is necessary to load and generate array files used by the translator"
},
"type": "library",
"autoload": {
"psr-4": {
"Gettext\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Oscar Otero",
"email": "oom@oscarotero.com",
"homepage": "http://oscarotero.com",
"role": "Developer"
}
],
"description": "Gettext translator functions",
"homepage": "https://github.com/php-gettext/Translator",
"keywords": [
"gettext",
"i18n",
"php",
"translator"
],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/php-gettext/Translator/issues",
"source": "https://github.com/php-gettext/Translator/tree/v1.1.1"
},
"funding": [
{
"url": "https://paypal.me/oscarotero",
"type": "custom"
},
{
"url": "https://github.com/oscarotero",
"type": "github"
},
{
"url": "https://www.patreon.com/misteroom",
"type": "patreon"
}
],
"time": "2022-02-23T20:29:40+00:00"
},
{
"name": "graham-campbell/guzzle-factory",
"version": "v5.0.3",
@ -4633,6 +4759,62 @@
},
"time": "2018-02-13T20:26:39+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.13.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
},
"time": "2021-11-30T19:35:32+00:00"
},
{
"name": "pagerfanta/core",
"version": "v3.6.1",
@ -10955,62 +11137,6 @@
},
"time": "2022-01-20T13:18:17+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.13.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077",
"reference": "210577fe3cf7badcc5814d99455df46564f3c077",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=7.0"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
},
"bin": [
"bin/php-parse"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
}
},
"autoload": {
"psr-4": {
"PhpParser\\": "lib/PhpParser"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov"
}
],
"description": "A PHP parser written in PHP",
"keywords": [
"parser",
"php"
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2"
},
"time": "2021-11-30T19:35:32+00:00"
},
{
"name": "phar-io/manifest",
"version": "2.0.3",

View File

@ -16,6 +16,9 @@ RUN USER=node && \
mkdir -p /etc/fixuid && \
printf "user: $USER\ngroup: $GROUP\npaths:\n - /\n - /data/frontend/node_modules\n" > /etc/fixuid/config.yml
COPY ./entrypoint.sh /
RUN chmod a+x /entrypoint.sh
# Define working directory.
WORKDIR /data/frontend
@ -27,5 +30,5 @@ VOLUME /data/frontend/node_modules
ENV NODE_ENV=production
# Define default command.
ENTRYPOINT ["fixuid"]
CMD ["npm", "run", "dev"]
ENTRYPOINT ["/entrypoint.sh"]
CMD ["bash"]

8
frontend/entrypoint.sh Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
fixuid
cd /data/frontend
npm ci
exec "$@"

File diff suppressed because it is too large Load Diff

View File

@ -2,10 +2,10 @@
"name": "azuracast",
"license": "Apache-2.0",
"scripts": {
"dev": "npm ci && bash",
"dev-build": "npm ci && npm run build",
"build": "gulp",
"watch": "gulp watch"
"watch": "gulp watch",
"generate-locales": "gettext-extract --attribute v-translate --keywords '$gettext' --output ../resources/locale/frontend.pot $(find ./vue -type f -name '*.vue')",
"import-locales": "gettext-compile --output ../resources/locale/translations.json $(find ../resources/locale/*.UTF-8/LC_MESSAGES -type f -name 'default.po')"
},
"dependencies": {
"@babel/core": "^7.15.5",
@ -28,6 +28,7 @@
"codemirror": "^5.62.3",
"css-loader": "^6.5.0",
"del": "^6",
"easygettext": "^2.17.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-clean-css": "^4",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -6,6 +6,9 @@ namespace App\Console\Command\Locale;
use App\Console\Command\CommandAbstract;
use App\Environment;
use Gettext\Generator\PoGenerator;
use Gettext\Loader\PoLoader;
use Gettext\Scanner\PhpScanner;
use Gettext\Translations;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
@ -35,45 +38,45 @@ class GenerateCommand extends CommandAbstract
$exportDir = $this->environment->getBaseDirectory() . '/resources/locale';
$dest_file = $exportDir . '/default.pot';
$translations = Translations::create('default');
$destFile = $exportDir . '/default.pot';
$translations = new Translations();
// Import the JS-generated files if they exist
$frontendJsFile = $exportDir . '/frontend.pot';
// Find all JS/Vue file translations.
$directory = new RecursiveDirectoryIterator($this->environment->getBaseDirectory() . '/frontend/vue');
$iterator = new RecursiveIteratorIterator($directory);
$vueRegex = new RegexIterator($iterator, '/^.+\.(vue)$/i', RegexIterator::GET_MATCH);
foreach ($vueRegex as $pathMatch) {
$translations->addFromVueJsFile($pathMatch[0]);
}
$jsRegex = new RegexIterator($iterator, '/^.+\.(js)$/i', RegexIterator::GET_MATCH);
foreach ($jsRegex as $pathMatch) {
$translations->addFromJsCodeFile($pathMatch[0]);
if (is_file($frontendJsFile)) {
$translations = (new PoLoader())->loadFile($frontendJsFile, $translations);
@unlink($frontendJsFile);
}
// Find all PHP/PHTML files in the application's code.
$translatable_folders = [
$translatableFolders = [
$this->environment->getBaseDirectory() . '/src',
$this->environment->getBaseDirectory() . '/config',
$this->environment->getViewsDirectory(),
];
foreach ($translatable_folders as $folder) {
$phpScanner = new PhpScanner($translations);
$phpScanner->setDefaultDomain('default');
foreach ($translatableFolders as $folder) {
$directory = new RecursiveDirectoryIterator($folder);
$iterator = new RecursiveIteratorIterator($directory);
$regex = new RegexIterator($iterator, '/^.+\.(phtml|php)$/i', RegexIterator::GET_MATCH);
foreach ($regex as $path_match) {
$path = $path_match[0];
$translations->addFromPhpCodeFile($path);
$phpScanner->scanFile($path);
}
}
$translations->ksort();
@unlink($destFile);
$translations->toPoFile($dest_file);
$poGenerator = new PoGenerator();
$poGenerator->generateFile(
$translations,
$destFile
);
$io->success('Locales generated.');
return 0;

View File

@ -7,8 +7,8 @@ namespace App\Console\Command\Locale;
use App\Console\Command\CommandAbstract;
use App\Enums\SupportedLocales;
use App\Environment;
use Gettext\Translation;
use Gettext\Translations;
use Gettext\Generator\MoGenerator;
use Gettext\Loader\PoLoader;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
@ -32,58 +32,26 @@ class ImportCommand extends CommandAbstract
$io = new SymfonyStyle($input, $output);
$io->title('Import Locales');
$localeBase = $this->environment->getBaseDirectory() . '/resources/locale';
$jsTranslations = [];
$localesBase = $this->environment->getBaseDirectory() . '/resources/locale';
$supportedLocales = SupportedLocales::cases();
$defaultLocale = SupportedLocales::default();
$poLoader = new PoLoader();
$moGenerator = new MoGenerator();
foreach ($supportedLocales as $supportedLocale) {
if ($supportedLocale === $defaultLocale) {
continue;
}
$locale_source = $localeBase . '/' . $supportedLocale->value . '/LC_MESSAGES/default.po';
$localeFolder = $localesBase . '/' . $supportedLocale->value . '/LC_MESSAGES';
$localeSource = $localeFolder . '/default.po';
$localeDest = $localeFolder . '/default.mo';
if (is_file($locale_source)) {
$translations = Translations::fromPoFile($locale_source);
// Temporary inclusion of frontend translations
$frontendTranslations = $localeBase . '/' . $supportedLocale->value . '/LC_MESSAGES/frontend.po';
if (is_file($frontendTranslations)) {
$frontendTranslations = Translations::fromPoFile($frontendTranslations);
$translations->mergeWith($frontendTranslations);
}
$locale_dest = $localeBase . '/compiled/' . $supportedLocale->value . '.php';
$translations->toPhpArrayFile($locale_dest);
$localeJsKey = str_replace('.UTF-8', '', $supportedLocale->value);
/** @var Translation $translation */
foreach ($translations as $translation) {
if ($translation->isDisabled() || !$translation->hasTranslation()) {
continue;
}
if ($translation->hasPlural()) {
$string = [
$translation->getTranslation(),
];
$pluralStrings = $translation->getPluralTranslations();
if (count($pluralStrings) > 0) {
$string = array_merge($string, $pluralStrings);
}
} else {
$string = $translation->getTranslation();
}
$jsTranslations[$localeJsKey][$translation->getOriginal()] = $string;
}
ksort($jsTranslations[$localeJsKey]);
if (is_file($localeSource)) {
$translations = $poLoader->loadFile($localeSource);
$moGenerator->generateFile($translations, $localeDest);
$io->writeln(
__('Imported locale: %s', $supportedLocale->value . ' (' . $supportedLocale->getLocalName() . ')')
@ -91,14 +59,6 @@ class ImportCommand extends CommandAbstract
}
}
$jsTranslations = json_encode(
$jsTranslations,
JSON_THROW_ON_ERROR | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE
);
$jsTranslationsPath = $localeBase . '/translations.json';
file_put_contents($jsTranslationsPath, $jsTranslations);
$io->success('Locales imported.');
return 0;
}

View File

@ -8,7 +8,9 @@ namespace App\Enums;
use App\Environment;
use App\Http\ServerRequest;
use Gettext\Translator;
use Gettext\GettextTranslator;
use Gettext\TranslatorFunctions;
use Gettext\TranslatorInterface;
use Psr\Http\Message\ServerRequestInterface;
enum SupportedLocales: string
@ -62,24 +64,19 @@ enum SupportedLocales: string
return self::stripLocaleEncoding($this);
}
public function createTranslator(Environment $environment): Translator
public function createTranslator(Environment $environment): TranslatorInterface
{
$translator = new Translator();
$localeBase = $environment->getBaseDirectory() . '/resources/locale/compiled';
$localePath = $localeBase . '/' . $this->value . '.php';
if (file_exists($localePath)) {
$translator->loadTranslations($localePath);
}
$translator = new GettextTranslator();
$translator->setLanguage($this->value);
$translator->loadDomain('default', $environment->getBaseDirectory() . '/resources/locale');
return $translator;
}
public function register(Environment $environment): void
{
$translator = $this->createTranslator($environment);
$translator->register();
TranslatorFunctions::register($translator);
// Register translation superglobal functions
setlocale(LC_ALL, $this->value);

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Http;
use App\Entity;
use App\Enums\SupportedLocales;
use App\Environment;
use App\Exception;
use App\Exception\NotLoggedInException;
@ -13,7 +14,6 @@ use App\Middleware\InjectSession;
use App\Session\Flash;
use App\View;
use DI\FactoryInterface;
use Gettext\Translator;
use Monolog\Logger;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
@ -110,8 +110,8 @@ class ErrorHandler extends \Slim\Handlers\ErrorHandler
protected function respond(): ResponseInterface
{
if (!function_exists('__')) {
$translator = new Translator();
$translator->register();
$locale = SupportedLocales::default();
$locale->register($this->environment);
}
// Special handling for cURL requests.