chore: add translations

This commit is contained in:
Ephraim Atta-Duncan
2025-06-05 12:31:53 +00:00
parent de45a63c97
commit 64695fad32
7 changed files with 68 additions and 46 deletions

View File

@ -91,7 +91,7 @@ export function DocumentsDataTable({
const columns = useMemo(() => {
return [
{
header: 'Created',
header: _(msg`Created`),
accessorKey: 'createdAt',
cell: ({ row }) =>
i18n.date(row.original.createdAt, { ...DateTime.DATETIME_SHORT, hourCycle: 'h12' }),

View File

@ -1,3 +1,5 @@
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Plural, Trans } from '@lingui/react/macro';
import type { Table } from '@tanstack/react-table';
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
@ -21,6 +23,8 @@ export function DataTablePagination<TData>({
table,
additionalInformation = 'VisibleCount',
}: DataTablePaginationProps<TData>) {
const { _ } = useLingui();
return (
<div className="flex flex-wrap items-center justify-between gap-x-4 gap-y-4 px-2">
<div className="text-muted-foreground flex-1 text-sm">
@ -86,7 +90,7 @@ export function DataTablePagination<TData>({
onClick={() => table.setPageIndex(0)}
disabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to first page</span>
<span className="sr-only">{_(msg`Go to first page`)}</span>
<ChevronsLeft className="h-4 w-4" />
</Button>
<Button
@ -95,7 +99,7 @@ export function DataTablePagination<TData>({
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<span className="sr-only">Go to previous page</span>
<span className="sr-only">{_(msg`Go to previous page`)}</span>
<ChevronLeft className="h-4 w-4" />
</Button>
<Button
@ -104,7 +108,7 @@ export function DataTablePagination<TData>({
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to next page</span>
<span className="sr-only">{_(msg`Go to next page`)}</span>
<ChevronRight className="h-4 w-4" />
</Button>
<Button
@ -113,7 +117,7 @@ export function DataTablePagination<TData>({
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
disabled={!table.getCanNextPage()}
>
<span className="sr-only">Go to last page</span>
<span className="sr-only">{_(msg`Go to last page`)} </span>
<ChevronsRight className="h-4 w-4" />
</Button>
</div>

View File

@ -1,5 +1,8 @@
import * as React from 'react';
import type { MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import type { Column } from '@tanstack/react-table';
import { Check } from 'lucide-react';
@ -18,7 +21,7 @@ interface DataTableFacetedFilterProps<TData, TValue> {
onFilterChange?: (values: string[]) => void;
selectedValues?: string[];
options: {
label: string;
label: MessageDescriptor;
value: string;
icon?: React.ComponentType<{ className?: string }>;
color?: string;
@ -35,6 +38,7 @@ export function DataTableFacetedFilter<TData, TValue>({
selectedValues,
options,
}: DataTableFacetedFilterProps<TData, TValue>) {
const { _ } = useLingui();
const facets = column?.getFacetedUniqueValues();
const selectedValuesSet = new Set(selectedValues || (column?.getFilterValue() as string[]));
@ -53,7 +57,7 @@ export function DataTableFacetedFilter<TData, TValue>({
<div className="hidden gap-1 lg:flex">
{selectedValuesSet.size > 2 ? (
<Badge variant="neutral" className="rounded-sm px-2 py-0.5 font-normal">
{selectedValuesSet.size} selected
{selectedValuesSet.size} {_(msg`selected`)}
</Badge>
) : (
options
@ -67,7 +71,7 @@ export function DataTableFacetedFilter<TData, TValue>({
option.bgColor ? option.bgColor : 'bg-secondary',
)}
>
{option.label}
{_(option.label)}
</Badge>
))
)}
@ -79,7 +83,7 @@ export function DataTableFacetedFilter<TData, TValue>({
<PopoverContent className="w-[200px] p-0" align="start">
<Command>
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandEmpty>{_(msg`No results found.`)}</CommandEmpty>
<CommandGroup>
{options.map((option) => {
const isSelected = selectedValuesSet.has(option.value);
@ -120,7 +124,7 @@ export function DataTableFacetedFilter<TData, TValue>({
)}
/>
)}
<span>{option.label}</span>
<span>{_(option.label)}</span>
{(stats?.[option.value] || facets?.get(option.value)) && (
<span className="text-muted-foreground ml-auto flex size-4 items-center justify-center font-mono text-xs">
{stats?.[option.value] || facets?.get(option.value)}

View File

@ -1,5 +1,7 @@
import * as React from 'react';
import type { MessageDescriptor } from '@lingui/core';
import { useLingui } from '@lingui/react';
import type { Column } from '@tanstack/react-table';
import { cn } from '../../lib/utils';
@ -22,14 +24,14 @@ interface DataTableSingleFilterProps<TData, TValue> {
onFilterChange?: (values: string[]) => void;
selectedValues?: string[];
options: {
label: string;
label: MessageDescriptor;
value: string;
icon?: React.ComponentType<{ className?: string }>;
color?: string;
bgColor?: string;
}[];
groups?: {
label: string;
label: MessageDescriptor;
values: string[];
}[];
}
@ -43,6 +45,7 @@ export function DataTableSingleFilter<TData, TValue>({
onFilterChange,
selectedValues,
}: DataTableSingleFilterProps<TData, TValue>) {
const { _ } = useLingui();
const filterValue = column?.getFilterValue() as string[] | undefined;
const selectedValue = selectedValues?.[0] || (filterValue?.[0] ?? undefined);
const selectedOption = options.find((option) => option.value === selectedValue);
@ -66,9 +69,9 @@ export function DataTableSingleFilter<TData, TValue>({
const renderOptions = () => {
if (groups) {
return groups.map((group, groupIndex) => (
<React.Fragment key={group.label}>
<React.Fragment key={JSON.stringify(group.label)}>
<SelectGroup>
<SelectLabel>{group.label}</SelectLabel>
<SelectLabel>{_(group.label)}</SelectLabel>
{options
.filter((option) => group.values.includes(option.value))
.map((option) => (
@ -82,7 +85,7 @@ export function DataTableSingleFilter<TData, TValue>({
)}
/>
)}
<span>{option.label}</span>
<span>{_(option.label)}</span>
</div>
</SelectItem>
))}
@ -102,7 +105,7 @@ export function DataTableSingleFilter<TData, TValue>({
className={cn('size-4', option.color ? option.color : 'text-muted-foreground')}
/>
)}
<span>{option.label}</span>
<span>{_(option.label)}</span>
</div>
</SelectItem>
))}
@ -125,7 +128,7 @@ export function DataTableSingleFilter<TData, TValue>({
selectedOption.bgColor ? selectedOption.bgColor : 'variant-secondary',
)}
>
{selectedOption.label}
{_(selectedOption.label)}
</Badge>
</>
)}

View File

@ -1,3 +1,5 @@
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import type { Table } from '@tanstack/react-table';
import { Calendar, CircleDashedIcon, Globe, ListFilter, X, XCircle } from 'lucide-react';
@ -36,6 +38,7 @@ export function DataTableToolbar<TData>({
isTimePeriodFiltered,
isSourceFiltered,
}: DataTableToolbarProps<TData>) {
const { _ } = useLingui();
const isFiltered =
table.getState().columnFilters.length > 0 ||
isStatusFiltered ||
@ -58,7 +61,7 @@ export function DataTableToolbar<TData>({
<div className="relative">
<Input
className="peer h-8 w-[150px] pe-9 ps-9 lg:w-[250px]"
placeholder="Search documents..."
placeholder={_(msg`Search documents...`)}
value={searchValue}
onChange={(event) => table.getColumn('title')?.setFilterValue(event.target.value)}
/>
@ -68,7 +71,7 @@ export function DataTableToolbar<TData>({
{searchValue && (
<button
className="text-muted-foreground/80 hover:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md outline-none transition-[color,box-shadow] focus:z-10 focus-visible:ring-[3px] disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
aria-label="Clear filter"
aria-label={_(msg`Clear filter`)}
onClick={handleClearFilter}
>
<XCircle className="size-3" aria-hidden="true" />
@ -79,7 +82,7 @@ export function DataTableToolbar<TData>({
{table.getColumn('status') && (
<DataTableFacetedFilter
column={table.getColumn('status')}
title="Status"
title={_(msg`Status`)}
options={statuses}
icon={CircleDashedIcon}
stats={stats}
@ -91,7 +94,7 @@ export function DataTableToolbar<TData>({
{table.getColumn('createdAt') && (
<DataTableSingleFilter
column={table.getColumn('createdAt')}
title="Time Period"
title={_(msg`Time Period`)}
options={timePeriods}
groups={timePeriodGroups}
icon={Calendar}
@ -103,7 +106,7 @@ export function DataTableToolbar<TData>({
{table.getColumn('source') && (
<DataTableFacetedFilter
column={table.getColumn('source')}
title="Source"
title={_(msg`Source`)}
options={sources}
icon={Globe}
onFilterChange={onSourceFilterChange}
@ -113,7 +116,7 @@ export function DataTableToolbar<TData>({
{isFiltered && (
<Button variant="ghost" className="h-8 gap-2" size="sm" onClick={handleReset}>
Reset
{_(msg`Reset`)}
<X className="size-4" />
</Button>
)}

View File

@ -1,6 +1,8 @@
import * as React from 'react';
import { useMemo } from 'react';
import { msg } from '@lingui/core/macro';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/react/macro';
import type {
ColumnDef,
@ -83,6 +85,7 @@ export function DataTable<TData, TValue>({
isSourceFiltered,
emptyState,
}: DataTableProps<TData, TValue>) {
const { _ } = useLingui();
const [rowSelection, setRowSelection] = React.useState({});
const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({});
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([]);
@ -211,10 +214,14 @@ export function DataTable<TData, TValue>({
</div>
) : emptyState?.enable ? (
(emptyState.component ?? (
<div className="flex h-24 items-center justify-center text-center">No results.</div>
<div className="flex h-24 items-center justify-center text-center">
{_(msg`No results.`)}
</div>
))
) : (
<div className="flex h-24 items-center justify-center text-center">No results.</div>
<div className="flex h-24 items-center justify-center text-center">
{_(msg`No results.`)}
</div>
)}
</div>

View File

@ -1,37 +1,38 @@
import { msg } from '@lingui/core/macro';
import { CheckCircle2, Clock, File, FileText, Inbox, Link, XCircle } from 'lucide-react';
export const statuses = [
{
value: 'INBOX',
label: 'Inbox',
label: msg`Inbox`,
icon: Inbox,
color: 'text-blue-700 dark:text-blue-300',
bgColor: 'bg-blue-100 dark:bg-blue-100 text-blue-700 dark:text-blue-700',
},
{
value: 'DRAFT',
label: 'Draft',
label: msg`Draft`,
icon: File,
color: 'text-yellow-500 dark:text-yellow-300',
bgColor: 'bg-yellow-100 dark:bg-yellow-100 text-yellow-700 dark:text-yellow-700',
},
{
value: 'PENDING',
label: 'Pending',
label: msg`Pending`,
icon: Clock,
color: 'text-blue-700 dark:text-blue-300',
bgColor: 'bg-blue-100 dark:bg-blue-100 text-blue-700 dark:text-blue-700',
},
{
value: 'COMPLETED',
label: 'Completed',
label: msg`Completed`,
icon: CheckCircle2,
color: 'text-documenso-700 dark:text-documenso-300',
bgColor: 'bg-documenso-200 dark:bg-documenso-200 text-documenso-800 dark:text-documenso-800',
},
{
value: 'REJECTED',
label: 'Rejected',
label: msg`Rejected`,
icon: XCircle,
color: 'text-red-700 dark:text-red-300',
bgColor: 'bg-red-100 dark:bg-red-100 text-red-500 dark:text-red-700',
@ -41,14 +42,14 @@ export const statuses = [
export const sources = [
{
value: 'TEMPLATE',
label: 'Template',
label: msg`Template`,
icon: FileText,
color: 'text-blue-700 dark:text-blue-300',
bgColor: 'bg-blue-100 dark:bg-blue-100 text-blue-700 dark:text-blue-700',
},
{
value: 'DIRECT_LINK',
label: 'Direct Link',
label: msg`Direct Link`,
icon: Link,
color: 'text-green-700 dark:text-green-300',
bgColor: 'bg-green-100 dark:bg-green-100 text-green-700 dark:text-green-700',
@ -58,61 +59,61 @@ export const sources = [
export const timePeriods = [
{
value: 'today',
label: 'Today',
label: msg`Today`,
},
{
value: 'this-week',
label: 'This Week',
label: msg`This Week`,
},
{
value: 'this-month',
label: 'This Month',
label: msg`This Month`,
},
{
value: 'this-quarter',
label: 'This Quarter',
label: msg`This Quarter`,
},
{
value: 'this-year',
label: 'This Year',
label: msg`This Year`,
},
{
value: 'yesterday',
label: 'Yesterday',
label: msg`Yesterday`,
},
{
value: 'last-week',
label: 'Last Week',
label: msg`Last Week`,
},
{
value: 'last-month',
label: 'Last Month',
label: msg`Last Month`,
},
{
value: 'last-quarter',
label: 'Last Quarter',
label: msg`Last Quarter`,
},
{
value: 'last-year',
label: 'Last Year',
label: msg`Last Year`,
},
{
value: 'all-time',
label: 'All Time',
label: msg`All Time`,
},
];
export const timePeriodGroups = [
{
label: 'Present',
label: msg`Present`,
values: ['today', 'this-week', 'this-month', 'this-quarter', 'this-year'],
},
{
label: 'Past',
label: msg`Past`,
values: ['yesterday', 'last-week', 'last-month', 'last-quarter', 'last-year'],
},
{
label: '',
label: msg``,
values: ['all-time'],
},
];