|
| 1 | +# Internationalization (i18n) and Localization (l10n) Implementation |
| 2 | + |
| 3 | +This document explains how we implemented internationalization and localization in the PDF project. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +We've implemented a complete i18n/l10n solution that allows the application to be translated into multiple languages. The implementation consists of: |
| 8 | + |
| 9 | +1. A standalone localizer library (`@profullstack/localizer`) that provides the core functionality |
| 10 | +2. Translation files for each supported language |
| 11 | +3. Integration with the application's UI components |
| 12 | +4. A language switcher component |
| 13 | + |
| 14 | +## Localizer Library |
| 15 | + |
| 16 | +The `@profullstack/localizer` library is a lightweight, dependency-free library that provides: |
| 17 | + |
| 18 | +- Simple API for translating text |
| 19 | +- Support for multiple languages |
| 20 | +- Fallback to default language when a translation is missing |
| 21 | +- Interpolation of variables in translations |
| 22 | +- Support for pluralization |
| 23 | +- Works in both browser and Node.js environments |
| 24 | + |
| 25 | +The library is published as an npm package and can be used in any JavaScript project. |
| 26 | + |
| 27 | +## Translation Files |
| 28 | + |
| 29 | +Translation files are stored in the `public/i18n` directory as JSON files, with one file per language: |
| 30 | + |
| 31 | +- `en.json`: English (default) |
| 32 | +- `fr.json`: French |
| 33 | +- `de.json`: German |
| 34 | + |
| 35 | +Each file contains translations for all the text in the application, organized in a nested structure: |
| 36 | + |
| 37 | +```json |
| 38 | +{ |
| 39 | + "navigation": { |
| 40 | + "dashboard": "Dashboard", |
| 41 | + "api_docs": "API Docs", |
| 42 | + "api_keys": "API Keys", |
| 43 | + ... |
| 44 | + }, |
| 45 | + "errors": { |
| 46 | + "page_not_found": "404 - Page Not Found", |
| 47 | + ... |
| 48 | + }, |
| 49 | + ... |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +## Integration with the Application |
| 54 | + |
| 55 | +The integration is handled by the `public/js/i18n.js` file, which: |
| 56 | + |
| 57 | +1. Imports the localizer library |
| 58 | +2. Loads the translation files |
| 59 | +3. Sets the initial language based on browser preference or localStorage |
| 60 | +4. Provides functions to translate text and change the language |
| 61 | +5. Observes DOM changes to translate dynamically added content |
| 62 | + |
| 63 | +Since the localizer library expects flat key-value pairs, we implemented a `flattenObject` function that converts the nested translation structure to a flat one: |
| 64 | + |
| 65 | +```javascript |
| 66 | +function flattenObject(obj, prefix = '') { |
| 67 | + return Object.keys(obj).reduce((acc, key) => { |
| 68 | + const prefixedKey = prefix ? `${prefix}.${key}` : key; |
| 69 | + |
| 70 | + if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) { |
| 71 | + Object.assign(acc, flattenObject(obj[key], prefixedKey)); |
| 72 | + } else { |
| 73 | + acc[prefixedKey] = obj[key]; |
| 74 | + } |
| 75 | + |
| 76 | + return acc; |
| 77 | + }, {}); |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +## Language Switcher Component |
| 82 | + |
| 83 | +We created a `language-switcher` web component (`public/js/components/language-switcher.js`) that allows users to switch between languages. The component: |
| 84 | + |
| 85 | +1. Displays a dropdown with available languages |
| 86 | +2. Shows the current language |
| 87 | +3. Allows users to select a new language |
| 88 | +4. Updates the UI when the language changes |
| 89 | + |
| 90 | +## Usage in HTML |
| 91 | + |
| 92 | +To translate text in HTML, we use the `data-i18n` attribute: |
| 93 | + |
| 94 | +```html |
| 95 | +<span data-i18n="navigation.dashboard">Dashboard</span> |
| 96 | +``` |
| 97 | + |
| 98 | +For interpolation, we use the `data-i18n-params` attribute: |
| 99 | + |
| 100 | +```html |
| 101 | +<span data-i18n="errors.page_not_found_message" data-i18n-params='{"path":"/example"}'> |
| 102 | + The page "/example" could not be found. |
| 103 | +</span> |
| 104 | +``` |
| 105 | + |
| 106 | +## Usage in JavaScript |
| 107 | + |
| 108 | +To translate text in JavaScript, we use the `_t` function: |
| 109 | + |
| 110 | +```javascript |
| 111 | +import { _t } from '/js/i18n.js'; |
| 112 | + |
| 113 | +const message = _t('common.loading'); |
| 114 | +const welcomeMessage = _t('auth.welcome', { name: 'John' }); |
| 115 | +``` |
| 116 | + |
| 117 | +## Demo Page |
| 118 | + |
| 119 | +We created a demo page (`public/views/i18n-demo.html`) that showcases the localization features: |
| 120 | + |
| 121 | +1. Language selection |
| 122 | +2. Basic translations |
| 123 | +3. Interpolation |
| 124 | +4. JavaScript API |
| 125 | + |
| 126 | +## Adding a New Language |
| 127 | + |
| 128 | +To add a new language: |
| 129 | + |
| 130 | +1. Create a new translation file in the `public/i18n` directory (e.g., `es.json` for Spanish) |
| 131 | +2. Add the language code to the `AVAILABLE_LANGUAGES` array in `public/js/i18n.js` |
| 132 | +3. Add the language name to the `getLanguageName` function in both `public/js/i18n.js` and `public/js/components/language-switcher.js` |
| 133 | + |
| 134 | +## Adding New Translations |
| 135 | + |
| 136 | +To add new translations: |
| 137 | + |
| 138 | +1. Add the new keys and values to each language file |
| 139 | +2. Use the `data-i18n` attribute or `_t` function to translate the text |
| 140 | + |
| 141 | +## Future Improvements |
| 142 | + |
| 143 | +Possible future improvements include: |
| 144 | + |
| 145 | +1. Adding more languages |
| 146 | +2. Supporting region-specific languages (e.g., `en-US`, `en-GB`) |
| 147 | +3. Adding a translation management system |
| 148 | +4. Implementing automatic translation detection |
| 149 | +5. Adding support for RTL languages |
0 commit comments