Serving Diverse Language Communities
Immigration advocacy platforms must serve linguistically diverse communities. Language selection must be frictionless and intuitive.
Language Switcher Best Practices
Placement
| Layout | Position |
|---|---|
| LTR (Left-to-Right) | Top right of header |
| RTL (Right-to-Left) | Top left of header |
Labeling
Languages must always be labeled in native script:
<nav class="language-switcher" aria-label="Select language">
<ul>
<li><a href="/en/" hreflang="en" lang="en">English</a></li>
<li><a href="/es/" hreflang="es" lang="es">Español</a></li>
<li><a href="/zh/" hreflang="zh" lang="zh">中文</a></li>
<li><a href="/vi/" hreflang="vi" lang="vi">Tiếng Việt</a></li>
<li><a href="/ar/" hreflang="ar" lang="ar">العربية</a></li>
</ul>
</nav>
Avoid Flags
Never use national flags to represent languages:
| Problem | Example |
|---|---|
| Languages span nations | Spanish: Spain, Mexico, 20+ countries |
| Political sensitivities | Flags invoke national tensions |
| Exclusionary | Displaced populations may reject origin flags |
Persistence
// Save language preference
function setLanguage(lang) {
// Local storage for persistence
localStorage.setItem('preferred-language', lang);
// Cookie for server-side rendering
document.cookie = `lang=${lang}; path=/; max-age=31536000`;
// Redirect to translated page
window.location.href = `/${lang}${window.location.pathname}`;
}
// Auto-detect on first visit
if (!localStorage.getItem('preferred-language')) {
const browserLang = navigator.language.split('-')[0];
const supportedLangs = ['en', 'es', 'zh', 'vi', 'ar'];
if (supportedLangs.includes(browserLang)) {
// Suggest but don't force
showLanguageSuggestion(browserLang);
}
}
Language Suggestion Banner
<div class="language-suggestion" role="dialog" aria-labelledby="lang-heading">
<h2 id="lang-heading">¿Prefiere español?</h2>
<p>This page is available in Spanish.</p>
<div class="language-suggestion__actions">
<a href="/es/" class="button--primary">Ver en español</a>
<button class="button--secondary" onclick="dismissSuggestion()">
Continue in English
</button>
</div>
</div>
Right-to-Left (RTL) Support
Languages Requiring RTL
- Arabic (العربية)
- Hebrew (עברית)
- Farsi/Persian (فارسی)
- Urdu (اردو)
HTML Setup
<html lang="ar" dir="rtl">
CSS Mirroring
/* Base LTR styles */
.sidebar {
margin-left: 2rem;
padding-left: 1rem;
border-left: 4px solid var(--color-primary);
}
/* RTL override */
[dir="rtl"] .sidebar {
margin-left: 0;
margin-right: 2rem;
padding-left: 0;
padding-right: 1rem;
border-left: none;
border-right: 4px solid var(--color-primary);
}
/* Modern approach: logical properties */
.sidebar {
margin-inline-start: 2rem;
padding-inline-start: 1rem;
border-inline-start: 4px solid var(--color-primary);
}
Elements to Mirror
| Element | LTR | RTL | Mirror? |
|---|---|---|---|
| Text alignment | Left | Right | Yes |
| Navigation | Left | Right | Yes |
| Icons (back arrow) | ← | → | Yes |
| Progress bars | Left to right | Right to left | Yes |
| Numbers | Left to right | Left to right | No |
| Clocks | Clockwise | Clockwise | No |
| Phone numbers | LTR | LTR | No |
| URLs/Code | LTR | LTR | No |
Mixed Direction Content
English legal terms in Arabic text require isolation:
<p dir="rtl">
للحصول على
<span dir="ltr" lang="en">Habeas Corpus</span>
يجب تقديم الطلب
</p>
/* Isolate embedded LTR content */
[dir="rtl"] .legal-term {
unicode-bidi: isolate;
direction: ltr;
}
Code-Switching Patterns
Understanding Code-Switching
Bilingual communities frequently mix languages:
| Type | Example |
|---|---|
| Inter-sentential | "I need to apply for DACA. ¿Cómo empiezo?" |
| Intra-sentential | "Necesito ver mi green card status" |
| Tag-switching | "That's right, ¿verdad?" |
Search Tolerance
// Accept mixed-language queries
const searchNormalizer = (query) => {
// Map common code-switched terms
const mappings = {
'la migra': 'ice',
'papeles': 'documentation',
'corte de inmigración': 'immigration court',
'abogado': 'lawyer attorney',
'deportación': 'removal deportation'
};
let normalized = query.toLowerCase();
for (const [term, replacement] of Object.entries(mappings)) {
normalized = normalized.replace(term, replacement);
}
return normalized;
};
Form Input Handling
// Accept mixed-language input without errors
const nameField = document.querySelector('#name');
nameField.setAttribute('lang', ''); // Accept any language
nameField.setAttribute('spellcheck', 'false'); // No red squiggles
Untranslatable Legal Terms
Keep specific legal terminology in English with explanations:
<p>
Puede solicitar
<dfn lang="en" title="Documento legal para obtener custodia temporal">
Habeas Corpus
</dfn>
para desafiar su detención.
</p>
Bilingual Layouts
Side-by-Side Pattern
For legal documents requiring verification:
<div class="bilingual-document">
<div class="bilingual-document__original" lang="en">
<h2>Power of Attorney</h2>
<p>I hereby grant full authority to...</p>
</div>
<div class="bilingual-document__translation" lang="es">
<h2>Poder Notarial</h2>
<p>Por la presente otorgo plena autoridad a...</p>
</div>
</div>
.bilingual-document {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
}
@media (max-width: 768px) {
.bilingual-document {
grid-template-columns: 1fr;
}
}
Toggle Pattern
<div class="content-toggle">
<button aria-pressed="true" data-lang="en">English</button>
<button aria-pressed="false" data-lang="es">Español</button>
</div>
<div class="content" lang="en">
<!-- English content -->
</div>
<div class="content" lang="es" hidden>
<!-- Spanish content -->
</div>
Typography for Non-Latin Scripts
Script Categories
| Category | Scripts | Considerations |
|---|---|---|
| English-like | Latin, Greek, Cyrillic | Standard line height |
| Tall | Arabic, Hindi, Thai, Vietnamese | Extra line height |
| Dense | Chinese, Japanese, Korean | Square characters, special wrapping |
Vietnamese Typography
Vietnamese uses Latin alphabet with stacked diacritics:
/* Extra line height for diacritics */
[lang="vi"] {
line-height: 1.8;
font-family: 'Noto Sans', sans-serif;
}
CJK Typography
/* Chinese, Japanese, Korean */
[lang="zh"], [lang="ja"], [lang="ko"] {
line-height: 1.7;
word-break: keep-all; /* Prevent mid-word breaks */
overflow-wrap: break-word;
}
/* Punctuation handling */
[lang="zh"] {
font-feature-settings: "halt" 1; /* Proper CJK punctuation */
}
Arabic Typography
[lang="ar"] {
font-family: 'Noto Naskh Arabic', 'Amiri', serif;
line-height: 2; /* Arabic requires generous line height */
letter-spacing: 0; /* Maintain cursive connections */
}
Font Loading Optimization
Unicode Subsetting
Only download glyphs needed for current language:
/* Latin subset */
@font-face {
font-family: 'Noto Sans';
src: url('/fonts/NotoSans-Latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153;
font-display: swap;
}
/* Arabic subset - only loads on Arabic pages */
@font-face {
font-family: 'Noto Sans Arabic';
src: url('/fonts/NotoSansArabic.woff2') format('woff2');
unicode-range: U+0600-06FF, U+FB50-FDFF, U+FE70-FEFF;
font-display: swap;
}
/* Chinese subset */
@font-face {
font-family: 'Noto Sans SC';
src: url('/fonts/NotoSansSC-Regular.woff2') format('woff2');
unicode-range: U+4E00-9FFF; /* CJK Unified Ideographs */
font-display: swap;
}
Font Stacks
/* Multilingual font stack */
:root {
--font-sans: 'Inter', 'Noto Sans', 'Noto Sans Arabic',
'Noto Sans SC', 'Noto Sans JP', system-ui, sans-serif;
}
body {
font-family: var(--font-sans);
}
11ty Multilingual Setup
Directory Structure
src/
├── en/
│ ├── know-your-rights/
│ │ └── home-raids.md
│ └── en.json (directory data)
├── es/
│ ├── conozca-sus-derechos/
│ │ └── redadas-en-casa.md
│ └── es.json
├── zh/
│ └── zh.json
└── _data/
└── i18n/
├── en.json
├── es.json
└── zh.json
Language Data Files
// src/en/en.json
{
"lang": "en",
"dir": "ltr",
"locale": "en-US"
}
// src/ar/ar.json
{
"lang": "ar",
"dir": "rtl",
"locale": "ar"
}
Hreflang Tags
{# Generate hreflang for all translations #}
{% for lang in ['en', 'es', 'zh', 'vi', 'ar'] %}
<link rel="alternate"
hreflang="{{ lang }}"
href="{{ site.url }}/{{ lang }}{{ page.url }}">
{% endfor %}
<link rel="alternate" hreflang="x-default" href="{{ site.url }}/en{{ page.url }}">
Testing Checklist
Language Switching
- [ ] All languages accessible from any page
- [ ] Preference persists across sessions
- [ ] Auto-detect suggests but doesn't force
- [ ] Native script labels used
RTL Support
- [ ] Arabic/Hebrew layouts fully mirrored
- [ ] Mixed content isolated correctly
- [ ] Navigation icons reversed
- [ ] Forms aligned properly
Typography
- [ ] Vietnamese diacritics not clipped
- [ ] CJK characters properly wrapped
- [ ] Arabic cursive connections intact
- [ ] Font subsets loading correctly
Related Resources
- Multilingual SEO - Hreflang, localized keywords
- Multilingual Chatbot - Language-specific AI
- Accessibility - Screen reader i18n
- Performance - Font optimization