summaryrefslogtreecommitdiff
path: root/locales/README-locales.md
blob: c6a51936d69f3ccbdd3c0ac522a3d03423b0b512 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
# YaCy-Lokalisierung: Systematik & Syntax der `.lng`-Dateien

Dieses Verzeichnis enthält die Übersetzungsdateien für die YaCy-Weboberfläche.
Dieses Dokument beschreibt, wie das Übersetzungssystem funktioniert und wie
`.lng`-Dateien aufgebaut sein müssen, damit Übersetzungen zur Laufzeit greifen.

---

## 1. Überblick

- Die Oberfläche (die Dateien unter `htroot/`) ist **auf Englisch** geschrieben.
  Das Englische ist die Referenz/Quelle.
- Pro Sprache gibt es eine Datei `locales/<code>.lng` (z. B. `de.lng`), die
  englische Textstellen auf die Zielsprache abbildet.
- YaCy übersetzt **nicht** live beim Ausliefern jeder Anfrage, sondern erzeugt
  beim Aktivieren einer Sprache **übersetzte Kopien** der `htroot`-Dateien nach
  `DATA/LOCALE/htroot/<code>/` und liefert diese aus.
- Die Übersetzung selbst ist **reine Textersetzung** (Substring-Replace),
  **kein** Template-System. Das hat wichtige Konsequenzen für die Syntax der
  Schlüssel (siehe Abschnitt 6).

Vorhandene Sprachdateien:

```
de.lng el.lng es.lng fr.lng hi.lng it.lng ja.lng ru.lng sk.lng tr.lng uk.lng zh.lng
```

`de.lng` ist üblicherweise die vollständigste Übersetzung und dient als
Referenz. Zusätzlich existiert `master.lng.xlf` (siehe Abschnitt 8).

---

## 2. Grundaufbau einer `.lng`-Datei

Eine `.lng`-Datei besteht aus einem Kopf-Kommentar, gefolgt von **Abschnitten
pro Quelldatei**:

```
#File: ConfigBasic.html
#---------------------------
Access Configuration==Zugangseinstellungen
Basic Configuration==Grundkonfiguration
Set Configuration==Konfiguration speichern
#-----------------------------

#File: env/templates/submenuMaintenance.template
#---------------------------
Performance==Performance
Web Cache==Web-Cache
#-----------------------------
```

Bestandteile:

| Element | Bedeutung |
|---|---|
| `#File: <pfad>` | Beginn eines Abschnitts. `<pfad>` ist der **htroot-relative** Pfad der Quelldatei (z. B. `ConfigBasic.html`, `env/templates/header.template`, `Settings_Proxy.inc`). |
| `#---------------------------` | Trenner nach der Kopfzeile (dekorativ, üblich aber nicht zwingend geparst). |
| `original==übersetzung` | Ein Übersetzungseintrag (siehe Abschnitt 3). |
| `#-----------------------------` | Abschluss des Abschnitts (dekorativ). |
| `# ...` | Kommentarzeile (Zeilen, die mit `#` beginnen, sind keine Einträge). |
| Leerzeile | Trennt Abschnitte optisch. |

Wichtig:
- **Kodierung: UTF-8.**
- **Ein Abschnitt = eine Quelldatei.** Der `#File:`-Pfad muss exakt einer real
  existierenden Datei unter `htroot/` entsprechen. Abschnitte für gelöschte
  Dateien sind tote Einträge und sollten entfernt werden.
- Die Übersetzung gilt **nur** für die im `#File:` genannte Datei. Wenn derselbe
  englische Text auf mehreren Seiten vorkommt, braucht **jede** Seite ihren
  eigenen Abschnitt mit diesem Eintrag (Übersetzung ist pro Datei-Abschnitt).

### Abschnitts-Header: nur `#File:`
Der Runtime-Loader (`Translator.loadTranslationsLists`) erkennt derzeit **nur**
`#File:` als Abschnitts-Header. Zeilen mit anderen Präfixen, z. B. `#Dosya:`,
werden wie normale Kommentarzeilen behandelt; die folgenden Einträge landen dann
nicht im beabsichtigten Dateiabschnitt und greifen zur Laufzeit nicht korrekt.

