mirror of
https://github.com/sergeyyarkov/yarkov.tech.git
synced 2026-10-11 10:29:21 +03:00
fixed i18n
This commit is contained in:
parent
3f42730659
commit
c2523dd294
@ -1,8 +1,3 @@
|
|||||||
import { defineConfig } from "astro/config";
|
|
||||||
import { h } from "hastscript";
|
|
||||||
import { toString } from "hast-util-to-string";
|
|
||||||
import { escape } from "html-escaper";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integrations
|
* Integrations
|
||||||
*/
|
*/
|
||||||
@ -24,6 +19,14 @@ import remarkSmartypants from "remark-smartypants";
|
|||||||
import rehypeSlug from "rehype-slug";
|
import rehypeSlug from "rehype-slug";
|
||||||
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Other required modules
|
||||||
|
*/
|
||||||
|
import { defineConfig } from "astro/config";
|
||||||
|
import { h } from "hastscript";
|
||||||
|
import { toString } from "hast-util-to-string";
|
||||||
|
import { escape } from "html-escaper";
|
||||||
|
|
||||||
const createAnchorLabel = (heading) => {
|
const createAnchorLabel = (heading) => {
|
||||||
const node = h("span.anchor-label", escape(heading));
|
const node = h("span.anchor-label", escape(heading));
|
||||||
node.properties["is:raw"] = true;
|
node.properties["is:raw"] = true;
|
||||||
@ -41,11 +44,14 @@ export default defineConfig({
|
|||||||
locales: {
|
locales: {
|
||||||
ru: "ru",
|
ru: "ru",
|
||||||
en: "en",
|
en: "en",
|
||||||
|
de: "de",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
image(),
|
image(),
|
||||||
compress(),
|
compress({
|
||||||
|
img: false,
|
||||||
|
}),
|
||||||
mdx({
|
mdx({
|
||||||
remarkPlugins: [remarkGfm, remarkSmartypants],
|
remarkPlugins: [remarkGfm, remarkSmartypants],
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
|
|||||||
30
src/components/AlternateLangLink/AlternateLangLink.astro
Normal file
30
src/components/AlternateLangLink/AlternateLangLink.astro
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
/**
|
||||||
|
* This components is used in article layout to display links in alternative lanugages.
|
||||||
|
*/
|
||||||
|
import { DEFAULT_LANGUAGE } from "@root/config";
|
||||||
|
import { getLanguageFromURL } from "@root/utils";
|
||||||
|
|
||||||
|
export interface Props extends astroHTML.JSX.AnchorHTMLAttributes {
|
||||||
|
lang: LanguageKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { pathname } = Astro.url;
|
||||||
|
const siteLang = getLanguageFromURL(pathname);
|
||||||
|
const { lang, ...attrs } = Astro.props as Props;
|
||||||
|
let href: string;
|
||||||
|
if (lang === DEFAULT_LANGUAGE) {
|
||||||
|
href = `/${pathname.split("/").slice(2).join("/")}`;
|
||||||
|
} else {
|
||||||
|
href = `/${lang}/`;
|
||||||
|
if (siteLang !== DEFAULT_LANGUAGE) {
|
||||||
|
href += `${pathname.split("/").slice(2).join("/")}`;
|
||||||
|
} else {
|
||||||
|
href += `${pathname.split("/").slice(1).join("/")}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href={href} {...attrs}>
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
1
src/components/AlternateLangLink/index.ts
Normal file
1
src/components/AlternateLangLink/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from "./AlternateLangLink.astro";
|
||||||
@ -11,7 +11,7 @@ export type ArticleItemProps = {
|
|||||||
|
|
||||||
export const ArticleItem: Component<ArticleItemProps> = (props) => {
|
export const ArticleItem: Component<ArticleItemProps> = (props) => {
|
||||||
const isNonDefaultLanguage = props.data.lang && props.data.lang !== props.lang;
|
const isNonDefaultLanguage = props.data.lang && props.data.lang !== props.lang;
|
||||||
const hrefLangPrefix = props.data.lang && props.data.lang !== DEFAULT_LANGUAGE ? "/en" : "";
|
const hrefLangPrefix = props.data.lang && props.data.lang !== DEFAULT_LANGUAGE ? `/${props.data.lang}` : "";
|
||||||
return (
|
return (
|
||||||
<article class="article-item">
|
<article class="article-item">
|
||||||
<a
|
<a
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
import { Icon } from "astro-icon";
|
import { Icon } from "astro-icon";
|
||||||
import { DEFAULT_LANGUAGE } from "@root/config";
|
import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from "@root/config";
|
||||||
import languages from "@i18n/languages";
|
import languages from "@i18n/languages";
|
||||||
import { getLanguageFromURL } from "@root/utils";
|
import { getLanguageFromURL } from "@root/utils";
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ const lang = getLanguageFromURL(Astro.url.pathname);
|
|||||||
<Icon name="translate" width="21" height="21" />
|
<Icon name="translate" width="21" height="21" />
|
||||||
<select id="languageSelect" value={lang} aria-label="Select language">
|
<select id="languageSelect" value={lang} aria-label="Select language">
|
||||||
{
|
{
|
||||||
Object.entries(languages).map(([code]) => (
|
SUPPORTED_LANGUAGES.map((code) => (
|
||||||
<option value={code} selected={lang === code}>
|
<option value={code} selected={lang === code}>
|
||||||
<span>{code.toLocaleUpperCase()}</span>
|
<span>{code.toLocaleUpperCase()}</span>
|
||||||
</option>
|
</option>
|
||||||
@ -71,7 +71,15 @@ const lang = getLanguageFromURL(Astro.url.pathname);
|
|||||||
const changeLanguageHandler = (e) => {
|
const changeLanguageHandler = (e) => {
|
||||||
const newLang = e.target.value;
|
const newLang = e.target.value;
|
||||||
const pathname = window.location.pathname;
|
const pathname = window.location.pathname;
|
||||||
const url = newLang === DEFAULT_LANGUAGE ? pathname.slice(3) : `${newLang}${pathname}`;
|
let url;
|
||||||
|
|
||||||
|
if (lang !== DEFAULT_LANGUAGE) {
|
||||||
|
url = pathname.split("/").slice(2).join("/");
|
||||||
|
} else {
|
||||||
|
url = pathname.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLang !== DEFAULT_LANGUAGE) url = `${newLang}/${url}`;
|
||||||
|
|
||||||
/* Move user to articles page with new language */
|
/* Move user to articles page with new language */
|
||||||
if (window.location.pathname.includes("/blog/")) {
|
if (window.location.pathname.includes("/blog/")) {
|
||||||
|
|||||||
@ -3,6 +3,8 @@ export const DEFAULT_LANGUAGE: LanguageKeys = "ru";
|
|||||||
/* Show banner about website development */
|
/* Show banner about website development */
|
||||||
export const IS_SITE_UNDER_CONSTRUCTION = import.meta.env.IS_SITE_UNDER_CONSTRUCTION === "true" ? true : false;
|
export const IS_SITE_UNDER_CONSTRUCTION = import.meta.env.IS_SITE_UNDER_CONSTRUCTION === "true" ? true : false;
|
||||||
|
|
||||||
|
export const SUPPORTED_LANGUAGES: SupportedLanguages = ["ru", "en"];
|
||||||
|
|
||||||
export const SITE_METADATA: SiteMetadataType = {
|
export const SITE_METADATA: SiteMetadataType = {
|
||||||
title: "Sergey Yarkov",
|
title: "Sergey Yarkov",
|
||||||
name: "yarkov.tech",
|
name: "yarkov.tech",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
export default {
|
export default {
|
||||||
ru: "Русский",
|
ru: "Русский",
|
||||||
en: "English",
|
en: "English",
|
||||||
|
de: "Deutsch",
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { AstroGlobal, MDXInstance } from "astro";
|
import type { AstroGlobal, MDXInstance } from "astro";
|
||||||
import * as utils from "@utils/url";
|
import * as utils from "@utils/url";
|
||||||
import { DEFAULT_LANGUAGE } from "@root/config";
|
import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from "@root/config";
|
||||||
import languages from "./languages";
|
import languages from "./languages";
|
||||||
|
|
||||||
type TranslatedArticlesType = Record<string, Record<LanguageKeys, MDXInstance<ArticleType>> | Record<string, never>>;
|
type TranslatedArticlesType = Record<string, Record<LanguageKeys, MDXInstance<ArticleType>> | Record<string, never>>;
|
||||||
@ -21,7 +21,7 @@ export function formatArticlesByLangs(data: Record<string, MDXInstance<ArticleTy
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getLanguageKeys(): Array<string> {
|
export function getLanguageKeys(): Array<string> {
|
||||||
return Object.keys(languages);
|
return Object.keys(languages).filter((lang) => SUPPORTED_LANGUAGES.includes(lang as LanguageKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformExports<T>(modules: Record<string, { default: T }>) {
|
function transformExports<T>(modules: Record<string, { default: T }>) {
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
import type { MDXInstance } from "astro";
|
import type { MDXInstance } from "astro";
|
||||||
|
|
||||||
import ArticleLayout from "@layouts/article.astro";
|
import ArticleLayout from "@layouts/article.astro";
|
||||||
|
import AlternateLangLink from "@components/AlternateLangLink";
|
||||||
import { getLanguageFromURL } from "@root/utils";
|
import { getLanguageFromURL } from "@root/utils";
|
||||||
import { DEFAULT_LANGUAGE } from "@root/config";
|
import { DEFAULT_LANGUAGE } from "@root/config";
|
||||||
import { formatArticlesByLangs, useTranslation } from "@i18n/utils";
|
import { formatArticlesByLangs, useTranslation } from "@i18n/utils";
|
||||||
@ -37,8 +38,6 @@ const {
|
|||||||
article: { Content, frontmatter },
|
article: { Content, frontmatter },
|
||||||
alternateLangs,
|
alternateLangs,
|
||||||
} = Astro.props as Props;
|
} = Astro.props as Props;
|
||||||
|
|
||||||
const { pathname } = Astro.url;
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<ArticleLayout lang={siteLang} content={frontmatter} canonicalUrl={canonicalUrl.href}>
|
<ArticleLayout lang={siteLang} content={frontmatter} canonicalUrl={canonicalUrl.href}>
|
||||||
@ -48,11 +47,7 @@ const { pathname } = Astro.url;
|
|||||||
{t("article.availableOn")}:
|
{t("article.availableOn")}:
|
||||||
{alternateLangs
|
{alternateLangs
|
||||||
.filter((lang) => lang !== siteLang)
|
.filter((lang) => lang !== siteLang)
|
||||||
.map((lang) => (
|
.map((lang) => <AlternateLangLink lang={lang}>{languages[lang]}</AlternateLangLink>)
|
||||||
<a href={DEFAULT_LANGUAGE === lang ? `/${pathname.split("/").slice(2).join("/")}` : `/${lang}${pathname}`}>
|
|
||||||
{languages[lang]}
|
|
||||||
</a>
|
|
||||||
))
|
|
||||||
.reduce((prev, curr) => [prev, ", ", curr])}
|
.reduce((prev, curr) => [prev, ", ", curr])}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
---
|
---
|
||||||
import { SITE_METADATA } from "@root/config";
|
import type { MDXInstance } from "astro";
|
||||||
|
|
||||||
|
import { DEFAULT_LANGUAGE, SITE_METADATA } from "@root/config";
|
||||||
import PageLayout from "@layouts/default.astro";
|
import PageLayout from "@layouts/default.astro";
|
||||||
import PageHeading from "@components/PageHeading";
|
import PageHeading from "@components/PageHeading";
|
||||||
import SkillsList from "@components/SkillsList";
|
import SkillsList from "@components/SkillsList";
|
||||||
@ -11,7 +13,14 @@ import { useTranslation } from "@i18n/utils";
|
|||||||
|
|
||||||
const lang = getLanguageFromURL(Astro.url.pathname);
|
const lang = getLanguageFromURL(Astro.url.pathname);
|
||||||
const t = useTranslation(Astro);
|
const t = useTranslation(Astro);
|
||||||
const { Content } = await import(`../../content/about/${lang}/index.mdx`);
|
let markdown: MDXInstance<{}> | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
markdown = (await import(`../../content/about/${lang}/index.mdx`)) as MDXInstance<{}>;
|
||||||
|
} catch (error) {
|
||||||
|
markdown = (await import(`../../content/about/${DEFAULT_LANGUAGE}/index.mdx`)) as MDXInstance<{}>;
|
||||||
|
}
|
||||||
|
|
||||||
const { skills } = SITE_METADATA;
|
const { skills } = SITE_METADATA;
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -19,7 +28,7 @@ const { skills } = SITE_METADATA;
|
|||||||
<PageHeading heading={t("pageTitle.about")} />
|
<PageHeading heading={t("pageTitle.about")} />
|
||||||
<section>
|
<section>
|
||||||
<ArticleContent>
|
<ArticleContent>
|
||||||
<Content />
|
{markdown && <markdown.Content />}
|
||||||
</ArticleContent>
|
</ArticleContent>
|
||||||
<SkillsList>
|
<SkillsList>
|
||||||
{skills.map((block) => <SkillsBlock data={block} />)}
|
{skills.map((block) => <SkillsBlock data={block} />)}
|
||||||
|
|||||||
5
src/types/main.d.ts
vendored
5
src/types/main.d.ts
vendored
@ -17,6 +17,7 @@ declare global {
|
|||||||
|
|
||||||
type LanguageKeys = keyof typeof languages;
|
type LanguageKeys = keyof typeof languages;
|
||||||
type UIDictionaryKeys = keyof typeof uiKeys;
|
type UIDictionaryKeys = keyof typeof uiKeys;
|
||||||
|
type SupportedLanguages = LanguageKeys[];
|
||||||
|
|
||||||
type SiteMetadataType = {
|
type SiteMetadataType = {
|
||||||
title: string;
|
title: string;
|
||||||
@ -52,14 +53,14 @@ declare global {
|
|||||||
icon: string;
|
icon: string;
|
||||||
name: string;
|
name: string;
|
||||||
year: string;
|
year: string;
|
||||||
description: Record<LanguageKeys, string>;
|
description: Record<string, string>;
|
||||||
sourceUrl?: string | undefined;
|
sourceUrl?: string | undefined;
|
||||||
articleUrl?: string | undefined;
|
articleUrl?: string | undefined;
|
||||||
demoUrl?: string | undefined;
|
demoUrl?: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SkillsType = {
|
type SkillsType = {
|
||||||
title: Record<LanguageKeys, string>;
|
title: Record<string, string>;
|
||||||
list: Array<{
|
list: Array<{
|
||||||
icon?: string | undefined;
|
icon?: string | undefined;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@ -12,3 +12,7 @@ export const getLanguageFromURL = (pathname: string): LanguageKeys => {
|
|||||||
if (Object.hasOwn(languages, lang)) return lang;
|
if (Object.hasOwn(languages, lang)) return lang;
|
||||||
return DEFAULT_LANGUAGE;
|
return DEFAULT_LANGUAGE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const removeLangFromURL = (pathname: string): string => {
|
||||||
|
return pathname.split("/").slice(2).join("/");
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user