i18n(fr): address code review findings

Localize a pack shot title only for the shot the pack marker binds to that
title, so an operator's shot named like a pack shot shows as typed. Markers
saved without shotBindings keep the title-only check.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
German KhokhlovandClaude Opus 5.5 committed 2026-10-29 14:48:09 +04:00
1 parent ed26fa12d8
commit d034e7355d
2 files changed
+34 -7

No files matched your search

+22 -1
View File
@@ -17,7 +17,8 @@ import test from 'node:test';
import { LayerLifecycle } from '../data/lifecycle.js';
import { SceneDirector } from './director.js';
import { SCENE_TRACKING_PARAM_KEYS } from './scenePolicy.js';
import { SCENE_RECIPES, getSceneAppendRecipeById } from './recipes.js';
import { SCENE_RECIPES, displayShotTitle, getSceneAppendRecipeById } from './recipes.js';
import { setLocale } from '../i18n/index.js';
const NEPAL_ORIGINAL_SHOT_TITLES = [
'Global Incident Context',
@@ -2019,3 +2020,23 @@ test('a caught run failure resolves as run-failed, not success (#971)', async ()
);
} finally { console.warn = warn; await director.destroy(); restore(); }
});
test('a user shot whose title matches an applied pack title keeps the typed title', () => {
const { director, restore } = makeDirector({ project: legacyThreeShotNepalProjectFixture() });
try {
const scene = director._project.scenes[0];
setLocale('ru');
// The bootstrap-rebuilt shot (no sourcePackId, bound by the pack marker) still localizes.
const bootstrap = scene.shots[0];
assert.equal(bootstrap.sourcePackId, undefined);
assert.notEqual(displayShotTitle(bootstrap.title, bootstrap, scene), bootstrap.title);
// A shot the operator added and named like a pack shot shows as typed.
for (const title of ['Final view', 'Global Incident Context']) {
const userShot = { id: `user-shot-${title}`, title };
assert.equal(displayShotTitle(title, userShot, scene), title);
}
} finally {
setLocale('en');
restore();
}
});
+12 -6
View File
@@ -1069,7 +1069,7 @@ export function displaySceneTitle(scene) {
export function displayShotTitle(title, shot = undefined, scene = undefined) {
const text = typeof title === 'string' ? title : '';
const fromRecipe = shot
? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text)
? Boolean(shot.sourcePackId) || recipeDeclaresShotTitle(scene, text, shot)
: true;
if (fromRecipe && BUILTIN_SHOT_TITLES.has(text)) return t(text);
const numbered = /^Shot ([1-9]\d*)$/.exec(text);
@@ -1080,9 +1080,11 @@ export function displayShotTitle(title, shot = undefined, scene = undefined) {
* Whether the built-in recipe behind a scene, or a shot pack applied to it,
* declares a shot with this title. A pack's legacy bootstrap rebuilds the
* first shots of an upgraded scene without a sourcePackId, so the pack's
* required titles vouch for them.
* required titles vouch for them: through the marker's shotBindings when it
* has them, so an operator's shot named like a pack shot stays as typed, and
* by title alone for markers saved before bindings.
*/
function recipeDeclaresShotTitle(scene, title) {
function recipeDeclaresShotTitle(scene, title, shot) {
const recipe = scene?.id ? getSceneRecipeById(scene.id) : null;
if (recipe?.cameraPath?.some((keyframe) => keyframe?.title === title))
return true;
@@ -1090,8 +1092,12 @@ function recipeDeclaresShotTitle(scene, title) {
? scene.appliedShotPacks
: [];
return packs.some((entry) =>
Boolean(
getSceneAppendRecipeById(entry?.id)?.requiredShotTitles?.includes(title),
),
entry?.shotBindings
? entry.shotBindings[title] === shot?.id
: Boolean(
getSceneAppendRecipeById(entry?.id)?.requiredShotTitles?.includes(
title,
),
),
);
}