livelocale 0.8.1 → 0.10.0-next.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +411 -5
  2. package/dist/client/index.cjs +150 -86
  3. package/dist/client/index.cjs.map +1 -1
  4. package/dist/client/index.d.cts +35 -21
  5. package/dist/client/index.d.ts +35 -21
  6. package/dist/client/index.js +150 -86
  7. package/dist/client/index.js.map +1 -1
  8. package/dist/codemod/index.cjs +4133 -129
  9. package/dist/codemod/index.cjs.map +1 -1
  10. package/dist/codemod/index.js +4155 -151
  11. package/dist/codemod/index.js.map +1 -1
  12. package/dist/react/index.cjs +157 -92
  13. package/dist/react/index.cjs.map +1 -1
  14. package/dist/react/index.js +157 -92
  15. package/dist/react/index.js.map +1 -1
  16. package/dist/server/index.cjs +185 -114
  17. package/dist/server/index.cjs.map +1 -1
  18. package/dist/server/index.d.cts +12 -2
  19. package/dist/server/index.d.ts +12 -2
  20. package/dist/server/index.js +185 -114
  21. package/dist/server/index.js.map +1 -1
  22. package/dist/studio/assets/index-Dlvw1H47.js +14 -0
  23. package/dist/studio/assets/index-FFC_lDHv.css +1 -0
  24. package/dist/studio/assets/inter-latin-300-normal-BVlfKGgI.woff2 +0 -0
  25. package/dist/studio/assets/inter-latin-300-normal-i8F0SvXL.woff +0 -0
  26. package/dist/studio/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  27. package/dist/studio/assets/inter-latin-400-normal-CyCys3Eg.woff +0 -0
  28. package/dist/studio/assets/inter-latin-500-normal-BL9OpVg8.woff +0 -0
  29. package/dist/studio/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  30. package/dist/studio/assets/inter-latin-600-normal-CiBQ2DWP.woff +0 -0
  31. package/dist/studio/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  32. package/dist/studio/assets/inter-latin-700-normal-BLAVimhd.woff +0 -0
  33. package/dist/studio/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
  34. package/dist/studio/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
  35. package/dist/studio/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
  36. package/dist/studio/assets/outfit-latin-500-normal-ClnHRwRh.woff +0 -0
  37. package/dist/studio/assets/outfit-latin-500-normal-DKnIMDSk.woff2 +0 -0
  38. package/dist/studio/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
  39. package/dist/studio/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
  40. package/dist/studio/assets/outfit-latin-700-normal-Cu9v6i1X.woff2 +0 -0
  41. package/dist/studio/assets/outfit-latin-700-normal-D4itBLBr.woff +0 -0
  42. package/dist/studio/index.html +3 -6
  43. package/dist/vite/index.cjs +740 -77
  44. package/dist/vite/index.cjs.map +1 -1
  45. package/dist/vite/index.d.cts +22 -2
  46. package/dist/vite/index.d.ts +22 -2
  47. package/dist/vite/index.js +739 -77
  48. package/dist/vite/index.js.map +1 -1
  49. package/package.json +4 -1
  50. package/dist/studio/assets/index-D6D5nPQI.js +0 -10
  51. package/dist/studio/assets/index-z0sbyt6N.css +0 -2
