# Portability: UNIVERSAL
# Last validated: 2026-03-08 (Claude/BACH wiki-author)
# Next review: 2027-03-08
# Sources: Unicode CLDR, GNU gettext Manual, MDN Web Docs (Intl API), W3C i18n Best Practices

INTERNATIONALIZATION (i18n) AND LOCALIZATION (l10n)
====================================================

Date: 2026-03-08
Language: EN


WHAT IS i18n?
--------------
i18n is the abbreviation for "internationalization" (i + 18 letters + n).
It means: designing software so it can support multiple languages and
regions without requiring source code changes.

The related term l10n stands for "localization" (l + 10 letters + n)
and refers to the actual translation and adaptation for a specific
language or region.

  i18n = Preparation (architecture)
  l10n = Implementation (content)


WHY i18n?
----------
  - Global reach: 75% of internet users don't speak English
  - Legal requirements: EU regulations, accessibility laws
  - User experience: People prefer software in their language
  - Market expansion: New markets without code changes


WHAT GETS INTERNATIONALIZED?
------------------------------

  Aspect            i18n (Preparation)          l10n (Implementation)
  -----------------------------------------------------------------------
  Text              Externalize strings         Translate to DE, FR, ES...
  Numbers           Build format system         1,000.00 vs 1.000,00
  Date/Time         Locale-aware formatters     03/08/2026 vs 08.03.2026
  Currency          Dynamic symbol              $, EUR, ¥
  Sorting           Locale-aware collation      ae vs ä ordering
  Plurals           Plural rule system          1 file vs 2 files
  Text direction    RTL support                 Arabic, Hebrew
  Images/Icons      Culturally neutral assets   Local adaptations
  Units             Unit system                 Metric vs Imperial


TECHNICAL IMPLEMENTATION
--------------------------

  1. Externalize strings
  ----------------------
  NEVER hardcode text. Extract all visible strings to separate files.

    Bad:
      print("File saved")

    Good:
      print(_("File saved"))

  2. Locale identifier (BCP 47 / IETF)
  --------------------------------------
    en          English (general)
    en-US       English (United States)
    en-GB       English (Great Britain)
    de-DE       German (Germany)
    de-AT       German (Austria)
    de-CH       German (Switzerland)
    zh-Hans     Chinese (simplified)
    zh-Hant     Chinese (traditional)

  3. Unicode and encoding
  ------------------------
    - ALWAYS use UTF-8 (standard since HTML5)
    - Database, files, API responses: all UTF-8
    - Python: PYTHONIOENCODING=utf-8 (especially on Windows)


TRANSLATION FILE FORMATS
--------------------------

  Format       Use case                      Notes
  ------------------------------------------------------------------
  .po/.mo      gettext (Python, C, PHP)      GNU standard
  .json        Web apps (React, Vue)         i18next, vue-i18n
  .xliff       Enterprise, iOS               XML-based, tool-compatible
  .arb         Flutter/Dart                  JSON variant
  .strings     iOS/macOS (native)            Apple format
  .xml         Android                       res/values-de/strings.xml
  .resx        .NET/C#                       XML-based
  .properties  Java                          key=value
  .ts          Qt/PySide6                    Qt Linguist


i18n IN PYTHON (gettext)
--------------------------

  Setup:

    import gettext
    import locale

    # Set locale
    locale.setlocale(locale.LC_ALL, '')

    # Load translations
    lang = gettext.translation('myapp', localedir='locales', languages=['de'])
    lang.install()
    _ = lang.gettext

    # Usage
    print(_("File saved"))           # -> "Datei gespeichert"
    print(_("Welcome, %s") % name)   # -> "Willkommen, Max"

  Directory structure:

    locales/
    ├── de/LC_MESSAGES/
    │   ├── myapp.po                 # Source file (editable)
    │   └── myapp.mo                 # Compiled (for runtime)
    ├── fr/LC_MESSAGES/
    │   ├── myapp.po
    │   └── myapp.mo
    └── pot/
        └── myapp.pot                # Template (base for all)

  Workflow:
    1. xgettext --language=Python -o myapp.pot *.py    Extract strings
    2. msginit -l de -o de.po -i myapp.pot             Create PO file
    3. Translate (manually or with tool)
    4. msgfmt -o myapp.mo de.po                        Compile


i18n IN JAVASCRIPT/WEB
------------------------

  i18next (popular framework):

    // Initialization
    import i18next from 'i18next';

    i18next.init({
      lng: 'de',
      resources: {
        de: {
          translation: {
            "welcome": "Willkommen, {{name}}!",
            "items_one": "{{count}} Artikel",
            "items_other": "{{count}} Artikel"
          }
        },
        en: {
          translation: {
            "welcome": "Welcome, {{name}}!",
            "items_one": "{{count}} item",
            "items_other": "{{count}} items"
          }
        }
      }
    });

    i18next.t('welcome', { name: 'Max' });  // "Willkommen, Max!"

  Browser Intl API (native):

    // Numbers
    new Intl.NumberFormat('de-DE').format(1234.5)    // "1.234,5"
    new Intl.NumberFormat('en-US').format(1234.5)    // "1,234.5"

    // Dates
    new Intl.DateTimeFormat('de-DE').format(date)    // "08.03.2026"
    new Intl.DateTimeFormat('en-US').format(date)    // "3/8/2026"

    // Currency
    new Intl.NumberFormat('de-DE', {
      style: 'currency', currency: 'EUR'
    }).format(42.5)                                  // "42,50 EUR"


i18n IN PYSIDE6/QT
--------------------

  Qt Linguist workflow:

    # In code: use tr()
    from PySide6.QtWidgets import QLabel
    label = QLabel(self.tr("File saved"))

    # Extract strings
    pyside6-lupdate main.py -ts translations/app_de.ts

    # Translate in Qt Linguist
    pyside6-linguist translations/app_de.ts

    # Compile
    pyside6-lrelease translations/app_de.ts

    # Load
    from PySide6.QtCore import QTranslator
    translator = QTranslator()
    translator.load("translations/app_de.qm")
    app.installTranslator(translator)


BEST PRACTICES
---------------
  - Start early: retrofitting i18n is expensive
  - No string concatenation for sentences (word order varies!)
  - Handle plural forms (Russian has 3, Arabic has 6)
  - Plan for space: German text is ~30% longer than English
  - Provide context: "Open" can mean "to open" or "is open"
  - Avoid images with text (must be created per language)
  - Test RTL layout when relevant
  - Use professional translators (not just Google Translate)
  - Use translation management tools (Crowdin, Transifex, Weblate)


BACH CONTEXT
-------------
BACH uses its own i18n system with database tables:

  languages_config        Configured languages and fallbacks
  languages_translations  All translated strings (key -> locale -> text)

Handler: bach language list, bach language set <code>

BACH agents and skills contain strings in DE (primary) and EN.
The commit style "i18n:" is used for translation changes.


SEE ALSO
---------
  wiki/informatik/softwareentwicklung/i18n.txt      i18n (Deutsch)
  wiki/informatik/softwareentwicklung/README.txt    Software development
  wiki/informatik/web_entwicklung/                  Web development
