Skip to main content

multi-language-localization

Best practices for multi-language static websites with proper i18n and l10n support

Source facts

Repository
Hack23/riksdagsmonitor
Last source activity
April 16, 2026 at 09:31
Detected SKILL.md language
English
Stars
13
Forks
3

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
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 |
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub