Tier 2 Localization — Scope Review
==================================

Scope estimate and decision for making the load-bearing English
keywords (tag names; recipe-body section headings) translatable, per
[Phase 13 of the recipe edition plan][p1].  Tier 1 ([Phase 12][p1])
fully meets [edition design criterion #7][ed]; Tier 2 is a quality
upgrade — French-edition users would see properly-translated tag
captions and edit recipes with section headings in their language.


Tag-name inventory
------------------

The existing [`$:/community/recipes/config/RecipeTag`][rt] config
holds the literal `Recipe` and is consumed only by the ViewTemplate
and TiddlerIcon cascade entries for the recipe body and icon.
Everywhere else, tag names appear as filter literals.

### Filter-literal sites in source ###

| File | Tag literals | Notes |
|------|--------------|-------|
| [Recipe.tid][f1] | `tag[Recipe]` ×5, `!match[Recipe]` ×1 | "All Recipes" list and category-button row |
| [$__community_recipes_recipe-box-card_favorites.tid][f2] | `tag[Recipe]` + `tag[Favorite]` ×3 | Favorites card |
| [$__community_recipes_recipe-box-card_popular-ingredients.tid][f3] | `tag[Ingredient]` ×2, `tag[Recipe]` ×2 | Popular ingredients card |
| [$__community_recipes_recipe-box-card_tags.tid][f4] | `tag[Recipe]` ×2, `!match[Recipe]` ×2, `!match[Favorite]` ×2, `!tag[Category]` ×2 | Tags card |
| [$__community_recipes_recipe-box-card_categories.tid][f5] | `tag[Category]` ×1 | Categories card |
| [$__community_recipes_ui_Buttons_cooking-mode.tid][f6] | `tag[Recipe]` ×1 | Cooking-mode button visibility |
| [$__community_recipes_ui_EditTemplate_extra-fields-hint.tid][f7] | `tag[Recipe]` ×1 | Edit-mode hint |
| [$__community_recipes_ui_EditTemplate_photo.tid][f8] | `tag[Recipe]` + `tag[Ingredient]` ×1 | Photo edit form scope |
| [$__community_recipes_ui_RemoveDemoContent.tid][f9] | `tag[Recipe]` ×7, `tag[Ingredient]` ×7, `tag[Category]` ×4 | Demo-removal UI |
| [$__community_recipes_ui_ViewTemplate_ingredient.tid][fa] | `tag[Recipe]` ×4, `tag[Ingredient]` ×3 | Ingredient view |
| [$__community_recipes_ui_ViewTemplate_recipe-meta.tid][fb] | `tag[Recipe]` ×1 | Metadata strip gate |
| [$__community_recipes_ui_ViewTemplate_category.tid][fc] | `tag[Category]` ×1 | Category view |
| [$__community_recipes_config_ViewTemplateBodyFilters_ingredient.tid][fd] | `tag[Ingredient]` ×1 | Cascade entry |
| [$__community_recipes_config_TiddlerIconFilters_ingredient.tid][fe] | `tag[Ingredient]` ×1 | Cascade entry |
| [$__language_MissingTiddler_Hint.tid][ff] | `tag[Ingredient]` ×1 | Suppresses default hint on alias tiddlers |

**Filter-literal subtotal: ~57 `tag[…]` / `!match[…]` occurrences
across 15 files.**  Many are in close proximity (the same filter
appearing on a `<%if>` and again inside a `$list`); the unique-site
count is closer to 35.

### Other tag-name sites ###

  - [$__community_recipes_ui_Buttons_new-recipe.tid][f6b] line 12:
    `tags="Recipe"` on the New Recipe page-control button.
  - [Recipe Box.tid][rb] line 10: `tags="Recipe"` on the Recipe
    Box's "Create a new Recipe" action.
  - [$__EvidentlyCube_Trigger_1.tid][ec] line 5: AutoComplete trigger
    filter `[all[tiddlers]tag[Ingredient]…]`.  Locked to the literal.
  - [$__config_RelinkOnRename.tid][rr]: hardcodes whichever tag
    names Relink is configured to follow on rename.
  - Five category tag tiddlers:
    [Breakfast.tid][cb], [Main.tid][cm], [Salad.tid][cs],
    [Side.tid][csi], [Dessert.tid][cd] — title *is* the tag name.
  - Two structural tag tiddlers:
    [Recipe.tid][f1] (the "All Recipes" list), [Ingredient.tid][in]
    (`<<list-links filter:"[tag<currentTiddler>]">>` — already
    self-referential, would survive a rename).

### Difficulty notes ###

  - The bulk of filter-literal sites are mechanical: introduce a
    `<<recipe-tag>>` / `<<ingredient-tag>>` / `<<category-tag>>` /
    `<<favorite-tag>>` set of variables (or a single `\procedure`
    that returns the literal) and rewrite filters to
    `tag<recipe-tag>` form.
  - The negated forms (`!match[Recipe]`, `!tag[Category]`) and
    composite forms inside `:sort:number[…]` work the same way
    syntactically — no surprise here.
  - The two `tags="Recipe"` action attributes need a runtime
    transclusion: `tags={{$:/community/recipes/config/RecipeTag}}`
    (or equivalent).
  - The AutoComplete trigger filter is the awkward one — its
    `filter` field is a static string the plugin reads at trigger
    time.  Plugin behaviour with a transcluded value needs
    confirmation; if it does not resolve transclusions, the
    workaround is to ship a per-locale trigger tiddler (i.e., the
    French translation pack carries an override).
  - [Recipe.tid][f1] could be retrofitted to use
    `[tag<currentTiddler>]` like [Ingredient.tid][in] already does
    — small free improvement that makes the Recipe-tag rename
    self-healing.
  - The five category tag tiddlers cannot be dereferenced in place;
    a localized content collection ships its own set
    (`Petit-déjeuner.tid`, etc.).  Existing sample data in
    `editions/recipes/samples/en-US/` stays English-only.


Section-heading inventory
-------------------------

Three literals to externalize: `!! Ingredients`, `!! Steps`,
`!! About`.  Proposed config tiddler (or single tiddler with three
fields): `$:/community/recipes/config/section-headings/{about,ingredients,steps}`.

### Consumers ###

| File | Heading occurrences | Role |
|------|---------------------|------|
| [$__community_recipes_ui_ViewTemplate_recipe-body.tid][bv] | `!! Ingredients` ×1, `!! Steps` ×3, `!! About` ×1 | Splitter that extracts each section from recipe text |
| [$__community_recipes_templates_new-recipe.tid][nt] | `!! About`, `!! Ingredients`, `!! Steps` ×1 each | Prefilled new-recipe scaffolding |
| [Tidbits_ Recipes.tid][tr] | `!! Ingredients`, `!! Steps`, `!! About` mentioned in prose | In-edition documentation |

**Filter-literal subtotal: 8 `splitregexp[!! …]` occurrences across
2 files; 1 docs prose tiddler.**  The body view template's
`splitregexp[!! Ingredients]` calls would each be rewritten as
`splitregexp{$:/community/recipes/config/section-headings/ingredients}`
or via a transcluded variable.

### Difficulty notes ###

  - Body view template's `splitregexp` pattern is ugly but
    mechanical — the literal becomes a transcluded value and the
    regex characters in the heading must be escape-safe.  For
    `!! Ingredients` / `!! Steps` / `!! About` and reasonable
    locale equivalents (`!! Ingrédients` / `!! Étapes` /
    `!! À propos`), no regex escapes are needed.
  - New-recipe template prefill is trivial — the file is wikitext
    text content, not a filter, so a transclusion or `<<>>` macro
    expansion is enough.
  - Docs prose stays English in the empty edition; localized
    documentation is content-pack territory if pursued.
  - Sample recipe content (32 recipes in
    `editions/recipes/samples/en-US/32-recipes-us.json`) is English
    by virtue of being a US recipe collection.  A French
    collection would naturally use French headings; the splitter
    config would already match.


User-visible consequence under Tier 1
-------------------------------------

The Phase 12 French pack already acknowledges this seam.  The
Favorites-card caption translates cleanly to "Favoris", but the
empty-state hint reads:

> *"Marquez une recette comme **Favorite** pour la voir ici."*

— see [fr-FR/lang.json][fr] line 210.  The translator preserved the
English `Favorite`, capitalized, because that is the literal string
a French user must actually type into the tag field for the recipe
to appear in the card.  The same applies to `Recipe`, `Ingredient`,
and `Category`: under Tier 1 the UI speaks French, but the
load-bearing tag vocabulary stays English.

This is the user-visible gap Tier 2 closes.  It is not a defect of
Tier 1 — Tier 1 was scoped to UI strings — but it is the reason a
fully French edition reads as half-localized to a French user, and
the most concrete argument for prioritizing Tier 2 in v1.1.


Risk surfaces
-------------

### Relink ###

[Relink][rl] rewrites tag references on user tiddlers when a tag
tiddler is renamed.  The edition's [`$:/config/RelinkOnRename`][rr]
already enables this.  Two consequences:

  - **Renaming `Recipe` to `Recette` rewrites user recipes' `tags:
    Recipe` to `tags: Recette`** automatically.  The bulk of user
    content stays consistent.
  - **Filter literals in shadow tiddlers do not get rewritten by
    Relink.**  After a rename, `[tag[Recipe]]` in the empty
    edition's source still refers to the old name.  Without
    dereferencing through a config, the user's wiki is half-broken
    (Recipe Box no longer finds their recipes).
  - This is the load-bearing reason Tier 2 needs the dereferencing
    pass: Relink alone is necessary but not sufficient.

### AutoComplete ###

The `[[` ingredient autocomplete is wired through
[$__EvidentlyCube_Trigger_1.tid][ec], whose `filter` field is
`[all[tiddlers]tag[Ingredient]…]`.  Two paths:

  - **Confirm whether the AutoComplete plugin resolves transclusions
    in the `filter` field at trigger time.**  If yes, dereferencing
    works the same way as everywhere else.
  - **If not, ship a per-locale trigger tiddler in the translation
    pack** (the French pack overrides
    `$:/EvidentlyCube/Trigger/1` with `tag[Ingrédient]`).  Doable
    but adds a coupling from translation packs to plugin-specific
    overrides.

### Sample-content alignment ###

A localized content collection needs:

  - Locale-renamed category tag tiddlers
    (`Petit-déjeuner.tid`, `Plat principal.tid`, `Salade.tid`,
    `Accompagnement.tid`, `Dessert.tid`).
  - Recipe `tags:` fields rewritten to match
    (`tags: Recette Petit-déjeuner`).
  - Section headings translated in every recipe body.
  - Ingredient tiddlers retitled and re-aliased for the locale.

This is mechanical per-collection but high-touch — for the 32-recipe
US collection, a French equivalent is essentially a from-scratch
content build, not a translation.  This work is not blocked by Tier
2; it is the necessary companion to it.

### Mid-flight migration ###

A user populates their wiki in English, then flips the edition's
language config to French.  Without further action:

  - Tag tiddler titles stay English (`Recipe.tid`, `Breakfast.tid`,
    …).  The user's recipes still tag `Recipe`.  Filter literals
    in the source still match.  **Outcome: nothing breaks; UI
    strings translate; tag names remain English.**

If the user *also* renames the tag tiddlers (manually or via a
helper):

  - Relink rewrites their recipes' tags fields.
  - Filter literals in the source break unless dereferenced.
  - **Tier 2 is the prerequisite for this path to work cleanly.**

The fully-French case (French translation pack + French content
collection from scratch) is the cleanest target — no migration
involved.  Tier 2 enables this case to ship as a single coherent
French edition build.


Decision
--------

**Defer Tier 2 to post-1.0.**

Reasoning:

  - [Edition design criterion #7][ed] is fully met by Tier 1; the
    [verification note][vn] already records this as ✓.
  - Tier 2 is ~35 unique source sites (filters and action
    attributes), plus the AutoComplete trigger workaround if
    needed, plus 5 hardcoded category tag tiddlers per locale,
    plus a per-locale content collection build.  Estimate: a full
    phase, not a quick pass.
  - Phase 12 just shipped a substantial localization story
    (lingo macro + English defaults + French pack +
    edit-template refactor).  Releasing Tier 1 as v1.0 lets the
    Tier 2 follow-up build on user feedback rather than guess at
    requirements.
  - The AutoComplete and Relink risk surfaces are real but
    bounded — they are not mid-1.0-release surprises, they are
    deliberate Tier 2 design questions.  Solving them under
    1.0-release pressure is worse than solving them in v1.1.
  - 1.0 ships a French translation pack already, so the visible
    localization story is strong without Tier 2.

**Handoff for v1.1+:**

  - This scope note is the starting point.  Re-validate the
    inventory before implementation in case sites have moved.
  - First implementation step: introduce
    `$:/community/recipes/config/{IngredientTag,CategoryTag,FavoriteTag}`
    siblings to the existing `RecipeTag`, plus
    `section-headings/{about,ingredients,steps}`.  Then a
    sweep-and-replace pass.
  - Second step: confirm AutoComplete trigger transclusion
    behaviour empirically; pick the in-place dereferencing path
    or the per-locale-override path based on what the plugin
    actually does.
  - Third step: build a French content-collection companion and
    ship as an additional sample alongside `en-US/`.
  - The original Phase 13 spec in the [plan][p1] becomes the
    starting outline for the v1.1 phase; this scope note becomes
    the design input.


  [bv]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_ViewTemplate_recipe-body.tid
  [cb]:  ../../editions/recipes/wiki/tiddlers/Breakfast.tid
  [cd]:  ../../editions/recipes/wiki/tiddlers/Dessert.tid
  [cm]:  ../../editions/recipes/wiki/tiddlers/Main.tid
  [cs]:  ../../editions/recipes/wiki/tiddlers/Salad.tid
  [csi]: ../../editions/recipes/wiki/tiddlers/Side.tid
  [ec]:  ../../editions/recipes/wiki/tiddlers/$__EvidentlyCube_Trigger_1.tid
  [ed]:  001-edition-design.md
  [f1]:  ../../editions/recipes/wiki/tiddlers/Recipe.tid
  [f2]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_recipe-box-card_favorites.tid
  [f3]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_recipe-box-card_popular-ingredients.tid
  [f4]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_recipe-box-card_tags.tid
  [f5]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_recipe-box-card_categories.tid
  [f6]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_Buttons_cooking-mode.tid
  [f6b]: ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_Buttons_new-recipe.tid
  [f7]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_EditTemplate_extra-fields-hint.tid
  [f8]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_EditTemplate_photo.tid
  [f9]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_RemoveDemoContent.tid
  [fa]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_ViewTemplate_ingredient.tid
  [fb]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_ViewTemplate_recipe-meta.tid
  [fc]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_ui_ViewTemplate_category.tid
  [fd]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_config_ViewTemplateBodyFilters_ingredient.tid
  [fe]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_config_TiddlerIconFilters_ingredient.tid
  [ff]:  ../../editions/recipes/wiki/tiddlers/$__language_MissingTiddler_Hint.tid
  [fr]:  ../../editions/recipes/samples/fr-FR/lang.json
  [in]:  ../../editions/recipes/wiki/tiddlers/Ingredient.tid
  [nt]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_templates_new-recipe.tid
  [p1]:  ../plans/001-recipe-edition.md
  [rb]:  ../../editions/recipes/wiki/tiddlers/Recipe Box.tid
  [rl]:  https://flibbles.github.io/tw5-relink/
  [rr]:  ../../editions/recipes/wiki/tiddlers/$__config_RelinkOnRename.tid
  [rt]:  ../../editions/recipes/wiki/tiddlers/$__community_recipes_config_RecipeTag.tid
  [tr]:  ../../editions/recipes/wiki/tiddlers/Tidbits_ Recipes.tid
  [vn]:  003-recipe-edition-verification.md
