Name shortcut zu mailadler

This commit is contained in:
georg0480
2026-02-04 02:47:35 +01:00
parent f0af0d641f
commit f836c5cf34
27 changed files with 10494 additions and 908 deletions

644
INTERNATIONALISIERUNG.md Normal file
View File

@@ -0,0 +1,644 @@
# Mail-Adler Internationalisierung (i18n) - Deutsch-First Strategie
## 1. Design-Prinzip: Deutsch als Master-Language
### 1.1 Warum Deutsch-First?
**Problem mit Englisch-First:**
```cpp
// ❌ FALSCH: Englisch im Code
const char *text = tr("Inbox"); // Später zu "Eingang" übersetzt
// Problem: UI-Layouts nicht optimal für Deutsch
// Deutsche Wörter sind meist länger → Layout-Probleme
```
**Richtig: Deutsch im Code**
```cpp
// ✅ RICHTIG: Deutsch zuerst
const char *text = tr("Eingang"); // Master ist Deutsch
// Automatisch zu "Inbox" übersetzt für Englisch
// UI optimiert für längere deutsche Wörter von Anfang an
```
### 1.2 Vorteile
| Aspekt | Englisch-First | Deutsch-First |
|--------|---|---|
| **UI-Layout** | ❌ Zu kurz | ✅ Optimal |
| **Übersetzungsqualität** | ⚠️ KI macht Fehler | ✅ Deutsche Muttersprachler |
| **Kontext** | ❌ Verloren | ✅ Im Code klar |
| **Performance** | ❌ Übersetzungs-Overhead | ✅ Native Sprache |
| **Wartbarkeit** | ❌ Verwirrend | ✅ Klar |
| **Marktposition** | ❌ Generisch | ✅ "Für Deutsche" |
---
## 2. Code-Architektur: Deutsch-Only Source Code
### 2.1 Alle String-Konstanten in Deutsch
```cpp
// src/ui/MainWindow.h
class MainWindow : public QMainWindow {
private:
// ✅ Deutsch in Source Code
QString m_title = "Mail-Adler";
QString m_statusReady = "Bereit";
QString m_statusSyncing = "Synchronisiere...";
QString m_errorConnection = "Verbindungsfehler";
};
// src/models/MailFolder.h
enum StandardFolder {
FOLDER_INBOX = "Eingang", // Nicht "Inbox"
FOLDER_SENT = "Gesendet", // Nicht "Sent"
FOLDER_DRAFTS = "Entwürfe", // Nicht "Drafts"
FOLDER_TRASH = "Papierkorb", // Nicht "Trash"
FOLDER_SPAM = "Spam", // Nicht "Junk"
FOLDER_ARCHIVE = "Archiv" // Nicht "Archive"
};
// src/localization/Strings.h
namespace Strings {
constexpr auto MENU_FILE = "Datei";
constexpr auto MENU_EDIT = "Bearbeiten";
constexpr auto MENU_VIEW = "Ansicht";
constexpr auto MENU_TOOLS = "Werkzeuge";
constexpr auto MENU_HELP = "Hilfe";
constexpr auto ACTION_NEW = "Neu";
constexpr auto ACTION_OPEN = "Öffnen";
constexpr auto ACTION_SAVE = "Speichern";
constexpr auto ACTION_EXIT = "Beenden";
constexpr auto BUTTON_OK = "OK";
constexpr auto BUTTON_CANCEL = "Abbrechen";
constexpr auto BUTTON_APPLY = "Anwenden";
constexpr auto BUTTON_CLOSE = "Schließen";
};
```
### 2.2 UI-Dateien (Qt Designer) in Deutsch
```xml
<!-- forms/mainwindow.ui -->
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="windowTitle">
<string>Mail-Adler</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QMenuBar" name="menubar">
<widget class="QMenu" name="menuDatei">
<property name="title">
<string>Datei</string>
</property>
<addaction name="actionNeu"/>
<addaction name="actionÖffnen"/>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
<action name="actionNeu">
<property name="text">
<string>Neu</string>
</property>
<property name="shortcut">
<string>Ctrl+N</string>
</property>
</action>
</ui>
```
### 2.3 CMakeLists.txt - Deutsch als Standard-Sprache
```cmake
# CMakeLists.txt
# Qt Internationalization
set(CMAKE_AUTORCC ON)
# Standard-Sprache: Deutsch
set(QT_TRANSLATIONS_DEFAULT_LANGUAGE "de_DE")
# Alle .ts Dateien (Translation Source) basierend auf Deutsch
set(TS_FILES
translations/mail-adler_de.ts # Master (Deutsch)
translations/mail-adler_en.ts # English
translations/mail-adler_fr.ts # Français
translations/mail-adler_es.ts # Español
translations/mail-adler_it.ts # Italiano
)
# Nur eine master .ts datei (Deutsch)
qt_add_translations(mailadler_app
TS_FILES ${TS_FILES}
RESOURCE_PREFIX "/translations"
)
```
---
## 3. i18n System: Dynamische Übersetzungen
### 3.1 Ressourcen-basiertes System (nicht hardcoded)
```cpp
// src/localization/LocalizationManager.h
class LocalizationManager : public QObject {
Q_OBJECT
public:
static LocalizationManager& instance();
void setLanguage(const QString &langCode); // "de_DE", "en_US", "fr_FR"
QString tr(const QString &germanText); // Übersetze Deutsch → aktuelle Sprache
bool loadTranslations(const QString &langCode);
private:
QTranslator *m_translator = nullptr;
QString m_currentLanguage = "de_DE";
};
// Beispiel:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// Standard: Deutsch
LocalizationManager::instance().setLanguage("de_DE");
// Falls System-Sprache Englisch → English laden
QString systemLang = QLocale::system().language();
if (systemLang == "en") {
LocalizationManager::instance().setLanguage("en_US");
}
MainWindow window;
window.show();
return app.exec();
}
```
### 3.2 Verwendung im Code
```cpp
// src/ui/MainWindow.cpp
#include "localization/LocalizationManager.h"
MainWindow::MainWindow() {
auto &i18n = LocalizationManager::instance();
// ✅ Einfach - übersetzen wenn nötig
ui->menuDatei->setTitle(i18n.tr("Datei"));
ui->menuBearbeiten->setTitle(i18n.tr("Bearbeiten"));
ui->menuAnsicht->setTitle(i18n.tr("Ansicht"));
// Mit Pluralisierung
int messageCount = 5;
QString text = i18n.tr("%1 ungelesene Nachricht(en)").arg(messageCount);
// DE: "5 ungelesene Nachrichten"
// EN: "5 unread messages"
// FR: "5 messages non lus"
}
```
### 3.3 Translation Source File (mail-adler_de.ts)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>MainWindow</name>
<message>
<location filename="src/ui/mainwindow.cpp" line="123"/>
<source>Datei</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/ui/mainwindow.cpp" line="124"/>
<source>Bearbeiten</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>
```
---
## 4. Übersetzungs-Management mit KI
### 4.1 Automatische Übersetzung (mit GPT)
**Workflow:**
```bash
# 1. Deutsch Source Code → Extrahiere alle Strings
lupdate -no-obsolete src/ -ts translations/mail-adler_de.ts
# Erzeugt: translations/mail-adler_de.ts (Master)
# 2. Übersetze zu allen anderen Sprachen (mit KI)
./scripts/translate_with_ai.py \
--source translations/mail-adler_de.ts \
--target en_US,fr_FR,es_ES,it_IT \
--ai-engine gpt-4 \
--output translations/
# Erzeugt:
# translations/mail-adler_en.ts
# translations/mail-adler_fr.ts
# translations/mail-adler_es.ts
# translations/mail-adler_it.ts
# 3. Kompiliere Übersetzungen
lrelease translations/mail-adler_*.ts
# Erzeugt: translations/mail-adler_de.qm, mail-adler_en.qm, etc.
```
### 4.2 Python-Script für KI-Übersetzungen
```python
# scripts/translate_with_ai.py
#!/usr/bin/env python3
import openai
import xml.etree.ElementTree as ET
from pathlib import Path
class AITranslator:
def __init__(self, api_key):
openai.api_key = api_key
self.cache = {}
def translate(self, text: str, target_lang: str) -> str:
"""Übersetze Text von Deutsch zu Zielsprache mit GPT"""
cache_key = f"{text}::{target_lang}"
if cache_key in self.cache:
return self.cache[cache_key]
lang_names = {
'en_US': 'English',
'fr_FR': 'French',
'es_ES': 'Spanish',
'it_IT': 'Italian'
}
prompt = f"""
Übersetze folgendes Deutsch in {lang_names[target_lang]}.
Nur das Übersetzungs-Ergebnis ausgeben, keine Erklärung.
Behalte Formatierung und Sonderzeichen.
Deutsch: {text}
{lang_names[target_lang]}:
"""
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": prompt}],
temperature=0.3 # Niedrig für Konsistenz
)
translation = response['choices'][0]['message']['content'].strip()
self.cache[cache_key] = translation
return translation
def translate_ts_file(self, source_ts: str, target_lang: str) -> str:
"""Übersetze komplette .ts Datei"""
tree = ET.parse(source_ts)
root = tree.getroot()
for message in root.findall('.//message'):
source_elem = message.find('source')
translation_elem = message.find('translation')
if source_elem is not None and translation_elem is not None:
source_text = source_elem.text
translated = self.translate(source_text, target_lang)
translation_elem.text = translated
translation_elem.set('type', 'finished')
return ET.tostring(root, encoding='unicode')
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--source', required=True)
parser.add_argument('--target', required=True)
parser.add_argument('--output', required=True)
args = parser.parse_args()
translator = AITranslator(api_key='your-api-key')
for lang in args.target.split(','):
print(f"Übersetze zu {lang}...")
translated_xml = translator.translate_ts_file(args.source, lang.strip())
output_path = f"{args.output}/mail-adler_{lang.split('_')[0]}.ts"
Path(output_path).write_text(translated_xml)
print(f"Gespeichert: {output_path}")
```
### 4.3 Qualitätskontrolle vor Release
```bash
# 1. Übersetzte Strings prüfen
./scripts/validate_translations.py translations/*.ts
# 2. Context-Mismatch prüfen
./scripts/check_context_consistency.py translations/mail-adler_*.ts
# 3. Längste Strings pro Sprache prüfen (UI-Layout)
./scripts/check_string_lengths.py translations/mail-adler_*.ts
```
---
## 5. Sprachen-Fallback & Lokalisierung
### 5.1 Fallback-Kette
```cpp
// src/localization/LocalizationManager.cpp
void LocalizationManager::setLanguage(const QString &langCode) {
QLocale locale(langCode);
// Fallback-Kette:
// 1. Gewünschte Sprache (z.B. de_AT → de)
// 2. Basis-Sprache (z.B. de_AT → de_DE)
// 3. Englisch (fallback)
// 4. Deutsch (Master)
QStringList fallbackList;
fallbackList << langCode; // de_AT
fallbackList << langCode.split("_").first(); // de
fallbackList << "en_US"; // English
fallbackList << "de_DE"; // Deutsch (Master)
for (const QString &lang : fallbackList) {
if (m_translator->load(lang, ":/translations")) {
QCoreApplication::installTranslator(m_translator);
m_currentLanguage = lang;
emit languageChanged(lang);
return;
}
}
}
```
### 5.2 Lokale Format-Strings
```cpp
// src/localization/LocaleFormatting.h
class LocaleFormatting {
public:
// Deutsche Datumsformate
static QString formatDate_de(const QDateTime &dt) {
return dt.toString("d. MMMM yyyy"); // "3. Februar 2025"
}
static QString formatTime_de(const QDateTime &dt) {
return dt.toString("HH:mm Uhr"); // "14:30 Uhr"
}
static QString formatDateTime_de(const QDateTime &dt) {
return formatDate_de(dt) + ", " + formatTime_de(dt);
}
// Englische Formate
static QString formatDate_en(const QDateTime &dt) {
return dt.toString("MMMM d, yyyy"); // "February 3, 2025"
}
// Französische Formate
static QString formatDate_fr(const QDateTime &dt) {
return dt.toString("d MMMM yyyy"); // "3 février 2025"
}
};
// Verwendung:
QString formatted = LocaleFormatting::formatDate_de(QDateTime::currentDateTime());
```
### 5.3 Pluralisierung
```cpp
// src/localization/Pluralization.h
class Pluralization {
public:
static QString unreadMessages(int count) {
auto &i18n = LocalizationManager::instance();
if (count == 0) {
return i18n.tr("Keine ungelesenen Nachrichten");
} else if (count == 1) {
return i18n.tr("1 ungelesene Nachricht");
} else {
return i18n.tr("%1 ungelesene Nachrichten").arg(count);
}
}
};
// Automatische Pluralisierung mit Qt:
QString text = tr("nplurals=2; plural=(n != 1);") // German rule
+ i18n.tr("%n ungelesene Nachricht(en)", "", count);
// DE: "5 ungelesene Nachrichten"
// EN: "5 unread messages"
```
---
## 6. Sprachen-Support nach Priorität
### Phase B (Aktuell)
-**Deutsch** (Master Language)
- 100% von Anfang an
- Native Muttersprachler
- Vollständig getestet
### Phase C (April 2025)
-**Englisch** (English)
- KI-übersetzen (GPT-4)
- Review vor Release
- ~200 Strings
### Phase D (Mai 2025)
-**Französisch** (Français)
-**Italienisch** (Italiano)
-**Spanisch** (Español)
### Phase E (Juni 2025)
-**Niederländisch** (Nederlands)
-**Polnisch** (Polski)
-**Schwedisch** (Svenska)
### Nicht geplant
- ❌ Chinesisch, Japanisch, Arabisch (Zu komplex, andere Zeichensätze)
- ❌ Russisch (Politische Gründe für deutsches Projekt)
---
## 7. Workflow für Neue Strings
### 7.1 Entwickler hinzufügt neuen String
```cpp
// src/ui/AccountSetupDialog.cpp
void AccountSetupDialog::setupUI() {
auto label = new QLabel(tr("E-Mail Adresse:")); // ← Deutsch!
// Nicht: tr("Email Address:")
}
```
### 7.2 Automatische Extraktion
```bash
# Täglich (via Git Hook):
lupdate src/ forms/ -ts translations/mail-adler_de.ts
# .git/hooks/pre-commit
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
lupdate src/ forms/ -ts translations/mail-adler_de.ts
git add translations/mail-adler_de.ts
```
### 7.3 Neue Strings markieren
In `mail-adler_de.ts`:
```xml
<message>
<location filename="src/ui/accountsetupdialog.cpp" line="42"/>
<source>E-Mail Adresse:</source>
<translation type="unfinished"></translation> <!-- NEUER STRING -->
</message>
```
### 7.4 Vor Release: Review & Übersetzen
```bash
# Git-Hook vor Release:
./scripts/review_untranslated.py translations/mail-adler_de.ts
# → Zeigt: 3 übersetzte, 0 unübersetzt
# Falls unübersetzt: Release blockiert!
# Dann KI-Übersetzung:
./scripts/translate_with_ai.py \
--source translations/mail-adler_de.ts \
--target en_US,fr_FR \
--output translations/
```
---
## 8. Vorteile dieses Ansatzes
| Vorteil | Erklärung |
|---------|-----------|
| **Natürliche UI** | Deutsche Wörter → längere Strings → Layout optimiert |
| **Bessere Übersetzung** | KI arbeitet von Deutsch → andere Sprachen (natives Deutsch als Kontext) |
| **Einfache Maintenance** | Ein Source-of-Truth (Deutsch), keine verwirrenden Englisch-Kommentare |
| **KI-Freundlich** | GPT übersetzt besser von Deutsch als von technischem Englisch |
| **Markt-Vorteil** | "Für Deutsche gemacht" ist erkennbar und authentisch |
| **Performance** | Master-Language = Runtime-Language (kein Übersetzungs-Overhead) |
| **Branding** | Mail-Adler ist "Deutsch-zentriert", nicht "Globales Englisch-Projekt" |
---
## 9. Ressourcen-Dateien Structure
```
translations/
├─ mail-adler_de.ts (Master - von Entwickler gepflegt)
├─ mail-adler_de.qm (Compiled - verwendet zur Laufzeit)
├─ mail-adler_en.ts (English - von KI generiert)
├─ mail-adler_en.qm (Compiled)
├─ mail-adler_fr.ts (Français - von KI generiert)
├─ mail-adler_fr.qm (Compiled)
└─ translations.qrc (Qt Resource File)
translations.qrc:
<?xml version="1.0" encoding="UTF-8"?>
<RCC>
<qresource prefix="/translations">
<file>mail-adler_de.qm</file>
<file>mail-adler_en.qm</file>
<file>mail-adler_fr.qm</file>
</qresource>
</RCC>
```
---
## 10. GitHub Workflow für Übersetzungen
```yaml
# .github/workflows/translations.yml
name: Translations
on:
push:
paths:
- 'src/**'
- 'forms/**'
jobs:
update-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Update master (German) strings
run: |
lupdate src/ forms/ -ts translations/mail-adler_de.ts
- name: Auto-translate to other languages (GPT-4)
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
./scripts/translate_with_ai.py \
--source translations/mail-adler_de.ts \
--target en_US,fr_FR,es_ES,it_IT \
--output translations/
- name: Compile translations
run: |
lrelease translations/mail-adler_*.ts
- name: Commit and push
run: |
git config --local user.email "action@github.com"
git config --local user.name "Translation Bot"
git add translations/
git commit -m "Auto-update translations from master (German)"
git push
```
---
## 11. Fazit: "Deutsch-First" ist die Zukunft
**Klassisches Englisch-First Projekt:**
```
Englisch Code → Deutsche Übersetzung → UI passt nicht → Fixxen
```
**Mail-Adler Deutsch-First:**
```
Deutsch Code → UI perfekt → KI übersetzt → Fertig
```
**Mail-Adler wird sich als "deutsches Projekt" schneller durchsetzen** weil:
1. ✅ Native Qualität von Anfang an
2. ✅ Deutsche Nutzer fühlen sich verstanden
3. ✅ Keine verloren gehen Übersetzungs-Kontext
4. ✅ KI produziert bessere Qualität mit natürlichem Deutsch als Input
5. ✅ Markenpositionierung klar: "Open Source für Deutsche"