Multi-Language Localization Skill
Purpose
Implement proper internationalization (i18n) and localization (l10n) for static websites supporting multiple languages.
Core Principles
1. Language Declaration
<!-- ✅ Always declare language -->
<html lang="en">
<!-- For Swedish -->
<html lang="sv">
<!-- For Arabic (RTL) -->
<html lang="ar" dir="rtl">
2. File Structure
index.html (en - English, default)
index_sv.html (sv - Swedish)
index_da.html (da - Danish)
index_no.html (no - Norwegian)
index_fi.html (fi - Finnish)
index_de.html (de - German)
index_fr.html (fr - French)
index_es.html (es - Spanish)
index_nl.html (nl - Dutch)
index_ar.html (ar - Arabic, RTL)
index_he.html (he - Hebrew, RTL)
index_ja.html (ja - Japanese)
index_ko.html (ko - Korean)
index_zh.html (zh - Chinese)
3. Language Switcher
<nav aria-label="Language selection">
<ul>
<li><a href="index.html" hreflang="en">English</a></li>
<li><a href="index_sv.html" hreflang="sv">Svenska</a></li>
<li><a href="index_ar.html" hreflang="ar">العربية</a></li>
</ul>
</nav>
4. RTL Support
/* RTL-specific styles */
[dir="rtl"] .element {
text-align: right;
direction: rtl;
}
/* Use logical properties */
.element {
margin-inline-start: 1rem; /* Not margin-left */
padding-inline-end: 1rem; /* Not padding-right */
}
5. Cultural Considerations
- Date formats (US: MM/DD/YYYY, EU: DD/MM/YYYY)
- Number formats (1,000.00 vs 1.000,00)
- Currency symbols
- Text direction (LTR vs RTL)
- Color meanings (cultural significance)
SEO Best Practices
Hreflang Tags
<link rel="alternate" hreflang="en" href="https://example.com/index.html">
<link rel="alternate" hreflang="sv" href="https://example.com/index_sv.html">
<link rel="alternate" hreflang="x-default" href="https://example.com/index.html">
Sitemap
<url>
<loc>https://example.com/index.html</loc>
<xhtml:link rel="alternate" hreflang="sv" href="https://example.com/index_sv.html"/>
</url>
Testing
- Native speaker review
- RTL layout testing
- Character encoding verification
- Cultural appropriateness check
- SEO validation (hreflang)
Remember
- Native Speakers: Use professional translation
- Cultural Context: Consider cultural differences
- RTL Support: Test right-to-left languages
- Consistent UX: Same experience across languages
- SEO: Proper hreflang and sitemap
References
Number and Date Formatting (Production Data)
This section provides validated formatting from actual translated news articles (Feb 2026).
Number Formatting by Language
Thousands Separator and Decimal Point:
| Language |
Thousands |
Decimal |
Example |
Usage |
| English (en) |
comma (,) |
period (.) |
1,000.50 |
International standard |
| Swedish (sv) |
space ( ) |
comma (,) |
1 000,50 |
Official Swedish standard |
| German (de) |
space ( ) or period (.) |
comma (,) |
1 000,50 or 1.000,50 |
Space preferred |
| French (fr) |
space ( ) |
comma (,) |
1 000,50 |
Official French standard |
| Spanish (es) |
space ( ) or period (.) |
comma (,) |
1 000,50 or 1.000,50 |
Space preferred |
| Dutch (nl) |
period (.) |
comma (,) |
1.000,50 |
Period for thousands |
| Danish (da) |
period (.) |
comma (,) |
1.000,50 |
Period for thousands |
| Norwegian (no) |
space ( ) |
comma (,) |
1 000,50 |
Official Norwegian standard |
| Finnish (fi) |
space ( ) |
comma (,) |
1 000,50 |
Official Finnish standard |
| Japanese (ja) |
comma (,) |
period (.) |
1,000.50 |
Western style |
| Korean (ko) |
comma (,) |
period (.) |
1,000.50 |
Western style |
| Chinese (zh) |
comma (,) |
period (.) |
1,000.50 |
Western style |
| Arabic (ar) |
comma (,) |
period (.) |
١٬٠٠٠٫٥٠ or 1,000.50 |
Arabic-Indic optional |
| Hebrew (he) |
comma (,) |
period (.) |
1,000.50 |
Western style |
Implementation:
// Format numbers for language with documented separators
function formatNumber(num, lang) {
const formats = {
'en': { thousands: ',', decimal: '.' },
'sv': { thousands: ' ', decimal: ',' },
'de': { thousands: ' ', decimal: ',' },
'fr': { thousands: ' ', decimal: ',' },
'es': { thousands: ' ', decimal: ',' },
'nl': { thousands: '.', decimal: ',' },
'da': { thousands: '.', decimal: ',' },
'no': { thousands: ' ', decimal: ',' },
'fi': { thousands: ' ', decimal: ',' },
'ja': { thousands: ',', decimal: '.' },
'ko': { thousands: ',', decimal: '.' },
'zh': { thousands: ',', decimal: '.' },
'ar': { thousands: ',', decimal: '.' },
'he': { thousands: ',', decimal: '.' }
};
const fmt = formats[lang] || formats['en'];
// Normalize to two decimals, then trim to 0–2 as needed
const isNegative = num < 0;
const absolute = Math.abs(num);
const fixed = absolute.toFixed(2);
let [intPart, fracPart] = fixed.split('.');
// Insert thousands separators in the integer part
intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, fmt.thousands);
// Trim trailing zeros from fractional part to allow 0–2 decimals
fracPart = fracPart.replace(/0+$/, '');
let result = intPart;
if (fracPart.length > 0) {
result += fmt.decimal + fracPart;
}
if (isNegative) {
result = '-' + result;
}
return result;
}
Date Formatting by Language
From News Articles (Feb 2026):
| Language |
Format |
Example |
Day-Month Order |
| English (en) |
Month D, YYYY |
February 15, 2026 |
Month first |
| Swedish (sv) |
D month YYYY |
15 februari 2026 |
Day first |
| German (de) |
D. Month YYYY |
15. Februar 2026 |
Day first (with period) |
| French (fr) |
D month YYYY |
15 février 2026 |
Day first |
| Spanish (es) |
D de month de YYYY |
15 de febrero de 2026 |
Day first (with "de") |
| Dutch (nl) |
D month YYYY |
15 februari 2026 |
Day first |
| Danish (da) |
D. month YYYY |
15. februar 2026 |
Day first (with period) |
| Norwegian (no) |
D. month YYYY |
15. februar 2026 |
Day first (with period) |
| Finnish (fi) |
D. monthkuuta YYYY |
15. helmikuuta 2026 |
Day first (genitive case) |
| Japanese (ja) |
YYYY年M月D日 |
2026年2月15日 |
Year-Month-Day |
| Korean (ko) |
YYYY년 M월 D일 |
2026년 2월 15일 |
Year-Month-Day |
| Chinese (zh) |
YYYY年M月D日 |
2026年2月15日 |
Year-Month-Day |
| Arabic (ar) |
D month YYYY |
١٥ فبراير ٢٠٢٦ |
Day first (Arabic-Indic optional) |
| Hebrew (he) |
D bmonth YYYY |
15 בפברואר 2026 |
Day first (with ב prefix) |
Month Names:
| English |
Swedish |
German |
French |
Spanish |
Dutch |
| January |
januari |
Januar |
janvier |
enero |
januari |
| February |
februari |
Februar |
février |
febrero |
februari |
| March |
mars |
März |
mars |
marzo |
maart |
| April |
april |
April |
avril |
abril |
april |
| May |
maj |
Mai |
mai |
mayo |
mei |
| June |
juni |
Juni |
juin |
junio |
juni |
| July |
juli |
Juli |
juillet |
julio |
juli |
| August |
augusti |
August |
août |
agosto |
augustus |
| September |
september |
September |
septembre |
septiembre |
september |
| October |
oktober |
Oktober |
octobre |
octubre |
oktober |
| November |
november |
November |
novembre |
noviembre |
november |
| December |
december |
Dezember |
décembre |
diciembre |
december |
Day of Week:
| English |
Swedish |
German |
French |
Spanish |
Dutch |
Finnish |
| Monday |
måndag |
Montag |
lundi |
lunes |
maandag |
maanantai |
| Tuesday |
tisdag |
Dienstag |
mardi |
martes |
dinsdag |
tiistai |
| Wednesday |
onsdag |
Mittwoch |
mercredi |
miércoles |
woensdag |
keskiviikko |
| Thursday |
torsdag |
Donnerstag |
jeudi |
jueves |
donderdag |
torstai |
| Friday |
fredag |
Freitag |
vendredi |
viernes |
vrijdag |
perjantai |
| Saturday |
lördag |
Samstag |
samedi |
sábado |
zaterdag |
lauantai |
| Sunday |
söndag |
Sonntag |
dimanche |
domingo |
zondag |
sunnuntai |
Time Formatting
24-hour vs. 12-hour:
| Language |
Clock |
Example |
Note |
| English (en) |
12-hour |
2:30 PM |
AM/PM required |
| Swedish (sv) |
24-hour |
14:30 |
Period or colon separator |
| German (de) |
24-hour |
14:30 Uhr |
"Uhr" suffix |
| French (fr) |
24-hour |
14h30 |
"h" separator |
| Spanish (es) |
24-hour |
14:30 |
Colon separator |
| Nordic (da, no, fi) |
24-hour |
14:30 or 14.30 |
Period common |
| CJK (ja, ko, zh) |
24-hour |
14:30 |
Colon separator |
| Arabic (ar) |
12-hour |
٢:٣٠ م |
Arabic-Indic optional |
| Hebrew (he) |
24-hour |
14:30 |
Colon separator |
Currency Formatting
Swedish Krona (SEK):
| Language |
Format |
Example |
Note |
| English |
SEK 1,000.50 or 1,000.50 kr |
SEK 1,000.50 |
Currency code preferred |
| Swedish |
1 000,50 kr |
1 000,50 kr |
"kr" suffix standard |
| German |
1 000,50 SEK |
1 000,50 SEK |
Currency code suffix |
| French |
1 000,50 SEK |
1 000,50 SEK |
Currency code suffix |
Ordinal Numbers
| Language |
Example |
Pattern |
| English |
1st, 2nd, 3rd, 4th |
-st, -nd, -rd, -th |
| Swedish |
1:a, 2:a, 3:e, 4:e |
:a or :e |
| German |
1., 2., 3., 4. |
Period suffix |
| French |
1er, 2e, 3e, 4e |
-er for first, -e for rest |
| Spanish |
1.º, 2.º, 3.º, 4.º |
Masculine ordinal |
Practical Implementation
Date Formatting Function:
function formatDate(date, lang) {
const months = {
en: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
sv: ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'],
de: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
fr: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],
es: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],
da: ['januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'],
no: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'],
nl: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],
fi: ['tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta']
};
const d = date.getDate();
const m = date.getMonth();
const y = date.getFullYear();
if (lang === 'en') return `${months[lang][m]} ${d}, ${y}`;
if (lang === 'de' || lang === 'da' || lang === 'no') return `${d}. ${months[lang][m]} ${y}`;
if (lang === 'es') return `${d} de ${months[lang][m]} de ${y}`;
if (lang === 'fi') return `${d}. ${months[lang][m]} ${y}`;
if (lang === 'ja') return `${y}年${m+1}月${d}日`;
if (lang === 'ko') return `${y}년 ${m+1}월 ${d}일`;
if (lang === 'zh') return `${y}年${m+1}月${d}日`;
return `${d} ${months[lang]?.[m] || months['en'][m]} ${y}`; // Default format with fallback
}
Validation Checklist
For each language version, verify:
Data Source: Validated against 81 news articles (Feb 2026)
Standards: Unicode CLDR, ISO 8601
Last Updated: 2026-02-15
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
1---2name: multi-language-localization3description: Best practices for multi-language static websites with proper i18n and l10n support Use when this capability is needed.4---56# Multi-Language Localization Skill78## Purpose910Implement proper internationalization (i18n) and localization (l10n) for static websites supporting multiple languages.1112## Core Principles1314### 1. Language Declaration15```html16<!-- ✅ Always declare language -->17<html lang="en">1819<!-- For Swedish -->20<html lang="sv">2122<!-- For Arabic (RTL) -->23<html lang="ar" dir="rtl">24```2526### 2. File Structure27```28index.html (en - English, default)29index_sv.html (sv - Swedish)30index_da.html (da - Danish)31index_no.html (no - Norwegian)32index_fi.html (fi - Finnish)33index_de.html (de - German)34index_fr.html (fr - French)35index_es.html (es - Spanish)36index_nl.html (nl - Dutch)37index_ar.html (ar - Arabic, RTL)38index_he.html (he - Hebrew, RTL)39index_ja.html (ja - Japanese)40index_ko.html (ko - Korean)41index_zh.html (zh - Chinese)42```4344### 3. Language Switcher45```html46<nav aria-label="Language selection">47 <ul>48 <li><a href="index.html" hreflang="en">English</a></li>49 <li><a href="index_sv.html" hreflang="sv">Svenska</a></li>50 <li><a href="index_ar.html" hreflang="ar">العربية</a></li>51 </ul>52</nav>53```5455### 4. RTL Support56```css57/* RTL-specific styles */58[dir="rtl"] .element {59 text-align: right;60 direction: rtl;61}6263/* Use logical properties */64.element {65 margin-inline-start: 1rem; /* Not margin-left */66 padding-inline-end: 1rem; /* Not padding-right */67}68```6970### 5. Cultural Considerations71- Date formats (US: MM/DD/YYYY, EU: DD/MM/YYYY)72- Number formats (1,000.00 vs 1.000,00)73- Currency symbols74- Text direction (LTR vs RTL)75- Color meanings (cultural significance)7677## SEO Best Practices7879### Hreflang Tags80```html81<link rel="alternate" hreflang="en" href="https://example.com/index.html">82<link rel="alternate" hreflang="sv" href="https://example.com/index_sv.html">83<link rel="alternate" hreflang="x-default" href="https://example.com/index.html">84```8586### Sitemap87```xml88<url>89 <loc>https://example.com/index.html</loc>90 <xhtml:link rel="alternate" hreflang="sv" href="https://example.com/index_sv.html"/>91</url>92```9394## Testing9596- Native speaker review97- RTL layout testing98- Character encoding verification99- Cultural appropriateness check100- SEO validation (hreflang)101102## Remember103104- **Native Speakers**: Use professional translation105- **Cultural Context**: Consider cultural differences106- **RTL Support**: Test right-to-left languages107- **Consistent UX**: Same experience across languages108- **SEO**: Proper hreflang and sitemap109110## References111112- [W3C Internationalization](https://www.w3.org/International/)113- [MDN Localization](https://developer.mozilla.org/en-US/docs/Mozilla/Localization)114115---116117## Number and Date Formatting (Production Data)118119This section provides **validated formatting** from actual translated news articles (Feb 2026).120121### Number Formatting by Language122123**Thousands Separator and Decimal Point**:124125| Language | Thousands | Decimal | Example | Usage |126|----------|-----------|---------|---------|-------|127| English (en) | comma (,) | period (.) | 1,000.50 | International standard |128| Swedish (sv) | space ( ) | comma (,) | 1 000,50 | Official Swedish standard |129| German (de) | space ( ) or period (.) | comma (,) | 1 000,50 or 1.000,50 | Space preferred |130| French (fr) | space ( ) | comma (,) | 1 000,50 | Official French standard |131| Spanish (es) | space ( ) or period (.) | comma (,) | 1 000,50 or 1.000,50 | Space preferred |132| Dutch (nl) | period (.) | comma (,) | 1.000,50 | Period for thousands |133| Danish (da) | period (.) | comma (,) | 1.000,50 | Period for thousands |134| Norwegian (no) | space ( ) | comma (,) | 1 000,50 | Official Norwegian standard |135| Finnish (fi) | space ( ) | comma (,) | 1 000,50 | Official Finnish standard |136| Japanese (ja) | comma (,) | period (.) | 1,000.50 | Western style |137| Korean (ko) | comma (,) | period (.) | 1,000.50 | Western style |138| Chinese (zh) | comma (,) | period (.) | 1,000.50 | Western style |139| Arabic (ar) | comma (,) | period (.) | ١٬٠٠٠٫٥٠ or 1,000.50 | Arabic-Indic optional |140| Hebrew (he) | comma (,) | period (.) | 1,000.50 | Western style |141142**Implementation**:143```javascript144// Format numbers for language with documented separators145function formatNumber(num, lang) {146 const formats = {147 'en': { thousands: ',', decimal: '.' },148 'sv': { thousands: ' ', decimal: ',' },149 'de': { thousands: ' ', decimal: ',' },150 'fr': { thousands: ' ', decimal: ',' },151 'es': { thousands: ' ', decimal: ',' },152 'nl': { thousands: '.', decimal: ',' },153 'da': { thousands: '.', decimal: ',' },154 'no': { thousands: ' ', decimal: ',' },155 'fi': { thousands: ' ', decimal: ',' },156 'ja': { thousands: ',', decimal: '.' },157 'ko': { thousands: ',', decimal: '.' },158 'zh': { thousands: ',', decimal: '.' },159 'ar': { thousands: ',', decimal: '.' },160 'he': { thousands: ',', decimal: '.' }161 };162 const fmt = formats[lang] || formats['en'];163 164 // Normalize to two decimals, then trim to 0–2 as needed165 const isNegative = num < 0;166 const absolute = Math.abs(num);167 const fixed = absolute.toFixed(2);168 let [intPart, fracPart] = fixed.split('.');169 170 // Insert thousands separators in the integer part171 intPart = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, fmt.thousands);172 173 // Trim trailing zeros from fractional part to allow 0–2 decimals174 fracPart = fracPart.replace(/0+$/, '');175 176 let result = intPart;177 if (fracPart.length > 0) {178 result += fmt.decimal + fracPart;179 }180 181 if (isNegative) {182 result = '-' + result;183 }184 185 return result;186}187```188189### Date Formatting by Language190191**From News Articles (Feb 2026)**:192193| Language | Format | Example | Day-Month Order |194|----------|--------|---------|-----------------|195| English (en) | Month D, YYYY | February 15, 2026 | Month first |196| Swedish (sv) | D month YYYY | 15 februari 2026 | Day first |197| German (de) | D. Month YYYY | 15. Februar 2026 | Day first (with period) |198| French (fr) | D month YYYY | 15 février 2026 | Day first |199| Spanish (es) | D de month de YYYY | 15 de febrero de 2026 | Day first (with "de") |200| Dutch (nl) | D month YYYY | 15 februari 2026 | Day first |201| Danish (da) | D. month YYYY | 15. februar 2026 | Day first (with period) |202| Norwegian (no) | D. month YYYY | 15. februar 2026 | Day first (with period) |203| Finnish (fi) | D. monthkuuta YYYY | 15. helmikuuta 2026 | Day first (genitive case) |204| Japanese (ja) | YYYY年M月D日 | 2026年2月15日 | Year-Month-Day |205| Korean (ko) | YYYY년 M월 D일 | 2026년 2월 15일 | Year-Month-Day |206| Chinese (zh) | YYYY年M月D日 | 2026年2月15日 | Year-Month-Day |207| Arabic (ar) | D month YYYY | ١٥ فبراير ٢٠٢٦ | Day first (Arabic-Indic optional) |208| Hebrew (he) | D bmonth YYYY | 15 בפברואר 2026 | Day first (with ב prefix) |209210**Month Names**:211212| English | Swedish | German | French | Spanish | Dutch |213|---------|---------|--------|--------|---------|-------|214| January | januari | Januar | janvier | enero | januari |215| February | februari | Februar | février | febrero | februari |216| March | mars | März | mars | marzo | maart |217| April | april | April | avril | abril | april |218| May | maj | Mai | mai | mayo | mei |219| June | juni | Juni | juin | junio | juni |220| July | juli | Juli | juillet | julio | juli |221| August | augusti | August | août | agosto | augustus |222| September | september | September | septembre | septiembre | september |223| October | oktober | Oktober | octobre | octubre | oktober |224| November | november | November | novembre | noviembre | november |225| December | december | Dezember | décembre | diciembre | december |226227**Day of Week**:228229| English | Swedish | German | French | Spanish | Dutch | Finnish |230|---------|---------|--------|--------|---------|-------|---------|231| Monday | måndag | Montag | lundi | lunes | maandag | maanantai |232| Tuesday | tisdag | Dienstag | mardi | martes | dinsdag | tiistai |233| Wednesday | onsdag | Mittwoch | mercredi | miércoles | woensdag | keskiviikko |234| Thursday | torsdag | Donnerstag | jeudi | jueves | donderdag | torstai |235| Friday | fredag | Freitag | vendredi | viernes | vrijdag | perjantai |236| Saturday | lördag | Samstag | samedi | sábado | zaterdag | lauantai |237| Sunday | söndag | Sonntag | dimanche | domingo | zondag | sunnuntai |238239### Time Formatting240241**24-hour vs. 12-hour**:242243| Language | Clock | Example | Note |244|----------|-------|---------|------|245| English (en) | 12-hour | 2:30 PM | AM/PM required |246| Swedish (sv) | 24-hour | 14:30 | Period or colon separator |247| German (de) | 24-hour | 14:30 Uhr | "Uhr" suffix |248| French (fr) | 24-hour | 14h30 | "h" separator |249| Spanish (es) | 24-hour | 14:30 | Colon separator |250| Nordic (da, no, fi) | 24-hour | 14:30 or 14.30 | Period common |251| CJK (ja, ko, zh) | 24-hour | 14:30 | Colon separator |252| Arabic (ar) | 12-hour | ٢:٣٠ م | Arabic-Indic optional |253| Hebrew (he) | 24-hour | 14:30 | Colon separator |254255### Currency Formatting256257**Swedish Krona (SEK)**:258259| Language | Format | Example | Note |260|----------|--------|---------|------|261| English | SEK 1,000.50 or 1,000.50 kr | SEK 1,000.50 | Currency code preferred |262| Swedish | 1 000,50 kr | 1 000,50 kr | "kr" suffix standard |263| German | 1 000,50 SEK | 1 000,50 SEK | Currency code suffix |264| French | 1 000,50 SEK | 1 000,50 SEK | Currency code suffix |265266### Ordinal Numbers267268| Language | Example | Pattern |269|----------|---------|---------|270| English | 1st, 2nd, 3rd, 4th | -st, -nd, -rd, -th |271| Swedish | 1:a, 2:a, 3:e, 4:e | :a or :e |272| German | 1., 2., 3., 4. | Period suffix |273| French | 1er, 2e, 3e, 4e | -er for first, -e for rest |274| Spanish | 1.º, 2.º, 3.º, 4.º | Masculine ordinal |275276### Practical Implementation277278**Date Formatting Function**:279```javascript280function formatDate(date, lang) {281 const months = {282 en: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],283 sv: ['januari', 'februari', 'mars', 'april', 'maj', 'juni', 'juli', 'augusti', 'september', 'oktober', 'november', 'december'],284 de: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],285 fr: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'],286 es: ['enero', 'febrero', 'marzo', 'abril', 'mayo', 'junio', 'julio', 'agosto', 'septiembre', 'octubre', 'noviembre', 'diciembre'],287 da: ['januar', 'februar', 'marts', 'april', 'maj', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'december'],288 no: ['januar', 'februar', 'mars', 'april', 'mai', 'juni', 'juli', 'august', 'september', 'oktober', 'november', 'desember'],289 nl: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december'],290 fi: ['tammikuuta', 'helmikuuta', 'maaliskuuta', 'huhtikuuta', 'toukokuuta', 'kesäkuuta', 'heinäkuuta', 'elokuuta', 'syyskuuta', 'lokakuuta', 'marraskuuta', 'joulukuuta']291 };292 293 const d = date.getDate();294 const m = date.getMonth();295 const y = date.getFullYear();296 297 if (lang === 'en') return `${months[lang][m]} ${d}, ${y}`;298 if (lang === 'de' || lang === 'da' || lang === 'no') return `${d}. ${months[lang][m]} ${y}`;299 if (lang === 'es') return `${d} de ${months[lang][m]} de ${y}`;300 if (lang === 'fi') return `${d}. ${months[lang][m]} ${y}`;301 if (lang === 'ja') return `${y}年${m+1}月${d}日`;302 if (lang === 'ko') return `${y}년 ${m+1}월 ${d}일`;303 if (lang === 'zh') return `${y}年${m+1}月${d}日`;304 return `${d} ${months[lang]?.[m] || months['en'][m]} ${y}`; // Default format with fallback305}306```307308### Validation Checklist309310For each language version, verify:311- [ ] Numbers use correct thousands separator312- [ ] Numbers use correct decimal point313- [ ] Dates follow language convention314- [ ] Month names correctly translated and case-appropriate315- [ ] Day names correctly translated316- [ ] Time uses 24-hour format (except English)317- [ ] Currency formatted per convention318- [ ] Ordinals follow language pattern319320---321322**Data Source**: Validated against 81 news articles (Feb 2026) 323**Standards**: Unicode CLDR, ISO 8601 324**Last Updated**: 2026-02-15325326---327> Converted and distributed by [TomeVault](https://tomevault.io/claim/hack23) — claim your Tome and manage your conversions.328<!-- tomevault:4.0:skill_md:2026-04-13 -->