@takuhon/ui 0.5.0 → 0.6.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.
package/dist/index.js CHANGED
@@ -1,6 +1,121 @@
1
1
  // src/components/TakuhonProfile.tsx
2
2
  import "./tokens-TEMWJS5E.css";
3
3
 
4
+ // src/lib/date-formatter.ts
5
+ var YEAR_MONTH = /^(\d{4})-(0[1-9]|1[0-2])$/;
6
+ function formatYearMonth(value, locale) {
7
+ const match = YEAR_MONTH.exec(value);
8
+ if (!match) return value;
9
+ const year = Number(match[1]);
10
+ const month = Number(match[2]);
11
+ const date = /* @__PURE__ */ new Date(0);
12
+ date.setUTCFullYear(year, month - 1, 1);
13
+ const options = {
14
+ year: "numeric",
15
+ month: "short",
16
+ timeZone: "UTC"
17
+ };
18
+ try {
19
+ return new Intl.DateTimeFormat(locale || "en", options).format(date);
20
+ } catch {
21
+ return new Intl.DateTimeFormat("en", options).format(date);
22
+ }
23
+ }
24
+
25
+ // src/lib/ui-labels.ts
26
+ var EN = {
27
+ "timeline.present": "Present",
28
+ "certification.noExpiration": "No expiration",
29
+ "patent.filed": "Filed",
30
+ "patent.granted": "Granted",
31
+ "patent.coInventorsPrefix": "with ",
32
+ "publication.coAuthorsPrefix": "with ",
33
+ "proficiency.native": "Native",
34
+ "proficiency.fluent": "Fluent",
35
+ "proficiency.professional": "Professional working",
36
+ "proficiency.intermediate": "Intermediate",
37
+ "proficiency.basic": "Basic",
38
+ "patentStatus.pending": "Pending",
39
+ "patentStatus.issued": "Issued",
40
+ "patentStatus.expired": "Expired",
41
+ "patentStatus.abandoned": "Abandoned",
42
+ "section.career": "Career",
43
+ "section.education": "Education",
44
+ "section.certifications": "Certifications",
45
+ "section.patents": "Patents",
46
+ "section.projects": "Projects",
47
+ "section.publications": "Publications",
48
+ "section.honors": "Honors & Awards",
49
+ "section.recommendations": "Recommendations",
50
+ "section.volunteering": "Volunteering",
51
+ "section.memberships": "Memberships",
52
+ "section.courses": "Courses",
53
+ "section.languages": "Languages",
54
+ "section.testScores": "Test Scores",
55
+ "section.skills": "Skills",
56
+ "section.contact": "Contact",
57
+ // a11y / chrome affixes. Status/Cause prefixes carry their trailing
58
+ // separator (a space in English) so callers concatenate prefix + value.
59
+ "a11y.statusPrefix": "Status: ",
60
+ "a11y.causePrefix": "Cause: ",
61
+ "a11y.profileLinks": "Profile links",
62
+ "a11y.tags": "Tags",
63
+ "a11y.skillsSuffix": "skills",
64
+ "a11y.selectLanguage": "Select language",
65
+ "contact.formLink": "Contact form",
66
+ "skills.uncategorized": "Other"
67
+ };
68
+ var JA = {
69
+ "timeline.present": "\u73FE\u5728",
70
+ "certification.noExpiration": "\u7121\u671F\u9650",
71
+ "patent.filed": "\u51FA\u9858",
72
+ "patent.granted": "\u767B\u9332",
73
+ "patent.coInventorsPrefix": "\u5171\u540C\u767A\u660E\u8005\uFF1A",
74
+ "publication.coAuthorsPrefix": "\u5171\u8457\u8005\uFF1A",
75
+ "proficiency.native": "\u30CD\u30A4\u30C6\u30A3\u30D6",
76
+ "proficiency.fluent": "\u6D41\u66A2",
77
+ "proficiency.professional": "\u5B9F\u52D9\u30EC\u30D9\u30EB",
78
+ "proficiency.intermediate": "\u4E2D\u7D1A",
79
+ "proficiency.basic": "\u521D\u7D1A",
80
+ "patentStatus.pending": "\u51FA\u9858\u4E2D",
81
+ "patentStatus.issued": "\u767B\u9332\u6E08",
82
+ "patentStatus.expired": "\u5931\u52B9",
83
+ "patentStatus.abandoned": "\u653E\u68C4",
84
+ "section.career": "\u8077\u6B74",
85
+ "section.education": "\u5B66\u6B74",
86
+ "section.certifications": "\u8CC7\u683C\u30FB\u8A8D\u5B9A",
87
+ "section.patents": "\u7279\u8A31",
88
+ "section.projects": "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8",
89
+ "section.publications": "\u8AD6\u6587\u30FB\u51FA\u7248",
90
+ "section.honors": "\u53D7\u8CDE\u30FB\u6804\u8A89",
91
+ "section.recommendations": "\u63A8\u85A6",
92
+ "section.volunteering": "\u30DC\u30E9\u30F3\u30C6\u30A3\u30A2",
93
+ "section.memberships": "\u6240\u5C5E",
94
+ "section.courses": "\u8B1B\u5EA7",
95
+ "section.languages": "\u8A00\u8A9E",
96
+ "section.testScores": "\u30C6\u30B9\u30C8\u30B9\u30B3\u30A2",
97
+ "section.skills": "\u30B9\u30AD\u30EB",
98
+ "section.contact": "\u9023\u7D61\u5148",
99
+ // Status/Cause prefixes use a full-width colon (no trailing space), the
100
+ // conventional Japanese form, mirroring the co-author prefix convention.
101
+ "a11y.statusPrefix": "\u30B9\u30C6\u30FC\u30BF\u30B9\uFF1A",
102
+ "a11y.causePrefix": "\u5206\u91CE\uFF1A",
103
+ "a11y.profileLinks": "\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u30EA\u30F3\u30AF",
104
+ "a11y.tags": "\u30BF\u30B0",
105
+ "a11y.skillsSuffix": "\u30B9\u30AD\u30EB",
106
+ "a11y.selectLanguage": "\u8A00\u8A9E\u3092\u9078\u629E",
107
+ "contact.formLink": "\u304A\u554F\u3044\u5408\u308F\u305B\u30D5\u30A9\u30FC\u30E0",
108
+ "skills.uncategorized": "\u305D\u306E\u4ED6"
109
+ };
110
+ var DICTIONARIES = {
111
+ en: EN,
112
+ ja: JA
113
+ };
114
+ function getUILabel(key, locale) {
115
+ const base = locale.split("-")[0] ?? locale;
116
+ return DICTIONARIES[locale]?.[key] ?? DICTIONARIES[base]?.[key] ?? EN[key];
117
+ }
118
+
4
119
  // src/components/CareerTimeline.tsx
