← Plugin catalog
Business & Operations

Crowdin

Crowdin OÜ v1.8.0

Localize products with Crowdin

Create a free account to save this plugin.

From the developer

Declared limitations

  • Ad-hoc translation of pasted text is not a Crowdin project operation.
  • Requests about other issue trackers or tools stay out of scope.
  • Unrelated everyday questions must not trigger the app.

Not specified in the available declarations: capabilities, pricing & account requirements.

Sources & dates

Developer declarations; not independently tested. Listing last checked Nov 6, 2026. Package observed Nov 6, 2026.

View package source →

Description

From the marketplace listing

Crowdin connects ChatGPT and Codex to your own Crowdin localization projects. Everything runs inside your account, in projects you already have access to. What you can do: - Check translation progress by language - Find source strings and their translations - Look up glossary terms and translation memory - Review tasks, reports, labels, and comments - Make bounded changes: add labels, upload source files, start a translation build – the agent confirms before writing With the bundled Codex skills, you can also set up localization in a code repository, keep files in sync through the Crowdin CLI and GitHub Action, and write translator context and glossaries. Who it's for: Localization managers, product managers, and developers who already use Crowdin and want answers without switching tabs – how far along a language is, where a source string is used, whether a term is in the glossary, what a report says – or who want Codex to set up localization in a repo and keep it in sync.

Language: English · Automatically detected from descriptions.

Matches for “string”

Exact text from the indicated source. A mention alone does not establish support for your task.

Publisher full description

Crowdin connects ChatGPT and Codex to your own Crowdin localization projects. Everything runs inside your account, in projects you already have access to. What you can do: - Check translation progress by language - Find source strings and their translations - Look up glossary terms and translation memory - Review tasks, reports, labels, and comments - Make bounded changes: add labels, upload source files, start a translation build – the agent confirms before writing With the bundled Codex skills, you can also set up localization in a code repository, keep files in sync through the Crowdin CLI and GitHub Action, and write translator context and glossaries. Who it's for: Localization managers, product managers, and developers who already use Crowdin and want answers without switching tabs – how far along a language is, where a source string is used, whether a term is in the glossary, what a report says – or who want Codex to set up localization in a repo and keep it in sync.

Changes

No changes recorded yet. Follow this plugin to keep track of future changes.

First seen Oct 28, 2026. Last seen Nov 6, 2026.

Keywords

Files & skills

File archives

Plugin package50 files · 140 KBBrowse files →
Skill instructions
context-extraction5.09 KB

View saved version →

---
name: context-extraction
description: Writes meaningful ai_context values in Crowdin JSONL files for strings that need translator context. Use when extracting context, filling ai_context fields, adding context to ambiguous strings, or working with Crowdin JSONL context files.
---

# Context Extraction

## Information sources (priority order)

For each string, use these JSONL fields in order - stop when you have enough to write a confident `ai_context`:

1. `text` - the source string itself; always the primary signal
2. `key` - often encodes structure (e.g. `button.save`, `modal.title.delete_user`, `error.network.timeout`)
3. `context` - may contain a free-text description, a translator comment, a source file reference, or be empty; treat as supplementary and don't assume any specific format
4. Source files - only if `context` contains a parseable file path + line number and the string is still ambiguous; read ±10–15 lines around the reference to identify UI element type, surrounding component, and props

## Strings that need context

Prioritize these - skip strings that are already clear from `text` + `key` alone:

- Ambiguous short words - single verbs, nouns, or adjectives that change meaning depending on UI placement
- Color / status names - words that name a color, state, or category; could be a label, badge, or filter
- ICU / message format strings - strings with plural forms or named parameters whose meaning depends on what's being counted or substituted
- Strings with inline tags - text containing markup tags where the role of the tagged portion isn't clear from the string alone
- Short phrases with unclear scope - brief imperative or standalone phrases that could belong to multiple UI contexts

## Writing good `ai_context` values

- 1–3 sentences, written for a translator - not a developer
- State the UI element type (button, label, tab, tooltip, modal title, dropdown option, etc.) and where it appears
- For plurals: what entity is counted, what `#` is replaced with
- For inline tags: what the tagged portion renders as (link, code, bold text, etc.)
- For color/status names: whether it's a selectable option, badge, filter label, etc.
- Avoid file names and variable names unless they clarify meaning

### Examples

| String | Key | Good `ai_context` |
|--------|-----|-------------------|
| `"Red"` | `color.red` | `"Color option label in a color picker. Refers to the color red as a selectable choice."` |
| `"Blue"` | *(none)* | `"Color name used as a selectable option or status label. Clarify based on surrounding UI."` |
| `"{count, plural, one {# month} other {# months}}"` | `duration.months` | `"Displays a duration in months. '#' is replaced by the numeric count."` |
| `"Edit <0>src/App.tsx</0> and save to test HMR"` | *(none)* | `"Instructional UI message. The tagged portion is rendered as an inline code element highlighting a filename."` |
| `"New"` | `button.new` | `"Label for a button that creates a new item. The exact entity depends on the current page context."` |

## Orchestrated inputs (optional)

When another workflow invokes this skill with extra context, use it:

- App domain - a one-line description of what the product is. Prefix or fold it into placement descriptions where it disambiguates ("Button label in a coffee-brew logging app…").
- Source checkout - when the JSONL `context` field carries a `#: path:line` reference (PO uploads add these automatically) and the repo is available, read the surrounding code instead of guessing: identify the component type, the props, and what any placeholder is replaced with.

Neither input changes the safety rules below - still edit only `ai_context`.

## JSONL file safety rules

**Only ever edit the `ai_context` field value.** Never touch `id`, `key`, `text`, `file`, or `context`.

### Editing procedure

Single-string (1–5 lines): Use StrReplace scoped to the exact line. Target the `"ai_context":""` substring (or the full current value if already set):

