Formatere datoer, tall og flertall etter lokalisering
Bruk Intl-API-ene til å gjengi datoer, valutaer og flertallsformer som er korrekte for lokaliseringen.
Formatere datoer, tall og flertall etter lokalisering er en gratis leksjon i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit. Dette er leksjon 4 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Next.js 15 fullstack (App Router + Server Actions), og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Next.js 15 fullstack (App Router + Server Actions) inneholder totalt 4 leksjoner.
Hvorfor locale-bevisst formatering er viktig
En dato som 06/07/2025 betyr 7. juni for en amerikaner, men 6. juli for en europeer. Et tall som 1.234 betyr ett tusen to hundre og trettifire i USA, men én komma to tre fire i Tyskland.
Hvis formatlogikken hardkodes, slutter appen å fungere riktig for internasjonale brukere. I stedet leveres både nettleseren og Node.js med Intl-navnerommet — et standardbasert sett med API-er som håndterer lokalitetstilpasset formatering uten tredjepartsbiblioteker.
Intl.DateTimeFormat— formaterer datoer og klokkeslettIntl.NumberFormat— formaterer tall, valutaer og enheterIntl.PluralRules— velger riktig flertallsform
I et Next.js 15-prosjekt med App Router kjøres disse på serveren (i Server Components og Server Actions) så vel som på klienten. Dermed får du et konsistent resultat uten å sende med ekstra JavaScript.
Finne aktiv lokalitet i App Router
Next.js 15 med App Router lagrer den aktive lokaliteten i URL-segmentet. En vanlig konvensjon er /en/dashboard eller /de/dashboard. layout.tsx mottar en params-prop som inneholder den.
Utdraget nedenfor viser hvordan du leser params.locale i en asynkron Server Component og sender den videre til formateringshjelpere.
// app/[locale]/layout.tsx
import { ReactNode } from 'react';
interface Props {
children: ReactNode;
params: Promise<{ locale: string }>;
}
export default async function LocaleLayout({ children, params }: Props) {
const { locale } = await params; // e.g. 'en', 'de', 'tr'
return (
<html lang={locale}>
<body>{children}</body>
</html>
);
}Formatere datoer med Intl.DateTimeFormat
Intl.DateTimeFormat mottar en lokalitetsstreng og et options-objekt. Du kan styre hvilke dato- og klokkeslettdeler som skal vises, og hvilken stil de skal ha.
- dateStyle:
'short','medium','long','full' - timeStyle: de samme alternativene
- Enkeltfelter:
year,month,day,hour,minuteog så videre
Kallet .format(date) returnerer en lokalitetsriktig streng. Siden Intl er innebygd i Node.js, kan dette kjøres trygt i en Server Component uten ekstra kostnad for klientens bundle.
// lib/format-date.ts
export function formatDate(
date: Date,
locale: string,
options: Intl.DateTimeFormatOptions = { dateStyle: 'long' }
): string {
return new Intl.DateTimeFormat(locale, options).format(date);
}
// Usage examples:
// formatDate(new Date(), 'en-US') => 'June 7, 2025'
// formatDate(new Date(), 'de-DE') => '7. Juni 2025'
// formatDate(new Date(), 'tr-TR') => '7 Haziran 2025'
// formatDate(new Date(), 'ja-JP') => '2025年6月7日'Bruke formatDate i en Server Component
Siden Server Components kjører på Node.js, kan du kalle formatDate-hjelperen direkte — ingen useEffect, ingen hydreringsavvik og ingen ekstra bundle-størrelse for klienten.
Lokaliteten hentes fra params og sendes direkte til formateringsfunksjonen. Resultatet er en vanlig streng som bygges inn i HTML.
// app/[locale]/blog/[slug]/page.tsx
import { formatDate } from '@/lib/format-date';
interface Props {
params: Promise<{ locale: string; slug: string }>;
}
export default async function BlogPost({ params }: Props) {
const { locale, slug } = await params;
// In a real app you would fetch the post from a DB or CMS
const publishedAt = new Date('2025-06-07T09:00:00Z');
return (
<article>
<time dateTime={publishedAt.toISOString()}>
{formatDate(publishedAt, locale, { dateStyle: 'full', timeStyle: 'short' })}
</time>
<h1>Post: {slug}</h1>
</article>
);
}Formatere tall og valutaer
Intl.NumberFormat håndterer tre hovedbruksområder:
- Vanlige tall — desimalskilletegn og grupperinger varierer etter lokalitet (
1,234.56mot1.234,56) - Valuta — plasseringen av symbolet, antallet desimaler og til og med valutanavnet varierer
- Enheter — kilogram, miles, byte og så videre, formatert i henhold til lokale konvensjoner
Send alltid med currency sammen med style: 'currency'. Valutakoden (ISO 4217) forteller formateringsfunksjonen hvilket symbol som skal brukes, mens lokaliteten forteller hvor det skal plasseres.
// lib/format-number.ts
export function formatCurrency(
amount: number,
currency: string,
locale: string
): string {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(amount);
}
export function formatNumber(
value: number,
locale: string,
options?: Intl.NumberFormatOptions
): string {
return new Intl.NumberFormat(locale, options).format(value);
}
// formatCurrency(1234.5, 'USD', 'en-US') => '$1,234.50'
// formatCurrency(1234.5, 'EUR', 'de-DE') => '1.234,50 €'
// formatCurrency(1234.5, 'TRY', 'tr-TR') => '₺1.234,50'En frittstående Intl-demo (kjørbar)
Utdraget nedenfor er et komplett, selvstendig TypeScript-program som demonstrerer Intl.DateTimeFormat og Intl.NumberFormat på tvers av flere lokaliteter. Du trenger ingen rammeverk eller ekstern pakke — programmet kan kjøres med ts-node eller limes inn i en TypeScript-lekeplass.
const locales = ['en-US', 'de-DE', 'tr-TR', 'ja-JP', 'ar-SA'];
const date = new Date('2025-06-07T14:30:00Z');
const price = 9999.99;
for (const locale of locales) {
const formattedDate = new Intl.DateTimeFormat(locale, {
dateStyle: 'medium',
timeStyle: 'short',
}).format(date);
const formattedPrice = new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'USD',
}).format(price);
console.log(`[${locale}] date: ${formattedDate} | price: ${formattedPrice}`);
}Flertallsregler — den skjulte kompleksiteten
Engelsk har to flertallsformer: 1 item mot 2 items. Arabisk har derimot seks, russisk har tre og polsk har fire. Hvis du implementerer flertallsbøying med en enkel sjekk som count === 1 ? 'item' : 'items', blir appen feil for det meste av verden.
Intl.PluralRules løser dette ved å returnere riktig CLDR-flertallskategori for et gitt tall og en gitt lokalitet:
- zero
- one
- two
- few
- many
- other
Du knytter hver kategori til den riktige oversatte strengen i meldingskatalogen, og lar deretter PluralRules velge riktig nøkkel under kjøring.
Implementere en pluralize-hjelper
Hjelperen nedenfor mottar et antall, en lokalitet og et oppslag med strenger for flertallskategoriene. Den bruker Intl.PluralRules til å velge riktig form, og erstatter deretter plassholderen {{count}} med det faktiske tallet.
Dermed holdes flertallslogikken utenfor oversettelsesfilene — filene trenger bare malene for hver kategori, ikke forgreningskode.
// lib/pluralize.ts
type PluralForms = Partial<Record<Intl.LDMLPluralRule, string>>;
export function pluralize(
count: number,
locale: string,
forms: PluralForms
): string {
const rules = new Intl.PluralRules(locale);
const category = rules.select(count); // 'zero'|'one'|'two'|'few'|'many'|'other'
const template = forms[category] ?? forms['other'] ?? '';
return template.replace('{{count}}', String(count));
}
// English
// pluralize(1, 'en', { one: '{{count}} item', other: '{{count}} items' })
// => '1 item'
// pluralize(5, 'en', { one: '{{count}} item', other: '{{count}} items' })
// => '5 items'
// Arabic (6 forms)
// pluralize(11, 'ar', { zero:'...', one:'...', two:'...', few:'...', many:'{{count}} عنصرًا', other:'...' })
// => '11 عنصرًا'Bruke pluralize i en Server Component
Kombiner pluralize-hjelperen med lokalitetstilpasset tallformatering for en komplett løsning som er klar til bruk i produksjon. Handlekurvsammendraget nedenfor viser antallet varer og totalprisen, begge korrekt formatert for alle lokaliteter.
// app/[locale]/cart/page.tsx
import { pluralize } from '@/lib/pluralize';
import { formatCurrency } from '@/lib/format-number';
interface Props {
params: Promise<{ locale: string }>;
}
// Minimal translation catalog — in real projects use next-intl or similar
const itemForms: Record<string, Record<string, string>> = {
'en-US': { one: '{{count}} item', other: '{{count}} items' },
'de-DE': { one: '{{count}} Artikel', other: '{{count}} Artikel' },
'tr-TR': { one: '{{count}} ürün', other: '{{count}} ürün' },
};
export default async function CartPage({ params }: Props) {
const { locale } = await params;
const itemCount = 3;
const total = 129.99;
const forms = itemForms[locale] ?? itemForms['en-US'];
return (
<section>
<p>{pluralize(itemCount, locale, forms)}</p>
<p>Total: {formatCurrency(total, 'USD', locale)}</p>
</section>
);
}Formatere relativ tid med Intl.RelativeTimeFormat
Intl.RelativeTimeFormat formaterer tidsrom relativt til nå — 3 days ago, in 2 hours — for alle lokaliteter og numeriske stiler.
- numeric: 'always' — bruker alltid tall: 1 day ago
- numeric: 'auto' — bruker naturlig språk når det er mulig: yesterday
Hjelperen nedenfor beregner automatisk den beste enheten og overlater strengformateringen til API-et.
// lib/format-relative.ts
export function formatRelative(date: Date, locale: string): string {
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' });
const diffMs = date.getTime() - Date.now();
const diffSec = Math.round(diffMs / 1000);
const thresholds: [number, Intl.RelativeTimeFormatUnit][] = [
[60, 'second'],
[3600, 'minute'],
[86400, 'hour'],
[2592000, 'day'],
[31536000, 'month'],
];
for (const [limit, unit] of thresholds) {
if (Math.abs(diffSec) < limit) {
const divisor = unit === 'second' ? 1
: unit === 'minute' ? 60
: unit === 'hour' ? 3600
: unit === 'day' ? 86400
: 2592000;
return rtf.format(Math.round(diffSec / divisor), unit);
}
}
return rtf.format(Math.round(diffSec / 31536000), 'year');
}
// formatRelative(new Date(Date.now() - 90000), 'en-US') => '2 minutes ago'
// formatRelative(new Date(Date.now() - 90000), 'de-DE') => 'vor 2 Minuten'Opprette en gjenbrukbar FormattedDate-klientkomponent
Noen ganger trenger du datoformatering på klienten — for eksempel når datoen endres etter en brukerinteraksjon. En tynn klientkomponent som leser navigator.language, unngår hydreringsavvik ved å la nettleseren velge sin egen lokalitet.
Legg merke til 'use client'-direktivet. Selve komponenten leveres uten en Intl-polyfill, fordi alle moderne nettlesere og Node 18+ har innebygd støtte for hele Intl-spesifikasjonen.
'use client';
import { useMemo } from 'react';
interface Props {
date: string; // ISO string — safe to serialize from Server to Client
options?: Intl.DateTimeFormatOptions;
}
export function FormattedDate({ date, options = { dateStyle: 'medium' } }: Props) {
// navigator.language gives the browser's locale, e.g. 'en-GB'
const formatted = useMemo(() => {
return new Intl.DateTimeFormat(navigator.language, options).format(
new Date(date)
);
}, [date, options]);
return <time dateTime={date}>{formatted}</time>;
}Kunnskapssjekk: Flertallsformer og Intl.PluralRules
Bruk det du har lært i denne leksjonen, og svar på følgende spørsmål om Intl.PluralRules og lokalitetstilpasset flertallsbøying.
Oppsummering: Lokalitetstilpasset formatering i Next.js 15
I denne leksjonen har du lært å bruke de innebygde Intl-API-ene til å formatere datoer, tall, valutaer, relativ tid og strenger med riktig flertallsform for alle lokaliteter — uten behov for tredjepartsbiblioteker.
- Intl.DateTimeFormat — formaterer datoer og klokkeslett. Bruk
dateStyle/timeStylefor rask formatering eller alternativer for enkeltfelter når du trenger detaljert kontroll. - Intl.NumberFormat — håndterer vanlige tall, valutaer (
style: 'currency') og enheter. Knytt alltid en valutakode sammen med lokaliteten. - Intl.RelativeTimeFormat — produserer lokalitetsriktige relative strenger som yesterday eller vor 2 Minuten.
- Intl.PluralRules — velger CLDR-flertallskategorien (zero / one / two / few / many / other), slik at oversettelseskatalogen kan levere riktig form for hvert språk.
- I Next.js 15 App Router bør du kjøre disse formateringsfunksjonene i Server Components for å unngå hydreringsavvik og bundle-kostnader. Bruk en
'use client'-omslutning mednavigator.languagebare når det er nødvendig å finne lokaliteten på klienten.
Disse fire Intl-API-ene dekker de aller fleste behov for i18n-formatering uten at du trenger et tungt bibliotek.
Lær deg TypeScript med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 22
- Leksjoner
- 88
Ofte stilte spørsmål
Er leksjonen «Formatere datoer, tall og flertall etter lokalisering» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Next.js 15 fullstack (App Router + Server Actions), inkludert «Formatere datoer, tall og flertall etter lokalisering», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Next.js 15 fullstack (App Router + Server Actions) inneholder totalt 4 leksjoner.
Hva lærer jeg i «Formatere datoer, tall og flertall etter lokalisering»?
Bruk Intl-API-ene til å gjengi datoer, valutaer og flertallsformer som er korrekte for lokaliseringen. Du øver på Next.js 15 fullstack (App Router + Server Actions) med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Next.js 15 fullstack (App Router + Server Actions)?
Ingen tidligere erfaring er nødvendig. Next.js 15 fullstack (App Router + Server Actions) på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.
Hvor lang tid tar leksjonen «Formatere datoer, tall og flertall etter lokalisering»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Next.js 15 fullstack (App Router + Server Actions)-leksjonen?
Ja. Alle Next.js 15 fullstack (App Router + Server Actions)-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Lokalisering og subruting med middleware
- Lasting av oversettelser på serversiden og meldingskataloger
- Lokalisert metadata, sitemaps og hreflang
- Formatere datoer, tall og flertall etter lokalisering