- name
- multi-language-localization
- description
- Best practices for multi-language static websites with proper i18n and l10n support
- license
- Apache-2.0
# Multi-Language Localization Skill
## 🔴 AI FIRST Quality Principle
> **Apply the AI FIRST principle: never accept first-pass quality. Minimum 2 iterations. Read all output, improve every section. No shortcuts.**
## Purpose
Implement proper internationalization (i18n) and localization (l10n) for static websites supporting multiple languages.
## Core Principles
### 1. Language Declaration
```html
<!-- ✅ 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
```html
<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
```css
/* 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
```html
<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
```xml
<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
- [W3C Internationalization](https://www.w3.org/International/)
- [MDN Localization](https://developer.mozilla.org/en-US/docs/Mozilla/Localization)
---
## 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**:
```javascript
// 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 |
GitHubで見る