```
old: "ai_

Preview of the first 4,000 characters. Read full instructions →

create-app25.1 KB

View saved version →

---
name: create-app
description: Build a Crowdin app end to end and leave the user with a published app they can click - scaffold it with @crowdin/serverless-apps-cli, write the UI with @crowdin/serverless-apps-sdk, publish it into their Crowdin or Crowdin Enterprise organization, and open it for them. Reach for this whenever someone wants something of their own inside the Crowdin UI - a panel in the translation editor, a tool or report in a project, a page in the organization menu, a dashboard over their projects - and also when they describe a localization chore they are tired of doing by hand. Covers phrasings like "create a Crowdin app", "add a tool to my Crowdin project", a bare "/create-app", and cases where the word "app" is never said. Also use it when a serverless Crowdin app already exists in the working directory and needs another module, a manifest change, or a republish. Not for the separate Crowdin CLI that syncs sources and translations through crowdin.yml.
---

# Create a Crowdin app

## Who is asking

A translator or a localization manager. They arrive with a chore they are sick of, not a specification: "show me how we translated this term before", "I want to see what the proofreader changed after me", "every Thursday I build this spreadsheet by hand".

They do not know what a module, a manifest, a scope, an editor mode or a project identifier is, and they do not know what this platform can and cannot do. They will not pre-check whether their idea is buildable, and they should not have to. **Every question you put to them must be answerable by someone who has never seen a line of code.** A question about module types, scopes, manifests, templates, editor modes, project ids or editions is a defect in this workflow, not a gap in the user.

When their request runs past what the platform allows, that is your problem to solve, not theirs to have avoided. See [when the platform says no](#when-the-platform-says-no).

## What you are actually building

A frontend-only React bundle that Crowdin loads into an iframe inside its own UI. There is no backend and no token in the app: the host executes Crowdin REST calls and keeps the app's persisted records ([Crowdin Storage](#when-the-app-needs-to-remember-something)) for you, under the session of whoever opened the app, limited to the scopes the manifest declares.

## Where the facts come from

The platform gains module types, manifest fields, SDK methods and scopes over time. This skill cannot keep up with that, and neither can your training data - so for **what exists**, fetch the docs. They ship a machine-readable variant of every page: append `.md` to any documentation URL, or take the whole set at once.

| Fetch this | For |
|---|---|
| [building-app/modules.md](https://crowdin.github.io/serverless-apps/building-app/modules.md) | The current module types and their `prepare*` functions |
| [reference/manifest.md](https://crowdin.github.io/serverless-apps/reference/manifest.md) | Manifest fields, module shapes, permissions |
| [reference/cli-commands.md](https://crowdin.github.io/serverless-apps/reference/cli-commands.md) | Commands and flags as released |
| [building-app/crowdin-api.md](https://crowdin.github.io/serverless-apps/building-app/crowdin-api.md) | The tokenless API client |
| [building-app/storage.md](https://crowdin.github.io/serverless-apps/building-app/storage.md) | Crowdin Storage - persisted shared, per-user and module-scoped records |
| [building-app/context.md](https://crowdin.github.io/serverless-apps/building-app/context.md) | Context, theme, events |
| [building-app/host-actions.md](https://crowdin.github.io/serverless-apps/building-app/host-actions.md) | Editor and host actions |
| [building-app/user-interface.md](https://crowdin.github.io/serverless-apps/building-app/user-interface.md) | The UI kit |
| [building-app/i18n.md](https://crowdin.github.io/serverless-apps/building-app/i18n.md) | Localization |
| [development/troubleshooting.md](https:

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 4 — file references are metadata, not package contents.

croql4.56 KB

View saved version →

---
name: croql
description: Helps write, fix, and optimize Crowdin CroQL expressions for strings, translations, TM segments, and glossary terms. Use whenever the user mentions CroQL, Crowdin filters, advanced editor filtering, "where" conditions for localization data, or API queries with a `croql` parameter, even if they do not explicitly ask for query syntax help.
---

# CroQL Skill

Use this skill to turn natural-language filtering goals into valid Crowdin CroQL expressions.

## Full documentation

- [Crowdin Query Language (CroQL) docs](https://support.crowdin.com/developer/croql/)

## What to produce

When helping with CroQL, return:

1. A primary CroQL expression.
2. A short explanation of why it matches the request.
3. One optional stricter or broader variant if the request is ambiguous.

## Quick workflow

1. Identify the data context:
   - Source strings
   - Language translations
   - TM segments
   - Glossary terms
2. Map user intent to CroQL fields and operators.
3. Build the query in small clauses and combine with `and`/`or`.
4. Validate likely pitfalls (wrong context field, missing language scope, unencoded query).
5. Provide the final query and ready-to-run endpoint sample.

## Core syntax cheatsheet

- Comparison: `=`, `!=`, `>`, `>=`, `<`, `<=`, `between ... and ...`, `contains`
- Logic: `and`, `or`, `xor`, `not`
- Filtering collections: `collection where (predicate)`
- Counting: `count of translations`, `count of comments where (...)`
- Object member access: `id of file`, `count of votes`
- Mentions:
  - User: `@user:"username"`
  - Language: `@language:"uk"`

## Context-aware query patterns

Pick fields that belong to the correct context. A frequent failure mode is using fields from a different context.

### 1) Source strings context

Common fields:

- `text`, `identifier`, `context`
- `is hidden`, `is duplicate`
- `count of translations`, `count of comments`, `count of screenshots`
- `count of languages summary where (...)`
- `id of file`, `added`, `updated`
- Enterprise fields filters:
  - `count of fields where (name = "Priority" and value = "High") > 0`

Examples:

- Hidden non-duplicates with translations:
  - `is hidden and not is duplicate and count of translations > 0`
- Source contains `ABC`, but translations do not:
  - `text contains "ABC" and count of translations where (text contains "ABC") = 0`
- At least one approval in any language:
  - `count of languages summary where (approvalsCount >= 1) > 0`

### 2) Translation context

Common fields:

- `text`, `plural form`, `is pre translated`, `provider`, `user`, `updated`
- Nested: `count of votes where (is up)`, `count of approvals where (...)`

Example:

- By specific user or highly upvoted:
  - `user = @user:"crowdin" or count of votes where (is up) >= 100`

### 3) TM segment context

Common structure is record-based:

- `count of records where (usageCount > 0) > 0`
- `count of records where (createdBy = @user:"crowdin") > 0`

### 4) Glossary term context

Common fields:

- `text`, `description`, `language`, `user`, `partOfSpeech`, `status`, `type`, `gender`
- `note`, `lemma`, `url`, `createdAt`, `updatedAt`

Examples:

- Obsolete or not recommended:
  - `status = "not_recommended" or status = "obsolete"`
- English lemma:
  - `lemma = "cancel" and language = @language:"en"`

## Advanced editor-style filters

These are frequent requests from users trying to mirror UI filters in API calls:

- Untranslated:
  - `count of languages summary = 0`
- Translated:
  - `count of languages summary where (is translated) > 0`
- Approved:
  - `count of languages summary where (is approved) > 0`
- Has QA issues:
  - `count of languages summary where (has qa issues) > 0`
- Duplicates only:
  - `is duplicate`

If target language matters, scope it explicitly:

- `count of languages summary where (language = @language:"uk" and is translated) > 0`

## Query construction strategy

When a user request is underspecified:

1. Start with the strictest interpretation.
2. O

Preview of the first 4,000 characters. Read full instructions →

crowdin-api-client5.15 KB

View saved version →

---
name: crowdin-api-client
description: Use when implementing, refactoring, or reviewing `@crowdin/crowdin-api-client` usage in any JavaScript or TypeScript project, especially for endpoint selection, request/response typing, pagination, uploads, retries, timeouts, or `CrowdinError` handling.
---

# Crowdin API Client

## Overview

Use this skill when touching Crowdin API integration code in any project that depends on `@crowdin/crowdin-api-client`.
Core principle: verify local client typings first, then implement with strict model types and correct response envelope handling.

## When to Use

- New or changed calls to `@crowdin/crowdin-api-client`.
- Compile/type errors after API-client upgrades.
- Confusion about method names, request fields, or `ResponseList` vs `ResponseObject`.
- Refactors involving uploads, file translations, screenshots, tasks, comments, strings, or projects.
- Reviews where behavior works at runtime but types/mapping look suspicious.
- Multi-step flows: build and download, pre-translate, upload or update files, label strings and open a task, TM or glossary import, reports. Start from [references/recipes.md](references/recipes.md) instead of composing the calls from memory.

Do not use this skill for unrelated infra-only changes.

## Required Preflight (Before Editing)

1. Check local declarations first: `node_modules/@crowdin/crowdin-api-client/out/<module>/index.d.ts`.
2. Confirm exact API class and method name in use.
3. Confirm request model type and required fields.
4. Confirm response envelope: `ResponseList<T>` or `ResponseObject<T>`.

Do not code from memory when typings and docs disagree.

## Quick Reference

| Scenario | Preferred Pattern |
|---------|-------------------|
| Multi-module flow | `new Client(credentials, options)` and destructure needed APIs |
| Single narrow flow | Direct module API class is acceptable |
| Full collection reads | `.withFetchAll()` |
| Transient failures | `retryConfig` |
| Bounded request duration | `{ httpRequestTimeout: 60_000 }` |
| Uploads | `uploadStorageApi.addStorage` -> `sourceFilesApi.createFile` |
| Long-running operations (builds, pre-translation, imports, exports, reports) | Poll the matching `check...Status` method with a delay; stop on `finished`, `failed` or `canceled` — [recipes](references/recipes.md#helpers-wait-save-chunk) |
| Error branching | `CrowdinValidationError` before `CrowdinError` |

## Core Patterns

### Bootstrap

```ts
import { Client, Credentials } from '@crowdin/crowdin-api-client';

const credentials: Credentials = {
  token: process.env.CROWDIN_PERSONAL_TOKEN!,
  organization: process.env.CROWDIN_ORGANIZATION, // Crowdin Enterprise only
};

const client = new Client(credentials);
```

### Response Envelope Handling

```ts
const listResponse = await client.tasksApi.withFetchAll().listTasks(projectId, options);
const tasks = listResponse.data.map((entry) => entry.data); // ResponseList<T>

const createResponse = await client.tasksApi.addTask(projectId, request);
const task = createResponse.data; // ResponseObject<T>
```

### Typed Request Models

```ts
const request: TasksModel.CreateTaskRequest = {
  title: 'My Task',
  languageId: 'de',
  type: 0,
  fileIds: [12],
};
```

### Error Handling

```ts
import { CrowdinError, CrowdinValidationError } from '@crowdin/crowdin-api-client';

try {
  // API call
} catch (error) {
  if (error instanceof CrowdinValidationError) throw error;
  if (error instanceof CrowdinError) throw error;
  throw error;
}
```

## Common Mistakes

| Mistake | Fix |
|---------|-----|
| Guessing endpoint methods from memory | Validate in local `index.d.ts` first |
| Treating list response as object response | Check `ResponseList<T>` vs `ResponseObject<T>` and map accordingly |
| Weakening or bypassing model typing | Use client `*Model` types in service signatures and fixtures |
| Manual pagination loops by default | Prefer `.withFetchAll()` unless custom batching is required |
| Uploading file directly to `

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 1 — file references are metadata, not package contents.

crowdin-cli11.2 KB

View saved version →

---
name: crowdin-cli
description: Guides correct usage of Crowdin CLI - the `crowdin` command that syncs localization files between a local project and Crowdin. Use whenever the user runs, scripts, or debugs `crowdin` commands, authorizes the CLI, creates or edits a crowdin.yml configuration, uploads sources, downloads translations, checks translation status, auto-translates a project, wires localization into CI/CD, or migrates scripts from CLI v4 to v5 - even if they just say "sync translations" or "push strings to Crowdin" without naming the CLI.
---

# Crowdin CLI

Crowdin CLI is the command-line tool for managing and synchronizing localization resources with a Crowdin project. It ships as a single self-contained binary — no Java or other runtime required.

Check what's installed with `crowdin --version`. If it prints `4.x` or a Java error, the user is on the legacy CLI — commands below still mostly apply, but see [references/migrating-from-v4.md](references/migrating-from-v4.md) for the differences.

Full documentation: https://crowdin.github.io/crowdin-cli

## Install

```bash
npm install -g @crowdin/cli
```

Also available via Homebrew (`brew tap crowdin/crowdin && brew install crowdin@5`), WinGet, Chocolatey, Docker (`crowdin/cli`), Linux package repositories, and as a standalone binary — see [references/configuration.md](references/configuration.md#installation) for every option.

## Authenticate

The CLI needs an **API token** and (for most commands) a **project ID**. On a developer's machine the quickest route is:

```bash
crowdin login
```

It authorizes in the browser and saves the token to the identity file `~/.crowdin.yml`, where every later command — run by the user or by an agent — picks it up. No configuration file is generated or required, and Crowdin Enterprise needs nothing extra: the organization comes from the account signed in. `crowdin init` runs the same browser authorization and then generates a `crowdin.yml`; `login` is the choice when the config is written by hand or already exists. The flow finishes through a browser callback on the same machine, so when the agent's shell may be elsewhere, the user runs it in their own terminal. The browser-issued token expires after 30 days — re-run `crowdin login` when a command exits `101`. Details: [references/commands.md](references/commands.md#login).

For CI and anything long-lived, use a **personal access token** — it does not expire:

- crowdin.com: create the token in **Settings → API** (`https://crowdin.com/settings#api-key`). `base_url` is `https://api.crowdin.com` (the default — no need to set it).
- Crowdin Enterprise: create it in **Account Settings → Access Tokens**. `base_url` must be set to `https://{organization}.api.crowdin.com`.

The project ID is numeric — get it with `crowdin project list` once a token is configured (add `-i 1` while no `crowdin.yml` carries a `project_id`: validation demands one even though this command ignores it), or from the project page in Crowdin.

Credentials resolve in this priority order (highest wins):

1. CLI flags: `-T/--token`, `-i/--project-id`, `--base-url`, `--base-path`
2. Identity file: `--identity <path>`, or `~/.crowdin.yml` / `~/.crowdin.yaml` if present
3. `*_env` keys in the config file (`api_token_env: MY_VAR` reads `$MY_VAR`)
4. Literal keys in the config file (`api_token: "..."`)
5. `CROWDIN_PERSONAL_TOKEN`, `CROWDIN_PROJECT_ID`, `CROWDIN_BASE_PATH`, `CROWDIN_BASE_URL` environment variables

`.env` files in the working directory are loaded automatically, so `CROWDIN_PERSONAL_TOKEN` can live there. **Never write a real token into `crowdin.yml`** if the file is committed — use `api_token_env` or the `CROWDIN_PERSONAL_TOKEN` variable instead. A committed `api_token_env` and a local `crowdin login` coexist: the unset variable contributes nothing, so the identity file supplies the token on the developer's machine and the variable supplies it in CI.

## Configure — crowdin.yml

Commands read `crowdin.yml`

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 3 — file references are metadata, not package contents.

crowdin-context-cli5.11 KB

View saved version →

---
name: crowdin-context-cli
description: Documents the Crowdin CLI context commands (download, upload, status, reset) for AI enrichment. Use when downloading or uploading strings context for Crowdin, checking context coverage, resetting AI-generated context, managing context files, or running crowdin context commands.
---

# Crowdin Context CLI

Use the Crowdin CLI for context download and upload. Config is read from `crowdin.yml` by default; override with `-c, --config=<path>` if needed.

```
crowdin context <command> [options]
```

## context download

Download strings context to a separate file for enrichment by AI Agent.

```
crowdin context download [CONFIG OPTIONS] [OPTIONS]
```

- `--to=<path>` — File path to download the context to. Default: `crowdin-context.jsonl`
- `-f, --file=<glob>` — Filter strings by Crowdin file paths (glob). Multiple paths can be specified
- `--label=<label>` — Filter strings by labels. Multiple labels can be specified
- `-b, --branch=<name>` — Filter by branch name
- `--croql=<expr>` — CroQL expression (cannot be combined with the other filter options)
- `--since=<YYYY-MM-DD>` — Only strings created after this date
- `--status=<value>` — Which kind of context a string already has: `empty` (none of any kind), `manual` (source context, no AI context), `ai` (AI context written). See below — this is not a filter for "still needs context"

Config options (if not using a config file): `-T, --token`, `-i, --project-id`, `--base-url`, `--base-path`. Use `-c, --config=<path>` to override config file (default: `crowdin.yml` or `crowdin.yaml`).

**Which `--status` selects the strings needing AI context depends on the source format, so prefer omitting it.** A format that carries source references into Crowdin — PO `#:` lines, for one — leaves every string holding manual context, so `empty` matches nothing and `manual` matches everything; a format carrying no context at all inverts that. With no `--status` the download covers both cases in one call, and costs nothing extra: `context upload` writes back only the records whose `ai_context` was actually filled.

## context upload

Upload strings context. Only files previously downloaded by `context download` are supported.

```
crowdin context upload [CONFIG OPTIONS] [OPTIONS]
```

- `--from=<path>` — File path to upload the context from. Default: `crowdin-context.jsonl`
- `--overwrite` — Also update strings where `ai_context` is empty (removes their AI section). Default: false
- `--dryrun` — Print command output without execution

## context status

Show context coverage statistics — how many strings have manual, AI, or no context.

```
crowdin context status [CONFIG OPTIONS] [OPTIONS]
```

- `-f, --file=<glob>` — Filter strings by Crowdin file paths (glob). Multiple paths can be specified
- `--label=<label>` — Filter strings by labels. Multiple labels can be specified
- `-b, --branch=<name>` — Filter by branch name
- `--croql=<expr>` — CroQL expression (cannot be combined with the other filter options)
- `--since=<YYYY-MM-DD>` — Only strings created after this date
- `--by-file` — Break statistics down per file

## context reset

Remove AI-generated context from strings; manually written context is preserved.

```
crowdin context reset [CONFIG OPTIONS] [OPTIONS]
```

- `-f, --file=<glob>` — Only reset strings from matching file paths. Multiple paths can be specified
- `--label=<label>` — Only reset strings with matching labels. Multiple labels can be specified
- `-b, --branch=<name>` — Only reset strings from the matching branch
- `--croql=<expr>` — Only reset strings matching the CroQL expression (cannot be combined with the other filter options)
- `--since=<YYYY-MM-DD>` — Only reset strings created after this date
- `--dryrun` — Print command output without execution
- `--all` — Required safety flag when no filter is specified

## JSONL format

One JSON object per line. Fields:

- `id` — String ID in Crowdin
- `key` — String key
- `text` — Source text
-

Preview of the first 4,000 characters. Read full instructions →

feedback7.92 KB

View saved version →

---
name: feedback
description: Drafts feedback about Crowdin for the Crowdin team - the skills in this plugin, the Crowdin MCP server, the Crowdin CLI, the Crowdin API or the product - and sends it as a GitHub issue in crowdin/skills only when the user explicitly asks. Use when the user asks to report or file something about Crowdin; after a Crowdin skill instruction, CLI command, MCP tool call or API call failed reproducibly and was just fixed or given up on; when the user is clearly frustrated with a Crowdin component; or when a Crowdin capability the user expected does not exist and blocked the task. Feedback about the agent itself belongs to the agent's own feedback mechanism.
---

# Feedback

Turns a problem with a Crowdin component (a skill in this plugin, the Crowdin MCP server, the Crowdin CLI, the Crowdin API, the product) into a short, factual draft on the user's machine and, only when the user asks, into a GitHub issue the Crowdin team reads.

## When to draft

Draft at high-signal moments, with or without being asked:

- The user asks: "report this", "file feedback", "this should be an issue", "tell Crowdin about this", "the skill was wrong about X".
- A Crowdin skill instruction, CLI command, MCP tool call or API call failed reproducibly and was just fixed or given up on.
- The user expressed clear frustration with a Crowdin component.
- A Crowdin capability the user reasonably expected does not exist and blocked the task.

Type each draft as one of `bug` (something behaves differently from what the documentation, the skill or the user reasonably expected), `idea` (a change that would have made the task easier) or `missing_capability` (something Crowdin cannot do that blocked the task).

One draft per distinct problem per session. Before writing, list `~/.crowdin/feedback/`; if a draft there describes the same problem, update it rather than create a second one. The same failure hit twice in different places is still one problem.

Drafting is silent. Finish the current reply as you would have, then add one line at the very end: `Drafted feedback about <short title> to ~/.crowdin/feedback/<file>. Say "send feedback" to review and send it.` That line is the only trace of the draft in the reply; questions about it wait until the user brings it up. When the user asked for the draft explicitly, show the draft in the reply instead of that line.

## Where drafts live

Write drafts to `~/.crowdin/feedback/<yyyy-mm-dd>-<slug>.md`, where the slug is three to six lowercase words joined by hyphens that name the problem. Create the folder on first use. The folder sits outside any repository, so a draft is never committed with the user's code.

Assume no shell exists until you see one. Where there is no filesystem or shell, as in Claude Cowork, ChatGPT or a skill uploaded to Claude.ai, put the same draft inline in the reply and store nothing; the user copies it from there.

## The draft

The file body is exactly what will become the issue body: no YAML frontmatter, since GitHub renders `---` in an issue as a horizontal rule. Labeled lines in this order, one to three lines each, facts only, no narrative:

```markdown
**Type:** bug
**Component:** api
**Agent:** Claude Code 2.1.269
**Plugin version:**

**What happened:** `POST /api/v2/projects/{projectId}/translations/builds` returned 500 with `{"error":{"message":"Internal Server Error"}}` for a project with one branch and eight target languages. Expected a build identifier, or a 4xx that names what is wrong with the request.
**What the user said:** "third time today, I can't ship without the build"
**Repro:** Call the endpoint with an empty JSON body on a file-based project that has one branch; three attempts one minute apart returned the same response.
**Evidence:** 2026-09-14T10:32:07Z, 10:33:11Z and 10:34:20Z (UTC); the request body was `{}`; the same call on a project without branches succeeded.
```

- `Component` is the skill name for a skill (`crowdin-cli`, `how-to-crowdin

Preview of the first 4,000 characters. Read full instructions →

github-action13.5 KB

View saved version →

---
name: github-action
description: Sets up and debugs the Crowdin GitHub Action (crowdin/github-action), which syncs a repository with a Crowdin project and opens the translation pull request. Use whenever the user wires Crowdin into GitHub Actions, writes or reviews a .github/workflows/crowdin.yml step, tunes its inputs (upload_sources, download_translations, localization_branch_name, create_pull_request, command), or debugs a run that opened no pull request, opened one that gets no CI checks, or hit a 409 while a build was in progress - including bare phrasings like "automate translations in CI" or "my Crowdin workflow is broken".
---

# Crowdin GitHub Action

`crowdin/github-action` runs [Crowdin CLI](https://crowdin.github.io/crowdin-cli) inside a Docker container as a single workflow step: it uploads source files to Crowdin, downloads finished translations, commits them to a localization branch, and opens a pull request.

Because it is a Docker action it only runs on **Linux** runners — `ubuntu-latest`, or a self-hosted Linux runner with Docker available. It will not run on `macos-*` or `windows-*`.

Reference: [README](https://raw.githubusercontent.com/crowdin/github-action/refs/heads/master/README.md) · [examples](https://raw.githubusercontent.com/crowdin/github-action/refs/heads/master/docs/EXAMPLES.md) · [inputs and outputs](references/inputs.md) · [workflow recipes](references/recipes.md)

## The step is a pipeline, not a command

One step performs up to five operations, always in this fixed order, and each one is gated by its own input:

| Order | Input | Runs |
|---|---|---|
| 1 | `upload_sources: true` *(default)* | `crowdin upload sources` |
| 2 | `upload_translations: true` | `crowdin upload translations` |
| 3 | `download_sources: true` | `crowdin download sources`, then the **git half** |
| 4 | `download_translations: true` | `crowdin download`, then the **git half** |
| 5 | `download_bundle: <id>` | `crowdin bundle download <id>`, then the **git half** |

The **git half** is a single unit of work: `git add .`, commit, force-push the localization branch, open the PR. Its parts are individually switchable (`push_translations`, `push_sources`, `create_pull_request`), and only rows 3–5 can reach it.

That order explains nearly every surprise the action produces:

- **`upload_sources` defaults to `true`.** A step you intended as download-only also pushes your sources to Crowdin unless you write `upload_sources: false`. Set every flag you care about explicitly rather than relying on defaults.
- **The git half runs only after a download.** `create_pull_request: true` on an upload-only step is inert — there is nothing to commit.
- **Two downloads in one step run the git half twice** — two commits to the same localization branch, under one PR.
- **The git half commits with `git add .`** — everything dirty in the workspace goes in, including files earlier steps generated. Keep the Crowdin step ahead of any build steps, or give it its own job.
- **Every run with changes force-pushes**, so an open translation PR is rewritten rather than appended to — which is why its checks start over each time.

## Setting it up

Two of the five steps belong to a human: the repository secrets in step 2 and the pull-request setting in step 4 need someone with repository admin access clicking through the GitHub UI. Hand that list over explicitly rather than assuming it is already in place — a workflow that is perfect on disk still fails its first run without them.

### 1. Configure `crowdin.yml`

The action reads the same `crowdin.yml` as the CLI — the [crowdin-cli](../crowdin-cli/SKILL.md) skill covers `files`, placeholders, and language mapping. Three parts matter specifically here:

```yaml
"project_id_env": "CROWDIN_PROJECT_ID"
"api_token_env": "CROWDIN_PERSONAL_TOKEN"
"preserve_hierarchy": true

files:
  - source: "/src/locales/en/**/*.json"
    translation: "/src/locales/%two_letters_code%/**/%original_file_name%"
```

- `project_

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 2 — file references are metadata, not package contents.

glossary-generation8.79 KB

View saved version →

---
name: glossary-generation
description: Generates a starting glossary for a Crowdin project from the project's own source strings and uploads it with the Crowdin CLI. Use when someone wants to create a glossary, extract key terms or terminology from an app's strings, mark product and feature names as do-not-translate, or seed a Crowdin project with consistent vocabulary - including bare phrasings like "make a glossary for my project". Terms are drafted for review and never uploaded unseen, and translations are never invented. Not for managing an existing glossary's entries one by one, and not for the full internationalize-and-connect journey (that is i18n-setup, which delegates here).
---

# Glossary generation

Translators meet a product's vocabulary one string at a time, with no way to tell which words are the product's own. A glossary is where a term gets decided once — translated one way everywhere, or not translated at all — and it is worth most before the first translation is made rather than after fifty of them disagree.

The glossary this skill produces is a **starting point, not a finished asset**. Ten to thirty terms a localization manager can accept, edit, or delete beats two hundred that read as noise; the second kind gets deleted wholesale, which also throws away the few good entries in it. Treat forty terms as a hard ceiling, and prefer leaving a doubtful term out — a missing entry costs one inconsistent translation, a wrong one teaches every translator the wrong answer.

For the `glossary` command's full flag set, read the `crowdin-cli` skill's [commands reference](../crowdin-cli/references/commands.md#glossary); below are only the flags this skill passes.

## Inputs

Three things, resolved before any term is picked:

- **The source strings.** Read the **source catalog** — the file `crowdin.yml` uploads, at its resolved `source` pattern — not the source tree. Those are exactly the strings translators will see, already stripped of code. When there is no `crowdin.yml`, ask the user where the source-language strings live rather than scanning code for them.
- **A one-line product description.** This is what makes "brew" a domain term in a coffee-logging app and an ordinary verb anywhere else; without it, term selection degenerates into picking capitalized words. Ask for it if nothing in the conversation or repository supplies one.
- **A draft location outside version control** — a scratch directory, or a gitignored path the caller names — so a rejected draft never lands in the repository.

## What earns an entry

A term qualifies when a translator, seeing it in one string with no other context, could reasonably get it wrong. In practice that is four kinds:

- **Product and feature names.** Brand names, plan names, named surfaces — usually the entries that say *do not translate this*. This is the single most valuable category and the one most often missing.
- **Domain vocabulary the product leans on.** Words with a specific meaning in this product's world, particularly ones that recur across strings.
- **Words that are ambiguous out of context.** English's noun/verb pairs are the classic case: on its own, a `Log` label could be a record or an action, and a translator has to pick a word class before they can pick a word.
- **UI objects that must stay consistent with each other.** When a product distinguishes two similar things, translating them to the same word collapses a distinction the interface depends on.

Recurrence is the strongest signal: a term in two or more source strings is a candidate on frequency alone. A term appearing once needs one of the other reasons — a brand name earns its entry the first time it is used.

**What does not earn an entry:** ordinary UI verbs every translator has already translated a thousand times (`Save`, `Cancel`, `Delete`) unless this product uses one in a non-obvious way; whole sentences or message strings, which are strings to translate rather than terms to define; and anyth

Preview of the first 4,000 characters. Read full instructions →

graphql4.41 KB

View saved version →

---
name: graphql
description: Write valid, schema-aware Crowdin GraphQL queries and debug invalid ones. Use this whenever the user asks for Crowdin GraphQL queries, filters, pagination, sorting, or when they share GraphQL errors from Crowdin Playground (especially unknown argument/field errors) and need a corrected query that actually matches the schema.
---

# Crowdin GraphQL Query Writing

Use this skill to produce valid Crowdin GraphQL queries that match the live schema, avoid unsupported arguments, and include practical pagination/filtering patterns.

## What to Deliver

Return:
1. A working GraphQL query.
2. A short explanation of how it works.
3. If relevant, a corrected version of the user's broken query plus a brief "what was wrong".
4. Optional: variables object when it improves readability.

## Core Workflow

### 1) Confirm intent and scope

Identify:
- Target resource (projects, strings, translations, etc.).
- Required constraints (language, dates, status, user, approval state).
- Output fields user needs.

If the request is ambiguous, choose a conservative default and say so briefly.

### 2) Build from schema-safe primitives

Use this sequence:
1. Pick the root field that actually exposes the target connection.
2. Add required pagination arguments (`first` or `last`) on every connection.
3. Add nested selections (`edges -> node`) and only requested fields.
4. Add filtering/sorting only where the schema supports it.

Do not invent arguments by analogy with REST parameters.

### 3) Validate against common Crowdin GraphQL constraints

Before finalizing:
- Every queried connection has `first` or `last` (1..10000).
- Estimated total requested nodes stay under 10,000.
- Query includes `pageInfo` when pagination is likely needed.
- Query avoids unsupported arguments on a field.

### 4) Add safe pagination pattern

Prefer cursor pagination:
- Forward: `first` + `after`
- Backward: `last` + `before`

If user asks for "from date X to date Y", use supported `filter` input fields (for resources that expose them), not ad-hoc args.

## High-Risk Mistakes to Prevent

### Unknown argument errors

If the user query contains field arguments that are not in the schema, rewrite the query using supported alternatives.

Example anti-pattern from real failures:
- `translations(..., createdAfter: "...", createdBefore: "...")`

Fix strategy:
1. Remove unsupported args.
2. Keep supported args like `languageId`, `first`, `after`.
3. If date constraints are required, move them to a supported `filter` input on fields that provide one (or explain that this field does not expose date filtering directly).

### Missing required pagination arguments

Crowdin GraphQL connections require `first` or `last`. Never omit them.

### Over-fetching

Do not request large nested fan-outs without reason. Keep node count budgeted.

## Query Patterns

### Pattern A: Minimal safe connection query

```graphql
query GetProjects($first: Int!, $after: String) {
  viewer {
    projects(first: $first, after: $after) {
      edges {
        node {
          id
          name
        }
        cursor
      }
      pageInfo {
        hasNextPage
        endCursor
      }
      totalCount
    }
  }
}
```

### Pattern B: Filtering + ordering (where supported)

```graphql
query FilteredProjects {
  viewer {
    projects(
      first: 10
      filter: { createdAt: { gt: "2023-01-01T00:00:00Z" } }
      order: [{ lastActivityAt: asc }]
    ) {
      edges {
        node {
          id
          name
          lastActivityAt
        }
      }
    }
  }
}
```

### Pattern C: Rate limit awareness

```graphql
query MeAndCost {
  viewer {
    username
  }
  rateLimit {
    limit
    cost
    remaining
    resetAt
  }
}
```

## Debugging Template

When the user provides an error, follow this output format:

1. **Cause**: one sentence pointing to schema mismatch.
2. **Fixed query**: full corrected query.
3. **Why this works**: 2-4 bullets tied to schema rules.
4. **If date filtering

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 1 — file references are metadata, not package contents.

how-to-crowdin21 KB

View saved version →

---
name: how-to-crowdin
description: Answers "how do I do X in Crowdin" by mapping a localization pain to the cheapest thing Crowdin already offers - a built-in feature, a few actions through the Crowdin connector or API, an app from the Crowdin Store, or a custom app - and handing the exact how to the skill that owns it. Use whenever someone describes a Crowdin or localization problem without naming a tool ("translators keep missing our terminology", "find strings changed since the last release", "QA passes but the German is wrong"), asks whether Crowdin can do something, asks which Crowdin app to use, or names a store app and wants to know what it does or whether they need it. Not for a crowdin CLI command or crowdin.yml (crowdin-cli), a CroQL expression already in hand (croql), a GraphQL query or Playground error (graphql), code against the API client (crowdin-api-client), building an app (create-app), or internationalizing a codebase (i18n-setup).
---

# How to Crowdin

Crowdin usually offers several ways to solve the same localization problem: a setting the user never found, a few actions on their strings, an app from the Crowdin Store, or something built for the job. Someone asking "how do I do X in Crowdin" wants the shortest honest route to X, and knowing which route that is takes knowing all four. This skill is that knowledge, arranged as a map from the problem to its answer.

You are a **triage layer**, not an execution layer. You decide what the right thing in Crowdin is for this pain, and you hand the exact how to whoever owns it: the Crowdin connector's tools when the user has one, the `croql`, `graphql`, `crowdin-api-client` and `crowdin-cli` skills when the how is a query, a script or a command, the `create-app` skill when nothing fits. You never improvise API calls or filter syntax that one of those owns.

## Who is asking

Usually a localization manager working through an AI assistant with the Crowdin connector, in Cowork, Claude.ai or ChatGPT. Sometimes a developer in a terminal. Assume no shell exists until you see one. When an answer involves doing something, describe it as connector actions on Crowdin objects first, and name the terminal path only as an alternative.

## The ladder

Every answer sits on one **rung**, and you try them cheapest first:

1. **Native feature** the user did not know about. Labels plus a filter, a QA check, a workflow step, a report, a setting.
2. **Connector actions.** A short sequence you perform on demand through the Crowdin connector or API, described at the level of Crowdin objects: filter strings, add a label, create a task, pre-translate a set, pull a report. The same sequence runs as REST calls in a terminal, so there is never a second version to write.
3. **Store app.** Installed from store.crowdin.com.
4. **Custom app.** Nothing fits; hand off to `create-app`.

The rung 2 test decides most disputes. A job is rung 2 when it is a read, a filter, a bulk edit or a report over Crowdin's own data, done when the user asks. It stops being rung 2 when it needs continuous watching (webhooks, schedules), an external system (a CMS, a repo host, a chat tool, a design tool), a file parser, an MT or AI provider connection, a UI inside the Crowdin editor, or a model pass over thousands of strings that the user needs again next week. Be honest in both directions: overstating rung 2 sends people to do by hand what an app does better, understating it pushes an install where a filter would do.

When rung 3 or 4 wins, say in one line each why the cheaper rungs lost. That line is what tells the user the answer was weighed rather than guessed, and it is what makes an install worth paying for when an install is genuinely the answer.

## The flow

1. **Restate the pain in Crowdin terms.** Users describe symptoms: "the German is wrong", "translators ignore our terms". Name the Crowdin objects underneath before you answer: strings, translations, TM, glossary, workflow step, QA check, task, report

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 1 — file references are metadata, not package contents.

i18n-setup28.5 KB

View saved version →

---
name: i18n-setup
description: Takes a project from hardcoded strings to internationalized, connected to Crowdin, and translating continuously. Use when someone wants to add i18n or multi-language support, internationalize an app, extract hardcoded strings, set up Lingui (or another i18n library), or connect Crowdin to a repository - including connect-only, "my app already uses i18next/next-intl/vue-i18n/Lingui, wire it to Crowdin". Not for individual `crowdin` CLI commands or crowdin.yml syntax (that is `crowdin-cli`), not for editing Crowdin context files or `ai_context` on their own (`context-extraction`, `crowdin-context-cli`), not for generating a glossary alone (`glossary-generation`), and not for building Crowdin apps (`create-app`).
---

# i18n Setup

This skill orchestrates the journey: the phase sequence, the decisions, and the filesystem workspace those decisions live in. Library-specific work runs through the library's own skills, routed by `manifest.json`; this skill does the Crowdin side of each phase and verifies the delegated work on disk. For any `crowdin` command's syntax and semantics, read the `crowdin-cli` skill.

Load references lazily: read `manifest.json` when phase 2 starts, and read a reference only when the step that needs it is the step you are on. A phase you skip should cost nothing.

## The journey

| Phase | Name | Produces | Credentials |
|---|---|---|---|
| 1 | Detect | `.crowdin/detection.json` | none |
| 2 | Decide | `decisions.md`, `manifest-snapshot.json`, `plan.md` | none |
| 3 | Setup | i18n library installed, configured, catalogs scaffolded, `.agents/crowdin-i18n-rules.md` rendered | none |
| 4 | Wrap | every user-visible string wrapped, catalogs populated, build green | none |
| 5 | Connect | `crowdin.yml`, verified config, sources uploaded | **token gate** |
| 6 | Context | `ai_context` written for the new strings, a starting glossary uploaded | token |
| 7 | CI | sync workflow + the secret instruction for the user | token (as a CI secret) |

Two entry points share this spine, and phase 2 decides which: the **full journey** runs all seven phases; **connect-only** — the project is already internationalized — omits phases 3–4 entirely rather than emitting no-op steps. Everything before phase 5 is offline; the token gate opens phase 5 — say so at the end of phase 2, so the user can authorize the CLI while phases 3–4 run.

## Execution model

> The plan is a linear checklist. Execute steps in order on the main thread. If your environment provides a subagent/task tool, you may dispatch the convert phase's file partitions as parallel workers that write `progress/wrap-N.json`; collect them all before the verify step. Never require this: a run with no subagent support must produce an identical end state, just serially.

Two rules are correctness, not architecture, and hold in both modes:

- **Extraction runs once, after all wrapping is done.** Parallel writers pointed at one catalog race and lose messages. Wrap every file first, then extract a single time.
- **Ambiguity is stop-and-ask, never improvisation.** If a reference does not cover the case in front of you — an odd config layout, two i18n libraries present, a string you cannot tell is user-visible — stop and ask. Guessing produces plausible code that breaks a build the user has to debug later.

Package installs always run on the main thread, never inside a worker — including when a delegated skill does the installing — so the lockfile stays consistent.

## The workspace

```
.crowdin/
  detection.json          # phase 1 output: stack, existing i18n, candidate files, locale signals
  decisions.md            # frozen user choices: entry point, locales, library, scope, add-ons, mode
  plan.md                 # the executable checklist ("- [ ] step_id" lines)
  manifest-snapshot.json  # verbatim copy of the matched stacks[] entry + the catalogs[] rows it uses
  progress/               # ONLY when parallel wrap workers are dispatched (wr

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 15 — file references are metadata, not package contents.

translate16.4 KB

View saved version →

---
name: translate
description: Drafts translations into the project's own resource files from the terminal and uploads them to Crowdin as suggestions for review. Use when a developer asks to translate their app's strings, fill the missing translations for a locale, or translate the catalog into a newly added language. Not for prose documents, not for Crowdin's server-side pre-translation (`crowdin auto-translate`, in crowdin-cli), not for the full internationalize-and-connect journey (i18n-setup, which delegates here).
---

# Translate

A developer adds twelve strings and wants to see them in German today, not after the next translation cycle. This skill is the translator seat for that moment: it drafts translations into the project's own resource files, keeps them consistent with what the project's Crowdin resources already say, checks them mechanically, and uploads them to Crowdin as **unapproved suggestions** for reviewers to decide on.

Its one real advantage over Crowdin's server-side pre-translation is that the agent has the code. A source reference or a translator comment leads to the component a string renders in, and that is where `Order` turns out to be a button rather than a noun. For bulk work that advantage costs more than it earns, and the skill says so (see "Large runs").

Every `crowdin` command below belongs to the `crowdin-cli` skill — syntax, credentials, exit codes, `crowdin.yml`. This file names only the flags it passes.

## Preconditions

- **`crowdin.yml` exists** in the working directory. Without it, stop: say that the skill would be drafting with no glossary, no TM and no review in Crowdin, and offer the `i18n-setup` skill's connect-only path instead.
- **The CLI is installed and authorized.** Exit code `101` means the user runs `crowdin login` in their own terminal; the token value stays out of the conversation.
- **The CLI is current.** `--assigned`, `language list --verbose` and `style-guide` are what this skill leans on; an unknown-option or unknown-command error means an older install; upgrade it the way it was installed (the `crowdin-cli` skill has the line for each method).

## The run

Six steps, in order. Steps 1–3 and 5–6 run on the main thread; step 4 may fan out (see "Large runs").

### 1. Resolve

- **Files.** `crowdin config sources` and `crowdin config translations` print the resolved local source and translation paths per language, with any `languages_mapping` from `crowdin.yml` already applied. The path is the only source of a language's locale.
- **Languages.** The ones the user named, otherwise every project language. Run `crowdin language list --verbose -o json` once and keep two fields per language: `code`, which under the default `--code id` is the Crowdin language id that `-l` takes, and `pluralCategoryNames`, which feeds the plural check in step 5. `code` is the only source of the id; a mapping changes path placeholders, and the id stays what the CLI printed.
- **Gaps.** One rule for every format: an entry present in the source file with no non-empty counterpart in the target file, in that format's own notion of an entry, plus any entry the format marks as needing work (a fuzzy PO entry). A target file that does not exist yet is all gaps. [references/formats.md](references/formats.md) shows the rule in each common format family, the fallback for one it does not list, and the library checks that count gaps for you where they exist (Lingui's `lingui check missing --locale <locale> --mode catalog`).

Done when every language in scope has a target path, an id, its plural categories and a gap count.

### 2. Sync

Two commands, in this order, for the languages in scope:

```bash
crowdin upload sources --cache
crowdin download translations -l <language id> --skip-untranslated-strings
```

Before the upload, a library that can prove its source catalog is current gets asked, about the source catalog only: `lingui check sync --locale <source locale>` for Lingui 6.8 or later, and a failu

Preview of the first 4,000 characters. Read full instructions →

Referenced files: 4 — file references are metadata, not package contents.

Package details

Publisher declarations from the archived package. These are separate from our research and the live service's terms.

Package author
Crowdin OÜ
Keywords
See keywords
Commerce declaration
Does not support commerceThis does not establish whether access is free or paid.
Review scenarios
5 positive · 3 negativeScenario counts, not test results.

Package observed Nov 6, 2026.

Technical details
First seen
Oct 28, 2026 · 12:00 UTC
Last seen
Nov 6, 2026 · 12:00 UTC
Collection status
Collected

plugin_asdk_app_6ac7b1a0689c81919b1b49bfa1eb5a9d

Download plugin data (JSON)

Plugin details: served from cache. Prepared . Refreshed when plugin data changes or after 6 hours. Your account and Follow status are live.