@prettifystudio/lyngo-cli 0.2.2 → 0.2.3

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 (3) hide show
  1. package/README.md +4 -1
  2. package/bin/lyngo +42 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -45,6 +45,9 @@ already set up.
45
45
  - With an agent: build as usual. The hook runs `lyngo localize` at the end of
46
46
  every task.
47
47
  - Without an agent: run `lyngo localize` before you commit.
48
+ - A repository that was never localized: `lyngo localize --all` once. It walks
49
+ every source file a scan would read, in batches, and leaves the result in
50
+ your working tree to review and commit. No pull request.
48
51
  - Anything pushed without it still gets a pull request from the Lyngo GitHub
49
52
  App.
50
53
 
@@ -56,7 +59,7 @@ already set up.
56
59
  | `lyngo logout` | Revokes the token and deletes it from this machine |
57
60
  | `lyngo whoami` | The account, the token prefix and your workspaces |
58
61
  | `lyngo init` | Connects the repository (see above). Flags: `--languages`, `--workspace`, `--yes`, `--github` |
59
- | `lyngo localize` | Localizes and translates what changed in the working tree. Flags: `--languages`, `--dry` |
62
+ | `lyngo localize` | Localizes and translates what changed in the working tree. Flags: `--all` (the whole repository, in batches of 30), `--languages`, `--no-translate`, `--dry` |
60
63
  | `lyngo check <file>` | The user-facing strings of one file |
61
64
  | `lyngo status` | The project as Lyngo knows it |
62
65
 
package/bin/lyngo CHANGED
@@ -8,7 +8,7 @@
8
8
  // lyngo whoami who the token belongs to
9
9
  // lyngo init [--languages fr,de] [--primary en] [--workspace <name>] [--yes] [--github]
10
10
  // connect this repository: project, scaffolding, languages, agent hook
11
- // lyngo localize [--languages fr,de] [--no-translate] [--dry]
11
+ // lyngo localize [--all] [--languages fr,de] [--no-translate] [--dry]
12
12
  // localize (+ translate) the working tree's changes
13
13
  // lyngo check <file> the user-facing strings of one file
14
14
  // lyngo status the project as Lyngo knows it
@@ -626,23 +626,48 @@ function changedFiles(top) {
626
626
  return [...out].sort();
627
627
  }
628
628
 
