Skip to main content

localize

Use when creating or fixing translated / localized variants of an existing CoDesign / CE.SDK design (e.g. de/ja/ru/ar editions); when a localized edition's text blocks or decorative elements have drifted, re-centered, or resized away from the source layout; when translated copy is tofu, overflowing, mis-tracked, or the wrong font after a language swap; or when loading a non-Latin script (Cyrillic / CJK / Arabic RTL / Vietnamese) font into a scene. Also for animated / video designs: longer holds, re-timed reveals, a new voice-over and captions per language.

Informations de source

Dépôt
imgly/codesign
Dernière activité de la source
20 octobre 2026 à 21:27
Langue détectée de SKILL.md
anglais
Étoiles
43
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
8 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
localize
description
Use when creating or fixing translated / localized variants of an existing CoDesign / CE.SDK design (e.g. de/ja/ru/ar editions); when a localized edition's text blocks or decorative elements have drifted, re-centered, or resized away from the source layout; when translated copy is tofu, overflowing, mis-tracked, or the wrong font after a language swap; or when loading a non-Latin script (Cyrillic / CJK / Arabic RTL / Vietnamese) font into a scene. Also for animated / video designs: longer holds, re-timed reveals, a new voice-over and captions per language.
# localize Point this skill at the current design and the target locales, and it produces or repairs the localized editions. It operates on the **design in the current session**, and each locale is **saved as its own `.imgly` file**. Single home for localizing CoDesign designs: the **operational workflow**, the **font-loading mechanics**, and the **per-language quality rules**. It builds on two things it does _not_ restate: handbook §6.1 (general typographic thresholds — leading, tracking, all-caps, the content-area line-height conversion (`design.font`), smart punctuation, reshape-recolor) and handbook §6.7 (general Latin font mechanics — single-URI `text.font` declarations, static-vs-variable, blank-glyph diagnosis). This skill is the non-Latin / localization extension of both. **Scoring:** localizing is judged with the `judge` skill — every applicable axis ≥ 8, no averaging, N/A = 10. A single tofu glyph, an overflow after expansion, un-mirrored RTL, or a block that drifted off the source grid fails the edition (the `localization` axis). ## Reference files (load on demand) This `SKILL.md` holds the always-needed spine: inputs, core principle, workflow, block classification, and the snap-to-reference routine. Two situational bodies of rules live beside it and are pulled in only when the task needs them: - **`reference/font-loading.md`** — getting a non-Latin / non-handbook face to render (jsDelivr picks, weights from a variable file, font-declaration gotchas, the silent-sans failure). Read it whenever the target locale needs a Cyrillic / CJK / Arabic / Vietnamese font, or copy came out tofu / wrong face. - **`reference/language-rules.md`** — the cross-language spine: preserve-vs-localize, translation quality, layout integrity after translation, and the localization pass checklist. - **`reference/<family>.md`** — per-script-family conventions, numeric leading bands, and quotation marks, one file per family: `latin-expansion.md` (de/fr/es…), `arabic.md`, `cjk.md` (ja/zh/ko), `vietnamese.md`, `cyrillic.md` (ru…). Read the file(s) for the **target locale(s)** you're building, e.g. `reference/arabic.md`. Several locales of one design, or re-applying a master fix to locales you already built: the **master → editions** workflow, `../resize/editions.md`. For an animated or video design, read **Video and animated designs** below as well. ## Inputs — what to localize, and into what Resolved before any work by the intake contract — derive, ask once, echo, invent nothing: `../handbook/intake.md`. **R** = required, no default; **A** = ask if underived; **D** = defaultable. | Parameter | Kind | Chips / values | Default | | -------------- | ------- | --------------------------------------------------------------------------- | --------------------------------- | | target locales | **R** | `German` · `French` · `Spanish` · `Japanese` · `Chinese` · `Arabic` · Other | none | | source locale | A | detected from the design's copy · Other | detected, stated in the echo | | source design | derived | — | the design in the current session | **1. The source (reference)** — the design in the current session, in its source language (usually `en`). **Save it first** (`export({ format: 'imgly' })`) and keep the `uri`: its geometry is the grid every target locale snaps to, and every locale starts by re-importing that file. Never localize _from_ a non-reference locale. If the user means a design saved earlier, its `uri` IS the reference `uri`: `open` it to `preview` and capture it, skip the first save, then `import` a copy of it per locale. A session holds one design, so the locales are built in sequence and the saved reference is what you return to between them (handbook §1): ``` export({ format: 'imgly' }) → REFERENCE_URI (save the source FIRST) per locale: import({ source: { uri: REFERENCE_URI } }) → a copy of the reference is the session edit(…) translate + swap the script font + snap to the reference geometry preview() → check it against the reference render export({ format: 'imgly' }) → that locale's own file ``` **2. The locales** — the target languages, e.g. `de ja ru ar`. If omitted, **ask** — _**Which languages do you need?**_ — with the chips above; there is no defaulting to a language the user didn't name. Then echo the resolved set ("1 design × 3 locales, source `en` (detected)") before building. **Never invent copy.** A translation is the user's own content: if a block's meaning is ambiguous, or a term is a name/product you cannot safely render in the target script, ask rather than guess — see the keep-byte-identical list in `reference/language-rules.md` §1. **Per locale, then:** run the Workflow below (re-import the reference, or load an existing localized file and snap it). Give each locale's `edit` a `note` naming the locale, `preview` it, and **save it** — an unsaved locale is one the user never receives. Report every locale's `uri` at the end. ## Core principle — localize, then snap back to the reference Localizing is **surgical**: change the words + the font the new script forces, and **nothing else**. Then **snap every block back to the reference variant's geometry** so the localized edition is positionally identical to the source. - The **reference** is the source-locale variant (usually `en`) **of the same size**. Each size has its own reference grid. - **Never re-center or re-size a block per variant "to fit better."** That independent re-fitting is exactly what makes a localized set drift — the eyebrow creeps up, the quote grows, the rule and footer slide down, and the editions stop matching. If there is room for the translated text at the reference position/size, keep the reference position/size. - Deviate from the reference **only** when the translated text genuinely overflows (expansion languages) — then shrink _that block's_ font within its band; do not move its neighbours. - **Swap the script font per block, not per scene.** Apply the new face **only to blocks whose copy is actually in the target script.** A block that stays in the source script — a personal name, brand/wordmark, `@handle`, URL, email, number, date, or product/tech name (the "keep byte-identical" list in `reference/language-rules.md` §1) — **keeps its original typeface.** Re-fonting it to the script face is drift even though its text was correctly preserved: a Latin name rendered in the Arabic/CJK serif is the classic tell. So a localized edition differs from its reference in **only the translated blocks' text + face**; every untranslated block is byte-identical (position mirrored for RTL). ## When to use - Producing new locale editions (de/ja/ru/ar/…) of a finished design, across one or more sizes. - Fixing a localized set whose blocks drifted / re-centered / resized vs the source. - Post-translation breakage: tofu, overflow, wrong tracking, Latin-looking sans where a script font should be. - Loading a non-Latin or non-handbook typeface into a scene. **Not for:** the original design build (that's the handbook + §6); pure copy edits in the same language. To change the **size/format** — re-compose a design for a new aspect rather than translate it — use the **resize** skill (localize snaps geometry; resize re-derives it). ## Reuse an existing localized build vs build fresh - **A saved file for the locale already exists** (an earlier pass built it — the user has its `uri`): **reuse its build** — `open({ uri })` it (`import` would give you a copy); the translated copy, script fonts, and RTL are already solved — but still **snap it to the reference geometry**. Earlier builds commonly drift; reuse the assets, fix the positions. Your fix goes to that design itself. Save it when you are done. - **No existing build:** `import` a copy of the reference file and swap text + font. Either way the last step is the same: every block lands on the reference grid. ## Workflow 1. **Capture the reference geometry.** With the source-locale design in the session, `preview` it (that render is your parity reference for the `judge` gate) and read, per block: `x, y, width, widthMode, heightMode, fontSize (Pixel), lineHeight, letterSpacing, alignment`, plus page `w/h`, the ghost's anchor (left / centered), and the rule position. Do this **once**; the captured JSON is what you carry from locale to locale. 2. **Load the target** — `open` the existing localized file to fix, or `import` a copy of the reference file for a fresh build. 3. **Classify blocks by role** (see below). 4. **Apply the reference geometry** to each corresponding block; keep the localized **text** and the **script font** (for a non-Latin/non-handbook face see `reference/font-loading.md`). Set per-locale: `letterSpacing = 0` for CJK & Arabic; RTL ghost mirrored to the right; alignment as the reference (centered-symmetric stays centered — see `reference/arabic.md`). 5. **Reconcile ghost count.** Keep the reference's number of decorative glyphs. If the localized scene has extra ones (e.g. an Arabic closing-quote bookend the English lacks), **destroy the extras**; mirror the kept one for RTL. 6. **Overflow guard.** After setting the reference font size, measure the quote's frame height; if it collides with the element below, step the font size down (only that block) until it fits. Never move neighbours to make room. 7. **Re-apply rich text after a TRANSLATED string lands.** Font/size/line-height changes via `setProps` auto-reshape with every style range preserved — no manual step. A **translated string** is different: the write replays ranges at their OLD offsets, which are source-string indices. Capture each block with `getProps(id, ['text.ranges'])` first (each range carries its `text` substring), re-apply semantically after. ⚠ `getTextColors(id)[0]` is **not** a capture — it reads the first run only, so re-applying it flattens a two-color headline onto one color and the accent is gone with no error. Paragraph state (`getProps(id, ['text.paragraphs'])` — listStyle/listLevel per paragraph) survives a same-string reshape but not a **re-write**, so re-apply it whenever the string itself changed. **Ranges are index-based on the source string** — a translated string has different offsets, so never replay `from`/`to` verbatim; re-locate the styled substring in the target language (§ "Carrying rich text across a translation"). 8. **`loadResources` → `preview`.** One preview per locale — tofu / RTL / overflow / position match are only visible in the render. A video design needs several per locale, at different `time`s (below). Then apply the per-locale quality rules in `reference/language-rules.md` **and the family file(s) for the target locale(s)** (`reference/latin-expansion.md`, `arabic.md`, `cjk.md`, `vietnamese.md`, `cyrillic.md`), and dry-run the localization pass checklist against the render before reporting done. ## Block-role classification Classify by measurable properties, not hard-coded ids (ids are session-scoped). For a quote-card family the roles are: - **ghost** (oversized decorative quote) — largest font size **and** trimmed string length ≤ 2. A design may have **more than one** (opening + closing bookend); collect all. - **footer / handle** — text containing `@`. - **quote / headline** — the largest remaining text after removing ghosts + footer. - **eyebrow** vs **attribution** — the two small texts; eyebrow sits **above** the quote, attribution **below**. - **rule / divider** — the graphic (non-text) block. Roles are design-specific. The general rule: **map each localized block to its reference block by role, or by index** (every locale is imported from the same reference file, so they keep the same child order), then restore that reference block's geometry. ## The snap-to-reference routine A single CoDesign `edit` body. Fill the `EN` reference geometry (from step 1) and the locale flags, then it classifies, restores geometry, reconciles ghosts, applies per-locale tracking / RTL mirroring, guards overflow, and re-applies colors across the reshape. ⚠ This routine is a **worked example, not a template**: every number in `EN` below is from one example quote-card, and the classification heuristics (`fs >= 150`, `s.includes('@')`, …) are that card's — never reuse either literally. Fill `EN` only from your own reference capture (the read at the bottom), and rewrite the classification for the actual design's roles. ```js // --- config: reference geometry (read from the source-locale variant of THIS size) --- const PW = 1080, PH = 1350; // page dims const EN = { // lh = VISUAL leading target (from the target locale's script band, NOT the reference's // raw engine number) — setLeading() converts it through each block's target face. For a // localized display headline in a diacritic language, this is where the conditional +0.2 // lives (latin-expansion.md): bump ≤1.2 → ~1.35 only if the rendered gap needs it. ghost: { x: 70, y: 55, fs: 300, lh: 1 }, // Auto-sized; keep size+lh, reposition eyebrow: { x: 110, y: 395, w: 860, fs: 16, lh: 1, ls: 0.25 }, quote: { x: 110, y: 529, w: 860, fs: 62, lh: 0.85 }, // ls always 0 rule: { x: 504, y: 930, w: 72 }, // graphic attribution: { x: 110, y: 960, w: 860, fs: 16, lh: 1, ls: 0.25 }, footer: { x: 110, y: 1225, w: 860, fs: 15, lh: 1, ls: 0.12 } }; const RTL = false; // true for Arabic const trackOK = true; // false for CJK/Arabic → force letterSpacing 0 on eyebrow/attr/footer const ghostAnchor = 'left'; // 'left' (post/square) mirrors to the right for RTL; 'center' (story) stays centered const belowQuoteY = EN.rule.y; // element the quote must stay above const [page] = await engine.design.findByType('page'); const blocks = []; const walk = async (id) => { for (const c of await engine.design.getChildren(id)) { blocks.push(c); await walk(c); } }; await walk(page); const typeOf = async (id) => (await engine.design.getProps(id, ['type'])).type; const texts = []; let graphic; for (const id of blocks) { const type = await typeOf(id); if (type === 'text') texts.push(id); else if (type === 'graphic') graphic ??= id; } await engine.design.loadResources([page]); const meta = async (id) => { const p = await engine.design.getProps(id, [ 'text.string', 'text.fontSize', 'position' ]); return { id, s: p.text.string, fs: parseFloat(p.text.fontSize), y: p.position.y }; }; const tm = []; for (const id of texts) tm.push(await meta(id)); // classify const ghosts = tm.filter((t) => t.fs >= 150 && t.s.trim().length <= 2); let ghost = ghosts.find((t) => t.s.includes('“')) || ghosts.slice().sort((a, b) => a.y - b.y)[0]; for (const g of ghosts.filter((t) => t !== ghost)) await engine.design.destroy(g.id); // drop extra bookend glyphs const footer = tm.find((t) => t.s.includes('@')); const rest = tm.filter((t) => !ghosts.includes(t) && t !== footer);
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub