feat(design): the Copy rule — names, verbs, dates and units (E28 S3g)
The owner's picks (all the recommended options) become DESIGN.md's Copy chapter and a sweep of both languages (742 values, no key drift): - One name per feature: the rail's label, which may shorten it (Alerts -> Notifications, Fiókok -> Felhasználók, Download Center -> Downloads, Channel manager -> Channels); one "sync from YouTube" verb. - Four verbs, four meanings (Delete / Remove / Dismiss / Discard, and their Hungarian pairs), checked against what each action does. - Sentence case, the app's places capitalised; "…" on a command that asks first (a popover or form title got its own key without it); one-sentence messages without a stop or a tick, "Couldn't …"; curly quotes. - Dates only from lib/format.ts, in the UI language: formatDateTime names the month and stops at the minute (it printed "9/27/2026, 8:30:14 AM"), formatDateTimeSec for the log, the audit and the recorder; ui/RelativeTime pairs "3d ago" with the exact minute on hover. local/date-format refuses toLocale*String and Intl date formatters elsewhere. - Units from Intl, short (formatUnit): runtimes, totals, the Scheduler countdown, the stats range, the player's tap skip. "2h 13m" was English in both languages. - src/i18n/copyRule.test.ts holds the machine-readable part (quotes, "...", ticks, bare unit letters).
This commit is contained in:
@@ -82,6 +82,37 @@ const focusSafeDisabled = {
|
||||
};
|
||||
},
|
||||
};
|
||||
// E28 S3g (docs/DESIGN.md "Copy"): the app shows a date in three forms plus the relative one, all
|
||||
// built in lib/format.ts in the UI language. A bare `toLocaleString()` formats in the BROWSER's locale
|
||||
// and as numbers with seconds; seven call sites had drifted into five shapes. Outside lib/format.ts
|
||||
// a `toLocale*String` call or an `Intl.DateTimeFormat` / `Intl.RelativeTimeFormat` is refused (a
|
||||
// number goes through formatNumber, which the same rule covers).
|
||||
const dateFormat = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
messages: {
|
||||
date: "Format dates and numbers through lib/format.ts (formatDate, formatDateTime, formatDateTimeSec, relativeTime, formatNumber), in the UI language.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const path = context.filename.split("\\").join("/");
|
||||
// lib/format.ts is where the forms live; a test computes its expectations; the Plex player's
|
||||
// on-screen clock (lib/plexPlayerPrefs.ts) is a clock face with its own 12/24h switch, not a date.
|
||||
if (/\/src\/lib\/(format|plexPlayerPrefs)\.ts$|\.test\.tsx?$/.test(path)) return {};
|
||||
return {
|
||||
"CallExpression > MemberExpression.callee[property.name=/^toLocale(Date|Time)?String$/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({ node, messageId: "date" });
|
||||
},
|
||||
"MemberExpression[object.name='Intl'][property.name=/^(DateTimeFormat|RelativeTimeFormat)$/]"(
|
||||
node,
|
||||
) {
|
||||
context.report({ node, messageId: "date" });
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
// E28 S3b: one primitive per button family (docs/DESIGN.md). 268 hand-rolled buttons in 79 files had
|
||||
// drifted into as many looks, heights and hover styles; they were swept onto ui/Button, IconButton,
|
||||
// Pressable, Chip and DragHandle, and this keeps the next one out. The raw element lives only in the
|
||||
@@ -351,6 +382,7 @@ const localRules = {
|
||||
"jsx-comment-text": jsxCommentText,
|
||||
"focus-safe-disabled": focusSafeDisabled,
|
||||
"button-primitive": buttonPrimitive,
|
||||
"date-format": dateFormat,
|
||||
"input-primitive": inputPrimitive,
|
||||
"surface-role": surfaceRole,
|
||||
"literal-a11y-text": literalA11yText,
|
||||
@@ -445,6 +477,7 @@ export default tseslint.config(
|
||||
"local/jsx-comment-text": "error",
|
||||
"local/focus-safe-disabled": "error",
|
||||
"local/button-primitive": "error",
|
||||
"local/date-format": "error",
|
||||
"local/input-primitive": "error",
|
||||
"local/surface-role": "error",
|
||||
"local/literal-a11y-text": "error",
|
||||
|
||||
Reference in New Issue
Block a user