629
+ // Every tracked source file of the repository, as the scan would pick them:
630
+ // a quick local cut by extension and folder, then the server's own rules.
631
+ async function allSourceFiles(top) {
632
+ const tracked = git(['ls-files', '-z']).split('\0').filter(Boolean).filter((p) => SRC.test(p) && !SKIP.test(p) && fs.existsSync(path.join(top, p)));
633
+ if (tracked.length === 0) return [];
634
+ try {
635
+ const r = await call('select_files', { paths: tracked });
636
+ if (Array.isArray(r.paths)) return r.paths.filter((p) => tracked.includes(p));
637
+ } catch { /* an older server without the tool: the local cut stands */ }
638
+ return tracked;
639
+ }
640
+
629
641
  async function localize(opts) {
630
642
  const top = root();
631
643
  process.chdir(top);
632
644
  const status = await call('status', {});
633
- const folder = (status.i18n?.catalog_folder || 'lang').replace(/\/+$/, '');
634
645
  const langs = opts.languages || [status.primary_language, ...(status.languages || [])];
635
- const catalogs = [];
636
- for (const code of langs) {
637
- const p = path.join(folder, code + '.json');
638
- if (fs.existsSync(p)) catalogs.push({ path: p, content: fs.readFileSync(p, 'utf8') });
639
- }
640
- let files = changedFiles(top);
641
- if (files.length === 0) { console.log('lyngo: nothing changed in the working tree.'); return null; }
646
+ // Both catalog folders (Laravel's lang and the frontend's own), read again
647
+ // before EVERY call: a catalog the previous batch created must go back, or
648
+ // the server diffs it as new twice (corp1, 2026-10-18: "already exists").
649
+ const folders = [...new Set([status.i18n?.catalog_folder || 'lang', status.i18n?.js_catalog_folder].filter(Boolean).map((f) => f.replace(/\/+$/, '')))];
650
+ const catalogsNow = () => {
651
+ const out = [];
652
+ for (const folder of folders) for (const code of langs) {
653
+ const p = path.join(folder, code + '.json');
654
+ if (fs.existsSync(p)) out.push({ path: p, content: fs.readFileSync(p, 'utf8') });
655
+ }
656
+ return out;
657
+ };
658
+ // --all: the whole repository, not the changed files. The server picks the
659
+ // paths a scan would process out of the tracked tree (its own rules, so
660
+ // the two never drift); the batches of 30 below do the rest (2026-10-18).
661
+ let files = opts.all ? await allSourceFiles(top) : changedFiles(top);
662
+ if (files.length === 0) { console.log(opts.all ? 'lyngo: no source file of this project found in the repository.' : 'lyngo: nothing changed in the working tree.'); return null; }
663
+ const total = files.length;
664
+ if (opts.all) console.log(`lyngo: localizing ${total} file${total === 1 ? '' : 's'} in batches of 30 (${Math.ceil(total / 30)} call${total > 30 ? 's' : ''}); each batch applies before the next.`);
642
665
  const report = { files: [], added: [], reused: [], languages: {} };
666
+ let batch = 0;
643
667
  while (files.length) {
668
+ batch++;
644
669
  const payload = files.map((p) => ({ path: p, content: fs.readFileSync(p, 'utf8') }));
645
- const args = { files: payload, catalogs: catalogs.map((c) => ({ path: c.path, content: fs.existsSync(c.path) ? fs.readFileSync(c.path, 'utf8') : c.content })), format: 'patch' };
670
+ const args = { files: payload, catalogs: catalogsNow(), format: 'patch' };
646
671
  if (opts.languages) args.languages = opts.languages.filter((l) => l !== status.primary_language);
647
672
  // --no-translate: keys only, catalogs for translators. Without the flag the project's setting decides.
648
673
  if (opts['no-translate']) args.translate = false;
@@ -666,6 +691,11 @@ async function localize(opts) {
666
691
  report.languages[code] = cur;
667
692
  }
668
693
  files = r.deferred || [];
694
+ if (opts.all) {
695
+ const done = total - files.length;
696
+ const got = (r.report?.files || []).reduce((n, f) => n + (f.wrapped?.length || 0), 0);
697
+ console.log(` batch ${batch}: ${done}/${total} files, ${got} string${got === 1 ? '' : 's'} localized`);
698
+ }
669
699
  }
670
700
  const wrapped = report.files.reduce((n, f) => n + f.wrapped.length, 0);
671
701
  console.log(`lyngo: ${wrapped} string${wrapped === 1 ? '' : 's'} localized in ${report.files.length} file${report.files.length === 1 ? '' : 's'}; ${report.added.length} new key${report.added.length === 1 ? '' : 's'}, ${report.reused.length} reused.`);
@@ -710,9 +740,10 @@ const HELP = `lyngo ${version()}: localization for your repository, from the ter
710
740
  (--languages are the target languages; the source stays en unless --primary)
711
741
  lyngo onboard --run=<id> [--languages fr,de]
712
742
  the guided setup an agent follows, from lyngo.app/start; run it again to continue
713
- lyngo localize [--languages fr,de] [--no-translate] [--dry]
743
+ lyngo localize [--all] [--languages fr,de] [--no-translate] [--dry]
714
744
  localize what changed in the working tree, and translate it
715
745
  (--no-translate: keys only; the project setting "Translate when localizing" is the default)
746
+ (--all: the whole repository instead of the changed files, in batches of 30)
716
747
  lyngo translate <code> [<code>…] fill every key a language's catalog lacks, from the primary catalog
717
748
  lyngo check <file> the user-facing strings of one file
718
749
  lyngo status the project as Lyngo knows it
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prettifystudio/lyngo-cli",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Localization for Laravel applications, from the terminal: Lyngo wraps user-facing text with your framework's i18n call, reuses your project's keys, translates and verifies the catalogs. Blade, Livewire, PHP, and Inertia with React, Vue or Svelte.",
5
5
  "bin": {
6
6
  "lyngo": "bin/lyngo"