Kielialueen tunnistus ja alihakemistoreititys middlewaressa
Tunnistakaa käyttäjän kielialue ja uudelleenkirjoittakaa pyynnöt lokalisoituihin alihakemistoihin middlewaressa.
Kielialueen tunnistus ja alihakemistoreititys middlewaressa on ilmainen Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Next.js 15 -fullstack-kehitys (App Router + Server Actions)-kurssilla on yhteensä 4 oppituntia.
Mitä lokaalin automaattinen tunnistus tarkoittaa
Next.js 15:n kansainvälistäminen (i18n) alkaa locale-tunnistuksesta: selvitetään, minkä kielen ja alueen kävijä haluaa, ennen kuin hänelle tarjotaan sisältöä.
Tunnistus lukee tiedot yleensä kolmesta lähteestä seuraavassa tärkeysjärjestyksessä:
- URL-polku —
/en/about,/tr/about(selkein) - Cookie — aiemmin tallennettu asetus, kuten
NEXT_LOCALE=fr - Accept-Language-otsake — selaimen lähettämä automaattisesti
Next.js 15 poisti sisäänrakennetun i18n-määrityksen App Routerin aikakaudella, joten toteutatte tämän logiikan itse middleware-koodissa. Näin saatte täyden hallinnan vastaavuussäännöistä, varavaihtoehdoista ja uudelleenohjauksista.
Projektin määritys: tuetut localet
Ennen middleware-koodin kirjoittamista määrittäkää tuetut localet ja oletuslocale jaetussa vakiotiedostossa. Tämä keskitetty totuuden lähde tuodaan middleware-koodiin, layout-komponentteihin ja kaikkiin locale-tietoisiin apuohjelmiin.
Yleinen käytäntö on lib/i18n.ts-tiedosto, joka vie käyttöön seuraavat:
locales— kaikkien tuettujen locale-merkkijonojen luettelodefaultLocale— varavaihtoehto, kun vastaavuutta ei löydy- Apumäärittely tyyppiturvallisia locale-arvoja varten
// lib/i18n.ts
export const locales = ['en', 'tr', 'de', 'fr'] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = 'en';
export function isValidLocale(value: string): value is Locale {
return (locales as readonly string[]).includes(value);
}Accept-Language-otsakkeen jäsentäminen
Accept-Language-otsakkeen, joka voi olla esimerkiksi tr-TR,tr;q=0.9,en;q=0.8. Teidän on jäsennettävä se ja löydettävä paras vastaavuus tuettujen localejen joukosta.
Kokonaisen jäsentimen kirjoittamisen sijaan suosittu @formatjs/intl-localematcher-kirjasto hoitaa painotetun neuvottelun oikein. Yhdistäkää se negotiator-kirjastoon, jotta voitte muodostaa järjestetyn luettelon raakaotsakkeen merkkijonosta.
Asentakaa molemmat paketit:
npm i @formatjs/intl-localematcher negotiatornpm i -D @types/negotiator
// lib/locale-detection.ts
import Negotiator from 'negotiator';
import { match } from '@formatjs/intl-localematcher';
import { locales, defaultLocale, type Locale } from './i18n';
export function getLocaleFromHeader(acceptLanguage: string | null): Locale {
if (!acceptLanguage) return defaultLocale;
const headers = { 'accept-language': acceptLanguage };
const languages = new Negotiator({ headers }).languages();
try {
return match(languages, [...locales], defaultLocale) as Locale;
} catch {
return defaultLocale;
}
}Locale-cookien lukeminen
Kun käyttäjä vaihtaa kielen manuaalisesti, tallennatte valinnan cookieen, jotta tulevilla käynneillä sitä noudatetaan heti — Accept-Language-otsaketta ei tarvitse lukea uudelleen.
Middleware-koodissa luette cookiet suoraan saapuvasta NextRequest-pyynnöstä. Cookien nimenä käytetään yleensä nimeä NEXT_LOCALE, mutta voitte käyttää mitä tahansa nimeä, kunhan käytätte sitä johdonmukaisesti myös cookiea kirjoitettaessa (tämä tehdään yleensä Server Actionissa tai API-reitillä).
Tunnistuksen tärkeysjärjestyksen tulisi olla: ensin cookie, sitten otsake ja lopuksi oletus.
// lib/locale-detection.ts (continued)
import { type NextRequest } from 'next/server';
import { isValidLocale, defaultLocale, type Locale } from './i18n';
import { getLocaleFromHeader } from './locale-detection';
export const LOCALE_COOKIE = 'NEXT_LOCALE';
export function detectLocale(request: NextRequest): Locale {
// 1. Check explicit cookie preference
const cookieValue = request.cookies.get(LOCALE_COOKIE)?.value;
if (cookieValue && isValidLocale(cookieValue)) {
return cookieValue;
}
// 2. Negotiate from Accept-Language header
const acceptLanguage = request.headers.get('accept-language');
return getLocaleFromHeader(acceptLanguage);
}Alipolkujen reitityskäytäntö
Alipolkujen reititys tarkoittaa, että jokaisen URL-osoitteen alussa on locale: /en/dashboard, /tr/dashboard, /de/dashboard. Tämä lähestymistapa on:
- hakukoneystävällinen — hakukoneet indeksoivat jokaisen lokalen erillisenä URL-osoitteena
- helposti jaettava — linkki osoittaa aina samaan localeen
- välimuistissa säilytettävä — CDN voi tallentaa kunkin lokalen erikseen ilman cookien tarkistamista
App Routerin kansiorakenne vastaa tätä:
app/[lang]/page.tsx— kunkin lokalen kotisivuapp/[lang]/layout.tsx— locale-tietoinen juurilayoutapp/[lang]/dashboard/page.tsx— sisäkkäiset reitit
[lang]-dynaaminen segmentti poimii locale-merkkijonon URL-osoitteesta.
Middlewaren kirjoittaminen: peruslogiikka
Projektin juurihakemistossa oleva middleware.ts-tiedosto sieppaa jokaisen pyynnön. Sen tehtävänä on:
- ohittaa pyynnöt, joissa on jo kelvollinen locale-etuliite, ja tarjota ne sellaisinaan
- tunnistaa locale pyynnöistä, joissa ei ole locale-etuliitettä, ja tehdä uudelleenohjaus lokalisoituun URL-osoitteeseen
Käyttäkää NextResponse.redirect-menetelmää (pysyvä 308 SEO-tarkoituksiin tai väliaikainen 307 dynaamisia asetuksia varten) tai NextResponse.rewrite-menetelmää (piilottaa etuliitteen selaimen osoiteriviltä — alipolkujen reitityksessä harvinaisempi).
// middleware.ts
import { NextResponse, type NextRequest } from 'next/server';
import { locales, defaultLocale, isValidLocale } from './lib/i18n';
import { detectLocale } from './lib/locale-detection';
export function middleware(request: NextRequest): NextResponse {
const { pathname } = request.nextUrl;
// Check if the path already starts with a valid locale
const pathnameLocale = locales.find(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
);
if (pathnameLocale) {
// Already localized — pass through
return NextResponse.next();
}
// Detect locale and redirect
const locale = detectLocale(request);
const newUrl = new URL(`/${locale}${pathname}`, request.url);
newUrl.search = request.nextUrl.search; // preserve query params
return NextResponse.redirect(newUrl, { status: 307 });
}matcher-määritys: staattisten resurssien poissulkeminen
Ilman matcher-määritystä middleware suoritetaan jokaiselle pyynnölle — myös pyynnöille, jotka koskevat polkuja /_next/static ja /favicon.ico, sekä API-reiteille. Tämä tuhlaa laskentaresursseja ja voi rikkoa staattisten resurssien toimituksen.
Viekää käyttöön config-objekti, jossa on matcher-taulukko, ja rajoittakaa sen avulla middleware-koodin käsittelemät polut. Alla oleva kuvio sulkee pois:
- Next.js:n sisäiset polut (
/_next) - staattisten tiedostojen päätteet (kuvat, fontit ja manifestit)
- API-reitit, jos käsittelette niiden i18n:n erikseen
// middleware.ts (add at the bottom)
export const config = {
matcher: [
/*
* Match all request paths EXCEPT:
* - _next/static (static files)
* - _next/image (image optimization)
* - favicon.ico, sitemap.xml, robots.txt
* - Files with extensions (e.g. .png, .svg, .woff2)
*/
'/((?!_next/static|_next/image|favicon\.ico|sitemap\.xml|robots\.txt|.*\.(?:png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|otf|webp)).*)',
],
};[lang]-layout: lokalen välittäminen eteenpäin
Kun middleware takaa, että jokaisessa URL-osoitteessa on locale-etuliite, app/[lang]/layout.tsx vastaanottaa params.lang-arvon propina. Käyttäkää sitä seuraaviin tarkoituksiin:
- määrittäkää
lang-attribuutti elementille<html>esteettömyttä ja hakukoneoptimointia varten - määrittäkää RTL-kielille
dir-attribuutti (arabia, heprea) - ladatkaa oikea käännössanakirja
Next.js 15:ssä layout-parametrit ovat nyt asynkronisia — teidän on tehtävä await params ennen ominaisuuksien lukemista.
// app/[lang]/layout.tsx
import { type Locale, isValidLocale, defaultLocale } from '@/lib/i18n';
import { getDictionary } from '@/lib/dictionaries';
interface RootLayoutProps {
children: React.ReactNode;
params: Promise<{ lang: string }>;
}
export default async function RootLayout({ children, params }: RootLayoutProps) {
const { lang } = await params;
const locale: Locale = isValidLocale(lang) ? lang : defaultLocale;
const dict = await getDictionary(locale);
return (
<html lang={locale} dir={locale === 'ar' ? 'rtl' : 'ltr'}>
<body>{children}</body>
</html>
);
}Käännössanakirjojen lataaminen
S anakirja on JSON-tiedosto, joka sisältää kaikki yhden lokalen käännetyt merkkijonot. Kun sanakirjat ladataan laiskasti (yksi tiedosto localea kohden), alkuperäinen bundle pysyy pienenä — vain aktiivisen lokalen merkkijonot haetaan.
getDictionary-funktio käyttää dynaamista import()-kutsua, jotta Next.js voi jakaa kunkin lokalen build-aikana omaksi chunkikseen.
// lib/dictionaries.ts
import type { Locale } from './i18n';
const dictionaries = {
en: () => import('../dictionaries/en.json').then((m) => m.default),
tr: () => import('../dictionaries/tr.json').then((m) => m.default),
de: () => import('../dictionaries/de.json').then((m) => m.default),
fr: () => import('../dictionaries/fr.json').then((m) => m.default),
};
export type Dictionary = Awaited<ReturnType<(typeof dictionaries)['en']>>;
export async function getDictionary(locale: Locale): Promise<Dictionary> {
return dictionaries[locale]();
}
// dictionaries/en.json (example shape)
// {
// "nav": { "home": "Home", "about": "About" },
// "hero": { "title": "Welcome", "subtitle": "Start learning today" }
// }Käyttäjän locale-asetuksen tallentaminen Server Actionilla
Kun käyttäjä valitsee kielenvaihtajan käyttöliittymästä toisen kielen, tallentakaa valinta cookieen Server Action-toiminnolla. Seuraavassa pyynnössä cookie on tällöin saatavilla middleware-koodissa ja ohittaa Accept-Language-otsakkeen.
Käyttäkää next/headers-moduulin cookies()-funktiota Server Actionin sisällä. Kun olette asettaneet cookien, kutsukaa redirect()-funktiota siirtyäksenne samalle polulle uuden lokalen alla.
// app/actions/set-locale.ts
'use server';
import { cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { isValidLocale, type Locale } from '@/lib/i18n';
import { LOCALE_COOKIE } from '@/lib/locale-detection';
export async function setLocaleAction(
locale: string,
currentPath: string
): Promise<void> {
if (!isValidLocale(locale)) {
throw new Error(`Unsupported locale: ${locale}`);
}
const cookieStore = await cookies();
cookieStore.set(LOCALE_COOKIE, locale, {
path: '/',
maxAge: 60 * 60 * 24 * 365, // 1 year
sameSite: 'lax',
});
// Strip existing locale prefix and redirect to new locale path
const pathWithoutLocale = currentPath.replace(/^\/[a-z]{2}(\/|$)/, '/');
redirect(`/${locale}${pathWithoutLocale}`);
}Kielenvaihtajakomponentin rakentaminen
Kielenvaihtaja on Client Component, joka kutsuu setLocaleAction-Server Actionia, kun käyttäjä valitsee uuden lokalen. Se käyttää usePathname()-funktiota nykyisen URL-osoitteen selvittämiseen, jotta toiminto voi ohjata vastaavalle sivulle uudessa localessa.
Huomioikaa, että myös lomakelähestymistapa (käyttämällä rakennetta <form action={...}>) toimii ja on esteetön — se toimii hallitusti myös ilman JavaScriptiä.
// components/language-switcher.tsx
'use client';
import { usePathname } from 'next/navigation';
import { useTransition } from 'react';
import { setLocaleAction } from '@/app/actions/set-locale';
import { locales, type Locale } from '@/lib/i18n';
const labels: Record<Locale, string> = {
en: 'English',
tr: 'Turkce',
de: 'Deutsch',
fr: 'Francais',
};
export function LanguageSwitcher({ currentLocale }: { currentLocale: Locale }) {
const pathname = usePathname();
const [isPending, startTransition] = useTransition();
function handleChange(locale: Locale) {
startTransition(() => {
setLocaleAction(locale, pathname);
});
}
return (
<select
value={currentLocale}
onChange={(e) => handleChange(e.target.value as Locale)}
disabled={isPending}
aria-label="Select language"
>
{locales.map((locale) => (
<option key={locale} value={locale}>
{labels[locale]}
</option>
))}
</select>
);
}Tietotesti: Middlewaren uudelleenohjaus vai rewrite
Kävijä saapuu osoitteeseen /dashboard ilman locale-etuliitettä. Middleware tunnistaa hänen suosikkilocaleekseen fr. Mikä toimintatapa sopii parhaiten julkiseen ja SEO-optimoituun alipolkujen i18n-toteutukseen?
Oppitunnin kertaus: Locale-tunnistus ja alipolkujen reititys
Tässä oppitunnissa rakensitte Next.js 15:n App Routerille täydellisen i18n-reititystason:
- Vakiotiedosto (
lib/i18n.ts) — keskitetty totuuden lähde tuetuille localeille ja oletuslocalelle sekä tyyppiturvallinenLocale-unionityyppi. - Tunnistusapuohjelmat (
lib/locale-detection.ts) — tärkeysjärjestys: ensin cookie, sittenAccept-Language-otsakkeen neuvottelu@formatjs/intl-localematcher-kirjastolla ja lopuksi varavaihtoehtona oletuslocale. - Middleware (
middleware.ts) — päästää valmiiksi lokalisoidut polut läpi ja ohjaa paljaat polut tunnistetun lokalen alipolkuun;matcherrajoittaa käsittelyä ja ohittaa staattiset resurssit. - App Router -rakenne —
app/[lang]/layout.tsxvastaanottaa Next.js 15:ssäparams-arvon awaitattavana Promisena, asettaahtml lang-arvon ja lataa laiskasti sanakirjan. - Server Action — kirjoittaa käyttäjän tekemän valinnan pitkäikäiseen cookieen ja ohjaa vastaavalle lokalisoidulle polulle.
- Kielenvaihtaja — Client Component, joka kutsuu Server Actionia
useTransition-funktion sisällä estämättömän käyttökokemuksen takaamiseksi.
Tämä malli tarjoaa kaikki SEO-hyödyt (erilliset URL-osoitteet localea kohden), hallitun toiminnan heikennetyissä tilanteissa ja käyttäjän asetuksen säilymisen — ilman kolmannen osapuolen i18n-reitityskirjastoa.
Opi TypeScript tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 22
- Oppitunnit
- 88
Usein kysytyt kysymykset
Onko oppitunti ”Kielialueen tunnistus ja alihakemistoreititys middlewaressa” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolun 3 oppituntia, myös oppitunnin “Kielialueen tunnistus ja alihakemistoreititys middlewaressa”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Next.js 15 -fullstack-kehitys (App Router + Server Actions)-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Kielialueen tunnistus ja alihakemistoreititys middlewaressa”?
Tunnistakaa käyttäjän kielialue ja uudelleenkirjoittakaa pyynnöt lokalisoituihin alihakemistoihin middlewaressa. Harjoittelet Next.js 15 -fullstack-kehitys (App Router + Server Actions)-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Next.js 15 -fullstack-kehitys (App Router + Server Actions)-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.
Kuinka kauan ”Kielialueen tunnistus ja alihakemistoreititys middlewaressa”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunnilla?
Kyllä. Jokainen Next.js 15 -fullstack-kehitys (App Router + Server Actions)-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Kielialueen tunnistus ja alihakemistoreititys middlewaressa
- Käännösten lataaminen palvelimella ja viestiluettelot
- Lokalisoinnin mukaiset metatiedot, sivustokartat ja hreflang
- Päivämäärien, lukujen ja monikkojen muotoilu kielialueen mukaan