@stats-forge/github-stats-forge-core 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/build/api/contributed-to.js +1 -1
  2. package/build/api/gist.js +1 -1
  3. package/build/api/index.d.ts +1 -0
  4. package/build/api/index.d.ts.map +1 -1
  5. package/build/api/index.js +1 -0
  6. package/build/api/organization.d.ts +29 -0
  7. package/build/api/organization.d.ts.map +1 -0
  8. package/build/api/organization.js +53 -0
  9. package/build/api/params.js +1 -1
  10. package/build/api/pin.js +1 -1
  11. package/build/api/stats.js +1 -1
  12. package/build/api/top-langs.js +1 -1
  13. package/build/api/wakatime.js +1 -1
  14. package/build/cards/{contributed-to.d.ts → contributed-to/index.d.ts} +3 -3
  15. package/build/cards/contributed-to/index.d.ts.map +1 -0
  16. package/build/cards/{contributed-to.js → contributed-to/index.js} +31 -30
  17. package/build/cards/contributed-to/locales.d.ts +38 -0
  18. package/build/cards/contributed-to/locales.d.ts.map +1 -0
  19. package/build/cards/contributed-to/locales.js +39 -0
  20. package/build/cards/{gist.d.ts → gist/index.d.ts} +3 -3
  21. package/build/cards/gist/index.d.ts.map +1 -0
  22. package/build/cards/{gist.js → gist/index.js} +20 -15
  23. package/build/cards/gist/locales.d.ts +14 -0
  24. package/build/cards/gist/locales.d.ts.map +1 -0
  25. package/build/cards/gist/locales.js +15 -0
  26. package/build/cards/organization/index.d.ts +36 -0
  27. package/build/cards/organization/index.d.ts.map +1 -0
  28. package/build/cards/organization/index.js +226 -0
  29. package/build/cards/organization/locales.d.ts +47 -0
  30. package/build/cards/organization/locales.d.ts.map +1 -0
  31. package/build/cards/organization/locales.js +47 -0
  32. package/build/cards/{repo.d.ts → repo/index.d.ts} +3 -3
  33. package/build/cards/repo/index.d.ts.map +1 -0
  34. package/build/cards/{repo.js → repo/index.js} +20 -23
  35. package/build/cards/repo/locales.d.ts +129 -0
  36. package/build/cards/repo/locales.d.ts.map +1 -0
  37. package/build/cards/repo/locales.js +129 -0
  38. package/build/cards/{stats.d.ts → stats/index.d.ts} +3 -3
  39. package/build/cards/stats/index.d.ts.map +1 -0
  40. package/build/cards/{stats.js → stats/index.js} +38 -42
  41. package/build/cards/stats/locales.d.ts +621 -0
  42. package/build/cards/stats/locales.d.ts.map +1 -0
  43. package/build/cards/stats/locales.js +623 -0
  44. package/build/cards/{top-languages.d.ts → top-languages/index.d.ts} +3 -3
  45. package/build/cards/top-languages/index.d.ts.map +1 -0
  46. package/build/cards/{top-languages.js → top-languages/index.js} +13 -16
  47. package/build/cards/top-languages/locales.d.ts +103 -0
  48. package/build/cards/top-languages/locales.d.ts.map +1 -0
  49. package/build/cards/top-languages/locales.js +103 -0
  50. package/build/cards/{wakatime.d.ts → wakatime/index.d.ts} +3 -3
  51. package/build/cards/wakatime/index.d.ts.map +1 -0
  52. package/build/cards/{wakatime.js → wakatime/index.js} +22 -23
  53. package/build/cards/wakatime/locales.d.ts +250 -0
  54. package/build/cards/wakatime/locales.d.ts.map +1 -0
  55. package/build/cards/wakatime/locales.js +250 -0
  56. package/build/common/brand.d.ts +1 -0
  57. package/build/common/brand.d.ts.map +1 -1
  58. package/build/common/brand.js +1 -0
  59. package/build/common/error.d.ts +3 -1
  60. package/build/common/error.d.ts.map +1 -1
  61. package/build/common/error.js +3 -1
  62. package/build/common/http.d.ts +2 -0
  63. package/build/common/http.d.ts.map +1 -1
  64. package/build/common/icons.d.ts +5 -0
  65. package/build/common/icons.d.ts.map +1 -1
  66. package/build/common/icons.js +19 -4
  67. package/build/common/languageColors.json +2 -0
  68. package/build/common/locales.d.ts +59 -0
  69. package/build/common/locales.d.ts.map +1 -0
  70. package/build/common/locales.js +59 -0
  71. package/build/common/localize.d.ts +60 -0
  72. package/build/common/localize.d.ts.map +1 -0
  73. package/build/common/localize.js +163 -0
  74. package/build/fetchers/index.d.ts +2 -1
  75. package/build/fetchers/index.d.ts.map +1 -1
  76. package/build/fetchers/index.js +1 -0
  77. package/build/fetchers/organization.d.ts +15 -0
  78. package/build/fetchers/organization.d.ts.map +1 -0
  79. package/build/fetchers/organization.js +130 -0
  80. package/build/fetchers/types.d.ts +39 -0
  81. package/build/fetchers/types.d.ts.map +1 -1
  82. package/build/graphql/generated/organization.d.ts +88 -0
  83. package/build/graphql/generated/organization.d.ts.map +1 -0
  84. package/build/graphql/generated/organization.js +59 -0
  85. package/package.json +1 -1
  86. package/src/api/contributed-to.ts +1 -1
  87. package/src/api/gist.ts +1 -1
  88. package/src/api/index.ts +1 -0
  89. package/src/api/organization.ts +90 -0
  90. package/src/api/params.ts +1 -1
  91. package/src/api/pin.ts +1 -1
  92. package/src/api/stats.ts +1 -1
  93. package/src/api/top-langs.ts +1 -1
  94. package/src/api/wakatime.ts +1 -1
  95. package/src/cards/{contributed-to.ts → contributed-to/index.ts} +42 -39
  96. package/src/cards/contributed-to/locales.ts +41 -0
  97. package/src/cards/{gist.ts → gist/index.ts} +23 -20
  98. package/src/cards/gist/locales.ts +17 -0
  99. package/src/cards/organization/index.ts +359 -0
  100. package/src/cards/organization/locales.ts +49 -0
  101. package/src/cards/{repo.ts → repo/index.ts} +23 -26
  102. package/src/cards/repo/locales.ts +131 -0
  103. package/src/cards/{stats.ts → stats/index.ts} +48 -56
  104. package/src/cards/stats/locales.ts +625 -0
  105. package/src/cards/{top-languages.ts → top-languages/index.ts} +17 -20
  106. package/src/cards/top-languages/locales.ts +105 -0
  107. package/src/cards/{wakatime.ts → wakatime/index.ts} +26 -27
  108. package/src/cards/wakatime/locales.ts +252 -0
  109. package/src/common/brand.ts +1 -0
  110. package/src/common/error.ts +4 -0
  111. package/src/common/http.ts +6 -1
  112. package/src/common/icons.ts +20 -4
  113. package/src/common/languageColors.json +2 -0
  114. package/src/common/locales.ts +61 -0
  115. package/src/common/localize.ts +251 -0
  116. package/src/fetchers/index.ts +2 -0
  117. package/src/fetchers/organization.ts +172 -0
  118. package/src/fetchers/types.ts +37 -0
  119. package/src/graphql/generated/organization.ts +109 -0
  120. package/src/graphql/queries/organization.graphql +57 -0
  121. package/build/cards/contributed-to.d.ts.map +0 -1
  122. package/build/cards/gist.d.ts.map +0 -1
  123. package/build/cards/repo.d.ts.map +0 -1
  124. package/build/cards/stats.d.ts.map +0 -1
  125. package/build/cards/top-languages.d.ts.map +0 -1
  126. package/build/cards/wakatime.d.ts.map +0 -1
  127. package/build/common/I18n.d.ts +0 -21
  128. package/build/common/I18n.d.ts.map +0 -1
  129. package/build/common/I18n.js +0 -34
  130. package/build/translations.d.ts +0 -1212
  131. package/build/translations.d.ts.map +0 -1
  132. package/build/translations.js +0 -1213
  133. package/src/common/I18n.ts +0 -50
  134. package/src/translations.ts +0 -1239
