# Moved every user‑facing string out of Python into a content tree of 873 files across three languages, after finding dead translations nobody could see were dead and a check silently grading a third of the achievements.

2025

**Situation.** Every user‑facing string in the generator — every achievement, every review, every section heading, every summary, in three languages — lived inside Python source. That makes editing a sentence a code change, makes reviewing a translation a diff against source, and makes it impossible to tell at a glance whether a language is complete. It also hides the failure mode that matters: a translation can be present, wrong, and unreachable at the same time.

**Task.** The strings had to move out of code into a content tree that can be counted, compared across languages, and checked without running the renderer.

**Action.** The result is 873 files under a content directory, organised by kind and then by language: achievements, reviews, summaries, titles, companies, regions, categories, services, profiles, references and cover‑letter fragments. Tab‑separated files where the unit is a line with an identifier, individual files where the unit is a paragraph. The loader reads them at build time and the database is assembled from them, so the tree is the source and the database is derived. Two findings came directly out of being able to count. Some translated strings no longer had any English counterpart — dead entries that nothing rendered and nobody could have noticed while they were embedded in code, because an unreferenced dictionary key looks exactly like a referenced one. And a content check that was supposed to grade every achievement was reading only the subset it could resolve, grading thirty‑seven of ninety‑three and reporting success. Making the corpus a directory made both of these visible as a mismatch in file counts.

**Result.** The prose is now editable without touching code and comparable across languages by counting. The cost is that adding a language is now unambiguous rather than gradual — the tree makes an incomplete language obvious, which is the point, but it also means partial translations cannot be shipped quietly while they are being finished.

---

- Role: Database Engineer
- Categories: [Backend Engineering](https://engineer.company/categories/backend/), [Data Governance](https://engineer.company/categories/data-governance/), [Migrations & Modernization](https://engineer.company/categories/migration/), [Python](https://engineer.company/categories/python/), [Internationalization](https://engineer.company/categories/i18n/), [Documentation](https://engineer.company/categories/documentation/)
- Services: [Backend & API Development](https://engineer.company/services/backend-development/), [Internationalization & Localization](https://engineer.company/services/i18n-localization/), [Database Migration & Modernization](https://engineer.company/services/database-migration/), [Data Governance & Quality](https://engineer.company/services/data-governance/)

<https://engineer.company/portfolio/moved-every-user-facing-string-into-a-content-tree-152/>