5
120
  import styles from "./CareerTimeline.module-BGFX3LGA.module.css";
6
121
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -15,11 +130,14 @@ function sortCareers(careers) {
15
130
  function isOngoing(career) {
16
131
  return career.isCurrent === true || career.endDate === null || career.endDate === void 0;
17
132
  }
18
- function CareerTimeline({ careers }) {
133
+ function CareerTimeline({
134
+ careers,
135
+ locale = "en"
136
+ }) {
19
137
  if (careers.length === 0) return null;
20
138
  const ordered = sortCareers(careers);
21
139
  return /* @__PURE__ */ jsxs("section", { className: styles.section, "aria-labelledby": "takuhon-career-heading", children: [
22
- /* @__PURE__ */ jsx("h2", { id: "takuhon-career-heading", className: styles.heading, children: "Career" }),
140
+ /* @__PURE__ */ jsx("h2", { id: "takuhon-career-heading", className: styles.heading, children: getUILabel("section.career", locale) }),
23
141
  /* @__PURE__ */ jsx("ol", { className: styles.list, children: ordered.map((career) => /* @__PURE__ */ jsxs("li", { className: styles.item, children: [
24
142
  /* @__PURE__ */ jsx("div", { className: styles.timelineMarker, "aria-hidden": "true" }),
25
143
  /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
@@ -42,12 +160,9 @@ function CareerTimeline({ careers }) {
42
160
  career.organization
43
161
  ] }) }),
44
162
  /* @__PURE__ */ jsxs("p", { className: styles.range, children: [
45
- /* @__PURE__ */ jsx("time", { dateTime: career.startDate, children: career.startDate }),
163
+ /* @__PURE__ */ jsx("time", { dateTime: career.startDate, children: formatYearMonth(career.startDate, locale) }),
46
164
  " \u2013 ",
47
- isOngoing(career) ? (
48
- // TODO(i18n-phase-2): Localize the 'Present' label via the locale resolver.
49
- "Present"
50
- ) : /* @__PURE__ */ jsx("time", { dateTime: career.endDate, children: career.endDate })
165
+ isOngoing(career) ? getUILabel("timeline.present", locale) : /* @__PURE__ */ jsx("time", { dateTime: career.endDate, children: formatYearMonth(career.endDate, locale) })
51
166
  ] }),
52
167
  career.location?.display ? /* @__PURE__ */ jsx("p", { className: styles.location, children: career.location.display }) : null,
53
168
  career.description ? /* @__PURE__ */ jsx("p", { className: styles.description, children: career.description }) : null
@@ -67,11 +182,14 @@ function sortCerts(certs) {
67
182
  return b.issueDate.localeCompare(a.issueDate);
68
183
  });
69
184
  }
70
- function Certifications({ certifications }) {
185
+ function Certifications({
186
+ certifications,
187
+ locale = "en"
188
+ }) {
71
189
  if (certifications.length === 0) return null;
72
190
  const ordered = sortCerts(certifications);
73
191
  return /* @__PURE__ */ jsxs2("section", { className: styles2.section, "aria-labelledby": "takuhon-certifications-heading", children: [
74
- /* @__PURE__ */ jsx2("h2", { id: "takuhon-certifications-heading", className: styles2.heading, children: "Certifications" }),
192
+ /* @__PURE__ */ jsx2("h2", { id: "takuhon-certifications-heading", className: styles2.heading, children: getUILabel("section.certifications", locale) }),
75
193
  /* @__PURE__ */ jsx2("ul", { className: styles2.list, children: ordered.map((cert) => /* @__PURE__ */ jsxs2("li", { className: styles2.item, children: [
76
194
  /* @__PURE__ */ jsx2("p", { className: styles2.title, children: cert.url ? /* @__PURE__ */ jsx2(
77
195
  "a",
@@ -85,13 +203,14 @@ function Certifications({ certifications }) {
85
203
  ) : cert.title }),
86
204
  /* @__PURE__ */ jsx2("p", { className: styles2.issuer, children: cert.issuingOrganization }),
87
205
  /* @__PURE__ */ jsxs2("p", { className: styles2.range, children: [
88
- /* @__PURE__ */ jsx2("time", { dateTime: cert.issueDate, children: cert.issueDate }),
89
- cert.expirationDate === null ? (
90
- // TODO(i18n-phase-2): Localize the 'No expiration' label via the locale resolver.
91
- /* @__PURE__ */ jsx2("span", { className: styles2.tag, children: " \xB7 No expiration" })
92
- ) : cert.expirationDate !== void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
206
+ /* @__PURE__ */ jsx2("time", { dateTime: cert.issueDate, children: formatYearMonth(cert.issueDate, locale) }),
207
+ cert.expirationDate === null ? /* @__PURE__ */ jsxs2("span", { className: styles2.tag, children: [
208
+ " ",
209
+ "\xB7 ",
210
+ getUILabel("certification.noExpiration", locale)
211
+ ] }) : cert.expirationDate !== void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
93
212
  " \u2013 ",
94
- /* @__PURE__ */ jsx2("time", { dateTime: cert.expirationDate, children: cert.expirationDate })
213
+ /* @__PURE__ */ jsx2("time", { dateTime: cert.expirationDate, children: formatYearMonth(cert.expirationDate, locale) })
95
214
  ] }) : null
96
215
  ] })
97
216
  ] }, cert.id)) })
@@ -101,11 +220,14 @@ function Certifications({ certifications }) {
101
220
  // src/components/ContactInfo.tsx
102
221
  import styles3 from "./ContactInfo.module-7SO24KHC.module.css";
103
222
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
104
- function ContactInfo({ contact }) {
223
+ function ContactInfo({
224
+ contact,
225
+ locale = "en"
226
+ }) {
105
227
  const showEmail = contact.showEmail === true && contact.email !== void 0;
106
228
  if (!showEmail && contact.formUrl === void 0) return null;
107
229
  return /* @__PURE__ */ jsxs3("section", { className: styles3.section, "aria-labelledby": "takuhon-contact-heading", children: [
108
- /* @__PURE__ */ jsx3("h2", { id: "takuhon-contact-heading", className: styles3.heading, children: "Contact" }),
230
+ /* @__PURE__ */ jsx3("h2", { id: "takuhon-contact-heading", className: styles3.heading, children: getUILabel("section.contact", locale) }),
109
231
  /* @__PURE__ */ jsxs3("ul", { className: styles3.list, children: [
110
232
  showEmail && contact.email !== void 0 ? /* @__PURE__ */ jsx3("li", { className: styles3.item, children: /* @__PURE__ */ jsx3("a", { className: styles3.link, href: `mailto:${contact.email}`, children: contact.email }) }) : null,
111
233
  contact.formUrl !== void 0 ? /* @__PURE__ */ jsx3("li", { className: styles3.item, children: /* @__PURE__ */ jsx3(
@@ -115,7 +237,7 @@ function ContactInfo({ contact }) {
115
237
  href: contact.formUrl,
116
238
  target: "_blank",
117
239
  rel: "noopener noreferrer",
118
- children: "Contact form"
240
+ children: getUILabel("contact.formLink", locale)
119
241
  }
120
242
  ) }) : null
121
243
  ] })
@@ -133,11 +255,11 @@ function sortCourses(entries) {
133
255
  return (b.completionDate ?? "").localeCompare(a.completionDate ?? "");
134
256
  });
135
257
  }
136
- function Courses({ courses }) {
258
+ function Courses({ courses, locale = "en" }) {
137
259
  if (courses.length === 0) return null;
138
260
  const ordered = sortCourses(courses);
139
261
  return /* @__PURE__ */ jsxs4("section", { className: styles4.section, "aria-labelledby": "takuhon-courses-heading", children: [
140
- /* @__PURE__ */ jsx4("h2", { id: "takuhon-courses-heading", className: styles4.heading, children: "Courses" }),
262
+ /* @__PURE__ */ jsx4("h2", { id: "takuhon-courses-heading", className: styles4.heading, children: getUILabel("section.courses", locale) }),
141
263
  /* @__PURE__ */ jsx4("ul", { className: styles4.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs4("li", { className: styles4.item, children: [
142
264
  /* @__PURE__ */ jsx4("p", { className: styles4.title, children: entry.certificateUrl ? /* @__PURE__ */ jsx4(
143
265
  "a",
@@ -151,7 +273,7 @@ function Courses({ courses }) {
151
273
  ) : entry.title }),
152
274
  entry.provider ? /* @__PURE__ */ jsx4("p", { className: styles4.provider, children: entry.provider }) : null,
153
275
  entry.courseNumber ? /* @__PURE__ */ jsx4("p", { className: styles4.courseNumber, children: entry.courseNumber }) : null,
154
- entry.completionDate ? /* @__PURE__ */ jsx4("p", { className: styles4.date, children: /* @__PURE__ */ jsx4("time", { dateTime: entry.completionDate, children: entry.completionDate }) }) : null,
276
+ entry.completionDate ? /* @__PURE__ */ jsx4("p", { className: styles4.date, children: /* @__PURE__ */ jsx4("time", { dateTime: entry.completionDate, children: formatYearMonth(entry.completionDate, locale) }) }) : null,
155
277
  entry.description ? /* @__PURE__ */ jsx4("p", { className: styles4.description, children: entry.description }) : null
156
278
  ] }, entry.id)) })
157
279
  ] });
@@ -177,11 +299,14 @@ function composeStudyLine(entry) {
177
299
  }
178
300
  return entry.degree ?? entry.fieldOfStudy;
179
301
  }
180
- function EducationTimeline({ education }) {
302
+ function EducationTimeline({
303
+ education,
304
+ locale = "en"
305
+ }) {
181
306
  if (education.length === 0) return null;
182
307
  const ordered = sortEducation(education);
183
308
  return /* @__PURE__ */ jsxs5("section", { className: styles5.section, "aria-labelledby": "takuhon-education-heading", children: [
184
- /* @__PURE__ */ jsx5("h2", { id: "takuhon-education-heading", className: styles5.heading, children: "Education" }),
309
+ /* @__PURE__ */ jsx5("h2", { id: "takuhon-education-heading", className: styles5.heading, children: getUILabel("section.education", locale) }),
185
310
  /* @__PURE__ */ jsx5("ol", { className: styles5.list, children: ordered.map((entry) => {
186
311
  const study = composeStudyLine(entry);
187
312
  return /* @__PURE__ */ jsxs5("li", { className: styles5.item, children: [
@@ -199,12 +324,9 @@ function EducationTimeline({ education }) {
199
324
  ) : entry.institution }),
200
325
  study ? /* @__PURE__ */ jsx5("p", { className: styles5.study, children: study }) : null,
201
326
  /* @__PURE__ */ jsxs5("p", { className: styles5.range, children: [
202
- /* @__PURE__ */ jsx5("time", { dateTime: entry.startDate, children: entry.startDate }),
327
+ /* @__PURE__ */ jsx5("time", { dateTime: entry.startDate, children: formatYearMonth(entry.startDate, locale) }),
203
328
  " \u2013 ",
204
- isOngoing2(entry) ? (
205
- // TODO(i18n-phase-2): Localize the 'Present' label via the locale resolver.
206
- "Present"
207
- ) : /* @__PURE__ */ jsx5("time", { dateTime: entry.endDate, children: entry.endDate })
329
+ isOngoing2(entry) ? getUILabel("timeline.present", locale) : /* @__PURE__ */ jsx5("time", { dateTime: entry.endDate, children: formatYearMonth(entry.endDate, locale) })
208
330
  ] }),
209
331
  entry.grade ? /* @__PURE__ */ jsx5("p", { className: styles5.grade, children: entry.grade }) : null,
210
332
  entry.description ? /* @__PURE__ */ jsx5("p", { className: styles5.description, children: entry.description }) : null
@@ -245,11 +367,11 @@ function sortHonors(honors) {
245
367
  return b.date.localeCompare(a.date);
246
368
  });
247
369
  }
248
- function HonorsList({ honors }) {
370
+ function HonorsList({ honors, locale = "en" }) {
249
371
  if (honors.length === 0) return null;
250
372
  const ordered = sortHonors(honors);
251
373
  return /* @__PURE__ */ jsxs7("section", { className: styles7.section, "aria-labelledby": "takuhon-honors-heading", children: [
252
- /* @__PURE__ */ jsx7("h2", { id: "takuhon-honors-heading", className: styles7.heading, children: "Honors & Awards" }),
374
+ /* @__PURE__ */ jsx7("h2", { id: "takuhon-honors-heading", className: styles7.heading, children: getUILabel("section.honors", locale) }),
253
375
  /* @__PURE__ */ jsx7("ul", { className: styles7.list, children: ordered.map((honor) => /* @__PURE__ */ jsxs7("li", { className: styles7.item, children: [
254
376
  /* @__PURE__ */ jsx7("p", { className: styles7.title, children: honor.url ? /* @__PURE__ */ jsx7(
255
377
  "a",
@@ -264,7 +386,7 @@ function HonorsList({ honors }) {
264
386
  /* @__PURE__ */ jsxs7("p", { className: styles7.meta, children: [
265
387
  honor.issuer,
266
388
  " \xB7 ",
267
- /* @__PURE__ */ jsx7("time", { dateTime: honor.date, children: honor.date })
389
+ /* @__PURE__ */ jsx7("time", { dateTime: honor.date, children: formatYearMonth(honor.date, locale) })
268
390
  ] }),
269
391
  honor.description ? /* @__PURE__ */ jsx7("p", { className: styles7.description, children: honor.description }) : null
270
392
  ] }, honor.id)) })
@@ -274,13 +396,6 @@ function HonorsList({ honors }) {
274
396
  // src/components/Languages.tsx
275
397
  import styles8 from "./Languages.module-X6RQNFRY.module.css";
276
398
  import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
277
- var PROFICIENCY_LABEL = {
278
- native: "Native",
279
- fluent: "Fluent",
280
- professional: "Professional working",
281
- intermediate: "Intermediate",
282
- basic: "Basic"
283
- };
284
399
  function sortLanguages(languages) {
285
400
  return [...languages].sort((a, b) => {
286
401
  const aOrder = a.order ?? Number.POSITIVE_INFINITY;
@@ -288,14 +403,14 @@ function sortLanguages(languages) {
288
403
  return aOrder - bOrder;
289
404
  });
290
405
  }
291
- function Languages({ languages }) {
406
+ function Languages({ languages, locale = "en" }) {
292
407
  if (languages.length === 0) return null;
293
408
  const ordered = sortLanguages(languages);
294
409
  return /* @__PURE__ */ jsxs8("section", { className: styles8.section, "aria-labelledby": "takuhon-languages-heading", children: [
295
- /* @__PURE__ */ jsx8("h2", { id: "takuhon-languages-heading", className: styles8.heading, children: "Languages" }),
410
+ /* @__PURE__ */ jsx8("h2", { id: "takuhon-languages-heading", className: styles8.heading, children: getUILabel("section.languages", locale) }),
296
411
  /* @__PURE__ */ jsx8("ul", { className: styles8.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs8("li", { className: styles8.item, children: [
297
412
  /* @__PURE__ */ jsx8("span", { className: styles8.name, lang: entry.language, children: entry.displayName ?? entry.language }),
298
- /* @__PURE__ */ jsx8("span", { className: styles8.proficiency, children: PROFICIENCY_LABEL[entry.proficiency] })
413
+ /* @__PURE__ */ jsx8("span", { className: styles8.proficiency, children: getUILabel(`proficiency.${entry.proficiency}`, locale) })
299
414
  ] }, entry.id)) })
300
415
  ] });
301
416
  }
@@ -318,10 +433,10 @@ function formatLinkLabel(link) {
318
433
  if (link.type === "custom") return link.id;
319
434
  return link.type;
320
435
  }
321
- function LinksList({ links }) {
436
+ function LinksList({ links, locale = "en" }) {
322
437
  if (links.length === 0) return null;
323
438
  const ordered = sortLinks(links);
324
- return /* @__PURE__ */ jsx9("nav", { "aria-label": "Profile links", className: styles9.nav, children: /* @__PURE__ */ jsx9("ul", { className: styles9.list, children: ordered.map((link) => /* @__PURE__ */ jsx9("li", { className: styles9.item, children: /* @__PURE__ */ jsxs9(
439
+ return /* @__PURE__ */ jsx9("nav", { "aria-label": getUILabel("a11y.profileLinks", locale), className: styles9.nav, children: /* @__PURE__ */ jsx9("ul", { className: styles9.list, children: ordered.map((link) => /* @__PURE__ */ jsx9("li", { className: styles9.item, children: /* @__PURE__ */ jsxs9(
325
440
  "a",
326
441
  {
327
442
  className: styles9.link,
@@ -351,11 +466,14 @@ function sortMemberships(entries) {
351
466
  function isOngoing3(entry) {
352
467
  return entry.isCurrent === true || entry.endDate === null || entry.endDate === void 0;
353
468
  }
354
- function Memberships({ memberships }) {
469
+ function Memberships({
470
+ memberships,
471
+ locale = "en"
472
+ }) {
355
473
  if (memberships.length === 0) return null;
356
474
  const ordered = sortMemberships(memberships);
357
475
  return /* @__PURE__ */ jsxs10("section", { className: styles10.section, "aria-labelledby": "takuhon-memberships-heading", children: [
358
- /* @__PURE__ */ jsx10("h2", { id: "takuhon-memberships-heading", className: styles10.heading, children: "Memberships" }),
476
+ /* @__PURE__ */ jsx10("h2", { id: "takuhon-memberships-heading", className: styles10.heading, children: getUILabel("section.memberships", locale) }),
359
477
  /* @__PURE__ */ jsx10("ol", { className: styles10.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs10("li", { className: styles10.item, children: [
360
478
  /* @__PURE__ */ jsx10("div", { className: styles10.timelineMarker, "aria-hidden": "true" }),
361
479
  /* @__PURE__ */ jsxs10("div", { className: styles10.content, children: [
@@ -371,12 +489,9 @@ function Memberships({ memberships }) {
371
489
  ) : entry.organization }),
372
490
  entry.role ? /* @__PURE__ */ jsx10("p", { className: styles10.role, children: entry.role }) : null,
373
491
  /* @__PURE__ */ jsxs10("p", { className: styles10.range, children: [
374
- /* @__PURE__ */ jsx10("time", { dateTime: entry.startDate, children: entry.startDate }),
492
+ /* @__PURE__ */ jsx10("time", { dateTime: entry.startDate, children: formatYearMonth(entry.startDate, locale) }),
375
493
  " \u2013 ",
376
- isOngoing3(entry) ? (
377
- // TODO(i18n-phase-2): Localize the 'Present' label via the locale resolver.
378
- "Present"
379
- ) : /* @__PURE__ */ jsx10("time", { dateTime: entry.endDate, children: entry.endDate })
494
+ isOngoing3(entry) ? getUILabel("timeline.present", locale) : /* @__PURE__ */ jsx10("time", { dateTime: entry.endDate, children: formatYearMonth(entry.endDate, locale) })
380
495
  ] }),
381
496
  entry.description ? /* @__PURE__ */ jsx10("p", { className: styles10.description, children: entry.description }) : null
382
497
  ] })
@@ -387,12 +502,6 @@ function Memberships({ memberships }) {
387
502
  // src/components/Patents.tsx
388
503
  import styles11 from "./Patents.module-L3GWPB3V.module.css";
389
504
  import { Fragment as Fragment3, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
390
- var STATUS_LABEL = {
391
- pending: "Pending",
392
- issued: "Issued",
393
- expired: "Expired",
394
- abandoned: "Abandoned"
395
- };
396
505
  function sortPatents(entries) {
397
506
  return [...entries].sort((a, b) => {
398
507
  const aOrder = a.order ?? Number.POSITIVE_INFINITY;
@@ -403,11 +512,11 @@ function sortPatents(entries) {
403
512
  return bDate.localeCompare(aDate);
404
513
  });
405
514
  }
406
- function Patents({ patents }) {
515
+ function Patents({ patents, locale = "en" }) {
407
516
  if (patents.length === 0) return null;
408
517
  const ordered = sortPatents(patents);
409
518
  return /* @__PURE__ */ jsxs11("section", { className: styles11.section, "aria-labelledby": "takuhon-patents-heading", children: [
410
- /* @__PURE__ */ jsx11("h2", { id: "takuhon-patents-heading", className: styles11.heading, children: "Patents" }),
519
+ /* @__PURE__ */ jsx11("h2", { id: "takuhon-patents-heading", className: styles11.heading, children: getUILabel("section.patents", locale) }),
411
520
  /* @__PURE__ */ jsx11("ul", { className: styles11.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs11("li", { className: styles11.item, children: [
412
521
  /* @__PURE__ */ jsxs11("p", { className: styles11.title, children: [
413
522
  entry.url ? /* @__PURE__ */ jsx11(
@@ -421,24 +530,24 @@ function Patents({ patents }) {
421
530
  }
422
531
  ) : entry.title,
423
532
  /* @__PURE__ */ jsxs11("span", { className: styles11.statusBadge, "data-status": entry.status, children: [
424
- /* @__PURE__ */ jsx11("span", { className: styles11.srOnly, children: "Status: " }),
425
- STATUS_LABEL[entry.status]
533
+ /* @__PURE__ */ jsx11("span", { className: styles11.srOnly, children: getUILabel("a11y.statusPrefix", locale) }),
534
+ getUILabel(`patentStatus.${entry.status}`, locale)
426
535
  ] })
427
536
  ] }),
428
537
  /* @__PURE__ */ jsx11("p", { className: styles11.patentNumber, children: entry.patentNumber }),
429
538
  entry.office ? /* @__PURE__ */ jsx11("p", { className: styles11.office, children: entry.office }) : null,
430
539
  entry.filingDate !== void 0 || entry.grantDate !== void 0 ? /* @__PURE__ */ jsxs11("p", { className: styles11.dates, children: [
431
540
  entry.filingDate ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
432
- "Filed ",
433
- /* @__PURE__ */ jsx11("time", { dateTime: entry.filingDate, children: entry.filingDate })
541
+ `${getUILabel("patent.filed", locale)} `,
542
+ /* @__PURE__ */ jsx11("time", { dateTime: entry.filingDate, children: formatYearMonth(entry.filingDate, locale) })
434
543
  ] }) : null,
435
544
  entry.filingDate && entry.grantDate ? " \xB7 " : null,
436
545
  entry.grantDate ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
437
- "Granted ",
438
- /* @__PURE__ */ jsx11("time", { dateTime: entry.grantDate, children: entry.grantDate })
546
+ `${getUILabel("patent.granted", locale)} `,
547
+ /* @__PURE__ */ jsx11("time", { dateTime: entry.grantDate, children: formatYearMonth(entry.grantDate, locale) })
439
548
  ] }) : null
440
549
  ] }) : null,
441
- entry.coInventors && entry.coInventors.length > 0 ? /* @__PURE__ */ jsx11(Fragment3, { children: /* @__PURE__ */ jsx11("p", { className: styles11.coInventors, children: `with ${entry.coInventors.join(", ")}` }) }) : null,
550
+ entry.coInventors && entry.coInventors.length > 0 ? /* @__PURE__ */ jsx11("p", { className: styles11.coInventors, children: `${getUILabel("patent.coInventorsPrefix", locale)}${entry.coInventors.join(", ")}` }) : null,
442
551
  entry.description ? /* @__PURE__ */ jsx11("p", { className: styles11.description, children: entry.description }) : null
443
552
  ] }, entry.id)) })
444
553
  ] });
@@ -482,11 +591,14 @@ function sortProjects(projects) {
482
591
  return aOrder - bOrder;
483
592
  });
484
593
  }
485
- function ProjectsList({ projects }) {
594
+ function ProjectsList({
595
+ projects,
596
+ locale = "en"
597
+ }) {
486
598
  if (projects.length === 0) return null;
487
599
  const ordered = sortProjects(projects);
488
600
  return /* @__PURE__ */ jsxs13("section", { className: styles13.section, "aria-labelledby": "takuhon-projects-heading", children: [
489
- /* @__PURE__ */ jsx13("h2", { id: "takuhon-projects-heading", className: styles13.heading, children: "Projects" }),
601
+ /* @__PURE__ */ jsx13("h2", { id: "takuhon-projects-heading", className: styles13.heading, children: getUILabel("section.projects", locale) }),
490
602
  /* @__PURE__ */ jsx13("ul", { className: styles13.list, children: ordered.map((project) => /* @__PURE__ */ jsxs13(
491
603
  "li",
492
604
  {
@@ -504,15 +616,12 @@ function ProjectsList({ projects }) {
504
616
  }
505
617
  ) : project.title }),
506
618
  project.startDate !== void 0 ? /* @__PURE__ */ jsxs13("p", { className: styles13.range, children: [
507
- /* @__PURE__ */ jsx13("time", { dateTime: project.startDate, children: project.startDate }),
619
+ /* @__PURE__ */ jsx13("time", { dateTime: project.startDate, children: formatYearMonth(project.startDate, locale) }),
508
620
  " \u2013 ",
509
- project.endDate ? /* @__PURE__ */ jsx13("time", { dateTime: project.endDate, children: project.endDate }) : (
510
- // TODO(i18n-phase-2): Localize the 'Present' label via the locale resolver.
511
- "Present"
512
- )
621
+ project.endDate ? /* @__PURE__ */ jsx13("time", { dateTime: project.endDate, children: formatYearMonth(project.endDate, locale) }) : getUILabel("timeline.present", locale)
513
622
  ] }) : null,
514
623
  project.description ? /* @__PURE__ */ jsx13("p", { className: styles13.description, children: project.description }) : null,
515
- project.tags && project.tags.length > 0 ? /* @__PURE__ */ jsx13("ul", { className: styles13.tags, "aria-label": "Tags", children: project.tags.map((tag) => /* @__PURE__ */ jsx13("li", { className: styles13.tag, children: tag }, tag)) }) : null
624
+ project.tags && project.tags.length > 0 ? /* @__PURE__ */ jsx13("ul", { className: styles13.tags, "aria-label": getUILabel("a11y.tags", locale), children: project.tags.map((tag) => /* @__PURE__ */ jsx13("li", { className: styles13.tag, children: tag }, tag)) }) : null
516
625
  ]
517
626
  },
518
627
  project.id
@@ -522,7 +631,7 @@ function ProjectsList({ projects }) {
522
631
 
523
632
  // src/components/Publications.tsx
524
633
  import styles14 from "./Publications.module-INRTHJMO.module.css";
525
- import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
634
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
526
635
  function sortPublications(entries) {
527
636
  return [...entries].sort((a, b) => {
528
637
  const aOrder = a.order ?? Number.POSITIVE_INFINITY;
@@ -534,11 +643,14 @@ function sortPublications(entries) {
534
643
  function normalizeDoi(doi) {
535
644
  return doi.replace(/^https?:\/\/(?:dx\.)?doi\.org\//i, "");
536
645
  }
537
- function Publications({ publications }) {
646
+ function Publications({
647
+ publications,
648
+ locale = "en"
649
+ }) {
538
650
  if (publications.length === 0) return null;
539
651
  const ordered = sortPublications(publications);
540
652
  return /* @__PURE__ */ jsxs14("section", { className: styles14.section, "aria-labelledby": "takuhon-publications-heading", children: [
541
- /* @__PURE__ */ jsx14("h2", { id: "takuhon-publications-heading", className: styles14.heading, children: "Publications" }),
653
+ /* @__PURE__ */ jsx14("h2", { id: "takuhon-publications-heading", className: styles14.heading, children: getUILabel("section.publications", locale) }),
542
654
  /* @__PURE__ */ jsx14("ul", { className: styles14.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs14("li", { className: styles14.item, children: [
543
655
  /* @__PURE__ */ jsx14("p", { className: styles14.title, children: entry.url ? /* @__PURE__ */ jsx14(
544
656
  "a",
@@ -551,8 +663,8 @@ function Publications({ publications }) {
551
663
  }
552
664
  ) : entry.title }),
553
665
  entry.publisher ? /* @__PURE__ */ jsx14("p", { className: styles14.publisher, children: entry.publisher }) : null,
554
- /* @__PURE__ */ jsx14("p", { className: styles14.date, children: /* @__PURE__ */ jsx14("time", { dateTime: entry.date, children: entry.date }) }),
555
- entry.coAuthors && entry.coAuthors.length > 0 ? /* @__PURE__ */ jsx14(Fragment4, { children: /* @__PURE__ */ jsx14("p", { className: styles14.coAuthors, children: `with ${entry.coAuthors.join(", ")}` }) }) : null,
666
+ /* @__PURE__ */ jsx14("p", { className: styles14.date, children: /* @__PURE__ */ jsx14("time", { dateTime: entry.date, children: formatYearMonth(entry.date, locale) }) }),
667
+ entry.coAuthors && entry.coAuthors.length > 0 ? /* @__PURE__ */ jsx14("p", { className: styles14.coAuthors, children: `${getUILabel("publication.coAuthorsPrefix", locale)}${entry.coAuthors.join(", ")}` }) : null,
556
668
  entry.doi ? (() => {
557
669
  const bare = normalizeDoi(entry.doi);
558
670
  return /* @__PURE__ */ jsx14("p", { className: styles14.doi, children: /* @__PURE__ */ jsx14(
@@ -583,12 +695,13 @@ function sortRecommendations(entries) {
583
695
  });
584
696
  }
585
697
  function Recommendations({
586
- recommendations
698
+ recommendations,
699
+ locale = "en"
587
700
  }) {
588
701
  if (recommendations.length === 0) return null;
589
702
  const ordered = sortRecommendations(recommendations);
590
703
  return /* @__PURE__ */ jsxs15("section", { className: styles15.section, "aria-labelledby": "takuhon-recommendations-heading", children: [
591
- /* @__PURE__ */ jsx15("h2", { id: "takuhon-recommendations-heading", className: styles15.heading, children: "Recommendations" }),
704
+ /* @__PURE__ */ jsx15("h2", { id: "takuhon-recommendations-heading", className: styles15.heading, children: getUILabel("section.recommendations", locale) }),
592
705
  /* @__PURE__ */ jsx15("ul", { className: styles15.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs15("li", { className: styles15.item, children: [
593
706
  /* @__PURE__ */ jsx15("blockquote", { className: styles15.body, children: /* @__PURE__ */ jsx15("p", { className: styles15.quote, children: entry.body }) }),
594
707
  /* @__PURE__ */ jsxs15("p", { className: styles15.attribution, children: [
@@ -605,7 +718,7 @@ function Recommendations({
605
718
  entry.author.headline ? /* @__PURE__ */ jsx15("span", { className: styles15.headline, children: entry.author.headline }) : null
606
719
  ] }),
607
720
  entry.relationship ? /* @__PURE__ */ jsx15("p", { className: styles15.meta, children: entry.relationship }) : null,
608
- entry.date ? /* @__PURE__ */ jsx15("p", { className: styles15.meta, children: /* @__PURE__ */ jsx15("time", { dateTime: entry.date, children: entry.date }) }) : null
721
+ entry.date ? /* @__PURE__ */ jsx15("p", { className: styles15.meta, children: /* @__PURE__ */ jsx15("time", { dateTime: entry.date, children: formatYearMonth(entry.date, locale) }) }) : null
609
722
  ] }, entry.id)) })
610
723
  ] });
611
724
  }
@@ -613,6 +726,7 @@ function Recommendations({
613
726
  // src/components/SkillsList.tsx
614
727
  import styles16 from "./SkillsList.module-XIAWE55H.module.css";
615
728
  import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
729
+ var UNCATEGORIZED = "other";
616
730
  function groupSkills(skills) {
617
731
  const sorted = [...skills].sort((a, b) => {
618
732
  const aOrder = a.order ?? Number.POSITIVE_INFINITY;
@@ -621,7 +735,7 @@ function groupSkills(skills) {
621
735
  });
622
736
  const groups = /* @__PURE__ */ new Map();
623
737
  for (const skill of sorted) {
624
- const key = skill.category ?? "other";
738
+ const key = skill.category ?? UNCATEGORIZED;
625
739
  const bucket = groups.get(key);
626
740
  if (bucket) {
627
741
  bucket.push(skill);
@@ -631,15 +745,25 @@ function groupSkills(skills) {
631
745
  }
632
746
  return [...groups.entries()].map(([category, items]) => ({ category, skills: items }));
633
747
  }
634
- function SkillsList({ skills }) {
748
+ function SkillsList({ skills, locale = "en" }) {
635
749
  if (skills.length === 0) return null;
636
750
  const groups = groupSkills(skills);
637
751
  return /* @__PURE__ */ jsxs16("section", { className: styles16.section, "aria-labelledby": "takuhon-skills-heading", children: [
638
- /* @__PURE__ */ jsx16("h2", { id: "takuhon-skills-heading", className: styles16.heading, children: "Skills" }),
639
- /* @__PURE__ */ jsx16("div", { className: styles16.groups, children: groups.map((group) => /* @__PURE__ */ jsxs16("div", { className: styles16.group, children: [
640
- /* @__PURE__ */ jsx16("h3", { className: styles16.category, children: group.category }),
641
- /* @__PURE__ */ jsx16("ul", { className: styles16.list, "aria-label": `${group.category} skills`, children: group.skills.map((skill) => /* @__PURE__ */ jsx16("li", { className: styles16.item, children: skill.label }, skill.id)) })
642
- ] }, group.category)) })
752
+ /* @__PURE__ */ jsx16("h2", { id: "takuhon-skills-heading", className: styles16.heading, children: getUILabel("section.skills", locale) }),
753
+ /* @__PURE__ */ jsx16("div", { className: styles16.groups, children: groups.map((group) => {
754
+ const categoryLabel = group.category === UNCATEGORIZED ? getUILabel("skills.uncategorized", locale) : group.category;
755
+ return /* @__PURE__ */ jsxs16("div", { className: styles16.group, children: [
756
+ /* @__PURE__ */ jsx16("h3", { className: styles16.category, children: categoryLabel }),
757
+ /* @__PURE__ */ jsx16(
758
+ "ul",
759
+ {
760
+ className: styles16.list,
761
+ "aria-label": `${categoryLabel} ${getUILabel("a11y.skillsSuffix", locale)}`,
762
+ children: group.skills.map((skill) => /* @__PURE__ */ jsx16("li", { className: styles16.item, children: skill.label }, skill.id))
763
+ }
764
+ )
765
+ ] }, group.category);
766
+ }) })
643
767
  ] });
644
768
  }
645
769
 
@@ -657,11 +781,14 @@ function sortTestScores(entries) {
657
781
  return b.date.localeCompare(a.date);
658
782
  });
659
783
  }
660
- function TestScores({ testScores }) {
784
+ function TestScores({
785
+ testScores,
786
+ locale = "en"
787
+ }) {
661
788
  if (testScores.length === 0) return null;
662
789
  const ordered = sortTestScores(testScores);
663
790
  return /* @__PURE__ */ jsxs17("section", { className: styles17.section, "aria-labelledby": "takuhon-test-scores-heading", children: [
664
- /* @__PURE__ */ jsx17("h2", { id: "takuhon-test-scores-heading", className: styles17.heading, children: "Test Scores" }),
791
+ /* @__PURE__ */ jsx17("h2", { id: "takuhon-test-scores-heading", className: styles17.heading, children: getUILabel("section.testScores", locale) }),
665
792
  /* @__PURE__ */ jsx17("ul", { className: styles17.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs17("li", { className: styles17.item, children: [
666
793
  /* @__PURE__ */ jsx17("p", { className: styles17.title, children: entry.url ? /* @__PURE__ */ jsx17(
667
794
  "a",
@@ -676,7 +803,7 @@ function TestScores({ testScores }) {
676
803
  /* @__PURE__ */ jsxs17("p", { className: styles17.meta, children: [
677
804
  /* @__PURE__ */ jsx17("span", { className: styles17.score, children: entry.score }),
678
805
  " \xB7 ",
679
- /* @__PURE__ */ jsx17("time", { dateTime: entry.date, children: entry.date })
806
+ /* @__PURE__ */ jsx17("time", { dateTime: entry.date, children: formatYearMonth(entry.date, locale) })
680
807
  ] }),
681
808
  entry.description ? /* @__PURE__ */ jsx17("p", { className: styles17.description, children: entry.description }) : null
682
809
  ] }, entry.id)) })
@@ -697,11 +824,14 @@ function sortVolunteering(entries) {
697
824
  function isOngoing4(entry) {
698
825
  return entry.isCurrent === true || entry.endDate === null || entry.endDate === void 0;
699
826
  }
700
- function Volunteering({ volunteering }) {
827
+ function Volunteering({
828
+ volunteering,
829
+ locale = "en"
830
+ }) {
701
831
  if (volunteering.length === 0) return null;
702
832
  const ordered = sortVolunteering(volunteering);
703
833
  return /* @__PURE__ */ jsxs18("section", { className: styles18.section, "aria-labelledby": "takuhon-volunteering-heading", children: [
704
- /* @__PURE__ */ jsx18("h2", { id: "takuhon-volunteering-heading", className: styles18.heading, children: "Volunteering" }),
834
+ /* @__PURE__ */ jsx18("h2", { id: "takuhon-volunteering-heading", className: styles18.heading, children: getUILabel("section.volunteering", locale) }),
705
835
  /* @__PURE__ */ jsx18("ol", { className: styles18.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs18("li", { className: styles18.item, children: [
706
836
  /* @__PURE__ */ jsx18("div", { className: styles18.timelineMarker, "aria-hidden": "true" }),
707
837
  /* @__PURE__ */ jsxs18("div", { className: styles18.content, children: [
@@ -718,17 +848,14 @@ function Volunteering({ volunteering }) {
718
848
  /* @__PURE__ */ jsxs18("p", { className: styles18.role, children: [
719
849
  entry.role,
720
850
  entry.cause ? /* @__PURE__ */ jsxs18("span", { className: styles18.cause, children: [
721
- /* @__PURE__ */ jsx18("span", { className: styles18.srOnly, children: "Cause: " }),
851
+ /* @__PURE__ */ jsx18("span", { className: styles18.srOnly, children: getUILabel("a11y.causePrefix", locale) }),
722
852
  entry.cause
723
853
  ] }) : null
724
854
  ] }),
725
855
  /* @__PURE__ */ jsxs18("p", { className: styles18.range, children: [
726
- /* @__PURE__ */ jsx18("time", { dateTime: entry.startDate, children: entry.startDate }),
856
+ /* @__PURE__ */ jsx18("time", { dateTime: entry.startDate, children: formatYearMonth(entry.startDate, locale) }),
727
857
  " \u2013 ",
728
- isOngoing4(entry) ? (
729
- // TODO(i18n-phase-2): Localize the 'Present' label via the locale resolver.
730
- "Present"
731
- ) : /* @__PURE__ */ jsx18("time", { dateTime: entry.endDate, children: entry.endDate })
858
+ isOngoing4(entry) ? getUILabel("timeline.present", locale) : /* @__PURE__ */ jsx18("time", { dateTime: entry.endDate, children: formatYearMonth(entry.endDate, locale) })
732
859
  ] }),
733
860
  entry.description ? /* @__PURE__ */ jsx18("p", { className: styles18.description, children: entry.description }) : null
734
861
  ] })
@@ -740,24 +867,25 @@ function Volunteering({ volunteering }) {
740
867
  import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
741
868
  function TakuhonProfile({ data }) {
742
869
  const showFooter = data.settings.showPoweredBy !== false;
870
+ const locale = data.resolvedLocale;
743
871
  return /* @__PURE__ */ jsxs19("article", { className: styles19.root, children: [
744
872
  /* @__PURE__ */ jsx19(ProfileHeader, { profile: data.profile }),
745
- /* @__PURE__ */ jsx19(LinksList, { links: data.links }),
746
- /* @__PURE__ */ jsx19(EducationTimeline, { education: data.education }),
747
- /* @__PURE__ */ jsx19(Courses, { courses: data.courses }),
748
- /* @__PURE__ */ jsx19(CareerTimeline, { careers: data.careers }),
749
- /* @__PURE__ */ jsx19(Memberships, { memberships: data.memberships }),
750
- /* @__PURE__ */ jsx19(Certifications, { certifications: data.certifications }),
751
- /* @__PURE__ */ jsx19(Patents, { patents: data.patents }),
752
- /* @__PURE__ */ jsx19(ProjectsList, { projects: data.projects }),
753
- /* @__PURE__ */ jsx19(Publications, { publications: data.publications }),
754
- /* @__PURE__ */ jsx19(HonorsList, { honors: data.honors }),
755
- /* @__PURE__ */ jsx19(Recommendations, { recommendations: data.recommendations }),
756
- /* @__PURE__ */ jsx19(Volunteering, { volunteering: data.volunteering }),
757
- /* @__PURE__ */ jsx19(SkillsList, { skills: data.skills }),
758
- /* @__PURE__ */ jsx19(Languages, { languages: data.languages }),
759
- /* @__PURE__ */ jsx19(TestScores, { testScores: data.testScores }),
760
- /* @__PURE__ */ jsx19(ContactInfo, { contact: data.contact }),
873
+ /* @__PURE__ */ jsx19(LinksList, { links: data.links, locale }),
874
+ /* @__PURE__ */ jsx19(EducationTimeline, { education: data.education, locale }),
875
+ /* @__PURE__ */ jsx19(Courses, { courses: data.courses, locale }),
876
+ /* @__PURE__ */ jsx19(CareerTimeline, { careers: data.careers, locale }),
877
+ /* @__PURE__ */ jsx19(Memberships, { memberships: data.memberships, locale }),
878
+ /* @__PURE__ */ jsx19(Certifications, { certifications: data.certifications, locale }),
879
+ /* @__PURE__ */ jsx19(Patents, { patents: data.patents, locale }),
880
+ /* @__PURE__ */ jsx19(ProjectsList, { projects: data.projects, locale }),
881
+ /* @__PURE__ */ jsx19(Publications, { publications: data.publications, locale }),
882
+ /* @__PURE__ */ jsx19(HonorsList, { honors: data.honors, locale }),
883
+ /* @__PURE__ */ jsx19(Recommendations, { recommendations: data.recommendations, locale }),
884
+ /* @__PURE__ */ jsx19(Volunteering, { volunteering: data.volunteering, locale }),
885
+ /* @__PURE__ */ jsx19(SkillsList, { skills: data.skills, locale }),
886
+ /* @__PURE__ */ jsx19(Languages, { languages: data.languages, locale }),
887
+ /* @__PURE__ */ jsx19(TestScores, { testScores: data.testScores, locale }),
888
+ /* @__PURE__ */ jsx19(ContactInfo, { contact: data.contact, locale }),
761
889
  showFooter ? /* @__PURE__ */ jsx19(Footer, {}) : null
762
890
  ] });
763
891
  }
@@ -765,7 +893,6 @@ function TakuhonProfile({ data }) {
765
893
  // src/components/LocaleSwitcher.tsx
766
894
  import styles20 from "./LocaleSwitcher.module-QVLPVGLG.module.css";
767
895
  import { jsx as jsx20 } from "react/jsx-runtime";
768
- var DEFAULT_ARIA_LABEL = "Select language";
769
896
  function LocaleSwitcher({
770
897
  availableLocales,
771
898
  currentLocale,
@@ -773,7 +900,7 @@ function LocaleSwitcher({
773
900
  ariaLabel,
774
901
  formatLocale
775
902
  }) {
776
- const label = ariaLabel ?? DEFAULT_ARIA_LABEL;
903
+ const label = ariaLabel ?? getUILabel("a11y.selectLanguage", currentLocale);
777
904
  const format = formatLocale ?? ((locale) => locale);
778
905
  return /* @__PURE__ */ jsx20("div", { className: styles20.wrapper, children: /* @__PURE__ */ jsx20(
779
906
  "select",
@@ -792,7 +919,7 @@ function LocaleSwitcher({
792
919
  // src/components/TakuhonHead.tsx
793
920
  import { generateJsonLd } from "@takuhon/core";
794
921
  import { useEffect } from "react";
795
- import { Fragment as Fragment5, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
922
+ import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs20 } from "react/jsx-runtime";
796
923
  function primarySubtag(tag) {
797
924
  const dash = tag.indexOf("-");
798
925
  return (dash === -1 ? tag : tag.slice(0, dash)).toLowerCase();
@@ -877,7 +1004,7 @@ function TakuhonHead({ data, siteUrl, pageUrl }) {
877
1004
  script.remove();
878
1005
  };
879
1006
  }, [jsonLdPayload]);
880
- return /* @__PURE__ */ jsxs20(Fragment5, { children: [
1007
+ return /* @__PURE__ */ jsxs20(Fragment4, { children: [
881
1008
  /* @__PURE__ */ jsx21("title", { children: profile.displayName }),
882
1009
  description ? /* @__PURE__ */ jsx21("meta", { name: "description", content: description }) : null,
883
1010
  canonical ? /* @__PURE__ */ jsx21("link", { rel: "canonical", href: canonical }) : null,