@@ -0,0 +1,90 @@
1
+ import * as z from 'zod/mini';
2
+
3
+ import { renderOrganizationCard } from '../cards/organization/index.ts';
4
+ import { fetchOrganization } from '../fetchers/organization.ts';
5
+
6
+ import { cardHandler } from './handler.ts';
7
+ import {
8
+ booleanParam,
9
+ listParam,
10
+ localeParam,
11
+ looseIntParam,
12
+ numberParam,
13
+ rawParam,
14
+ usernameParam,
15
+ } from './params.ts';
16
+
17
+ /** What the organization endpoint accepts, on top of the shared color params. */
18
+ const orgQuery = z.object({
19
+ org: usernameParam,
20
+ hide: listParam,
21
+ show: listParam,
22
+ show_icons: booleanParam,
23
+ hide_title: booleanParam,
24
+ hide_border: booleanParam,
25
+ hide_description: booleanParam,
26
+ card_width: looseIntParam,
27
+ line_height: rawParam,
28
+ custom_title: rawParam,
29
+ disable_animations: booleanParam,
30
+ number_format: rawParam,
31
+ text_bold: booleanParam,
32
+ locale: localeParam,
33
+ border_radius: numberParam,
34
+ });
35
+
36
+ /**
37
+ * Render the organization card for a set of query params.
38
+ *
39
+ * @returns The rendered card, or a rendered error.
40
+ */
41
+ const renderOrg = cardHandler(
42
+ orgQuery,
43
+ async (
44
+ {
45
+ org,
46
+ hide,
47
+ show,
48
+ show_icons,
49
+ hide_title,
50
+ hide_border,
51
+ hide_description,
52
+ card_width,
53
+ line_height,
54
+ custom_title,
55
+ disable_animations,
56
+ number_format,
57
+ text_bold,
58
+ locale,
59
+ border_radius,
60
+ },
61
+ colors,
62
+ config,
63
+ ) => {
64
+ const organizationData = await fetchOrganization({ org }, config);
65
+
66
+ return renderOrganizationCard(organizationData, {
67
+ ...colors,
68
+ hide,
69
+ show,
70
+ show_icons,
71
+ hide_title,
72
+ hide_border,
73
+ hide_description,
74
+ card_width,
75
+ line_height,
76
+ custom_title,
77
+ disable_animations,
78
+ number_format,
79
+ text_bold,
80
+ locale,
81
+ border_radius,
82
+ });
83
+ },
84
+ );
85
+
86
+ /**
87
+ * The card, and the values each of its options accepts, keyed by the option's own name.
88
+ * A UI reads them off the function it calls: `org.OPTIONS.show`.
89
+ */
90
+ export const org = Object.assign(renderOrg, { OPTIONS: renderOrganizationCard.OPTIONS });
package/src/api/params.ts CHANGED
@@ -5,8 +5,8 @@ import { COLOR_PARAM_KEYS, THEME_PARAM_KEYS, isValidColorInput } from '../common
5
5
  import { GITHUB_USERNAME_PATTERN } from '../common/constants.ts';
