protected function execute(InputInterface $input, OutputInterface $output) { $container = $this->getContainer(); $filesystem = new Filesystem(); $bundleAlias = $input->getArgument("bundle"); $bundlePath = $container->get("agit.common.filecollector")->resolve($bundleAlias); $defaultLocale = $container->get("agit.intl.locale")->getDefaultLocale(); $locales = $input->getArgument("locales") ? array_map("trim", explode(",", $input->getArgument("locales"))) : $container->getParameter("agit.intl.locales"); $globalCatalogPath = $container->getParameter("kernel.root_dir") . "/{$this->catalogSubdir}"; $this->cacheBasePath = sprintf("%s/agit.intl.temp/%s", sys_get_temp_dir(), $bundleAlias); $filesystem->mkdir($this->cacheBasePath); $finder = (new Finder())->in("{$bundlePath}")->name("*\\.php")->name("*\\.js")->notPath("/test.*/i")->notPath("public/js/ext"); $files = []; foreach ($finder as $file) { $filePath = $file->getRealpath(); $alias = str_replace($bundlePath, "@{$bundleAlias}/", $filePath); $files[$filePath] = $alias; } $this->getContainer()->get("event_dispatcher")->dispatch("agit.intl.bundle.files", new BundleTranslationFilesEvent($this, $bundleAlias, $this->cacheBasePath)); $this->extraTranslations = new Translations(); $this->getContainer()->get("event_dispatcher")->dispatch("agit.intl.bundle.translations", new BundleTranslationsEvent($this, $bundleAlias)); $files += $this->extraSourceFiles; $frontendFiles = array_filter(array_keys($files), function ($file) { return preg_match("|\\.js\$|", $file); }); $backendFiles = array_filter(array_keys($files), function ($file) { return !preg_match("|\\.js\$|", $file); }); $frontendCatalogs = ""; foreach ($locales as $locale) { if (!preg_match("|^[a-z]{2}_[A-Z]{2}|", $locale)) { throw new Exception("Invalid locale: {$locale}"); } // we use the global catalog as source for already translated strings $globalCatalogFile = "{$globalCatalogPath}/{$locale}/LC_MESSAGES/agit.po"; $globalCatalog = $filesystem->exists($globalCatalogFile) ? $this->deleteReferences(Translations::fromPoFile($globalCatalogFile)) : new Translations(); $bundleCatalogFile = "{$bundlePath}/{$this->catalogSubdir}/bundle.{$locale}.po"; $oldBundleCatalog = $filesystem->exists($bundleCatalogFile) ? $this->deleteReferences(Translations::fromPoFile($bundleCatalogFile)) : new Translations(); // NOTE: we delete all headers and only set language, in order to avoid garbage commits $bundleCatalog = new Translations(); $bundleCatalog->deleteHeaders(); $bundleCatalog->setLanguage($locale); // first: only JS messages foreach ($frontendFiles as $file) { $bundleCatalog->addFromJsCodeFile($file, $this->extractorOptions); } $bundleCatalog->mergeWith($oldBundleCatalog, 0); $bundleCatalog->mergeWith($globalCatalog, 0); if ($bundleCatalog->count() && $locale !== $defaultLocale) { $transMap = []; foreach ($bundleCatalog as $entry) { $msgid = ltrim($entry->getId(), ""); $msgstr = $entry->getTranslation(); $transMap[$msgid] = $entry->hasPlural() ? array_merge([$msgstr], $entry->getPluralTranslations()) : $msgstr; } $frontendCatalogs .= sprintf("ag.intl.register(\"%s\", %s);\n\n", $locale, json_encode($transMap, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } // now the same with all messages foreach ($backendFiles as $file) { $bundleCatalog->addFromPhpCodeFile($file, $this->extractorOptions); } $bundleCatalog->mergeWith($this->extraTranslations, Merge::ADD); $bundleCatalog->mergeWith($oldBundleCatalog, 0); $bundleCatalog->mergeWith($globalCatalog, 0); $catalog = $bundleCatalog->toPoString(); $catalog = str_replace(array_keys($files), array_values($files), $catalog); if ($bundleCatalog->count()) { $filesystem->dumpFile("{$bundlePath}/{$this->catalogSubdir}/bundle.{$locale}.po", $catalog); } } if ($frontendCatalogs) { $filesystem->dumpFile("{$bundlePath}/{$this->frontendSubdir}/translations.js", $frontendCatalogs); } $filesystem->remove($this->cacheBasePath); }