Skip to main content

Phrase Discovery

Loco automatically discovers translatable text on your page using a TreeWalker DOM traversal plus a MutationObserver for live updates.

What gets discovered

1. Plain text nodes

Any visible text between block elements.

<p>Hello, welcome to our app.</p>

→ key: "Hello, welcome to our app."

2. Input values

Button, submit, and reset input values.

<input type="submit" value="Save Changes" />

→ key: "Save Changes"

3. Input attributes

placeholder, title, and aria-label attributes.

<input placeholder="Search..." aria-label="Search field" />

→ two separate phrases: "Search..." and "Search field"

4. Mixed content (variable slots)

Text with inline child elements (<var>, <strong>, <time>, <span>, <em>).

<p>You have <strong>5</strong> unread messages</p>

→ key: "You have {{number:0}} unread messages", slot: { type: 'number', index: 0, value: '5' }

What gets filtered out

Text nodes are skipped if:

  • Fewer than 2 characters
  • Exceed 4096 characters
  • Only punctuation or symbols
  • Already contain {{type:N}} tokens (translation artifacts)
  • Inside a blocked tag: <script>, <style>, <noscript>, <textarea>, <code>, etc.
  • The element has data-notranslate attribute
  • The element or an ancestor is hidden

Context tracing

Each phrase records a context string that traces its DOM location for disambiguation:

"button.delete | form.login, email-field"

This lets you translate the same word differently depending on where it appears on the page. Context depth is configurable in Dashboard → Settings.

Dynamic content (MutationObserver)

After the initial scan, a MutationObserver watches for newly added DOM nodes. When new content appears (e.g., from a SPA route change or an AJAX response), Loco automatically discovers and registers those phrases too — no manual trigger needed.

You can pause/resume it:

Loco.stopScan(); // pause
Loco.startScan(); // resume
Loco.rescan(); // force a re-scan right now

Large page optimization

For pages with many text nodes, Loco uses collectPhrasesAsync — a batched traversal that yields to the browser between batches (100 nodes per batch) to avoid freezing the UI during the initial scan.