symfony/translation · error · InvalidResourceException

The pgs:switch token

Error message

The pgs:switch token "%s" must use the "type:variable" form.

What it means

Each whitespace-separated token in a pgs:switch attribute must be of the form type:variable. A token lacking the colon, or with an empty type or variable part, makes the loader throw InvalidResourceException naming the offending token.

Solutions

  1. Rewrite each token as type:variable with non-empty parts, e.g. "env:BRANCH os:PLATFORM".
  2. Check for stray whitespace/typos splitting a token incorrectly (the loader splits on any whitespace).
  3. Re-export the file from the tool with the pgs extension correctly configured.

Example fix

// before
<unit id="u1" pgs:switch="env: os">...</unit>
// after
<unit id="u1" pgs:switch="env:BRANCH os:PLATFORM">...</unit>
Defensive patterns

Strategy: validation

Validate before calling

foreach (preg_split('/\s+/', trim($pgsSwitch)) as $token) {
    if (!preg_match('/^[^:\s]+:[^:\s]+$/', $token)) {
        throw new \InvalidArgumentException(sprintf('Bad pgs:switch token: %s', $token));
    }
}

Try / catch

try {
    $catalogue = $loader->load($resource, $locale);
} catch (InvalidResourceException $e) {
    if (str_contains($e->getMessage(), 'must use the "type:variable" form')) {
        // rewrite tokens as type:variable per the message
    }
    throw $e;
}

Prevention

When it happens

Trigger: Loading an XLIFF 2.0 pgs unit whose pgs:switch contains a malformed token such as "env" (no colon), ":BRANCH" (empty type), or "env:" (empty variable).

Common situations: Hand-authored pgs extensions; tooling bugs emitting half-formed switch expressions; copy/paste edits that dropped the variable part.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15). Data as JSON: /api/errors/0efd79c031e09a2d. Report an issue: GitHub.

Appendix: source

Thrown at Loader/XliffFileLoader.php:263

                $metadata['notes'][] = $note;
            }
        }

        $catalogue->setMetadata($source, $metadata, $intlDomain);
    }

    private function parsePgsSwitch(string $pgsSwitch): array
    {
        $trimmed = trim($pgsSwitch);
        if ('' === $trimmed) {
            throw new InvalidResourceException('The pgs:switch attribute must not be empty.');
        }

        $switches = [];
        foreach (preg_split('/\s+/', $trimmed) as $item) {
            $parts = explode(':', $item, 2);
            if (2 !== \count($parts) || '' === $parts[0] || '' === $parts[1]) {
                throw new InvalidResourceException(\sprintf('The pgs:switch token "%s" must use the "type:variable" form.', $item));
            }
            $switches[] = ['type' => $parts[0], 'variable' => $parts[1]];
        }

        return $switches;
    }

    private function extractPgsSegmentText(\SimpleXMLElement $element, array $switches): string
    {
        $pluralVariables = [];
        foreach ($switches as $switch) {
            if ('plural' === $switch['type'] || 'ordinal' === $switch['type']) {
                $pluralVariables[$switch['variable']] = true;
            }
        }

        return $this->collectPgsText(dom_import_simplexml($element), $pluralVariables);
    }

View on GitHub (pinned to ae9e8a51bc)