6
6
  import { getWidestRange, parseRangeDate } from '../common/date.ts';
7
7
  import { CardError } from '../common/error.ts';
8
+ import { isLocaleAvailable } from '../common/localize.ts';
8
9
  import { parseArray, parseBoolean } from '../common/ops.ts';
9
- import { isLocaleAvailable } from '../translations.ts';
10
10
 
11
11
  /**
12
12
  * @file The api layer is the trust boundary:
package/src/api/pin.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod/mini';
2
2
 
3
- import { renderRepoCard } from '../cards/repo.ts';
3
+ import { renderRepoCard } from '../cards/repo/index.ts';
4
4
  import { fetchRepo } from '../fetchers/repo.ts';
5
5
 
6
6
  import { cardHandler } from './handler.ts';
package/src/api/stats.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod/mini';
2
2
 
3
- import { renderStatsCard } from '../cards/stats.ts';
3
+ import { renderStatsCard } from '../cards/stats/index.ts';
4
4
  import { OWNER_AFFILIATIONS } from '../common/constants.ts';
5
5
  import { fetchStats } from '../fetchers/stats.ts';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod/mini';
2
2
 
3
- import { renderTopLanguages } from '../cards/top-languages.ts';
3
+ import { renderTopLanguages } from '../cards/top-languages/index.ts';
4
4
  import { OWNER_AFFILIATIONS } from '../common/constants.ts';
5
5
  import { fetchTopLanguages } from '../fetchers/top-languages.ts';
6
6
 
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod/mini';
2
2
 
3
- import { renderWakatimeCard } from '../cards/wakatime.ts';
3
+ import { renderWakatimeCard } from '../cards/wakatime/index.ts';
4
4
  import { fetchWakatimeStats } from '../fetchers/wakatime.ts';
5
5
 
6
6
  import { cardHandler } from './handler.ts';
@@ -1,17 +1,18 @@
1
- import { CARD_ICON, CARD_WIDTH, FONT_SIZE, firefoxFontSize, font } from '../common/brand.ts';
2
- import { Card } from '../common/Card.ts';
3
- import { getLightDarkColors } from '../common/color.ts';
4
- import { formatYears } from '../common/date.ts';
5
- import { kFormatter } from '../common/fmt.ts';
6
- import { I18n } from '../common/I18n.ts';
7
- import { clampValue } from '../common/ops.ts';
8
- import { createProgressNode, measureText } from '../common/render.ts';
9
- import type { ContributedRepo, ContributedToData } from '../fetchers/types.ts';
10
- import type { Child } from '../markup/index.ts';
11
- import { atRule, el, rule } from '../markup/index.ts';
12
- import { contributedToCardLocales } from '../translations.ts';
1
+ import { CARD_ICON, CARD_WIDTH, FONT_SIZE, firefoxFontSize, font } from '../../common/brand.ts';
2
+ import { Card } from '../../common/Card.ts';
3
+ import { getLightDarkColors } from '../../common/color.ts';
4
+ import { formatYears } from '../../common/date.ts';
5
+ import { kFormatter } from '../../common/fmt.ts';
6
+ import type { Localized } from '../../common/localize.ts';
7
+ import { localize } from '../../common/localize.ts';
8
+ import { clampValue } from '../../common/ops.ts';
9
+ import { createProgressNode, measureText } from '../../common/render.ts';
10
+ import type { ContributedRepo, ContributedToData } from '../../fetchers/types.ts';
11
+ import type { Child } from '../../markup/index.ts';
12
+ import { atRule, el, rule } from '../../markup/index.ts';
13
+ import type { CardOptions, CommonCardOptions } from '../options.ts';
13
14
 
14
- import type { CardOptions, CommonCardOptions } from './options.ts';
15
+ import { contributedToCardLocales } from './locales.ts';
15
16
 
16
17
  const CARD_DEFAULT_WIDTH = CARD_WIDTH.wide;
17
18
  const MIN_CARD_WIDTH = 340;
@@ -53,9 +54,6 @@ interface ContributedToCardOptions extends CommonCardOptions {
53
54
  hide_years: boolean;
54
55
  }
55
56
 
56
- /** The card's own translation table, so `t` is checked against the keys it declares. */
57
- type ContributedToI18n = I18n<ReturnType<typeof contributedToCardLocales>>;
58
-
59
57
  /**
60
58
  * The title, naming the account unless that makes it too wide for the card.
61
59
  *
@@ -64,11 +62,13 @@ type ContributedToI18n = I18n<ReturnType<typeof contributedToCardLocales>>;
64
62
  *
65
63
  * @returns The default title, which `custom_title` still overrides.
66
64
  */
