============================================ Directives for creating new translation keys ============================================ These directives are meant to ensure better consistency across bundles, avoid duplication, and make keys more predictable. General Principles ================== 1. **Use lowercase snake_case for all keys** 2. **Use dot-separated namespaces** The dot is used to reflect: - bundle - feature - sub-feature - key type 3. **Do not use spaces in keys** 4. **Avoid duplicating the same text in multiple places** When a translation is needed, try a search for the translation value first and see if it exists elsewhere 5. **If a key is used across multiple bundles, it must live in ChillMainBundle.** 6. **If a key is used across multiple bundles and is a generic term, it must be placed in the ``common`` namespace.** Key Structure ============= We use the following structure: .. code-block:: text ... Where: * ``<>`` identifies the bundle or shared context * ```` identifies the part of the module using the translation * ```` describes the text purpose * ```` for a multi-level element ( eg. activity.export.person.count.description) Examples of scopes ------------------ * ``activity`` — ChillActivityBundle * ``person`` — ChillPersonBundle * ``common`` — neutral shared translation values Naming Scopes ============= 1. **Bundle-specific keys** For most things inside a bundle: .. code-block:: text activity.. Example: .. code-block:: text activity.form.save activity.list.title activity.entity.type activity.menu.activities activity.controller.success_created 2. **Shared UI elements (buttons, labels, generic text)** These belong in the ``common`` namespace in ChillMainBundle: .. code-block:: text common.save common.delete common.edit common.filter common.duration_time Translation workflow ==================== Use the following workflow when deciding where a key belongs: 1. **Is this text used in more than one bundle?** → Place in ``main`` or ``common`` 2. **Is this text generic UI (button, label, pagination, yes/no)?** → Place in ``common`` 3. **Is this text specific to one bundle and one feature?** → Place in ``.feature.`` 4. **Is this text related to an entity or value object?** → Place in ``.entity..`` 5. **Is this text used in forms?** → ``.form.`` or ``.form.`` 6. **Is this text related to exports?** → ``.export..`` 7. **Is it related to filtering, searching or parameters?** → ``.filter.`` or → ``.filter..`` for nested filters Examples based on translations within ChillActivityBundle ========================================================= Below are concrete examples from ``ChillActivityBundle``, refactored according to the guidelines. General activity keys --------------------- Instead of scattered keys like:: Show the activity Edit the activity Activity Duration time ... We use: .. code-block:: text activity.general.show activity.general.edit activity.general.title activity.general.duration activity.general.travel_time activity.general.attendee activity.general.remark activity.general.no_comments Forms ----- Instead of keys like:: Activity creation Save activity Reset form Choose a type Use: .. code-block:: text activity.form.title_create activity.form.save activity.form.reset activity.form.choose_type activity.form.choose_duration Long lists (like durations) should be grouped: .. code-block:: text activity.form.duration.5min activity.form.duration.10min activity.form.duration.15min activity.form.duration.1h activity.form.duration.1h30 activity.form.duration.2h ... Entities -------- Entity fields should follow: .. code-block:: text activity.entity.activity.date activity.entity.activity.comment activity.entity.activity.deleted activity.entity.location.name activity.entity.location.type Controller messages ------------------- Instead of strings as keys:: 'Success : activity created!' 'The form is not valid. The activity has not been created !' Use: .. code-block:: text activity.controller.success_created activity.controller.error_invalid_create activity.controller.success_updated activity.controller.error_invalid_update Roles ----- Access control keys should be: .. code-block:: text activity.role.create activity.role.update activity.role.see activity.role.see_details activity.role.delete activity.role.stats activity.role.list Admin ----- .. code-block:: text activity.admin.configuration activity.admin.types activity.admin.reasons activity.admin.reason_category activity.admin.presence CRUD ---- .. code-block:: text activity.crud.type.title_new activity.crud.type.title_edit activity.crud.presence.title_new Activity Reason --------------- .. code-block:: text activity.reason.list activity.reason.create activity.reason.active activity.reason.category activity.reason.entity_title Exports ------- Group them logically: .. code-block:: text activity.export.person.count.title activity.export.person.count.description activity.export.person.count.header activity.export.period.sum_duration.title activity.export.period.sum_duration.description activity.export.period.sum_duration.header Filters ------- Use hierarchical filters: .. code-block:: text activity.filter.by_reason activity.filter.by_type activity.filter.by_date activity.filter.by_location activity.filter.by_sent_received activity.filter.by_user Aggregators ----------- .. code-block:: text activity.aggregator.reason.by_category activity.aggregator.reason.level activity.aggregator.user.by_scope activity.aggregator.user.by_job Global/Shared Keys ================== Keys like the following **must not be redeclared** in each bundle: - First name - Last name - Username - ID - Type - Duration - Comment - Date - Location - Present / Not present - Add / Edit / Delete / Save / Update These belong in ``common`` or ``main``: .. code-block:: text common.firstname common.lastname common.username common.id common.type common.comment common.date common.location common.present common.absent common.add common.edit common.delete common.save common.update Naming directives summary ========================== * **snake_case** * **namespaced with dots** * **bundle prefix for bundle-specific concepts** * **common or main for shared concepts** * **avoid free-floating keys (without namespace)** * **reuse common keys wherever possible** Migration Strategy (Optional) ============================= To apply this structure progressively: 1. New keys must follow these guidelines. 2. Existing keys may remain as-is until refactored. 3. When refactoring: - Move cross-bundle keys to ChillMainBundle and possible `common` namespace. - Replace duplicated keys with shared ones. =========================================== Avoiding duplicate translations =========================================== 1. Use Shared Namespaces ======================== Two namespaces must be used for shared translations: * ``common.*`` — generic UI concepts (save, delete, date, name, etc.) If a translation may be reused in multiple bundles, it must be placed in the ``common`` namespace or in ChillMainBundle. 2. Bundle-Specific Keys ======================= Keys belonging only to one bundle or one feature are namespaced inside that bundle: .. code-block:: text activity.. person.. 3. Search Before Creating ========================= Before adding a new translation key, developers must: 1. For common translations like: "enregistrer/opslaan" look in the `common` namespace. 3. Search in Loco or translations for existing values. If a suitable key exists, reuse it. 4. Only Create a New Key When Necessary ======================================= Create a new key only when the text is: * specific to the bundle * specific to the feature * not reusable elsewhere 6. Progressive Cleanup ====================== Old duplicates may remain temporarily. When updating code in an area, clean duplicate values by moving them into ``common`` or ``main``. General workflow ================ * **Reuse shared keys** within ``common`` namespace. * **Search before creating** new keys. * **Namespace bundle-specific keys** under their bundle. * **Refactor progressively** when touching old code.