Skip to content

Translate: show where linked strings live when active filters don't match - #4281

Open
ayshushus wants to merge 17 commits into
mozilla:mainfrom
ayshushus:2921
Open

Translate: show where linked strings live when active filters don't match#4281
ayshushus wants to merge 17 commits into
mozilla:mainfrom
ayshushus:2921

Conversation

@ayshushus

@ayshushus ayshushus commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Fix #2921

The string URL param permalinks a specific string, but shared links also carry the filters active at link time (status=missing, search, ...). When the target doesn't match those filters (e.g. link says status=missing but the string is now translated), we silently redirected to the first list entry + a toast, landing users on an unrelated string. Now surface where the string actually lives and let the user choose.

Backend:

  • base.views._get_paginated_entities: when the requested entity is filtered out, run a second, filter-free lookup gated only by viewability (obsolete=False, translatedresources__locale, project not disabled/system, Project.objects.visible_for(user)) and attach requested_entity_location ({pk, project slug, resource path}) to the response. Absent when the string is invalid/obsolete/not viewable, so behavior is unchanged there. Thread user through for the visibility gate.

State:

  • api/entity.ts: add RequestedEntityLocation type, optional requested_entity_location on the response.
  • entities/actions.ts, reducer.ts: carry it onto RECEIVE_ENTITIES, store as requestedEntityLocation. Preserve across pages (backend only reports on page 1), clear on RESET.
  • entities/hooks.ts: useEntityNotFound()show when entity > 0 && requestedEntityLocation != null && !found.

UI:

  • entities/components/StringNotFound.{tsx,css}: new editor-panel screen. "See string" → push({ ...emptyParams, project, resource, entity }) (keep string, drop filters; navigates cross-project). "See other strings" → push({ entity: 0 }) (keep filters, drop string).
  • App.tsx: render <StringNotFound> over <Entity>/<BatchActions> when useEntityNotFound().show.
  • entitieslist/EntitiesList.tsx: skip the "select first entity" redirect + ENTITY_NOT_FOUND toast when the string-not-found screen applies.
  • context/Location.tsx: export emptyParams (consumed by StringNotFound).
  • locale/en-US/translate.ftl: add entities-StringNotFound--* strings.

Tests:

  • test_entities_not_matching_string_reports_location: reports location when filtered out; absent when the string matches.
  • StringNotFound.test.jsx: both navigation paths (incl. cross-project) + null-location renders nothing.

@ayshushus ayshushus self-assigned this Jul 3, 2026
@ayshushus
ayshushus requested a review from eemeli July 3, 2026 18:03
@ayshushus
ayshushus marked this pull request as ready for review July 3, 2026 18:03
@ayshushus

Copy link
Copy Markdown
Collaborator Author

TODO

We should file follow-up issues to:

Inform users when non-string URL parameters are ignored.
Show the regular 404 page when the resource in the path doesn't exist.

@ayshushus
ayshushus requested review from eemeli and functionzz and removed request for eemeli July 7, 2026 13:16

@eemeli eemeli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks decent, though I only did a surface-level review pass here.

Comment thread pontoon/base/views.py Outdated
Comment thread translate/src/modules/entities/components/StringNotFound.tsx Outdated
Comment on lines +86 to +89
{`String ${string} is in ${stringResource} (${stringProject}). ` +
(filters
? `You're browsing ${queryLabel}, filtered by ${filters}.`
: `You're browsing ${queryLabel}.`)}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really be able to rely on our own localization system, rather than duplicating the English strings all over the place.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Had a meeting with Flod. Changed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code still duplicates the English messages in source as well as FTL.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had quite the time wrapping my head around this, let me know if anything's still off, sorry for the back and forth here.

Comment thread translate/src/modules/entities/components/StringNotFound.tsx Outdated
Comment thread translate/src/modules/entities/hooks.ts Outdated
Comment thread translate/src/modules/entitieslist/components/EntitiesList.tsx Outdated
Comment thread translate/public/locale/en-US/translate.ftl
Comment thread translate/public/locale/en-US/translate.ftl Outdated
Comment thread translate/src/modules/entities/hooks.ts Outdated
@ayshushus

Copy link
Copy Markdown
Collaborator Author

Attached are some screenshots of typical pages this PR would create. Along with their conditions. This is the string used in testing for the search functionality.
image

  1. When the string is in a different project, in the same locale.
image
  1. When the string is in the same project, but doesn't match the current filters.
image
  1. When the string is in a different locale, we default to the "can't load specified string" notification. Note that this notification lasts for a couple of seconds.
image

We now:

  1. Reuse existing translations.
  2. Have no fluent variants.
  3. Joining the lists use the UI language.
  4. FTL carries comments explaining variables.
  5. The pre-joined list is explicitly considered.

Comment thread translate/public/locale/en-US/translate.ftl Outdated
Comment thread translate/public/locale/en-US/translate.ftl Outdated
Comment thread translate/public/locale/en-US/translate.ftl Outdated
ayshushus and others added 3 commits July 21, 2026 15:13
Co-authored-by: Francesco Lodolo <flod@lodolo.net>
Co-authored-by: Francesco Lodolo <flod@lodolo.net>
@ayshushus
ayshushus requested review from eemeli and mathjazz July 22, 2026 14:15

@eemeli eemeli left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly nitpicks left; overall looks good. See also reply on an unresolved previous comment.

Comment thread translate/src/modules/entities/components/StringNotFound.tsx Outdated
Comment thread translate/src/modules/entities/components/StringNotFound.tsx Outdated
@ayshushus
ayshushus requested a review from eemeli July 24, 2026 08:22
@ayshushus
ayshushus requested a review from flodolo July 24, 2026 08:23
## on screen. One description per case: hidden by filters, or living in another
## resource, project, or outside all open projects.

entities-StringNotFound--description-filtered = String { $stringId } is in { $stringResource } ({ $stringProject }), but it doesn’t match your current filters.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try to differentiate at least some part of the string from the rest of the text. Can we rap the string ID and resources in a span and style them differently?

Comment thread pontoon/base/views.py
),
}
if requested_entity_location is not None:
response["requested_entity"] = requested_entity_location

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we passing a location in a field called requested_entity?

@flodolo flodolo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks broken
Image

## on screen. One description per case: hidden by filters, or living in another
## resource, project, or outside all open projects.

entities-StringNotFound--description-filtered = String { $stringId } is in { $stringResource } ({ $stringProject }), but it doesn’t match your current filters.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
entities-StringNotFound--description-filtered = String { $stringId } is in { $stringResource } ({ $stringProject }), but it doesn’t match your current filters.
entities-StringNotFound--description-filtered = String with internal ID <id>{ $stringId }</id> is in <id>{ $stringResource }</id> (project <project>{ $stringProject }</project>), but it doesn’t match your current filters.

Similar edits would apply to other strings. Right now it doesn't feel very readable.

Image

Comment thread translate/public/locale/en-US/translate.ftl Outdated
entities-StringNotFound--go-to-string = See string { $stringId } in { $stringResource }
entities-StringNotFound--go-to-string-hint = Search for the requested string, reset current filters.

entities-StringNotFound--show-matching = See other strings in { $queryLabel }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we show the name and not the slug of the project in these strings?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In query parameters, the string should take priority over others

3 participants