67
- const defaultTitleFor = (i18n: ContributedToI18n, contentWidth: number): string => {
68
- const named = i18n.t('contributedtocard.title');
69
- return measureText(named, TITLE_FONT_SIZE) <= contentWidth
70
- ? named
71
- : i18n.t('contributedtocard.title-unnamed');
65
+ const defaultTitleFor = (
66
+ t: Localized<typeof contributedToCardLocales>,
67
+ login: string,
68
+ contentWidth: number,
69
+ ): string => {
70
+ const named = t.title({ login });
71
+ return measureText(named, TITLE_FONT_SIZE) <= contentWidth ? named : t.titleUnnamed();
72
72
  };
73
73
 
74
74
  /**
@@ -190,19 +190,21 @@ const createRepoRow = ({
190
190
  * @returns The footer text.
191
191
  */
192
192
  const footerText = ({
193
- i18n,
193
+ t,
194
194
  shown,
195
195
  totalRepos,
196
196
  years,
197
197
  }: {
198
- i18n: ContributedToI18n;
198
+ t: Localized<typeof contributedToCardLocales>;
199
199
  shown: number;
200
200
  totalRepos: number;
201
201
  /** Empty when the year marks are hidden, which is what puts the years on the card. */
202
202
  years: Array<number>;
203
203
  }): string => {
204
204
  const parts = [
205
- i18n.t(shown < totalRepos ? 'contributedtocard.footer-top' : 'contributedtocard.footer-all'),
205
+ shown < totalRepos
206
+ ? t.footerTop({ shown, count: totalRepos })
207
+ : t.footerAll({ count: totalRepos }),
206
208
  ];
207
209
 
208
210
  const [firstYear] = years;
@@ -261,12 +263,9 @@ const renderContributedToCard = (
261
263
  }),
262
264
  );
263
265
 
