mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
* feat(desktop): follow OS language in packaged builds
Packaged Electron currently shows Open Design in en-US regardless of
the OS language setting, because the renderer's i18n picks its locale
from `navigator.language` and Chromium hard-codes that to en-US unless
the host process intervenes. Browser users and `tools-dev` users are
unaffected because their `navigator.language` already reflects the
OS / browser preference.
This change:
- Adds `applyOsLocaleSwitch(app)` in `@open-design/desktop/main`. It
reads `app.getPreferredSystemLanguages()[0]` and (when called before
Electron's `ready` event) points Chromium's `--lang` flag at it, so
the renderer's `navigator.language` follows the OS. Safe to call
more than once: `appendSwitch` is a no-op once `app.isReady()`.
- Calls the helper from both Electron entries: `apps/packaged` before
its own `whenReady`, and `runDesktopMain` for tools-dev parity.
- Forwards the resolved locale through
`BrowserWindow.webPreferences.additionalArguments` as
`--od-os-locale=<bcp-47>`, parsed by the preload and exposed at
`window.__od__.client.osLocale`. The host bridge type
(`OpenDesignHostClient.osLocale`) is extended accordingly.
- Updates `detectInitialLocale` in `apps/web/src/i18n/index.tsx` to
read that field as a new step between the existing localStorage and
navigator fallbacks. Browser/web continues to fall through to
`navigator.languages` unchanged.
The explicit `osLocale` channel exists in addition to `--lang` because
some `app.getPreferredSystemLanguages()` strings (e.g. `zh-Hant-TW`,
`pt-PT`) need to round-trip through `resolveSystemLocale` to land on
the right supported locale, which Chromium's `navigator.language`
cannot do on its own.
* fix(web): route OS locale read through getOpenDesignHost
The first cut of detectInitialLocale read `window.__od__.client.osLocale`
directly, which trips `tests/host-boundary.test.ts` — that guard test
keeps web source from referencing preload globals by name so the
boundary stays single-source. Switch to `getOpenDesignHost()` from
`@open-design/host`, and rewrite the i18n test to install the host via
`installMockOpenDesignHost` instead of poking the global directly.
* fix(tools-pack): unblock mac packaged build on pnpm workspaces
Two independent issues prevented `pnpm tools-pack mac build --to all`
from completing on a clean macOS workspace, both unrelated to the
desktop OS-locale change in this PR but bundled here because verifying
that change end-to-end required the packaged pipeline to actually
finish.
1. `apps/web/.next/standalone/node_modules/.pnpm/node_modules/<pkg>`
contained dangling symlinks left by Next's nft trace (e.g. a
`semver -> ../semver@5.7.2/node_modules/semver` link to a
`.pnpm/<pkg>@<ver>` directory pnpm never created). The downstream
`cp { dereference: true }` aborted the whole packaged pipeline
with ENOENT. Walk every artifact tree before copy and unlink
symlinks whose target doesn't resolve. Targets that *do* resolve
stay untouched.
2. Next 16's standalone build under pnpm workspaces does not hoist
peer-dep packages (react, react-dom, styled-jsx) into
`<standalone>/apps/web/node_modules`. The downstream
`web-standalone-after-pack.cjs` audit then does
`createRequire(server.js).resolve('react/package.json')`, whose
module walk falls out of the standalone tree and aborts the
electron-builder phase. Add a `hoistStandaloneNextPeerDeps` step
for the web standalone artifact only: it locates the
`<pkg>@<version>` (not peer-resolved sibling) directory under
`.pnpm` and symlinks it into `apps/web/node_modules/<pkg>`. The
subsequent `cp { dereference: true }` then writes the real
directory into the cache so the packaged tree stays self-contained.
Verified by `pnpm tools-pack mac build --to all` succeeding end-to-end
(zip + dmg + app), then `pnpm tools-pack mac install` and
`pnpm exec tools-pack mac inspect --expr` reading the desired
`__od__.client.osLocale` from the packaged renderer.
* feat(desktop): fold encodeURIComponent + manual locale source + pet window from #2554
Three defensive improvements lifted from @Eli-tangerine's parallel
implementation on #2554, kept consistent with the OS-locale chain
already on this branch:
- The argv value crossing main → preload is now wrapped with
encodeURIComponent / decodeURIComponent so a locale string with `;`,
`=`, or any other Chromium argv special char round-trips cleanly.
BCP-47 region tags don't carry those today, but the renderer parser
no longer has to assume it.
- `setLocale` now also writes `open-design:locale-source = "manual"`
to localStorage, and `detectInitialLocale` only treats the stored
locale as winning when that marker is present. An untagged value
(left over from a future auto-write path, or a stale install) no
longer pins the app to an old language once the host injects a
fresh OS locale. Today `setLocale` is the only writer so the marker
has no behaviour difference yet — this is a defensive net.
- `createDesktopPetWindow` now receives `osLocale` and forwards the
same `additionalArguments` as the main `BrowserWindow`, so the
pet renderer's `__od__.client.osLocale` is consistent with the main
window's instead of being silently undefined.
Co-authored idea credit: changes mirror the locale-piece of
@Eli-tangerine on #2554 — that PR is closing in favour of this one.
Tests: detect-initial-locale gets a new "untagged localStorage value
loses to host locale" case. desktop 62/62, host 13/13, web i18n +
host-boundary 15/15 stay green.
* feat(web): fold onboarding view styles from #2554
Pulls the 747-line addition to `apps/web/src/styles/home/entry-layout.css`
from @Eli-tangerine's #2554 — the visual layer for the global onboarding
flow (`/onboarding` view, Connect / About-you / Design-system steps).
The view itself was already plumbed through `EntryShell.tsx`; this adds
the styling that makes it shippable on v0.8.0.
#2554 is closing in favour of this branch, so the CSS lands here so the
onboarding work doesn't get dropped on the floor.
Co-authored idea credit: @Eli-tangerine — original styling on #2554.
* fix(tools-pack): make hoistStandaloneNextPeerDeps idempotent across builds
Addresses non-blocking review by @PerishCode on #2560: the previous
`if (await pathExists(linkPath)) continue;` guard uses `access()`,
which follows symlinks. A stale symlink from a previous build whose
`.pnpm/<pkg>@<version>` target moved (e.g. after a react/react-dom
version bump that invalidates the workspace-build cache key and forces
a re-run) reports as missing through `pathExists`, then `symlink()`
rejects with EEXIST and the unhandled rejection aborts the packaged
build.
Switch to `lstat` (which does not follow the link) so we can tell
"genuinely empty slot", "real directory left by Next" and "stale
symlink" apart, then unlink stale entries before re-creating. Also
move `stripBrokenSymlinks` ahead of `hoistStandaloneNextPeerDeps` in
`copyWorkspaceBuildArtifactsToCache` so any leftover dangling links
that survived a previous run are cleared before hoist tries to write.
|
||
|---|---|---|
| .. | ||
| src | ||
| tests | ||
| esbuild.config.mjs | ||
| package.json | ||
| tsconfig.json | ||
| tsconfig.tests.json | ||