LocalePack
ChromeFirefoxEdgeOperaSafariCWS Listing
Vue.jsReact
Next.jsi18nextReact Native
Guides
Home/Guides/Chrome listing automation
March 24, 2026

Automate Chrome Web Store listing translations with a console script

Chrome Web Store doesn’t offer a bulk upload for store descriptions. With 52 supported languages, manually switching and pasting each translation takes hours. This guide shows how to automate the entire process with a browser console script that fills every language in under a minute.

The problem

The Chrome Developer Dashboard has a “Store Listing” tab where you enter per-language marketing text. But there’s no bulk import — you have to:

  1. Select a language from the dropdown
  2. Wait for the form to load
  3. Paste the translated description
  4. Repeat for every language (up to 52 times)

The extension name and short description are controlled by manifest.json via __MSG_appName__ and __MSG_shortDesc__ — those are applied automatically from your _locales folder. But the detailed store description (up to 16,000 characters) must be entered manually in the dashboard for each language.

What the script does

The automation script runs in the browser console on the CWS Developer Dashboard. It:

1

Creates a file picker

A green button appears at the top of the page. You click it and select the _locales folder from the ZIP that LocalePack generated.

2

Reads all locale files

The script scans every messages.json inside _locales/ and extracts the storeDesc.message value for each locale.

3

Fills each language automatically

For each locale, it opens the CWS language dropdown, selects the matching language, waits for the form to load, and fills the description textarea.

4

Reports results

The console shows how many locales were filled and how many were skipped. You click Save draft to commit the changes.

The script handles locale code differences automatically — for example, Chrome’s locale code for Hebrew is iw, not he. The script maps these automatically.

Prerequisites

Before running the script, you need:

  • A translated _locales folder with messages.json files containing a storeDesc key. You can generate this with LocalePack’s store listing translator.
  • Access to the Chrome Developer Dashboard for your extension
  • The extension must already be published or in draft with at least one language

Step-by-step instructions

1

Open the Store Listing tab

Go to the Chrome Developer Dashboard, select your extension, and navigate to the Store Listing tab. You should see the language dropdown labeled “Current editing language”.

2

Open the browser console

Press F12 (or Cmd+Option+J on Mac) to open Chrome DevTools, then switch to the Console tab.

3

Allow pasting (if blocked)

Chrome may block pasting in the console. If you see a warning, type allow pasting and press Enter. This is a one-time action per tab.

4

Paste and run the script

Copy the script below (use the copy button), paste it into the console, and press Enter.

5

Select the _locales folder

A green file picker will appear at the top of the page. Click it and select the _locales folder from your downloaded ZIP. The script will begin processing automatically.

6

Save and verify

When the console shows “Done!”, click Save draft in the CWS dashboard. Then spot-check a few languages by switching the dropdown — verify the description was filled correctly.

The script

Copy the entire script and paste it into the Chrome DevTools console on the CWS Store Listing page. You can also download it as a file.

cws-localization.js
const ANIMATION_TIMEOUT = 500;

const fileInput = document.createElement("input");
fileInput.setAttribute("id", "filepicker");
fileInput.setAttribute("type", "file");
fileInput.setAttribute("webkitdirectory", "");
fileInput.setAttribute("multiple", "");
fileInput.setAttribute(
  "style",
  "position: absolute;top: 0;z-index: 999;padding: 1rem;background: green;",
);
document.documentElement.append(fileInput);

document.getElementById("filepicker").addEventListener(
  "change",
  async event => {
    const files = event.target.files;

    const locales = {};

    const localeFiles = Object.values(files)
      .filter(f => f.name == "messages.json")
      .filter(f => f.type == "application/json");

    for (const localeFile of localeFiles) {
      const localeCode = localeFile.webkitRelativePath
        .replace("_locales/", "")
        .replace("/messages.json", "");
      const fileText = await localeFile.text();

      const localeJson = JSON.parse(fileText);
      if (localeJson.storeDesc) {
        locales[localeCode] = localeJson.storeDesc.message;
      } else {
        console.warn(`[${localeCode}] - no storeDesc key, skipping`);
      }
    }

    console.log(`Found ${Object.keys(locales).length} locales with storeDesc`);
    console.log("Locales:", locales);

    await uploadLocales(locales);
  },
  false,
);

