============================================
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

    <scope>.<feature>.<sub-feature>.<key-type>

Where:

* ``<>`` identifies the bundle or shared context
* ``<feature>`` identifies the part of the module using the translation
* ``<element>`` describes the text purpose
* ``<subelement>`` 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.<feature>.<element>

   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 ``<bundle>.feature.<element>``

4. **Is this text related to an entity or value object?**
   → Place in ``<bundle>.entity.<entityname>.<field>``

5. **Is this text used in forms?**
   → ``<bundle>.form.<field>`` or ``<bundle>.form.<action>``

6. **Is this text related to exports?**
   → ``<bundle>.export.<feature>.<column>``

7. **Is it related to filtering, searching or parameters?**
   → ``<bundle>.filter.<name>`` or
   → ``<bundle>.filter.<feature>.<field>`` 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.<feature>.<element>
    person.<feature>.<element>

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.
