diff --git a/README.md b/README.md
index cabf936..b0f1241 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,9 @@
- [middleware.ts](/middleware.ts) - основной функционал работы i18n
- [getLang()](src/shared/config/i18n/get-lang.ts) - возвращает выбранный язык `en | ru`
+- [useLang()](src/shared/config/i18n/use-lang.ts) - как `getLang()`, только для клиентского компонента
- [getDictionary()](src/shared/config/i18n/dictionaries.ts) - возвращает объект с переводами `ключ-значение`
+- [useDictionary()](src/shared/config/i18n/use-dictionary.ts) - как `getDictionary()`, только для клиентского компонента
- [type Dictionary](src/shared/config/i18n/dictionaries.ts)
- [/dictionary](src/shared/config/i18n/dictionaries/) - директория с json файлами переводов
diff --git a/app/[lang]/projects/[category]/page.tsx b/app/[lang]/projects/[category]/page.tsx
index 4e04f85..c5cae67 100644
--- a/app/[lang]/projects/[category]/page.tsx
+++ b/app/[lang]/projects/[category]/page.tsx
@@ -1,6 +1,7 @@
import { getProjectsByCategory } from '@/entity/project';
+import { Link } from '@/shared/config';
+import { Header } from '@/widgets';
import { Metadata } from 'next';
-import Link from 'next/link';
export type ProjectCategoryPageProps = {
params: { category: string };
@@ -13,16 +14,26 @@ export default async function ProjectCategoryPage({
return (
<>
-
{category.title}
+
- Projects:
- {projects.map((project) => (
- <>
-
- {project.title} - {project.description}
+
+ {projects.map((project) => (
+
+ {project.title}
+
+ {project.description}
+
- >
- ))}
+ ))}
+
>
);
}
diff --git a/middleware.ts b/middleware.ts
index ddbc0f2..38491a5 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -24,7 +24,7 @@ export function middleware(request: NextRequest) {
pathname === `/${i18n.defaultLocale}`
) {
// The incoming request is for /en/whatever, so we'll reDIRECT to /whatever
- return NextResponse.redirect(
+ const response = NextResponse.redirect(
new URL(
pathname.replace(
`/${i18n.defaultLocale}`,
@@ -36,6 +36,8 @@ export function middleware(request: NextRequest) {
headers: requestHeaders,
},
);
+ // response.cookies.set('NEXT_LOCALE', i18n.defaultLocale);
+ return response;
}
const pathnameIsMissingLocale = i18n.locales.every(
@@ -46,7 +48,7 @@ export function middleware(request: NextRequest) {
if (pathnameIsMissingLocale) {
// Now for EITHER /en or /nl (for example) we're going to tell Next.js that the request is for /en/whatever
// or /nl/whatever, and then reWRITE the request to that it is handled properly.
- return NextResponse.rewrite(
+ const response = NextResponse.rewrite(
new URL(
`/${i18n.defaultLocale}${pathname}${request.nextUrl.search}`,
request.nextUrl.href,
@@ -57,13 +59,19 @@ export function middleware(request: NextRequest) {
},
},
);
+ // response.cookies.set('NEXT_LOCALE', i18n.defaultLocale);
+ return response;
}
- return NextResponse.next({
+ // const lang = (pathname.split('/')[1] as Locale) || i18n.defaultLocale;
+
+ const response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
+ // response.cookies.set('NEXT_LOCALE', lang);
+ return response;
}
export const config = {
diff --git a/package.json b/package.json
index 6933a11..d48bb28 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"framer-motion": "^11.2.13",
"gray-matter": "^4.0.3",
"jose": "^5.6.3",
+ "js-cookie": "^3.0.5",
"next": "14.2.4",
"next-mdx-remote": "^5.0.0",
"next-themes": "^0.3.0",
@@ -27,7 +28,6 @@
"react-dom": "^18.3.1",
"react-icons": "^5.2.1",
"react-syntax-highlighter": "^15.5.0",
- "rehype-mdx-code-props": "^3.0.1",
"remark-gfm": "^4.0.0",
"tailwind-merge": "^2.4.0",
"unist-util-visit": "^5.0.0",
@@ -37,6 +37,7 @@
"devDependencies": {
"@tailwindcss/typography": "^0.5.13",
"@types/bcryptjs": "^2.4.6",
+ "@types/js-cookie": "^3.0.6",
"@types/mdx": "^2.0.13",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fb5015a..58fb2cd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,9 @@ dependencies:
jose:
specifier: ^5.6.3
version: 5.6.3
+ js-cookie:
+ specifier: ^3.0.5
+ version: 3.0.5
next:
specifier: 14.2.4
version: 14.2.4(react-dom@18.3.1)(react@18.3.1)(sass@1.77.7)
@@ -56,9 +59,6 @@ dependencies:
react-syntax-highlighter:
specifier: ^15.5.0
version: 15.5.0(react@18.3.1)
- rehype-mdx-code-props:
- specifier: ^3.0.1
- version: 3.0.1
remark-gfm:
specifier: ^4.0.0
version: 4.0.0
@@ -82,6 +82,9 @@ devDependencies:
'@types/bcryptjs':
specifier: ^2.4.6
version: 2.4.6
+ '@types/js-cookie':
+ specifier: ^3.0.6
+ version: 3.0.6
'@types/mdx':
specifier: ^2.0.13
version: 2.0.13
@@ -3285,6 +3288,10 @@ packages:
'@types/unist': 3.0.2
dev: false
+ /@types/js-cookie@3.0.6:
+ resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==}
+ dev: true
+
/@types/json-schema@7.0.15:
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
dev: false
@@ -4652,12 +4659,6 @@ packages:
source-map: 0.7.4
dev: false
- /estree-util-value-to-estree@3.1.2:
- resolution: {integrity: sha512-S0gW2+XZkmsx00tU2uJ4L9hUT7IFabbml9pHh2WQqFmAbxit++YGZne0sKJbNwkj9Wvg9E4uqWl4nCIFQMmfag==}
- dependencies:
- '@types/estree': 1.0.5
- dev: false
-
/estree-util-visit@2.0.0:
resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==}
dependencies:
@@ -5005,21 +5006,6 @@ packages:
resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
dev: false
- /hast-util-properties-to-mdx-jsx-attributes@1.0.0:
- resolution: {integrity: sha512-MZEdAYiXC8wDBfntAc7syyWHbcg/X1h03DQ7IQ6MKagMttpYhnKqOZR/nia0657Dt2v2vuXB8YuKNExw0Fljew==}
- dependencies:
- '@types/estree': 1.0.5
- '@types/hast': 3.0.4
- comma-separated-tokens: 2.0.3
- estree-util-value-to-estree: 3.1.2
- mdast-util-mdx-jsx: 3.1.2
- property-information: 6.5.0
- space-separated-tokens: 2.0.2
- style-to-js: 1.1.12
- transitivePeerDependencies:
- - supports-color
- dev: false
-
/hast-util-to-estree@3.1.0:
resolution: {integrity: sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==}
dependencies:
@@ -5440,6 +5426,11 @@ packages:
resolution: {integrity: sha512-1Jh//hEEwMhNYPDDLwXHa2ePWgWiFNNUadVmguAAw2IJ6sj9mNxV5tGXJNqlMkJAybF6Lgw1mISDxTePP/187g==}
dev: false
+ /js-cookie@3.0.5:
+ resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
+ engines: {node: '>=14'}
+ dev: false
+
/js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -6809,20 +6800,6 @@ packages:
set-function-name: 2.0.2
dev: true
- /rehype-mdx-code-props@3.0.1:
- resolution: {integrity: sha512-BWWKn0N6r7/qd7lbLgv5J8of7imz1l1PyCNoY7BH0AOR9JdJlQIfA9cKqTZVEb2h2GPKh473qrBajF0i01fq3A==}
- dependencies:
- '@types/hast': 3.0.4
- hast-util-properties-to-mdx-jsx-attributes: 1.0.0
- mdast-util-from-markdown: 2.0.1
- mdast-util-mdx: 3.0.0
- micromark-extension-mdxjs: 3.0.0
- unified: 11.0.5
- unist-util-visit-parents: 6.0.1
- transitivePeerDependencies:
- - supports-color
- dev: false
-
/remark-gfm@4.0.0:
resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==}
dependencies:
@@ -7204,12 +7181,6 @@ packages:
engines: {node: '>=8'}
dev: true
- /style-to-js@1.1.12:
- resolution: {integrity: sha512-tv+/FkgNYHI2fvCoBMsqPHh5xovwiw+C3X0Gfnss/Syau0Nr3IqGOJ9XiOYXoPnToHVbllKFf5qCNFJGwFg5mg==}
- dependencies:
- style-to-object: 1.0.6
- dev: false
-
/style-to-object@0.4.4:
resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==}
dependencies:
diff --git a/projects/best-practice/app-router-auth/en.mdx b/projects/best-practice/app-router-auth/en.mdx
index 9cb79da..553e79b 100644
--- a/projects/best-practice/app-router-auth/en.mdx
+++ b/projects/best-practice/app-router-auth/en.mdx
@@ -17,7 +17,7 @@ Getting user data: `const user = await getUser();`. It's very simple :)
test))
-```TypeScript filename="src/features/auth/api/jwt.ts"
+```TypeScript filename="features/auth/api/jwt.ts" githubPath="src/features/auth/api/jwt.ts"
import { SignJWT, jwtVerify } from 'jose';
import { SessionPayload } from '../types/definitions';
diff --git a/projects/best-practice/app-router-auth/examples/auth.tsx b/projects/best-practice/app-router-auth/examples/auth.tsx
index 01215f5..a7e34f2 100644
--- a/projects/best-practice/app-router-auth/examples/auth.tsx
+++ b/projects/best-practice/app-router-auth/examples/auth.tsx
@@ -1,4 +1,5 @@
import { LogoutButton } from '@/features';
+import { getDictionary } from '@/shared/config';
import { CodeBlock } from '@/shared/ui';
import { Card } from '@nextui-org/react';
import { FiUserCheck } from 'react-icons/fi';
@@ -7,6 +8,7 @@ import { FormLoginExample } from './ui/form-login';
export const AuthExample = async () => {
const user = await getUserExample();
+ const dict = await getDictionary();
return (
<>
@@ -15,16 +17,17 @@ export const AuthExample = async () => {
- You have successfully logged in as an {user?.name}
+ {`${dict.ui['auth-logged']} ${user?.name}`}
-
+
)}
{
-// const dir = path.join(process.cwd(), 'projects', category);
-// const indexFile = path.join(dir, 'index.mdx');
-// const categoryMetadata = (await getMetadata(indexFile)) as CategoryMetadata;
-
-// const projectDirs = await fs.readdir(dir, { withFileTypes: true });
-// const projectMetadata = await Promise.all(
-// projectDirs
-// .filter((dirent) => dirent.isDirectory())
-// .map(async (dirent) => {
-// const projectFile = path.join(dir, dirent.name, 'page.mdx');
-// const projectMetadata = await getMetadata(projectFile);
-// return {
-// ...projectMetadata,
-// link: `/projects/${category}/${dirent.name}`,
-// } as ProjectMetadata & { link: string };
-// }),
-// );
-
-// return {
-// category: categoryMetadata,
-// projects: projectMetadata,
-// };
-// }
diff --git a/src/features/auth/ui/logout-button/logout-button.tsx b/src/features/auth/ui/logout-button/logout-button.tsx
index 25197db..4dbaedc 100644
--- a/src/features/auth/ui/logout-button/logout-button.tsx
+++ b/src/features/auth/ui/logout-button/logout-button.tsx
@@ -1,10 +1,11 @@
'use client';
+import { Dictionary } from '@/shared/config';
import { Button } from '@nextui-org/react';
import { RxExit } from 'react-icons/rx';
import { logout } from '../../services/logout';
-export const LogoutButton = () => {
+export const LogoutButton = ({ dict }: { dict: Dictionary['ui'] }) => {
return (
}
@@ -13,7 +14,7 @@ export const LogoutButton = () => {
size='sm'
onClick={async () => await logout()}
>
- Logout
+ {dict['auth-logout']}
);
};
diff --git a/src/features/locale-switcher/locale-switcher.tsx b/src/features/locale-switcher/locale-switcher.tsx
index 62c1869..0c04041 100644
--- a/src/features/locale-switcher/locale-switcher.tsx
+++ b/src/features/locale-switcher/locale-switcher.tsx
@@ -64,17 +64,5 @@ export const LocaleSwitcher = ({ dict }: { dict: Dictionary['ui'] }) => {
- //
- //
- //
);
};
diff --git a/src/mdx-components.tsx b/src/mdx-components.tsx
index 27f6e7d..5df89f5 100644
--- a/src/mdx-components.tsx
+++ b/src/mdx-components.tsx
@@ -1,18 +1,20 @@
import { Code, CodeBlock, StackVariants, Text } from '@/shared/ui';
import type { MDXComponents } from 'mdx/types';
+import { getDictionary } from './shared/config';
interface ExtendedCodeProps extends React.HTMLAttributes {
filename?: string;
- // [key: string]: any; // Для поддержки любых других пользовательских атрибутов
+ githubPath?: string;
}
export const MDXComponentsFormat: MDXComponents = {
- code: (props: ExtendedCodeProps) => {
+ code: async (props: ExtendedCodeProps) => {
const { children, className, ...rest } = props;
const match = /language-(\w+)/.exec(className || '');
+ const dict = await getDictionary();
if (!match) {
- return
;
+ return
;
}
return (
@@ -20,6 +22,10 @@ export const MDXComponentsFormat: MDXComponents = {
text={String(children)}
language={match[1] as StackVariants}
fileName={props?.filename}
+ dict={dict.ui}
+ github={{
+ path: props?.githubPath,
+ }}
{...rest}
/>
);
diff --git a/src/shared/config/i18n/dictionaries/en.json b/src/shared/config/i18n/dictionaries/en.json
index e67f37a..7580cde 100644
--- a/src/shared/config/i18n/dictionaries/en.json
+++ b/src/shared/config/i18n/dictionaries/en.json
@@ -11,6 +11,9 @@
"copy-code": "Copy code",
"copy-success": "Copied to clipboard",
"copy-error": "Failed to copy",
+ "code-show": "Show code",
+ "code-hide": "Hide",
+ "code-view-github": "View code on GitHub",
"footer-copyright": "Copyright © 2024 Mark Melior.",
"footer-made": "Made with ❤️",
"footer-edit": "Edit this page on GitHub",
@@ -18,6 +21,8 @@
"footer-next": "Next",
"navbar-title": "Simple App",
"navbar-desc": "Small and modern pet-projects",
- "change-lang": "Change language"
+ "change-lang": "Change language",
+ "auth-logged": "You have successfully logged in as an",
+ "auth-logout": "Logout"
}
}
diff --git a/src/shared/config/i18n/dictionaries/ru.json b/src/shared/config/i18n/dictionaries/ru.json
index 1559a56..ebca433 100644
--- a/src/shared/config/i18n/dictionaries/ru.json
+++ b/src/shared/config/i18n/dictionaries/ru.json
@@ -11,6 +11,9 @@
"copy-code": "Скопировать код",
"copy-success": "Скопировано в буфер обмена",
"copy-error": "Не удалось скопировать",
+ "code-show": "Показать код",
+ "code-hide": "Скрыть",
+ "code-view-github": "Посмотреть код на GitHub",
"footer-copyright": "Копирайт © 2024 Mark Melior.",
"footer-made": "Сделано с ❤️",
"footer-edit": "Редактировать страницу на GitHub",
@@ -18,6 +21,8 @@
"footer-next": "Далее",
"navbar-title": "Simple App",
"navbar-desc": "Небольшие и современные пет-проекты",
- "change-lang": "Сменить язык"
+ "change-lang": "Сменить язык",
+ "auth-logged": "Вы успешно вошли в систему как",
+ "auth-logout": "Выйти"
}
}
diff --git a/src/shared/config/i18n/get-lang.ts b/src/shared/config/i18n/get-lang.ts
index a42fd92..a016586 100644
--- a/src/shared/config/i18n/get-lang.ts
+++ b/src/shared/config/i18n/get-lang.ts
@@ -6,9 +6,19 @@ import { Locale, i18n } from './i18n.config';
export const getLang = async (): Promise => {
const pathname = await getPathname();
+ // // Получаем язык из куки, если она установлена
+ // const localeCookie = cookies().get('NEXT_LOCALE')?.value as Locale;
+
+ // // Если куки установлена и язык валиден, возвращаем его
+ // if (localeCookie && i18n.locales.includes(localeCookie)) {
+ // return localeCookie;
+ // }
+
const segment = pathname.split('/')[1] as Locale;
+ // Если сегмент URL валиден, возвращаем его
if (i18n.locales.includes(segment)) return segment;
+ // В противном случае возвращаем язык по умолчанию
return i18n.defaultLocale;
};
diff --git a/src/shared/config/i18n/link.tsx b/src/shared/config/i18n/link.tsx
new file mode 100644
index 0000000..4e3a95f
--- /dev/null
+++ b/src/shared/config/i18n/link.tsx
@@ -0,0 +1,46 @@
+'use client';
+
+import NextLink, { LinkProps as NextLinkProps } from 'next/link';
+import { FC } from 'react';
+import { UrlObject } from 'url';
+import { i18n } from './i18n.config';
+import { useLang } from './use-lang';
+
+interface LinkProps extends NextLinkProps {
+ children: React.ReactNode;
+}
+
+const isExternalLink = (href: string | UrlObject): boolean => {
+ return (
+ typeof href === 'string' &&
+ (href.startsWith('http://') || href.startsWith('https://'))
+ );
+};
+
+const getLocalizedHref = (
+ href: string | UrlObject,
+ lang: string,
+ defaultLocale: string,
+): string | UrlObject => {
+ if (isExternalLink(href) || typeof href !== 'string') {
+ return href;
+ }
+ return lang === defaultLocale ? href : `/${lang}${href}`;
+};
+
+export const Link: FC<
+ Omit, keyof LinkProps> &
+ LinkProps & {
+ children?: React.ReactNode;
+ } & React.RefAttributes
+> = ({ children, href, ...props }) => {
+ const lang = useLang();
+
+ const localizedHref = getLocalizedHref(href, lang, i18n.defaultLocale);
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/shared/config/i18n/use-dictionary.ts b/src/shared/config/i18n/use-dictionary.ts
new file mode 100644
index 0000000..df2119a
--- /dev/null
+++ b/src/shared/config/i18n/use-dictionary.ts
@@ -0,0 +1,37 @@
+'use client';
+
+import { useEffect, useState } from 'react';
+import { Dictionary } from './dictionaries';
+import { Locale } from './i18n.config';
+import { useLang } from './use-lang';
+
+export const useDictionary = (locale?: Locale): Dictionary | undefined => {
+ const dictionaries = {
+ en: () => import('./dictionaries/en.json').then((module) => module.default),
+ ru: () => import('./dictionaries/ru.json').then((module) => module.default),
+ };
+
+ const [dict, setDict] = useState();
+
+ const lang = useLang();
+
+ useEffect(() => {
+ dictionaries[locale || lang]?.().then(setDict);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [lang, locale]);
+
+ return dict as Dictionary;
+};
+
+// * The main logic is in getDictionary()
+// ! There are a lot of requests to the server
+// export const useDictionary = (locale?: Locale): Dictionary | undefined => {
+// const [dict, setDict] = useState();
+// const lang = useLang();
+
+// useEffect(() => {
+// getDictionary().then(setDict);
+// }, [lang, locale]);
+
+// return dict;
+// };
diff --git a/src/shared/config/i18n/use-lang.ts b/src/shared/config/i18n/use-lang.ts
new file mode 100644
index 0000000..c1b0a16
--- /dev/null
+++ b/src/shared/config/i18n/use-lang.ts
@@ -0,0 +1,26 @@
+'use client';
+
+import { usePathname } from 'next/navigation';
+import { Locale, i18n } from './i18n.config';
+
+export const useLang = (): Locale => {
+ const pathname = usePathname();
+
+ const segment = pathname.split('/')[1] as Locale;
+
+ if (i18n.locales.includes(segment)) return segment;
+
+ return i18n.defaultLocale;
+};
+
+// * The main logic is in getLang()
+// ! There are a lot of requests to the server
+// export const useLang = (): Locale => {
+// const [lang, setLang] = useState(i18n.defaultLocale);
+
+// useEffect(() => {
+// getLang().then(setLang);
+// }, []);
+
+// return lang;
+// };
diff --git a/src/shared/config/index.ts b/src/shared/config/index.ts
index 3e4373a..ea9d1d3 100644
--- a/src/shared/config/index.ts
+++ b/src/shared/config/index.ts
@@ -1,6 +1,9 @@
import { Dictionary, getDictionary } from './i18n/dictionaries';
import { getLang } from './i18n/get-lang';
import { i18n, Locale } from './i18n/i18n.config';
+import { Link } from './i18n/link';
+import { useDictionary } from './i18n/use-dictionary';
+import { useLang } from './i18n/use-lang';
-export { getDictionary, getLang, i18n };
+export { getDictionary, getLang, i18n, Link, useDictionary, useLang };
export type { Dictionary, Locale };
diff --git a/src/shared/hooks/useCopy/useCopy.tsx b/src/shared/hooks/useCopy/useCopy.tsx
index f055614..16ab43a 100644
--- a/src/shared/hooks/useCopy/useCopy.tsx
+++ b/src/shared/hooks/useCopy/useCopy.tsx
@@ -1,9 +1,11 @@
+import { useDictionary } from '@/shared/config';
import { useState } from 'react';
import { useMessage } from '../useMessage/useMessage';
export const useCopy = () => {
const { showMessage } = useMessage();
const [copied, setCopied] = useState(false);
+ const dict = useDictionary();
const handleCopy = (text: string) => {
if (copied) {
@@ -12,15 +14,18 @@ export const useCopy = () => {
try {
navigator.clipboard.writeText(text);
- showMessage({
- content: 'Copied to clipboard!',
- type: 'success',
- });
+
+ dict?.ui &&
+ showMessage({
+ content: dict.ui['copy-success'],
+ type: 'success',
+ });
} catch (err) {
- showMessage({
- content: 'Failed to copy!',
- type: 'error',
- });
+ dict?.ui &&
+ showMessage({
+ content: dict.ui['copy-error'],
+ type: 'error',
+ });
}
setCopied(true);
diff --git a/src/shared/types/github-path.ts b/src/shared/types/github-path.ts
index 3a7209c..88e0d6b 100644
--- a/src/shared/types/github-path.ts
+++ b/src/shared/types/github-path.ts
@@ -1,5 +1,5 @@
export interface GitHubPath {
- path: string;
+ path?: string;
owner?: string;
repo?: string;
}
diff --git a/src/shared/ui/code-block/code-block.tsx b/src/shared/ui/code-block/code-block.tsx
index 1fa3373..737fb1d 100644
--- a/src/shared/ui/code-block/code-block.tsx
+++ b/src/shared/ui/code-block/code-block.tsx
@@ -1,5 +1,6 @@
'use client';
+import { Dictionary } from '@/shared/config';
import { cn, gitHubRepoLink } from '@/shared/lib';
import { GitHubPath } from '@/shared/types/github-path';
import { Theme } from '@/shared/types/theme';
@@ -26,6 +27,7 @@ interface CodeBlockProps {
className?: string;
disableLineNumbers?: boolean;
showHeader?: boolean;
+ dict: Dictionary['ui'];
}
export const CodeBlock: FC = ({
@@ -37,6 +39,7 @@ export const CodeBlock: FC = ({
showHeader = true,
className,
disableLineNumbers,
+ dict,
}) => {
const [isExpanded, setIsExpanded] = useState(false);
const lines = text.split('\n');
@@ -61,7 +64,7 @@ export const CodeBlock: FC = ({
{fileName ? fileName : language}
{github?.path && (
-
+
)}
-
+
@@ -107,7 +110,7 @@ export const CodeBlock: FC = ({
onClick={() => setIsExpanded(!isExpanded)}
className='bg-default-100 text-default-600 py-2 px-3 w-full text-left data-[pressed=true]:scale-100 hover:bg-default-200'
>
- {isExpanded ? 'Hide' : 'Show more'}
+ {isExpanded ? dict['code-hide'] : dict['code-show']}
)}
diff --git a/src/shared/ui/code-block/code.tsx b/src/shared/ui/code-block/code.tsx
index 40fc81f..40b782f 100644
--- a/src/shared/ui/code-block/code.tsx
+++ b/src/shared/ui/code-block/code.tsx
@@ -1,5 +1,6 @@
'use client';
+import { Dictionary } from '@/shared/config';
import { useCopy } from '@/shared/hooks';
import { Button, Tooltip } from '@nextui-org/react';
import { FC } from 'react';
@@ -8,9 +9,14 @@ import { StackVariants } from '../stack-buttons/model/data';
interface CodeProps {
text: string;
language?: StackVariants;
+ dict: Dictionary['ui'];
}
-export const Code: FC = ({ text, language = 'TypeScript' }) => {
+export const Code: FC = ({
+ text,
+ dict,
+ language = 'TypeScript',
+}) => {
const { handleCopy } = useCopy();
// const [mounted, setMounted] = useState(false);
// const { theme } = useTheme();
@@ -20,7 +26,7 @@ export const Code: FC = ({ text, language = 'TypeScript' }) => {
// }, []);
return (
-
+