Skip to content

Exports: draw annotation text in every script, and translate everything into every supported language - #288

Merged
Twest2 merged 14 commits into
mainfrom
fix/188-annotation-unicode
Nov 9, 2026
Merged

Twest2 merged 14 commits into
mainfrom
fix/188-annotation-unicode

Conversation

@Twest2

@Twest2 Twest2 commented Nov 9, 2026 •

Copy link
Copy Markdown
Owner

Issue

Part of #286 (point 2: export text stays English), plus @Weiking2019's report in discussion #188 (Chinese annotation text missing from PDF/Word exports).

Summary

Two problems, fixed together:

  1. Chinese (and other non-Latin) annotation text showed as ? in exports. In every format, text boxes and tooltips are burned into the screenshot by StepForge's own rasterizer. That rasterizer only had a Lato atlas of about 200 Latin characters. The editor looked fine because it draws with the system font. Now any character the atlas lacks is drawn from an installed font's outlines, the way a browser falls back to another font.
  2. Exports and many app messages were always English. Examples are "Last verified", "Contents", page numbers, alt text and callout names, plus sign-in, sync, publishing and update errors. Exports now use the interface language (Settings → General → Language). Every shipped language is complete: fr, es, ru, zh-CN and ja are each at 2258 of 2258.

Changes

Text in any script in exported images

  • core/text-raster.js fills characters missing from the atlas using installed fonts, from the same font lists the PDF exporter uses (core/pdf-fonts.js). Glyphs sit on the Lato baseline at the same em size.
    • On Windows: YaHei, Yu Gothic, Malgun, Segoe UI, Leelawadee, Nirmala.
    • On Linux: fontconfig.
  • Japanese and Korean text prefers Japanese and Korean fonts for Han characters.
  • core/ttf.js reads glyph outlines, both simple and composite.
  • New core/cff.js reads CFF charstrings, so Noto Sans CJK, the usual Linux CJK font, works. CFF fonts are still never embedded in PDFs.
  • Wrapping breaks between CJK characters (GIF title cards), and ellipsis fitting no longer splits characters outside the BMP.
  • The test font builder moved to tests/unit/font-fixtures.js.

Translations

  • Language flow: app/main.js sends the interface language with every export, preview, clipboard copy, publish and quality-check job. It travels through export-runner → export-worker → buildRenderAst({ language }) into ast.language.
  • Exporters take their labels from core/export-text.js.
  • New tc(context, text) in core/i18n.js covers English words that need two translations ("Contents" as a TOC heading vs. the Export dialog option).
  • Export text now translated in PDF, DOCX, Confluence (Word and storage), HTML (simple and rich), Markdown, Wiki.js, clipboard, PPTX, GIF and image-bundle cards, JSON summaries and the GitHub Pages front page:
    • cover fields: Last verified, Review again on, Author, Guide version, …
    • "N steps · generated DATE", Contents, Untitled step and guide, Skipped
    • callout names, "Go to step N", "Page X of Y"
    • screenshot, flowchart and logo alt text
    • the HTML checklist, copy buttons and footer credit
    • the Confluence HOW-TO-IMPORT.txt and version note
    • <html lang>
  • core/ui-text.js translates main-process messages (329 new strings): Confluence, Wiki.js, GitHub, Google Drive, OneDrive, Dropbox and WebDAV sign-in and errors; cloud sync status; brand and library errors; AI errors; update messages; the recording tray menu; the region-selection hint; capture errors.
  • scripts/check-translations.js now scans all of app/, core/ and exporters/, understands tc() and \n, and has a --same option that lists translations identical to the English.
  • Small English output changes:
    • "1 step" on a one-step PDF cover (was "1 steps")
    • the HOW-TO-IMPORT.txt underline now matches its heading
    • the HTML footer credit is wrapped in <span class="credit">, so GitHub Pages still finds it in any language
    • "The clipboard has no image."
  • Left English on purpose:
    • GitHub alert keywords, because GitHub only reads the English ones
    • file and folder names, commands, JSON fields and git commit messages
    • AI prompts and MCP tool text, which agents read rather than people
    • console logs
    • PowerShell console text during Windows "Update now" (Windows PowerShell 5.1 may not read non-Latin text correctly)
    • dates stay YYYY-MM-DD

Area

  • Exports
  • Sharing and publishing (GitHub Pages, Confluence, Wiki.js)
  • Cloud sync (Google Drive, OneDrive, Dropbox, Nextcloud / WebDAV)
  • Translations
  • Documentation
  • Tests

