@localheroai/cli 0.0.87 → 0.0.88-rc.1
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.
- package/dist/api/target-edit-alignments.js +45 -0
- package/dist/api/target-edit-alignments.js.map +1 -0
- package/dist/commands/translate.js +62 -26
- package/dist/commands/translate.js.map +1 -1
- package/dist/utils/aligned-import.js +24 -5
- package/dist/utils/aligned-import.js.map +1 -1
- package/dist/utils/alignment-candidates.js +5 -5
- package/dist/utils/alignment-candidates.js.map +1 -1
- package/dist/utils/git-changes.js +26 -21
- package/dist/utils/git-changes.js.map +1 -1
- package/dist/utils/github.js +4 -0
- package/dist/utils/github.js.map +1 -1
- package/dist/utils/import-guard.js +192 -0
- package/dist/utils/import-guard.js.map +1 -0
- package/dist/utils/source-alignment.js +7 -5
- package/dist/utils/source-alignment.js.map +1 -1
- package/dist/utils/target-changes.js.map +1 -1
- package/dist/utils/target-edit-alignment.js +238 -0
- package/dist/utils/target-edit-alignment.js.map +1 -0
- package/dist/utils/target-edit-candidates.js +88 -0
- package/dist/utils/target-edit-candidates.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { createTargetEditAlignment, TargetEditAlignmentRequestError } from '../api/target-edit-alignments.js';
|
|
4
|
+
import { localeCodesMatch } from './translation-processor.js';
|
|
5
|
+
import { chunked, groupBy } from './source-alignment.js';
|
|
6
|
+
const MAX_ITEMS_PER_REQUEST = 25;
|
|
7
|
+
const MAX_KEYS = 250;
|
|
8
|
+
const NOT_FOUND_STATUS = 404;
|
|
9
|
+
const INVALID_PARAMETERS_STATUS = 422;
|
|
10
|
+
const UPDATED = 'updated';
|
|
11
|
+
const LOCAL_FIX = 'local_fix';
|
|
12
|
+
// Nothing to report: no translation was edited, or the developer edited the source text too.
|
|
13
|
+
const QUIET_STATUSES = new Set(['no_trigger', 'source_edited']);
|
|
14
|
+
/**
|
|
15
|
+
* Ask the backend whether a translation edited in this branch changed what the
|
|
16
|
+
* text says, and write the source text it sends back. The other locales then
|
|
17
|
+
* follow that source text through the ordinary source alignment. An older
|
|
18
|
+
* server or a project without the setting answers nothing, and the run goes on
|
|
19
|
+
* as before.
|
|
20
|
+
*/
|
|
21
|
+
export async function runTargetEditAlignment(candidates, request, deps) {
|
|
22
|
+
const result = emptyTargetEditResult();
|
|
23
|
+
const updatedKeys = [];
|
|
24
|
+
let enabled = false;
|
|
25
|
+
for (const chunk of chunked(candidates.slice(0, MAX_KEYS), MAX_ITEMS_PER_REQUEST)) {
|
|
26
|
+
try {
|
|
27
|
+
const response = await createTargetEditAlignment({ ...request, items: chunk.map(toRequestItem) });
|
|
28
|
+
if (!response.enabled)
|
|
29
|
+
return result;
|
|
30
|
+
enabled = true;
|
|
31
|
+
matchedItems(chunk, response.items).forEach((item, index) => {
|
|
32
|
+
if (isUpdate(item)) {
|
|
33
|
+
updatedKeys.push({ candidate: chunk[index], item });
|
|
34
|
+
}
|
|
35
|
+
else if (item.status === LOCAL_FIX) {
|
|
36
|
+
result.localFixes += 1;
|
|
37
|
+
}
|
|
38
|
+
else if (!QUIET_STATUSES.has(item.status)) {
|
|
39
|
+
result.skipped[item.status] = (result.skipped[item.status] ?? 0) + 1;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof TargetEditAlignmentRequestError && error.status === NOT_FOUND_STATUS)
|
|
45
|
+
return result;
|
|
46
|
+
logRequestFailure(deps.console, error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const leftOut = candidates.length - MAX_KEYS;
|
|
50
|
+
if (enabled && leftOut > 0) {
|
|
51
|
+
deps.console.log(chalk.yellow(`Not following ${leftOut} more ${leftOut === 1 ? 'key' : 'keys'}: more than ${MAX_KEYS} to check.`));
|
|
52
|
+
}
|
|
53
|
+
for (const [sourcePath, fileKeys] of groupBy(updatedKeys, updated => updated.candidate.source_path)) {
|
|
54
|
+
if (!(await writeSourceTexts(sourcePath, fileKeys, deps)))
|
|
55
|
+
continue;
|
|
56
|
+
result.writtenPaths.push(sourcePath);
|
|
57
|
+
for (const updated of fileKeys) {
|
|
58
|
+
result.sourceCells.push(sourceCell(updated, deps.config.sourceLocale));
|
|
59
|
+
result.alignmentCandidates.push(...alignmentCandidates(updated));
|
|
60
|
+
const reverted = revertedChange(updated);
|
|
61
|
+
if (reverted)
|
|
62
|
+
result.revertedChanges.push(reverted);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
export function emptyTargetEditResult() {
|
|
68
|
+
return { sourceCells: [], alignmentCandidates: [], revertedChanges: [], writtenPaths: [], localFixes: 0, skipped: {} };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A key whose source text followed an edit is aligned from the source text as
|
|
72
|
+
* it was before the write, for the locales the server named, instead of from
|
|
73
|
+
* the first pass's rewording.
|
|
74
|
+
*/
|
|
75
|
+
export function replaceAlignmentCandidates(candidates, targetEdits) {
|
|
76
|
+
const updated = new Set(targetEdits.sourceCells.map(keyId));
|
|
77
|
+
return [
|
|
78
|
+
...candidates.filter(candidate => !updated.has(keyId(candidate))),
|
|
79
|
+
...targetEdits.alignmentCandidates
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
export function withRevertedChanges(targetChanges, reverted) {
|
|
83
|
+
const files = targetChanges.map(file => ({ ...file, changes: [...file.changes] }));
|
|
84
|
+
for (const revertedFile of reverted) {
|
|
85
|
+
const file = files.find(f => f.path === revertedFile.path && f.locale === revertedFile.locale);
|
|
86
|
+
if (file) {
|
|
87
|
+
file.changes.push(...revertedFile.changes);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
files.push(revertedFile);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return files;
|
|
94
|
+
}
|
|
95
|
+
export function addSourceCells(alignment, sourceCells) {
|
|
96
|
+
if (sourceCells.length === 0)
|
|
97
|
+
return alignment;
|
|
98
|
+
const base = alignment ?? { enabled: true, alignedCells: [], localeSummaries: {}, notices: [], shortUrl: null };
|
|
99
|
+
return { ...base, alignedCells: [...base.alignedCells, ...sourceCells] };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Missing-key detection reads the content cached when the files were found, so
|
|
103
|
+
* a file this run wrote has to be read again first.
|
|
104
|
+
*/
|
|
105
|
+
export function refreshFileContent(files, writtenPaths) {
|
|
106
|
+
const contentByPath = new Map();
|
|
107
|
+
for (const file of files) {
|
|
108
|
+
if (file.content === undefined || !writtenPaths.includes(file.path))
|
|
109
|
+
continue;
|
|
110
|
+
if (!contentByPath.has(file.path)) {
|
|
111
|
+
contentByPath.set(file.path, Buffer.from(readFileSync(file.path, 'utf-8')).toString('base64'));
|
|
112
|
+
}
|
|
113
|
+
file.content = contentByPath.get(file.path);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function reportTargetEditAlignment(result, logger) {
|
|
117
|
+
const lines = result.sourceCells.map(cell => `${cell.key}: ${cell.locale} updated to match the ${cell.trigger_locale} edit`);
|
|
118
|
+
if (result.localFixes > 0) {
|
|
119
|
+
lines.push(`${result.localFixes} left as they are: the edit kept the meaning`);
|
|
120
|
+
}
|
|
121
|
+
const reasons = Object.entries(result.skipped);
|
|
122
|
+
if (reasons.length > 0) {
|
|
123
|
+
const total = reasons.reduce((sum, [, count]) => sum + count, 0);
|
|
124
|
+
lines.push(`${total} skipped (${reasons.map(([reason, count]) => `${count} ${reason}`).join(', ')})`);
|
|
125
|
+
}
|
|
126
|
+
if (lines.length === 0)
|
|
127
|
+
return;
|
|
128
|
+
logger.log('» Edited translations:');
|
|
129
|
+
for (const line of lines)
|
|
130
|
+
logger.log(` ${line}`);
|
|
131
|
+
}
|
|
132
|
+
function isUpdate(item) {
|
|
133
|
+
return item.status === UPDATED &&
|
|
134
|
+
typeof item.source === 'string' &&
|
|
135
|
+
typeof item.trigger_locale === 'string' &&
|
|
136
|
+
typeof item.trigger_value === 'string' &&
|
|
137
|
+
Array.isArray(item.align_locales);
|
|
138
|
+
}
|
|
139
|
+
async function writeSourceTexts(sourcePath, keys, deps) {
|
|
140
|
+
const values = Object.fromEntries(keys.map(({ candidate, item }) => [candidate.key, item.source]));
|
|
141
|
+
try {
|
|
142
|
+
await deps.updateTranslationFile(sourcePath, values, deps.config.sourceLocale, sourcePath, undefined, deps.config);
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
deps.console.log(chalk.yellow(`⚠ Could not write the updated source texts to ${sourcePath}: ${error.message}`));
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function sourceCell({ candidate, item }, sourceLocale) {
|
|
151
|
+
return {
|
|
152
|
+
locale: sourceLocale,
|
|
153
|
+
source_path: candidate.source_path,
|
|
154
|
+
target_path: candidate.source_path,
|
|
155
|
+
format: candidate.format,
|
|
156
|
+
key: candidate.key,
|
|
157
|
+
previous_source: candidate.source,
|
|
158
|
+
source: item.source,
|
|
159
|
+
target_base: candidate.source_base,
|
|
160
|
+
target_current: candidate.source,
|
|
161
|
+
value: item.source,
|
|
162
|
+
trigger_locale: item.trigger_locale,
|
|
163
|
+
trigger_path: findTarget(candidate, item.trigger_locale)?.target_path,
|
|
164
|
+
aligned_source: item.trigger_value
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// The branch value is sent as both base and current: the source alignment reads
|
|
168
|
+
// the cell as untouched and aligns it from where the branch has it.
|
|
169
|
+
function alignmentCandidates({ candidate, item }) {
|
|
170
|
+
return item.align_locales
|
|
171
|
+
.map(locale => findTarget(candidate, locale))
|
|
172
|
+
.filter((target) => target !== undefined && target.writable)
|
|
173
|
+
.map(target => ({
|
|
174
|
+
locale: target.locale,
|
|
175
|
+
source_path: candidate.source_path,
|
|
176
|
+
target_path: target.target_path,
|
|
177
|
+
format: target.format,
|
|
178
|
+
key: candidate.key,
|
|
179
|
+
previous_source: candidate.source,
|
|
180
|
+
source: item.source,
|
|
181
|
+
target_base: target.current,
|
|
182
|
+
target_current: target.current,
|
|
183
|
+
trigger_locale: item.trigger_locale
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
// The edit was undone: the trigger's own proposal is withdrawn rather than
|
|
187
|
+
// staging its merge-base value, which merge could apply over a newer live text.
|
|
188
|
+
function revertedChange({ candidate, item }) {
|
|
189
|
+
if (!item.trigger_at_base)
|
|
190
|
+
return null;
|
|
191
|
+
const trigger = findTarget(candidate, item.trigger_locale);
|
|
192
|
+
if (!trigger)
|
|
193
|
+
return null;
|
|
194
|
+
return {
|
|
195
|
+
path: trigger.target_path,
|
|
196
|
+
source_path: candidate.source_path,
|
|
197
|
+
locale: trigger.locale,
|
|
198
|
+
format: trigger.format,
|
|
199
|
+
changes: [{ key: candidate.key, status: 'reverted', value: trigger.current, old_value: trigger.base }]
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function findTarget(candidate, locale) {
|
|
203
|
+
return candidate.targets.find(target => localeCodesMatch(target.locale, locale));
|
|
204
|
+
}
|
|
205
|
+
function matchedItems(requested, returned) {
|
|
206
|
+
const matches = returned.length === requested.length && returned.every((item, index) => item.key === requested[index].key && item.source_path === requested[index].source_path);
|
|
207
|
+
if (!matches) {
|
|
208
|
+
throw new Error('the response did not match the request');
|
|
209
|
+
}
|
|
210
|
+
return returned;
|
|
211
|
+
}
|
|
212
|
+
function logRequestFailure(logger, error) {
|
|
213
|
+
const message = error.message;
|
|
214
|
+
if (error instanceof TargetEditAlignmentRequestError && error.status === INVALID_PARAMETERS_STATUS) {
|
|
215
|
+
logger.log(chalk.yellow(`⚠ Request to update source texts to match edited translations was rejected: ${message}`));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
logger.log(chalk.yellow(`⚠ Could not update source texts to match edited translations: ${message}. Source texts were left as they are.`));
|
|
219
|
+
}
|
|
220
|
+
function toRequestItem(candidate) {
|
|
221
|
+
return {
|
|
222
|
+
source_path: candidate.source_path,
|
|
223
|
+
format: candidate.format,
|
|
224
|
+
key: candidate.key,
|
|
225
|
+
source_base: candidate.source_base,
|
|
226
|
+
source: candidate.source,
|
|
227
|
+
targets: candidate.targets.map(target => ({
|
|
228
|
+
locale: target.locale,
|
|
229
|
+
target_path: target.target_path,
|
|
230
|
+
base: target.base,
|
|
231
|
+
current: target.current
|
|
232
|
+
}))
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function keyId(cell) {
|
|
236
|
+
return `${cell.source_path}\0${cell.key}`;
|
|
237
|
+
}
|
|
238
|
+
//# sourceMappingURL=target-edit-alignment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-edit-alignment.js","sourceRoot":"","sources":["../../src/utils/target-edit-alignment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { getBaseBranch, resolveCompareRef, extractLocaleContent } from './git-changes.js';
|
|
3
|
+
import { parseFile } from './files.js';
|
|
4
|
+
import { findTargetFile } from './translation-utils.js';
|
|
5
|
+
import { ALIGNABLE_FORMATS, isFilledString, isRewording, readDiff, uniqueByPath } from './alignment-candidates.js';
|
|
6
|
+
/**
|
|
7
|
+
* Collect the keys whose translation or source text this branch changed, with
|
|
8
|
+
* the source text and every locale's value at the merge-base and now. The
|
|
9
|
+
* backend decides which edit, if any, the source text should follow. Keys the
|
|
10
|
+
* source does not have at the merge-base are left out: an edit needs a before.
|
|
11
|
+
*/
|
|
12
|
+
export function collectTargetEditCandidates(targetChanges, sourceFiles, targetFilesByLocale, config, verbose, ignoreMatcher) {
|
|
13
|
+
const editedKeysBySource = editedKeys(targetChanges, ignoreMatcher);
|
|
14
|
+
const editedSourceFiles = uniqueByPath(sourceFiles).filter(file => ALIGNABLE_FORMATS.has(file.format.toLowerCase()) && editedKeysBySource.has(file.path) && writableUnderLocale(file));
|
|
15
|
+
if (editedSourceFiles.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
const resolvedRef = resolveCompareRef(getBaseBranch(config), verbose);
|
|
18
|
+
if (!resolvedRef)
|
|
19
|
+
return [];
|
|
20
|
+
const candidates = [];
|
|
21
|
+
for (const sourceFile of editedSourceFiles) {
|
|
22
|
+
const sourceDiff = readDiff(sourceFile, resolvedRef, verbose);
|
|
23
|
+
if (!sourceDiff)
|
|
24
|
+
continue;
|
|
25
|
+
const targetDiffs = readTargetDiffs(sourceFile, targetFilesByLocale, config, resolvedRef, verbose);
|
|
26
|
+
for (const key of editedKeysBySource.get(sourceFile.path) ?? []) {
|
|
27
|
+
const sourceBase = sourceDiff.oldFlat[key];
|
|
28
|
+
const source = sourceDiff.newFlat[key];
|
|
29
|
+
if (!isFilledString(sourceBase) || !isFilledString(source))
|
|
30
|
+
continue;
|
|
31
|
+
const targets = targetsWithKey(targetDiffs, key);
|
|
32
|
+
if (targets.length === 0)
|
|
33
|
+
continue;
|
|
34
|
+
candidates.push({ source_path: sourceFile.path, format: sourceFile.format, key, source_base: sourceBase, source, targets });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return candidates;
|
|
38
|
+
}
|
|
39
|
+
const YAML_FORMATS = new Set(['yml', 'yaml']);
|
|
40
|
+
// The YAML writer always puts the key under a locale root; in a file without
|
|
41
|
+
// one it would add a second tree that hides the existing keys. Such a target
|
|
42
|
+
// still counts as an edited language; it is just never written.
|
|
43
|
+
function writableUnderLocale(file) {
|
|
44
|
+
if (!YAML_FORMATS.has(file.format.toLowerCase()))
|
|
45
|
+
return true;
|
|
46
|
+
try {
|
|
47
|
+
const parsed = parseFile(readFileSync(file.path, 'utf-8'), file.format, file.path);
|
|
48
|
+
return extractLocaleContent(parsed, file.locale) !== parsed;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function readTargetDiffs(sourceFile, targetFilesByLocale, config, resolvedRef, verbose) {
|
|
55
|
+
const diffs = [];
|
|
56
|
+
for (const locale of config.outputLocales) {
|
|
57
|
+
const file = findTargetFile(targetFilesByLocale[locale] ?? [], locale, sourceFile, config.sourceLocale);
|
|
58
|
+
if (!file)
|
|
59
|
+
continue;
|
|
60
|
+
const diff = readDiff(file, resolvedRef, verbose);
|
|
61
|
+
if (diff)
|
|
62
|
+
diffs.push({ locale, file, diff, writable: writableUnderLocale(file) });
|
|
63
|
+
}
|
|
64
|
+
return diffs;
|
|
65
|
+
}
|
|
66
|
+
function targetsWithKey(targetDiffs, key) {
|
|
67
|
+
return targetDiffs.flatMap(({ locale, file, diff, writable }) => {
|
|
68
|
+
const current = diff.newFlat[key];
|
|
69
|
+
if (!isFilledString(current))
|
|
70
|
+
return [];
|
|
71
|
+
const base = diff.oldFlat[key];
|
|
72
|
+
return [{ locale, target_path: file.path, format: file.format, writable, base: isFilledString(base) ? base : null, current }];
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function editedKeys(targetChanges, ignoreMatcher) {
|
|
76
|
+
const keysBySource = new Map();
|
|
77
|
+
for (const file of targetChanges) {
|
|
78
|
+
for (const change of file.changes) {
|
|
79
|
+
if (!isRewording(change) || ignoreMatcher?.(change.key))
|
|
80
|
+
continue;
|
|
81
|
+
if (!keysBySource.has(file.source_path))
|
|
82
|
+
keysBySource.set(file.source_path, new Set());
|
|
83
|
+
keysBySource.get(file.source_path).add(change.key);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return keysBySource;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=target-edit-candidates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-edit-candidates.js","sourceRoot":"","sources":["../../src/utils/target-edit-candidates.ts"],"names":[],"mappings":"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"}
|