Agent skill

Store Localization

by dotnetdreamer in dotnetdreamer/open-screenshot-generator

Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (osg localize): it adds store locales to an existing project, writes per language copy…

MITAuto-check passedMobile

Install Store Localization

skills CLI
$ npx skills add dotnetdreamer/open-screenshot-generator --skill store-localization -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install dotnetdreamer/open-screenshot-generator store-localization --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/dotnetdreamer/open-screenshot-generator.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/store-localization .claude/skills/store-localization && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
store-localization
GitHub stars
124
Token cost
~3.8k tokens
SKILL.md length
1,822 words
Files
1
Skills in repo
13
Repo updated
First seen
Licence
MIT

At a glance

Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (osg localize): it adds store locales to an existing project, writes per language copy…

  • Works in 6 steps: name the base language before anything… → add the store locales → write the copy, because you are the… → …
  • Follow ups: a new language
  • SKILL.md covers The model, which is the thing…, Step 1: name the base language…, Step 2: add the store locales and Step 3: write the copy,…, plus 6 more sections
  • Calls npx and jq

What it does

Store Localization is an agent skill from dotnetdreamer/open-screenshot-generator. Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (osg localize): it adds store locales to an existing project, writes per language copy, overrides the screenshot, font, box or position where a translation needs it, runs a CSV round trip with a human translation agency, and renders a fastlane style screenshots/<locale/ folder per language. Use this whenever someone asks to localize store screenshots, translate their listing images, add German or…

Its SKILL.md is about 3.8k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Mobile, covering App store release, Translation and Internationalization. It works with Tauri. The repository describes itself as: Open source Canva with CLI/GUI, AI Agent, MCP for App Store and Play Store screenshots. Free alternative to AppScreens, AppLaunchpad and Previewed. The licence is MIT.

When your agent uses it

  • Follow ups: a new language
  • A reworded translation
  • Text that overflows in German
  • A localized in app screenshot

Example prompts

  • “make these in Spanish too”
  • “we are launching in Japan”
  • “translate the screenshots”
  • “/store-localization”

Requirements

  • Node.js

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. name the base language before anything else
  2. add the store locales
  3. write the copy, because you are the better translator
  4. the CSV round trip, for a human translation agency
  5. fix what one language needs, without touching the others
  6. render one folder per language

What it can do on your machine

Read from SKILL.md and the folder at commit 556578e. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npx
    • jq

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npx, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Store Localization loads about 3.8k tokens when it runs. Until then it costs about 221 tokens; SKILL.md has 1,822 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~221
When it runs · the whole SKILL.md, loaded when a task matches
~3.8k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from dotnetdreamer/open-screenshot-generator at commit 556578e, republished under its MIT licence (© dotnetdreamer). 1,822 words, ~3,758 tokens.

