Skip to content

feat(gallery): translate the image gallery and validate its image list - #1306

Merged
nanaf6203-bit merged 1 commit into
MettaChain:mainfrom
rozemary2026-a11y:feat/gallery-i18n-and-validation
Oct 21, 2026
Merged

nanaf6203-bit merged 1 commit into
MettaChain:mainfrom
rozemary2026-a11y:feat/gallery-i18n-and-validation

Conversation

@rozemary2026-a11y

Copy link
Copy Markdown
Contributor

Summary

The image gallery (ImageGallery / ImageLightbox) rendered hard-coded English strings and trusted the image list it received from the API. A broken address became a broken image, a duplicated address was rendered twice, and the gallery was the only part of the property page that ignored the language the user picked.

This PR translates the gallery and validates the image list before anything is rendered.

Closes #1264
Closes #1265

Changes

Translations (#1264)

  • Every string of ImageGallery and ImageLightbox now comes from the gallery section of the common namespace: the empty state, the overlay on the main image, the alternative text of the images and of the lightbox thumbnails, the lightbox controls and the position indicator.
  • The gallery section is shipped in all seven languages the app supports (en, es, fr, de, zh, ar, he), so the translation completeness test keeps them in sync.
  • Counted strings use the i18next plural form (viewAll / viewAll_one). The base key is kept as well, so languages with more plural categories than English (Arabic, Hebrew) resolve to a sentence instead of a raw key.
  • The alternative text of the images falls back to a generic, translated label when the property has no name, so an image never ends up without an alternative text.

Validation (#1265)

The image list is validated with a zod schema (galleryImageSchema) before it is rendered. The rules are the ones the renderer can actually honour:

Rule What happens
The entry is text The entry is skipped and reported
The entry is not empty once trimmed The entry is skipped and reported
The entry is an http(s) URL or a path that starts with / The entry is skipped and reported
The address was already used The entry is skipped and reported
The gallery is longer than GALLERY_MAX_IMAGES (50) The extra images are not rendered and counted

next/image only accepts an absolute http(s) URL or a path that starts with a slash, so a relative path without the leading slash and a data: URL are rejected before they can turn into a broken image.

Every rejected entry is reported to the user in a role="status" notice above the gallery, with the reason it was skipped. A gallery whose images are all invalid shows that notice and the empty state.

The lightbox index is clamped to the image list, so it can never point at an image that does not exist.

Tests

  • src/lib/__tests__/galleryValidation.test.ts — the validation rules themselves.
  • src/components/property/__tests__/ImageGallery.validation.test.tsx — which images are rendered, which are skipped and what the user is told about it.
  • src/components/property/__tests__/ImageGallery.i18n.test.tsx — the translated strings, the plural forms, the language switch and the key parity between the languages.
  • src/test/i18n.ts — a test helper that boots i18next with the real translations, so the tests assert the strings the app renders instead of the raw keys.
  • src/components/property/__tests__/ImageGallery.test.tsx — the existing suite, now rendering the translated strings.

Documentation

  • docs/gallery.md describes the validation rules, the translation keys and the tests, and is linked from the README.

How it was verified

npx jest src/components/property/__tests__ src/lib/__tests__/galleryValidation.test.ts
npm run typecheck
npx eslint src/lib/galleryValidation.ts src/test/i18n.ts src/components/property

The gallery suites pass, and the type check and the lint report exactly the same findings as the base commit — this change adds none.

The image gallery rendered hard-coded English strings and trusted the image
list it received from the API, so a broken address became a broken image and
a duplicated address was rendered twice.

- move every string of the gallery and of the lightbox into the `gallery`
  section of the `common` namespace, in all seven shipped languages, and use
  the i18next plural form for the counted strings
- validate the image list before rendering it: an entry that is not text, is
  empty, is not a source `next/image` can load, or repeats an address is
  skipped and reported to the user in a status notice
- clamp the lightbox index to the image list, so it can never point at an
  image that does not exist
- fall back to a generic label when the property has no name, so the images
  keep an alternative text
- cover the validation rules, the translations and the plural forms with
  tests, and document the behaviour in docs/gallery.md

Closes MettaChain#1264
Closes MettaChain#1265
@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

@rozemary2026-a11y Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@nanaf6203-bit nanaf6203-bit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Gallery i18n plus image list validation, solid combo. Approved.

@nanaf6203-bit
nanaf6203-bit merged commit 8d9864f into MettaChain:main Oct 21, 2026
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.

Add form validation to Gallery Add i18n translations for Gallery

2 participants