feat(i18n): implement localization using LinguiJS

This commit is contained in:
Amruth Pillai
2023-11-10 09:07:47 +01:00
parent 13d91411e3
commit 6ad4358d70
108 changed files with 4631 additions and 798 deletions

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { awardSchema, defaultAward } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const AwardsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Title</FormLabel>
<FormLabel>{t({ message: "Title", context: "Name of the Award" })}</FormLabel>
<FormControl>
<Input {...field} placeholder="3rd Runner Up" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,9 @@ export const AwardsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Awarder</FormLabel>
<FormLabel>{t`Awarder`}</FormLabel>
<FormControl>
<Input {...field} placeholder="TechCrunch Disrupt SF" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +64,15 @@ export const AwardsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Aug 2019" />
<Input
{...field}
placeholder={t({
message: "March 2023",
comment: "The month and year should be uniform across all languages.",
})}
/>
</FormControl>
<FormMessage />
</FormItem>
@ -77,9 +84,9 @@ export const AwardsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://techcrunch.com/events/disrupt-sf-2019" />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -91,7 +98,7 @@ export const AwardsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { certificationSchema, defaultCertification } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const CertificationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t({ message: "Name", context: "Name of the Certification" })}</FormLabel>
<FormControl>
<Input {...field} placeholder="Web Developer Bootcamp" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,9 @@ export const CertificationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Issuer</FormLabel>
<FormLabel>{t`Issuer`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Udemy" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +64,9 @@ export const CertificationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Aug 2019" />
<Input {...field} placeholder={t`March 2023`} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,7 +78,7 @@ export const CertificationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://udemy.com/certificate/UC-..." />
</FormControl>
@ -91,7 +92,7 @@ export const CertificationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { X } from "@phosphor-icons/react";
import { CustomSection, customSectionSchema, defaultCustomSection } from "@reactive-resume/schema";
import {
@ -49,7 +50,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@ -63,7 +64,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Description</FormLabel>
<FormLabel>{t`Description`}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@ -77,7 +78,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@ -91,7 +92,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Location</FormLabel>
<FormLabel>{t`Location`}</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
@ -105,7 +106,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} />
</FormControl>
@ -119,7 +120,7 @@ export const CustomSectionDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}
@ -141,12 +142,12 @@ export const CustomSectionDialog = () => {
render={({ field }) => (
<div className="col-span-2 space-y-3">
<FormItem>
<FormLabel>Keywords</FormLabel>
<FormLabel>{t`Keywords`}</FormLabel>
<FormControl>
<BadgeInput {...field} />
</FormControl>
<FormDescription>
You can add multiple keywords by separating them with a comma.
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
</FormDescription>
<FormMessage />
</FormItem>

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultEducation, educationSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Institution</FormLabel>
<FormLabel>{t`Institution`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Carnegie Mellon University" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,14 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Type of Study</FormLabel>
<FormLabel>
{t({
message: "Type of Study",
comment: "For example, Bachelor's Degree or Master's Degree",
})}
</FormLabel>
<FormControl>
<Input {...field} placeholder="Bachelor's Degree" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +69,14 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Area of Study</FormLabel>
<FormLabel>
{t({
message: "Area of Study",
comment: "For example, Computer Science or Business Administration",
})}
</FormLabel>
<FormControl>
<Input {...field} placeholder="Computer Science" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,7 +88,12 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Score</FormLabel>
<FormLabel>
{t({
message: "Score",
comment: "Score or honors for the degree, for example, CGPA or magna cum laude",
})}
</FormLabel>
<FormControl>
<Input {...field} placeholder="9.2 GPA" />
</FormControl>
@ -91,9 +107,9 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Aug 2006 - Oct 2012" />
<Input {...field} placeholder={t`March 2023 - Present`} />
</FormControl>
<FormMessage />
</FormItem>
@ -105,9 +121,9 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://www.cmu.edu/" />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -119,7 +135,7 @@ export const EducationDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultExperience, experienceSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Company</FormLabel>
<FormLabel>{t`Company`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Alphabet Inc." />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,14 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Position</FormLabel>
<FormLabel>
{t({
message: "Position",
context: "Position held at a company, for example, Software Engineer",
})}
</FormLabel>
<FormControl>
<Input {...field} placeholder="Chief Executive Officer" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +69,9 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Dec 2019 - Present" />
<Input {...field} placeholder={t`March 2023 - Present`} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,9 +83,9 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Location</FormLabel>
<FormLabel>{t`Location`}</FormLabel>
<FormControl>
<Input {...field} placeholder="New York, NY" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -91,9 +97,9 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://www.abc.xyz/" />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -105,7 +111,7 @@ export const ExperienceDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { X } from "@phosphor-icons/react";
import { defaultInterest, interestSchema } from "@reactive-resume/schema";
import {
@ -36,9 +37,9 @@ export const InterestsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Video Games" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -51,12 +52,12 @@ export const InterestsDialog = () => {
render={({ field }) => (
<div className="col-span-2 space-y-3">
<FormItem>
<FormLabel>Keywords</FormLabel>
<FormLabel>{t`Keywords`}</FormLabel>
<FormControl>
<BadgeInput {...field} placeholder="FIFA 23, Call of Duty, etc." />
<BadgeInput {...field} />
</FormControl>
<FormDescription>
You can add multiple keywords by separating them with a comma.
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
</FormDescription>
<FormMessage />
</FormItem>

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultLanguage, languageSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -33,9 +34,9 @@ export const LanguagesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="German" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -47,9 +48,9 @@ export const LanguagesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Fluency</FormLabel>
<FormLabel>{t`Fluency`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Native Speaker" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -61,7 +62,7 @@ export const LanguagesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Fluency (CEFR)</FormLabel>
<FormLabel>{t`Fluency (CEFR)`}</FormLabel>
<FormControl className="py-2">
<div className="flex items-center gap-x-4">
<Slider

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t, Trans } from "@lingui/macro";
import { defaultProfile, profileSchema } from "@reactive-resume/schema";
import {
Avatar,
@ -35,8 +36,9 @@ export const ProfilesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Network</FormLabel>
<FormLabel>{t`Network`}</FormLabel>
<FormControl>
{/* eslint-disable-next-line lingui/no-unlocalized-strings */}
<Input {...field} placeholder="LinkedIn" />
</FormControl>
<FormMessage />
@ -49,9 +51,9 @@ export const ProfilesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Username</FormLabel>
<FormLabel>{t`Username`}</FormLabel>
<FormControl>
<Input {...field} placeholder="johndoe" />
<Input {...field} placeholder="john.doe" />
</FormControl>
<FormMessage />
</FormItem>
@ -63,7 +65,7 @@ export const ProfilesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>URL</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://linkedin.com/in/johndoe" />
</FormControl>
@ -77,7 +79,7 @@ export const ProfilesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel htmlFor="iconSlug">Icon</FormLabel>
<FormLabel htmlFor="iconSlug">{t`Icon`}</FormLabel>
<FormControl>
<div className="flex items-center gap-x-2">
<Avatar className="h-8 w-8 bg-white">
@ -93,15 +95,17 @@ export const ProfilesDialog = () => {
</FormControl>
<FormMessage />
<FormDescription className="ml-10">
Powered by{" "}
<a
href="https://simpleicons.org/"
target="_blank"
rel="noopener noreferrer nofollow"
className="font-medium"
>
Simple Icons
</a>
<Trans>
Powered by{" "}
<a
href="https://simpleicons.org/"
target="_blank"
rel="noopener noreferrer nofollow"
className="font-medium"
>
Simple Icons
</a>
</Trans>
</FormDescription>
</FormItem>
)}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { X } from "@phosphor-icons/react";
import { defaultProject, projectSchema } from "@reactive-resume/schema";
import {
@ -40,9 +41,9 @@ export const ProjectsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Reactive Resume" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -54,9 +55,9 @@ export const ProjectsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Description</FormLabel>
<FormLabel>{t`Description`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Open Source Resume Builder" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -68,9 +69,9 @@ export const ProjectsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Sep 2018 - Present" />
<Input {...field} placeholder={t`March 2023 - Present`} />
</FormControl>
<FormMessage />
</FormItem>
@ -82,7 +83,7 @@ export const ProjectsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://rxresu.me" />
</FormControl>
@ -96,7 +97,7 @@ export const ProjectsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}
@ -118,12 +119,12 @@ export const ProjectsDialog = () => {
render={({ field }) => (
<div className="col-span-2 space-y-3">
<FormItem>
<FormLabel>Keywords</FormLabel>
<FormLabel>{t`Keywords`}</FormLabel>
<FormControl>
<BadgeInput {...field} placeholder="FIFA 23, Call of Duty, etc." />
<BadgeInput {...field} />
</FormControl>
<FormDescription>
You can add multiple keywords by separating them with a comma.
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
</FormDescription>
<FormMessage />
</FormItem>

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultPublication, publicationSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const PublicationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="The Great Gatsby" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,9 @@ export const PublicationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Publisher</FormLabel>
<FormLabel>{t`Publisher`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Charles Scribner's Sons" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +64,9 @@ export const PublicationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Release Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="April 10, 1925" />
<Input {...field} placeholder={t`March 2023`} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,9 +78,9 @@ export const PublicationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://books.google.com/..." />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -91,7 +92,7 @@ export const PublicationsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultReference, referenceSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const ReferencesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Cosmo Kramer" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,9 @@ export const ReferencesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Description</FormLabel>
<FormLabel>{t`Description`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Neighbour" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +64,9 @@ export const ReferencesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://linkedin.com/in/cosmo.kramer" />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,7 +78,7 @@ export const ReferencesDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { X } from "@phosphor-icons/react";
import { defaultSkill, skillSchema } from "@reactive-resume/schema";
import {
@ -37,9 +38,9 @@ export const SkillsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Name</FormLabel>
<FormLabel>{t`Name`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Content Management" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -51,9 +52,9 @@ export const SkillsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Description</FormLabel>
<FormLabel>{t`Description`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Advanced" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -65,7 +66,7 @@ export const SkillsDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-2">
<FormLabel>Level</FormLabel>
<FormLabel>{t`Level`}</FormLabel>
<FormControl className="py-2">
<div className="flex items-center gap-x-4">
<Slider
@ -91,12 +92,12 @@ export const SkillsDialog = () => {
render={({ field }) => (
<div className="col-span-2 space-y-3">
<FormItem>
<FormLabel>Keywords</FormLabel>
<FormLabel>{t`Keywords`}</FormLabel>
<FormControl>
<BadgeInput {...field} placeholder="WordPress, Joomla, Webflow etc." />
<BadgeInput {...field} />
</FormControl>
<FormDescription>
You can add multiple keywords by separating them with a comma.
{t`You can add multiple keywords by separating them with a comma or pressing enter.`}
</FormDescription>
<FormMessage />
</FormItem>

View File

@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/macro";
import { defaultVolunteer, volunteerSchema } from "@reactive-resume/schema";
import {
FormControl,
@ -35,9 +36,9 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Organization</FormLabel>
<FormLabel>{t`Organization`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Amnesty International" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -49,9 +50,9 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Position</FormLabel>
<FormLabel>{t`Position`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Recruiter" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -63,9 +64,9 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Date</FormLabel>
<FormLabel>{t`Date`}</FormLabel>
<FormControl>
<Input {...field} placeholder="Dec 2016 - Aug 2017" />
<Input {...field} placeholder={t`March 2023 - Present`} />
</FormControl>
<FormMessage />
</FormItem>
@ -77,9 +78,9 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1">
<FormLabel>Location</FormLabel>
<FormLabel>{t`Location`}</FormLabel>
<FormControl>
<Input {...field} placeholder="New York, NY" />
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -91,9 +92,9 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Website</FormLabel>
<FormLabel>{t`Website`}</FormLabel>
<FormControl>
<URLInput {...field} placeholder="https://www.amnesty.org/" />
<URLInput {...field} />
</FormControl>
<FormMessage />
</FormItem>
@ -105,7 +106,7 @@ export const VolunteerDialog = () => {
control={form.control}
render={({ field }) => (
<FormItem className="col-span-1 sm:col-span-2">
<FormLabel>Summary</FormLabel>
<FormLabel>{t`Summary`}</FormLabel>
<FormControl>
<RichInput
{...field}

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { Plus, PlusCircle } from "@phosphor-icons/react";
import {
Award,
@ -50,7 +51,15 @@ export const LeftSidebar = () => {
</Button>
<div className="flex flex-col items-center justify-center gap-y-2">
<SectionIcon id="basics" name="Basics" onClick={() => scrollIntoView("#basics")} />
<SectionIcon
id="basics"
onClick={() => scrollIntoView("#basics")}
name={t({
message: "Basics",
context:
"The Basics section of a Resume consists of User's Picture, Full Name, Location etc.",
})}
/>
<SectionIcon id="summary" onClick={() => scrollIntoView("#summary")} />
<SectionIcon id="profiles" onClick={() => scrollIntoView("#profiles")} />
<SectionIcon id="experience" onClick={() => scrollIntoView("#experience")} />
@ -68,10 +77,11 @@ export const LeftSidebar = () => {
<SectionIcon
id="custom"
variant="outline"
name="Add a new section"
name={t`Add a new section`}
icon={<Plus size={14} />}
onClick={() => {
addSection();
// eslint-disable-next-line lingui/no-unlocalized-strings
scrollIntoView("& > section:last-of-type");
}}
/>
@ -184,7 +194,7 @@ export const LeftSidebar = () => {
<Button size="lg" variant="outline" onClick={addSection}>
<PlusCircle />
<span className="ml-2">Add a new section</span>
<span className="ml-2">{t`Add a new section`}</span>
</Button>
</div>
</ScrollArea>

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { basicsSchema } from "@reactive-resume/schema";
import { Input, Label } from "@reactive-resume/ui";
@ -17,7 +18,7 @@ export const BasicsSection = () => {
<header className="flex items-center justify-between">
<div className="flex items-center gap-x-4">
{getSectionIcon("basics")}
<h2 className="line-clamp-1 text-3xl font-bold">Basics</h2>
<h2 className="line-clamp-1 text-3xl font-bold">{t`Basics`}</h2>
</div>
</header>
@ -27,10 +28,9 @@ export const BasicsSection = () => {
</div>
<div className="space-y-1.5 sm:col-span-2">
<Label htmlFor="basics.name">Full Name</Label>
<Label htmlFor="basics.name">{t`Full Name`}</Label>
<Input
id="basics.name"
placeholder="John Doe"
value={basics.name}
hasError={!basicsSchema.pick({ name: true }).safeParse({ name: basics.name }).success}
onChange={(event) => setValue("basics.name", event.target.value)}
@ -38,17 +38,16 @@ export const BasicsSection = () => {
</div>
<div className="space-y-1.5 sm:col-span-2">
<Label htmlFor="basics.headline">Headline</Label>
<Label htmlFor="basics.headline">{t`Headline`}</Label>
<Input
id="basics.headline"
placeholder="Highly Creative Frontend Web Developer"
value={basics.headline}
onChange={(event) => setValue("basics.headline", event.target.value)}
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="basics.email">Email Address</Label>
<Label htmlFor="basics.email">{t`Email`}</Label>
<Input
id="basics.email"
placeholder="john.doe@example.com"
@ -61,7 +60,7 @@ export const BasicsSection = () => {
</div>
<div className="space-y-1.5">
<Label htmlFor="basics.url">Website</Label>
<Label htmlFor="basics.url">{t`Website`}</Label>
<URLInput
id="basics.url"
value={basics.url}
@ -71,7 +70,7 @@ export const BasicsSection = () => {
</div>
<div className="space-y-1.5">
<Label htmlFor="basics.phone">Phone Number</Label>
<Label htmlFor="basics.phone">{t`Phone`}</Label>
<Input
id="basics.phone"
placeholder="+1 (123) 4567 7890"
@ -81,10 +80,9 @@ export const BasicsSection = () => {
</div>
<div className="space-y-1.5">
<Label htmlFor="basics.location">Location</Label>
<Label htmlFor="basics.location">{t`Location`}</Label>
<Input
id="basics.location"
placeholder="105 Cedarhurst Ave, Cedarhurst, NY 11516"
value={basics.location}
onChange={(event) => setValue("basics.location", event.target.value)}
/>

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { createId } from "@paralleldrive/cuid2";
import { DotsSixVertical, Plus, X } from "@phosphor-icons/react";
import { CustomField as ICustomField } from "@reactive-resume/schema";
@ -38,21 +39,22 @@ export const CustomField = ({ field, onChange, onRemove }: CustomFieldProps) =>
<DotsSixVertical />
</Button>
<Input
placeholder="Icon"
{/* <Input
placeholder={t`Icon`}
value={field.icon}
className="!ml-0"
onChange={(event) => handleChange("icon", event.target.value)}
/>
/> */}
<Input
placeholder="Name"
placeholder={t`Name`}
value={field.name}
className="!ml-0"
onChange={(event) => handleChange("name", event.target.value)}
/>
<Input
placeholder="Value"
placeholder={t`Value`}
value={field.value}
onChange={(event) => handleChange("value", event.target.value)}
/>
@ -126,7 +128,7 @@ export const CustomFieldsSection = ({ className }: Props) => {
<Button variant="link" onClick={onAddCustomField}>
<Plus className="mr-2" />
<span>Add a custom field</span>
<span>{t`Add a custom field`}</span>
</Button>
</div>
);

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import {
AspectRatio,
Checkbox,
@ -69,7 +70,7 @@ export const PictureOptions = () => {
<div className="flex flex-col gap-y-5">
<div className="grid grid-cols-3 items-center gap-x-6">
<Label htmlFor="picture.size" className="col-span-1">
Size (in px)
{t`Size (in px)`}
</Label>
<Input
type="number"
@ -85,7 +86,7 @@ export const PictureOptions = () => {
<div className="grid grid-cols-3 items-center gap-x-6">
<Label htmlFor="picture.aspectRatio" className="col-span-1">
Aspect Ratio
{t`Aspect Ratio`}
</Label>
<div className="col-span-2 flex items-center justify-between">
<ToggleGroup
@ -94,19 +95,19 @@ export const PictureOptions = () => {
onValueChange={onAspectRatioChange}
className="flex items-center justify-center"
>
<Tooltip content="Square">
<Tooltip content={t`Square`}>
<ToggleGroupItem value="square">
<div className="h-3 w-3 border border-foreground" />
</ToggleGroupItem>
</Tooltip>
<Tooltip content="Horizontal">
<Tooltip content={t`Horizontal`}>
<ToggleGroupItem value="horizontal">
<div className="h-2 w-3 border border-foreground" />
</ToggleGroupItem>
</Tooltip>
<Tooltip content="Portrait">
<Tooltip content={t`Portrait`}>
<ToggleGroupItem value="portrait">
<div className="h-3 w-2 border border-foreground" />
</ToggleGroupItem>
@ -130,7 +131,7 @@ export const PictureOptions = () => {
<div className="grid grid-cols-3 items-center gap-x-6">
<Label htmlFor="picture.borderRadius" className="col-span-1">
Border Radius
{t`Border Radius`}
</Label>
<div className="col-span-2 flex items-center justify-between">
<ToggleGroup
@ -139,19 +140,19 @@ export const PictureOptions = () => {
onValueChange={onBorderRadiusChange}
className="flex items-center justify-center"
>
<Tooltip content="Square">
<Tooltip content={t`Square`}>
<ToggleGroupItem value="square">
<div className="h-3 w-3 border border-foreground" />
</ToggleGroupItem>
</Tooltip>
<Tooltip content="Rounded">
<Tooltip content={t`Rounded`}>
<ToggleGroupItem value="rounded">
<div className="h-3 w-3 rounded-sm border border-foreground" />
</ToggleGroupItem>
</Tooltip>
<Tooltip content="Circle">
<Tooltip content={t`Circle`}>
<ToggleGroupItem value="circle">
<div className="h-3 w-3 rounded-full border border-foreground" />
</ToggleGroupItem>
@ -176,7 +177,7 @@ export const PictureOptions = () => {
<div>
<div className="grid grid-cols-3 items-start gap-x-6">
<div className="col-span-1">
<Label>Effects</Label>
<Label>{t`Effects`}</Label>
</div>
<div className="col-span-2 space-y-4">
<div className="flex items-center space-x-2">
@ -187,7 +188,7 @@ export const PictureOptions = () => {
setValue("basics.picture.effects.hidden", checked);
}}
/>
<Label htmlFor="picture.effects.hidden">Hidden</Label>
<Label htmlFor="picture.effects.hidden">{t`Hidden`}</Label>
</div>
<div className="flex items-center space-x-2">
@ -198,7 +199,7 @@ export const PictureOptions = () => {
setValue("basics.picture.effects.border", checked);
}}
/>
<Label htmlFor="picture.effects.border">Border</Label>
<Label htmlFor="picture.effects.border">{t`Border`}</Label>
</div>
<div className="flex items-center space-x-2">
@ -209,7 +210,7 @@ export const PictureOptions = () => {
setValue("basics.picture.effects.grayscale", checked);
}}
/>
<Label htmlFor="picture.effects.grayscale">Grayscale</Label>
<Label htmlFor="picture.effects.grayscale">{t`Grayscale`}</Label>
</div>
</div>
</div>

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { Aperture, UploadSimple } from "@phosphor-icons/react";
import {
Avatar,
@ -48,7 +49,7 @@ export const PictureSection = () => {
</Avatar>
<div className="flex w-full flex-col gap-y-1.5">
<Label htmlFor="basics.picture.url">Picture</Label>
<Label htmlFor="basics.picture.url">{t`Picture`}</Label>
<div className="flex items-center gap-x-2">
<Input
id="basics.picture.url"

View File

@ -14,6 +14,7 @@ import {
sortableKeyboardCoordinates,
verticalListSortingStrategy,
} from "@dnd-kit/sortable";
import { t } from "@lingui/macro";
import { Plus } from "@phosphor-icons/react";
import { SectionItem, SectionKey, SectionWithItem } from "@reactive-resume/schema";
import { Button } from "@reactive-resume/ui";
@ -103,7 +104,12 @@ export const SectionBase = <T extends SectionItem>({ id, title, description }: P
className="gap-x-2 border-dashed py-6 leading-relaxed hover:bg-secondary-accent"
>
<Plus size={14} />
<span className="font-medium">Add New {section.name}</span>
<span className="font-medium">
{t({
message: "Add New Item",
context: "For example, add a new work experience, or add a new profile.",
})}
</span>
</Button>
)}
@ -137,7 +143,12 @@ export const SectionBase = <T extends SectionItem>({ id, title, description }: P
<footer className="flex items-center justify-end">
<Button variant="outline" className="ml-auto gap-x-2" onClick={onCreate}>
<Plus />
<span>Add New {section.name}</span>
<span>
{t({
message: "Add New Item",
context: "For example, add a new work experience, or add a new profile.",
})}
</span>
</Button>
</footer>
)}

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { createId } from "@paralleldrive/cuid2";
import { CopySimple, PencilSimple, Plus } from "@phosphor-icons/react";
import { SectionItem, SectionWithItem } from "@reactive-resume/schema";
@ -20,7 +21,7 @@ import {
} from "@reactive-resume/ui";
import { produce } from "immer";
import get from "lodash.get";
import { useEffect, useMemo } from "react";
import { useEffect } from "react";
import { UseFormReturn } from "react-hook-form";
import { DialogName, useDialog } from "@/client/stores/dialog";
@ -40,12 +41,12 @@ export const SectionDialog = <T extends SectionItem>({
children,
}: Props<T>) => {
const { isOpen, mode, close, payload } = useDialog<T>(id);
const setValue = useResumeStore((state) => state.setValue);
const section = useResumeStore((state) => {
if (!id) return null;
return get(state.resume.data.sections, id);
}) as SectionWithItem<T> | null;
const name = useMemo(() => section?.name ?? "", [section?.name]);
const isCreate = mode === "create";
const isUpdate = mode === "update";
@ -111,18 +112,16 @@ export const SectionDialog = <T extends SectionItem>({
<Form {...form}>
<form>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure you want to delete this {name}?</AlertDialogTitle>
<AlertDialogTitle>{t`Are you sure you want to delete this item?`}</AlertDialogTitle>
<AlertDialogDescription>
This action can be reverted by clicking on the undo button in the floating
toolbar.
{t`This action can be reverted by clicking on the undo button in the floating toolbar.`}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogCancel>{t`Cancel`}</AlertDialogCancel>
<AlertDialogAction variant="error" onClick={form.handleSubmit(onSubmit)}>
Delete
{t`Delete`}
</AlertDialogAction>
</AlertDialogFooter>
</form>
@ -144,9 +143,9 @@ export const SectionDialog = <T extends SectionItem>({
{isUpdate && <PencilSimple />}
{isDuplicate && <CopySimple />}
<h2>
{isCreate && `Create a new ${name}`}
{isUpdate && `Update an existing ${name}`}
{isDuplicate && `Duplicate an existing ${name}`}
{isCreate && t`Create a new item`}
{isUpdate && t`Update an existing item`}
{isDuplicate && t`Duplicate an existing item`}
</h2>
</div>
</DialogTitle>
@ -156,9 +155,9 @@ export const SectionDialog = <T extends SectionItem>({
<DialogFooter>
<Button type="submit">
{isCreate && "Create"}
{isUpdate && "Save Changes"}
{isDuplicate && "Duplicate"}
{isCreate && t`Create`}
{isUpdate && t`Save Changes`}
{isDuplicate && t`Duplicate`}
</Button>
</DialogFooter>
</form>

View File

@ -1,5 +1,6 @@
import { useSortable } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { t } from "@lingui/macro";
import { CopySimple, DotsSixVertical, PencilSimple, TrashSimple } from "@phosphor-icons/react";
import {
DropdownMenu,
@ -81,19 +82,19 @@ export const SectionListItem = ({
</DropdownMenuTrigger>
<DropdownMenuContent align="center" side="left" sideOffset={-16}>
<DropdownMenuCheckboxItem checked={visible} onCheckedChange={onToggleVisibility}>
<span className="-ml-0.5">Visible</span>
<span className="-ml-0.5">{t`Visible`}</span>
</DropdownMenuCheckboxItem>
<DropdownMenuItem onClick={onUpdate}>
<PencilSimple size={14} />
<span className="ml-2">Edit</span>
<span className="ml-2">{t`Edit`}</span>
</DropdownMenuItem>
<DropdownMenuItem onClick={onDuplicate}>
<CopySimple size={14} />
<span className="ml-2">Copy</span>
<span className="ml-2">{t`Copy`}</span>
</DropdownMenuItem>
<DropdownMenuItem className="text-error" onClick={onDelete}>
<TrashSimple size={14} />
<span className="ml-2">Remove</span>
<span className="ml-2">{t`Remove`}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View File

@ -1,3 +1,4 @@
import { plural, t } from "@lingui/macro";
import {
ArrowCounterClockwise,
Broom,
@ -63,7 +64,7 @@ export const SectionOptions = ({ id }: Props) => {
<>
<DropdownMenuItem onClick={onCreate}>
<Plus />
<span className="ml-2">Add a new item</span>
<span className="ml-2">{t`Add a new item`}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
@ -73,12 +74,12 @@ export const SectionOptions = ({ id }: Props) => {
<DropdownMenuGroup>
<DropdownMenuItem onClick={toggleVisibility}>
{section.visible ? <Eye /> : <EyeSlash />}
<span className="ml-2">{section.visible ? "Hide" : "Show"}</span>
<span className="ml-2">{section.visible ? t`Hide` : t`Show`}</span>
</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<PencilSimple />
<span className="ml-2">Rename</span>
<span className="ml-2">{t`Rename`}</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<div className="relative col-span-2">
@ -103,15 +104,15 @@ export const SectionOptions = ({ id }: Props) => {
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<Columns />
<span className="ml-2">Columns</span>
<span className="ml-2">{t`Columns`}</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuRadioGroup value={`${section.columns}`} onValueChange={onChangeColumns}>
<DropdownMenuRadioItem value="1">1 Column</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="2">2 Columns</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="3">3 Columns</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="4">4 Columns</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="5">5 Columns</DropdownMenuRadioItem>
{Array.from({ length: 5 }, (_, i) => i + 1).map((value) => (
<DropdownMenuRadioItem value={`${value}`}>
{plural(value, { one: "Column", other: "Columns" })}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuSubContent>
</DropdownMenuSub>
@ -119,12 +120,12 @@ export const SectionOptions = ({ id }: Props) => {
<DropdownMenuSeparator />
<DropdownMenuItem disabled={!hasItems} onClick={onResetItems}>
<Broom />
<span className="ml-2">Reset</span>
<span className="ml-2">{t`Reset`}</span>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-error" disabled={!isCustomSection} onClick={onRemove}>
<TrashSimple />
<span className="ml-2">Remove</span>
<span className="ml-2">{t`Remove`}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>

View File

@ -1,3 +1,4 @@
import { t } from "@lingui/macro";
import { Tag } from "@phosphor-icons/react";
import { URL, urlSchema } from "@reactive-resume/schema";
import { Button, Input, Popover, PopoverContent, PopoverTrigger } from "@reactive-resume/ui";
@ -36,14 +37,14 @@ export const URLInput = forwardRef<HTMLInputElement, Props>(
<PopoverContent className="p-1.5">
<Input
value={value.label}
placeholder="Label"
placeholder={t`Label`}
onChange={(event) => onChange({ ...value, label: event.target.value })}
/>
</PopoverContent>
</Popover>
</div>
{hasError && <small className="opacity-75">URL must start with https://</small>}
{hasError && <small className="opacity-75">{t`URL must start with https://`}</small>}
</>
);
},