diff --git a/demo/python-basic/README.md b/demo/python-basic/README.md new file mode 100644 index 000000000..11f3e4f21 --- /dev/null +++ b/demo/python-basic/README.md @@ -0,0 +1,197 @@ +# Python Basic Example for Lingo.dev + +A simple Python example demonstrating how to use translations from Lingo.dev in backend applications, CLI tools, or scripts without requiring any frontend framework. + +## Overview + +This example shows how to: +- Load translation JSON files exported from Lingo.dev +- Access translations in a Python environment +- Switch languages dynamically at runtime +- Handle missing translation keys gracefully + +## Project Structure + +``` +demo/python-basic/ +├── translations/ +│ ├── en.json # English translations +│ ├── hi.json # Hindi translations +│ └── es.json # Spanish translations +├── translator.py # Translator class implementation +├── app.py # Demo application +└── README.md # This file +``` + +## Requirements + +- Python 3.7 or higher +- No external dependencies required (uses only Python standard library) + +## Quick Start + +1. **Navigate to the example directory:** + ```bash + cd demo/python-basic + ``` + +2. **Run the demo application:** + ```bash + python app.py + ``` + +## Usage + +### Basic Usage + +```python +from translator import Translator + +# Initialize with default language (English) +t = Translator(lang="en") + +# Get a translation +print(t.t("greeting")) # Output: Hello + +# Switch to another language +t.set_language("hi") +print(t.t("greeting")) # Output: नमस्ते +``` + +### Advanced Features + +```python +# Get available languages +languages = t.get_available_languages() +print(languages) # Output: ['en', 'hi', 'es'] + +# Get current language +current = t.get_current_language() +print(current) # Output: en + +# Handle missing keys with default values +translation = t.t("missing_key", "Default text") + +# Get all translations for current language +all_translations = t.get_all_translations() +``` + +### Custom Translation Path + +```python +# Use a custom path for translation files +t = Translator(lang="en", translations_path="path/to/translations") +``` + +## Integration Examples + +### Flask Application + +```python +from flask import Flask, request +from translator import Translator + +app = Flask(__name__) + +@app.route('/api/greeting') +def greeting(): + lang = request.args.get('lang', 'en') + t = Translator(lang=lang) + return {'message': t.t('greeting')} + +if __name__ == '__main__': + app.run() +``` + +### FastAPI Application + +```python +from fastapi import FastAPI, Query +from translator import Translator + +app = FastAPI() + +@app.get("/greeting") +async def get_greeting(lang: str = Query(default="en")): + t = Translator(lang=lang) + return {"message": t.t("greeting")} +``` + +### CLI Tool + +```python +import argparse +from translator import Translator + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--lang', default='en', help='Language code') + args = parser.parse_args() + + t = Translator(lang=args.lang) + print(t.t('welcome_message')) + +if __name__ == '__main__': + main() +``` + +## Translation File Format + +Translation files are simple JSON files with key-value pairs: + +```json +{ + "greeting": "Hello", + "farewell": "Goodbye", + "welcome_message": "Welcome to Lingo.dev!" +} +``` + +## Adding New Languages + +1. Create a new JSON file in the `translations/` directory (e.g., `fr.json`) +2. Add your translations following the same key structure +3. Use the new language code with `set_language("fr")` + +## Error Handling + +The Translator class handles common errors: + +- **Missing translation file**: Raises `FileNotFoundError` with available languages +- **Invalid JSON**: Raises `json.JSONDecodeError` +- **Missing translation key**: Returns the key itself or a provided default value + +## Best Practices + +1. **Organize keys logically**: Use descriptive key names (e.g., `user.profile.title`) +2. **Provide defaults**: Always provide fallback values for missing keys +3. **Cache translator instances**: Reuse translator instances instead of creating new ones +4. **Validate translations**: Ensure all language files have the same keys + +## Extending This Example + +This basic example can be extended with: + +- **Nested translations**: Support for hierarchical key structures +- **Pluralization**: Handle singular/plural forms +- **Variable interpolation**: Insert dynamic values into translations +- **Lazy loading**: Load translation files on-demand +- **Caching**: Cache loaded translations for better performance + +## Contributing + +Feel free to improve this example by: +- Adding more language examples +- Implementing advanced features +- Improving error handling +- Adding unit tests + +## License + +This example is part of the Lingo.dev project and follows the same license. + +## Resources + +- [Lingo.dev Documentation](https://lingo.dev) +- [Lingo.dev GitHub Repository](https://github.com/lingodotdev/lingo.dev) +- [Python i18n Best Practices](https://docs.python.org/3/library/i18n.html) diff --git a/demo/python-basic/app.py b/demo/python-basic/app.py new file mode 100644 index 000000000..b3c355995 --- /dev/null +++ b/demo/python-basic/app.py @@ -0,0 +1,74 @@ +""" +Lingo.dev Python Example - Demo Application + +This script demonstrates how to use the Translator class to manage +translations in a Python application. +""" + +from translator import Translator + + +def main(): + """Main demo function showing various translation features.""" + + print("=" * 60) + print("Lingo.dev Python Translation Example") + print("=" * 60) + print() + + # Initialize translator with English + t = Translator(lang="en") + + # Show available languages + print(f"Available languages: {', '.join(t.get_available_languages())}") + print() + + # Demo 1: Basic translation + print("--- Demo 1: Basic Translation ---") + print(f"Current language: {t.get_current_language()}") + print(f"Translation: {t.t('welcome_message')}") + print(f"Greeting: {t.t('greeting')}") + print(f"Farewell: {t.t('farewell')}") + print() + + # Demo 2: Switch to Hindi + print("--- Demo 2: Switch to Hindi ---") + t.set_language("hi") + print(f"Current language: {t.get_current_language()}") + print(f"Translation: {t.t('welcome_message')}") + print(f"Greeting: {t.t('greeting')}") + print(f"Farewell: {t.t('farewell')}") + print(f"Status: {t.t('language_switched')}") + print() + + # Demo 3: Switch to Spanish + print("--- Demo 3: Switch to Spanish ---") + t.set_language("es") + print(f"Current language: {t.get_current_language()}") + print(f"Translation: {t.t('welcome_message')}") + print(f"Greeting: {t.t('greeting')}") + print(f"Farewell: {t.t('farewell')}") + print(f"Status: {t.t('language_switched')}") + print() + + # Demo 4: Handling missing keys + print("--- Demo 4: Missing Key Handling ---") + print(f"Missing key: {t.t('non_existent_key')}") # Returns the key itself + print(f"With default: {t.t('non_existent_key', 'Default value')}") + print() + + # Demo 5: Get all translations + print("--- Demo 5: All Translations (English) ---") + t.set_language("en") + all_translations = t.get_all_translations() + for key, value in all_translations.items(): + print(f" {key}: {value}") + print() + + print("=" * 60) + print("Demo completed successfully!") + print("=" * 60) + + +if __name__ == "__main__": + main() diff --git a/demo/python-basic/translations/en.json b/demo/python-basic/translations/en.json new file mode 100644 index 000000000..cd4c7a8ca --- /dev/null +++ b/demo/python-basic/translations/en.json @@ -0,0 +1,6 @@ +{ + "greeting": "Hello", + "farewell": "Goodbye", + "welcome_message": "Welcome to Lingo.dev Python Example!", + "language_switched": "Language switched successfully" +} \ No newline at end of file diff --git a/demo/python-basic/translations/es.json b/demo/python-basic/translations/es.json new file mode 100644 index 000000000..12169c246 --- /dev/null +++ b/demo/python-basic/translations/es.json @@ -0,0 +1,6 @@ +{ + "greeting": "Hola", + "farewell": "Adiós", + "welcome_message": "¡Bienvenido al ejemplo de Python de Lingo.dev!", + "language_switched": "Idioma cambiado exitosamente" +} \ No newline at end of file diff --git a/demo/python-basic/translations/hi.json b/demo/python-basic/translations/hi.json new file mode 100644 index 000000000..d9e1e0fdc --- /dev/null +++ b/demo/python-basic/translations/hi.json @@ -0,0 +1,6 @@ +{ + "greeting": "नमस्ते", + "farewell": "अलविदा", + "welcome_message": "Lingo.dev Python उदाहरण में आपका स्वागत है!", + "language_switched": "भाषा सफलतापूर्वक बदल गई" +} \ No newline at end of file diff --git a/demo/python-basic/translator.py b/demo/python-basic/translator.py new file mode 100644 index 000000000..c58a693a4 --- /dev/null +++ b/demo/python-basic/translator.py @@ -0,0 +1,107 @@ +""" +Lingo.dev Python Translator + +A simple translation utility for loading and using Lingo.dev JSON translations +in Python applications. +""" + +import json +import os +from typing import Dict, Any, Optional + + +class Translator: + """ + A lightweight translator class for managing i18n translations. + + Usage: + translator = Translator(lang="en") + print(translator.t("greeting")) # Output: Hello + + translator.set_language("hi") + print(translator.t("greeting")) # Output: नमस्ते + """ + + def __init__(self, lang: str = "en", translations_path: str = "translations"): + """ + Initialize the translator with a default language. + + Args: + lang: The initial language code (e.g., "en", "hi", "es") + translations_path: Path to the directory containing translation JSON files + """ + self.translations_path = translations_path + self.translations: Dict[str, Any] = {} + self.lang: str = "" + self.set_language(lang) + + def set_language(self, lang: str) -> None: + """ + Switch to a different language by loading its translation file. + + Args: + lang: The language code to switch to + + Raises: + FileNotFoundError: If the translation file doesn't exist + json.JSONDecodeError: If the translation file is invalid JSON + """ + file_path = os.path.join(self.translations_path, f"{lang}.json") + + if not os.path.exists(file_path): + raise FileNotFoundError( + f"Translation file not found: {file_path}\n" + f"Available languages: {self.get_available_languages()}" + ) + + with open(file_path, "r", encoding="utf-8") as f: + self.translations = json.load(f) + + self.lang = lang + + def t(self, key: str, default: Optional[str] = None) -> str: + """ + Translate a key to the current language. + + Args: + key: The translation key to look up + default: Optional default value if key is not found + + Returns: + The translated string, or the key itself if not found + """ + return self.translations.get(key, default or key) + + def get_available_languages(self) -> list: + """ + Get a list of available language codes based on JSON files in the translations directory. + + Returns: + List of language codes (e.g., ["en", "hi", "es"]) + """ + if not os.path.exists(self.translations_path): + return [] + + return [ + f.replace(".json", "") + for f in os.listdir(self.translations_path) + if f.endswith(".json") + ] + + def get_current_language(self) -> str: + """ + Get the currently active language code. + + Returns: + The current language code + """ + return self.lang + + def get_all_translations(self) -> Dict[str, Any]: + """ + Get all translations for the current language. + + Returns: + Dictionary of all translation keys and values + """ + return self.translations.copy()