---
id: noloc
title: 'Debugging with noloc'
description: 'Turn localization off to see raw localization tags instead of localized text — the fastest way to find out which tag drives a piece of UI or an API label.'
sidebar_label: 'Debugging with Noloc'
sidebar_position: 9
tags: ['api', 'localization', 'troubleshooting', 'debugging']
---

:::tip The single most useful trick in this section
`noloc` makes the localizer return every tag verbatim instead of translating it.
Suddenly every label in the product tells you its own tag — which is exactly the
information you need in order to override it, translate it, or request it from
`loc-2.v1`.
:::

## The Problem It Solves

Localization is a one-way function. A screen shows **Backlog Items**; you want
to rename it. To do that you need the tag, but the tag is nowhere in the output:

```json title="Normal output — informative for users, useless for debugging"
{
  "Plural'Story": "Backlog Items",
  "Command'Delete'Story": "Remove Backlog Items"
}
```

Worse, the mapping is not one-to-one. **Backlog Items** on one screen and
**Backlog Items** on another may come from different tags, and a single visible
string may be assembled from several tags via
[nested substitution](/apis/loc-2-v1/nested-tags). Guessing the tag from the
text is not a reliable technique.

With localization disabled, the localizer becomes the identity function and the
tags surface directly:

```json title="With localization disabled — every value is its own tag"
{
  "Plural'Story": "Plural'Story",
  "Command'Delete'Story": "Command'Delete'Story"
}
```

Now do the same thing in the product UI and read the tags straight off the
screen.

## Turning It on in Agility

Agility reads a `NoLoc` application setting. It ships commented out:

```xml title="user.config"
<!-- <add key="NoLoc" value="true" /> -->
```

Uncomment it, set it to `true`, and restart the application.

:::warning Read the two constraints before you use this
- **It is server-wide.** Every user of the instance sees raw tags, not just you.
  Never enable it on production or on a shared environment anyone is relying on.
- **It is read once at startup**, into a static field. Toggling it requires an
  application restart in both directions, and it is not affected by
  [hot reload](/apis/loc-2-v1/hot-reload).
:::

Use it on a local instance.

## Worked Example: Finding the Tag Behind a Label

Suppose the Delete action on a Story reads **Remove Backlog Items** and you have
been asked to change the word *Remove*.

**1. Confirm what you get normally.** (The values below are from an illustrative
instance where the `Story` asset type has been renamed to `Backlog Item`; yours
will differ.)

```bash
curl -sS "https://dev.example.com/VersionOne/loc-2.v1?[Command'Delete'Story]" \
  -H "Accept-Language: en-US"
```

```json
{ "Command'Delete'Story": "Remove Backlog Items" }
```

**2. Enable `NoLoc` and restart.** Then reload the screen. Every label now
renders as its tag, so the button reads `Command'Delete'Story`. That is the
answer — but the endpoint will confirm it:

```bash
curl -sS "https://dev.example.com/VersionOne/loc-2.v1?[Command'Delete'Story]" \
  -H "Accept-Language: en-US"
```

```json
{ "Command'Delete'Story": "Command'Delete'Story" }
```

**3. Turn `NoLoc` back off and restart.** Now work out *which* template is
actually responsible, because it is probably not the tag you just found. Ask for
the pieces the tag is built from:

```bash
curl -sS "https://dev.example.com/VersionOne/loc-2.v1?[Command'Delete'Story,Plural'Story,Story]" \
  -H "Accept-Language: en-US"
```

```json
{
  "Command'Delete'Story": "Remove Backlog Items",
  "Plural'Story": "Backlog Items",
  "Story": "Backlog Item"
}
```

Read that top to bottom and the structure falls out:

- `Command'Delete'Story` has no template of its own. The
  [term-stack walk](/apis/loc-2-v1/tag-resolution) lands on `Command'Delete`,
  whose body is `Remove {Plural'2}`.
- `{Plural'2}` splices in term 2 of the original tag — `Story` — giving the
  nested tag `Plural'Story`, which resolves to `Backlog Items`.

:::note Do not probe the prefixes directly
It is tempting to also request `Command'Delete` and `Command` to "see the
template". Don't — you will get misleading answers, because a template is
expanded against whatever tag you asked for. `Command'Delete` has no term 2, so
`Remove {Plural'2}` becomes `Remove {Plural'}`, which resolves through the
generic `Plural={1}s` with an empty term and yields `Remove s`. Likewise a
generic `Command={1} {2}` asked for as bare `Command` yields an empty string.

Neither result is a bug, and neither tells you anything about the tag you
actually care about. Probe the real tag, plus the nested tags it references.
:::

So to change *Remove*, override `Command'Delete`, not `Command'Delete'Story`.
Overriding the longer tag would work for Stories and quietly leave every other
asset type alone — almost certainly not what was wanted.

**4. Apply the override** in the Terminology admin screen or in
`<culture>.Company.txt`, per
[Template sets](/apis/loc-2-v1/template-sets#the-set-stack-agility-actually-uses).

## Finding Text That Was Never Localized at All

The technique has a second use, which is what the library README highlights:
with localization off, **anything still rendering as normal English prose is
hard-coded**. Localized strings degrade to terse internal tags like
`Command'Delete'Story`; a hard-coded literal looks exactly the same as it did
before.

Scanning a screen with `NoLoc` on is therefore a fast audit for text that has
been missed by localization — the sentences that still read normally are the
bugs.

## Related Mechanisms

`NoLoc` is not the only switch, and they are easy to confuse.

| Mechanism | Scope | Where |
| --------- | ----- | ----- |
| `NoLoc` application setting | Server-wide, until restart | Agility — `Common/_user.config` |
| `V1.Config.noloc` | The browser client's own resolver | Agility's browser client |
| `?noloc` query-string parameter | One HTTP request | **Only** the localization engine's sample application |

:::warning `?noloc` does not work against Agility
The per-request `?noloc` query-string parameter is a feature of the
localization engine's **sample application**, which swaps in a no-op resolver
for the duration of the request.
Agility does not implement it. Appending `?noloc` to a `loc-2.v1` URL will be
parsed as a **tag** and echoed back to you as `{"noloc": "noloc"}` — which looks
deceptively like it worked.
:::

The client-side `V1.Config.noloc` short-circuits Agility's browser-side
localization resolver only. It does not affect `loc-2.v1` responses, which are
produced on the server.

## Related Topics

- [Tag resolution](/apis/loc-2-v1/tag-resolution) — reading the term stack you just uncovered
- [Nested tag substitution](/apis/loc-2-v1/nested-tags) — why one label needs several tags
- [Template sets and override order](/apis/loc-2-v1/template-sets) — where to put the override
- [Troubleshooting](/troubleshooting)