package/README.md CHANGED
@@ -195,6 +195,37 @@ Generates API route handlers based on your router structure (App vs Pages Router
195
195
  npx livelocale init [--dir <path>]
196
196
  ```
197
197
 
198
+ ### `init --share`
199
+
200
+ Sets up the share link for your stack and, on a GitHub remote, writes
201
+ `.github/workflows/livelocale.yml`, which turns change links into pull requests. It prints every
202
+ file it creates, updates, leaves unchanged or skips, then what is left for you to do.
203
+
204
+ ```bash
205
+ npx livelocale init --share [--locales <path>] [--source <locale>] [--branches <a,b>] [--overwrite] [--dir <path>]
206
+ ```
207
+
208
+ | Stack | Build change |
209
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
210
+ | CRA / webpack / Rsbuild | `"build": "react-scripts build && livelocale pack build"`. This is an explicit `&&`, not a `postbuild` hook, because Yarn Berry and some pnpm versions skip pre/post scripts, and hosts that call the bundler directly skip them too ([yarn](https://v2.yarnpkg.com/advanced/lifecycle-scripts), [pnpm](https://pnpm.io/cli/run)). |
211
+ | Next.js `output: 'export'` | `"build:preview": "livelocale build --preview -- next build"`, deployed to a staging location, because the HTML is pre-rendered and must be watermarked at build time. |
212
+ | Next.js on Vercel/Node | For the Preview environment, use the build command `livelocale build --preview -- next build`. It packs into a gitignored `public/livelocale/`. |
213
+ | Custom CI | `LIVELOCALE=preview <your build>` (only for SSR/SSG), then `npx livelocale pack <outDir>`. |
214
+
215
+ For Vite it adds `share: true` to your `liveLocaleVite({ ... })` call. The scripts it writes also
216
+ pass `--locales` and `--source`; webpack and Rsbuild pack `dist`.
217
+
218
+ - `--locales` — locales directory relative to the project (default: the first of `locales`,
219
+ `src/locales`, `public/locales`, `src/i18n/locales` and `messages` that holds locale JSON).
220
+ - `--source` — source locale (default `en`).
221
+ - `--branches` — branches a change link may target (default: the repository's default branch, at
222
+ most 10). Merge the workflow into each of them too: a pull request into a branch runs that
223
+ branch's copy of the workflow.
224
+ - `--overwrite` — replace an existing workflow file whose content differs (it is skipped otherwise).
225
+ - On another git host no workflow is written; use `npx livelocale apply "<link>" --pr`.
226
+
227
+ Commit and push the result: the workflow must be on the default branch.
228
+
198
229
  ### `studio`
199
230
 
200
231
  Spins up a lightweight, CORS-enabled HTTP server serving the Visual Studio assets statically.
@@ -212,11 +243,21 @@ Inspects the project for the integration problems the Studio cannot recover from
212
243
  probes the running app.
213
244
 
214
245
  ```bash
215
- npx livelocale doctor [--dir <path>] [--locales <path>] [--app <origin>] [--token <token>]
246
+ npx livelocale doctor [--dir <path>] [--locales <path>] [--app <url>] [--share] [--token <token>]
216
247
  ```
217
248
 
218
249
  - `--locales` — locales directory relative to the project (default `locales`).
219
- - `--app` — also check that the mutation API answers and that pages are embeddable.
250
+ - `--app` — also check that the mutation API answers and that pages are embeddable. A path is
251
+ the app base: `--app https://user.github.io/repo/` probes a GitHub Pages project site (a
252
+ trailing `index.html` is dropped).
253
+ - `--share` — run the share link probes even when `<base>livelocale/manifest.json` does not
254
+ answer. They also run on their own whenever the manifest answers with JSON. They check the
255
+ Studio page, the manifest, `flag.js` and its tag first in `<head>`, frame headers
256
+ (`X-Frame-Options: DENY` or `frame-ancestors 'none'` breaks the Studio; `SAMEORIGIN` is fine),
257
+ `script-src`, and service workers, then print `🔗 Share link: <base>livelocale/index.html`.
258
+ When a Workbox service worker (vite-plugin-pwa, workbox-webpack-plugin) would answer the Studio
259
+ with your app shell, add this line to its Workbox options:
260
+ `navigateFallbackDenylist: [/^\/livelocale\//]`.
220
261
  - `--token` — access token for a preview deployment (defaults to `LIVELOCALE_TOKEN`); with it the
221
262
  doctor also reports the server mode and repository access problems.
222
263
 
@@ -254,6 +295,107 @@ English's two are not reported.
254
295
  - run: npx livelocale check
