• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Astro Internalization With Dynamic Routing

Lomanu4 Оффлайн

Lomanu4

Команда форума
Администратор
Регистрация
1 Мар 2015
Сообщения
1,481
Баллы
155
Table of Contents

  1. About The Project
    • Built With
  2. How To Implement
    • Project Structure
    • Translation Files
    • Set Language Endpoint
    • Language Middleware
    • Disable Prerendering
    • Add Dynamic Routing
    • Add Components
    • Call Set Language Endpoint
    • Final
  3. Resources
  4. GitHub Link
About The Project


This project demonstrates an alternative approach to internationalization in Astro using dynamic routing and cookies. While disabling prerendering is not generally recommended, it is necessary on pages that rely on cookies for language detection. This method also doesn't prevent use of alternative translation methods.

You can also check libraries like

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

,

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

.

(back to top)

Built With


(back to top)

How To Implement

Project Structure



Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.



Configure Astro


First lets start with configuration. We have to define i18n settings. I used Turkish and English languages for my project and default locale for my website was Turkish. Also for this project Turkish language have been designated as fallback language.

Routing is set to manual. While options like prefixDefaultLocale are available, manual routing combined with middleware is easier to manage in this setup.

astro.config.mjs


import { defineConfig } from "astro/config";
import vue from "@astrojs/vue";
import tailwind from "@astrojs/tailwind";

//

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.


export default defineConfig({
i18n: {
locales: ["tr", "en"],
defaultLocale: "tr",
fallback: {
en: "tr",
},
routing: "manual",
},
integrations: [
vue(),
tailwind({
applyBaseStyles: false,
}),
],
});
Translation Files


After some configuration we have to create our translation methods and files. The functions are straightforward. We get translations from json files and from the url we decide which language to use.

src/translate/index.ts


import tr from "./tr.json";
import en from "./en.json";

export const supportedLangues = ["en", "tr"];
export const defaultLang = "tr";

export const translations = {
en,
tr,
} as const;

export function getLangFromUrl(url: URL) {
const lang = url.pathname.split("/").at(1)!;
if (lang in translations) return lang as keyof typeof translations;
return defaultLang;
}

function useTranslations(lang: keyof typeof translations) {
return function t(key: keyof (typeof translations)[typeof defaultLang]) {
return key in translations[lang]
? (translations[lang] as any)[key]
: translations[defaultLang][key];
};
}

export function getTranslation(url: URL) {
const lang = getLangFromUrl(url);
return useTranslations(lang);
}

src/translate/en.json


{
"hello": "Hello world"
}
Set Language Endpoint


To hold user language preference I used cookies. Create an endpoint to set language cookie.

src/pages/api/set-language.ts


import type { APIRoute } from "astro";

export const prerender = false;

export const POST: APIRoute = async ({ cookies, request }) => {
const language = await request.text();

cookies.set("language", language, {
httpOnly: true,
sameSite: "strict",
path: "/",
});

return new Response("", { status: 200 });
};
Language Middleware


The middleware determines which endpoint the user should be redirected to. First we check language cookie to find if user has set a language. If cookie is undefined than we check preferredLocale from the request. If both language cookie and preferredLocale is undefined user will be redirected to default language.

You should also not interrupt the requests that are not require language redirection (Like API request, asset requests etc.). So we added ignorPath function.

src/middleware/index.ts


import { sequence } from "astro:middleware";
import { languageMiddleware } from "./language.middleware";

export const onRequest = sequence(languageMiddleware);

src/middleware/language.middleware.ts


import { defineMiddleware } from "astro:middleware";
import { redirectToDefaultLocale } from "astro:i18n"; // function available with `manual` routing
import { supportedLangues } from "../translate";

export const languageMiddleware = defineMiddleware((ctx, next) => {
const pathName = ctx.url.pathname;

if (ignorePath(pathName)) {
return next();
}

let cookieLang = ctx.cookies.get("language")?.value;

if (!cookieLang && ctx.preferredLocale) {
cookieLang = ctx.preferredLocale;
}

if (cookieLang && supportedLangues.includes(cookieLang)) {
return ctx.redirect(`/${cookieLang}/${pathName}`, 302);
}

return redirectToDefaultLocale(ctx, 302);
});

function ignorePath(pathName: string) {
const ignoredPaths = [
...supportedLangues.map((lang) => `/${lang}`),
"/api",
"/assets",
"/static",
"/.",
];

return ignoredPaths.some((ignoredPath) => pathName.startsWith(ignoredPath));
}
Disable Prerendering


You have to disable prerending in pages that you want to get language preference from cookies.

src/pages/index.astro


---
export const prerender = false;
---
Add Dynamic Routing


Finally we have to add dynamic routing for creating multiple versions of pages. Create a [locale] folder under the pages and add your other pages that requires translation.

src/pages/[locale]/index.astro


---
import Layout from "@pw/layouts/Layout.astro";

export const prerender = false;

export async function getStaticPaths() {
return [{ params: { locale: "en" } }, { params: { locale: "tr" } }];
}
---

<Layout title="Mete ARSLAN" />
Add Components


I also added simple Layout.astro component for this project. There is a default slot for rendering page content and named slots for header, footer components.

src/layouts/Layout.astro


---
import DefaultFooter from "@pw/components/astro/footers/DefaultFooter.astro";
import DefaultHeader from "@pw/components/astro/headers/DefaultHeader.astro";
import "@pw/styles/main.scss";

interface Props {
title: string;
}

const { title } = Astro.props;
---

<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content="Astro description" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<header>
<slot name="header">
<DefaultHeader />
</slot>
</header>
<main>
<slot />
</main>
<footer>
<slot name="footer">
<DefaultFooter />
</slot>
</footer>
</body>
</html>

To get translation call getTranslation function that we have created and give page's url to it. For this example I also passed targetLanguage as a parameter to a vue component for being able to swap between the languages. You can also use other frameworks or simply add inline javascript to Astro components.

src/components/astro/headers/DefaultHeader.astro


---
import { LanguageSwapButton } from "@pw/vue-components";
import { getTranslation } from "@pw/translate";

const translate = getTranslation(Astro.url);

const currentLanguage =
Astro.cookies.get("language")?.value || Astro.preferredLocale || "tr"; // Default to "tr" if cookie is not set
const targetLanguage = currentLanguage === "en" ? "tr" : "en";
---

<div>
<LanguageSwapButton client:load targetLanguage={targetLanguage}>
<pre>{translate('hello')}</pre>
</LanguageSwapButton>
</div>
Call Set Language Endpoint


To change the language, send a request to /api/set-language.

src/components/vue/buttons/LanguageSwapButton.vue


<script lang="ts" setup>
import Button from "../shadcn/buttons/Button.vue";

const { targetLanguage } = defineProps({
targetLanguage: {
type: String,
required: true,
},
});

async function onClick() {
await fetch(`/api/set-language`, {
method: "POST",
headers: { "Content-Type": "application/text" },
body: targetLanguage,
});

window.location.href = "/" + targetLanguage;
}
</script>

<template>
<Button variant="outline" size="sm" @click="onClick()">
<slot />
</Button>
</template>

(back to top)

Resources


(back to top)


Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.




Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу