Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ projects installed. It also runs on `composer require` command.
You can manually download the localization files according to your configuration
by using `composer drupal:l10n`.

If you only need Drupal core translations (for example so Drush can detect and
install languages), use:

`composer drupal:l10n --core-only`

## Configuration

You can configure the plugin by providing some settings in the `extra` section
Expand All @@ -35,6 +40,7 @@ of your root `composer.json`.
"extra": {
"drupal-l10n": {
"destination": "translations/contrib",
"core-only": true,
"languages": [
"fr",
"es"
Expand All @@ -50,6 +56,9 @@ translation files. By default the destination is

The `languages` parameter specify the languages you want to retrieve.

The `core-only` parameter (default `false`) limits downloads to Drupal core
translations only, and skips contrib modules/themes/profiles.

## Drupal configuration

You can say to Drupal to not download translations files by updating your
Expand Down
3 changes: 2 additions & 1 deletion src/DrupalL10nCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ protected function configure() {
->setDescription('Download Drupal translations files.')
->setDefinition([
new InputOption('no-dev', NULL, InputOption::VALUE_NONE, 'Disables download of translations of require-dev dependencies.'),
new InputOption('core-only', NULL, InputOption::VALUE_NONE, 'Downloads translations for Drupal core only (skip contrib modules/themes/profiles).'),
]);
}

Expand All @@ -32,7 +33,7 @@ protected function configure() {
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$handler = new Handler($this->getComposer(), $this->getIO());
$handler->downloadLocalization(!$input->getOption('no-dev'));
$handler->downloadLocalization(!$input->getOption('no-dev'), [], $input->getOption('core-only'));
return 0;
}

Expand Down
24 changes: 20 additions & 4 deletions src/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ class Handler {
'drupal-theme',
'drupal-profile',
];
const DRUPAL_CORE_PACKAGE_NAMES = [
'drupal/core',
'drupal/drupal',
];

/**
* The composer object.
Expand Down Expand Up @@ -132,8 +136,11 @@ public function onPostCmdEvent(Event $event) {
* A list of Packages to download the localization. If empty, the
* localization for all Drupal packages detected in the installation will be
* downloaded.
* @param bool $coreOnly
* TRUE to download Drupal core localization only. FALSE to include contrib
* projects.
*/
public function downloadLocalization($dev = TRUE, array $packages = []) {
public function downloadLocalization($dev = TRUE, array $packages = [], $coreOnly = FALSE) {
$drupal_core_package = $this->getDrupalCorePackage();
// Ensure drupal core package is present.
if (is_null($drupal_core_package)) {
Expand All @@ -143,12 +150,23 @@ public function downloadLocalization($dev = TRUE, array $packages = []) {

$webroot = realpath($this->getWebRoot());

// Collect options.
$options = $this->getOptions();

// The command line option takes precedence, but the composer.json setting
// can enable this mode as well.
$coreOnly = $coreOnly || !empty($options['core-only']);

// Prepare a list of Drupal project to download the translations.
$drupal_projects = [];
if (empty($packages)) {
$packages = $this->composer->getRepositoryManager()->getLocalRepository()->getPackages();
}
foreach ($packages as $package) {
if ($coreOnly && !in_array($package->getName(), self::DRUPAL_CORE_PACKAGE_NAMES)) {
continue;
}

// Filter by the type of package.
if (in_array($package->getType(), $this::DRUPAL_L10N_PACKAGE_TYPES)) {
// Include development project or not.
Expand All @@ -170,9 +188,6 @@ public function downloadLocalization($dev = TRUE, array $packages = []) {
// Get the Drupal core version.
$core_version = $this->getDrupalCoreVersion($drupal_core_package);

// Collect options.
$options = $this->getOptions();

$httpDownloader = new HttpDownloader($this->io, $this->composer->getConfig());

$fetcher = new FileFetcher($this->io, $httpDownloader, $options, $core_version, $this->progress);
Expand Down Expand Up @@ -301,6 +316,7 @@ protected function getOptions() {
$options = $extra['drupal-l10n'] + [
'destination' => 'sites/default/files/translations',
'languages' => [],
'core-only' => FALSE,
];
return $options;
}
Expand Down
67 changes: 65 additions & 2 deletions tests/PluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,66 @@ public function testContribmodules() {
$this->assertFileExists($semver_fr_translation_file, 'French translations file should exist.');
}

/**
* Tests that core-only option skips contrib translations.
*/
public function testCoreOnlyOption() {
$core_version = '9.5.3';
$contrib_module = 'entity_share';
$contrib_composer_version = '3.0.0-rc4';
$contrib_drupal_version = '8.x-3.0-rc4';
$translations_directory = $this->tmpDir . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR . 'contrib';
$core_translation_file = $translations_directory . DIRECTORY_SEPARATOR . 'drupal-' . $core_version . '.fr.po';
$contrib_translation_file = $translations_directory . DIRECTORY_SEPARATOR . $contrib_module . '-' . $contrib_drupal_version . '.fr.po';

$this->composer('install');
$this->composer('require --update-with-dependencies drupal/core:"' . $core_version . '"');
$this->composer('require drupal/' . $contrib_module . ':"' . $contrib_composer_version . '"');
$this->assertFileExists($core_translation_file, 'Drupal core translation should exist after install.');
$this->assertFileExists($contrib_translation_file, 'Contrib translation should exist after install.');

$this->fs->remove($core_translation_file);
$this->fs->remove($contrib_translation_file);
$this->assertFileDoesNotExist($core_translation_file, 'Drupal core translation should not exist after removal.');
$this->assertFileDoesNotExist($contrib_translation_file, 'Contrib translation should not exist after removal.');

$this->composer('drupal:l10n --core-only');
$this->assertFileExists($core_translation_file, 'Drupal core translation should exist after --core-only command.');
$this->assertFileDoesNotExist($contrib_translation_file, 'Contrib translation should not exist after --core-only command.');
}

/**
* Tests that core-only option from composer.json skips contrib translations.
*/
public function testCoreOnlyOptionFromComposerJson() {
$composer_json = $this->composerJsonDefaults();
$composer_json['extra']['drupal-l10n']['core-only'] = TRUE;
$this->writeComposerJson($composer_json);

$core_version = '9.5.3';
$contrib_module = 'entity_share';
$contrib_composer_version = '3.0.0-rc4';
$contrib_drupal_version = '8.x-3.0-rc4';
$translations_directory = $this->tmpDir . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR . 'contrib';
$core_translation_file = $translations_directory . DIRECTORY_SEPARATOR . 'drupal-' . $core_version . '.fr.po';
$contrib_translation_file = $translations_directory . DIRECTORY_SEPARATOR . $contrib_module . '-' . $contrib_drupal_version . '.fr.po';

$this->composer('install');
$this->composer('require --update-with-dependencies drupal/core:"' . $core_version . '"');
$this->composer('require drupal/' . $contrib_module . ':"' . $contrib_composer_version . '"');
// With core-only set in composer.json, hooks already skip contrib.
$this->assertFileExists($core_translation_file, 'Drupal core translation should exist after install.');
$this->assertFileDoesNotExist($contrib_translation_file, 'Contrib translation should not exist when core-only is set.');

// Remove core translation to verify drupal:l10n also honours the setting.
$this->fs->remove($core_translation_file);
$this->assertFileDoesNotExist($core_translation_file, 'Drupal core translation should not exist after removal.');

$this->composer('drupal:l10n');
$this->assertFileExists($core_translation_file, 'Drupal core translation should exist after composer.json core-only mode.');
$this->assertFileDoesNotExist($contrib_translation_file, 'Contrib translation should not exist after composer.json core-only mode.');
}

/**
* Tests that on Drupal 7, core and contrib modules are handled.
*/
Expand Down Expand Up @@ -191,8 +251,11 @@ public function testDrupal10() {
/**
* Writes the default composer json to the temp directory.
*/
protected function writeComposerJson() {
$json = json_encode($this->composerJsonDefaults(), JSON_PRETTY_PRINT);
protected function writeComposerJson(array $composer_json = NULL) {
if (is_null($composer_json)) {
$composer_json = $this->composerJsonDefaults();
}
$json = json_encode($composer_json, JSON_PRETTY_PRINT);
// Write composer.json.
file_put_contents($this->tmpDir . '/composer.json', $json);
}
Expand Down
Loading