diff --git a/config/install/graphql_compose.settings.yml b/config/install/graphql_compose.settings.yml index b133391ec2dfd49a02ddfe821fd29681fca659d4..16722c6b4781d7ab4ead1254aa812f154d8eafea 100644 --- a/config/install/graphql_compose.settings.yml +++ b/config/install/graphql_compose.settings.yml @@ -10,3 +10,4 @@ settings: site_front: true site_name: false site_slogan: false + inflector_langcode: 'en' diff --git a/config/schema/graphql_compose.schema.yml b/config/schema/graphql_compose.schema.yml index 4c44bd42675278c73d16ad097cb7611b05447c53..6a7f6f8a06bdb52ce976117c4402714efd785621 100644 --- a/config/schema/graphql_compose.schema.yml +++ b/config/schema/graphql_compose.schema.yml @@ -49,6 +49,9 @@ graphql_compose.settings: svg_filesize: type: integer label: 'Expose SVG filesize' + inflector_langcode: + type: string + label: 'Inflector language code' custom: type: sequence label: 'Custom settings' diff --git a/graphql_compose.services.yml b/graphql_compose.services.yml index d5cde11a2052198b6aecbe70e8d00879833a7c0e..84863ce493a8cc9c6e3d77a9e94a352315898f39 100644 --- a/graphql_compose.services.yml +++ b/graphql_compose.services.yml @@ -12,7 +12,7 @@ services: class: Drupal\graphql_compose\LanguageInflector arguments: - '@module_handler' - - '@language_manager' + - '@config.factory' # Cache bin for graphql_compose plugin definitions. cache.graphql_compose.definitions: @@ -20,7 +20,8 @@ services: tags: - { name: cache.bin } factory: cache_factory:get - arguments: [graphql_compose_definitions] + arguments: + - graphql_compose_definitions # Plugin manager for schema graphql_compose.schema_type_manager: diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php index 5be428b5e4aa1b60dbe80690231337bb95f6623e..0e74ff7a86a1bf344f3e2403477c495edabe927c 100644 --- a/src/Form/SettingsForm.php +++ b/src/Form/SettingsForm.php @@ -326,6 +326,23 @@ class SettingsForm extends ConfigFormBase { ]; } + $form['advanced']['inflector_langcode'] = [ + '#type' => 'select', + '#title' => $this->t('Inflector language'), + '#description' => $this->t('The language to use for inflection. Inflection will change the singularization and pluralization of schema types. Eg Tags -> Tag, Quizzes -> Quiz.'), + '#options' => [ + 'en' => $this->t('English'), + 'fr' => $this->t('French'), + 'nb' => $this->t('Norwegian Bokmal'), + 'pt-pt' => $this->t('Portuguese'), + 'pt-br' => $this->t('Portuguese (Brazil)'), + 'es' => $this->t('Spanish'), + 'tr' => $this->t('Turkish'), + ], + '#default_value' => $this->getConfig()->get('settings.inflector_langcode') ?: 'en', + '#required' => TRUE, + ]; + return parent::buildForm($form, $form_state); } @@ -504,6 +521,7 @@ class SettingsForm extends ConfigFormBase { ->set('settings.site_slogan', $form_state->getValue('site_slogan')) ->set('settings.svg_image', $form_state->getValue('svg_image', FALSE)) ->set('settings.svg_filesize', $form_state->getValue('svg_filesize', 100)) + ->set('settings.inflector_langcode', $form_state->getValue('inflector_langcode')) ->set('settings.custom', $custom_settings) ->save(); diff --git a/src/LanguageInflector.php b/src/LanguageInflector.php index 365fc856296565fbec99a21e971e39e24b542625..ae98441c58ef31607cf4116a6aa3c7b665466841 100644 --- a/src/LanguageInflector.php +++ b/src/LanguageInflector.php @@ -8,8 +8,14 @@ use Doctrine\Inflector\Inflector; use Doctrine\Inflector\InflectorFactory; use Doctrine\Inflector\Language; use Doctrine\Inflector\LanguageInflectorFactory; +use Doctrine\Inflector\Rules\Patterns; +use Doctrine\Inflector\Rules\Ruleset; +use Doctrine\Inflector\Rules\Substitution; +use Doctrine\Inflector\Rules\Substitutions; +use Doctrine\Inflector\Rules\Transformations; +use Doctrine\Inflector\Rules\Word; +use Drupal\Core\Config\ConfigFactoryInterface; use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Language\LanguageManagerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; /** @@ -31,12 +37,12 @@ class LanguageInflector { * * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler * Module handler service. - * @param \Drupal\Core\Language\LanguageManagerInterface $languageManager - * Language manager service. + * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory + * Config factory service. */ public function __construct( protected ModuleHandlerInterface $moduleHandler, - protected LanguageManagerInterface $languageManager + protected ConfigFactoryInterface $configFactory, ) { $this->inflector = $this->getInflectorFactory()->build(); } @@ -53,7 +59,22 @@ class LanguageInflector { * @see https://www.doctrine-project.org/projects/doctrine-inflector/en/2.0/index.html */ protected function getInflectorFactory(): LanguageInflectorFactory { - return InflectorFactory::createForLanguage($this->getInflectorLanguage()); + $factory = InflectorFactory::createForLanguage($this->getInflectorLanguage()); + + $factory->withSingularRules( + new Ruleset( + new Transformations(), + new Patterns(), + new Substitutions( + // Drupal'isms point to 'media' being used in a singular form. + // Eg getMediaType() not getMediumType(). + // Adding an underscore to the singular form bypasses the inflector. + new Substitution(new Word('media'), new Word('_media')) + ) + ), + ); + + return $factory; } /** @@ -65,7 +86,10 @@ class LanguageInflector { * The language name that works with doctrine inflector. */ protected function getInflectorLanguage(): string { - switch ($this->languageManager->getDefaultLanguage()->getId()) { + + $langcode = $this->configFactory->get('graphql_compose.settings')->get('settings.inflector_langcode'); + + switch ($langcode) { case 'fr': return Language::FRENCH; @@ -91,7 +115,7 @@ class LanguageInflector { * Returns the singular form of a string. * * @param string $original - * The bundle string to be singularized. + * The string to be singularized. * * @return string * Singular form of a string. @@ -101,6 +125,9 @@ class LanguageInflector { public function singularize(string $original): string { $singular = $this->inflector->singularize($original); + // Remove any leading slash added by inflector rule bypasses. + $singular = ltrim($singular, '_'); + $this->moduleHandler->invokeAll('graphql_compose_singularize_alter', [ $original, &$singular, @@ -112,20 +139,23 @@ class LanguageInflector { /** * Returns the plural forms of a string. * - * If the method can't determine the form with certainty, - * several possible plurals are returned. - * * @param string $singular * Singular form of a string. * * @return string - * Plural form(s) of a string. + * Plural form of a string. * * @see hook_graphql_compose_pluralize_alter() */ public function pluralize(string $singular): string { $plural = $this->inflector->pluralize($singular); + // If the plural is the same as the original, + // Failsafe pluralize. news... news_items. + if ($plural === $singular) { + $plural .= '_' . $this->t('items'); + } + $this->moduleHandler->invokeAll('graphql_compose_pluralize_alter', [ $singular, &$plural, diff --git a/src/Wrapper/EntityTypeWrapper.php b/src/Wrapper/EntityTypeWrapper.php index a3fa0091a22451cff42cba50357587a3d4c8b61a..c5e317613ac99e5552daa52f3dc222d84cc51431 100644 --- a/src/Wrapper/EntityTypeWrapper.php +++ b/src/Wrapper/EntityTypeWrapper.php @@ -129,10 +129,6 @@ class EntityTypeWrapper { $singular = $this->inflector->singularize($this->entity->id()); $plural = $this->inflector->pluralize($singular); - if ($plural === $singular) { - $plural .= $this->t('Items'); - } - return u($plural) ->title() ->prepend($this->entityTypePlugin->getPrefix())