Testing

  • bash tests/run_test.sh passes

  • Tested manually (describe below)

  • npm test: 1518 pass, 0 fail. New tests:

    • annotation-text-unicode.test.js: TrueType and CFF outlines, glyph size and position, CJK wrapping, font preference, and a real-font test that runs when the machine has a Chinese font (Windows CI does).
    • export-language.test.js: fr, zh-CN, ja, ru and es exports checked in PDF, DOCX, HTML, Markdown, Wiki.js, clipboard, PPTX, JSON and Confluence.
  • npm run translations: fr, es, ru, zh-CN and ja are each at 2258 of 2258.

  • WSL/Linux, end to end: a guide with a Chinese text box and tooltip, exported to Word and PDF through the real exporters.

    • With the Windows fonts from C:\Windows\Fonts (the reporter's setup), Chinese draws correctly.
    • With Noto Sans CJK (CFF) through real fontconfig, Chinese draws correctly.
    • Japanese, Korean, Russian, Greek and Thai also checked.
  • With the language set to zh-CN, the Word export reads 上次验证:2026-11-09 / 下次审阅 / 1 个步骤 · 生成于 …, with no English left.

Still needs a manual check:

  • The live app on Windows: switch the language, then export.
  • The tray menu and region-selection hint in a translated language.
  • Confluence menu names in the translated HOW-TO-IMPORT.txt against a localized Confluence.

Screenshots or recordings

Word export of a step with a Chinese text box and tooltip, Windows fonts.

Before (main):

before

After:

after

Rollout notes

None. No settings or data changes. Exports made through the app now follow the interface language. Headless renders with no language stay English.

Known limits:

  • Arabic, Hebrew and Indic scripts draw letter by letter in exported images, without joining or right-to-left order. PDF body text has the same gap; fixing it needs a shaping engine.
  • On Linux, CJK PDF body text still needs a TrueType CJK font, because CFF fonts are drawn into images but not embedded in PDFs.

Checklist

  • Linked to an issue above
  • Scope is limited to that issue
  • New behavior has tests that check real output
  • Docs updated for anything users will notice
  • New interface text is in t(), and npm run translations lists nothing missing
  • Anything that still needs manual verification is listed above
  • No new network calls, dependencies, or third-party branding

Twest2 added 12 commits November 9, 2026 10:44
Text boxes, tooltips and GIF title cards are burned into screenshots by the
software rasterizer, whose Lato atlas only covers Latin; Chinese and other
scripts came out as "?" in PDF, Word and every other export. Characters the
atlas lacks are now drawn from the outlines of an installed font (the same
font lists the PDF exporter uses), including CFF fonts such as Noto Sans
CJK on Linux. Wrapping breaks between CJK characters.
core/export-text.js gives exporters the interface-language translator.
tc(context, text) tells apart English text used in two senses, and the
translation check now scans exporters/, core/renderast.js and
core/pages-site.js and reads \n in messages.
Exports used English for everything StepForge adds, whatever language
was chosen: "Last verified", "Contents", page numbers, alt text,
callout names, step counts, the HTML checklist and copy buttons, the
Confluence import instructions and the GitHub Pages front page.

The export worker now gets the interface language (Settings > General >
Language) with every job, the render AST carries it, and each exporter
writes its labels through core/export-text.js. English output stays the
same apart from "1 step" on a one-step PDF cover (was "1 steps") and a
correctly sized underline in HOW-TO-IMPORT.txt. GitHub alert names stay
English, since GitHub only reads those.
Errors and statuses from the sign-in, sync, publishing, AI, update and
capture code were English in every language: Confluence, Wiki.js, GitHub,
Google Drive, OneDrive, Dropbox and WebDAV messages, cloud sync status,
brand profile and library errors, find-and-replace field names, the
recording tray menu and the region-selection hint.

core/ui-text.js holds the main process's translator; app/main.js sets its
language with the interface's, and the translation check now scans all
of app/, core/ and exporters/.
…lish

npm run translations -- --same lists catalog entries that read the same
as the English, for review (most are right: Description, Logo, OK).
Adds the main-process messages (sign-in, sync, publishing, AI, updates,
capture, brand profiles, library) and the arrow keys shortcut, so npm run
translations reports nothing missing.
Adds the main-process messages (sign-in, sync, publishing, AI, updates,
capture, brand profiles, library) and the arrow keys shortcut, so npm run
translations reports nothing missing.
Adds the main-process messages (sign-in, sync, publishing, AI, updates,
capture, brand profiles, library) and the arrow keys shortcut, so npm run
translations reports nothing missing.
Adds the main-process messages (sign-in, sync, publishing, AI, updates,
capture, brand profiles, library) and the arrow keys shortcut, so npm run
translations reports nothing missing.
Adds the main-process messages (sign-in, sync, publishing, AI, updates,
capture, brand profiles, library) and the arrow keys shortcut, so npm run
translations reports nothing missing.
They were translated when the module loaded, before the interface
language is known.
@Twest2

Twest2 commented Nov 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T17:19:39.144230Z 65c3373 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 65c3373f0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/cloud-account.js Resolved
The cloud connection test decided pass or fail by looking for "failed"
in each check's text, and the Settings panel looked for /fail/i. With a
translated interface a failed cleanup showed a green check and "Connection
test passed." Each check is now { text, ok }. The sign-in, storage-access
and "Failed:" lines, which were still English, are translated too.
…icode

# Conflicts:
#	exporters/docx.js
#	exporters/html.js
#	exporters/pdf.js
@Twest2
Twest2 merged commit 0fe3f90 into main Nov 9, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant