Emergency Hotline: Call 1-844-363-1423 (United We Dream Hotline)
ICE Encounter

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