255
296
  ```
256
297
 
298
+ ### `pack`
299
+
300
+ Turns a finished static build into a share link: it writes the Studio, `manifest.json`, the locale
301
+ files and `flag.js` into `<outDir>/livelocale/` and links `flag.js` from every HTML page. Run it
302
+ after your build, for example `"build": "vite build && livelocale pack dist"`.
303
+
304
+ ```bash
305
+ npx livelocale pack <outDir> [--dir <path>] [--locales <path>] [--source <locale>] [--base <path>] [--expose-repo] [--no-inject]
306
+ ```
307
+
308
+ - `<outDir>` — the built site folder, relative to `--dir` (for example `dist`, `build` or `out`).
309
+ - `--locales` — locales directory relative to the project (default `locales`).
310
+ - `--source` — source locale (default `en`, else the first locale).
311
+ - `--base` — site path the app is served from, such as `/repo/` (default: detected from the
312
+ project, else `/`). A relative base (`./`) prints a warning; pass an absolute one if the app has
313
+ client-side routes.
314
+ - `--expose-repo` — put the GitHub `owner/repo` into `livelocale/manifest.json` (off by default).
315
+ - `--no-inject` — do not add the `flag.js` script to HTML files. Next.js outputs are never injected.
316
+
317
+ The share link is `<your site><base>livelocale/index.html`. Nothing is written outside
318
+ `<outDir>/livelocale/` except that one script tag, and an existing `livelocale/` folder is replaced
319
+ only when pack wrote it.
320
+
321
+ ### `build`
322
+
323
+ Runs your build command and packs its output in one step. The environment variables work the same
324
+ on Windows, macOS and Linux, so no `cross-env` is needed.
325
+
326
+ ```bash
327
+ npx livelocale build [--preview] [--out <dir>] [pack options] -- <your build command>
328
+ ```
329
+
330
+ - `--preview` — run the command with `LIVELOCALE=preview` and `NEXT_PUBLIC_LIVELOCALE=preview`, so
331
+ server-rendered and pre-rendered pages carry watermarks.
332
+ - `--out` — the build output folder (default: the first of `dist/`, `build/` or `out/` that holds an
333
+ `index.html` written by this build). Next.js projects always pack into `public/livelocale/`
334
+ before the build runs, so Next copies it into the output.
335
+ - `--dir`, `--locales`, `--source`, `--base` and `--expose-repo` work as they do for `pack`.
336
+
337
+ | Stack | Build change |
338
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
339
+ | Next.js `output: 'export'` | `"build:preview": "livelocale build --preview -- next build"`, deployed to a staging location, because the HTML is pre-rendered and must be watermarked at build time. |
340
+ | Next.js on Vercel/Node | For the Preview environment, use the build command `livelocale build --preview -- next build`. It packs into a gitignored `public/livelocale/`. |
341
+ | Custom CI | `LIVELOCALE=preview <your build>` (only for SSR/SSG), then `npx livelocale pack <outDir>`. |
342
+
343
+ A static export stops before building when `app/api/livelocale/route.*` exports POST, because export
344
+ mode only allows GET route handlers; the share link does not need that route.
345
+
346
+ ### `apply`
347
+
348
+ Applies a LiveLocale change link (the `lc1.` link a translator sends from the share link) to your
349
+ locale files. Every edit is checked again against your own files and source locale before anything
350
+ is written.
351
+
352
+ ```bash
353
+ npx livelocale apply "<link>" [--pr] [--dir <path>] [--locales <path>] [--source <locale>] [--force] [--dry-run]
354
+ npx livelocale apply changes.txt
355
+ npx livelocale apply - < changes.txt
356
+ npx livelocale apply --clipboard
357
+ ```
358
+
359
+ - The input is the change link itself (or the Studio link that carries it), a file that holds it
360
+ (the change file Send offers, or a saved email or issue), `-` to read standard input, or
361
+ `--clipboard` to read the clipboard. Pass the link or `--clipboard`, not both.
362
+ - cmd.exe cuts command lines at 8,191 characters, so on Windows pass a long link as a file or with
363
+ `--clipboard`.
364
+ - `--pr` — commit the changes on a new `livelocale/apply-<time>` branch, push it and open a pull
365
+ request.
366
+ - `--locales` and `--source` work as they do for `check` (default `locales`, and `en`, else the
367
+ first locale).
368
+ - `--dry-run` — plan the edits and print the summary without writing any file.
369
+ - `--force` — also apply edits the translator saved with "Save anyway" (for example a dropped
370
+ placeholder). Without it they are reported as `needs --force` and skipped.
371
+
372
+ The summary lists each edit's locale, key and status (applied, already done, conflict, needs
373
+ --force or rejected) and never prints translation values. The exit code is 0 when every edit was
374
+ applied or already done, and 1 when any edit is a conflict, needs `--force` or was rejected, or
375
+ when the link cannot be read.
376
+
377
+ #### `apply --github-event`
378
+
379
+ ```bash
380
+ npx livelocale apply --github-event --locales <path> --source <locale> [--branches <a,b>] [--dir <path>]
381
+ ```
382
+
383
+ For the generated `.github/workflows/livelocale.yml` workflow only; do not run it yourself. It reads
384
+ the issue, comment, dispatch or pull request event from `$GITHUB_EVENT_PATH` (never from the
385
+ command line) and needs `GITHUB_TOKEN`.
386
+
387
+ - Only a maintainer (OWNER, MEMBER or COLLABORATOR, or write access) makes it write. Anyone else
388
+ gets the reply "Waiting for a maintainer: comment `/livelocale apply`".
389
+ - It writes one commit on a `livelocale/issue-<n>` branch (`livelocale/run-<id>` for a manual
390
+ run), opens or reuses the pull request, and comments the link on the issue. When the repository
391
+ does not let GitHub Actions open pull requests, the comment carries a one-click compare link
392
+ instead.
393
+ - `--locales` and `--dir` are relative to the repository root. `--branches` lists the branches a
394
+ link may target (default: the repository's default branch); a link made from any other branch
395
+ targets the default branch, and the comment says so.
396
+ - `--force` is not accepted; a maintainer comments `/livelocale apply --force` instead.
397
+ - When the pull request is merged or closed, it closes the issue.
398
+
257
399
  ### `migrate`
258
400
 
259
401
  Performs static analysis to scan and automatically wrap existing `react-i18next` hooks with `wrapTranslationEngine`.
@@ -286,6 +428,33 @@ export default defineConfig({
286
428
  });
287
429
  ```