Hinweis: Ältere oder importierte Dateien können lokalisierte Header wie
`#Dosya:` enthalten. Solche Header müssen vor einem Runtime-Test nach `#File:`
normalisiert werden (oder der Java-Loader muss explizit erweitert werden).
Andere `#Xxx:`-Präfixe (`#YaCy:`, `#Subject:`, `#URL:` …) sind ebenfalls keine
Header. Da alle Zeilen mit `#` ignoriert werden, sind auch `#key==wert`-Zeilen
auskommentierte Einträge und keine aktiven Übersetzungen.

---

## 3. Eintrags-Syntax: `original==übersetzung`

```
Basic Configuration==Grundkonfiguration
```

- Trennzeichen ist **`==`** (doppeltes Gleichheitszeichen). Alles **links** vom
  ersten `==` ist der **Schlüssel** (der zu suchende englische Text), alles
  **rechts** die Übersetzung.
- Der **Schlüssel darf kein `==` enthalten** (der Split erfolgt am ersten `==`).
- **Genau eine Zeile pro Eintrag.** Schlüssel und Übersetzung dürfen **keine
  Zeilenumbrüche** enthalten (das Format ist zeilenbasiert).
- HTML-Entities werden **wörtlich** übernommen (z. B. `Fran&ccedil;ais`,
  `&amp;`, `&nbsp;`), da sie auch so in der Quelle stehen.
- Eine leere Übersetzung (`key==`) bzw. eine identische (`Chat==Chat`) ist
  technisch erlaubt, aber vermeide **überflüssige** Einträge – lege keine
  Abschnitte oder Einträge an, die nichts übersetzen.

### Sonder-Einträge im Abschnitt `ConfigLanguage_p.html`
Diese steuern die Anzeige der Sprache in der Sprachauswahl:

```
<!-- lang -->default(english)==Deutsch
<!-- author -->==Roland Ramthun, Oliver Wunder, ...
<!-- maintainer -->==&lt;webmaster@daburna.de&gt;
```

- `<!-- lang -->…` — der **Anzeigename** der Sprache.
- `<!-- author -->…` — Beitragende.
- `<!-- maintainer -->…` — Pflege-Kontakt.

---

## 4. Wie die Übersetzung technisch funktioniert

Relevante Klassen:
`net.yacy.data.Translator`,
`net.yacy.utils.translation.TranslationManager` / `TranslatorXliff` / `TranslatorUtil`.

Ablauf (`Translator.translate` / `translateFilesRecursive`):

1. Beim Aktivieren einer Sprache werden alle Quelldateien mit den Endungen
   **`html`, `template`, `inc`** rekursiv durch `htroot/` verarbeitet und als
   übersetzte Kopien nach `DATA/LOCALE/htroot/<code>/` geschrieben.
2. Für jede Datei wird der zugehörige `#File:`-Abschnitt geladen. Für **jeden**
   Eintrag `source==target` wird im Dateiinhalt **jedes Vorkommen** von `source`
   gesucht (`indexOf`) und durch `target` ersetzt (`replace`).
3. Vor jeder Ersetzung greift eine **Wortgrenzen-Prüfung**: das Zeichen direkt
   vor und nach dem Treffer muss eine „Grenze“ sein (Satzzeichen oder
   unsichtbares Zeichen — dazu zählen u. a. Leerzeichen sowie `<` und `>`).
   Dadurch wird verhindert, dass `bug` in `mybugfix` ersetzt wird, während
   `>English<` (umschlossen von `>`/`<`) korrekt getroffen wird.

**Kernaussage:** Ein Schlüssel wird genau dann übersetzt, wenn er als
**exakter Teilstring** im Dateiinhalt vorkommt und an Wortgrenzen liegt.
Es gibt **keinen** automatischen Extraktor, der „übersetzbare Strings“
erkennt — die Schlüssel werden von Hand gepflegt.

Wichtig: Beim Erzeugen der lokalisierten Dateien werden nur Quelldateien
geschrieben, für die in der Sprachdatei ein passender `#File:`-Abschnitt
existiert. Fehlt der Abschnitt, wird diese Datei nicht als lokalisierte Kopie
erzeugt.

Die erzeugten Seiten liegen zur Laufzeit unter `DATA/LOCALE/htroot/<sprache>`.
Beim Umschalten oder automatischen Refresh einer Sprache muss dieser Ordner
vorher gelöscht werden; sonst können nicht mehr erzeugte Altdateien weiterhin
ausgeliefert werden. Aktuelle YaCy-Versionen erledigen das beim Sprachwechsel
und beim versionsbedingten Startup-Refresh automatisch.

---

## 5. Template-Markup in den Quelldateien

Die `htroot`-Dateien enthalten Server-Template-Markup, das **vor** oder
**unabhängig von** der Übersetzung durch die Servlet-Engine ersetzt wird.
Ein Übersetzungsschlüssel darf dieses Markup **nicht überspannen**:

| Form | Bedeutung |
|---|---|
| `#[name]#` | Einzelwert (Platzhalter), wird durch einen Laufzeitwert ersetzt. |
| `#(name)#A::B::…#(/name)#` | Fallunterscheidung/Alternativen (A für Fall 0, B für Fall 1 …). |
| `#{name}#…#{/name}#` | Wiederholung/Aufzählung (Schleife). |
| `#%pfad%#` | Einbindung eines anderen Templates (z. B. `#%env/templates/header.template%#`). |

Konsequenz für Schlüssel: Übersetzbarer Text endet **an** solchen Markup-Grenzen.
Beispiel — die Quelle enthält:

```html
This path can be accessed at #[path]#
```

Der brauchbare Schlüssel ist daher `This path can be accessed at ` (mit dem
Leerzeichen, bis zum `#[path]#`), **nicht** die ganze Zeile inkl. `#[path]#`.

---

## 6. Regeln für gute Schlüssel (Authoring)

1. **Exakter Teilstring.** Der Schlüssel muss **zeichengenau** im Roh-Quelltext
   der Datei vorkommen (inkl. HTML-Entities, Groß-/Kleinschreibung,
   Interpunktion). Am einfachsten prüfbar mit `content.indexOf(key) >= 0`.
2. **Einzeilig.** Keine Zeilenumbrüche im Schlüssel.
3. **Inline-Tags bleiben im Schlüssel.** Für zusammenhängende Sätze mit
   Inline-Auszeichnung wird der ganze Satz **inklusive** der Inline-Tags zu
   einem Schlüssel, damit die deutsche Wortstellung passt:
   ```
   ... edited in the <a href="IndexSchema_p.html">Schema Editor</a>.==... im <a href="IndexSchema_p.html">Schema-Editor</a> bearbeitet werden.
   ```
   Als Inline gelten u. a. `a, em, strong, b, i, code, kbd, abbr, span, sup,
   sub, small, var, samp, br`. An **Block-Tags** (`p, div, li, td, h1..h6,
   option, label, fieldset, …`) und an Template-Markup wird getrennt.
4. **Menü-Einträge als Klartext.** Menü-Links wie
   `<a href="X.html" ...>LLM Selection</a>` werden als reiner Text
   `LLM Selection==LLM-Auswahl` gepflegt (der `<a>`-Wrapper enthält oft
   Template-Markup und gehört nicht in den Schlüssel).
5. **Reihenfolge: länger/spezifischer zuerst.** Die Einträge werden in
   Datei-Reihenfolge angewandt. Ist ein kurzer Schlüssel Teilstring eines
   längeren desselben Abschnitts, muss der **längere zuerst** stehen — sonst
   „zerschießt“ die kurze Ersetzung den längeren Treffer.
   Beispiel: `Index Export` **vor** `Export` einordnen.
6. **Keine Zerlegung über Markup hinweg** (siehe Abschnitt 5).

---

## 7. Was übersetzt wird — und was nicht

**Übersetzen:** Seiten mit sichtbarem Oberflächentext (`*_p.html`, Konfig-Seiten,
`*.inc`-Includes, `env/templates/submenu*.template` und andere UI-Templates).

**Nicht übersetzen** (keine leeren Abschnitte anlegen):
- **Daten-/Protokoll-Endpunkte:** `yacy/*.html`, `api/push_p.html`,
  `api/share.html` u. ä. (liefern XML/JSON, keine UI).
- **Inhaltsleere Templates:** `env/templates/footer.template`,
  `…/simplefooter.template`, `…/embedded*.template` usw.
- **Reine Code-/Beispielblöcke** innerhalb einer Seite (z. B. `curl`-Befehle,
  JSON-Snippets) — nur die umgebende Prosa übersetzen.
- **Test-/Demo-Dateien** und rein technische Bezeichner (Feldnamen wie
  `num_ctx`, `max_tokens`, Rollennamen wie `search-query`).
- **Technische Link-Ziele, Pfade, Servlets und URLs** bleiben literal. Nicht
  übersetzen oder durch Leerzeichen beschädigen: `Network.html` bleibt
  `Network.html`, `sharedBlacklist.html` bleibt `sharedBlacklist.html`,
  `share.json` bleibt `share.json`, `styles/prosilver/template/overall_header.html`
  bleibt unverändert und URLs wie `http://localhost:8090/proxy.html?...`
  dürfen nicht lokalisiert werden.

Prüfung aus dem Repository-Root:

```bash
python3 locales/validate-locale-links.py --exclude pl.lng
```

`--exclude` ist nützlich, wenn eine Sprache parallel in einem anderen Arbeitszweig
bearbeitet wird. Für einzelne Sprachen kann `--include de.lng --include fr.lng`
verwendet werden. Ein sauberer Lauf endet mit `OK: ... no link target issues found.`

---

## 8. `master.lng.xlf`

`master.lng.xlf` ist die source-basierte XLIFF-Referenz der übersetzbaren
Strings pro Datei. Die Wahrheit für diesen Master liegt in den Quellen unter
`htroot`, nicht in bereits vorhandenen `.lng`-Dateien.

- Sie wird mit `GenerateSourceMasterXliff` aus sichtbaren Textknoten und
  ausgewählten UI-Attributen (`alt`, `title`, `placeholder`, `aria-label`,
  Button-`value`) erzeugt.
- Jeder Kandidat wird gegen den Roh-Quelltext und die Runtime-Wortgrenzen der
  Übersetzung geprüft. Nicht darstellbare `.lng`-Keys, z. B. Keys mit `==` oder
  einem abschließenden `=`, werden verworfen.
- **Nicht** von Hand mit Hash-/Zeilen-IDs pflegen — nach Änderungen an Quellen
  über das YaCy-Tooling neu erzeugen und das Delta prüfen.
- Beim Refresh wird die Zieldatei ersetzt. Stale Master-Einträge fallen dadurch
  weg, auch wenn sie noch in alten `.lng`-Dateien stehen.

Refresh aus dem Repository-Root:

```bash
java -cp 'build/classes/java/main:lib/*' \
  net.yacy.utils.translation.GenerateSourceMasterXliff \
  htroot locales/master.lng.xlf
```

Falls die Klassen noch nicht kompiliert sind, vorher `ant compile` ausführen.
Das zweite Argument ist wichtig: ohne `locales/master.lng.xlf` schreibt das Tool
standardmäßig nach `./source-master.lng.xlf` im Repository-Root. Existiert die
Zieldatei bereits, wird sie ersetzt.

### Legacy: bestandbasierter Master

`GenerateMasterXliff` erzeugt nur einen bestandbasierten Master aus vorhandenen
`.lng`-Schlüsseln, gefiltert danach, ob sie noch als Teilstring in der
jeweiligen Quelldatei vorkommen (`content.indexOf >= 0`):

```bash
java -cp 'build/classes/java/main:lib/*' \
  net.yacy.utils.translation.GenerateMasterXliff \
  locales /tmp/master-from-lng.lng.xlf
```

Dieses Tool ist nützlich zur Diagnose von Altbestand, aber nicht als
Vollständigkeitsreferenz: englische UI-Texte, die noch in keiner `.lng`-Datei als
Schlüssel vorkommen, erscheinen dort nicht.