function sleep(time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

async function uploadLocales(locales) {
  const dropdown = document.evaluate(
    "//h3[text()='Current editing language']/../../div[2]//div[@jsshadow]/div/div",
    document,
    null,
    XPathResult.FIRST_ORDERED_NODE_TYPE,
    null,
  ).singleNodeValue;

  if (!dropdown) {
    console.error("Could not find the language dropdown. Make sure you are on the Store Listing tab.");
    return;
  }

  let filled = 0;
  let skipped = 0;

  for (const [rawCode, description] of Object.entries(locales)) {
    let code = rawCode.replace("_", "-");

    if (code === "he") {
      code = "iw";
    }

    dropdown.click();
    await sleep(ANIMATION_TIMEOUT);

    const langList = document.evaluate(
      "//ul[@aria-label='Language']",
      document,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null,
    ).singleNodeValue;

    if (!langList) {
      console.error("Could not find the language list. Try refreshing the page.");
      return;
    }

    const langItem = [...langList.children]
      .filter(e => e.tagName == "LI")
      .find(e => e.getAttribute("data-value") == code);

    if (!langItem) {
      console.warn(`[${code}] not found in CWS language dropdown, skipping`);
      skipped++;
      document.body.click();
      await sleep(ANIMATION_TIMEOUT);
      continue;
    }

    langItem.click();
    await sleep(ANIMATION_TIMEOUT);

    const textarea = document.evaluate(
      "//textarea[@maxlength='16000']",
      document,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null,
    ).singleNodeValue;

    if (!textarea) {
      console.error(`[${code}] could not find description textarea`);
      skipped++;
      continue;
    }

    textarea.dispatchEvent(new Event("focus"));
    textarea.value = description;
    textarea.dispatchEvent(new Event("input", { bubbles: true }));
    filled++;

    console.log(`[${code}] ✓ description filled`);
    await sleep(ANIMATION_TIMEOUT);
  }

  console.log(
    `Done! Filled ${filled} locale(s), skipped ${skipped}.` +
    ` Click "Save draft" to save your changes.`,
  );
}

Expected file format

The script expects a standard _locales folder structure where each locale’s messages.json contains a storeDesc key:

_locales/
├── en/
│   └── messages.json
├── fr/
│   └── messages.json
├── de/
│   └── messages.json
└── ... (one folder per language)

// Example: _locales/de/messages.json
{
  "appName": {
    "message": "Dunkelmodus",
    "description": "Extension name"
  },
  "shortDesc": {
    "message": "Dunkelmodus für Chrome mit einem Klick.",
    "description": "Short description (max 132 chars)"
  },
  "storeDesc": {
    "message": "🔥 Erleben Sie ultimativen visuellen Komfort...",
    "description": "Full store description (max 16000 chars)"
  }
}

The script only reads the storeDesc.message field. If a locale file doesn’t have a storeDesc key, it’s skipped with a console warning.

Locale code mapping

Chrome Web Store uses slightly different locale codes than the _locales folder convention. The script handles these mappings automatically:

_locales codeCWS codeLanguage
heiwHebrew
zh_CNzh-CNChinese (Simplified)
zh_TWzh-TWChinese (Traditional)
pt_BRpt-BRPortuguese (Brazil)
pt_PTpt-PTPortuguese (Portugal)
es_419es-419Spanish (Latin America)

All other locale codes are converted by replacing underscores with hyphens (e.g. pt_BR → pt-BR).

Troubleshooting

Console shows 'Could not find the language dropdown'

Make sure you're on the Store Listing tab (not Package, Privacy, or Distribution). The script looks for the heading 'Current editing language' — if CWS redesigned their UI, the XPath selectors may need updating.

Some locales show '[code] not found in CWS language dropdown, skipping'

This means the locale exists in your _locales folder but isn't available in CWS for your extension. You may need to add the language in the CWS dashboard first (under 'Add a language').

Script runs too fast and misses some languages

The script waits 500ms between each language switch. If your connection is slow, you can increase the ANIMATION_TIMEOUT constant at the top of the script to 1000 or higher.

Chrome blocks pasting in the console

Type allow pasting in the console and press Enter. This is a Chrome security feature that only needs to be done once per tab.

Generating the translated files

Before running the automation script, you need translated messages.json files with the storeDesc key. LocalePack generates these for you:

1

Go to the store listing translator

Open localepack.app/store-listing and click “Translate Store Listing”.

2

Enter your listing text

Fill in your extension name (75 chars), short description (132 chars), and full store description (16,000 chars). Character counters show remaining space.

3

Select languages and pay

Choose which languages to translate into (up to 51 target languages), review the price, and complete checkout.

4

Download the ZIP

Once translations are complete, download the ZIP. It contains a _locales folder with messages.json per language — ready for the automation script.

Translate your Chrome Web Store listing

LocalePack translates your store listing into up to 51 languages with marketing-quality AI translations. Download the _locales ZIP, run the automation script, and your CWS listing is fully localized in minutes.

Translate Store Listing →
← Back to Guides
LocalePack
GuidesPrivacyTermsSupport

© 2025 LocalePack. All rights reserved.

This project was translated with LocalePack logoLocalePack