v4: every message named by an id carries its English in the code — the emails and the four pages that share their words called Lingui with a bare id (i18n._("digest.community"), <Trans id="digest.community" />), so their English lived only in a hand-kept en.po, extract couldn't run with --overwrite, and a page reading the code couldn't tell what it said. The emails now pass descriptors, i18n._({ id, message, values }), the form Lingui reads without a macro, as the server needs. The fifteen messages the digest shares with the community page, Settings, the unsubscribe page and the avatar menu are declared once, as /*i18n*/ descriptors in shared/digest-messages.ts, which those pages translate with useLingui()'s i18n instead of the global one. lingui.config.ts scans shared/ too, and i18n:extract runs with --overwrite, so en.po is written from the code. Every other message already used the macros. The compiled catalogs are unchanged, key for key, in both languages. 272 backend tests and 677 frontend tests pass, and deno check, tsc, eslint, doc:lint and i18n:compile --strict are clean.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
80
shared/digest-messages.ts
Normal file
80
shared/digest-messages.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Words the digest emails share with the pages that show or govern them: the
|
||||
* `/community` page shows the digests' figures and sections, Settings and the
|
||||
* unsubscribe page name the digests, the avatar menu links the community
|
||||
* page. `api/mail/digest.ts` and those pages translate them from here, so an
|
||||
* email and a page always say the same.
|
||||
*
|
||||
* Each is a Lingui message descriptor with an explicit id, since the server
|
||||
* runs no macro; the `i18n` comment has `lingui extract` read its English into
|
||||
* the catalogs. Pass one to `i18n._`, with its values: on the client, the
|
||||
* `i18n` of `useLingui()`.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
|
||||
import type { MessageDescriptor } from "@lingui/core";
|
||||
|
||||
/** The shared messages, by name. */
|
||||
export const DIGEST_MESSAGES = {
|
||||
weekly: /*i18n*/ {
|
||||
id: "digest.weekly",
|
||||
message: "Weekly digest",
|
||||
},
|
||||
monthly: /*i18n*/ {
|
||||
id: "digest.monthly",
|
||||
message: "Monthly recap",
|
||||
},
|
||||
weeklyOff: /*i18n*/ {
|
||||
id: "digest.weekly.off",
|
||||
message: "Turn off weekly digests",
|
||||
},
|
||||
monthlyOff: /*i18n*/ {
|
||||
id: "digest.monthly.off",
|
||||
message: "Turn off monthly recaps",
|
||||
},
|
||||
community: /*i18n*/ {
|
||||
id: "digest.community",
|
||||
message: "Community",
|
||||
},
|
||||
topWeek: /*i18n*/ {
|
||||
id: "digest.topWeek",
|
||||
message: "Top this week",
|
||||
},
|
||||
topMonth: /*i18n*/ {
|
||||
id: "digest.topMonth",
|
||||
message: "Top this month",
|
||||
},
|
||||
newMembers: /*i18n*/ {
|
||||
id: "digest.newMembers",
|
||||
message: "New members",
|
||||
},
|
||||
newPlaylists: /*i18n*/ {
|
||||
id: "digest.newPlaylists",
|
||||
message: "New public playlists",
|
||||
},
|
||||
invitedBy: /*i18n*/ {
|
||||
id: "digest.invitedBy",
|
||||
message: "invited by @{username}",
|
||||
},
|
||||
invitedByYou: /*i18n*/ {
|
||||
id: "digest.invitedByYou",
|
||||
message: "invited by you",
|
||||
},
|
||||
statDumps: /*i18n*/ {
|
||||
id: "digest.stat.dumps",
|
||||
message: "{n, plural, one {dump} other {dumps}}",
|
||||
},
|
||||
statChat: /*i18n*/ {
|
||||
id: "digest.stat.chat",
|
||||
message: "{n, plural, one {chat message} other {chat messages}}",
|
||||
},
|
||||
countUpvotes: /*i18n*/ {
|
||||
id: "digest.count.upvotes",
|
||||
message: "{n, plural, one {upvote} other {upvotes}}",
|
||||
},
|
||||
countComments: /*i18n*/ {
|
||||
id: "digest.count.comments",
|
||||
message: "{n, plural, one {comment} other {comments}}",
|
||||
},
|
||||
} as const satisfies Record<string, MessageDescriptor>;
|
||||
Reference in New Issue
Block a user