---

## 9. Arbeitsablauf: eine Sprache vervollständigen

1. **Fehlende Seiten ermitteln:** alle UI-Dateien unter `htroot/`
   (`*.html`, `*.inc`, `*.template`) mit den `#File:`-Abschnitten der `.lng`
   abgleichen; Differenz bilden. Daten-Endpunkte/leere Templates (Abschnitt 7)
   herausfiltern.
2. **Schlüssel extrahieren:** pro Datei die sichtbaren, einzeiligen Textstellen
   gemäß den Regeln in Abschnitt 6 gewinnen (Inline-Tags behalten, an Block-Tags
   und Template-Markup trennen, Rand-Tags entfernen).
3. **Übersetzen** und Einträge `key==übersetzung` bilden.
4. **Verifizieren (Pflicht):** für **jeden** Schlüssel prüfen, dass
   `key in <roher Dateiinhalt>` gilt. Schlägt das fehl, greift die Übersetzung
   zur Laufzeit **nicht**.
5. **Einordnen:** neuen `#File:`-Abschnitt anlegen; Einträge längster-zuerst
   sortieren (Abschnitt 6, Regel 5). Neue Abschnitte können am Dateiende
   angehängt werden (die Datei ist nicht streng sortiert).
6. **Vollständigkeit beidseitig prüfen:**
   - `master.lng.xlf -> <sprache>.lng`: fehlende Source-Schlüssel ergänzen.
   - `<sprache>.lng -> master.lng.xlf`: Extras prüfen und in der Regel entfernen;
     sie sind stale oder stammen aus einem nicht frisch generierten Master.
   - Für jeden aktiven Sprach-Key prüfen: `key in htroot/<#File>`.
   - Doppelte Schlüssel und auskommentierte `#...==...`-Einträge entfernen oder
     bewusst reaktivieren.
7. **Zeilenenden beachten** (Abschnitt 10).

---

## 10. Fallstricke

- **Zeilenenden (CRLF):** Einige Dateien verwenden CRLF (`\r\n`), u. a.
  `it.lng`, `sk.lng` sowie einige `htroot`-Templates. Werkzeuge, die im
  Textmodus lesen und neu schreiben, normalisieren CRLF→LF und erzeugen einen
  Diff über die **ganze** Datei. Verwende `perl -i -pe` o. ä. bzw. arbeite
  byte-erhaltend; kontrolliere mit `git diff --numstat` (ein `+N -N` in Höhe der
  Zeilenzahl deutet auf ungewollte Newline-Normalisierung hin).
- **Synchronität über alle Sprachen:** Wird ein englischer Text in der Quelle
  korrigiert, muss der **Schlüssel** in **allen** `.lng`-Dateien analog
  angepasst werden (linke Seite von `==`), sonst passt er nicht mehr und die
  Übersetzung greift nicht.
- **Stale Keys:** Über die Zeit driften Schlüssel von der Quelle ab (Text in der
  Quelle geändert, `.lng` nicht) → der Eintrag greift nie mehr. Solche Einträge
  sollten aktualisiert oder entfernt werden.
- **Duplikate:** Doppelte `#File:`-Abschnitte oder doppelte Schlüssel innerhalb
  eines Abschnitts vermeiden.
- **`==` im Text:** Ein englischer Text mit `==` lässt sich nicht als Schlüssel
  abbilden (der Split bricht am ersten `==`).

---

## 11. Kurz-Checkliste für einen neuen Eintrag

- [ ] Schlüssel ist **exakter, einzeiliger Teilstring** der Quelldatei.
- [ ] Markup-Grenzen (`#[..]#`, `#(..)#`, `#{..}#`, `#%..%#`) nicht überspannt.
- [ ] Inline-Tags im Schlüssel belassen, an Block-Tags getrennt.
- [ ] Eintrag steht im **richtigen** `#File:`-Abschnitt.
- [ ] Längere Schlüssel stehen vor ihren kürzeren Teilstrings.
- [ ] UTF-8, korrektes Zeilenende, kein `==` im Schlüssel.
- [ ] Kein überflüssiger/leerer Eintrag.