Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions libs/core/src/lib/import/process-resource-group.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,48 @@ describe('process-resource-group', () => {
expect(changes[0].newStatus).toBe('translated');
});

it('should not downgrade a current verified value for translation-service', () => {
const currentBaseChecksum = calculateChecksum('OK');
mkdirSync(folderPath, { recursive: true });
writeFileSync(entryResourcePath, JSON.stringify({ ok: { source: 'OK', es: 'Bien' } }));
writeFileSync(
entryMetaPath,
JSON.stringify({
ok: {
en: { checksum: currentBaseChecksum },
es: {
checksum: calculateChecksum('Bien'),
baseChecksum: currentBaseChecksum,
status: 'verified',
},
},
}),
);

const filesModified = new Set<string>();
const warnings: string[] = [];
const changes = processResourceGroup(
{
folderPath,
entryResourcePath,
entryMetaPath,
resources: [{ resource: { key: 'common.buttons.ok', value: 'Bien' }, entryKey: 'ok' }],
},
'es',
'en',
{ source: 'test.json', locale: 'es', strategy: 'translation-service' },
false,
false,
filesModified,
warnings,
);

expect(changes[0]?.oldStatus).toBe('verified');
expect(changes[0]?.newStatus).toBe('verified');
expect(JSON.parse(readFileSync(entryMetaPath, 'utf8')).ok.es.status).toBe('verified');
expect(filesModified.size).toBe(0);
});

it('should preserve existing status when value does not change with update strategy', () => {
const group: ResourceGroup = {
folderPath,
Expand Down Expand Up @@ -290,6 +332,113 @@ describe('process-resource-group', () => {
expect(filesModified.size).toBe(0);
});

describe('reconfirming unchanged values with stale metadata', () => {
beforeEach(() => {
writeFileSync(
entryMetaPath,
JSON.stringify({
ok: {
en: { checksum: calculateChecksum('OK') },
es: {
checksum: calculateChecksum('Bien'),
baseChecksum: calculateChecksum('Old source'),
status: 'stale',
},
},
}),
);
});

function createUnchangedValueGroup(): ResourceGroup {
return {
folderPath,
entryResourcePath,
entryMetaPath,
resources: [
{
resource: {
key: 'common.buttons.ok',
value: 'Bien',
},
entryKey: 'ok',
},
],
};
}

it('should refresh the base checksum and set stale values to translated for translation-service', () => {
const filesModified = new Set<string>();
const warnings: string[] = [];

const changes = processResourceGroup(
createUnchangedValueGroup(),
'es',
'en',
{ source: 'test.json', locale: 'es', strategy: 'translation-service' },
false,
false,
filesModified,
warnings,
);

expect(changes[0]?.oldStatus).toBe('stale');
expect(changes[0]?.newStatus).toBe('translated');

const meta = JSON.parse(readFileSync(entryMetaPath, 'utf8'));
expect(meta.ok.es.status).toBe('translated');
expect(meta.ok.es.baseChecksum).toBe(calculateChecksum('OK'));
expect(filesModified.has(entryMetaPath)).toBe(true);
});

it('should refresh the base checksum and set stale values to verified for verification', () => {
const filesModified = new Set<string>();
const warnings: string[] = [];

const changes = processResourceGroup(
createUnchangedValueGroup(),
'es',
'en',
{ source: 'test.json', locale: 'es', strategy: 'verification' },
false,
false,
filesModified,
warnings,
);

expect(changes[0]?.oldStatus).toBe('stale');
expect(changes[0]?.newStatus).toBe('verified');

const meta = JSON.parse(readFileSync(entryMetaPath, 'utf8'));
expect(meta.ok.es.status).toBe('verified');
expect(meta.ok.es.baseChecksum).toBe(calculateChecksum('OK'));
expect(filesModified.has(entryMetaPath)).toBe(true);
});

it('should leave stale metadata unchanged for update', () => {
const filesModified = new Set<string>();
const warnings: string[] = [];

const changes = processResourceGroup(
createUnchangedValueGroup(),
'es',
'en',
{ source: 'test.json', locale: 'es', strategy: 'update' },
false,
false,
filesModified,
warnings,
);

expect(changes[0]?.oldStatus).toBe('stale');
expect(changes[0]?.newStatus).toBe('stale');

const meta = JSON.parse(readFileSync(entryMetaPath, 'utf8'));
expect(meta.ok.es.status).toBe('stale');
expect(meta.ok.es.baseChecksum).toBe(calculateChecksum('Old source'));
expect(filesModified.size).toBe(0);
});
});

it('should set status to verified for verification strategy', () => {
const group: ResourceGroup = {
folderPath,
Expand Down
18 changes: 15 additions & 3 deletions libs/core/src/lib/import/process-resource-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,23 +219,35 @@ function handleUnchangedTargetLocaleValue(
};
}

// Translation-service and verification imports re-confirm unchanged values.
// Keep the update/migration strategies' existing metadata behavior intact,
// while bringing the target locale's base checksum back in sync with the
// current base locale metadata during re-confirmation.
const shouldRefreshBaseChecksum = options.strategy === 'translation-service' || options.strategy === 'verification';
const currentBaseChecksum = entryMeta?.[baseLocale]?.checksum ?? calculateChecksum(entry.source);
const baseChecksumChanged = shouldRefreshBaseChecksum && entryMeta?.[locale]?.baseChecksum !== currentBaseChecksum;
const resolvedStatus: TranslationStatus = shouldUseSourceStatus(options, resource)
? resource.status
: options.strategy === 'verification'
? 'verified'
: (oldStatus ?? 'translated');
: options.strategy === 'translation-service' && (oldStatus === 'stale' || baseChecksumChanged)
? 'translated'
: (oldStatus ?? 'translated');

if (resolvedStatus !== oldStatus) {
if (resolvedStatus !== oldStatus || baseChecksumChanged) {
ensureEntryMeta(trackerMeta, entryKey);

if (!trackerMeta[entryKey][locale]) {
trackerMeta[entryKey][locale] = {
checksum: entryMeta?.[locale]?.checksum ?? calculateChecksum(oldValue),
baseChecksum: entryMeta?.[baseLocale]?.checksum ?? calculateChecksum(entry.source),
baseChecksum: currentBaseChecksum,
status: resolvedStatus,
};
} else {
trackerMeta[entryKey][locale].status = resolvedStatus;
if (shouldRefreshBaseChecksum) {
trackerMeta[entryKey][locale].baseChecksum = currentBaseChecksum;
}
}
ctx.dataModified = true;
}
Expand Down
Loading