feat(i18n): add Spanish (es) locale (#510)
Contributed by @AloePacci on issue #510. Drops their es.json into the existing locale set, registers Spanish in the language selector with a flag SVG matching the inline style of the other six locales, and extends the email pipeline so es-language guests receive a localised email subject/body where available. Coverage: - frontend/src/i18n/locales/es.json — 2132 translated keys. ~824 EN keys are not yet covered; i18next's `fallbackLng: 'en'` handles those at runtime so the UI never renders a missing key. fr/nl/pt/ru have a similar (smaller) gap and ship the same way. - LanguageSelector.tsx — added the ESFlag inline SVG (red/yellow/red horizontal bands, official #AA151B + #F1BF00; no coat of arms to stay consistent with the other simple flag components) and a new entry in SUPPORTED_LANGUAGES. - emailProcessor.js — added .es to the domain-language heuristic, and an `es:` row to the three inline-translated snippets (passwordSecurityI18n / noPasswordI18n / passwordSetAtCreationI18n). - 106_seed_es_email_template_translations.js (new) — idempotent seeder for the four customer-facing templates AloePacci translated: gallery_created, expiration_warning, gallery_expired, archive_complete. Mirrors the pattern from 099. Template keys without an `es` row fall back to `en` via the existing resolution chain in emailProcessor.processTemplate — no functional gap, just untranslated copy until someone fills them in. What I deliberately did NOT take from the contribution: the proposed in-place edit of migration 075 (history mutation — won't reseed for existing installs anyway) and the whitespace/`gallery_list_html`-drop churn in emailProcessor.js (would have regressed the #354 follow-up). The semantic additions from those files are preserved via 106 and the targeted edits above.
This commit is contained in:
@@ -140,6 +140,7 @@ async function getRecipientLanguage(email, eventId = null) {
|
||||
{ domains: ['.nl', '.be'], language: 'nl' },
|
||||
{ domains: ['.br', '.pt'], language: 'pt' },
|
||||
{ domains: ['.ru', '.su'], language: 'ru' },
|
||||
{ domains: ['.es'], language: 'es' },
|
||||
];
|
||||
for (const { domains, language: lang } of domainLanguageMap) {
|
||||
if (domains.some(d => domain.endsWith(d))) {
|
||||
@@ -497,6 +498,7 @@ async function processTemplate(template, variables, language = 'en') {
|
||||
nl: '(Om veiligheidsredenen niet weergegeven)',
|
||||
pt: '(Não exibido por motivos de segurança)',
|
||||
ru: '(Не показано в целях безопасности)',
|
||||
es: '(No se muestra por razones de seguridad)',
|
||||
};
|
||||
const noPasswordI18n = {
|
||||
en: 'No password required',
|
||||
@@ -504,6 +506,7 @@ async function processTemplate(template, variables, language = 'en') {
|
||||
nl: 'Geen wachtwoord vereist',
|
||||
pt: 'Nenhuma senha necessária',
|
||||
ru: 'Пароль не требуется',
|
||||
es: 'No se requiere contraseña',
|
||||
};
|
||||
// Sent by the publish-from-draft flow (adminEvents.js): by the time the
|
||||
// event is published, only the bcrypt hash is stored, so the plaintext
|
||||
@@ -515,6 +518,7 @@ async function processTemplate(template, variables, language = 'en') {
|
||||
nl: 'Het wachtwoord dat u bij het aanmaken van de galerij hebt ingesteld',
|
||||
pt: 'A senha definida ao criar a galeria',
|
||||
ru: 'Пароль, заданный при создании галереи',
|
||||
es: 'La contraseña que estableciste al crear la galería',
|
||||
};
|
||||
|
||||
if (processedVariables.gallery_password === '{{password_security_message}}') {
|
||||
|
||||
Reference in New Issue
Block a user