Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"date-fns": "^4.1.0",
"i18next": "^24.2.1",
"lodash": "^4.17.21",
"lucide-react": "^0.468.0",
"papaparse": "^5.4.1",
Expand All @@ -59,6 +60,7 @@
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.5",
"react-hook-form": "^7.54.1",
"react-i18next": "^15.4.0",
"react-router-dom": "^7.0.2",
"recharts": "^2.15.0",
"tailwind-merge": "^2.5.5",
Expand Down
55 changes: 55 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion src/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Icons } from '@/components/icons';
import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { Link, useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';

interface ApplicationHeaderProps {
heading: string;
Expand All @@ -23,6 +24,7 @@ export function ApplicationHeader({
backUrl,
}: ApplicationHeaderProps) {
const navigate = useNavigate();
const { t } = useTranslation();
return (
<div className={cn('flex w-full items-center justify-between', className)}>
<div className="flex items-center gap-2">
Expand All @@ -49,7 +51,7 @@ export function ApplicationHeader({
</>
)}

<h1 className="font-heading text-xl font-bold tracking-tight">{heading}</h1>
<h1 className="font-heading text-xl font-bold tracking-tight">{t(heading)}</h1>
{text && <p className="ml-4 text-lg font-light text-muted-foreground">{text}</p>}
</div>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/data-table/data-table-column-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@/components/ui/dropdown-menu';

import { Icons } from '@/components/icons';
import { useTranslation } from 'react-i18next';

import { cn } from '@/lib/utils';

Expand All @@ -22,16 +23,17 @@ export function DataTableColumnHeader<TData, TValue>({
title,
className,
}: DataTableColumnHeaderProps<TData, TValue>) {
const { t } = useTranslation();
if (!column.getCanSort()) {
return <div className={cn(className)}>{title}</div>;
return <div className={cn(className)}>{t(title)}</div>;
}

return (
<div className={cn('flex items-center space-x-2', className)}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="-ml-3 h-8 data-[state=open]:bg-accent">
<span>{title}</span>
<span>{t(title)}</span>
{column.getIsSorted() === 'desc' ? (
<Icons.ArrowDown className="ml-2 h-4 w-4" />
) : column.getIsSorted() === 'asc' ? (
Expand Down
4 changes: 3 additions & 1 deletion src/components/ui/data-table/data-table-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { DataTableFacetedFilter } from './data-table-faceted-filter';
import type { DataTableFacetedFilterProps } from './data-table-faceted-filter';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

interface ColumnMeta {
label?: string;
Expand All @@ -28,6 +29,7 @@ export function DataTableToolbar<TData>({
searchBy,
filters,
}: DataTableToolbarProps<TData>) {
const { t } = useTranslation();
const isFiltered = table.getState().columnFilters.length > 0 || table.getState().globalFilter;
const hideableColumns = table.getAllColumns().filter((column) => column.getCanHide());

Expand Down Expand Up @@ -60,7 +62,7 @@ export function DataTableToolbar<TData>({
}}
className="h-8 px-2 lg:px-3"
>
Reset
{t('Reset')}
<Icons.Close className="ml-2 h-4 w-4" />
</Button>
)}
Expand Down
6 changes: 4 additions & 2 deletions src/components/ui/empty-placeholder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';

import { cn } from '@/lib/utils';
import { Icons } from '@/components/icons';
import { useTranslation } from 'react-i18next';

interface EmptyPlaceholderProps extends React.HTMLAttributes<HTMLDivElement> {
icon?: React.ReactNode;
Expand All @@ -17,6 +18,7 @@ export function EmptyPlaceholder({
description,
...props
}: EmptyPlaceholderProps) {
const { t } = useTranslation();
return (
<div
className={cn(
Expand All @@ -31,8 +33,8 @@ export function EmptyPlaceholder({
{icon}
</div>
)}
{title && <EmptyPlaceholder.Title>{title}</EmptyPlaceholder.Title>}
{description && <EmptyPlaceholder.Description>{description}</EmptyPlaceholder.Description>}
{title && <EmptyPlaceholder.Title>{t(title)}</EmptyPlaceholder.Title>}
{description && <EmptyPlaceholder.Description>{t(description)}</EmptyPlaceholder.Description>}
{children}
</div>
</div>
Expand Down
24 changes: 24 additions & 0 deletions src/lib/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import en from './locales/en.json';
import zhCN from './locales/zh-CN.json';

i18n
.use(initReactI18next)
.init({
resources: {
en: {
translation: en,
},
'zh-CN': {
translation: zhCN,
},
},
lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});

export default i18n;
55 changes: 55 additions & 0 deletions src/lib/i18n/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"common": {
"settings": "Settings",
"general": "General",
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"add": "Add",
"back": "Back",
"success": "Success",
"error": "Error"
},
"settings": {
"General": "General",
"general": {
"title": "General",
"description": "Manage the general application settings and preferences",
"language": "Language",
"language_description": "Choose your preferred language",
"language_selection": "Select Language",
"baseCurrency": "Base Currency",
"baseCurrency_description": "Choose your base currency"
},
"Accounts": "Accounts",
"Limits": "Limits",
"Goals": "Goals",
"Appearance": "Appearance",
"Data Export": "Data Export",
"Contribution Limits": "Contribution Limits",
"Manage your investment and saving accounts.": "Manage your investment and saving accounts.",
"Manage your contribution limits.": "Manage your contribution limits.",
"Manage your investment and saving goals.": "Manage your investment and saving goals.",
"Customize the appearance of the application.": "Customize the appearance of the application.",
"Export all your financial data with flexible export options.": "Export all your financial data with flexible export options.",
"Choose Your Preferred Format": "Choose Your Preferred Format"
},
"dashboard": {
"Dashboard": "Dashboard",
"portfolio": "Portfolio",
"holdings": "Holdings",
"activities": "Activities",
"performance": "Performance"
},
"Dashboard": "Dashboard",
"Holdings": "Holdings",
"Performance": "Performance",
"Income": "Income",
"Activities": "Activities",
"Settings": "Settings",
"Investment Income": "Investment Income",
"Portfolio Performance": "Portfolio Performance",
"No income data available": "No income data available",
"Add account": "Add account"
}
Loading