translate pages

This commit is contained in:
Sergey Yarkov 2023-02-18 14:09:31 +03:00
parent cb0ae84515
commit c311050b65
No known key found for this signature in database
GPG Key ID: E91CE1FABC619B6F
11 changed files with 108 additions and 100 deletions

View File

@ -1,5 +1,9 @@
---
import Button from "@components/Button.astro";
import UIString from "./UIString.astro";
import { useTranslation } from "@i18n/utils";
const t = useTranslation(Astro);
---
<form name="contact" method="post" netlify-honeypot="bot-field" data-netlify="true">
@ -9,17 +13,44 @@ import Button from "@components/Button.astro";
</div>
<div class="flex">
<div>
<input name="name" placeholder={"Имя"} type="text" maxlength="20" autocomplete="off" required />
<input
name="name"
placeholder={t("input.nameField")}
type="text"
maxlength="20"
autocomplete="off"
required
/>
</div>
<div>
<input name="email" placeholder="example@email.com" autocomplete="off" type="email" required />
<input
name="email"
placeholder="example@email.com"
autocomplete="off"
type="email"
required
/>
</div>
</div>
<input name="subject" placeholder={"Тема"} type="text" autocomplete="off" required />
<textarea name="message" placeholder={"Сообщение"} id="message" autocomplete="off" cols={30} rows={10} required
></textarea>
<input
name="subject"
placeholder={t("input.subjectField")}
type="text"
autocomplete="off"
required
/>
<textarea
name="message"
placeholder={t("input.messageField")}
id="message"
autocomplete="off"
cols={30}
rows={10}
required></textarea>
<div class="footer">
<Button type="submit">{"Отправить"}</Button>
<Button type="submit">
<UIString key={"btn.submit"} />
</Button>
</div>
</form>

View File

