> ## Documentation Index
> Fetch the complete documentation index at: https://developers.phrase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Phrase Strings CLI

<Info>This tool is for **Phrase Strings** only.</Info>

The Phrase Strings CLI is a self-contained binary for macOS, Linux, and Windows. It provides command-line access to the full Phrase Strings API and makes it easy to sync locale files between your project and Phrase.

## Installation

<CodeGroup>
  ```bash Homebrew (macOS) theme={null}
  brew install phrase-cli
  ```

  ```bash asdf theme={null}
  asdf plugin add phrase
  asdf install phrase latest  # or a specific version
  asdf set phrase latest
  ```

  ```bash Docker theme={null}
  docker run --rm phrase/phrase-cli:latest help
  ```
</CodeGroup>

For a direct binary, download the archive for your platform from the [phrase-cli releases page](https://github.com/phrase/phrase-cli/releases/latest):

<Tabs>
  <Tab title="macOS / Linux">
    ```bash theme={null}
    curl -L https://github.com/phrase/phrase-cli/releases/latest/download/phrase_linux_amd64.tar.gz | tar xz
    mv phrase /usr/local/bin/phrase
    phrase version
    ```
  </Tab>

  <Tab title="Windows">
    Download the `.zip` archive from the [releases page](https://github.com/phrase/phrase-cli/releases/latest), extract it, and add the `phrase.exe` binary to a directory on your `PATH`. Verify with `phrase version` from the command prompt.
  </Tab>

  <Tab title="Build from source">
    ```bash theme={null}
    go install github.com/phrase/phrase-cli@latest
    ```

    Requires Go 1.21+. The binary is placed in `$GOPATH/bin`.
  </Tab>
</Tabs>

## Authentication

For details on token types and how to generate them, see [Authentication](/en/api/platform/authentication).

The CLI looks for the token in this order:

1. `--access_token` flag
2. `PHRASE_ACCESS_TOKEN` environment variable (recommended)
3. `phrase.access_token` in `.phrase.yml` (discouraged)

Avoid putting the token in `.phrase.yml`, especially if the file is committed to a repository:

```bash theme={null}
export PHRASE_ACCESS_TOKEN="<your_access_token>"
```

You can also pass it directly as a flag:

```bash theme={null}
phrase push --access_token $PHRASE_ACCESS_TOKEN
```

## Quick start

### 1. Initialize your project

<Tip>
  **Speed up setup with our AI agent skill**

  The `phrase-strings-config` skill follows the [Agent Skills](https://agentskills.io/home) open format and works with any compatible AI coding agent. It can detect your project's i18n setup and generate `.phrase.yml` automatically. Install it from the [Phrase skills repository](https://github.com/phrase/skills).
</Tip>

Run `phrase init` in your project root. The interactive wizard asks for your token, project ID, file format, and locale file path, then creates a `.phrase.yml` config file.

```bash theme={null}
phrase init
```

If your account is on the **US datacenter**, pass the host flag:

```bash theme={null}
phrase init --host https://api.us.app.phrase.com/v2
```

You can also skip the wizard entirely with flags:

```bash theme={null}
phrase init \
  --access_token $PHRASE_ACCESS_TOKEN \
  --project_id YOUR_PROJECT_ID \
  --file_format yml \
  --path 'config/locales/*.yml'
```

### 2. Upload locale files

```bash theme={null}
phrase push
```

Use `--wait` to block until processing completes (recommended in CI):

```bash theme={null}
phrase push --wait
```

### 3. Download locale files

```bash theme={null}
phrase pull
```

## Configuration

`phrase init` creates a `.phrase.yml` file in your project root. You can place it in the current working directory, your home directory, or point to it with the `--config` flag or the `PHRASEAPP_CONFIG` environment variable.

### Global settings

| Key                     | Required | Description                                                                                           |
| ----------------------- | -------- | ----------------------------------------------------------------------------------------------------- |
| `phrase.access_token`   | No       | Personal access token. Prefer `PHRASE_ACCESS_TOKEN` env var to avoid committing credentials.          |
| `phrase.project_id`     | Yes      | Public project ID from project settings → API tab.                                                    |
| `phrase.file_format`    | Yes      | Default locale file format (API extension, e.g. `yml`, `json`, `strings`).                            |
| `phrase.host`           | No       | Override API host, e.g. `https://api.us.app.phrase.com/v2` for US datacenter.                         |
| `phrase.locale_mapping` | No       | Maps Phrase locale names to custom locale names, which can be used in file or directory placeholders. |

### Framework examples

<Tabs>
  <Tab title="Rails">
    ```yaml theme={null}
    phrase:
      access_token: ACCESS_TOKEN
      project_id: PROJECT_ID
      file_format: yml

      push:
        sources:
          - file: ./config/locales/*.yml
            params:
              update_translations: true

      pull:
        targets:
          - file: ./config/locales/<locale_name>.yml
    ```
  </Tab>

  <Tab title="iOS">
    ```yaml theme={null}
    phrase:
      access_token: ACCESS_TOKEN
      project_id: PROJECT_ID
      file_format: strings

      push:
        sources:
          - file: ./<locale_code>.lproj/Localizable.strings

      pull:
        targets:
          - file: ./<locale_code>.lproj/Localizable.strings
          - file: ./<locale_code>.lproj/Localizable.stringsdict
            params:
              file_format: stringsdict
    ```
  </Tab>

  <Tab title="Android">
    Android uses non-standard locale directory names. Use `locale_mapping` to map Phrase locale names to Android directory names:

    ```yaml theme={null}
    phrase:
      access_token: ACCESS_TOKEN
      project_id: PROJECT_ID
      file_format: xml

      locale_mapping:
        en-US: values
        de-DE: values-de-rDE
        fr-FR: values-fr

      push:
        sources:
          - file: ./app/src/main/res/values/strings.xml
            params:
              locale_id: en-US

      pull:
        targets:
          - file: ./app/src/main/res/<locale_name>/strings.xml
    ```
  </Tab>

  <Tab title="Multi-platform">
    ```yaml theme={null}
    phrase:
      access_token: ACCESS_TOKEN
      project_id: PROJECT_ID

      push:
        sources:
          - file: apps/web/src/assets/i18n/<locale_name>.json
            params:
              file_format: nested_json
          - file: apps/android/app/src/main/res/values-<locale_code>/strings.xml
            params:
              file_format: xml
          - file: apps/ios/<locale_code>.lproj/Localizable.strings
            params:
              file_format: strings

      pull:
        targets:
          - file: apps/web/src/assets/i18n/<locale_name>.json
            params:
              file_format: nested_json
          - file: apps/android/app/src/main/res/values-<locale_code>/strings.xml
            params:
              file_format: xml
          - file: apps/ios/<locale_code>.lproj/Localizable.strings
            params:
              file_format: strings
    ```
  </Tab>
</Tabs>

### Full annotated example

<Accordion title="phrase_configuration_overview.yml">
  ```yaml theme={null}
  phrase:
    project_id: PROJECT_ID
    file_format: FORMAT_API_EXTENSION

    push:
      sources:
        - file: ./path/to/file/file.format
          params:
            file_format: FORMAT_API_EXTENSION
            locale_id: LOCALE_ID
            tags: TAG_1, TAG_2
            update_translations: false
            update_descriptions: false
            skip_upload_tags: false
            skip_unverification: false
            file_encoding: ENCODING
            autotranslate: false
            mark_reviewed: false
            format_options: # format-specific — see Help Center for available options per format

    pull:
      targets:
        - file: ./path/to/<locale_code>/file.format
          params:
            file_format: FORMAT_API_EXTENSION
            locale_id: LOCALE_ID
            tags: TAG_1, TAG_2
            include_empty_translations: false
            exclude_empty_zero_forms: false
            include_translated_keys: true
            keep_notranslate_tags: false
            encoding: ENCODING
            include_unverified_translations: true
            use_last_reviewed_version: false
            fallback_locale_id: LOCALE_ID
            format_options: # format-specific — see Help Center for available options per format
  ```
</Accordion>

### Placeholders and globbing

Use these placeholders in `file` paths:

| Placeholder     | Description                                                                |
| --------------- | -------------------------------------------------------------------------- |
| `<locale_name>` | The unique locale name (e.g. `en`, `de-AT`). Preferred for `pull` targets. |
| `<locale_code>` | RFC 5646 locale identifier. Not guaranteed unique across locales.          |
| `<tag>`         | Groups keys by tag — useful for maintaining original file structures.      |

Globbing operators work in `push.sources` paths:

| Operator | Behavior                                             |
| -------- | ---------------------------------------------------- |
| `*`      | Matches any characters within a single path segment. |
| `**`     | Matches across directory boundaries (recursive).     |

```
./config/locales/**/*.yml   # matches ./config/locales/en.yml and ./config/locales/api/en.yml
```

**Note:** globbing is not supported in `pull.targets` — use explicit paths with placeholders instead.

### Push parameters

Key parameters for `push.sources[].params`:

| Parameter                 | Default | Description                                                                                |
| ------------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `locale_id`               | —       | Locale name (e.g. `en-US`) or public locale ID.                                            |
| `update_translations`     | `false` | Overwrite existing translations with file content.                                         |
| `update_descriptions`     | `false` | Update key descriptions; empty descriptions overwrite existing.                            |
| `skip_upload_tags`        | `false` | Skip creating upload tags.                                                                 |
| `skip_unverification`     | `false` | Do not unverify updated translations.                                                      |
| `tags`                    | —       | Comma-separated tags to apply to new keys.                                                 |
| `file_format`             | —       | Override the global file format for this source.                                           |
| `file_encoding`           | —       | Enforce encoding: `UTF-8`, `UTF-16`, `UTF-16BE`, `UTF-16LE`, `ISO-8859-1`.                 |
| `autotranslate`           | `false` | Auto-fetch translations for the uploaded locale.                                           |
| `mark_reviewed`           | `false` | Mark imported translations as reviewed (requires review workflow).                         |
| `update_translation_keys` | `true`  | Set to `false` to prevent new keys from being created or existing keys from being updated. |
| `translation_key_prefix`  | —       | Prefix prepended to all key names on push. Use `<file_path>` as a magic placeholder.       |

### Pull parameters

Key parameters for `pull.targets[].params`:

| Parameter                         | Default | Description                                                           |
| --------------------------------- | ------- | --------------------------------------------------------------------- |
| `locale_id`                       | —       | Locale name or public locale ID.                                      |
| `tags`                            | —       | Comma-separated tags to filter which keys to pull.                    |
| `include_empty_translations`      | `false` | Include keys with no translations.                                    |
| `include_unverified_translations` | `true`  | Set to `false` to exclude unverified translations.                    |
| `use_last_reviewed_version`       | `false` | Use the last reviewed translation version (requires review workflow). |
| `fallback_locale_id`              | —       | Fallback locale for missing translations.                             |
| `exclude_empty_zero_forms`        | `false` | Exclude zero-form plurals when empty.                                 |
| `keep_notranslate_tags`           | `false` | Preserve `[NOTRANSLATE]` tags in output.                              |
| `encoding`                        | —       | Enforce encoding on the output file.                                  |
| `file_format`                     | —       | Override the global file format for this target.                      |
| `translation_key_prefix`          | —       | Strip this prefix from key names on pull.                             |
| `filter_by_prefix`                | `false` | Only pull keys that match the prefix.                                 |

### Format options

Some file formats support additional `format_options` in the `params` section:

```yaml theme={null}
push:
  sources:
    - file: file.csv
      params:
        format_options:
          column_separator: ";"

pull:
  targets:
    - file: file.xml
      params:
        format_options:
          convert_placeholder: true
```

For the full list of supported `format_options` per file format, refer to the [Help Center format articles](https://help.phrase.com/help/supported-platforms-and-formats).

## Core commands

| Command                            | Description                                                                                                                                                         |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `phrase init`                      | Interactive setup — creates `.phrase.yml`.                                                                                                                          |
| `phrase push`                      | Upload locale files to Phrase.                                                                                                                                      |
| `phrase push --wait`               | Upload and wait for processing to complete.                                                                                                                         |
| `phrase pull`                      | Download locale files from Phrase.                                                                                                                                  |
| `phrase locales list`              | List all locales in the project.                                                                                                                                    |
| `phrase uploads cleanup --id <ID>` | Delete keys in the project that were not present in the uploaded file. Run after `phrase push` to remove stale keys. The upload ID is returned by the push command. |
| `phrase <command> --help`          | Show all options for any command.                                                                                                                                   |
| `phrase`                           | List all available commands.                                                                                                                                        |

## Docker

Mount your project directory so the CLI can read `.phrase.yml` and write locale files:

```bash theme={null}
docker run --volume $(pwd):/code --workdir /code --rm phrase/phrase-cli:latest pull
```

For interactive commands like `init`, add the `-it` flag:

```bash theme={null}
docker run -it --volume $(pwd):/code --workdir /code phrase/phrase-cli:latest init
```

## Advanced

**Monorepos:** Place one `.phrase.yml` in each package and run the CLI from the corresponding folder, or use the `--config` flag to point CI jobs to different config files.

**Rate limiting:** When the locale download rate limit is reached, the CLI automatically waits and resumes. You'll see: `rate limit exceeded, download will resume in x seconds`.

**Proxy:** Set the `HTTPS_PROXY` environment variable:

```bash theme={null}
export HTTPS_PROXY=https://user:password@host:port
```

**Windows shell escaping:** When passing JSON on the command line, use double quotes and escape inner quotes with `\`:

```
phrase locales create --project_id PROJECT_ID --data "{\"name\":\"French\", \"code\":\"fr\"}" --access_token TOKEN
```

## Git integration

When using the CLI with a Git provider (GitHub, GitLab, Bitbucket), ensure the following prerequisites are met in addition to having `.phrase.yml` committed to the repository:

<AccordionGroup>
  <Accordion title="GitHub">
    * A GitHub access token scoped to the repository (`public_repo` for public repositories).
    * If SSO is enabled in GitHub, it must also be enabled for the access token.
    * The `phrase_translations` branch must not be protected.
    * The repository must not require signed commits.
    * Read and write access to the repository are required.
  </Accordion>

  <Accordion title="GitLab">
    * Read and write access to the repository are required.
    * GitLab 9.5 or newer is required for API compatibility.
    * Ensure `.phrase.yml` contains at least one push source and one pull target with the correct file formats.
  </Accordion>

  <Accordion title="Bitbucket">
    * Read and write access to the repository are required.
    * Ensure `.phrase.yml` contains at least one push source and one pull target with the correct file formats.
  </Accordion>
</AccordionGroup>

## GitHub Actions

To automate pushes and pulls in CI, use the [Phrase Strings GitHub Action](/en/developer-tools/strings-github-action), which installs the CLI and exposes it to your workflow steps.

<Card title="Phrase Strings CLI on GitHub" icon="github" horizontal href="https://github.com/phrase/phrase-cli" />