288
430
 
431
+ ### Share link from `vite build`
432
+
433
+ Set `share: true` and `vite build` also writes a share link: the Studio, `manifest.json`, the
434
+ locale files and `flag.js` go into `<outDir>/livelocale/`, and `index.html` loads
435
+ `<base>livelocale/flag.js` first in `<head>`. Deploy the output anywhere static and send
436
+ `<origin><base>livelocale/index.html`. Without `share` the build output is unchanged.
437
+
438
+ ```typescript
439
+ liveLocaleVite({
440
+ localesPath: './locales',
441
+ share: true, // write <outDir>/livelocale/ on vite build (default: false)
442
+ exposeRepo: false, // put the GitHub owner/repo into the manifest (default: false)
443
+ sourceLocale: 'en', // default: en when present, else the first locale
444
+ shareBase: '/app/', // the site path the HTML is served from (default: Vite base)
445
+ });
446
+ ```
447
+
448
+ | Option | Default | What it does |
449
+ | -------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
450
+ | `share` | `false` | Write the share Studio into `<outDir>/livelocale/` on `vite build`. SSR and library builds are skipped. |
451
+ | `exposeRepo` | `false` | Put the GitHub `owner/repo` into the published manifest and the change link. Leave it off for a private repository. |
452
+ | `sourceLocale` | `en` when present, else the first locale | The locale placeholders are checked against. |
453
+ | `shareBase` | Vite `base` | The path the HTML is served from. Set it when `base` is a full URL (a CDN), which the build otherwise rejects with `BAD_BASE`, or differs. |
454
+
455
+ A relative `base` (`./`) links `flag.js` per HTML file and prints a warning: pages served by a
456
+ client-side route fallback cannot load it, so prefer an absolute `base` for apps with such routes.
457
+
289
458
  ---
290
459
 