@ -1,59 +1,47 @@
---
import { SITE_METADATA } from "@root/constants";
import { Icon } from "astro-icon";
import TranslatedLink from "./TranslatedLink.astro";
import UIString from "./UIString.astro";
const date = new Date();
---
<footer>
<div class="container">
<ul>
<li>
<a href="https://astro.build/" target="_blank">Astro</a>
<Icon name="astro" width="20" height="20" />
</li>
<li>
<a href="https://www.netlify.com/" target="_blank">Netlify</a>
<Icon name="netlify" width="20" height="20" />
</li>
<li>
<a href="/rss.xml" target="_blank">RSS</a>
<div>
<i>
Разработка: <TranslatedLink to="/contacts">{SITE_METADATA.author}</TranslatedLink>
&copy; {date.getFullYear()}
</i>
</div>
<div>
<a href="/rss.xml" target="_blank"><UIString key={"rss.feed"} /></a>
<span>
<Icon name="rss" width="20" height="20" />
</li>
</ul>
<small>© Sergey Yarkov, {date.getFullYear()}</small>
</span>
</div>
</div>
</footer>
<style lang="scss">
footer {
user-select: none;
text-align: center;
font-weight: 500;
margin-top: 5rem;
color: var(--color-gray-200);
font-size: var(--font-size-sm);
& .container {
padding: 25px 0 10px 0;
padding: 15px 0 15px 0;
border-top: 1px solid var(--border-color);
display: flex;
flex-direction: column;
align-items: center;
row-gap: 15px;
}
& ul {
display: flex;
align-items: center;
column-gap: 25px;
& li {
justify-content: space-between;
& div:last-child {
display: flex;
align-items: center;
column-gap: 7px;
& a {
color: var(--font-color);
font-size: var(--font-size-sm);
margin-right: 0.25rem;
}
}
}
& small {
text-align: center;
font-size: var(--font-size-xs);
}
}
</style>

View File

@ -23,7 +23,7 @@ import TranslatedLink from "@components/TranslatedLink.astro";
<TranslatedLink
itemprop={"url"}
to={link.url}
class:list={[{ active: link.url === Astro.url.pathname }]}
class:list={[{ active: Astro.url.pathname.includes(link.url) }]}
>
<UIString key={link.key} />
</TranslatedLink>

View File

@ -1,6 +1,6 @@
---
import { Icon } from "astro-icon";
// import TranslatedLink from "@components/TranslatedLink";
import TranslatedLink from "@components/TranslatedLink.astro";
export interface Props {
icon: string;
@ -12,9 +12,9 @@ const { icon, href } = Astro.props as Props;
<div>
<Icon name={icon} width="18" height="18" />
<a href={href}>
<TranslatedLink to={href}>
<slot />
</a>
</TranslatedLink>
</div>
<style lang="scss">

View File

@ -16,7 +16,8 @@ export default {
/* Page descriptions */
"pageDescription.articles":
"Technical articles, tutorials and various reference materials related to IT topics can be found here.",
"pageDescription.projects": "A few of my main projects that have been developed and published in open access.",
"pageDescription.projects":
"A few of my main projects that have been developed and published in open access.",
"pageDescription.contacts": "Use the feedback form or write to me on social networks.",
/* Navigation */
"navigation.articles": "Articles",
@ -52,4 +53,6 @@ export default {
"form.contactError": "An error occurred while sending. Please try again later.",
/* Error messages */
"error.invalidEmail": "Fill in the field in the e-mail format.",
/* Other */
"rss.feed": "RSS Feed",
};

View File

@ -16,8 +16,10 @@ export default {
/* Page descriptions */
"pageDescription.articles":
"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь.",
"pageDescription.projects": "Несколько моих основных проектов которые были разработаны и выложены в открытый доступ.",
"pageDescription.contacts": "Воспользуйтесь формой обратной связи или напишите мне в социальные сети.",
"pageDescription.projects":
"Несколько моих основных проектов которые были разработаны и выложены в открытый доступ.",
"pageDescription.contacts":
"Воспользуйтесь формой обратной связи или напишите мне в социальные сети.",
/* Navigation */
"navigation.articles": "Статьи",
"navigation.projects": "Проекты",
@ -52,4 +54,6 @@ export default {
"form.contactError": "При отправке произошла ошибка. Повторите запрос позже.",
/* Error messages */
"error.invalidEmail": "Заполните поле в формате e-mail.",
/* Other */
"rss.feed": "RSS Лента",
};

View File

@ -2,13 +2,9 @@ import type { AstroGlobal } from "astro";
import { DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES } from "@root/constants";
import languages from "./languages";
function transformExports<T>(modules: Record<string, { default: T }>): Record<string, string> {
const translations: Record<string, T> = {};
for (const [path, module] of Object.entries(modules)) {
const [, lang] = path.split("/");
translations[lang] = module.default;
}
return translations;
export function useTranslation(Astro: Readonly<AstroGlobal>): (key: UIDictionaryKeys) => string {
const pageLang = getLanguageFromURL(Astro.url.pathname);
return (key: UIDictionaryKeys) => translate(key, pageLang);
}
export function getLanguageKeys(): Array<string> {
@ -27,19 +23,21 @@ export function removeLangFromURL(pathname: string): string {
return pathname.split("/").slice(2).join("/");
}
const translations = transformExports(import.meta.glob("./*/ui.ts", { eager: true }));
function transformExports<T>(modules: Record<string, { default: T }>) {
const translations: Record<string, T> = {};
for (const [path, module] of Object.entries(modules)) {
const [, lang] = path.split("/");
translations[lang as LanguageKeys] = module.default;
}
return translations;
}
const s = translations["ru"];
const translations = transformExports<Record<string, UIDictionaryKeys>>(
import.meta.glob("./*/ui.ts", { eager: true })
);
function translate(key: UIDictionaryKeys, lang: LanguageKeys): string | undefined {
function translate(key: UIDictionaryKeys, lang: LanguageKeys): string {
const value = translations[lang]?.[key] || translations[DEFAULT_LANGUAGE][key];
if (value === undefined) console.log(`Cannot find any string for translation key "${key}".`);
return value;
}
export function useTranslation(
Astro: Readonly<AstroGlobal>
): (key: UIDictionaryKeys) => string | undefined {
const pageLang = getLanguageFromURL(Astro.url.pathname);
return (key: UIDictionaryKeys) => translate(key, pageLang);
}

View File

@ -1,6 +1,6 @@
---
import { getCollection, getEntryBySlug } from "astro:content";
import { getLanguageFromURL } from "@i18n/utils";
import { getLanguageFromURL, useTranslation } from "@i18n/utils";
import PageLayout from "@layouts/default.astro";
import PageHeading from "@components/PageHeading.astro";
import SkillsList from "@components/SkillsList.astro";
@ -11,12 +11,11 @@ const pageLang = getLanguageFromURL(Astro.url.pathname);
const skills = await getCollection("skills", (e) => e.id.startsWith(`${pageLang}/`));
const about = await getEntryBySlug("authors", `${pageLang}/сергей-ярков`);
const data = await about?.render();
// const t = useTranslation(Astro);
const t = useTranslation(Astro);
---
<PageLayout noIndex lang={pageLang} title={"Обо мне"}>
<PageHeading heading={"Обо мне"} />
<PageLayout noIndex lang={pageLang} title={t("pageTitle.about")}>
<PageHeading heading={t("pageTitle.about")} />
<section>
<ArticleContent>
{data && <data.Content />}

View File

@ -1,29 +1,20 @@
---
import PageLayout from "@layouts/default.astro";
import PageHeading from "@components/PageHeading.astro";
// import ArticlesList from "@components/ArticlesList";
// import * as utils from "@utils/articles";
import { getLanguageFromURL } from "@i18n/utils";
// import { useTranslation } from "@i18n/utils";
// import * as API from "@root/lib/api";
// const t = useTranslation(Astro);
// const data = API.fetchTranslatedArticles(Astro);
// const tags = new Set(data.map((article) => article.frontmatter.tags).flat());
const lang = getLanguageFromURL(Astro.url.pathname);
// const articles = utils.transformArticles(data);
import { useTranslation, getLanguageFromURL } from "@i18n/utils";
const t = useTranslation(Astro);
const pageLang = getLanguageFromURL(Astro.url.pathname);
const canonicalUrl = new URL(Astro.url.pathname, Astro.site);
---
<PageLayout
lang={lang}
title={"Статьи"}
description={"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь."}
lang={pageLang}
title={t("pageTitle.articles")}
description={t("pageDescription.articles")}
canonicalUrl={canonicalUrl.href}
>
<PageHeading
heading={"Статьи"}
description={"Технические статьи, туториалы и различные справочные материалы которые связаны с IT тематикой находятся здесь."}
/>
<PageHeading heading={t("pageTitle.articles")} description={t("pageDescription.articles")} />
<section>
...
<!-- <ArticlesList

View File

@ -3,21 +3,18 @@ import PageLayout from "@layouts/default.astro";
import PageHeading from "@components/PageHeading.astro";
import ContactForm from "@components/ContactForm.astro";
import ContactsList from "@components/ContactsList.astro";
import { getLanguageFromURL } from "@i18n/utils";
// const t = useTranslation(Astro);
import { getLanguageFromURL, useTranslation } from "@i18n/utils";
const t = useTranslation(Astro);
const lang = getLanguageFromURL(Astro.url.pathname);
---
<PageLayout
noIndex
lang={lang}
title={"Контакты"}
description={"Воспользуйтесь формой обратной связи или напишите мне в социальные сети."}
title={t("pageTitle.contacts")}
description={t("pageDescription.contacts")}
>
<PageHeading
heading={"Контакты"}
description={"Воспользуйтесь формой обратной связи или напишите мне в социальные сети."}
/>
<PageHeading heading={t("pageTitle.contacts")} description={t("pageDescription.contacts")} />
<section>
<ContactForm />
<ContactsList />

View File

@ -4,9 +4,9 @@ import PageLayout from "@layouts/default.astro";
import ProjectsList from "@components/ProjectsList.astro";
import ProjectItem from "@components/ProjectItem.astro";
import PageHeading from "@components/PageHeading.astro";
import { getLanguageFromURL } from "@i18n/utils";
import { getLanguageFromURL, useTranslation } from "@i18n/utils";
// const t = useTranslation(Astro);
const t = useTranslation(Astro);
const pageLang = getLanguageFromURL(Astro.url.pathname);
const projects = (await getCollection("projects", (e) => e.slug.startsWith(`${pageLang}/`))).sort(
(a, b) => b.data.year - a.data.year
@ -16,13 +16,10 @@ const projects = (await getCollection("projects", (e) => e.slug.startsWith(`${pa
<PageLayout
noIndex
lang={pageLang}
title={"Проекты"}
description={"Несколько моих основных проектов которые были разработаны и выложены в открытый доступ."}
title={t("pageTitle.projects")}
description={t("pageDescription.projects")}
>
<PageHeading
heading={"Проекты"}
description={"Несколько моих основных проектов которые были разработаны и выложены в открытый доступ."}
/>
<PageHeading heading={t("pageTitle.projects")} description={t("pageDescription.projects")} />
<section>
<ProjectsList>
{projects.map((project) => <ProjectItem data={project.data} />)}