264
- const i18n = new I18n({
265
- locale,
266
- translations: contributedToCardLocales({ login, shown: repos.length, totalRepos }),
267
- });
266
+ const t = localize(contributedToCardLocales, locale);
268
267
 
269
- const footer = footerText({ i18n, shown: repos.length, totalRepos, years });
268
+ const footer = footerText({ t, shown: repos.length, totalRepos, years });
270
269
  const footerY = FIRST_ROW_Y + Math.max(repos.length, 1) * rowHeight + FOOTER_GAP;
271
270
  const height = BODY_OFFSET_Y + footerY + BOTTOM_PADDING;
272
271
 
@@ -274,7 +273,7 @@ const renderContributedToCard = (
274
273
 
275
274
  const card = new Card({
276
275
  customTitle: custom_title,
277
- defaultTitle: defaultTitleFor(i18n, contentWidth - TITLE_ICON_COLUMN),
276
+ defaultTitle: defaultTitleFor(t, login, contentWidth - TITLE_ICON_COLUMN),
278
277
  titlePrefixIcon: CARD_ICON.contributedTo,
279
278
  width,
280
279
  height,
@@ -342,14 +341,18 @@ const renderContributedToCard = (
342
341
  card.setAccessibilityLabel({
343
342
  title: card.title,
344
343
  desc: [
345
- ...repos.map((repo) => {
346
- const inYears = hide_years
347
- ? ''
348
- : `, ${i18n.t('contributedtocard.years')}: ${repo.years.join(', ')}`;
349
- return `${repo.nameWithOwner}: ${repo.contributions} ${i18n.t(
350
- 'contributedtocard.contributions',
351
- )}${inYears}`;
352
- }),
344
+ ...repos.map((repo) =>
345
+ hide_years
346
+ ? t.accessibilityRepo({
347
+ repo: repo.nameWithOwner,
348
+ count: repo.contributions,
349
+ })
350
+ : t.accessibilityRepoYears({
351
+ repo: repo.nameWithOwner,
352
+ count: repo.contributions,
353
+ years: repo.years.join(', '),
354
+ }),
355
+ ),
353
356
  footer,
354
357
  ].join('; '),
355
358
  });
@@ -362,7 +365,7 @@ const renderContributedToCard = (
362
365
  ? el(
363
366
  'text',
364
367
  { class: 'repo-name', 'data-testid': 'no-repos', x: 0, y: FIRST_ROW_Y },
365
- i18n.t('contributedtocard.no-contributions'),
368
+ t.noContributions(),
366
369
  )
367
370
  : rows,
368
371
  el('text', { class: 'footer', 'data-testid': 'footer', x: 0, y: footerY }, footer),
@@ -0,0 +1,41 @@
1
+ import { defineLocales } from '../../common/localize.ts';
2
+
3
+ /** The contributed-to card's labels in the locales they have been translated into. */
4
+ const contributedToCardLocales = defineLocales({
5
+ title: {
6
+ en: 'Repositories {login} contributed to',
7
+ },
8
+ // Drawn instead of the title above when naming the account overruns the card.
9
+ titleUnnamed: {
10
+ en: 'Repositories contributed to',
11
+ },
12
+ noContributions: {
13
+ en: 'No contributions found',
14
+ },
15
+ footerAll: {
16
+ en: { one: '{count} repository', other: '{count} repositories' },
17
+ },
18
+ footerTop: {
19
+ en: {
20
+ one: 'top {shown} of {count} repository',
21
+ other: 'top {shown} of {count} repositories',
22
+ },
23
+ },
24
+ // One row of what an assistive reader gets in place of the card, whose inner text
25
+ // `role="img"` hides. The year marks carry information no other element does, so the
26
+ // row naming them is a wording of its own rather than a fragment appended to the other.
27
+ accessibilityRepo: {
28
+ en: {
29
+ one: '{repo}: {count} contribution',
30
+ other: '{repo}: {count} contributions',
31
+ },
32
+ },
33
+ accessibilityRepoYears: {
34
+ en: {
35
+ one: '{repo}: {count} contribution, years: {years}',
36
+ other: '{repo}: {count} contributions, years: {years}',
37
+ },
38
+ },
39
+ });
40
+
41
+ export { contributedToCardLocales };
@@ -1,11 +1,11 @@
1
- import { CARD_ICON, CARD_WIDTH, FONT_SIZE, font } from '../common/brand.ts';
2
- import { Card } from '../common/Card.ts';
3
- import { getLightDarkColors } from '../common/color.ts';
4
- import { kFormatter } from '../common/fmt.ts';
5
- import { I18n } from '../common/I18n.ts';
6
- import { icons } from '../common/icons.ts';
7
- import { getLanguageColor } from '../common/languageColors.ts';
8
- import { parseEmojis } from '../common/ops.ts';
1
+ import { CARD_ICON, CARD_WIDTH, FONT_SIZE, font } from '../../common/brand.ts';
2
+ import { Card } from '../../common/Card.ts';
3
+ import { getLightDarkColors } from '../../common/color.ts';
4
+ import { kFormatter } from '../../common/fmt.ts';
5
+ import { icons } from '../../common/icons.ts';
6
+ import { getLanguageColor } from '../../common/languageColors.ts';
7
+ import { localize } from '../../common/localize.ts';
8
+ import { parseEmojis } from '../../common/ops.ts';
9
9
  import {
10
10
  countWrappedLines,
11
11
  wrapTextMultiline,
@@ -15,13 +15,13 @@ import {
15
15
  measureText,
16
16
  wrappedTextNode,
17
17
  wrappedTextStyles,
18
- } from '../common/render.ts';
19
- import type { GistData } from '../fetchers/types.ts';
20
- import type { Child } from '../markup/index.ts';
21
- import { el, rule } from '../markup/index.ts';
22
- import { gistCardLocales } from '../translations.ts';
18
+ } from '../../common/render.ts';
19
+ import type { GistData } from '../../fetchers/types.ts';
20
+ import type { Child } from '../../markup/index.ts';
21
+ import { el, rule } from '../../markup/index.ts';
22
+ import type { CardOptions, CommonCardOptions } from '../options.ts';
23
23
 
24
- import type { CardOptions, CommonCardOptions } from './options.ts';
24
+ import { gistCardLocales } from './locales.ts';
25
25
 
26
26
  const ICON_SIZE = 16;
27
27
  const CARD_DEFAULT_WIDTH = CARD_WIDTH.standard;
@@ -56,9 +56,9 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
56
56
 
57
57
  const { lightColors, darkColors } = getLightDarkColors({ ...options, theme });
58
58
 
59
- const i18n = new I18n({ locale, translations: gistCardLocales });
59
+ const t = localize(gistCardLocales, locale);
60
60
 
61
- const desc = parseEmojis(description || i18n.t('gistcard.no-description'));
61
+ const desc = parseEmojis(description || t.noDescription());
62
62
 
63
63
  let descriptionLines: number;
64
64
  let descriptionSvg: Child;
@@ -108,7 +108,7 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
108
108
  const svgStars = iconWithLabel(icons.star, totalStars, 'starsCount', ICON_SIZE);
109
109
  const svgForks = iconWithLabel(icons.fork, totalForks, 'forksCount', ICON_SIZE);
110
110
 
111
- const languageName = language || i18n.t('gistcard.unspecified-language');
111
+ const languageName = language || t.unspecifiedLanguage();
112
112
  const languageColor = getLanguageColor(languageName);
113
113
 
114
114
  const svgLanguage = createLanguageNode(languageName, languageColor);
@@ -161,9 +161,12 @@ const renderGistCard = (gistData: GistData, options: CardOptions<GistCardOptions
161
161
  // shows has to be repeated here.
162
162
  card.setAccessibilityLabel({
163
163
  title: card.title,
164
- desc: `${desc}. ${i18n.t('gistcard.language')}: ${languageName}, ${i18n.t(
165
- 'gistcard.stars',
166
- )}: ${totalStars}, ${i18n.t('gistcard.forks')}: ${totalForks}`,
164
+ desc: t.accessibilityDesc({
165
+ desc,
166
+ language: languageName,
167
+ stars: totalStars,
168
+ forks: totalForks,
169
+ }),
167
170
  });
168
171
 
169
172
  return card.render([
@@ -0,0 +1,17 @@
1
+ import { defineLocales } from '../../common/localize.ts';
2
+
3
+ /** The gist card's labels in the locales they have been translated into. */
4
+ const gistCardLocales = defineLocales({
5
+ noDescription: {
6
+ en: 'No description provided',
7
+ },
8
+ unspecifiedLanguage: {
9
+ en: 'Unspecified',
10
+ },
11
+ // What an assistive reader gets in place of the card, whose inner text `role="img"` hides.
12
+ accessibilityDesc: {
13
+ en: '{desc}. Language: {language}, Stars: {stars}, Forks: {forks}',
14
+ },
15
+ });
16
+
17
+ export { gistCardLocales };