291
460
  ## 🧾 Reviewing and committing from the Studio
@@ -346,6 +515,243 @@ value when you edit the source language itself.
346
515
  For API clients: send `reference` with the POST to enable the check, and `force: true` to bypass
347
516
  it. Without `reference` only the syntax check runs.
348
517
 
518
+ ## 🔗 Share link on any host
519
+
520
+ Translators fix text on your live site with no account, and every fix becomes a pull request with one click.
521
+
522
+ A share link needs no server, no account and no credential anywhere. The Studio ships inside your
523
+ build at `<base>livelocale/`, so any host that serves the site serves the Studio too: Apache,
524
+ Nginx, S3, GitHub Pages, Netlify, Cloudflare Pages or Vercel. The translator's fixes stay in their
525
+ own browser until they send you a change link. On GitHub you turn that link into a pull request
526
+ with one click; on any other git host, with one command.
527
+
528
+ ### Setup
529
+
530
+ 1. Run `npx livelocale init --share` in your project. It sets up the build for your stack (see the
531
+ table below) and, on a GitHub remote, writes `.github/workflows/livelocale.yml`. See
532
+ [`init --share`](#init---share) for its options.
533
+ 2. Commit and push the result. The workflow must be on the default branch, because GitHub runs
534
+ issue and comment workflows only from there.
535
+ 3. On GitHub, tick the one setting below.
536
+ 4. Deploy as usual, then check the deployment and print the share link (next step).
537
+
538
+ On a GitHub remote, `init --share` writes this workflow (`X.Y.Z` is the livelocale version you
539
+ installed, `locales`, `en` and `main` come from your project):
540
+
541
+ ````yaml
542
+ # Written by `npx livelocale init --share`. Turns LiveLocale change links into pull requests.
543
+ # livelocale reads the link from the event file; it never reaches a shell command.
544
+ name: LiveLocale
545
+ on:
546
+ issues: { types: [opened] }
547
+ issue_comment: { types: [created] }
548
+ pull_request: { types: [closed] }
549
+ workflow_dispatch: { inputs: { link: { description: 'LiveLocale change link', required: true } } }
550
+ permissions: { contents: write, pull-requests: write, issues: write }
551
+ concurrency: { group: 'livelocale-${{ github.event.issue.number || github.run_id }}', queue: max }
552
+ jobs:
553
+ apply:
554
+ if: >-
555
+ github.event_name == 'workflow_dispatch' ||
556
+ (github.event_name == 'issues' && contains(github.event.issue.body, '```livelocale')) ||
557
+ (github.event_name == 'issue_comment' && !github.event.issue.pull_request &&
558
+ startsWith(github.event.comment.body, '/livelocale')) ||
559
+ (github.event_name == 'pull_request' && startsWith(github.event.pull_request.head.ref, 'livelocale/issue-') &&
560
+ github.event.pull_request.base.ref != github.event.repository.default_branch)
561
+ runs-on: ubuntu-latest
562
+ steps:
563
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
564
+ with: { persist-credentials: false }
565
+ - run: npx --yes livelocale@X.Y.Z apply --github-event --locales locales --source en --branches main
566
+ env: { GITHUB_TOKEN: '${{ github.token }}' }
567
+ ````
568
+
569
+ It reads the change link only from the event file, never from a shell command, and it has no
570
+ `pull_request_target` trigger.
571
+
572
+ To set up the build by hand instead:
573
+
574
+ | Stack | Build change |
575
+ | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
576
+ | Vite | `share: true` in `liveLocaleVite(...)` (see [Share link from `vite build`](#share-link-from-vite-build)). |
577
+ | CRA, webpack and Rsbuild | `"build": "<bundler> && livelocale pack build"`, for example `"build": "react-scripts build && livelocale pack build"`. |
578
+ | Next.js `output: 'export'` | `livelocale build --preview -- next build`, deployed to a staging location, because the HTML is pre-rendered and must be watermarked. |
579
+ | Next.js on Vercel/Node | `livelocale build --preview -- next build` as the Preview environment's build command. It packs into a gitignored `public/livelocale/`. |
580
+ | Custom CI | `LIVELOCALE=preview <build>` (only for SSR/SSG), then `npx livelocale pack <outDir>`. |
581
+
582
+ For CRA, webpack and Rsbuild, use an explicit `&&`, not a `postbuild` script: Yarn Berry and some
583
+ pnpm versions skip pre/post scripts, and hosts that call the bundler directly skip them too.
584
+
585
+ Deploy the output as usual, then check it and print the share link:
586
+
587
+ ```bash
588
+ npx livelocale doctor --app <url>
589
+ ```
590
+
591
+ The doctor checks the Studio page, the manifest, `flag.js`, frame headers and service workers, then
592
+ prints `🔗 Share link: <base>livelocale/index.html`. Pin that link for your translators.
593
+
594
+ #### The one-checkbox setting
595
+
596
+ In the repository's **Settings → Actions → General → Workflow permissions**, tick
597
+ **Allow GitHub Actions to create and approve pull requests**. Without it the workflow still
598
+ commits the branch, but GitHub refuses to let it open the pull request; the issue comment then
599
+ carries a one-click compare link that opens the pull request form already filled in, and you
600
+ press **Create pull request** there.
601
+
602
+ ### Translator steps
603
+
604
+ 1. Open the share link in a desktop browser. There is no sign-up, no password and nothing to
605
+ install. If the site has its own login, sign in as usual.
606
+ 2. On the first visit, read the three tips and, optionally, type your name so you are credited in
607
+ the pull request.
608
+ 3. Check the language shown at the top. It is detected from the page text; change it if it is
609
+ wrong.
610
+ 4. Hold **Alt** (Option on Mac) and click the wrong text. The editor shows the source text, the
611
+ current translation, the placeholders that must stay, and one field per plural form.
612
+ 5. Type the fix and press **Save** (Ctrl+Enter). When a placeholder is missing, a message explains
613
+ it, and **Save anyway** stays available; it marks the edit for the developer.
614
+ 6. Keep browsing and fixing. Changes survive reloads and closing the tab. A counter shows how many
615
+ are not sent yet ("5 changes not sent"), and **Changes** lists each one with Undo.
616
+ 7. Click **Send to developer** and add an optional note. Then choose **Copy link** and paste it in
617
+ any chat or email, or **Download file** for a large batch.
618
+ 8. Sent changes stay in the list, marked "Sent".
619
+
620
+ ### Developer
621
+
622
+ Open the change link. The Studio opens in **Review mode**, with the proposed edits shown read-only
623
+ on the real page and a before/after table with the check results. Then turn it into a pull request.
624
+
625
+ **On GitHub, with the workflow:**
626
+
627
+ - Press **Create pull request** in Review mode. It opens a GitHub issue already filled in with the
628
+ change link; press **Submit new issue**. About a minute later the workflow has committed the
629
+ edits on a `livelocale/issue-<n>` branch, opened the pull request and commented its link on the
630
+ issue. Without `exposeRepo: true`, Review mode asks for `owner/repo` the first time and remembers
631
+ it in that browser.
632
+ - With issues turned off, or for a link you would rather not file: **Actions → LiveLocale → Run
633
+ workflow**, paste the link and run it. The result is on the run's summary page.
634
+ - **The trust gate.** The workflow writes only for a maintainer: the issue author or the
635
+ commenter must be an owner, member or collaborator, or have write access. For anyone else it
636
+ replies "Waiting for a maintainer: comment `/livelocale apply`", and nothing is written until a
637
+ maintainer posts that comment on the issue. Edits the translator saved with "Save anyway" are
638
+ skipped as `needs --force`; comment `/livelocale apply --force` to include them.
639
+ - **Base branches.** By default every pull request targets the default branch. To let links made
640
+ from other builds (for example a `staging` deployment) target their own branch, list the
641
+ branches with `npx livelocale init --share --branches main,staging`. A link from any other
642
+ branch targets the default branch, and the comment says so. A pull request into the default
643
+ branch says `Closes #n`, so merging it closes the issue; into another branch it says `Refs #n`,
644
+ because GitHub only closes issues from the default branch, and LiveLocale closes the issue
645
+ itself when that pull request is merged or closed.
646
+ Also merge .github/workflows/livelocale.yml into each extra branch; pull requests into it run workflows from that branch, so LiveLocale cannot close their issues otherwise.
647
+
648
+ **On any git host, from your machine:**
649
+
650
+ ```bash
651
+ npx livelocale apply "<link or file>" --pr
652
+ ```
653
+
654
+ This works with your own `git` login: it commits only the locale files on a new
655
+ `livelocale/apply-<time>` branch and pushes it. On GitHub it opens the pull request with `gh`;
656
+ elsewhere it prints the branch to open a pull or merge request from. Every edit is checked again
657
+ against your own files first. For a long link, use `npx livelocale apply --clipboard`, or pass `-` and pipe
658
+ the link in (`npx livelocale apply - < changes.txt`). See [`apply`](#apply) for every option.
659
+
660
+ #### Run CI on LiveLocale PRs without the approval click
661
+
662
+ Pull requests opened with the workflow's `GITHUB_TOKEN` start their CI in an approval-required
663
+ state: someone has to press **Approve workflows to run** on each one. Pull requests opened with a
664
+ GitHub App token start CI as usual. To use one:
665
+
666
+ 1. Create a GitHub App with **Contents**, **Pull requests** and **Issues** set to read and write,
667
+ and install it on the repository.
668
+ 2. Store its ID as the repository variable `LIVELOCALE_APP_ID` and its private key as the secret
669
+ `LIVELOCALE_APP_PRIVATE_KEY`.
670
+ 3. In `.github/workflows/livelocale.yml`, add this step before the `apply` step and give its token
671
+ to the `apply` step as `GITHUB_TOKEN`:
672
+
673
+ ```yaml
674
+ - id: app-token
675
+ uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
676
+ with:
677
+ {
678
+ app-id: '${{ vars.LIVELOCALE_APP_ID }}',
679
+ private-key: '${{ secrets.LIVELOCALE_APP_PRIVATE_KEY }}',
680
+ }
681
+ - run: npx --yes livelocale@X.Y.Z apply --github-event --locales locales --source en --branches main
682
+ env: { GITHUB_TOKEN: '${{ steps.app-token.outputs.token }}' }
683
+ ```
684
+
685
+ `init --share` leaves an edited workflow alone unless you pass `--overwrite`.
686
+
687
+ ### Translators with GitHub access
688
+
689
+ **Open on GitHub** in the Send dialog lets a translator file the issue themselves, so the pull
690
+ request opens with no developer click when the translator is a collaborator (otherwise a
691
+ maintainer comments `/livelocale apply`). It is available only with `exposeRepo: true`, because it
692
+ needs the repository's `owner/repo` in the public manifest. Turn it on for a private repository
693
+ whose translators already have GitHub access; with the default, translators use **Copy link** or
694
+ **Download file**, and the developer path is unchanged.
695
+
696
+ ### What "Sent" means
697
+
698
+ In this mode "Sent" means the translator handed the link over; it is not a pull request until a developer applies it.
699
+
700
+ ### Hosting notes
701
+
702
+ - **S3 and CloudFront:** the link must end in `index.html`, because an S3 REST origin does not
703
+ resolve folder indexes.
704
+ - **GitHub Pages:** the folder is `livelocale/`, with no underscore for Jekyll to drop, and a
705
+ project site's `/repo/` base path is handled.
706
+ - **Netlify and Cloudflare Pages:** `_headers` must not send DENY (`X-Frame-Options: DENY` or
707
+ `frame-ancestors 'none'`); SAMEORIGIN is fine. Every per-deploy URL is a separate origin with its
708
+ own drafts, so share the branch alias (for example
709
+ `https://staging--site.netlify.app/livelocale/index.html`), not a per-deploy URL.
710
+ - **Basic auth and host password protection** carry over, because the Studio is on the same site.
711
+ - **Vercel:** Deployment Protection must be off for the deployment you share, or the translator
712
+ must have access to it. `doctor --app` reports the login wall.
713
+ - **PWA:** a Workbox service worker (vite-plugin-pwa, workbox-webpack-plugin) can answer the Studio
714
+ with your app shell. Add `navigateFallbackDenylist: [/^\/livelocale\//]` to its Workbox options.
715
+ - **Relative bases** (`base: './'`, CRA `homepage: '.'`): pages served by a client-side route
716
+ fallback cannot load `flag.js`, so pack prints "The app base is relative (./), so flag.js is
717
+ linked per HTML file. Pages served by a client-side route fallback cannot load it; build with
718
+ an absolute base (--base /path/) if the app has such routes."
719
+
720
+ ### Security
721
+
722
+ - **No credential anywhere.** The share link, the build, the host and the browser hold no token.
723
+ Write access stays with the developer's own git login.
724
+ - **A leaked link only proposes text.** A developer still has to apply it, and a person has to
725
+ merge the pull request. `apply` re-validates every edit against your own source locale.
726
+ - **`exposeRepo: false` by default.** The GitHub `owner/repo` is published only with
727
+ `exposeRepo: true` (or `pack --expose-repo`).
728
+ - **The Studio is `noindex`**, so search engines do not list it.
729
+ - **`manifest.json` is public.** `<base>livelocale/manifest.json` makes every string and key name
730
+ public, including keys the app does not show.
731
+ - **The same-origin risk is accepted.** The Studio frames your app on the same origin, so app
732
+ scripts can read and alter drafts. This is accepted because no secret is stored, and you review
733
+ every edit before it is merged.
734
+
735
+ ### Honest risks
736
+
737
+ - **Issues in public repositories are public.** A change link filed as an issue, with its text,
738
+ the translator's name and note, is visible to everyone.
739
+ - **Bot pull requests wait for a click.** CI on a pull request the workflow opens waits until
740
+ someone presses **Approve workflows to run**, unless you use the
741
+ [App token](#run-ci-on-livelocale-prs-without-the-approval-click).
742
+ - **Vercel may refuse the commit.** Vercel can block deployments of commits whose author is not a
743
+ member of the Vercel team. The commit author is the maintainer who triggered the run, with a
744
+ `Translated-by:` trailer for the translator.
745
+ - **One-click automation is GitHub-only.** Other git hosts use
746
+ `npx livelocale apply "<link>" --pr`, which works anywhere git works.
747
+
748
+ ### Limits
749
+
750
+ - **Desktop only.** Alt+Click needs a keyboard; phones and tablets can only view.
751
+ - **Drafts live in one browser.** Clearing site data, a private window, or Safari's 7-day cap on
752
+ script-writable storage can lose unsent work. Send often, or use **Download backup** in Changes.
753
+ - **One app per repository.**
754
+
349
755
  ## 🌍 Preview mode: editing without a checkout
350
756
 
351
757
  Development mode needs a developer's machine. Preview mode lets a product manager, translator, or
@@ -397,9 +803,9 @@ The app must also let the Studio embed it. Next.js evaluates `headers()` in `nex
397
803
  preview is built, not only at run time.
398
804
 
399
805
  For a Vite app, the Vite plugin mirrors the server's `LIVELOCALE` flag into the page, so
400
- `LIVELOCALE=preview` alone is enough; no `NEXT_PUBLIC_` variable is needed there. The plugin runs
401
- on the Vite dev server only: a static `vite build` served by Apache, Nginx or a CDN has no server for
402
- the Studio to save through, so preview mode does not work there yet.
806
+ `LIVELOCALE=preview` alone is enough; no `NEXT_PUBLIC_` variable is needed there. Preview mode
807
+ runs on the Vite dev server only. For a static `vite build` served by Apache, Nginx or a CDN, use
808
+ the share link instead; see [Share link on any host](#-share-link-on-any-host).
403
809
 
404
810
  Then open the Studio with `?app=https://<preview-url>` (or `studio --app`). It shows a
405
811
  **PREVIEW** badge, asks for the access token, and the Changes panel switches to branch and