Lovable reads i18n rules from three places: workspace and project knowledge, which are always in context; skills, which load only when a prompt matches their description; and instruction files in the connected repository, where a root AGENTS.md is read regardless of how long the conversation has run. Put the rules in the wrong one and the app you translated last week ships its next feature in English. globalize.now is AI-powered localization infrastructure, so we see the result of that mistake in a lot of Lovable repositories; the fix is mostly knowing which surface is read when.

Why does a translated Lovable app drift back to English?

Because the instruction that made it multilingual was not in front of the agent when it wrote the next component. Lovable solves the prompt on screen. If that prompt says "add a testimonials section" and nothing in context says "every user-visible string goes through <Trans>", the heading lands as a literal, exactly as it would in a fresh project.

This is not the same problem as catalogs lagging behind code, which is the sync failure covered in why your Lovable app's translations break every time you ship. Sync moves wrapped strings into locale files. It cannot move a string that was never wrapped. The upstream question is what Lovable was reading at the moment it wrote the code, and Lovable's documentation is unusually specific about that.

What does Lovable actually read before it edits?

Per its knowledge documentation, project knowledge, workspace knowledge and instruction files in the Git repository such as AGENTS.md or CLAUDE.md all guide the agent, alongside the project code. Skills are separate and load on demand.

They differ in three ways that matter for i18n.

When they are read. Knowledge is included on every message. A skill is included only when the request matches its description. A root AGENTS.md is, in Lovable's words, always read regardless of session length.

How durable they are in a long chat. Lovable's docs carry an explicit caveat that in very long conversations with a lot of context, knowledge instructions may not always be followed consistently. The same page makes the opposite claim for the root AGENTS.md. That asymmetry is the whole reason this post exists.

Who can edit them. Workspace knowledge is owner and admin only. Project knowledge can be edited by anyone with edit rights on the project. The repository file is edited by whoever can push, which includes the Lovable agent itself.

Each knowledge level holds up to 10,000 characters. That is plenty for a pointer and far too little for the full rule set once you also want architecture notes, database schema and brand voice in there.

Where should the i18n rules go, then?

In the repository, with a short pointer in knowledge. The reasoning follows from the table above.

AGENTS.md at the repo root carries the full rules. It is read on every message regardless of session length, it lives in Git so it survives a new chat, a new collaborator and a move to another agent, and it has no character cap that competes with the rest of your project context. When the lovable-i18n skill runs its setup, its third phase writes exactly this file: a Lingui rules block between <!-- lovable-i18n:rules:start --> and <!-- lovable-i18n:rules:end --> markers, created if the file is missing, appended if it exists, and replaced between the markers on a re-run so nothing duplicates.

Project knowledge carries a two-line pointer. Something like:

Localization
- This app is localized with Lingui. Every user-visible string is wrapped
  (<Trans>, t``, msg``) and new strings are appended to src/locales/*/messages.po.
- The full rules are in AGENTS.md at the repo root. Follow them on every edit.

The pointer is there for the case the docs warn about. If a long conversation has diluted the knowledge block, the agent still has the repo file; if for some reason the repo file is not in context, the pointer names the constraint. Two surfaces, one rule.

Workspace knowledge only if every project uses the same library. Workspace knowledge applies to all projects in the workspace and there is exactly one of it. If half your projects are Lingui and half are something else, a Lingui rule at workspace level is wrong for half of them, and Lovable is encouraged to prioritize project knowledge on a conflict anyway. Keep workspace knowledge for the rules that are true everywhere: sentence-case buttons, no console.log, English code comments.

The skill is not the home for the rules. This surprises people who just imported it. A skill loads when the prompt matches its description, so lovable-i18n is in context when you ask for i18n setup and absent when you ask for a checkout page. That is by design; a skill that loaded on every message would just be knowledge. The skill's job is to write the durable rules into the repo once and then get out of the way.

What do the rules in AGENTS.md say?

They answer the questions an agent gets wrong when it is only told to "use i18n". The block the skill writes has six parts.

Which macro. A decision list: text that changes with a number uses <Plural> or an ICU plural; JSX text uses <Trans>; attribute values and event-handler strings such as toasts use the t returned by useLingui(); module-scope constants use msg and are resolved inside the component. The rule also says which import path each comes from, because the wrong t import binds a global instance the app never loads.

Interpolation. Only a bare variable names its own slot in the extracted message. Any other expression extracts as {0}, which a translator cannot work with, so the rule requires ph() to name it.

Plurals. other is always required, categories are CLDR, and a ternary between two strings is banned because it bakes English plural rules into the component. If you want the background, what ICU MessageFormat is covers the syntax the plural forms compile to.

Numbers and dates. i18n.number() and i18n.date(), never toFixed() or a currency symbol concatenated onto a value. Lovable's own workspace-knowledge example includes a localization section that sets a date format and European number formatting, which is a good instinct, but it is a formatting rule, not a wrapping rule. An app can follow it perfectly and still ship every heading in English.

Translator comments. Short strings with several readings, bare action labels and domain terms get a comment= describing where the string appears. context= is reserved for the same text needing different translations in different places.

Catalog upkeep. Every new string is wrapped and appended to each src/locales/*/messages.po with an empty msgstr, so Lingui falls back to source text until a translation arrives. The agent never runs lingui extract, because there is no terminal in Lovable; a GitHub Action does that after the sync. And it never edits the #. and #: comment lines on existing entries, because extraction regenerates them.

That last section is what makes the rules Lovable-specific. A Cursor or Claude Code rules file can end with "run the linter". A Lovable rules file cannot, so it has to say what to do by hand instead, and what to leave for CI.

What enforces the rule when Lovable cannot run anything?

The GitHub workflow, and only the GitHub workflow. Lovable has no terminal, so there is no lint step between the agent writing a literal and the change syncing to your repository. This is the structural difference from IDE agents, where a lint rule in CI is what makes the build fail on a hardcoded string.

If you opt in during setup, the skill adds a GitHub Actions workflow that runs on pushes to the default branch, which is where Lovable's sync lands, extracts wrapped strings into the catalogs, and commits a catalog sync back. If the GitHub app lacks the workflows permission, the skill asks you to add the file by hand in GitHub. That closes the loop for anything the agent wrapped. It does nothing for a string the agent did not wrap, because extraction only sees macros.

So the honest picture is: the rules in AGENTS.md lower how often an unwrapped literal appears, the knowledge pointer backs them up in long chats, and the diff in GitHub is where you catch the rest. If you want a machine to catch the rest, add eslint-plugin-i18next's no-literal-string rule as a step in the same workflow. It runs on the repository, which is the one place a Lovable project can run anything at all.

What happens to the strings that do get wrapped?

They need translating, and that is the part worth automating rather than re-prompting. Conversion is one-time and happens in the app: connect the repository, and globalize.now converts the codebase once, delivering the catalog as a pull request you review. After that, push jobs translate new catalog units as they land, so a <Trans> Lovable wrote on Tuesday has its translations in a pull request by Wednesday. No dashboard step, no export, no approval queue; the longer argument for that shape is in localizing a Lovable app without a dashboard, and the exact setup path, including the GitHub connection and the globalize connector, is on the Lovable integration page.

One historical note, because it explains why this problem feels new to some Lovable builders. Lovalingo translated Lovable apps at runtime in the browser, so a newly generated English component was simply re-translated on load and the recurrence never surfaced. It shut down on 31 August 2026, and the apps that moved to committed catalogs through the migration guide are meeting the upstream question for the first time. The catalog model is the right trade, since the translated markup is yours and indexable, but it asks the agent to write translatable code, and that means telling it where the rules are.

Put the rules where Lovable reads them

Run the skill once so AGENTS.md carries the full block, paste the two-line pointer into project knowledge, and let the GitHub workflow do the extraction the editor cannot. If you are building in Lovable and want the translation of everything that reaches the catalog handled rather than maintained, the vibe coders page is the overview and pricing is on its own page.

globalize.now turns hardcoded app copy into translation-ready locale files and keeps them updated as you ship.

Try globalize.now free