i18n(de): address code review findings

Localize a legacy Nepal base shot only when the applied pack marker binds
that title to this exact shot id, so a user shot renamed to a built-in
title stays as typed in every locale.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-29 14:52:45 +04:00
1 parent a0c8b6f893
commit 0e45bcdf14
3 files changed
+80 -15

No files matched your search

+14 -13
View File
@@ -1071,7 +1071,7 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) {
const fromRecipe = shot const fromRecipe = shot
? Boolean(shot.sourcePackId) || ? Boolean(shot.sourcePackId) ||
recipeDeclaresShotTitle(scene?.id, text) || recipeDeclaresShotTitle(scene?.id, text) ||
shotPackDeclaresBaseTitle(scene, text) shotPackBindsShot(scene, text, shot)
: true; : true;
if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text); if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text);
const numbered = /^Shot ([1-9]\d*)$/.exec(text); const numbered = /^Shot ([1-9]\d*)$/.exec(text);
@@ -1079,21 +1079,22 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) {
} }
/** /**
* Whether a shot pack that upgraded this scene declares the title for one of * Whether a shot pack applied to this scene binds this title to this exact
* its legacy base shots. The upgrade rebuilds those shots without a * shot. The legacy upgrade rebuilds the base shots without a sourcePackId
* sourcePackId (see SceneDirector._bootstrapLegacyShotPacks), so the pack's * (see SceneDirector._bootstrapLegacyShotPacks), but the pack marker records
* own shots in the scene vouch for them. * their ids, so a user shot that only shares the title is not vouched for.
* @param {{shots?: Array<{sourcePackId?: string}>}} [scene] * @param {{appliedShotPacks?: Array<{shotBindings?: Object<string, string>}>}} [scene]
* @param {string} title * @param {string} title
* @param {{id?: string}} shot
* @returns {boolean} * @returns {boolean}
*/ */
function shotPackDeclaresBaseTitle(scene, title) { function shotPackBindsShot(scene, title, shot) {
const shots = Array.isArray(scene?.shots) ? scene.shots : []; const packs = Array.isArray(scene?.appliedShotPacks)
return SCENE_APPEND_RECIPES.some( ? scene.appliedShotPacks
(pack) => : [];
pack.legacySceneBootstrap?.cameraPath?.some( return (
(keyframe) => keyframe?.title === title, Boolean(shot?.id) &&
) && shots.some((item) => item?.sourcePackId === pack.id), packs.some((pack) => pack?.shotBindings?.[title] === shot.id)
); );
} }
+15 -2
View File
@@ -151,12 +151,25 @@ test('the base shots of a scene the Nepal pack upgraded localize', () => {
setLocale('de'); setLocale('de');
const title = pack.legacySceneBootstrap.cameraPath[0].title; const title = pack.legacySceneBootstrap.cameraPath[0].title;
const base = { id: 'shot-base', title }; const base = { id: 'shot-base', title };
// A user shot renamed to the same built-in title is not the bound one.
const renamed = { id: 'shot-user', title };
const upgraded = { const upgraded = {
id: 'scene-upgraded', id: 'scene-upgraded',
shots: [base, { id: 'shot-pack', title: 'x', sourcePackId: pack.id }], shots: [
base,
{ id: 'shot-pack', title: 'x', sourcePackId: pack.id },
renamed,
],
appliedShotPacks: [
{ id: pack.id, version: 1, shotBindings: { [title]: base.id } },
],
}; };
assert.equal(displayShotTitle(title, base, upgraded), displayShotTitle(title)); assert.equal(
displayShotTitle(title, base, upgraded),
displayShotTitle(title),
);
assert.notEqual(displayShotTitle(title), title); assert.notEqual(displayShotTitle(title), title);
assert.equal(displayShotTitle(title, renamed, upgraded), title);
// The same title in a scene no pack touched stays as typed. // The same title in a scene no pack touched stays as typed.
assert.equal( assert.equal(
displayShotTitle(title, base, { id: 'scene-user', shots: [base] }), displayShotTitle(title, base, { id: 'scene-user', shots: [base] }),
+51
View File
@@ -0,0 +1,51 @@
// Reproduction: a user-authored shot whose typed title equals a legacy base
// title of the Nepal pack must stay as typed in an upgraded scene.
import test from 'node:test';
import assert from 'node:assert/strict';
import { SCENE_APPEND_RECIPES, displayShotTitle } from './recipes.js';
import { setLocale } from '../i18n/index.js';
test.afterEach(() => setLocale('en'));
test('a user shot named like a legacy base shot stays as typed in an upgraded scene', () => {
const pack = SCENE_APPEND_RECIPES.find(
(recipe) => recipe.legacySceneBootstrap?.cameraPath?.length,
);
assert.ok(pack, 'Nepal append pack with legacy bootstrap');
const baseTitles = pack.legacySceneBootstrap.cameraPath.map((k) => k.title);
// Shape written by SceneDirector._bootstrapLegacyShotPacks + appendShotPack:
// base shots without sourcePackId, pack shots with it, marker bindings.
const base = baseTitles.map((title, i) => ({ id: `base-${i}`, title }));
const packShot = {
id: 'pack-0',
title: 'Upper Valley Collapse',
sourcePackId: pack.id,
};
// Captured by captureShot ("Shot 10"), then renamed by the user.
const userShot = { id: 'user-1', title: 'Bhote Koshi Flood Path' };
const scene = {
id: 'scene-user-upgraded',
shots: [...base, packShot, userShot],
appliedShotPacks: [
{
id: pack.id,
version: Number(pack.version) || 1,
shotBindings: Object.fromEntries(base.map((s) => [s.title, s.id])),
},
],
};
for (const locale of ['de', 'ru', 'es']) {
setLocale(locale);
// The real base shot localizes (intended by the branch).
assert.notEqual(
displayShotTitle(base[5].title, base[5], scene),
base[5].title,
);
// The user's shot must stay as typed.
assert.equal(
displayShotTitle(userShot.title, userShot, scene),
userShot.title,
`${locale}: user-typed title was translated`,
);
}
});