Download SKILL.mdSave it as .claude/skills/store-localization/SKILL.md (or your agent's skills folder).
name
store-localization
description
Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (`osg localize`): it adds store locales to an existing project, writes per language copy, overrides the screenshot, font, box or position where a translation needs it, runs a CSV round trip with a human translation agency, and renders a fastlane style screenshots/<locale>/ folder per language. Use this whenever someone asks to localize store screenshots, translate their listing images, add German or Japanese or Arabic screenshots, ship a multi language App Store listing, or says things like "make these in Spanish too", "we are launching in Japan", "translate the screenshots" or "send the strings to a translator". Also use it for follow ups: a new language, a reworded translation, text that overflows in German, or a localized in app screenshot.
license
MIT
metadata.package
open-screenshot-generator
metadata.homepage
https://openscrgen.app

One design, up to 57 languages

The end state: one project, one layout, several store languages, rendered into a screenshots/<locale>/ folder per language under osg/out/ that fastlane's deliver can upload as is, with osg verify exiting 0 for every locale.

The model, which is the thing everyone gets wrong

A language is an overlay, not a copy. The project keeps one set of artboards and one layout. Only these can differ per language:

  • the text content
  • the screenshot inside a device frame
  • the font, the font size, the line height, the box, the position of an individual element
  • whether an element is shown at all

Everything else is shared. There is no per language artboard, no duplicated project, and no second design to keep in sync. That is the whole point: a layout fix lands in every language at once.

Two consequences that will otherwise cost you an hour:

  1. Every editing tool writes the base document, the one all languages share. update_element changes the copy every language starts from. Only set_localized_text, set_localized_texts and set_locale_override write one language.
  2. Rendering follows the canvas. To export a language you switch to it and then export. osg render does that per locale for you; if you are driving tools by hand, set_locale then export_all.

Step 1: name the base language before anything else

The base language is the language the design is written in. It labels the source that every translation is tracked against, and it names the base folder in both store uploads.

It is locked the moment the project has any export language, because every override is hashed against a base string and re-basing would silently re-point all of them. So set it first.

json
[{ "tool": "add_locales", "args": { "locales": ["de-DE"], "baseLocale": "en-US" } }]

baseLocale is accepted only on that first call. After that, set_base_locale refuses.

Step 2: add the store locales

Codes are store locales, not two letter languages: en-US and en-GB are different listings, and so are zh-Hans and zh-Hant. pt alone is ambiguous and is refused.

bash
npx -y open-screenshot-generator@0 edit --script osg/locales.json
json
[
  { "tool": "list_supported_locales", "args": { "query": "chinese" } },
  { "tool": "add_locales", "args": { "locales": ["de-DE", "ja", "pt-BR", "zh-Hans"], "autoFont": true, "autoFit": true } },
  { "tool": "list_locales", "args": {} }
]

list_supported_locales is the catalog of all 57, with the code to add by, whether a machine engine can draft it, what App Store Connect and Google Play each call it, and which font has to be substituted for its script. Call it before add_locales rather than guessing a code.

  • autoFont (default true) substitutes a family that can actually draw the script. Turn it off only if you have checked the design font covers Japanese, Arabic or Thai. It does not.
  • autoFit (default true) shrinks a translation that overruns its box instead of clipping it.
  • machineTranslate (default false) drafts every new language with the engine right away. Leave it off, see the next step.

Mirror the same list into locales in osg/osg.config.ts so a fresh clone renders the same set.

Two vocabularies, and they resolve against different lists. add_locales and set_base_locale resolve against the catalog, because a language being added is by definition not in the project yet. Every other language tool resolves against the project's own list. Using the wrong one either invents a locale with no override map or refuses a language that does exist.

Step 3: write the copy, because you are the better translator

Store copy is exactly what a machine translator is worst at: it is short, idiomatic, brand specific and load bearing. An agent that reads the app writes better German headlines than the engine does. So the preferred path is read, translate, write back, in two calls.

json
[{ "tool": "list_translations", "args": { "filter": "untranslated", "limit": 200 } }]

Each cell says where its string came from, which is what tells you what you may overwrite:

OriginMeaningSafe to overwrite
inheritednothing written yet, the base copy is showingyes
manuala person or an agent wrote itask first
autothe machine engine drafted ityes, and improving it is the job
stale-*the base copy changed after this was translatedyes, it is a translation of copy that no longer exists

Then write them all in one call. One round trip, one undo step, one save:

json
[
  { "tool": "set_localized_texts", "args": { "writes": [
    { "elementId": "headline", "locale": "de-DE", "text": "Schlaf endlich durch" },
    { "elementId": "sub", "locale": "de-DE", "text": "Jede Nacht, automatisch" },
    { "elementId": "headline", "locale": "ja", "text": "ぐっすり眠れる夜へ" }
  ] } }
]

An empty string, or a string identical to the base copy, clears the translation and the element falls back to the base. Everything written this way is marked as human written, so a later engine run will not overwrite it.

Translation notes that are not optional:

  • Translate the benefit, not the words. A literal German headline is usually 40 percent longer and says less.
  • Keep product names, feature names and units in the source language unless the app itself localizes them.
  • German, Finnish and Russian run long. Dutch and French run long. Japanese, Korean and Chinese run short and want a larger size, not a smaller one.
  • Arabic, Hebrew, Farsi and Urdu align to the correct edge automatically. The composition is not mirrored: nothing flips element positions across the board. If a right to left layout needs the badge on the other side, that is a per locale position override, Step 5.

The machine engine is the fallback, for a language you do not read and for refreshing its own earlier drafts:

json
[{ "tool": "translate_locales", "args": { "locales": ["th"], "only": "empty", "guidance": "informal, second person, keep product names in English" } }]

only: "stale" refreshes drafts whose base copy has since changed. Strings a person wrote are skipped unless includeManual is set, and leaving it off is what protects reviewed copy. If no engine is configured, the tool says so and tells you to write the strings yourself, which was the better path anyway.

Step 4: the CSV round trip, for a human translation agency

json
[{ "tool": "export_translations_csv", "args": {} }]

The result is a JSON document, not a file: { csv, locales, rows }, where csv is RFC 4180 text with one row per string, the ids first, then the base language, then a column per language. Write the csv field to a file yourself and send that file. It is the format an agency takes.

bash
npx -y open-screenshot-generator@0 call export_translations_csv | jq -r .csv > osg/translations.csv
powershell
(npx -y open-screenshot-generator@0 call export_translations_csv | ConvertFrom-Json).csv |
  Set-Content -Encoding utf8 osg/translations.csv

When it comes back, read the file and send its contents as the csv argument. Build the call programmatically rather than pasting a spreadsheet into a prompt:

json
[
  { "tool": "import_translations_csv", "args": { "csv": "<the file contents>", "dryRun": true } },
  { "tool": "import_translations_csv", "args": { "csv": "<the file contents>" } }
]
  • Rows match on artboardId plus elementId, falling back to the base string when the ids do not line up and exactly one element has that string. So do not let the agency reorder or renumber.
  • An empty cell means "I did not translate this one" and never clears an existing translation. That is deliberate: a sheet that came back with three columns filled will not wipe the fourth.
  • Only languages the project already has are written. Run add_locales first.
  • Always run dryRun first and report what it says it will change.
Show full SKILL.md (753 more words)Show less

Step 5: fix what one language needs, without touching the others

json
[
  { "tool": "set_locale_override", "args": { "elementId": "headline", "locale": "de-DE", "fontSize": 40, "size": { "width": 900, "height": 260 } } },
  { "tool": "set_locale_override", "args": { "elementId": "phone-1", "locale": "ja", "screenshotSrc": "asset:<id>" } },
  { "tool": "set_locale_override", "args": { "elementId": "award-badge", "locale": "pt-BR", "hidden": true } }
]

What each one is for:

  • screenshotSrc is the big one. A German headline over an English app screen is not localized. Take the app's own screenshots per language, upload_asset each once, and override the device slot.
  • fontFamily when a script needs a face the design font cannot draw. Setting it also turns off the automatic script substitution for that element, so only set it when you mean to.
  • fontSize when a translation is long. Setting it turns off auto shrink for that element, so the box will clip if the string grows again.
  • position, size, rotation, scale, textAlign for a real layout difference.
  • hidden: true to drop a badge or an award from the markets that never earned it. Store review does read those.

Overriding is what pulls a property apart. content, screenshotSrc, imageSrc and mediaId are always per language. Everything else is shared until you override it, and update_element remains the way to change something for every language at once.

To undo: reset_locale_overrides with scope of element, artboard or project. With fields it drops only those properties and keeps the copy. Without fields it drops everything that language holds, translations included, which is what to do before re-translating from scratch.

Step 6: render one folder per language

bash
npx -y open-screenshot-generator@0 localize
npx -y open-screenshot-generator@0 render
npx -y open-screenshot-generator@0 manifest
npx -y open-screenshot-generator@0 verify

osg localize is the convenience wrapper over Steps 2 to 4 driven from osg/osg.config.ts. Run osg localize --help for the exact subcommand and flag names in the release you have; when the wrapper and this page disagree, the tool calls above are the contract.

osg render switches the canvas to each locale, exports, and writes:

osg/out/
  screenshots/
    en-US/    01_Hero.png  02_Search.png  ...
    de-DE/    01_Hero.png  02_Search.png  ...
    ja/       01_Hero.png  02_Search.png  ...

That is the fastlane deliver layout, so a repo that already uses fastlane can point at it directly. Read osg/osg.manifest.json for the authoritative list rather than globbing.

The upload maps the codes for you: this project's key is zh-Hans, App Store Connect says zh-Hans, Google Play says zh-CN. Nothing derives one from the other, so a locale the store does not have is reported rather than guessed.

Follow up dispatch

The user asks forEditThen run
One more languageosg.config.ts locales, then add_localeslocalize, render
Better wording in one languageset_localized_textsrender
"The German headline is cut off"set_locale_override fontSize or size for de-DErender
Localized app screenshotsupload_asset, then set_locale_override screenshotSrcrender
A badge removed in one marketset_locale_override hidden: truerender
Send strings to a translatorexport_translations_csvwrite the file
Strings came backimport_translations_csv with dryRun firstrender
Drop a languageremove_locales, and osg.config.ts localesrender
Start one language overreset_locale_overrides scope: "project"localize, render
A layout change in every languageupdate_element on the base documentrender

Troubleshooting

"This project has no language X." You used a code the project does not have. list_locales is the project's list, list_supported_locales is the catalog. Add before you write.

A tool refused the base language. Correct. The base language is the design. Use update_element to change the copy every language starts from.

Boxes of squares instead of Japanese, Arabic or Thai text. That is tofu: the family cannot draw the script. Either autoFont was turned off, or a fontFamily override pinned a Latin face. Check list_fonts --script cjk (also arabic, urdu, hebrew, thai, devanagari, bengali) and override with a family from that list. An unknown family is rejected outright rather than substituted, so a serif in the export means the family never reached the element.

A translation is there in list_translations but not in the render. The canvas is on another language, or the export ran before the switch. osg render handles this; a hand driven export needs set_locale first.

Text clips even though autoFit is on. Something set a fontSize override on that element, which turns auto shrink off for it. Clear it with reset_locale_overrides and fields: ["fontSize"].

An override "did nothing". A property other than content, screenshotSrc, imageSrc or mediaId only takes effect once it is detached, which is what writing it through set_locale_override does. Writing it through update_element changed the shared design instead.

The base language cannot be changed. By design, once export languages exist. Start a new project if the design really was written in the wrong language.

A CSV import wiped nothing and reported nothing. The ids did not match. The sheet was reordered, renumbered, or saved from a different project.

  • store-screenshots for building the design the languages sit on top of
  • store-compliance for the per locale caps and for osg upload
  • editor-tools for the full locale tool surface and its asymmetries

© dotnetdreamer, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/store-localization of dotnetdreamer/open-screenshot-generator.

Open the folder on GitHubat commit 556578e

Compare with similar skills

Store Localization next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Store Localization compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Store Localization this skilldotnetdreamer/open-screenshot-generator124—~3.8kAutomated safety check: PassMIT
Asc Localize MetadataCamilleScholtz/swmpc2395 repos~2.8kAutomated safety check: PassEUPL-1.2
Update TranslationsRaicuparta/rai-pal732—~839Automated safety check: PassGPL-3.0
Asc Metadata Syncn0an/VivaDicta1311 repos~1kAutomated safety check: PassMIT
Add UI Stringopenfootmanager/openfootmanager1.1k—~2.6kAutomated safety check: PassGPL-3.0
Localizationappeeky/aso-skills2.2k—~1.5kAutomated safety check: PassMIT

Similar skills

  • Asc Localize Metadata

    CamilleScholtz/swmpc

    Automatically translate and sync App Store metadata (description, keywords, what's new, subtitle) to multiple languages using LLM translation and asc CLI.

    239 GitHub starsUsed in 5 repos~2.8k tokens
    MobileAuto-check passed
  • Update Translations

    Raicuparta/rai-pal

    A skill your agent uses when asked to update translations, localize strings, add new languages, fix missing translation keys, or sync language files in this project.

    732 GitHub stars~839 tokensUpdated yesterday
    Writing & ContentAuto-check passed
  • Asc Metadata Sync

    n0an/VivaDicta

    Sync and validate App Store metadata and localizations with asc, including legacy metadata format migration.

    131 GitHub starsUsed in 1 repo~1k tokens
    Frontend & DesignAuto-check passed
  • Add UI String

    openfootmanager/openfootmanager

    Add or change any text a player can see, in every locale the game ships in.

    1.1k GitHub stars~2.6k tokensUpdated yesterday
    Testing & QAAuto-check passed
  • Localization

    appeeky/aso-skills

    When the user wants to localize their App Store listing for international markets.

    2.2k GitHub stars~1.5k tokensUpdated yesterday
    Marketing & SEOAuto-check passed
  • Translation Diff Export

    Devolutions/UniGetUI

    Compares UniGetUI JSON locale files against English, identifies untranslated or source-changed keys, and generates patch, reference, and handoff files for a target language.

    26k GitHub stars~1.1k tokensUpdated today
    Writing & ContentAuto-check passed

More from dotnetdreamer/open-screenshot-generator

All 13 skills in this repo
  • App Preview Video

    dotnetdreamer/open-screenshot-generator

    Builds an App Store App Preview video (and a Play Store or landing page promo cut) from a screen recording of the app, using the open-screenshot-generator CLI (osg video): it starts from one of 20…

    124 GitHub stars~3.3k tokensUpdated yesterday
    Auto-check passed
  • App Screenshots

    dotnetdreamer/open-screenshot-generator

    Drive Open Screenshot Generator headlessly (puppeteer-core + Edge) to take UI screenshots, add palette elements, upload device screenshots, export artboard PNGs, and regenerate the 3D device…

    124 GitHub stars~5.1k tokensUpdated yesterday
    Auto-check: notes
  • Editor Tools

    dotnetdreamer/open-screenshot-generator

    Drives the live Open Screenshot Generator editor tool by tool over MCP, using osg mcp to expose the design tools (artboards, elements, backgrounds, fonts, the asset libraries, templates, App Preview…

    124 GitHub stars~3.8k tokensUpdated yesterday
    Auto-check passed
  • Gpt4free Provider Sync

    dotnetdreamer/open-screenshot-generator

    Check the latest xtekky/gpt4free releases for provider additions/changes and decide whether Open Screenshot Generator's AI providers need the same.

    124 GitHub stars~2.3k tokensUpdated yesterday
    Auto-check passed
  • Stock Image Assets

    dotnetdreamer/open-screenshot-generator

    Add properly licensed Adobe Stock photos to the Images palette library (e.g.

    124 GitHub stars~1.7k tokensUpdated yesterday
    Auto-check passed
  • Store Compliance

    dotnetdreamer/open-screenshot-generator

    Checks that rendered store assets will actually be accepted, and then ships them, using the open-screenshot-generator CLI: osg verify audits the produced PNGs and MP4s against App Store and Google…

    124 GitHub stars~3k tokensUpdated yesterday
    Auto-check passed

Works with

Questions about Store Localization

What does Store Localization do?

Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (osg localize): it adds store locales to an existing project, writes per language copy…. Store Localization is an agent skill from dotnetdreamer/open-screenshot-generator. Ships one screenshot design in many App Store and Play Store languages using the open-screenshot-generator CLI (osg localize): it adds store locales to an existing project, writes per language copy, overrides the screenshot, font, box or position where a translation needs it, runs a CSV round trip with a human translation agency, and renders a fastlane style screenshots/<locale/ folder per language.

When should I use Store Localization?

Store Localization fits situations like: follow ups: a new language; A reworded translation; text that overflows in German; A localized in app screenshot.

How do I install Store Localization in Claude Code?

Run `npx skills add dotnetdreamer/open-screenshot-generator --skill store-localization -a claude-code`. Or copy the skill folder (skills/store-localization in dotnetdreamer/open-screenshot-generator) into .claude/skills/store-localization in your project. Claude Code loads it when a task matches its description.

How do I install Store Localization in Codex?

Run `npx skills add dotnetdreamer/open-screenshot-generator --skill store-localization -a codex`. Or copy the skill folder (skills/store-localization in dotnetdreamer/open-screenshot-generator) into .agents/skills/store-localization in your project. Codex loads it when a task matches its description.

Can I use Store Localization in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add dotnetdreamer/open-screenshot-generator --skill store-localization -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/store-localization, .gemini/skills/store-localization, .github/skills/store-localization and .opencode/skills/store-localization in your project.

What does Store Localization need to run?

Going by SKILL.md and its folder, Store Localization needs the command-line tools its instructions call (npx and jq). Our summary lists: Node.js.

Does Store Localization access the network?

SKILL.md contains no URLs. Its commands use npx, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Store Localization safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Store Localization use?

Store Localization is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Store Localization use?

About 3.8k tokens (SKILL.md is roughly 15k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Store Localization?

Skills that share tags, products or a category with Store Localization: Asc Localize Metadata (CamilleScholtz/swmpc, 239 stars), Update Translations (Raicuparta/rai-pal, 732 stars), Asc Metadata Sync (n0an/VivaDicta, 131 stars) and Add UI String (openfootmanager/openfootmanager, 1.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Store Localization?

dotnetdreamer (a GitHub user) maintains it in dotnetdreamer/open-screenshot-generator, which has 124 GitHub stars. The repository holds 13 skills in this directory. The repository was last updated on October 7, 2026.

Source: dotnetdreamer/open-screenshot-generator on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.