Skip to content

Conversation

@KhanbalaRashidov
Copy link

Overview

Refactored the entire internationalization (i18n) system from hardcoded Go functions to a dynamic JSON-based loader using reflection. This change makes adding new languages as simple as creating a JSON file - no code changes required.

What Changed

Before (Static Approach)

  • Each language required a new Go function (e.g., spanishSet(), frenchSet())
  • 100+ lines of manual field mapping per language
  • Required recompilation for every new language
  • Not accessible to non-developers/translators

After (Dynamic Approach)

  • Languages defined in JSON files (translations/en.json, translations/es.json, etc.)
  • Automatic mapping using reflection
  • Zero code changes needed for new languages
  • Translators can directly edit JSON files

Technical Details

New Architecture

  1. TranslationLoader: Manages loading and caching of translations from JSON
  2. Reflection-based Mapping: Automatically maps JSON keys to struct fields
  3. Cache System: Loaded translations are cached for performance
  4. Fallback Chain: Automatically falls back to English if requested language unavailable

Key Files Added

  • pkg/i18n/i18n.go - Dynamic loader with reflection
  • pkg/i18n/types.go - Type definitions
  • translations/*.json - Language files (en, az, tr, es)
  • create_language.py - Utility to generate new language files
  • create_language.sh - Bash alternative for language generation

Performance

  • First load: Reads from JSON (slower)
  • Subsequent loads: Retrieved from cache (fast)
  • Memory overhead: Minimal (only loaded languages cached)

Migration Guide

Old Code

func spanishSet() TranslationSet {
    return TranslationSet{
        GlobalTitle: "Global",
        MainTitle: "Inicio",
        Remove: "borrar",
        // ... 100+ more lines
    }
}

New Code

{
  "code": "es",
  "name": "Español",
  "translations": {
    "GlobalTitle": "Global",
    "MainTitle": "Inicio",
    "Remove": "borrar"
  }
}

Usage Example

// Load translation dynamically
ts, err := i18n.NewTranslationSetFromConfig(
    logger,
    "es",              // language code
    "./translations",  // path to JSON files
)

// Use it
fmt.Println(ts.GlobalTitle)  // "Global"

Adding New Languages

Method 1: Using Python Script

python3 create_language.py ru "Русский"
# Edit translations/ru.json

Method 2: Using Bash Script

./create_language.sh de "Deutsch"
# Edit translations/de.json

Method 3: Manual

Create translations/xx.json with structure:

{
  "code": "xx",
  "name": "Language Name",
  "translations": {
    "Key": "Translation"
  }
}

Benefits

For Developers

  • ✅ No more repetitive code for each language
  • ✅ Easier to maintain and extend
  • ✅ Type-safe through reflection
  • ✅ Automatic validation

For Translators

  • ✅ Simple JSON format
  • ✅ No programming knowledge required
  • ✅ Can use translation tools/editors
  • ✅ Easy to review changes in PRs

For Project

  • ✅ Scalable to 100+ languages
  • ✅ Reduced code complexity
  • ✅ Better separation of concerns
  • ✅ Community contributions easier

Backward Compatibility

The old static functions (englishSet(), spanishSet(), etc.) remain as fallback if JSON loading fails, ensuring zero breaking changes.

Testing

Tested with 4 languages:

  • ✅ English (en) - Base language
  • ✅ Azerbaijani (az) - Full translation
  • ✅ Turkish (tr) - Full translation
  • ✅ Spanish (es) - Full translation

Files Changed

  • Modified: pkg/i18n/i18n.go (refactored to use reflection)
  • Added: pkg/i18n/types.go (type definitions)
  • Added: translations/en.json (English)
  • Added: translations/az.json (Azerbaijani)
  • Added: translations/tr.json (Turkish)
  • Added: translations/es.json (Spanish)
  • Added: create_language.py (utility script)
  • Added: create_language.sh (utility script)
  • Added: USAGE.md (documentation)

Future Enhancements

Possible additions:

  1. Hot-reload support (file watcher)
  2. Remote translation loading (API/database)
  3. Plural forms support
  4. Variable interpolation
  5. Translation validation tools

Breaking Changes

None. The system maintains backward compatibility with existing code.


Closes: #XXX (if applicable)
Related: Translation system modernization initiative

## Overview
Refactored the entire internationalization (i18n) system from hardcoded Go functions to a dynamic JSON-based loader using reflection. This change makes adding new languages as simple as creating a JSON file - no code changes required.

## What Changed

### Before (Static Approach)
- Each language required a new Go function (e.g., `spanishSet()`, `frenchSet()`)
- 100+ lines of manual field mapping per language
- Required recompilation for every new language
- Not accessible to non-developers/translators

### After (Dynamic Approach)
- Languages defined in JSON files (`translations/en.json`, `translations/es.json`, etc.)
- Automatic mapping using reflection
- Zero code changes needed for new languages
- Translators can directly edit JSON files

## Technical Details

### New Architecture
1. **TranslationLoader**: Manages loading and caching of translations from JSON
2. **Reflection-based Mapping**: Automatically maps JSON keys to struct fields
3. **Cache System**: Loaded translations are cached for performance
4. **Fallback Chain**: Automatically falls back to English if requested language unavailable

### Key Files Added
- `pkg/i18n/i18n.go` - Dynamic loader with reflection
- `pkg/i18n/types.go` - Type definitions
- `translations/*.json` - Language files (en, az, tr, es)
- `create_language.py` - Utility to generate new language files
- `create_language.sh` - Bash alternative for language generation

### Performance
- First load: Reads from JSON (slower)
- Subsequent loads: Retrieved from cache (fast)
- Memory overhead: Minimal (only loaded languages cached)

## Migration Guide

### Old Code
```go
func spanishSet() TranslationSet {
    return TranslationSet{
        GlobalTitle: "Global",
        MainTitle: "Inicio",
        Remove: "borrar",
        // ... 100+ more lines
    }
}
```

### New Code
```json
{
  "code": "es",
  "name": "Español",
  "translations": {
    "GlobalTitle": "Global",
    "MainTitle": "Inicio",
    "Remove": "borrar"
  }
}
```

### Usage Example
```go
// Load translation dynamically
ts, err := i18n.NewTranslationSetFromConfig(
    logger,
    "es",              // language code
    "./translations",  // path to JSON files
)

// Use it
fmt.Println(ts.GlobalTitle)  // "Global"
```

## Adding New Languages

### Method 1: Using Python Script
```bash
python3 create_language.py ru "Русский"
# Edit translations/ru.json
```

### Method 2: Using Bash Script
```bash
./create_language.sh de "Deutsch"
# Edit translations/de.json
```

### Method 3: Manual
Create `translations/xx.json` with structure:
```json
{
  "code": "xx",
  "name": "Language Name",
  "translations": {
    "Key": "Translation"
  }
}
```

## Benefits

### For Developers
- ✅ No more repetitive code for each language
- ✅ Easier to maintain and extend
- ✅ Type-safe through reflection
- ✅ Automatic validation

### For Translators
- ✅ Simple JSON format
- ✅ No programming knowledge required
- ✅ Can use translation tools/editors
- ✅ Easy to review changes in PRs

### For Project
- ✅ Scalable to 100+ languages
- ✅ Reduced code complexity
- ✅ Better separation of concerns
- ✅ Community contributions easier

## Backward Compatibility

The old static functions (`englishSet()`, `spanishSet()`, etc.) remain as fallback if JSON loading fails, ensuring zero breaking changes.

## Testing

Tested with 4 languages:
- ✅ English (en) - Base language
- ✅ Azerbaijani (az) - Full translation
- ✅ Turkish (tr) - Full translation
- ✅ Spanish (es) - Full translation

## Files Changed
- Modified: `pkg/i18n/i18n.go` (refactored to use reflection)
- Added: `pkg/i18n/types.go` (type definitions)
- Added: `translations/en.json` (English)
- Added: `translations/az.json` (Azerbaijani)
- Added: `translations/tr.json` (Turkish)
- Added: `translations/es.json` (Spanish)
- Added: `create_language.py` (utility script)
- Added: `create_language.sh` (utility script)
- Added: `USAGE.md` (documentation)

## Future Enhancements

Possible additions:
1. Hot-reload support (file watcher)
2. Remote translation loading (API/database)
3. Plural forms support
4. Variable interpolation
5. Translation validation tools

## Breaking Changes
None. The system maintains backward compatibility with existing code.

---

**Closes**: #XXX (if applicable)
**Related**: Translation system modernization initiative
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant