diff --git a/.changes/unreleased/Feature-20241118-150627.yaml b/.changes/unreleased/Feature-20241118-150627.yaml deleted file mode 100644 index 765d66f08..000000000 --- a/.changes/unreleased/Feature-20241118-150627.yaml +++ /dev/null @@ -1,7 +0,0 @@ -kind: Feature -body: "Implementation of new translation management with one source of truth for both - twig and vue component templates using YAML files. \nDuplicate translation keys - can also be detected with new command." -time: 2024-11-18T15:06:27.929549251+01:00 -custom: - Issue: "" diff --git a/composer.json b/composer.json index c247e978d..f72ad3135 100644 --- a/composer.json +++ b/composer.json @@ -67,12 +67,10 @@ "symfony/security-guard": "^5.4", "symfony/security-http": "^5.4", "symfony/serializer": "^5.4", - "symfony/stimulus-bundle": "^2.19", "symfony/string": "^5.4", "symfony/templating": "^5.4", "symfony/translation": "^5.4", "symfony/twig-bundle": "^5.4", - "symfony/ux-translator": "^2.19", "symfony/validator": "^5.4", "symfony/webpack-encore-bundle": "^1.11", "symfony/workflow": "^5.4", diff --git a/config/bundles.php b/config/bundles.php index 2b02f90a9..815c3e62d 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -36,6 +36,4 @@ return [ Chill\BudgetBundle\ChillBudgetBundle::class => ['all' => true], Chill\WopiBundle\ChillWopiBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], - Symfony\UX\StimulusBundle\StimulusBundle::class => ['all' => true], - Symfony\UX\Translator\UxTranslatorBundle::class => ['all' => true], ]; diff --git a/config/packages/ux_translator.yaml b/config/packages/ux_translator.yaml deleted file mode 100644 index 1c1c70608..000000000 --- a/config/packages/ux_translator.yaml +++ /dev/null @@ -1,3 +0,0 @@ -ux_translator: - # The directory where the JavaScript translations are dumped - dump_directory: '%kernel.project_dir%/var/translations' diff --git a/docs/source/development/translations.rst b/docs/source/development/translations.rst deleted file mode 100644 index 818e7bd4b..000000000 --- a/docs/source/development/translations.rst +++ /dev/null @@ -1,31 +0,0 @@ -Translations -************* - -Translator-UX: one source of truth -================================== - -The Translator-ux integration streamlines the process of managing and using translation keys dynamically in our views, whether they be in twig or vue components. The goal is to have one source of truth -for all translations and avoid having to add translation keys in the YAML files as well as in i18ns files. - -To add new translation keys, you can define them in your translation YAML files. Running `symfony console cache:clear` will subsequently update the compiled translation keys which can then also be imported and -used within any vue component. For use within a twig template they can be leveraged by using the |trans function. -Within vue components you will have to import the translation keys you require and then they can be used in the template with the trans() function. - -It is advisable, before adding a translation key to do a search on the existing translation keys of the translation you require. An IDE will allow you to do so easily. -However to avoid the creation of duplicate translation keys a command also exists to detect them. We also strongly advise you to use this command as explained below. - -Detect duplicates command -========================= - -The DetectTranslationDuplicatesCommand `chill:detect-duplicate-translations` is a Symfony console command designed to identify duplicate translations across YAML files in a project. -It checks for repeated translation values linked to different keys within a specified locale. -The command accepts two main options: - -1. `--locale`: to specify the language locale to check (defaulting to 'en') -2. `--exclude-namespaces`: to list namespaces to ignore during the check. -3. [optional] `--verify-hash`: can be used to ensure that the hash of current duplicates matches a given expected value, -aiding in maintaining translation integrity. - -When duplicates are detected, they are displayed in a table format, listing the repeated translations alongside the keys where they are found. -If a mismatch occurs between the computed and expected hash values, an error message is displayed to signal a potential issue in translation consistency. -This command is useful for maintaining clean and consistent translations, avoiding redundancy in your YAML files. diff --git a/package.json b/package.json index eb45c1388..d4537d59b 100644 --- a/package.json +++ b/package.json @@ -13,9 +13,6 @@ "@ckeditor/ckeditor5-markdown-gfm": "^41.4.2", "@ckeditor/ckeditor5-theme-lark": "^41.4.2", "@ckeditor/ckeditor5-vue": "^5.1.0", - "@hotwired/stimulus": "^3.0.0", - "@symfony/stimulus-bridge": "^3.2.0", - "@symfony/ux-translator": "file:vendor/symfony/ux-translator/assets", "@symfony/webpack-encore": "^4.1.0", "@tsconfig/node14": "^1.0.1", "@types/dompurify": "^3.0.5", @@ -24,7 +21,6 @@ "chokidar": "^3.5.1", "dompurify": "^3.1.0", "fork-awesome": "^1.1.7", - "intl-messageformat": "^10.5.11", "jquery": "^3.6.0", "marked": "^12.0.1", "node-sass": "^8.0.0", diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue index edd6434ca..7ec62d07d 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/ConcernedGroups.vue @@ -22,8 +22,8 @@ @@ -14,7 +14,7 @@ @close="modal.showModal = false"> @@ -81,13 +81,6 @@ import AddAddress from "ChillMainAssets/vuejs/Address/components/AddAddress.vue" import { mapState } from "vuex"; import { getLocationTypes } from "../../api"; import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods'; -import { - SAVE, - ACTIVITY_LOCATION_FIELDS_EMAIL, ACTIVITY_LOCATION_FIELDS_PHONENUMBER1, - ACTIVITY_LOCATION_FIELDS_PHONENUMBER2, ACTIVITY_LOCATION_FIELDS_NAME, - ACTIVITY_LOCATION_FIELDS_TYPE, ACTIVITY_CHOOSE_LOCATION_TYPE, ACTIVITY_CREATE_NEW_LOCATION, - trans -} from "../../../../../../../../../../../../assets/translator"; export default { name: "NewLocation", @@ -95,19 +88,6 @@ export default { Modal, AddAddress, }, - setup() { - return { - trans, - SAVE, - ACTIVITY_LOCATION_FIELDS_EMAIL, - ACTIVITY_LOCATION_FIELDS_PHONENUMBER1, - ACTIVITY_LOCATION_FIELDS_PHONENUMBER2, - ACTIVITY_LOCATION_FIELDS_NAME, - ACTIVITY_LOCATION_FIELDS_TYPE, - ACTIVITY_CHOOSE_LOCATION_TYPE, - ACTIVITY_CREATE_NEW_LOCATION, - }; - }, props: ['availableLocations'], data() { return { diff --git a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue index 02b642cf9..4691a860a 100644 --- a/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue +++ b/src/Bundle/ChillActivityBundle/Resources/public/vuejs/Activity/components/SocialIssuesAcc.vue @@ -3,7 +3,7 @@
- +
@@ -31,7 +31,7 @@ :allow-empty="true" :show-labels="false" :loading="issueIsLoading" - :placeholder="trans(ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE)" + :placeholder="$t('activity.choose_other_social_issue')" :options="socialIssuesOther" @select="addIssueInList"> @@ -42,7 +42,7 @@
- +
@@ -51,7 +51,7 @@
- {{ trans(ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE) }} + {{ $t('activity.select_first_a_social_issue') }} - {{ trans(ACTIVITY_SOCIAL_ACTION_LIST_EMPTY) }} + {{ $t('activity.social_action_list_empty') }} @@ -81,11 +81,6 @@ import VueMultiselect from 'vue-multiselect'; import CheckSocialIssue from './SocialIssuesAcc/CheckSocialIssue.vue'; import CheckSocialAction from './SocialIssuesAcc/CheckSocialAction.vue'; import { getSocialIssues, getSocialActionByIssue } from '../api.js'; -import { - ACTIVITY_SOCIAL_ACTION_LIST_EMPTY, - ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE, ACTIVITY_SOCIAL_ACTIONS, - ACTIVITY_SOCIAL_ISSUES, ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE, trans -} from "../../../../../../../../../../../assets/translator"; export default { name: "SocialIssuesAcc", @@ -94,16 +89,6 @@ export default { CheckSocialAction, VueMultiselect }, - setup() { - return { - trans, - ACTIVITY_SOCIAL_ACTION_LIST_EMPTY, - ACTIVITY_SELECT_FIRST_A_SOCIAL_ISSUE, - ACTIVITY_SOCIAL_ACTIONS, - ACTIVITY_SOCIAL_ISSUES, - ACTIVITY_CHOOSE_OTHER_SOCIAL_ISSUE - }; - }, data() { return { issueIsLoading: false, diff --git a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml index 17288a0c5..a4d73728b 100644 --- a/src/Bundle/ChillActivityBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillActivityBundle/translations/messages.fr.yml @@ -101,31 +101,6 @@ activity: Insert a document: Insérer un document Remove a document: Supprimer le document comment: Commentaire - errors: Le formulaire contient des erreurs - social_issues: Problématiques sociales - choose_other_social_issue: Ajouter une autre problématique sociale... - social_actions: Actions d'accompagnement - select_first_a_social_issue: Sélectionnez d'abord une problématique sociale - social_action_list_empty: Aucune action sociale disponible - add_persons: Ajouter des personnes concernées - bloc_persons: Usagers - bloc_persons_associated: Usagers du parcours - bloc_persons_not_associated: Tiers non-pro. - bloc_thirdparty: Tiers professionnels - bloc_users: T(M)S - location: Localisation - choose_location: Choisissez une localisation - choose_location_type: Choisissez un type de localisation - create_new_location: Créer une nouvelle localisation - location_fields: - name: Nom - type: Type - phonenumber1: Téléphone - phonenumber2: Autre téléphone - email: Adresse courriel - create_address: Créer une adresse - edit_address: Modifier l'adresse - No documents: Aucun document # activity filter in list page diff --git a/src/Bundle/ChillEventBundle/translations/messages.fr.yml b/src/Bundle/ChillEventBundle/translations/messages.fr.yml index 8136a9e84..6046881ff 100644 --- a/src/Bundle/ChillEventBundle/translations/messages.fr.yml +++ b/src/Bundle/ChillEventBundle/translations/messages.fr.yml @@ -123,6 +123,7 @@ Role: Rôles Role creation: Nouveau rôle Role edit: Modifier un rôle +'': '' xlsx: xlsx ods: ods csv: csv diff --git a/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php b/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php deleted file mode 100644 index 0305ea700..000000000 --- a/src/Bundle/ChillMainBundle/Command/DetectTranslationDuplicatesCommand.php +++ /dev/null @@ -1,181 +0,0 @@ -setDescription('Detects duplicate translations in YAML files.') - ->addOption('locale', null, InputOption::VALUE_REQUIRED, 'Locale to check for duplicate translations', 'en') - ->addOption('exclude-namespaces', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_OPTIONAL, 'Namespaces to exclude from duplicate detection', []) - ->addArgument('verify-hash', InputArgument::OPTIONAL, 'The expected hash to verify translation integrity'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $locale = $input->getOption('locale'); - $excludedNamespaces = $input->getOption('exclude-namespaces'); - $expectedHash = $input->getArgument('verify-hash'); - - // Loop through all bundles and get the translation directories - foreach ($this->kernel->getBundles() as $bundle) { - $bundlePath = $bundle->getPath(); - $translationDir = $this->getTranslationDirectory($bundle->getName(), $bundlePath); - - if (null !== $translationDir && is_dir($translationDir)) { - foreach (glob($translationDir.'/*.yaml') as $file) { - $this->translator->addResource('yaml', $file, $locale); - } - } - } - - $catalogue = $this->translator->getCatalogue($locale); - - $allTranslations = []; - - // Iterate through each domain in the catalogue - foreach ($catalogue->all() as $domain => $translations) { - foreach ($translations as $key => $value) { - if ($this->isExcludedNamespace("{$domain}.{$key}", $excludedNamespaces)) { - continue; - } - if (is_array($value)) { - $this->flattenTranslation($value, "{$domain}.{$key}", $allTranslations); - } else { - if (!isset($allTranslations[$value])) { - $allTranslations[$value] = []; - } - $allTranslations[$value][] = "{$domain}.{$key}"; - } - } - } - - // Detect values that appear in more than one key - $duplicates = array_filter($allTranslations, fn ($keys) => count($keys) > 1); - - $duplicatesHash = $this->generateDuplicatesHash($duplicates); - - if ('' !== $expectedHash) { - if ($duplicatesHash === $expectedHash) { - $output->writeln('Translations are consistent with the expected hash.'); - - $output->writeln("Current duplicate hash: {$duplicatesHash}"); - - return Command::SUCCESS; - } - $output->writeln('Translation hash mismatch! Potential duplicate added.'); - $this->renderDuplicatesTable($output, $duplicates, $locale); - - $output->writeln("Current duplicate hash: {$duplicatesHash}"); - - return Command::FAILURE; - - } - - $this->renderDuplicatesTable($output, $duplicates, $locale); - - $output->writeln("Current duplicate hash: {$duplicatesHash}"); - - return Command::SUCCESS; - } - - private function flattenTranslation(array $translations, string $prefix, array &$allTranslations): void - { - foreach ($translations as $key => $value) { - $fullKey = "{$prefix}.{$key}"; - if (is_array($value)) { - $this->flattenTranslation($value, $fullKey, $allTranslations); - } else { - if (!isset($allTranslations[$value])) { - $allTranslations[$value] = []; - } - $allTranslations[$value][] = $fullKey; - } - } - } - - private function getTranslationDirectory(string $bundleName, string $bundlePath): ?string - { - $translationDir = $bundlePath.'/translations'; - - if ('ChillAsideActivityBundle' === $bundleName) { - $translationDir = $bundlePath.'/src/translations'; - } - - return is_dir($translationDir) ? $translationDir : null; - } - - private function wrapText(string $text, int $width): string - { - return wordwrap($text, $width, "\n", true); - } - - private function isExcludedNamespace(string $key, array $excludedNamespaces): bool - { - foreach ($excludedNamespaces as $namespace) { - if (str_starts_with($key, (string) $namespace)) { - return true; - } - } - - return false; - } - - private function generateDuplicatesHash(array $duplicates): string - { - ksort($duplicates); - foreach ($duplicates as $translation => $keys) { - sort($keys); - } - - return hash('md5', serialize($duplicates)); - } - - private function renderDuplicatesTable(OutputInterface $output, array $duplicates, string $locale): void - { - if ([] === $duplicates) { - $output->writeln("No duplicate translations found for locale '{$locale}'."); - - return; - } - - $output->writeln("Duplicate translations found for locale '{$locale}':"); - $table = new Table($output); - $table->setHeaders(['Translation', 'Used in Keys']); - - foreach ($duplicates as $translation => $keys) { - $wrappedTranslation = $this->wrapText($translation, 40); - $wrappedKeys = $this->wrapText(implode(', ', $keys), 80); - $table->addRow([$wrappedTranslation, $wrappedKeys]); - } - - $table->render(); - } -} diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js index 63977c8df..28670f56c 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/Address/i18n.js @@ -1,6 +1,5 @@ import { multiSelectMessages } from 'ChillMainAssets/vuejs/_js/i18n' -// translations added to yaml file and used through symfony ux translator. -// these can be deleted once everything is verified to work. + const addressMessages = { fr: { add_an_address_title: 'Créer une adresse', diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue index 24968e364..22b0181e5 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/OnTheFly/components/Create.vue @@ -4,7 +4,7 @@ @@ -37,61 +37,59 @@
- diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue index 5fdbbc7e3..943ea85f3 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflow.vue @@ -38,24 +38,24 @@
- {{ trans(WORKFLOW_ON_HOLD) }} + {{ $t('on_hold') }}

- {{ trans(WORKFLOW_YOU_DESCRIBED_TO_ALL_STEPS) }} + {{ $t('you_subscribed_to_all_steps') }}

- {{ trans(WORKFLOW_YOU_SUBSCRIBED_TO_FINAL_STEP) }} + {{ $t('you_subscribed_to_final_step') }}

@@ -65,47 +65,76 @@
- diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue index 770a1a191..ab52b7452 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue @@ -1,5 +1,5 @@ - diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Modal.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Modal.vue index d484bfb79..11bb9db2f 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Modal.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/Modal.vue @@ -17,7 +17,7 @@ @@ -28,7 +28,8 @@ - diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OpenWopiLink.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OpenWopiLink.vue index 2b34d6071..5f8a85208 100644 --- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OpenWopiLink.vue +++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/OpenWopiLink.vue @@ -4,182 +4,216 @@ isChangeIcon ? 'change-icon' : '', isChangeClass ? options.changeClass : 'btn-wopilink' ]" @click="openModal"> - + - + - {{ trans(WOPI_ONLINE_EDIT_DOCUMENT) }} + {{ $t('online_edit_document') }} - +
- + - + - +
- - + - - + +
-