From a2823d44ca1a06cb7762c4f7619c0e31d642658b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:04 -0600 Subject: [PATCH 001/317] New translations csharp-differences.md (French) [ci skip] --- docs/fr/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/fr/csharp-differences.md diff --git a/docs/fr/csharp-differences.md b/docs/fr/csharp-differences.md new file mode 100644 index 0000000..39dd18a --- /dev/null +++ b/docs/fr/csharp-differences.md @@ -0,0 +1,52 @@ +# Différences par rapport aux bibliothèques C\# + +sil-lift s'apparente vaguement aux outils LIFT de SIL en C# — principalement `SIL.Lift` dans [libpalaso](https://github.com/sillsdev/libpalaso) (analyseur syntaxique, validateur, migrateur, `LiftSorter`), `SIL.DictionaryServices` dans le même dépôt (le modèle `LexEntry`/`LexSense`, doté de son propre lecteur/enregistreur LIFT, utilisé par The Combine et WeSay), ainsi que les gestionnaires LIFT de [Chorus](https://github.com/sillsdev/chorus). Il s'agit d'une nouvelle implémentation, et non d'un portage. Cette page résume les points sur lesquels le comportement diffère délibérément. + +## Champ d'application + +| Capacité | Bibliothèques C# | sil-lift | +| -------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| Versions de LIFT | 0,10–0,13 (migration intégrée) | **0.13 uniquement** ; les versions antérieures sont rejetées et génèrent une erreur claire | +| Migration de version | `Migrator` (chaîne XSLT) | aucun — utiliser les fichiers XSLT du répertoire « lift-standard » pour les mises à jour ponctuelles | +| Fusion / synchronisation à trois voies | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From dbad3246caae50c5d778023667a4450f69b79f69 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:05 -0600 Subject: [PATCH 002/317] New translations csharp-differences.md (Spanish) [ci skip] --- docs/es/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/es/csharp-differences.md diff --git a/docs/es/csharp-differences.md b/docs/es/csharp-differences.md new file mode 100644 index 0000000..506f1d2 --- /dev/null +++ b/docs/es/csharp-differences.md @@ -0,0 +1,52 @@ +# Diferencias con respecto a las bibliotecas de C\# + +sil-lift es, a grandes rasgos, análogo a las herramientas LIFT de SIL para C# —principalmente `SIL.Lift` en [libpalaso](https://github.com/sillsdev/libpalaso) (analizador sintáctico, validador, migrador, `LiftSorter`), `SIL.DictionaryServices` del mismo repositorio (el modelo `LexEntry`/`LexSense`, con su propio lector/escritor LIFT, que utilizan The Combine y WeSay), y los controladores LIFT de [Chorus](https://github.com/sillsdev/chorus). Se trata de una implementación nueva, no de una adaptación. En esta página se resumen los aspectos en los que el comportamiento difiere deliberadamente. + +## Ámbito de aplicación + +| Capacidad | Bibliotecas de C# | sil-lift | +| ----------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------- | +| Versiones de LIFT | 0,10–0,13 (migración incluida) | **Solo 0,13**; las versiones anteriores se rechazan con un error claro | +| Migración de versiones | `Migrator` (cadena XSLT) | ninguna — utiliza los XSLT de «lift-standard» para actualizaciones puntuales | +| Fusión/sincronización a tres bandas | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 184d6f9df7a9c01488424ad402bc4315a5488eff Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:07 -0600 Subject: [PATCH 003/317] New translations csharp-differences.md (Arabic) [ci skip] --- docs/ar/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/ar/csharp-differences.md diff --git a/docs/ar/csharp-differences.md b/docs/ar/csharp-differences.md new file mode 100644 index 0000000..567c2bb --- /dev/null +++ b/docs/ar/csharp-differences.md @@ -0,0 +1,52 @@ +# الاختلافات عن مكتبات C\# + +تُعتبر «sil-lift» مشابهة بشكل عام لأدوات LIFT الخاصة بـ SIL المكتوبة بلغة C# — وبشكل أساسي `SIL.Lift` الموجودة في [libpalaso](https://github.com/sillsdev/libpalaso) (المحلل النحوي، أداة التحقق من الصحة، أداة الترحيل، `LiftSorter`)، و`SIL.DictionaryServices` في نفس المستودع (نموذج `LexEntry`/`LexSense`، مع قارئ/كاتب LIFT خاص به، والذي يستخدمه كل من The Combine و WeSay)، ومعالجات LIFT في [Chorus](https://github.com/sillsdev/chorus). إنه تطبيق جديد، وليس نسخة معدلة. تلخص هذه الصفحة النقاط التي يختلف فيها السلوك بشكل متعمد. + +## النطاق + +| القدرة | مكتبات C# | سيل-ليفت | +| ----------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| إصدارات LIFT | 0.10–0.13 (مع ميزة الترحيل المدمجة) | **0.13 فقط**؛ يتم رفض الإصدارات الأقدم مع ظهور خطأ واضح | +| ترحيل الإصدار | `Migrator` (سلسلة XSLT) | لا شيء — استخدم ملفات XSLT الموجودة في «lift-standard» لإجراء عمليات الترقية لمرة واحدة | +| دمج/مزامنة ثلاثية | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From b2d0910b54e45d78ca52811c3c395529bcabe9ec Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:08 -0600 Subject: [PATCH 004/317] New translations csharp-differences.md (German) [ci skip] --- docs/de/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/de/csharp-differences.md diff --git a/docs/de/csharp-differences.md b/docs/de/csharp-differences.md new file mode 100644 index 0000000..6e84fac --- /dev/null +++ b/docs/de/csharp-differences.md @@ -0,0 +1,52 @@ +# Unterschiede zu den C#-Bibliotheken + +sil-lift ist in etwa vergleichbar mit den C#-LIFT-Tools von SIL – vor allem mit `SIL.Lift` in [libpalaso](https://github.com/sillsdev/libpalaso) (Parser, Validator, Migrator, `LiftSorter`), `SIL.DictionaryServices` im selben Repository (das `LexEntry`/`LexSense`-Modell mit eigenem LIFT-Reader/Writer, das von The Combine und WeSay verwendet wird) sowie die LIFT-Handler in [Chorus](https://github.com/sillsdev/chorus). Es handelt sich um eine neue Implementierung, nicht um eine Portierung. Auf dieser Seite wird zusammengefasst, in welchen Punkten sich das Verhalten bewusst unterscheidet. + +## Geltungsbereich + +| Fähigkeit | C#-Bibliotheken | sil-lift | +| ----------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------- | +| LIFT-Versionen | 0,10–0,13 (Migration integriert) | **nur 0.13**; ältere Versionen werden mit einer eindeutigen Fehlermeldung abgelehnt | +| Versionsmigration | `Migrator` (XSLT-Kette) | keine — Verwenden Sie die XSLT-Dateien aus „lift-standard“ für einmalige Upgrades | +| 3-Wege-Zusammenführung / Synchronisierung | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 02ffaf56973bbbcbc26b7cac0d482e497ad265ce Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:10 -0600 Subject: [PATCH 005/317] New translations csharp-differences.md (Japanese) [ci skip] --- docs/ja/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/ja/csharp-differences.md diff --git a/docs/ja/csharp-differences.md b/docs/ja/csharp-differences.md new file mode 100644 index 0000000..840d476 --- /dev/null +++ b/docs/ja/csharp-differences.md @@ -0,0 +1,52 @@ +# C# ライブラリとの違い + +sil-lift は、SIL の C# LIFT ツール群――主に [libpalaso](https://github.com/sillsdev/libpalaso) 内の `SIL.Lift`(パーサー、バリデータ、マイグレーター、`LiftSorter`)、同じリポジトリ内の `SIL.DictionaryServices`(The Combine や WeSay で使用されている、独自の LIFT リーダー/ライターを備えた `LexEntry`/`LexSense` モデル)、および [Chorus](https://github.com/sillsdev/chorus) 内の LIFT ハンドラーなどです。 これは移植版ではなく、新規に実装されたものです。 このページでは、意図的に異なる仕様となっている点をまとめています。 + +## 適用範囲 + +| 機能 | C# ライブラリ | シルリフト | +| ---------- | -------------------------------------------------------- | ---------------------------------------------------- | +| LIFTのバージョン | 0.10–0.13(移行機能が組み込まれている) | **0.13のみ**;それより古いバージョンは明確なエラーで拒否されます | +| バージョンの移行 | `Migrator`(XSLTチェーン) | なし — 単発のアップグレードには、lift-standardに含まれるXSLTを使用してください | +| 3ウェイマージ/同期 | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 29c67189d810cbd005caec9108c16b8c9c469ba9 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:11 -0600 Subject: [PATCH 006/317] New translations csharp-differences.md (Portuguese) [ci skip] --- docs/pt/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/pt/csharp-differences.md diff --git a/docs/pt/csharp-differences.md b/docs/pt/csharp-differences.md new file mode 100644 index 0000000..7c87b09 --- /dev/null +++ b/docs/pt/csharp-differences.md @@ -0,0 +1,52 @@ +# Diferenças em relação às bibliotecas do C\# + +O sil-lift é, de certa forma, análogo às ferramentas LIFT da SIL para C# — principalmente o `SIL.Lift` em [libpalaso](https://github.com/sillsdev/libpalaso) (analisador sintático, validador, migrador, `LiftSorter`), o `SIL.DictionaryServices` no mesmo repositório (o modelo `LexEntry`/`LexSense`, com o seu próprio leitor/gravador LIFT, utilizado pelo The Combine e pelo WeSay), e os manipuladores LIFT no [Chorus](https://github.com/sillsdev/chorus). Trata-se de uma nova implementação, não de uma adaptação. Esta página resume os casos em que o comportamento difere deliberadamente. + +## Âmbito + +| Capacidade | Bibliotecas C# | sil-lift | +| ------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Versões do LIFT | 0,10–0,13 (migração integrada) | **Apenas 0.13**; as versões mais antigas são rejeitadas com um erro claro | +| Migração de versão | `Migrator` (cadeia XSLT) | nenhuma — utilizar os XSLT do «lift-standard» para atualizações pontuais | +| Fusão/sincronização a três vias | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From dae45d8ccbb1616b397cf3e7a02f46344aa82f45 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:13 -0600 Subject: [PATCH 007/317] New translations csharp-differences.md (Russian) [ci skip] --- docs/ru/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/ru/csharp-differences.md diff --git a/docs/ru/csharp-differences.md b/docs/ru/csharp-differences.md new file mode 100644 index 0000000..01b9867 --- /dev/null +++ b/docs/ru/csharp-differences.md @@ -0,0 +1,52 @@ +# Отличия от библиотек C\# + +sil-lift в общих чертах аналогичен инструментарию SIL для C# LIFT — в первую очередь `SIL.Lift` из [libpalaso](https://github.com/sillsdev/libpalaso) (парсер, валидатор, мигратор, `LiftSorter`), `SIL.DictionaryServices` в том же репозитории (модель `LexEntry`/`LexSense` с собственным считывателем/записывателем LIFT, которую используют The Combine и WeSay), а также обработчики LIFT в [Chorus](https://github.com/sillsdev/chorus). Это новая реализация, а не порт. На этой странице приведены краткие сведения о том, в каких случаях поведение намеренно отличается. + +## Область применения + +| Возможности | Библиотеки C# | sil-lift | +| ----------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------- | +| Версии LIFT | 0,10–0,13 (с учётом миграции) | **Только версия 0.13**; более старые версии отклоняются с явной ошибкой | +| Переход на новую версию | `Migrator` (цепочка XSLT) | нет — использовать XSLT-файлы из пакета lift-standard для разовых обновлений | +| 3-стороннее слияние / синхронизация | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 774c7fe4cbfd42e8362d4cd99739f6404f28fbb9 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:14 -0600 Subject: [PATCH 008/317] New translations csharp-differences.md (Chinese Simplified) [ci skip] --- docs/zh/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/zh/csharp-differences.md diff --git a/docs/zh/csharp-differences.md b/docs/zh/csharp-differences.md new file mode 100644 index 0000000..6153ffd --- /dev/null +++ b/docs/zh/csharp-differences.md @@ -0,0 +1,52 @@ +# 与 C# 库的区别 + +sil-lift 与 SIL 的 C# LIFT 工具集大致类似——主要包括 [libpalaso](https://github.com/sillsdev/libpalaso) 中的 `SIL.Lift`(解析器、验证器、迁移器、`LiftSorter`)、同一仓库中的 `SIL.DictionaryServices`(该仓库中的 `LexEntry`/`LexSense` 模型,带有专用的 LIFT 读写器,被 The Combine 和 WeSay 所采用),以及 [Chorus](https://github.com/sillsdev/chorus) 中的 LIFT 处理程序。 这是一个全新的实现,而不是移植。 本页总结了行为在哪些方面存在有意差异。 + +## 范围 + +| 能力 | C# 库 | sil-lift | +| ---------- | ------------------------------------------------- | ------------------------------------------ | +| LIFT 版本 | 0.10–0.13(内置迁移功能) | **仅限 0.13 版**;旧版本将被明确拒绝 | +| 版本迁移 | `Migrator`(XSLT 链) | 无 — 对于一次性升级,请使用 lift-standard 中的 XSLT 文件 | +| 三向合并/同步 | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 262652073fe8a9668e74143cb2fedb9c31449912 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:16 -0600 Subject: [PATCH 009/317] New translations csharp-differences.md (Hindi) [ci skip] --- docs/hi/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/hi/csharp-differences.md diff --git a/docs/hi/csharp-differences.md b/docs/hi/csharp-differences.md new file mode 100644 index 0000000..8a2cdc9 --- /dev/null +++ b/docs/hi/csharp-differences.md @@ -0,0 +1,52 @@ +# C# लाइब्रेरियों से अंतर + +sil-lift मोटे तौर पर SIL के C# LIFT टूलिंग के समान है — मुख्य रूप से [libpalaso](https://github.com/sillsdev/libpalaso) में `SIL.Lift` (पार्सर, वैलिडेटर, माइग्रेटर, `LiftSorter`), `SIL.DictionaryServices` उसी रिपॉजिटरी में (`LexEntry`/`LexSense` मॉडल, अपने स्वयं के LIFT रीडर/राइटर के साथ, जिसका उपयोग The Combine और WeSay करते हैं), और [Chorus](https://github.com/sillsdev/chorus) में LIFT हैंडलर। यह एक नया कार्यान्वयन है, पोर्ट नहीं। यह पृष्ठ उन स्थानों का सारांश प्रस्तुत करता है जहाँ व्यवहार जानबूझकर भिन्न होता है। + +## दायरा + +| क्षमता | सी# लाइब्रेरीज़ | सिल-लिफ्ट | +| ------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | +| लिफ्ट संस्करण | 0.10–0.13 (स्थानांतरण अंतर्निहित) | केवल **0.13**; पुराने संस्करणों को एक स्पष्ट त्रुटि के साथ अस्वीकार कर दिया जाता है। | +| संस्करण माइग्रेशन | `Migrator` (XSLT श्रृंखला) | कोई नहीं — एकमुश्त अपग्रेड के लिए लिफ्ट-स्टैंडर्ड में मौजूद XSLTs का उपयोग करें। | +| 3-तरफ़ा मर्ज / सिंक | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 97449a3df15dc357d7699de909e5c14ffe198ac7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:18 -0600 Subject: [PATCH 010/317] New translations csharp-differences.md (Swahili) [ci skip] --- docs/sw/csharp-differences.md | 52 +++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/sw/csharp-differences.md diff --git a/docs/sw/csharp-differences.md b/docs/sw/csharp-differences.md new file mode 100644 index 0000000..78a9a58 --- /dev/null +++ b/docs/sw/csharp-differences.md @@ -0,0 +1,52 @@ +# Tofauti na maktaba za C\# + +sil-lift ni mfano hafifu wa zana za LIFT za C# za SIL — hasa `SIL.Lift` katika [libpalaso](https://github.com/sillsdev/libpalaso) (mshinikizo, mhakiki, mhamishaji, `LiftSorter`), `SIL.DictionaryServices` katika repo hiyo hiyo (mfano wa `LexEntry`/`LexSense`, ukiwa na msomaji/mwandishi wake wa LIFT, ambao The Combine na WeSay hutumia), na vishughulikiaji vya LIFT katika [Chorus](https://github.com/sillsdev/chorus). Ni utekelezaji mpya, sio toleo lililohamishwa. Ukurasa huu unafupisha mahali tabia inatofautiana kwa makusudi. + +## Wigo + +| Uwezo | Maktaba za C# | sil-lift | +| ----------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | +| Toleo za LIFT | 0.10–0.13 (uhamiaji umejengewa ndani) | **0.13 tu**; matoleo ya zamani yanakataliwa kwa kosa dhahiri | +| Uhamishaji wa toleo | `Migrator` (mnyororo wa XSLT) | Hakuna — tumia XSLTs katika lifti-kawaida kwa ajili ya masasisho ya mara moja | +| Muunganiko/Ulinganisho wa njia tatu | Chorus | out of scope | +| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | +| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | + +## API shape + +`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. + +## Round-trip fidelity + +The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: + +- an unchanged document saves **byte-identically**, and +- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). + +See [Fidelity guarantees](fidelity.md). + +## Validation + +The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: + +- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. +- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. +- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. + +sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) + +## Canonical sorting + +`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: + +- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); +- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); +- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. + +The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. + +## Not carried over + +- WeSay-specific conveniences (dashboard/config handling around LIFT files). +- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. +- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. From 454ad1ba96f5822edfd8b076f69147612c003d09 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:19 -0600 Subject: [PATCH 011/317] New translations fidelity.md (French) [ci skip] --- docs/fr/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/fr/fidelity.md diff --git a/docs/fr/fidelity.md b/docs/fr/fidelity.md new file mode 100644 index 0000000..c8241af --- /dev/null +++ b/docs/fr/fidelity.md @@ -0,0 +1,30 @@ +# Garanties de fidélité + +LIFT est un format d'_échange_ : la règle d'or est de **ne jamais omettre ce que l'on ne comprend pas**. Le contrat de `sil-lift`, vérifié par la suite de tests à chaque exécution (fichiers de corpus et génération basée sur les propriétés) : + +## Lecture + +Tout document LIFT 0.13 bien formé se charge, même s'il contient du contenu non conforme au schéma. Tout ce qui n'est pas défini par le modèle est stocké dans le compartiment opaque `Extras` du nœud le plus proche : attributs et éléments inconnus, commentaires XML et instructions de traitement, texte isolé, ainsi que les attributs typés mal formés (une date incorrecte reste sous forme de chaîne d'origine dans `Extras` ; le champ typé prend la valeur `None`). + +## Enregistrer un document sans modification + +`load()` → `save()` sans modification génère une **sortie identique au niveau des octets** — pas de reformatage, pas de ré-échappement, pas de réorganisation ; les marques d'ordre des octets et les déclarations XML sont incluses. Il n'existe actuellement aucune liste de normalisation : l'identité est exacte. + +Exceptions (le programme de lecture revient à la sérialisation canonique complète, qui est sémantiquement complète mais ne préserve pas les octets) : + +- le codage source n'est pas compatible ASCII (il ne s'agit ni d'UTF-8 ni d'US-ASCII), ou +- le code source contient une déclaration DOCTYPE, ou +- le scanner d'octets et l'analyseur syntaxique ne s'accordent pas sur la structure de premier niveau du document — par exemple, un deuxième `
` non conforme à la spécification, que l'analyseur syntaxique ne conserve qu'une seule fois (le scanner se montre délibérément méfiant : le moindre doute l'amène à ne capturer aucun octet source), ou +- le code source a été généré en mémoire plutôt que chargé à partir d'un fichier. + +## Enregistrer un document modifié + +- **Les entrées non modifiées sont transmises telles quelles, à partir de leurs octets d'origine.** Une entrée est considérée comme modifiée si une partie quelconque de son objet modèle a changé depuis l'analyse (ce qui est détecté par l'instantané de sérialisation canonique, et non par un indicateur de modification). +- **Les entrées modifiées sont resérialisées de manière canonique et complète** : UTF-8, indentation à 2 espaces _en dehors_ du contenu mixte (les espaces à l'intérieur de `` et `` ne sont jamais modifiés), un regroupement des éléments enfants documenté pour chaque élément (par exemple, entrée : unité lexicale, citation, prononciations, variantes, sens, notes, relations, étymologies, annotations, traits, champs), ordre fixe des attributs, dates au format ISO-8601 (`Z` pour l'UTC). Tous les résidus sont réémis ; leur position est rétablie dans l'index enfant d'origine, en étant ancrée à la nouvelle liste des enfants (il s'agit d'une approximation — les positions exactes en octets ne sont garanties que pour les entrées non modifiées). +- L'ajout, la suppression ou le réordonnancement d'entrées entraîne une nouvelle sérialisation de la structure du document, mais les octets de chaque entrée inchangée sont toujours restitués à l'identique. + +## Approximations connues (nœuds touchés uniquement) + +- Les commentaires situés _à l'intérieur_ d'une exécution `` sont conservés, mais déplacés à côté de l'exécution, et non à leur position exacte en caractères. +- L'ordre croisé des enfants au sein d'un élément modifié est normalisé selon le regroupement canonique (la propriété `interleave` du schéma LIFT rend cet ordre sans importance sur le plan sémantique). +- Un élément multitext présent mais ne contenant rien — ni forme, ni résidu, par exemple `` — n'est pas réémis. Le modèle représente ces champs sous la forme d'un `Multitext` toujours présent (`lexical-unit`, `citation`, `definition`, l'`usage` d'une relation et `label` / `abbrev` / `description` sur les références URL, les intervalles, les éléments d’intervalle et l’en-tête), de sorte qu’un champ vide est impossible à distinguer d’un champ absent après analyse. Il n'y a aucune perte sémantique. From de1e462d1150cd83db28fac06905e1f53d676c9c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:21 -0600 Subject: [PATCH 012/317] New translations fidelity.md (Spanish) [ci skip] --- docs/es/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/es/fidelity.md diff --git a/docs/es/fidelity.md b/docs/es/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/es/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 7c91a3a4949ee78be2fece6745c2312c6535dbca Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:22 -0600 Subject: [PATCH 013/317] New translations fidelity.md (Arabic) [ci skip] --- docs/ar/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/ar/fidelity.md diff --git a/docs/ar/fidelity.md b/docs/ar/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/ar/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 1a0fd7e8532379f80551490c97146733d93e5b5e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:24 -0600 Subject: [PATCH 014/317] New translations fidelity.md (German) [ci skip] --- docs/de/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/de/fidelity.md diff --git a/docs/de/fidelity.md b/docs/de/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/de/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 2c0cba50653dab966441e0bca4a6633cd06f2513 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:25 -0600 Subject: [PATCH 015/317] New translations fidelity.md (Japanese) [ci skip] --- docs/ja/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/ja/fidelity.md diff --git a/docs/ja/fidelity.md b/docs/ja/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/ja/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 487b7b6b6d05eb677336a0cfd679b4832e924ba2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:27 -0600 Subject: [PATCH 016/317] New translations fidelity.md (Portuguese) [ci skip] --- docs/pt/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/pt/fidelity.md diff --git a/docs/pt/fidelity.md b/docs/pt/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/pt/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 0a024067a89758f8961d85e2c4dc2e0f9690ef81 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:28 -0600 Subject: [PATCH 017/317] New translations fidelity.md (Russian) [ci skip] --- docs/ru/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/ru/fidelity.md diff --git a/docs/ru/fidelity.md b/docs/ru/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/ru/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From a31e45d5f6d379a034f243d9d7f93cc73661d8dc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:30 -0600 Subject: [PATCH 018/317] New translations fidelity.md (Chinese Simplified) [ci skip] --- docs/zh/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/zh/fidelity.md diff --git a/docs/zh/fidelity.md b/docs/zh/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/zh/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 679bea7fbfe956673b5ec04d7353a7fefa4f6e7d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:31 -0600 Subject: [PATCH 019/317] New translations fidelity.md (Hindi) [ci skip] --- docs/hi/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/hi/fidelity.md diff --git a/docs/hi/fidelity.md b/docs/hi/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/hi/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From 93f51dd96bcd960a54fccfea005d75b3591cdf92 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:33 -0600 Subject: [PATCH 020/317] New translations fidelity.md (Swahili) [ci skip] --- docs/sw/fidelity.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/sw/fidelity.md diff --git a/docs/sw/fidelity.md b/docs/sw/fidelity.md new file mode 100644 index 0000000..bb4e858 --- /dev/null +++ b/docs/sw/fidelity.md @@ -0,0 +1,30 @@ +# Fidelity guarantees + +LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): + +## Reading + +Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). + +## Saving an unchanged document + +`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. + +Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): + +- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or +- the source contains a DOCTYPE, or +- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or +- the source was built in memory rather than loaded from a file. + +## Saving an edited document + +- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). +- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). +- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. + +## Known approximations (touched nodes only) + +- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. +- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). +- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. From bf20c98f4e2667d07b9c86f5aac892c03bd3e1fa Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:34 -0600 Subject: [PATCH 021/317] New translations build-export.md (French) [ci skip] --- docs/fr/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/fr/guides/build-export.md diff --git a/docs/fr/guides/build-export.md b/docs/fr/guides/build-export.md new file mode 100644 index 0000000..965b73a --- /dev/null +++ b/docs/fr/guides/build-export.md @@ -0,0 +1,168 @@ +# Exemple pratique : créer une exportation LIFT à partir de zéro + +Si vous exportez les données d'une autre application au format LIFT — ce qui correspond à la tâche décrite dans [« Produire un LIFT conforme »](lift-export-interop.md) —, `sil-lift` peut construire le document objet par objet et le sérialiser, au lieu de générer manuellement du code XML. Ce guide présente un script qui construit une entrée comprenant les éléments caractéristiques d'un véritable dictionnaire (plusieurs systèmes d'écriture, une prononciation, un sens accompagné d'un exemple, une illustration, un trait de domaine sémantique et un champ spécifique à l'application), écrit les vocabulaires contrôlés dans un fichier compagnon `.lift-ranges`, effectue une validation, puis enregistre le tout. + +## Le scénario + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# Une entrée, construite à partir du modèle source. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # Convention de nommage des locuteurs du Combine +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "une volaille domestique élevée pour ses œufs et sa viande" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "Une poule" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # un champ supplémentaire spécifique à l’application +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# Les vocabulaires contrôlés auxquels l'entrée fait référence, dans un fichier .lift-ranges associé. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Valider ce que save() écrirait, avant d'écrire sur le disque. +problems = list(lex.iter_problems()) +print(f"validation : {len(problems)} problème(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## Ce qu'il produit + +`validation : 0 problème(s)`, puis le `.lift` et son équivalent côte à côte : + +``` +=== birds.lift === + + +
+ + + + +
+ + +
+ nkhuku +
+
+ galinha +
+
+ +
+ Intervenante : Ana +
+ +
+ + + + poulet + + +
+ volaille élevée pour ses œufs et sa viande +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ Je veux un poulet. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Remarques sur l'API + +- Champs multitexte (`lexical_unit`, `definition`, une étiquette `Form`/`URLRef`, le contenu d'un `Field`, etc.) Prendre une chaîne par système d'écriture via l'interface de mappage : `entry.lexical_unit["seh"] = "nkhuku"` ajoute un `
`. Un modèle source qui indexe les chaînes de caractères par code de langue s'adapte parfaitement à cette structure. +- `RangesFile.add_range()` / `Range.add_element()` permettent de créer les vocabulaires contrôlés, tandis que `Lexicon.add_ranges_file(ranges, href=...)` associe le fichier correspondant et ajoute les références d’en-tête ``, de sorte que les entrées `` et `` renvoient aux plages que vous avez définies. +- Un `URLRef` est un attribut `href` accompagné d'un texte multiple facultatif (légende ou étiquette) — utilisé à la fois pour `` (audio) et `` (photos). La prononciation suivie ici respecte la convention de The Combine, qui prévoit une forme « en » se lisant « Intervenant : ». +- Les données spécifiques à l'application ne comportant pas de trajets de retour LIFT natifs, sous la forme « » (ou « ») : FieldWorks les interprète comme des champs personnalisés et The Combine les conserve. +- Attribuez à chaque entrée un `guid` réel et stable (généré par exemple par `uuid.uuid4()`, réutilisé d'une exportation à l'autre) : une réimportation ultérieure mettra à jour l'entrée sur place plutôt que de la dupliquer. La commande `sil-lift validate --require-ids` garantit le respect de cette règle. +- La fonction `lex.iter_problems()` valide le document en mémoire (ce que la fonction `save()` écrirait) avant que quoi que ce soit ne soit enregistré sur le disque ; ici, il est correct. Comme le lexique ne dispose pas encore de dossier, les vérifications « media-presence » et « companion-href » sont ignorées — exécutez [`sil-lift validate`](cli.md) sur le fichier de sortie enregistré (ou avec l'option `--no-check-media`) une fois que les fichiers audio et photo sont en place. + +## Emballage + +La commande `lex.save("export/birds.lift")` enregistre le dossier sous la forme (fichiers `.lift` et `.lift-ranges` côte à côte). Pour générer un seul fichier compressé que FieldWorks et The Combine importent directement, utilisez plutôt `lex.save_zip("birds.zip")` — voir [Création de fichiers LIFT conformes](lift-export-interop.md). From 954f275c496ede734d870fa7461ff6ed51eb9302 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:36 -0600 Subject: [PATCH 022/317] New translations build-export.md (Spanish) [ci skip] --- docs/es/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/es/guides/build-export.md diff --git a/docs/es/guides/build-export.md b/docs/es/guides/build-export.md new file mode 100644 index 0000000..37a5597 --- /dev/null +++ b/docs/es/guides/build-export.md @@ -0,0 +1,168 @@ +# Ejemplo práctico: cómo crear una exportación LIFT desde cero + +Si estás exportando los datos de otra aplicación en formato LIFT —la tarea que subyace a [La generación de LIFT conforme a las normas](lift-export-interop.md)—, `sil-lift` puede construir el documento objeto a objeto y serializarlo, en lugar de generar el XML manualmente. Aquí se explica paso a paso cómo funciona un script que crea una entrada con los elementos que contiene un diccionario real (varios sistemas de escritura, una pronunciación, un significado con un ejemplo, una ilustración, una característica de dominio semántico y un campo específico de la aplicación), escribe los vocabularios controlados en un archivo complementario `.lift-ranges`, los valida y los guarda. + +## El guión + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# Una entrada, creada a partir del modelo de origen. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Hablante: Ana" # La convención de etiquetas de hablantes de The Combine +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "ave doméstica criada por sus huevos y su carne" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "Una gallina" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # un campo adicional específico de la aplicación +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# Los vocabularios controlados a los que hace referencia la entrada, en un archivo .lift-ranges complementario. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Valida lo que escribiría save(), antes de guardar en el disco. +problems = list(lex.iter_problems()) +print(f"validación: {len(problems)} problema(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## Qué produce + +`validación: 0 problema(s)`, y a continuación el `.lift` y su equivalente, uno al lado del otro: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ gallina +
+
+ +
+ Hablante: Ana +
+ +
+ + + + gallina + + +
+ ave doméstica criada por sus huevos y su carne +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ Quiero un pollo. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== aves.gamas de peso === + + + + + + + + + + + + + +``` + +## Notas sobre la API + +- Campos multitexto (`lexical_unit`, `definition`, una etiqueta de `Form`/`URLRef`, el contenido de un `Field`, etc.) Selecciona una cadena por sistema de escritura a través de la interfaz de mapeo: `entry.lexical_unit["seh"] = "nkhuku"` añade un `
`. Un modelo de origen que indexa las cadenas por código de idioma se corresponde directamente con esto. +- `RangesFile.add_range()` / `Range.add_element()` crean los vocabularios controlados, y `Lexicon.add_ranges_file(ranges, href=...)` adjunta el archivo complementario y añade las referencias de encabezado ``, de modo que las entradas `` y `` se resuelven en función de los rangos que hayas definido. +- Un `URLRef` es un atributo `href` junto con un texto múltiple opcional (leyenda o etiqueta), que se utiliza tanto para `` (audio) como para `` (fotos). La pronunciación aquí sigue la convención de The Combine, que consiste en una forma «en» que se lee « ». +- Datos específicos de la aplicación que no contengan desplazamientos de ida a casa nativos de LIFT como « » (o « »): FieldWorks los interpreta como campos personalizados y The Combine los conserva. +- Asigna a cada entrada un `guid` real y estable (por ejemplo, generado con `uuid.uuid4()`, que se reutilice en todas las exportaciones): así, si se vuelve a importar más adelante, la entrada se actualizará in situ en lugar de duplicarse. El comando `sil-lift validate --require-ids` garantiza el cumplimiento de esta norma. +- `lex.iter_problems()` comprueba la validez del documento almacenado en memoria (lo que escribiría `save()`) antes de que nada se guarde en el disco; aquí está en perfecto estado. Dado que el léxico aún no tiene ninguna carpeta, se omiten las comprobaciones de «media-presence» y «companion-href»: ejecuta [`sil-lift validate`](cli.md) sobre el resultado guardado (o con `--no-check-media`) una vez que los archivos de audio y las fotos estén en su sitio. + +## Embalaje + +`lex.save("export/birds.lift")` guarda la estructura de la carpeta (los archivos `.lift` y `.lift-ranges` uno al lado del otro). Para generar un único paquete comprimido que FieldWorks y The Combine puedan importar directamente, utiliza en su lugar `lex.save_zip("birds.zip")`; consulta [Cómo generar archivos LIFT conformes](lift-export-interop.md). From 2b75f294f45ecbec2682ea02dbc806ba5c0427e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:37 -0600 Subject: [PATCH 023/317] New translations build-export.md (Arabic) [ci skip] --- docs/ar/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/ar/guides/build-export.md diff --git a/docs/ar/guides/build-export.md b/docs/ar/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/ar/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From 1e2dde0cb1fb37a11e37b1b4b9f4ee4238af2d06 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:39 -0600 Subject: [PATCH 024/317] New translations build-export.md (German) [ci skip] --- docs/de/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/de/guides/build-export.md diff --git a/docs/de/guides/build-export.md b/docs/de/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/de/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From 18afc8be3538bed4c9edb998456c2a7b4d0cf22b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:40 -0600 Subject: [PATCH 025/317] New translations build-export.md (Japanese) [ci skip] --- docs/ja/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/ja/guides/build-export.md diff --git a/docs/ja/guides/build-export.md b/docs/ja/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/ja/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From b9e421bd8fbacdc19a80dcc5cd41058b264c2fd3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:45 -0600 Subject: [PATCH 026/317] New translations build-export.md (Portuguese) [ci skip] --- docs/pt/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/pt/guides/build-export.md diff --git a/docs/pt/guides/build-export.md b/docs/pt/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/pt/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From f1448952440ceb6feebf2a124b856383641ce381 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:47 -0600 Subject: [PATCH 027/317] New translations build-export.md (Russian) [ci skip] --- docs/ru/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/ru/guides/build-export.md diff --git a/docs/ru/guides/build-export.md b/docs/ru/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/ru/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From fb307200404b2ae4ae591bdd6610afa15431c311 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:49 -0600 Subject: [PATCH 028/317] New translations build-export.md (Chinese Simplified) [ci skip] --- docs/zh/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/zh/guides/build-export.md diff --git a/docs/zh/guides/build-export.md b/docs/zh/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/zh/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From e8db8ac6edfc0c4f82e0a91fff6d3fa780f93723 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:50 -0600 Subject: [PATCH 029/317] New translations build-export.md (Hindi) [ci skip] --- docs/hi/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/hi/guides/build-export.md diff --git a/docs/hi/guides/build-export.md b/docs/hi/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/hi/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From ff84619d944570aac29c346923ef57ec97b6fda4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:52 -0600 Subject: [PATCH 030/317] New translations build-export.md (Swahili) [ci skip] --- docs/sw/guides/build-export.md | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 docs/sw/guides/build-export.md diff --git a/docs/sw/guides/build-export.md b/docs/sw/guides/build-export.md new file mode 100644 index 0000000..ce13b26 --- /dev/null +++ b/docs/sw/guides/build-export.md @@ -0,0 +1,168 @@ +# Worked example: building a LIFT export from scratch + +If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. + +## The script + +```python +from pathlib import Path + +import sil_lift + +lex = sil_lift.Lexicon(producer="my-exporter") + +# One entry, built from the source model. +entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") +entry.lexical_unit["seh"] = "nkhuku" +entry.lexical_unit["pt"] = "galinha" + +pron = sil_lift.Pronunciation() +pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) +entry.pronunciations.append(pron) + +sense = sil_lift.Sense(id="kanga_s1") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) +sense.definition["en"] = "a domestic fowl kept for its eggs and meat" + +example = sil_lift.Example() +example.forms["seh"] = "Ndinafuna nkhuku." +translation = sil_lift.Translation() +translation.forms["en"] = "I want a chicken." +example.translations.append(translation) +sense.examples.append(example) + +photo = sil_lift.URLRef(href="pictures/hen.jpg") +photo.label["en"] = "A hen" +sense.illustrations.append(photo) + +sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) + +scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific.content["en"] = "Gallus gallus domesticus" +sense.fields.append(scientific) + +entry.senses.append(sense) +lex.entries.append(entry) + +# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +ranges = sil_lift.RangesFile() +ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +lex.add_ranges_file(ranges, href="birds.lift-ranges") + +# Validate what save() would write, before touching the disk. +problems = list(lex.iter_problems()) +print(f"validation: {len(problems)} problem(s)") + +out = Path("export") +out.mkdir(exist_ok=True) +lex.save(out / "birds.lift") +print("=== birds.lift ===") +print((out / "birds.lift").read_text(encoding="utf-8"), end="") +print("=== birds.lift-ranges ===") +print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") +``` + +## What it produces + +`validation: 0 problem(s)`, then the `.lift` and its companion side by side: + +``` +=== birds.lift === + + +
+ + + + +
+ + + + nkhuku + +
+ galinha +
+
+ +
+ Speaker: Ana +
+ +
+ + + + chicken + + +
+ a domestic fowl kept for its eggs and meat +
+
+ +
+ Ndinafuna nkhuku. +
+ +
+ I want a chicken. +
+
+
+ + + + + +
+ Gallus gallus domesticus +
+
+
+
+
+=== birds.lift-ranges === + + + + + + + + + + + + + +``` + +## Notes on the API + +- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. +- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. +- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. +- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. +- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. +- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. + +## Packaging + +`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). From 42ffc9dd8dcb54bfe8ce7acddf4943239fb8eee1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:53 -0600 Subject: [PATCH 031/317] New translations bulk-edit-glosses.md (French) [ci skip] --- docs/fr/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/fr/guides/bulk-edit-glosses.md diff --git a/docs/fr/guides/bulk-edit-glosses.md b/docs/fr/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..2b5b683 --- /dev/null +++ b/docs/fr/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Exemple pratique : modification groupée des gloses + +Une tâche de maintenance courante : harmoniser l'orthographe de toutes les entrées en anglais d'un lexique (anglais britannique → anglais américain, ou inversement) sans modifier aucun autre élément du fichier. Cet exemple présente un script qui charge, modifie, valide et enregistre des données, illustrant ainsi le fonctionnement conjoint de l'API d'édition et de la garantie de fidélité. + +## Le scénario + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Renvoie chaque sens, y compris les sous-sens (récursif).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"Interruption : {len(errors)} erreur(s) de validation, rien n'a été enregistré") + +lex.save() +print(f" {edited_glosses} s de glosses modifiés sur {len(touched_entries)} entrée(s)"") +``` + +Quelques points à retenir : + +- `Sense.subsenses` est lui-même une `list[Sense]` ; ainsi, `iter_senses` effectue une itération récursive sur cet élément — une modification groupée qui ne parcourrait que `entry.senses` omettrait sans avertissement tout glossaire imbriqué sous un sens secondaire. +- `gloss.text` est un objet `Text`, et non une simple chaîne de caractères : `str(gloss.text)` l'aplatit pour permettre la correspondance, et le remplacement est réécrit à l'aide de `sil_lift.Text([new])` plutôt que de modifier la chaîne en place. +- La validation en mémoire (`lex.iter_problems()`) sérialise d'abord l'état modifié, ce qui permet de s'assurer qu'il reflète correctement les modifications avant que quoi que ce soit ne soit écrit sur le disque. L'interruption en cas de `Problem` de niveau « erreur » — les avertissements sont laissés à l'appréciation de l'appelant — garantit qu'une modification incorrecte n'atteindra jamais la fonction `save()`. + +Les gloss ne sont pas les seuls produits qui méritent d'être appliqués de cette manière. La même surface de mappage `Multitext` s'applique aux définitions et à tous les autres champs multilingues d'une entrée ou d'un sens : + +```python +sense.definition["en"] = "la couleur d'un objet" +``` + +## L'exécuter + +Effectuez une recherche dans un petit lexique comportant une définition et une sous-définition qui indiquent toutes deux « couleur » : + +``` +modification de 2 termes dans 1 entrée +``` + +## Les avantages de la fidélité + +La garantie s'applique à chaque _entrée_ : une entrée dont le modèle n'a pas changé est restituée **à l'identique au niveau des octets** par rapport à sa forme d'origine, et seules les entrées sur lesquelles vous avez effectivement intervenu sont à nouveau sérialisées. Dans l'extrait ci-dessus, les gloses d'une entrée ont été modifiées — toutes les autres entrées du fichier ont conservé exactement les mêmes octets. (Notez le niveau de détail : la modification d'une partie quelconque d'une entrée entraîne la resérialisation de l'intégralité de cette entrée, y compris ses sens apparentés qui n'ont pas été modifiés.) La modification d'un terme dans un lexique de 50 000 entrées génère donc un fichier « diff » ne concernant qu'une seule entrée, et non un fichier reformaté. Pour consulter le contrat dans son intégralité, voir [Garanties Fidelity](../fidelity.md). From 31238db74f9b7b614d907f303ce0fb564d250923 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:55 -0600 Subject: [PATCH 032/317] New translations bulk-edit-glosses.md (Spanish) [ci skip] --- docs/es/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/es/guides/bulk-edit-glosses.md diff --git a/docs/es/guides/bulk-edit-glosses.md b/docs/es/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..331746f --- /dev/null +++ b/docs/es/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Ejemplo práctico: edición masiva de glosas + +Una tarea habitual de mantenimiento: armonizar la ortografía de todas las entradas en inglés de un léxico (del inglés británico al americano, o viceversa) sin alterar el resto del archivo. En este ejemplo se muestra paso a paso un script que carga, edita, valida y guarda, lo que permite ver cómo funcionan conjuntamente la API de edición y la garantía de fidelidad. + +## El guión + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Devuelve cada acepción, incluidas las subacepciones (recursivo).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"interrupción: {len(errors)} error(es) de validación, nada guardado") + +lex.save() +print(f" {edited_glosses} de glosas editadas en {len(touched_entries)} entrada(s)") +``` + +Algunas cosas que conviene destacar: + +- `Sense.subsenses` es en sí mismo una `lista[Sense]`, por lo que `iter_senses` recorre su contenido de forma recursiva; una edición masiva que solo recorriera `entry.senses` omitiría sin avisar cualquier glosa anidada bajo un subsentido. +- `gloss.text` es un `Text`, no una cadena simple: `str(gloss.text)` lo convierte en una cadena para la búsqueda de coincidencias, y la sustitución se vuelve a escribir con `sil_lift.Text([new])` en lugar de modificar la cadena in situ. +- La validación en memoria (`lex.iter_problems()`) serializa primero el estado editado, de modo que este refleje correctamente los cambios antes de que se guarde nada en el disco. Interrumpir la operación ante cualquier `Problem` de nivel «error» —las advertencias se dejan a criterio de quien realiza la llamada— significa que una edición incorrecta nunca llega a `save()`. + +Los brillos no son lo único que merece la pena tratar de esta manera. La misma superficie de asignación `Multitext` se aplica a las definiciones y a cualquier otro campo multilingüe de una entrada o un significado: + +```python +sense.definition["en"] = "el color de algo" +``` + +## Ejecutarlo + +Compáralo con un léxico reducido que contenga una entrada y una subentrada que, en ambos casos, indiquen «color»: + +``` +se han editado 2 glosas en 1 entrada +``` + +## La recompensa de la fidelidad + +La garantía se aplica por _entrada_: una entrada cuyo modelo no haya cambiado se devuelve **identica al nivel de bytes** a como se leyó, y solo se vuelven a serializar las entradas en las que realmente se ha realizado algún cambio. En la ejecución anterior, se editaron las glosas de una entrada; el resto de entradas del archivo conservaron sus bytes exactos. (Fíjate en el nivel de detalle: al editar cualquier parte de una entrada, se vuelve a generar el identificador de serie de toda la entrada, incluidos los significados relacionados que no se hayan modificado.) Por lo tanto, al editar una entrada en un léxico de 50 000 entradas, se genera un archivo «diff» que afecta a una sola entrada, y no un archivo reformateado. Consulta [las garantías de Fidelity](../fidelity.md) para conocer los términos exactos del contrato. From 1792a6205fb474f2227e33b38c9590ec4fde46b4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:56 -0600 Subject: [PATCH 033/317] New translations bulk-edit-glosses.md (Arabic) [ci skip] --- docs/ar/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ar/guides/bulk-edit-glosses.md diff --git a/docs/ar/guides/bulk-edit-glosses.md b/docs/ar/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e24749d --- /dev/null +++ b/docs/ar/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# مثال توضيحي: التحرير الجماعي للتعليقات التوضيحية + +مهمة صيانة شائعة: توحيد قواعد الإملاء في جميع المصطلحات الإنجليزية الواردة في المعجم (من البريطانية إلى الأمريكية، أو العكس) دون المساس بأي عنصر آخر في الملف. يشرح هذا المثال أحد البرامج النصية التي تقوم بالتحميل والتحرير والتحقق من الصحة والحفظ — موضحًا كيفية عمل واجهة برمجة التطبيقات الخاصة بالتحرير وضمان الدقة معًا. + +## النص + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """تسليم كل معنى، بما في ذلك المعاني الفرعية (بشكل متكرر).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"إلغاء العملية: {len(errors)} خطأ (أخطاء) في التحقق من الصحة، لم يتم حفظ أي شيء") + +lex.save() +print(f"تم تحرير {edited_glosses} تعريف (تعريفات) عبر {len(touched_entries)} مدخل (مداخل)") +``` + +بعض النقاط الجديرة بالملاحظة: + +- تعد `Sense.subsenses` بحد ذاتها `list[Sense]`، لذا فإن `iter_senses` تتكرر بداخلها — أما عملية التحرير الجماعي التي تقتصر على `entry.senses` فستتجاهل بصمت أي تفسير متداخل تحت معنى فرعي. +- `gloss.text` هو كائن من نوع `Text`، وليس سلسلة نصية عادية: تعمل الدالة `str(gloss.text)` على تحويله إلى سلسلة نصية عادية لأغراض المطابقة، ويتم كتابة النص البديل باستخدام `sil_lift.Text([new])` بدلاً من تعديل السلسلة في مكانها. +- تقوم عملية التحقق من الصحة في الذاكرة (`lex.iter_problems()`) بتسلسل الحالة التي تم تعديلها أولاً، بحيث تعكس التعديل بشكل صحيح قبل كتابة أي شيء على القرص. إن إيقاف العملية عند حدوث أي `"خطأ"` من فئة `Problem` — حيث تُترك التحذيرات للمستدعي ليحكم عليها — يعني أن عملية التحرير الخاطئة لن تصل أبدًا إلى `save()`. + +اللمعان ليس الشيء الوحيد الذي يستحق أن نلمسه بهذه الطريقة. ينطبق سطح التعيين «Multitext» نفسه على التعريفات وعلى كل حقل متعدد اللغات آخر في أي مدخل أو معنى: + +```python +sense.definition["en"] = "لون الشيء" +``` + +## تشغيله + +قم بإجراء مقارنة مع معجم صغير يحتوي على تفسير رئيسي وتفسير فرعي، وكلاهما يشير إلى كلمة «colour»: + +``` +تم تعديل مصطلحين في مدخلة واحدة +``` + +## مكافأة الإخلاص + +يتم تطبيق الضمان على كل _قيمة_ على حدة: فالقيمة التي لم يتغير نموذجها تُعاد **بشكل مطابق تمامًا من حيث البايتات** كما تم قراءتها في البداية، ولا يتم إعادة تسلسل سوى القيم التي قمت بالتعديل عليها فعليًّا. في المقطع أعلاه، تم تعديل التعليقات التوضيحية في أحد المدخلات — بينما احتفظت جميع المدخلات الأخرى في الملف ببايتاتها بالضبط. (لاحظ مستوى التفصيل: يؤدي تعديل أي جزء من المدخل إلى إعادة تسلسل المدخل بأكمله، بما في ذلك المعاني المماثلة التي لم يتم تعديلها.) وبالتالي، فإن تعديل تعريف واحد في معجم يضم 50,000 مدخلاً ينتج عنه ملف «diff» يؤثر على مدخل واحد فقط، وليس ملفًا معاد تنسيقه. انظر [ضمانات فيديليتي](../fidelity.md) للاطلاع على نص العقد الدقيق. From 84a513037f17fbac56e70b51fc5e31b348f07634 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:58 -0600 Subject: [PATCH 034/317] New translations bulk-edit-glosses.md (German) [ci skip] --- docs/de/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/de/guides/bulk-edit-glosses.md diff --git a/docs/de/guides/bulk-edit-glosses.md b/docs/de/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/de/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From cb043fe9340af9b6ca9c3966117e6884f80bb91b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:18:59 -0600 Subject: [PATCH 035/317] New translations bulk-edit-glosses.md (Japanese) [ci skip] --- docs/ja/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ja/guides/bulk-edit-glosses.md diff --git a/docs/ja/guides/bulk-edit-glosses.md b/docs/ja/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/ja/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From ffb7fbdb9532b3254b349a7f54bfe07aa08e7789 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:01 -0600 Subject: [PATCH 036/317] New translations bulk-edit-glosses.md (Portuguese) [ci skip] --- docs/pt/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/pt/guides/bulk-edit-glosses.md diff --git a/docs/pt/guides/bulk-edit-glosses.md b/docs/pt/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/pt/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From bee0bfe3053f3cef3304e91db4d3920656fba670 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:02 -0600 Subject: [PATCH 037/317] New translations bulk-edit-glosses.md (Russian) [ci skip] --- docs/ru/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ru/guides/bulk-edit-glosses.md diff --git a/docs/ru/guides/bulk-edit-glosses.md b/docs/ru/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/ru/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From a1151c47e40618011d3dd2720ebe25102d8c6f36 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:03 -0600 Subject: [PATCH 038/317] New translations bulk-edit-glosses.md (Chinese Simplified) [ci skip] --- docs/zh/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/zh/guides/bulk-edit-glosses.md diff --git a/docs/zh/guides/bulk-edit-glosses.md b/docs/zh/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/zh/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From abb30a22caa3530f7a7a809a6100441f8811ab4e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:05 -0600 Subject: [PATCH 039/317] New translations bulk-edit-glosses.md (Hindi) [ci skip] --- docs/hi/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/hi/guides/bulk-edit-glosses.md diff --git a/docs/hi/guides/bulk-edit-glosses.md b/docs/hi/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/hi/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From 8cbea0dcd45a9a625eb6e1319ec91bc44f024ead Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:06 -0600 Subject: [PATCH 040/317] New translations bulk-edit-glosses.md (Swahili) [ci skip] --- docs/sw/guides/bulk-edit-glosses.md | 70 +++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/sw/guides/bulk-edit-glosses.md diff --git a/docs/sw/guides/bulk-edit-glosses.md b/docs/sw/guides/bulk-edit-glosses.md new file mode 100644 index 0000000..e00876c --- /dev/null +++ b/docs/sw/guides/bulk-edit-glosses.md @@ -0,0 +1,70 @@ +# Worked example: bulk-editing glosses + +A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. + +## The script + +```python +import sys + +import sil_lift + +path = "dictionary.lift" +lex = sil_lift.load(path) + + +def iter_senses(senses): + """Yield every sense, including subsenses (recursive).""" + for sense in senses: + yield sense + yield from iter_senses(sense.subsenses) + + +edited_glosses = 0 +touched_entries = set() + +for entry in lex.entries: + for sense in iter_senses(entry.senses): + for gloss in sense.glosses: + if gloss.lang != "en": + continue + old = str(gloss.text) + new = old.replace("colour", "color") + if new != old: + gloss.text = sil_lift.Text([new]) + edited_glosses += 1 + touched_entries.add(entry.id) + +errors = [p for p in lex.iter_problems() if p.level == "error"] +if errors: + for problem in errors: + print(problem) + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + +lex.save() +print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +``` + +A few things worth noting: + +- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. +- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. +- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. + +Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: + +```python +sense.definition["en"] = "the color of a thing" +``` + +## Running it + +Run against a small lexicon with a gloss and a subsense gloss that both say "colour": + +``` +edited 2 gloss(es) across 1 entry(ies) +``` + +## The fidelity payoff + +The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. From 33b35b75faeb39a435b7985058c73d9e0f69fbc5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:08 -0600 Subject: [PATCH 041/317] New translations cli.md (French) [ci skip] --- docs/fr/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/fr/guides/cli.md diff --git a/docs/fr/guides/cli.md b/docs/fr/guides/cli.md new file mode 100644 index 0000000..5f8d4ac --- /dev/null +++ b/docs/fr/guides/cli.md @@ -0,0 +1,70 @@ +# La ligne de commande + +L'installation du paquet (`pip install sil-lift`) installe également la commande `sil-lift` — un outil de type LiftTools pris en charge et fourni avec le paquet (ainsi que, pour `validate`, un exemple concret d'utilisation de l'API de la bibliothèque). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + tous les problèmes, traités par entrée/ligne ; sortie 1 en cas d’erreurs +sil-lift stats CHEMIN [--format {text,json}] + nombre d’entrées/sens/langues (en continu ; taille indifférente) +sil-lift sort CHEMIN [-o SORTIE] copie triée de manière canonique, prête pour la comparaison (par défaut : sur place) +sil-lift check-media PATH rapport sur les médias manquants et orphelins ; sortie 1 en cas de médias manquants +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + une ligne par sens de feuille (sous-sens aplatis) vers CSV/TSV (en continu) +``` + +`--format json` écrit un seul objet JSON sur la sortie standard (et rien d'autre) à l'intention des outils d'intégration continue (CI) et d'automatisation ; voir le schéma dans l'exemple ci-dessous. L'option `--strict` traite les avertissements comme des erreurs et renvoie la valeur 1 si elle en détecte — utilisez-la pour valider une compilation uniquement si tout est en ordre, et non pas uniquement en cas d'erreurs. L'option `--no-check-media` permet de ne pas effectuer la vérification de la présence des médias dans le système de fichiers (ce qui supprime les messages d'erreur de type `missing-media`), ce qui est utile lors de la validation d'une exportation fraîchement générée dont les fichiers audio/photo se trouvent ailleurs et ne sont pas stockés sur le même disque. `--require-ids` génère également une erreur (`missing-id`) pour toute entrée ne disposant pas d'un `guid` ou pour tout sens ne disposant pas d'un `id` — cette règle est plus stricte que celle de LIFT, pour les flux de travail qui réimportent à l'aide d'un identifiant stable. En passant `-` comme chemin d'accès, le document est lu à partir de l'entrée standard (un document transmis par canalisation n'ayant pas de dossier, son fichier associé `.lift-ranges` et ses médias ne sont pas résolus). La commande `stats` accepte également l'option `--format json`, qui renvoie les statistiques sous la forme d'un objet JSON unique. + +!!! note + Les codes de sortie de `validate` et le schéma `--format json` constituent une interface d'automatisation prise en charge : ils font tous deux l'objet de tests et ne sont modifiés que dans le respect de la norme SemVer. + +La commande `sort` ne modifie que le fichier `.lift` ; les fichiers `.lift-ranges` associés restent inchangés +(triez-les séparément à l'aide de l'API `RangesFile`). + +Les commandes `validate`, `stats`, `check-media` et `export` acceptent également un paquet LIFT compressé (un fichier `.zip` dans l'une ou l'autre des structures suivantes : fichiers à la racine de l'archive ou imbriqués dans un dossier de niveau supérieur) ; celui-ci est extrait dans un répertoire temporaire puis supprimé une fois la commande terminée. + +Exemples : + +``` +$ sil-lift validate dictionary.lift +erreur [dangling-ref] dictionary.lift:88 (entrée apu) : la référence « nope » ne correspond à aucun ID/GUID d'entrée ni à aucun ID de sens +avertissement [uri-not-rfc] dictionary.lift:6 : : lettre de lecteur Windows utilisée comme autorité URI (style FLEx file://C:/) +1 erreur(s), 1 avertissement(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "la référence 'nope' ne correspond à aucun ID d'entrée/GUID ni à aucun ID de sens", + "file": "dictionary.lift", + "entry_id" : "apu", + "guid" : null, + "line" : 88 + }, + { + "level" : "warning", + "code" : "uri-not-rfc", + "message" : ": Lettre de lecteur Windows utilisée comme autorité URI (style FLEx file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + « summary » : { + « errors » : 1, + « warnings » : 1 + } +} + +$ sil-lift stats sango.lift +entrées : 3507 +sens : 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Codes de sortie : `0` : opération réussie (avertissements autorisés, sauf si l'option `--strict` est activée), `1` : problèmes détectés (erreurs de validation / fichiers multimédias manquants / avertissements lorsque l'option `--strict` est activée), `2` : données d'entrée illisibles. From e08593a4783badfc154efe57e6c1cf28bfe64e44 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:10 -0600 Subject: [PATCH 042/317] New translations cli.md (Spanish) [ci skip] --- docs/es/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/es/guides/cli.md diff --git a/docs/es/guides/cli.md b/docs/es/guides/cli.md new file mode 100644 index 0000000..e6db0cc --- /dev/null +++ b/docs/es/guides/cli.md @@ -0,0 +1,70 @@ +# La línea de comandos + +Al instalar el paquete (`pip install sil-lift`) también se instala el comando `sil-lift`, una herramienta compatible con el estilo de LiftTools que se incluye con el paquete (y, en el caso de `validate`, un ejemplo práctico de la API de la biblioteca). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + todos los problemas, por entrada/línea; salida 1 en caso de error +sil-lift stats PATH [--format {text,json}] + recuentos por entrada/sentido/idioma (en streaming; cualquier tamaño) +sil-lift sort PATH [-o OUT] copia ordenada canónicamente y lista para comparaciones (por defecto: in situ) +sil-lift check-media PATH informe de medios que faltan y huérfanos; sale con código 1 si faltan +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + una fila por sentido principal (subsentidos aplanados) a CSV/TSV (en streaming) +``` + +`--format json` escribe un único objeto JSON en la salida estándar (y nada más) para su uso en CI/automatización; consulta el esquema del ejemplo que aparece a continuación. `--strict` trata las advertencias como errores y devuelve el valor 1 si se encuentra alguna; utilízalo para que la compilación solo se complete si todo está en orden, en lugar de basarte únicamente en los errores. `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos (suprimiendo los resultados de `missing-media`), lo cual resulta útil a la hora de validar una exportación recién generada cuyos archivos de audio o fotos se encuentran en otra ubicación y no están almacenados en el mismo disco. `--require-ids` también da error (un error de `missing-id`) en cualquier entrada que carezca de un `guid` o en cualquier sentido que carezca de un `id` — es más estricto que LIFT, para flujos de trabajo que vuelven a importar mediante un identificador estable. Si se pasa `-` como ruta, el documento se lee desde la entrada estándar (un documento transmitido por canalización no tiene carpeta, por lo que su archivo asociado `.lift-ranges` y los archivos multimedia no se resuelven). `stats` también admite la opción `--format json`, con lo que muestra los recuentos en forma de un único objeto JSON. + +!!! note + Los códigos de salida de `validate` y el esquema de `--format json` constituyen una interfaz de automatización compatible: ambos están cubiertos por pruebas y solo cambian según las normas de SemVer. + +`sort` solo reescribe el archivo `.lift`; los archivos complementarios `.lift-ranges` se mantienen sin modificar +(ordénalos por separado con la API `RangesFile`). + +`validate`, `stats`, `check-media` y `export` también admiten un paquete LIFT comprimido (un archivo `.zip` con cualquiera de las dos estructuras: archivos en la raíz del archivo comprimido o anidados dentro de una carpeta de nivel superior); este se extrae a un directorio temporal y se elimina una vez finalizado el comando. + +Ejemplos: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entrada apu): la referencia «nope» no coincide con ningún ID de entrada/GUID ni con ningún ID de significado +advertencia [uri-not-rfc] dictionary.lift:6: : Se ha utilizado una letra de unidad de Windows como autoridad URI (estilo FLEx: file://C:/) +1 error(es), 1 advertencia(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "la referencia 'nope' no coincide con ningún ID de entrada/GUID ni ID de sentido", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Se ha utilizado una letra de unidad de Windows como autoridad URI (estilo FLEx: file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + «summary»: { + «errors»: 1, + «warnings»: 1 + } +} + +$ sil-lift stats sango.lift +entradas: 3507 +acepciones: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Códigos de salida: `0`: éxito (se permiten advertencias, salvo si se utiliza la opción `--strict`); `1`: resultados (errores de validación / medios que faltan / advertencias si se utiliza la opción `--strict`); `2`: entrada ilegible. From 34bfa80a993148e4bfb2ad630e75310130657ad3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:11 -0600 Subject: [PATCH 043/317] New translations cli.md (Arabic) [ci skip] --- docs/ar/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ar/guides/cli.md diff --git a/docs/ar/guides/cli.md b/docs/ar/guides/cli.md new file mode 100644 index 0000000..ff725f7 --- /dev/null +++ b/docs/ar/guides/cli.md @@ -0,0 +1,70 @@ +# سطر الأوامر + +يؤدي تثبيت الحزمة (`pip install sil-lift`) أيضًا إلى تثبيت الأمر `sil-lift` — وهي أداة مدعومة على غرار LiftTools وتأتي مرفقة مع الحزمة (بالإضافة إلى `validate`، وهو مثال عملي على واجهة برمجة تطبيقات المكتبة). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + جميع المشكلات، مع معالجة كل إدخال/سطر على حدة؛ الخروج 1 عند حدوث أخطاء +sil-lift stats PATH [--format {text,json}] + عدد الإدخالات/المعاني/اللغات (بشكل متواصل؛ أي حجم) +sil-lift sort PATH [-o OUT] نسخة مرتبة بشكل قياسي وجاهزة للمقارنة (الافتراضي: في المكان نفسه) +sil-lift check-media PATH تقرير الوسائط المفقودة واليتيمة؛ الخروج برمز 1 في حالة وجود وسائط مفقودة +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + صف واحد لكل معنى فرعي (تم تسطيح المعاني الفرعية) إلى CSV/TSV (بشكل متواصل) +``` + +تقوم الخيار `--format json` بكتابة كائن JSON واحد إلى stdout (ولا شيء غير ذلك) لاستخدامه في عمليات التكامل المستمر (CI) والأتمتة؛ انظر المخطط في المثال أدناه. يعامل الخيار `--strict` التحذيرات كأخطاء، ويُخرج القيمة 1 في حالة العثور على أي منها — استخدمه لضمان أن يتم البناء فقط في حالة عدم وجود أي مشاكل، وليس بناءً على الأخطاء وحدها. تتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات (مما يؤدي إلى إخفاء نتائج `missing-media`)، وهو أمر مفيد عند التحقق من صحة ملف تصدير تم إنشاؤه حديثًا، حيث توجد ملفات الصوت/الصور الخاصة به في مكان آخر وليست موجودة في نفس موقع الملف على القرص. كما أن `--require-ids` تُسفر عن فشل (خطأ `missing-id`) في حالة أي إدخال يفتقر إلى `guid` أو أي معنى يفتقر إلى `id` — وهو أكثر صرامة من LIFT، وذلك بالنسبة لسير العمل التي تعيد الاستيراد باستخدام معرّف ثابت. عند تمرير `-` كمسار، يتم قراءة المستند من المدخل القياسي (لا يحتوي المستند الممرر عبر الأنابيب على مجلد، لذا لا يتم تحديد موقع ملف `.lift-ranges` المصاحب له والوسائط). كما تقبل `stats` الخيار `--format json`، حيث تُخرج الأعداد في شكل كائن JSON واحد. + +!!! note + تُعد رموز الخروج الخاصة بـ `validate` ومخطط `--format json` واجهة أتمتة مدعومة: حيث يخضع كلاهما للاختبارات ولا يتغيران إلا وفقًا لمعايير SemVer. + +تقوم الأداة `sort` بإعادة كتابة ملف `.lift` فقط؛ أما الملفات المصاحبة `.lift-ranges` فتُترك كما هي +(يمكن فرزها بشكل منفصل باستخدام واجهة برمجة التطبيقات `RangesFile`). + +تقبل الأوامر `validate` و`stats` و`check-media` و`export` أيضًا حزمة LIFT مضغوطة (ملف `.zip` بأي من الترتيبين — الملفات في جذر الأرشيف، أو متداخلة ضمن مجلد واحد من المستوى الأعلى)؛ حيث يتم استخراجها إلى دليل مؤقت ثم يتم حذفها عند انتهاء تنفيذ الأمر. + +أمثلة: + +``` +$ sil-lift validate dictionary.lift +خطأ [dangling-ref] dictionary.lift:88 (المدخل apu): المرجع 'nope' لا يتطابق مع أي معرّف مدخل/معرّف فريد (GUID) أو معرّف معنى +تحذير [uri-not-rfc] dictionary.lift:6: : استخدام حرف محرك أقراص Windows كمرجع URI (بأسلوب FLEx file://C:/) +خطأ واحد، تحذير واحد + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": تم استخدام حرف محرك أقراص Windows كمرجع URI (بأسلوب FLEx file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +رموز الخروج: `0` نجاح (يُسمح بوجود تحذيرات، ما لم يتم استخدام الخيار `--strict`)، `1` نتائج (أخطاء في التحقق من الصحة / وسائط مفقودة / تحذيرات عند استخدام الخيار `--strict`)، `2` مدخلات غير قابلة للقراءة. From 0af2532b94a5d6fc28b3edc46c7fb9b03b696d00 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:13 -0600 Subject: [PATCH 044/317] New translations cli.md (German) [ci skip] --- docs/de/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/de/guides/cli.md diff --git a/docs/de/guides/cli.md b/docs/de/guides/cli.md new file mode 100644 index 0000000..238adc9 --- /dev/null +++ b/docs/de/guides/cli.md @@ -0,0 +1,70 @@ +# Die Befehlszeile + +Durch die Installation des Pakets (`pip install sil-lift`) wird auch der Befehl `sil-lift` installiert – ein unterstütztes Tool im LiftTools-Stil, das im Paket enthalten ist (und im Fall von `validate` ein Beispiel für die Nutzung der Bibliotheks-API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + alle Probleme, nach Eintrag/Zeile aufgeschlüsselt; Beendigung mit 1 bei Fehlern +sil-lift stats PATH [--format {text,json}] + Anzahl der Einträge/Sinninhalte/Sprachen (Streaming; beliebige Größe) +sil-lift sort PATH [-o OUT] kanonisch sortierte, diff-fähige Kopie (Standard: an Ort und Stelle) +sil-lift check-media PATH Bericht über fehlende und verwaiste Medien; Beendet mit 1 bei Fehlern +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + eine Zeile pro Blatt-Sense (Subsenses abgeflacht) in CSV/TSV (Streaming) +``` + +`--format json` gibt ein einzelnes JSON-Objekt an die Standardausgabe aus (und sonst nichts), das für CI- und Automatisierungszwecke verwendet werden kann; siehe das Schema im folgenden Beispiel. `--strict` behandelt Warnungen als Fehler und gibt den Wert 1 zurück, wenn welche gefunden werden – verwenden Sie diese Option, um einen Build erst dann zuzulassen, wenn alles einwandfrei ist, und nicht nur bei Fehlern. `--no-check-media` überspringt die Überprüfung der Medienpräsenz im Dateisystem (wodurch `missing-media`-Fehler unterdrückt werden), was bei der Validierung eines frisch generierten Exports nützlich ist, dessen Audio- und Fotodateien an einem anderen Ort gespeichert sind und sich nicht auf derselben Festplatte befinden. `--require-ids` führt zudem zu einem Fehler (einem `missing-id`-Fehler), wenn bei einem Eintrag die `guid` fehlt oder bei einem Sense die `id` fehlt – dies ist strenger als bei LIFT und dient Workflows, bei denen der Reimport anhand einer stabilen ID erfolgt. Wird `-` als Pfad übergeben, wird das Dokument aus der Standard-Eingabe gelesen (ein über eine Pipe übermitteltes Dokument hat keinen Ordner, daher werden die zugehörige Datei `.lift-ranges` und die Medien nicht aufgelöst). `stats` akzeptiert ebenfalls die Option `--format json` und gibt die Zählwerte als einzelnes JSON-Objekt aus. + +!!! note + Die Exit-Codes von `validate` und das Schema von `--format json` stellen eine unterstützte Automatisierungsschnittstelle dar: Beide werden durch Tests abgedeckt und ändern sich nur gemäß SemVer. + +`sort` schreibt nur die `.lift`-Datei neu; die zugehörigen `.lift-ranges`-Dateien bleiben unberührt +(sortieren Sie diese separat mit der `RangesFile`-API). + +`validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls ein komprimiertes LIFT-Paket (eine `.zip`-Datei in einem der beiden Layouts – entweder mit Dateien im Stammverzeichnis des Archivs oder verschachtelt unter einem Ordner der obersten Ebene); dieses wird in ein temporäres Verzeichnis entpackt und nach Abschluss des Befehls gelöscht. + +Beispiele: + +``` +$ sil-lift validate dictionary.lift +Fehler [dangling-ref] dictionary.lift:88 (Eintrag „apu“): Die Referenz „nope“ entspricht keiner Eintrags-ID/GUID oder Bedeutungs-ID +Warnung [uri-not-rfc] dictionary.lift:6: : Windows-Laufwerksbuchstabe als URI-Autorität verwendet (im FLEx-Stil file://C:/) +1 Fehler, 1 Warnung + +$ sil-lift validate dictionary.lift --format json +{ + „problems“: [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' passt zu keiner Eintrags-ID/GUID oder Sinn-ID", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows-Laufwerksbuchstabe als URI-Autorität verwendet (im FLEx-Stil file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + „summary“: { + „errors“: 1, + „warnings“: 1 + } +} + +$ sil-lift stats sango.lift +Einträge: 3507 +Bedeutungen: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit-Codes: `0` erfolgreich (Warnungen zulässig, sofern nicht `--strict` angegeben), `1` Fehlermeldungen (Validierungsfehler / fehlende Medien / Warnungen bei Angabe von `--strict`), `2` unlesbare Eingabe. From 88995cae155b6fe80d7a3fe15eca2e9de1a81977 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:14 -0600 Subject: [PATCH 045/317] New translations cli.md (Japanese) [ci skip] --- docs/ja/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ja/guides/cli.md diff --git a/docs/ja/guides/cli.md b/docs/ja/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/ja/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From e5d04e05ba4e822586debc19282cfa46a6d9e874 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:16 -0600 Subject: [PATCH 046/317] New translations cli.md (Portuguese) [ci skip] --- docs/pt/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/pt/guides/cli.md diff --git a/docs/pt/guides/cli.md b/docs/pt/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/pt/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From 87ff7dbe4120e00e2124c3197502439e706b6db2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:17 -0600 Subject: [PATCH 047/317] New translations cli.md (Russian) [ci skip] --- docs/ru/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/ru/guides/cli.md diff --git a/docs/ru/guides/cli.md b/docs/ru/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/ru/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From 68fe6094dcedda0ce6c1bb268ff501e0d4150b82 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:19 -0600 Subject: [PATCH 048/317] New translations cli.md (Chinese Simplified) [ci skip] --- docs/zh/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/zh/guides/cli.md diff --git a/docs/zh/guides/cli.md b/docs/zh/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/zh/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From c3a31c413e4a55d5fb41569c588325c53d34c39a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:20 -0600 Subject: [PATCH 049/317] New translations cli.md (Hindi) [ci skip] --- docs/hi/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/hi/guides/cli.md diff --git a/docs/hi/guides/cli.md b/docs/hi/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/hi/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From f6998afdbaad2ed6acfe0223c5ee52ef536e567e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:22 -0600 Subject: [PATCH 050/317] New translations cli.md (Swahili) [ci skip] --- docs/sw/guides/cli.md | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 docs/sw/guides/cli.md diff --git a/docs/sw/guides/cli.md b/docs/sw/guides/cli.md new file mode 100644 index 0000000..3f1401e --- /dev/null +++ b/docs/sw/guides/cli.md @@ -0,0 +1,70 @@ +# The command line + +Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). + +``` +sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + all problems, entry/line-addressed; exit 1 on errors +sil-lift stats PATH [--format {text,json}] + entry/sense/language counts (streaming; any size) +sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) +sil-lift check-media PATH missing and orphaned media report; exit 1 if missing +sil-lift export PATH [-o OUT] [--langs L] [--tsv] + one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) +``` + +`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. + +!!! note + `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + +`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left +untouched (sort those separately with the `RangesFile` API). + +`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. + +Examples: + +``` +$ sil-lift validate dictionary.lift +error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id +warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) +1 error(s), 1 warning(s) + +$ sil-lift validate dictionary.lift --format json +{ + "problems": [ + { + "level": "error", + "code": "dangling-ref", + "message": "ref 'nope' matches no entry id/guid or sense id", + "file": "dictionary.lift", + "entry_id": "apu", + "guid": null, + "line": 88 + }, + { + "level": "warning", + "code": "uri-not-rfc", + "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "file": "dictionary.lift", + "entry_id": null, + "guid": null, + "line": 6 + } + ], + "summary": { + "errors": 1, + "warnings": 1 + } +} + +$ sil-lift stats sango.lift +entries: 3507 +senses: 4541 +... + +$ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv +``` + +Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. From 4d6486ef4efa49acf91467235462063f81af4940 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:23 -0600 Subject: [PATCH 051/317] New translations folder-media.md (French) [ci skip] --- docs/fr/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/fr/guides/folder-media.md diff --git a/docs/fr/guides/folder-media.md b/docs/fr/guides/folder-media.md new file mode 100644 index 0000000..f52ce4e --- /dev/null +++ b/docs/fr/guides/folder-media.md @@ -0,0 +1,41 @@ +# Le dossier LIFT : gammes et supports + +Un lexique LIFT se présente généralement sous la forme d'un _dossier_ : le fichier `.lift`, un ou plusieurs fichiers associés `.lift-ranges`, ainsi que les fichiers multimédias contenus dans les dossiers `audio/` et `pictures/`. + +## Gammes + +```python +lex = sil_lift.load("dictionary.lift") # compagnons suivis automatiquement + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # vue fusionnée {id: Range} +lex.all_ranges()["grammatical-info"].elements +``` + +La fonctionnalité « Companion Discovery » gère le monde réel : un `range/@href` pointant vers un fichier existant est utilisé ; les liens absolus « file://C:/... » orphelins de FieldWorks se rabattent sur le nom de base du lien situé à côté du fichier `.lift` ; et le fichier frère conventionnel `.lift-ranges` est pris en compte même lorsqu'aucun autre élément ne le référence. + +La fonction `lex.save()` enregistre le fichier `.lift` ainsi que tous les fichiers compagnons suivis. Les modifications apportées à un fichier `RangesFile` sont réenregistrées dans _ce_ fichier ; les plages non modifiées conservent exactement les mêmes octets. Utilisation autonome : + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Transmettez `resolve_ranges=False` à la fonction `load()` pour ignorer la recherche de composants associés. + +## Médias + +```python +for ref in lex.media_refs(): # toutes les références de type « » et « + » print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # références dont les fichiers n'existent pas +``` + +La résolution suit le schéma classique : un lien « href » relatif est vérifié tel qu'il est fourni (barres obliques inversées normalisées — WeSay écrit « pictures\photo with space.png ») et se trouve dans le répertoire « audio/ » (pour les fichiers audio de prononciation) ou « pictures/ » (pour les illustrations). Les liens « href » distants ou absolus ne peuvent pas être vérifiés et sont ignorés. + +## Autres éléments du dossier + +Un dossier LIFT contient souvent des fichiers que sil-lift ne modélise pas — le système d’écriture LDML dans `WritingSystems/`, les fichiers audio/image relatifs au consentement des locuteurs de The Combine dans `consent/`, etc. ; Les fonctions `load()` et `save()` ne les modifient pas, et [`Lexicon.save_zip()`](lift-export-interop.md) les transfère tels quels lors de la compression du dossier. From 1a58a17677912eaa344f68491ee2bcc1e0e51b4d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:24 -0600 Subject: [PATCH 052/317] New translations folder-media.md (Spanish) [ci skip] --- docs/es/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/es/guides/folder-media.md diff --git a/docs/es/guides/folder-media.md b/docs/es/guides/folder-media.md new file mode 100644 index 0000000..346867a --- /dev/null +++ b/docs/es/guides/folder-media.md @@ -0,0 +1,41 @@ +# La carpeta LIFT: gamas y soportes + +Un léxico de LIFT suele ser una _carpeta_: el archivo `.lift`, uno o varios archivos complementarios `.lift-ranges` y los archivos multimedia de las carpetas `audio/` y `pictures/`. + +## Gamas + +```python +lex = sil_lift.load("dictionary.lift") # los «companions» se registran automáticamente + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # vista fusionada {id: Range} +lex.all_ranges()["grammatical-info"].elements +``` + +La función «Companion discovery» se adapta al mundo real: se utiliza un `range/@href` que apunta a un archivo existente; los enlaces `file://C:/...` absolutos sin referencia de FieldWorks recurren al nombre base del enlace junto al `.lift`; y el elemento hermano convencional `.lift-ranges` se detecta incluso cuando nada hace referencia a él. + +`lex.save()` guarda el archivo `.lift` y todos los archivos complementarios de los que se lleva un registro. Las modificaciones realizadas en un `RangesFile` se guardan de nuevo en _su_ archivo; los rangos que no se han modificado conservan sus bytes exactos. Uso independiente: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pasa `resolve_ranges=False` a `load()` para omitir la detección de componentes complementarios. + +## Medios de comunicación + +```python +for ref in lex.media_refs(): # todos los y + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # referencias cuyos archivos no existen +``` + +La resolución sigue el esquema convencional: se comprueba un enlace «href» relativo tal y como se ha indicado (con las barras invertidas normalizadas — WeSay escribe «pictures\photo con espacio.png») y dentro de «audio/» (para archivos de audio con pronunciación) o «pictures/» (para ilustraciones). Los enlaces «href» remotos o absolutos no se pueden comprobar y se omiten. + +## Otros contenidos de la carpeta + +Una carpeta LIFT suele contener archivos que sil-lift no modela —el sistema de escritura LDML en `WritingSystems/`, los archivos de audio e imagen de consentimiento de los hablantes de The Combine en `consent/`, y similares—; Las funciones `load()` y `save()` no modifican estos archivos, y [`Lexicon.save_zip()`](lift-export-interop.md) los incluye tal cual al empaquetar la carpeta. From b4ea78b573d5d46a8582efbeb808d1d6ad1a75d1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:26 -0600 Subject: [PATCH 053/317] New translations folder-media.md (Arabic) [ci skip] --- docs/ar/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/ar/guides/folder-media.md diff --git a/docs/ar/guides/folder-media.md b/docs/ar/guides/folder-media.md new file mode 100644 index 0000000..df43a04 --- /dev/null +++ b/docs/ar/guides/folder-media.md @@ -0,0 +1,41 @@ +# مجلد LIFT: النطاقات ووسائل الإعلام + +عادةً ما يكون معجم LIFT عبارة عن _مجلد_: ملف `.lift`، وملف أو أكثر من ملفات `.lift-ranges` المصاحبة له، وملفات الوسائط الموجودة في مجلدي `audio/` و`pictures/`. + +## النطاقات + +```python +lex = sil_lift.load("dictionary.lift") # يتم تتبع المرافقات تلقائيًا + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # عرض {id: Range} المدمج +lex.all_ranges()["grammatical-info"].elements +``` + +تتعامل ميزة «Companion discovery» مع الواقع الفعلي: حيث يتم استخدام `range/@href` يشير إلى ملف موجود؛ تعود روابط href المطلقة المعلقة في FieldWorks `file://C:/...` إلى الاسم الأساسي لـ href الموجود بجوار `.lift`؛ ويتم التقاط العنصر الشقيق التقليدي `.lift-ranges` حتى في حالة عدم وجود أي مرجع له. + +تقوم الدالة `lex.save()` بكتابة ملف `.lift` وجميع الملفات المصاحبة التي يتم تتبعها معًا. يتم حفظ التعديلات التي تُجرى على ملف `RangesFile` في ملفه الخاص؛ أما النطاقات التي لم يتم التعديل عليها فتحتفظ بقيم البايتات الخاصة بها تمامًا. الاستخدام المستقل: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +قم بتمرير المعلمة `resolve_ranges=False` إلى الدالة `load()` لتخطي عملية اكتشاف المرافقات. + +## وسائل الإعلام + +```python +for ref in lex.media_refs(): # كل عنصر من نوع و + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # المراجع التي لا توجد ملفاتها +``` + +يتم تحديد المسار وفقًا للتنسيق التقليدي: يتم فحص رابط href النسبي كما هو مكتوب (مع توحيد علامات الخط المائل العكسي — حيث يكتب WeSay `pictures\photo with space.png`) وتحت مجلد `audio/` (لوسائط النطق) أو `pictures/` (للرسوم التوضيحية). لا يمكن التحقق من روابط href البعيدة/المطلقة، لذا يتم تخطيها. + +## محتويات المجلد الأخرى + +غالبًا ما يحتوي مجلد LIFT على ملفات لا يقوم sil-lift بنمذجتها — مثل نظام الكتابة LDML الموجود ضمن `WritingSystems/`، وملفات الصوت/الصور الخاصة بموافقة المتحدثين في The Combine الموجودة ضمن `consent/`، وما شابه ذلك؛ تترك الدالتان `load()` و`save()` هذه الملفات دون تغيير، بينما تقوم الدالة [`Lexicon.save_zip()`](lift-export-interop.md) بنقلها حرفياً عند حزم المجلد. From 68d980268bb17fee54ad7b9d74a5a7885d445699 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:28 -0600 Subject: [PATCH 054/317] New translations folder-media.md (German) [ci skip] --- docs/de/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/de/guides/folder-media.md diff --git a/docs/de/guides/folder-media.md b/docs/de/guides/folder-media.md new file mode 100644 index 0000000..81a80a7 --- /dev/null +++ b/docs/de/guides/folder-media.md @@ -0,0 +1,41 @@ +# Der LIFT-Ordner: Sortimente und Medien + +Ein LIFT-Lexikon besteht in der Regel aus einem _Ordner_: der `.lift`-Datei, einer oder mehreren zugehörigen `.lift-ranges`-Dateien sowie den Medien in den Ordnern `audio/` und `pictures/`. + +## Bereiche + +```python +lex = sil_lift.load("dictionary.lift") # Begleitdateien werden automatisch nachverfolgt + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # zusammengeführte {id: Range}-Ansicht +lex.all_ranges()["grammatical-info"].elements +``` + +Die Companion-Erkennung berücksichtigt die reale Welt: Es wird ein `range/@href` verwendet, das auf eine vorhandene Datei verweist; Die losen absoluten `file://C:/...`-href-Angaben von FieldWorks greifen auf den Basisnamen des href neben der `.lift`-Datei zurück; und das herkömmliche Geschwisterelement `.lift-ranges` wird auch dann erkannt, wenn nichts darauf verweist. + +`lex.save()` schreibt die `.lift`-Datei und alle nachverfolgten Companion-Dateien gemeinsam. Änderungen an einer `RangesFile` werden wieder in _diese_ Datei gespeichert; unveränderte Bereiche behalten ihre genauen Byte-Werte bei. Einzelbetrieb: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Übergeben Sie `resolve_ranges=False` an `load()`, um die Erkennung von Begleitkomponenten zu überspringen. + +## Medien + +```python +for ref in lex.media_refs(): # alle und + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # Verweise, deren Dateien nicht vorhanden sind +``` + +Die Auflösung erfolgt nach dem üblichen Schema: Ein relativer href-Link wird unverändert geprüft (Backslashes werden normalisiert – WeSay schreibt „pictures\photo with space.png“) und unter „audio/“ (für Aussprachedateien) oder „pictures/“ (für Abbildungen) gesucht. Externe/absolute „hrefs“ können nicht überprüft werden und werden übersprungen. + +## Sonstige Ordnerinhalte + +Ein LIFT-Ordner enthält oft Dateien, die sil-lift nicht modelliert – beispielsweise das Schriftsystem LDML unter `WritingSystems/`, die Audio- und Bilddateien zur Einwilligung der Sprecher von „The Combine“ unter `consent/` und Ähnliches; `load()`/`save()` lassen diese unberührt, und [`Lexicon.save_zip()`](lift-export-interop.md) übernimmt sie beim Verpacken des Ordners unverändert. From 382f35e1d01ea6d16348bc4ca1e7139ad9c8e3e1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:29 -0600 Subject: [PATCH 055/317] New translations folder-media.md (Japanese) [ci skip] --- docs/ja/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/ja/guides/folder-media.md diff --git a/docs/ja/guides/folder-media.md b/docs/ja/guides/folder-media.md new file mode 100644 index 0000000..227cc62 --- /dev/null +++ b/docs/ja/guides/folder-media.md @@ -0,0 +1,41 @@ +# 「LIFT」フォルダ:範囲とメディア + +LIFTのレキシコンは通常、_フォルダ_として構成されます。その中には、`.lift`ファイル、1つ以上の`.lift-ranges`ファイル、および`audio/` / `pictures/`フォルダ内のメディアファイルが含まれます。 + +## 範囲 + +```python +lex = sil_lift.load("dictionary.lift") # コンパニオンは自動的に追跡される + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # マージされた {id: Range} ビュー +lex.all_ranges()["grammatical-info"].elements +``` + +コンパニオンディスカバリーは実世界の状況を適切に処理します。既存のファイルを指す `range/@href` が使用されます。 FieldWorksの未参照の絶対パス `file://C:/...` のhrefは、`.lift`の隣にあるhrefのベース名にフォールバックします。また、従来の `.lift-ranges` という同階層のファイルは、参照元がなくても自動的に検出されます。 + +`lex.save()` は、`.lift` と追跡対象のすべてのコンパニオンをまとめて書き込みます。 `RangesFile` への編集内容は、そのファイルに保存されます。変更されていない範囲については、バイト単位でそのまま保持されます。 単体での使用: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +`load()` に `resolve_ranges=False` を渡すと、コンパニオンの検出をスキップできます。 + +## メディア + +```python +for ref in lex.media_refs(): # すべての および + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # ファイルが存在しない参照 +``` + +解決方法は従来のレイアウトに従います。相対的な href は指定されたままの形式でチェックされ(バックスラッシュは正規化されます — WeSay は `pictures\photo with space.png` と記述します)、`audio/`(発音用メディアの場合)または `pictures/`(イラストの場合)の下に配置されます。 リモートまたは絶対パスの href は検証できないため、スキップされます。 + +## その他のフォルダ内の内容 + +LIFTフォルダには、sil-liftがモデル化していないファイルがしばしば格納されています。たとえば、`WritingSystems/` にある文字体系の LDML ファイルや、`consent/` にある The Combine の話者同意に関する音声・画像ファイルなどです。 `load()`/`save()`はこれらをそのままにしておき、[`Lexicon.save_zip()`](lift-export-interop.md)はフォルダをパッケージ化する際、これらをそのまま引き継ぎます。 From 21facc4f0536198bd02e7e5fffb161e50145e79c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:30 -0600 Subject: [PATCH 056/317] New translations folder-media.md (Portuguese) [ci skip] --- docs/pt/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/pt/guides/folder-media.md diff --git a/docs/pt/guides/folder-media.md b/docs/pt/guides/folder-media.md new file mode 100644 index 0000000..03355ec --- /dev/null +++ b/docs/pt/guides/folder-media.md @@ -0,0 +1,41 @@ +# The LIFT folder: ranges and media + +A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. + +## Ranges + +```python +lex = sil_lift.load("dictionary.lift") # companions tracked automatically + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # merged {id: Range} view +lex.all_ranges()["grammatical-info"].elements +``` + +Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. + +`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pass `resolve_ranges=False` to `load()` to skip companion discovery. + +## Media + +```python +for ref in lex.media_refs(): # every and + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # refs whose files don't exist +``` + +Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. + +## Other folder contents + +A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. From 63a5df14d8d8538a1269252d0238e95250f8b49c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:32 -0600 Subject: [PATCH 057/317] New translations folder-media.md (Russian) [ci skip] --- docs/ru/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/ru/guides/folder-media.md diff --git a/docs/ru/guides/folder-media.md b/docs/ru/guides/folder-media.md new file mode 100644 index 0000000..03355ec --- /dev/null +++ b/docs/ru/guides/folder-media.md @@ -0,0 +1,41 @@ +# The LIFT folder: ranges and media + +A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. + +## Ranges + +```python +lex = sil_lift.load("dictionary.lift") # companions tracked automatically + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # merged {id: Range} view +lex.all_ranges()["grammatical-info"].elements +``` + +Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. + +`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pass `resolve_ranges=False` to `load()` to skip companion discovery. + +## Media + +```python +for ref in lex.media_refs(): # every and + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # refs whose files don't exist +``` + +Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. + +## Other folder contents + +A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. From 4d38da6d4da9abb01c327d7ca0da4b09beb57636 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:33 -0600 Subject: [PATCH 058/317] New translations folder-media.md (Chinese Simplified) [ci skip] --- docs/zh/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/zh/guides/folder-media.md diff --git a/docs/zh/guides/folder-media.md b/docs/zh/guides/folder-media.md new file mode 100644 index 0000000..03355ec --- /dev/null +++ b/docs/zh/guides/folder-media.md @@ -0,0 +1,41 @@ +# The LIFT folder: ranges and media + +A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. + +## Ranges + +```python +lex = sil_lift.load("dictionary.lift") # companions tracked automatically + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # merged {id: Range} view +lex.all_ranges()["grammatical-info"].elements +``` + +Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. + +`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pass `resolve_ranges=False` to `load()` to skip companion discovery. + +## Media + +```python +for ref in lex.media_refs(): # every and + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # refs whose files don't exist +``` + +Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. + +## Other folder contents + +A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. From 883b19bb867a2d58c69024e7cf517a5abfed201f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:35 -0600 Subject: [PATCH 059/317] New translations folder-media.md (Hindi) [ci skip] --- docs/hi/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/hi/guides/folder-media.md diff --git a/docs/hi/guides/folder-media.md b/docs/hi/guides/folder-media.md new file mode 100644 index 0000000..03355ec --- /dev/null +++ b/docs/hi/guides/folder-media.md @@ -0,0 +1,41 @@ +# The LIFT folder: ranges and media + +A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. + +## Ranges + +```python +lex = sil_lift.load("dictionary.lift") # companions tracked automatically + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # merged {id: Range} view +lex.all_ranges()["grammatical-info"].elements +``` + +Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. + +`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pass `resolve_ranges=False` to `load()` to skip companion discovery. + +## Media + +```python +for ref in lex.media_refs(): # every and + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # refs whose files don't exist +``` + +Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. + +## Other folder contents + +A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. From f953fa747fde5a331ed82587f7cde98db8a29f36 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:37 -0600 Subject: [PATCH 060/317] New translations folder-media.md (Swahili) [ci skip] --- docs/sw/guides/folder-media.md | 41 ++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/sw/guides/folder-media.md diff --git a/docs/sw/guides/folder-media.md b/docs/sw/guides/folder-media.md new file mode 100644 index 0000000..03355ec --- /dev/null +++ b/docs/sw/guides/folder-media.md @@ -0,0 +1,41 @@ +# The LIFT folder: ranges and media + +A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. + +## Ranges + +```python +lex = sil_lift.load("dictionary.lift") # companions tracked automatically + +lex.ranges_files # {Path(...): RangesFile} +lex.all_ranges() # merged {id: Range} view +lex.all_ranges()["grammatical-info"].elements +``` + +Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. + +`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: + +```python +ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") +ranges.find("grammatical-info") +ranges.sort() +ranges.save() +``` + +Pass `resolve_ranges=False` to `load()` to skip companion discovery. + +## Media + +```python +for ref in lex.media_refs(): # every and + print(ref.kind, ref.href, ref.entry_id) + +lex.missing_media() # refs whose files don't exist +``` + +Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. + +## Other folder contents + +A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. From 648406d635ee77497410ddf756a7d20b87982456 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:38 -0600 Subject: [PATCH 061/317] New translations large-files.md (French) [ci skip] --- docs/fr/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/fr/guides/large-files.md diff --git a/docs/fr/guides/large-files.md b/docs/fr/guides/large-files.md new file mode 100644 index 0000000..858fd21 --- /dev/null +++ b/docs/fr/guides/large-files.md @@ -0,0 +1,27 @@ +# Fichiers volumineux (diffusion en continu) + +La fonction `load()` construit l'ensemble du graphe d'objets. Pour les lexiques de plusieurs centaines de Mo, l'API de traitement en continu traite les entrées une par une dans une mémoire limitée — il s'agit du même type `Entry` ; ainsi, le code écrit pour un mode fonctionne également dans l'autre. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # analysé au début (précède les entrées) + for entry in reader: # itérateur paresseux de type Iterator[Entry] + ... +``` + +```python +avec sil_lift.open_reader("big.lift") en tant que lecteur, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) en tant qu'écrivain : + pour chaque entrée dans le lecteur : + if not entry.date_deleted: # par ex. supprimer les entrées obsolètes + writer.write(entry) +``` + +Remarques : + +- Le résultat généré par l'éditeur correspond exactement à ce que produirait le sérialiseur canonique « plein document » pour le même contenu — les deux modes ne divergent jamais. +- Le mode streaming ne comporte pas de couche de transfert d'octets : la sortie est toujours canonique. Les résidus de niveau racine — commentaires entre les entrées et attributs hors schéma sur `` — ne sont pas transférés ; les entrées et l'en-tête sont complets, résidus compris. +- Si une exception est levée dans le corps d'un bloc `open_writer`, le fichier reste visiblement inachevé (pas de commande de fermeture ``) — un lexique à moitié écrit ne doit pas donner l'impression d'être complet. From ba4f0892d028c00eb71b03719a2d0b4814fcd1a5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:39 -0600 Subject: [PATCH 062/317] New translations large-files.md (Spanish) [ci skip] --- docs/es/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/es/guides/large-files.md diff --git a/docs/es/guides/large-files.md b/docs/es/guides/large-files.md new file mode 100644 index 0000000..ac3d199 --- /dev/null +++ b/docs/es/guides/large-files.md @@ -0,0 +1,27 @@ +# Archivos de gran tamaño (reproducción en streaming) + +`load()` construye todo el grafo de objetos. En el caso de léxicos de varios cientos de MB, la API de streaming procesa una entrada cada vez en una memoria limitada —el mismo tipo `Entry`—, por lo que el código escrito para un modo funciona también en el otro. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # analizado al principio (precede a las entradas) + for entry in reader: # iterador perezoso [Entry] + ... +``` + +```python +con sil_lift.open_reader("big.lift") como reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) como writer: + for entry in reader: + if not entry.date_deleted: # p. ej., eliminar entradas obsoleta + writer.write(entry) +``` + +Notas: + +- El resultado del escritor es exactamente el mismo que produciría el serializador canónico de documento completo para el mismo contenido; los dos modos nunca se desvían entre sí. +- El modo de transmisión en continuo no cuenta con una capa de paso directo de bytes: la salida es siempre canónica. Los residuos de nivel raíz —comentarios entre entradas y atributos fuera del esquema en ``— no se transfieren; las entradas y el encabezado están completos, incluidos los residuos. +- Si se produce un error en el cuerpo de un bloque `open_writer`, el archivo queda visiblemente sin terminar (sin el cierre ``); un léxico a medio escribir no debe parecer completo. From d9dd4b3bbe329de8ad1f3e75ff10709bcc3d3edc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:41 -0600 Subject: [PATCH 063/317] New translations large-files.md (Arabic) [ci skip] --- docs/ar/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/ar/guides/large-files.md diff --git a/docs/ar/guides/large-files.md b/docs/ar/guides/large-files.md new file mode 100644 index 0000000..cf5dcd1 --- /dev/null +++ b/docs/ar/guides/large-files.md @@ -0,0 +1,27 @@ +# الملفات الكبيرة (البث المباشر) + +تقوم دالة `load()` بإنشاء مخطط الكائنات بالكامل. بالنسبة للمعاجم التي يتجاوز حجمها عدة مئات من الميغابايت، تعالج واجهة برمجة التطبيقات (API) الخاصة بالبث مدخلاً واحداً في كل مرة ضمن ذاكرة محدودة — وهو من نفس نوع `Entry`، لذا فإن الكود المكتوب لوضع معين يعمل في الوضع الآخر. + +```python +استيراد sil_lift + +مع sil_lift.open_reader("big.lift") كـ reader: + header = reader.header # تم تحليلها مسبقًا (تسبق السجلات) + لكل سجل في reader: # متكرر كسول من نوع Iterator[Entry] + ... +``` + +```python +باستخدام sil_lift.open_reader("big.lift") كقارئ، و sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) ككاتب: + لكل إدخال في القارئ: + if not entry.date_deleted: # على سبيل المثال، حذف السجلات القديمة + writer.write(entry) +``` + +ملاحظات: + +- ما ينتجه الكاتب هو بالضبط ما سينتج عنه مُسلسل النص القياسي الكامل لنفس المحتوى — ولا يحدث أي تباين بين الوضعين أبدًا. +- لا يحتوي وضع البث على طبقة تمرير البايتات: يكون الإخراج دائمًا في صيغته القياسية. لا يتم نقل «البقايا على مستوى الجذر» — وهي التعليقات الموجودة بين البنود والسمات الخارجة عن المخطط في `` —؛ حيث تكون البنود والرأس كاملة، بما في ذلك البقايا. +- إذا حدث استثناء داخل كتلة `open_writer`، يُترك الملف في حالة غير مكتملة بشكل واضح (بدون `` ختامي) — فلا يجب أن يبدو المعجم الذي لم يكتمل كتابته بعد وكأنه مكتمل. From 4c752e57f4f625f33d49c8b873de1e2da2b83c67 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:43 -0600 Subject: [PATCH 064/317] New translations large-files.md (German) [ci skip] --- docs/de/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/de/guides/large-files.md diff --git a/docs/de/guides/large-files.md b/docs/de/guides/large-files.md new file mode 100644 index 0000000..23df7ee --- /dev/null +++ b/docs/de/guides/large-files.md @@ -0,0 +1,27 @@ +# Große Dateien (Streaming) + +`load()` baut den gesamten Objektgraphen auf. Bei Lexika mit einer Größe von mehreren hundert MB verarbeitet die Streaming-API jeweils einen Eintrag nach dem anderen in einem begrenzten Speicherbereich – dabei handelt es sich um denselben `Entry`-Typ, sodass Code, der für einen Modus geschrieben wurde, auch im anderen Modus funktioniert. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # wird vorab geparst (steht vor den Einträgen) + for entry in reader: # verzögerter Iterator[Entry] + ... +``` + +```python +mit sil_lift.open_reader("big.lift") als reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) als writer: + for entry in reader: + if not entry.date_deleted: # z. B. Tombstones entfernen + writer.write(entry) +``` + +Anmerkungen: + +- Die Ausgabe des Writers entspricht genau dem, was der kanonische Serializer für das gesamte Dokument bei denselben Inhalten erzeugen würde – die beiden Modi weichen nie voneinander ab. +- Der Streaming-Modus verfügt über keine Byte-Passthrough-Schicht: Die Ausgabe erfolgt immer im kanonischen Format. Reste auf der obersten Ebene – Kommentare zwischen Einträgen und schemenfremde Attribute unter `` – werden nicht übertragen; Einträge und der Header sind vollständig, einschließlich der Reste. +- Wenn im Hauptteil eines `open_writer`-Blocks ein Fehler ausgelöst wird, bleibt die Datei sichtbar unvollständig (kein abschließendes ``) – ein nur zur Hälfte geschriebenes Lexikon darf nicht vollständig erscheinen. From 984a12f9e19b8c459d301dba36ef3397ecf59a68 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:44 -0600 Subject: [PATCH 065/317] New translations large-files.md (Japanese) [ci skip] --- docs/ja/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/ja/guides/large-files.md diff --git a/docs/ja/guides/large-files.md b/docs/ja/guides/large-files.md new file mode 100644 index 0000000..3fa8c12 --- /dev/null +++ b/docs/ja/guides/large-files.md @@ -0,0 +1,27 @@ +# 大容量ファイル(ストリーミング) + +`load()` はオブジェクトグラフ全体を構築します。 数百MB規模の辞書の場合、ストリーミングAPIは、制限されたメモリ内で1回に1つのエントリを処理します。エントリの型は同じ`Entry`であるため、一方のモード向けに記述されたコードは、もう一方のモードでも動作します。 + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # 最初に解析される(エントリより先) + for entry in reader: # 遅延評価される Iterator[Entry] + ... +``` + +```python +with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) as writer: + for entry in reader: + if not entry.date_deleted: # 例:トゥームストーンを削除 + writer.write(entry) +``` + +注記: + +- このライタの出力は、同じコンテンツに対してフルドキュメントの正規シリアライザが生成するものと完全に一致します。この2つのモードの間で結果にずれが生じることはありません。 +- ストリーミングモードにはバイトパススルー層が存在しないため、出力は常に正規化された形式となる。 ルートレベルの残余(エントリ間のコメントや、`` 上のスキーマ外属性)は転送されません。エントリとヘッダーは、残余を含めて完全な状態で転送されます。 +- `open_writer` ブロックの本体で例外が発生した場合、ファイルは明らかに未完了の状態(`` による閉じ処理が行われていない)のまま残されます。つまり、書きかけの辞書は完了しているように見えてはなりません。 From 8820db6a10e916a3b9239dc8ef0251906e4488d3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:46 -0600 Subject: [PATCH 066/317] New translations large-files.md (Portuguese) [ci skip] --- docs/pt/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/pt/guides/large-files.md diff --git a/docs/pt/guides/large-files.md b/docs/pt/guides/large-files.md new file mode 100644 index 0000000..00c271b --- /dev/null +++ b/docs/pt/guides/large-files.md @@ -0,0 +1,27 @@ +# Ficheiros de grande dimensão (transmissão em fluxo) + +A função `load()` constrói todo o grafo de objetos. No caso de léxicos com várias centenas de MB, a API de streaming processa uma entrada de cada vez numa memória limitada — o mesmo tipo `Entry`, pelo que o código escrito para um dos modos funciona também no outro. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # analisado antecipadamente (precede as entradas) + for entry in reader: # Iterador preguiçoso [Entry] + ... +``` + +```python +com sil_lift.open_reader("big.lift") como reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) como writer: + para cada entry em reader: + if not entry.date_deleted: # por exemplo, eliminar registos obsoletos + writer.write(entry) +``` + +Notas: + +- O resultado gerado pelo escritor é exatamente o que o serializador canónico de documento completo produziria para o mesmo conteúdo — os dois modos nunca divergem. +- O modo de streaming não possui uma camada de passagem direta de bytes: a saída é sempre canónica. Os resíduos ao nível da raiz — comentários entre entradas e atributos fora do esquema em `` — não são transportados; as entradas e o cabeçalho estão completos, incluindo os resíduos. +- Se ocorrer uma exceção no corpo de um bloco `open_writer`, o ficheiro fica visivelmente incompleto (sem o comando de fecho ``) — um léxico parcialmente escrito não deve parecer completo. From 9df5445d456658ff9fe2d336da439ed0865359cb Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:47 -0600 Subject: [PATCH 067/317] New translations large-files.md (Russian) [ci skip] --- docs/ru/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/ru/guides/large-files.md diff --git a/docs/ru/guides/large-files.md b/docs/ru/guides/large-files.md new file mode 100644 index 0000000..32f0881 --- /dev/null +++ b/docs/ru/guides/large-files.md @@ -0,0 +1,27 @@ +# Large files (streaming) + +`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # parsed up front (precedes entries) + for entry in reader: # lazy Iterator[Entry] + ... +``` + +```python +with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) as writer: + for entry in reader: + if not entry.date_deleted: # e.g. drop tombstones + writer.write(entry) +``` + +Notes: + +- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. +- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. +- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. From 241a395ec1b3669cbf75fb91a4535a7dae3fbeae Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:49 -0600 Subject: [PATCH 068/317] New translations large-files.md (Chinese Simplified) [ci skip] --- docs/zh/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/zh/guides/large-files.md diff --git a/docs/zh/guides/large-files.md b/docs/zh/guides/large-files.md new file mode 100644 index 0000000..32f0881 --- /dev/null +++ b/docs/zh/guides/large-files.md @@ -0,0 +1,27 @@ +# Large files (streaming) + +`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # parsed up front (precedes entries) + for entry in reader: # lazy Iterator[Entry] + ... +``` + +```python +with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) as writer: + for entry in reader: + if not entry.date_deleted: # e.g. drop tombstones + writer.write(entry) +``` + +Notes: + +- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. +- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. +- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. From f0910ab2e49ca791ce28ac73d2a59f8b45e0eff4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:50 -0600 Subject: [PATCH 069/317] New translations large-files.md (Hindi) [ci skip] --- docs/hi/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/hi/guides/large-files.md diff --git a/docs/hi/guides/large-files.md b/docs/hi/guides/large-files.md new file mode 100644 index 0000000..32f0881 --- /dev/null +++ b/docs/hi/guides/large-files.md @@ -0,0 +1,27 @@ +# Large files (streaming) + +`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # parsed up front (precedes entries) + for entry in reader: # lazy Iterator[Entry] + ... +``` + +```python +with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) as writer: + for entry in reader: + if not entry.date_deleted: # e.g. drop tombstones + writer.write(entry) +``` + +Notes: + +- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. +- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. +- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. From b82416638a4ac0e6d07efc5eb98f4ad15677b445 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:52 -0600 Subject: [PATCH 070/317] New translations large-files.md (Swahili) [ci skip] --- docs/sw/guides/large-files.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 docs/sw/guides/large-files.md diff --git a/docs/sw/guides/large-files.md b/docs/sw/guides/large-files.md new file mode 100644 index 0000000..32f0881 --- /dev/null +++ b/docs/sw/guides/large-files.md @@ -0,0 +1,27 @@ +# Large files (streaming) + +`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. + +```python +import sil_lift + +with sil_lift.open_reader("big.lift") as reader: + header = reader.header # parsed up front (precedes entries) + for entry in reader: # lazy Iterator[Entry] + ... +``` + +```python +with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( + "out.lift", header=reader.header, producer="my-script" +) as writer: + for entry in reader: + if not entry.date_deleted: # e.g. drop tombstones + writer.write(entry) +``` + +Notes: + +- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. +- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. +- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. From cd0228b0f6b02a59504f62af85724dce733bb149 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:53 -0600 Subject: [PATCH 071/317] New translations lift-export-interop.md (French) [ci skip] --- docs/fr/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/fr/guides/lift-export-interop.md diff --git a/docs/fr/guides/lift-export-interop.md b/docs/fr/guides/lift-export-interop.md new file mode 100644 index 0000000..ccfea47 --- /dev/null +++ b/docs/fr/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Création d'un fichier LIFT conforme + +Ce guide s'adresse à toute personne développant un _exportateur_ LIFT — c'est-à-dire un programme, quel que soit le langage utilisé, qui convertit le modèle de données d'une autre application au format LIFT 0.13. « sil-lift » remplit deux fonctions dans ce contexte : d'une part, il sert de filtre de conformité qui vérifie que la sortie respecte le schéma ainsi que les aspects sémantiques que ce dernier ne peut pas exprimer ; d'autre part, il sert de référence pour les formes et les règles de mise en forme du texte que la sortie doit respecter. + +Écrire du code LIFT est bien plus simple que de l'analyser : un exportateur ne génère que le sous-ensemble de constructions produit par son propre modèle, et n'est jamais confronté à l'ensemble des options prévues par la spécification complète. Le plus difficile, ce sont les détails — le compagnon `.lift-ranges`, le texte propre à chaque système d'écriture, les identifiants stables et l'échappement XML — et c'est précisément ce que détectent les vérifications ci-dessous. + +## Fichiers compressés + +LIFT est généralement transféré sous la forme d'un seul fichier `.zip` — FieldWorks et The Combine importent et exportent tous deux de cette manière — ; ainsi, `sil-lift` lit et écrit directement les paquets compressés, quelle que soit la structure utilisée par l'écosystème : les fichiers à la racine de l'archive ou imbriqués dans un dossier de premier niveau. + +- **À noter :** la commande `sil_lift.load("package.zip")` extrait le contenu dans un répertoire temporaire, localise le fichier `.lift` unique et le charge (les fichiers associés et les médias sont traités comme d'habitude). Les commandes CLI `validate`, `stats`, `check-media` et `export` acceptent également un chemin d'accès à un fichier `.zip` ; ainsi, le script ci-dessous s'exécute directement sur un paquet tel quel. La fonction d'extraction est protégée contre les fichiers malveillants : les éléments impliquant un parcours de chemin sont refusés, et le nombre d'entrées ainsi que la taille totale non compressée (10 GiB) sont plafonnés afin d'empêcher les « bombes ZIP ». +- **Écrivez :** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` regroupe le fichier `.lift`, ses fichiers `.lift-ranges` et tous les autres fichiers du dossier source (media, `WritingSystems/`, `consent/`, …) dans un fichier zip. `wrap_folder` utilise par défaut un dossier de niveau supérieur portant le nom du fichier zip (conformément à la convention d'importation de FieldWorks/Combine) ; passez `False` pour obtenir une archive plate. + +Les fichiers `.lift` et `.lift-ranges` conservent leur fidélité au niveau de l'octet au sein du paquet ; le conteneur zip lui-même n'est pas reproductible au niveau de l'octet. + +## Valider la sortie en tant que critère de conformité + +Passez `sil-lift validate` sur le fichier `.lift` généré. Il exécute RELAX NG (à la fois sur le fichier `.lift` et son fichier associé `.lift-ranges`) et effectue des vérifications sémantiques que la grammaire ne peut pas exprimer : références `relation`/`variant` orphelines, GUID en double, intégrité du parent des éléments de plage, valeurs de traits et d’informations grammaticales non définies dans leur plage, et références `range/@href` d’en-tête qui ne renvoient à aucun élément associé. + +Pour le CI, signaler tout échec et générer des résultats lisibles par machine : + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- L'option `--strict` fait en sorte que les avertissements (et pas seulement les erreurs) entraînent l'échec de l'exécution. +- L'option `--no-check-media` permet d'ignorer la vérification de la présence des médias dans le système de fichiers, dont les résultats indiquant « `missing-media` » constituent un faux positif lorsque les fichiers audio/photo ne se trouvent pas dans le même répertoire que le fichier `.lift` dans l'environnement de CI. +- L'option `--format json` affiche un seul objet JSON (`{"problems": [...], "summary": {...}}`) au lieu d'un texte lisible par l'utilisateur ; ses codes de sortie et son schéma constituent une interface prise en charge et conforme à SemVer (voir [le guide de la ligne de commande](cli.md)). +- `--require-ids` génère également des erreurs lorsque des entrées ne comportent pas de `guid` ou détecte l'absence d'un `id` — ce qui s'avère utile lorsqu'une réimportation ultérieure doit mettre à jour les données existantes plutôt que de les dupliquer. + +Prévenez les pertes de données silencieuses (le type de défaillance qui entraîne des pertes lors d'une exportation CSV au format plat) en vérifiant les comptages à l'aide de la commande `stats --format json` sur votre modèle source : + +``` +sil-lift stats export.lift --format json +``` + +Il fournit le nombre d'« entrées », de « sens », d'« exemples », de « références multimédias », de « langues » et de « traits » par nom. + +### Exécuter le gate sans la chaîne d'outils Python + +Dans un projet TypeScript ou C#, l'environnement de CI peut effectuer la même vérification sans installer Python, grâce à l'action GitHub intégrée : + +```yaml +- uses : sillsdev/python-sil-lift@v0.1.0 + with : + path : export.lift + strict : "true" + no-check-media : "true" + format : json +``` + +ou l'image du conteneur, générée à partir du fichier `Dockerfile` du dépôt : + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## Le compagnon `.lift-ranges` + +Les vocabulaires contrôlés — catégories grammaticales, domaines sémantiques et tout autre ensemble de valeurs associées à des caractéristiques — sont stockés dans un fichier `.lift-ranges` associé, référencé depuis le fichier `
` : + +```xml +
+ + + + +
+``` + +Le guide contient la définition complète de chaque gamme. Les valeurs sont des `` ; `parent` établit une hiérarchie ; `label` / `abbrev` / `description` sont des textes multiples : + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +Une entrée fait alors référence à une valeur par son identifiant : la catégorie grammaticale d'un sens est ``, et un domaine sémantique est ``. La commande `sil-lift validate` génère un avertissement (`undefined-range-value`) lorsqu'une valeur n'est pas définie dans son intervalle et une erreur (`range-parent`) lorsqu'un `parent` n'est pas un identifiant de frère — veillez donc à définir les intervalles réellement utilisés par vos données. Voir également [Gammes et supports](folder-media.md). + +Si vous créez l'exportation en Python, les méthodes `Lexicon.add_ranges_file()`, `RangesFile.add_range()` et `Range.add_element()` génèrent le fichier associé et ajoutent les références d'en-tête à votre place ; `open_writer(..., ranges=...)` effectue la même opération sur le chemin de streaming. + +## Texte et textes multiples + +Chaque chaîne de caractères en langue humaine dans LIFT est un _multitext_ : un `
` par système d'écriture, chacun contenant un `` : + +```xml + + kanga +
poulet
+
+``` + +Un modèle qui indexe les chaînes de caractères par code de langue (un `MultiString`, un `Record`, un `dict[str, str]`) s'adapte parfaitement à cette correspondance biunivoque : chaque entrée par clé correspond à un `
`. Un seul formulaire par langue est autorisé dans un même multitext — sinon, `sil-lift` affiche un avertissement `duplicate-form-lang`. + +L'échappement XML est le seul aspect qui nécessite une grande rigueur. Dans le texte d'un élément, les caractères `&`, `<`, and `>` doivent être échappés (`&`, `<`, `>`) ; dans les valeurs d'attribut, le caractère de guillemet doit également être échappé. Le programme « sil-lift » applique exactement ces règles et ne modifie jamais les espaces à l'intérieur de `` — il n'y ajoute aucune indentation, car cela altérerait les données lexicales. Si vous souhaitez obtenir le même résultat, réutilisez l'échappement d'un véritable sérialiseur XML (et non un remplacement fait maison qui oublie le caractère `&`) et conservez le contenu de `` octet par octet, tel qu'il apparaît dans votre source. From 9277b75a442fae3a16d0edaf0cc644cf325204cf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:55 -0600 Subject: [PATCH 072/317] New translations lift-export-interop.md (Spanish) [ci skip] --- docs/es/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/es/guides/lift-export-interop.md diff --git a/docs/es/guides/lift-export-interop.md b/docs/es/guides/lift-export-interop.md new file mode 100644 index 0000000..bcc351a --- /dev/null +++ b/docs/es/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Creación de un LIFT conforme + +Esta guía está dirigida a cualquier persona que esté desarrollando un _exportador_ de LIFT, es decir, código en cualquier lenguaje de programación que convierta el modelo de datos de otra aplicación al formato LIFT 0.13. `sil-lift` desempeña dos funciones en ese trabajo: por un lado, actúa como filtro de conformidad que comprueba que la salida se ajuste al esquema y a la semántica que este no puede expresar; y, por otro, sirve de referencia para las formas y las reglas de texto que debe respetar la salida. + +Escribir en LIFT es mucho más fácil que analizarlo sintácticamente: un exportador solo genera el subconjunto de construcciones que produce su propio modelo y nunca tiene que lidiar con todas las opciones de la especificación completa. Lo complicado son los detalles —el complemento `.lift-ranges`, el texto específico para cada sistema de escritura, los identificadores estables y el escape de XML— y eso es precisamente lo que detectan las comprobaciones que se indican a continuación. + +## Paquetes comprimidos + +LIFT suele transportarse como un único archivo `.zip` —tanto FieldWorks como The Combine importan y exportan de esa forma—, por lo que `sil-lift` lee y escribe paquetes comprimidos directamente, independientemente de la estructura que utilice el ecosistema: ya sea con los archivos en la raíz del archivo comprimido o anidados dentro de una carpeta de nivel superior. + +- **Nota:** `sil_lift.load("package.zip")` descomprime el archivo en un directorio temporal, localiza el único archivo `.lift` y lo carga (los archivos complementarios y multimedia se resuelven como de costumbre). Los comandos de la CLI `validate`, `stats`, `check-media` y `export` también admiten una ruta `.zip`, por lo que el proceso que se muestra a continuación se ejecuta sobre un paquete tal cual. La extracción está protegida contra archivos maliciosos: se rechazan los elementos que permiten el recorrido de rutas, y se limitan el número de entradas y el tamaño total sin comprimir (10 GiB) para evitar las «bombas ZIP». +- **Escribe:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` empaqueta el archivo `.lift`, sus archivos `.lift-ranges` y todos los demás archivos de la carpeta de origen (archivos multimedia, `WritingSystems/`, `consent/`, ...) en un archivo zip. `wrap_folder` toma por defecto una carpeta de nivel superior cuyo nombre coincide con el del archivo zip (según la convención de importación de FieldWorks/Combine); pasa `False` para obtener un archivo comprimido sin subcarpetas. + +Los archivos `.lift` y `.lift-ranges` conservan su fidelidad a nivel de byte dentro del paquete; el propio contenedor zip no es reproducible a nivel de byte. + +## Validar el resultado como criterio de conformidad + +Dirige el comando «sil-lift validate» al archivo «.lift» generado. Ejecuta RELAX NG (tanto sobre el `.lift` como sobre su complemento `.lift-ranges`) y realiza comprobaciones semánticas que la gramática no puede expresar: referencias sueltas a `relation`/`variant`, GUID duplicados, integridad del elemento padre del rango, valores de rasgos e información gramatical no definidos en su rango, y referencias del encabezado `range/@href` que no se resuelven en ningún complemento. + +En el caso de la CI, si se produce un error en cualquier paso, se deben generar resultados legibles por máquina: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- La opción `--strict` hace que las advertencias (y no solo los errores) provoquen el fallo de la ejecución. +- `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos, cuyos resultados de `missing-media` son irrelevantes cuando los archivos de audio o fotos no se encuentran en la misma ubicación que el archivo `.lift` en la integración continua (CI). +- `--format json` muestra un único objeto JSON (`{"problems": [...], "summary": {...}}`) en lugar de texto legible para el usuario; sus códigos de salida y su esquema constituyen una interfaz compatible y sujeta a SemVer (véase [la guía de la línea de comandos](cli.md)). +- `--require-ids` genera además un error si hay entradas a las que les falte un `guid` o detecta que faltan `id`s; esto resulta útil cuando, en una reimportación posterior, es necesario actualizar los datos en lugar de duplicarlos. + +Evita la pérdida silenciosa de datos (el modo de fallo que hace que la exportación a CSV plano conlleve pérdidas) comprobando los recuentos con `stats --format json` en tu modelo de origen: + +``` +sil-lift stats export.lift --format json +``` + +Muestra los recuentos de «entradas», «significados», «ejemplos», «referencias multimedia», «idiomas» y «características» por nombre. + +### Ejecutar Gate sin el entorno de desarrollo de Python + +La integración continua (CI) de un proyecto de TypeScript o C# puede ejecutar la misma comprobación sin necesidad de instalar Python, mediante la acción de GitHub incluida: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +o la imagen del contenedor, creada a partir del `Dockerfile` del repositorio: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## El complemento `.lift-ranges` + +Los vocabularios controlados —partes del discurso, dominios semánticos y cualquier otro conjunto de valores basados en rasgos— se encuentran en un archivo `.lift-ranges` asociado, al que se hace referencia desde el archivo `
`: + +```xml +
+ + + + +
+``` + +La guía incluye la descripción completa de cada gama. Los valores son « »; «parent» establece una jerarquía; «label», «abbrev» y «description» son textos múltiples: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +A continuación, una entrada hace referencia a un valor mediante su identificador: la categoría gramatical de un sentido es ``, y un dominio semántico es ``. `sil-lift validate` muestra una advertencia (`undefined-range-value`) cuando un valor no está definido en su rango y genera un error (`range-parent`) cuando un `parent` no es un identificador de elemento hermano; por lo tanto, indica los rangos que tus datos utilizan realmente. Véase también [Rangos y medios](folder-media.md). + +Si creas la exportación en Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()` y `Range.add_element()` construyen el archivo complementario y añaden las referencias de encabezado por ti; `open_writer(..., ranges=...)` hace lo mismo en la ruta de transmisión. + +## Texto y multitexto + +Cada cadena de lenguaje humano en LIFT es un _multitexto_: un `
` por sistema de escritura, cada uno de los cuales envuelve un ``: + +```xml + + kanga +
gallina
+
+``` + +Un modelo que indexa cadenas por código de idioma (un `MultiString`, un `Record`, un `dict[str, str]`) se corresponde con este de forma biunívoca: cada entrada por clave se convierte en un `
`. En un mismo multitexto solo se permite una forma por idioma; de lo contrario, `sil-lift` muestra el aviso `duplicate-form-lang`. + +El escape de XML es la única parte en la que realmente importa la precisión. En el texto de los elementos, los caracteres `&`, `<`, and `>` deben escaparse (`&`, `<`, `>`); en los valores de los atributos, también debe escaparse el carácter de comilla. El autor de `sil-lift` aplica exactamente estas reglas y nunca modifica los espacios en blanco dentro de ``: no añade sangría en ese lugar, ya que eso corrompería los datos léxicos. Si quieres que el resultado sea idéntico, reutiliza el escape de un serializador XML auténtico (no una sustitución hecha a mano en la que se olvide el símbolo `&`) y deja el contenido de `` tal y como aparece en el archivo original, byte a byte. From d58ef5ae71801b47cc00945464afb18d58419913 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:56 -0600 Subject: [PATCH 073/317] New translations lift-export-interop.md (Arabic) [ci skip] --- docs/ar/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/ar/guides/lift-export-interop.md diff --git a/docs/ar/guides/lift-export-interop.md b/docs/ar/guides/lift-export-interop.md new file mode 100644 index 0000000..65ad49d --- /dev/null +++ b/docs/ar/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# إنتاج LIFT متوافق مع المعايير + +هذا الدليل موجه لأي شخص يقوم بكتابة _مُصدِّر_ لـ LIFT — أي كود بلغة برمجة أيًّا كانت، يعمل على تحويل نموذج بيانات تطبيق آخر إلى LIFT 0.13. يؤدي `sil-lift` دورين في هذا العمل: بوابة مطابقة تتحقق من توافق الناتج مع المخطط، بالإضافة إلى الدلالات التي لا يستطيع المخطط التعبير عنها، ومرجعًا للأشكال وقواعد النص التي يجب أن يتبعها الناتج. + +يُعد كتابة لغة LIFT أسهل بكثير من تحليلها: فالمُصدِّر لا يُصدر سوى المجموعة الفرعية من البنيات التي ينتجها نموذجه الخاص، ولا يواجه أبدًا الخيارات الاختيارية الواردة في المواصفات الكاملة. يكمن الصعوبة في التفاصيل — العنصر المصاحب `.lift-ranges`، والنص الخاص بكل نظام كتابة، والمعرّفات الثابتة، وعمليات التهرب في XML — وهذه هي بالضبط ما تكتشفه عمليات الفحص الواردة أدناه. + +## الحزم المضغوطة + +عادةً ما يتم نقل LIFT كملف `.zip` واحد — حيث يقوم كل من FieldWorks و The Combine بالاستيراد والتصدير بهذه الطريقة — لذا فإن `sil-lift` يقرأ ويكتب الحزم المضغوطة مباشرةً، بأي من الترتيبين اللذين يستخدمهما النظام البيئي: الملفات الموجودة في جذر الأرشيف، أو الملفات المتداخلة ضمن مجلد واحد من المستوى الأعلى. + +- **قراءة:** تقوم `sil_lift.load("package.zip")` باستخراج الملفات إلى دليل مؤقت، وتحديد موقع ملف `.lift` الوحيد، وتحميله (يتم تحليل الملفات المصاحبة والوسائط كالمعتاد). تقبل أوامر واجهة سطر الأوامر `validate` و`stats` و`check-media` و`export` مسار ملف `.zip` أيضًا، لذا فإن البرنامج التالي يعمل على الحزمة كما هي. تم تعزيز إجراءات الاستخراج لمواجهة الملفات الضارة — حيث يتم رفض العناصر التي تتضمن اجتياز المسار، كما تم وضع حد أقصى لعدد الإدخالات والحجم الإجمالي غير المضغوط (10 جيجابايت) للحماية من «قنابل ZIP». +- **اكتب:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` يقوم بتجميع ملف `.lift` وملفات `.lift-ranges` الخاصة به، بالإضافة إلى كل الملفات الأخرى الموجودة في المجلد المصدر (الوسائط، `WritingSystems/`، `consent/`، ...) في ملف مضغوط. يتم تعيين `wrap_folder` افتراضيًّا على مجلد من المستوى الأعلى يحمل اسم ملف الـ zip (وفقًا لقواعد الاستيراد في FieldWorks/Combine)؛ قم بتمرير `False` للحصول على أرشيف مسطح. + +يحتفظ كل من `.lift` و`.lift-ranges` بدقة البايت داخل الحزمة؛ أما حاوية zip نفسها فهي غير قابلة لإعادة إنتاج البايتات. + +## التحقق من صحة المخرجات كمرحلة للتأكد من المطابقة + +وجه الأمر `sil-lift validate` إلى ملف `.lift` الذي تم إنشاؤه. وهو يُشغّل RELAX NG (على كل من `.lift` وملف `.lift-ranges` المصاحب له) بالإضافة إلى إجراء فحوصات دلالية لا يمكن للقواعد النحوية التعبير عنها: المراجع المعلقة لـ `relation`/`variant`، ومعرّفات GUID المكررة، وسلامة العنصر الأصلي في النطاق، وقيم السمات والمعلومات النحوية غير المُعرَّفة في نطاقها، ومراجع الرأس `range/@href` التي لا تُحل إلى أي عنصر مرافق. + +بالنسبة لـ CI، في حالة الفشل في أي خطوة، يجب إصدار نتائج قابلة للقراءة آليًّا: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- يؤدي الخيار `--strict` إلى إيقاف عملية التشغيل في حالة ظهور تحذيرات (وليس الأخطاء فقط). +- تتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات، حيث تُعد نتائج `missing-media` التي تظهرها هذه العملية مجرد تشويش عندما لا تكون ملفات الصوت/الصور موجودة في نفس الموقع مع ملف `.lift` في بيئة التكامل المستمر (CI). +- يُخرج الأمر `--format json` كائن JSON واحد (`{"problems": [...], "summary": {...}}`) بدلاً من النص المقروء؛ وتشكل رموز الخروج الخاصة به ومخططه واجهة مدعومة وخاضعة لمعايير SemVer (انظر [دليل سطر الأوامر](cli.md)). +- تُظهر `--require-ids` أخطاءً إضافيةً في حالة وجود إدخالات تفتقد إلى `guid` أو في حالة وجود إدخالات تفتقد إلى `id` — وهو أمر مفيد عندما يتعين عند إعادة الاستيراد لاحقًا تحديث البيانات بدلاً من تكرارها. + +احذر من فقدان البيانات الخفي (نمط الفشل الذي يجعل التصدير إلى ملف CSV عادي مصحوبًا بفقدان البيانات) عن طريق التحقق من الأعداد باستخدام الأمر `stats --format json` على نموذجك المصدر: + +``` +تصدير إحصائيات sil-lift.lift --format json +``` + +ويقدم التقرير إحصاءات عن «المدخلات» و«المعاني» و«الأمثلة» و«مراجع الوسائط» و«اللغات»، بالإضافة إلى «السمات» لكل اسم على حدة. + +### تشغيل البرنامج دون استخدام سلسلة أدوات Python + +يمكن لنظام التكامل المستمر (CI) لمشروع TypeScript أو C# إجراء نفس الفحص دون تثبيت Python، وذلك عبر GitHub Action المدمج: + +```yaml +- الاستخدامات: sillsdev/python-sil-lift@v0.1.0 + مع: + المسار: export.lift + الإعداد الصارم: "true" + عدم التحقق من الوسائط: "true" + التنسيق: json +``` + +أو صورة الحاوية، التي تم إنشاؤها من ملف `Dockerfile` الموجود في المستودع: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## المكون المصاحب `.lift-ranges` + +توجد المفردات الخاضعة للرقابة — مثل أجزاء الكلام، والمجالات الدلالية، وأي مجموعة قيم أخرى مرتبة حسب السمات — في ملف `.lift-ranges` موازٍ، يُشار إليه من ملف `
`: + +```xml +
+ + + + +
+``` + +يحتوي الدليل المصاحب على التعريف الكامل لكل نطاق. القيم هي ``؛ حيث تُشكّل `parent` تسلسلاً هرميًّا؛ أما `label` / `abbrev` / `description` فهي نصوص متعددة: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +ثم يشير المدخل إلى قيمة ما باستخدام المعرّف: ففئة الجزء من الكلام هي ``، والمجال الدلالي هو ``. تُصدر `sil-lift validate` تحذيرًا (`undefined-range-value`) عندما تكون القيمة غير محددة ضمن نطاقها، وتُصدر خطأً (`range-parent`) عندما لا يكون `parent` معرّفًا لأحد العناصر المتجاورة — لذا، قم بتحديد النطاقات التي تستخدمها بياناتك فعليًّا. انظر أيضًا [النطاقات ووسائل الإعلام](folder-media.md). + +إذا قمت بإنشاء عملية التصدير باستخدام لغة Python، فإن الدالات `Lexicon.add_ranges_file()` و`RangesFile.add_range()` و`Range.add_element()` تقوم بإنشاء الملف المصاحب وإضافة مراجع الرؤوس نيابة عنك؛ وتقوم الدالة `open_writer(..., ranges=...)` بنفس الشيء على مسار التدفق. + +## نص ونصوص متعددة + +كل سلسلة نصية بلغة بشرية في LIFT هي _نص متعدد_: حيث يوجد `
` واحد لكل نظام كتابة، ويحتوي كل منها على ``: + +```xml + + كانغا +
الدجاجة
+
+``` + +يتم تعيين النموذج الذي يستخدم رموز اللغات كمفاتيح للسلاسل (مثل `MultiString`، أو `Record`، أو `dict[str, str]`) وفقًا لعلاقة «واحد إلى واحد»: حيث يتحول كل إدخال لكل مفتاح إلى عنصر واحد من نوع `
`. يُسمح بوجود نموذج واحد على الأكثر لكل لغة في نص متعدد واحد — وإلا فإن `sil-lift` ستصدر تحذيرًا من نوع `duplicate-form-lang`. + +يُعد «الهروب من أحرف XML» الجزء الوحيد الذي يتطلب دقة فائقة حقًّا. في نص العنصر، يجب استخدام أحرف الهروب لـ `&` و`<`, and `>` (`&`، `<`، `>`)؛ أما في قيم السمات، فيجب استخدام أحرف الهروب لـ `"` أيضًا. يطبق مطور `sil-lift` هذه القواعد بالضبط ولا يغير أبدًا المسافات البيضاء داخل `` — فهو لا يضيف أي تباعد هناك، لأن ذلك من شأنه إتلاف البيانات اللغوية. إذا كنت تهدف إلى مطابقة ناتجه، فاستخدم آلية الهروب الخاصة بمُسلسل XML حقيقي (وليس عملية استبدال مبرمجة يدويًّا تتجاهل الرمز `&`) واحتفظ بمحتوى `` بايتًا بايتًا تمامًا كما هو موجود في المصدر. From 4e5db6a62d467f213c0f5444da04d3dcd72e6b0e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:58 -0600 Subject: [PATCH 074/317] New translations lift-export-interop.md (German) [ci skip] --- docs/de/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/de/guides/lift-export-interop.md diff --git a/docs/de/guides/lift-export-interop.md b/docs/de/guides/lift-export-interop.md new file mode 100644 index 0000000..b3818b1 --- /dev/null +++ b/docs/de/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Erstellung eines konformen LIFT + +Dieser Leitfaden richtet sich an alle, die einen LIFT-_Exporter_ schreiben – also Code in einer beliebigen Sprache, der das Datenmodell einer anderen Anwendung in LIFT 0.13 umwandelt. `sil-lift` erfüllt bei dieser Arbeit zwei Funktionen: zum einen dient es als Konformitätsprüfung, die die Ausgabe anhand des Schemas und der Semantik, die ein Schema nicht ausdrücken kann, überprüft, und zum anderen als Referenz für die Formen und Textregeln, denen die Ausgabe entsprechen muss. + +Das Schreiben von LIFT ist viel einfacher als dessen Analyse: Ein Exporter gibt nur die Teilmenge der Konstrukte aus, die sein eigenes Modell erzeugt, und muss sich nie mit den optionalen Elementen der vollständigen Spezifikation auseinandersetzen. Das Schwierige sind die Details – der `.lift-ranges`-Begleiter, der schriftsystemspezifische Text, die stabilen IDs und die XML-Escape-Zeichen – und genau diese werden durch die folgenden Prüfungen erfasst. + +## ZIP-Dateien + +LIFT wird in der Regel als einzelne `.zip`-Datei weitergegeben – sowohl FieldWorks als auch The Combine importieren und exportieren auf diese Weise –, daher liest und schreibt `sil-lift` komprimierte Pakete direkt, und zwar in beiden vom Ökosystem verwendeten Strukturen: entweder mit den Dateien im Stammverzeichnis des Archivs oder verschachtelt unter einem Ordner der obersten Ebene. + +- **Hinweis:** `sil_lift.load("package.zip")` entpackt die Datei in ein temporäres Verzeichnis, sucht die einzelne `.lift`-Datei und lädt sie (Begleitdateien und Medien werden wie gewohnt aufgelöst). Die CLI-Befehle `validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls einen `.zip`-Pfad, sodass das unten stehende Skript direkt auf ein Paket in seiner aktuellen Form angewendet werden kann. Die Extraktion ist gegen bösartige Archive abgesichert – Elemente, die eine Pfadüberquerung bewirken, werden abgelehnt, und die Anzahl der Einträge sowie die Gesamtgröße im unkomprimierten Zustand (10 GiB) sind zur Abwehr von ZIP-Bomben begrenzt. +- **Schreiben Sie:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packt die `.lift`-Datei, deren `.lift-ranges` sowie alle anderen Dateien im Quellordner (media, `WritingSystems/`, `consent/`, ...) zusammen. in eine ZIP-Datei. `wrap_folder` ist standardmäßig auf einen Ordner auf oberster Ebene eingestellt, der nach der ZIP-Datei benannt ist (gemäß der Importkonvention von FieldWorks/Combine); übergeben Sie `False`, um ein flaches Archiv zu erhalten. + +Die Dateien `.lift` und `.lift-ranges` behalten ihre Byte-Genauigkeit innerhalb des Pakets bei; der ZIP-Container selbst ist nicht byte-reproduzierbar. + +## Die Ausgabe als Konformitätsprüfung validieren + +Richten Sie den Befehl `sil-lift validate` auf die erstellte `.lift`-Datei aus. Es führt RELAX NG-Prüfungen durch (sowohl für die `.lift`-Datei als auch für die zugehörige `.lift-ranges`-Datei) sowie semantische Prüfungen, die die Grammatik nicht ausdrücken kann: frei schwebende `relation`-/`variant`-Verweise, doppelte GUIDs, die Integrität der übergeordneten Elemente von Bereichselementen, in ihrem Bereich nicht definierte Werte für Merkmale und grammatikalische Informationen sowie `range/@href`-Verweise in Headern, die auf kein zugehöriges Element verweisen. + +Bei CI: Bei jedem Fehler den Vorgang abbrechen und maschinenlesbare Ergebnisse ausgeben: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- Mit `--strict` führen bereits Warnungen (nicht nur Fehler) zum Abbruch der Ausführung. +- `--no-check-media` überspringt die Überprüfung des Dateisystems auf das Vorhandensein von Medien, deren `missing-media`-Ergebnisse irreführend sind, wenn sich die Audio- und Fotodateien in der CI nicht am selben Speicherort wie die `.lift`-Datei befinden. +- `--format json` gibt anstelle von lesbarem Text ein einzelnes JSON-Objekt aus (`{"problems": [...], "summary": {...}}`); die Rückgabecodes und das Schema bilden eine unterstützte, SemVer-konforme Schnittstelle (siehe [das Handbuch zur Befehlszeile](cli.md)). +- `--require-ids` gibt zusätzlich Fehlermeldungen aus, wenn bei Einträgen eine `guid` fehlt oder bei Sensoren eine `id` fehlt – nützlich, wenn bei einem späteren erneuten Import die Einträge aktualisiert und nicht dupliziert werden sollen. + +Schützen Sie sich vor unbemerktem Datenverlust (dem Fehlermodus, der den Export als flache CSV-Datei verlustbehaftet macht), indem Sie die Zählwerte mit `stats --format json` für Ihr Quellmodell überprüfen: + +``` +sil-lift stats export.lift --format json +``` + +Es gibt die Anzahl der „Einträge“, „Bedeutungen“, „Beispiele“, „Medienverweise“, „Sprachen“ sowie die Anzahl der „Merkmale“ pro Name an. + +### Ausführung von „gate“ ohne Python-Toolchain + +Die CI eines TypeScript- oder C#-Projekts kann dieselbe Überprüfung über die mitgelieferte GitHub-Action ausführen, ohne dass Python installiert werden muss: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +oder das Container-Image, das anhand der `Dockerfile`-Datei aus dem Repository erstellt wurde: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## Der `.lift-ranges`-Begleiter + +Kontrollierte Vokabulare – Wortarten, semantische Domänen und alle anderen auf Merkmalen basierenden Wertemengen – befinden sich in einer gleichrangigen `.lift-ranges`-Datei, auf die in der Datei `
` verwiesen wird: + +```xml +
+ + + + +
+``` + +Das Begleitheft enthält die vollständige Definition der einzelnen Bereiche. Die Werte sind ``s; `parent` bildet eine Hierarchie; `label` / `abbrev` / `description` sind Multitexte: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +Ein Eintrag verweist dann anhand der ID auf einen Wert: Die Wortart einer Bedeutung lautet ``, und eine semantische Domäne lautet ``. `sil-lift validate` gibt eine Warnung (`undefined-range-value`) aus, wenn ein Wert nicht innerhalb seines Bereichs definiert ist, und einen Fehler (`range-parent`), wenn ein `parent` keine Geschwister-ID ist – geben Sie daher die Bereiche an, die Ihre Daten tatsächlich verwenden. Siehe auch [Bereiche und Medien](folder-media.md). + +Wenn Sie den Export in Python erstellen, erstellen `Lexicon.add_ranges_file()`, `RangesFile.add_range()` und `Range.add_element()` das zugehörige Objekt und fügen die Header-Referenzen für Sie hinzu; `open_writer(..., ranges=...)` führt dasselbe auf dem Streaming-Pfad durch. + +## Text und Mehrfachtext + +Jede Zeichenkette in einer menschlichen Sprache in LIFT ist ein _Multitext_: ein `
` pro Schriftsystem, wobei jedes ein `` umschließt: + +```xml + + Kanga +
Huhn
+
+``` + +Ein Modell, das Zeichenfolgen anhand des Sprachcodes indiziert (ein `MultiString`, ein `Record`, ein `dict[str, str]`), lässt sich eins-zu-eins auf dieses Modell abbilden: Ein Eintrag pro Schlüssel entspricht einem `
`. In einem einzelnen Multitext ist höchstens eine Form pro Sprache zulässig – andernfalls gibt `sil-lift` die Warnung `duplicate-form-lang` aus. + +Das XML-Escaping ist der einzige Teil, bei dem es wirklich auf Korrektheit ankommt. Im Elementtext müssen `&`, `<`, and `>` mit Escape-Zeichen versehen werden (`&`, `<`, `>`); in Attributwerten gilt dies auch für das Anführungszeichen. Der Autor von `sil-lift` wendet genau diese Regeln an und verändert niemals die Leerzeichen innerhalb von `` – er fügt dort keine Einrückungen hinzu, da dies die lexikalischen Daten verfälschen würde. Wenn Sie die Ausgabe des Serialisierers nachbilden möchten, sollten Sie die Escaping-Zeichen eines echten XML-Serialisierers verwenden (und nicht eine selbst programmierte Ersetzungsfunktion, bei der das `&`-Zeichen vergessen wird) und den Inhalt von `` Byte für Byte so belassen, wie er in Ihrer Quelle vorliegt. From 757bae84c14dcea451b084dab971ef8ff5bbcb8f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:19:59 -0600 Subject: [PATCH 075/317] New translations lift-export-interop.md (Japanese) [ci skip] --- docs/ja/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/ja/guides/lift-export-interop.md diff --git a/docs/ja/guides/lift-export-interop.md b/docs/ja/guides/lift-export-interop.md new file mode 100644 index 0000000..292ec46 --- /dev/null +++ b/docs/ja/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# 準拠したLIFTの生成 + +このガイドは、LIFT _エクスポーター_ を開発するすべての方を対象としています。これは、任意の言語で記述された、他のアプリケーションのデータモデルを LIFT 0.13 形式に変換するコードのことです。 `sil-lift` は、その作業において 2 つの役割を果たします。1 つは、出力がスキーマに準拠しているかを確認する適合性チェック機能と、スキーマでは表現できない意味論のチェック機能であり、もう 1 つは、出力が従わなければならない形状やテキストに関する規則の参照基準としての役割です。 + +LIFTの記述は、その解析よりもはるかに簡単です。エクスポート機能は、自身のモデルが生成する構文のサブセットのみを出力するため、仕様全体のオプション性に対処する必要が一切ないからです。 難しいのは細部、つまり `.lift-ranges` コンパニオン、文字体系ごとのテキスト、安定した ID、XML エスケープなどですが、これらはまさに以下のチェックで検出される項目です。 + +## ZIP形式のパッケージ + +LIFTは通常、単一の`.zip`ファイルとして移動されます(FieldWorksとThe Combineはどちらもこの形式でインポートおよびエクスポートを行います)。そのため、`sil-lift`は、エコシステムで使用されるいずれのレイアウト(アーカイブのルートにファイルが配置されている場合、またはトップレベルのフォルダの下にネストされている場合)においても、zip形式のパッケージを直接読み書きします。 + +- **解説:** `sil_lift.load("package.zip")` は、一時ディレクトリに解凍を行い、単一の `.lift` ファイルを検出して読み込みます(コンパニオンやメディアは通常通り解決されます)。 `validate`、`stats`、`check-media`、および`export`の各CLIコマンドも`.zip`形式のパスを指定できるため、以下のゲートはパッケージをそのままの状態で実行します。 抽出処理は、悪意のあるアーカイブに対して強化されています。パストラバーサルを目的とした要素は拒否され、ZIPボム対策として、エントリ数および展開後の総サイズ(10 GiB)に上限が設けられています。 +- **記述例:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` とすると、`.lift`、その `.lift-ranges`、およびソースフォルダ内のその他のすべてのファイル(media、`WritingSystems/`、`consent/` など)がまとめてパッケージ化されます。 zipファイルにまとめる。 `wrap_folder` のデフォルト値は、zip ファイル名と同じ名前の最上位フォルダです(FieldWorks/Combine のインポート規約に従います)。フラットなアーカイブにする場合は、`False` を指定してください。 + +`.lift` および `.lift-ranges` は、パッケージ内ではバイト単位の忠実性を維持しますが、zip コンテナ自体はバイト単位で再現可能ではありません。 + +## 出力を適合性ゲートとして検証する + +生成された `.lift` ファイルを `sil-lift validate` の対象として指定します。 RELAX NG(`.lift` およびそのコンパニオンである `.lift-ranges` の両方に対して)を実行するほか、文法では表現できないセマンティックチェックも行います: ぶら下がった `relation`/`variant` の参照、重複する GUID、範囲要素の親の整合性、範囲内で定義されていない特性および文法情報の値、およびコンパニオンに解決されないヘッダー `range/@href` の参照などです。 + +CIでは、何か問題が発生した場合は失敗とし、機械可読な結果を出力する: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- `--strict` を指定すると、エラーだけでなく警告も実行の失敗原因となります。 +- `--no-check-media` を指定すると、ファイルシステムのメディア存在確認がスキップされます。CI環境でオーディオファイルや写真ファイルが `.lift` ファイルと同じ場所に配置されていない場合、この確認で検出される `missing-media` の結果はノイズとなるためです。 +- `--format json` を指定すると、人間が読みやすいテキストの代わりに単一の JSON オブジェクト (`{"problems": [...], "summary": {...}}`) が出力されます。その終了コードとスキーマは、SemVer に準拠したサポート対象のインターフェースとなっています([コマンドラインガイド](cli.md)を参照してください)。 +- `--require-ids` オプションを指定すると、`guid` が欠落しているエントリや `id` が欠落しているエントリに対して追加でエラーが発生します。これは、後で再インポートを行う際に、重複を避けるために更新のみを行う必要がある場合に役立ちます。 + +ソースモデルに対して `stats --format json` を使用してカウントを確認することで、サイレントデータ損失(フラットな CSV エクスポートでデータが失われる原因となる障害モード)を防ぐことができます: + +``` +sil-lift の統計データのエクスポート export.lift --format json +``` + +このレポートでは、`entries`、`senses`、`examples`、`media_refs`、`languages`、および名称ごとの`traits`の件数が報告されます。 + +### Pythonツールチェーンを使用せずにgateを実行する + +TypeScript または C# プロジェクトの CI では、Python をインストールしなくても、バンドルされている GitHub Action を通じて同じチェックを実行できます: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +あるいは、リポジトリの `Dockerfile` からビルドされたコンテナイメージ: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## `.lift-ranges` コンパニオン + +統制語彙(品詞、意味領域、およびその他の特性キー付き値セット)は、`
` から参照される同階層の `.lift-ranges` ファイルに格納されています: + +```xml +
+ + + + +
+``` + +このガイドブックには、各シリーズの完全な定義が掲載されています。 値は `` です。`parent` は階層を構築します。`label` / `abbrev` / `description` はマルチテキストです: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +エントリは、ID によって値を参照します。例えば、品詞は ``、意味領域は `` となります。 `sil-lift validate` は、値がその範囲内で定義されていない場合に警告(`undefined-range-value`)を出し、`parent` が兄弟要素の ID ではない場合にエラー(`range-parent`)を返します。したがって、データで実際に使用されている範囲を指定してください。 「範囲とメディア」も参照してください(folder-media.md)。 + +Pythonでエクスポートを構築する場合、`Lexicon.add_ranges_file()`、`RangesFile.add_range()`、および`Range.add_element()`がコンパニオンを構築し、ヘッダー参照を自動的に追加してくれます。 `open_writer(..., ranges=...)` は、ストリーミングパス上でも同様の処理を行います。 + +## テキストおよびマルチテキスト + +LIFT におけるすべての自然言語文字列は _マルチテキスト_ です。つまり、各文字体系ごとに 1 つの `
` があり、それぞれが `` を囲んでいます: + +```xml + + カンガ +
+
+``` + +言語コードをキーとする文字列のモデル(`MultiString`、`Record`、`dict[str, str]`)は、これと一対一で対応します。つまり、キー1つにつき1つのエントリが、1つの `
` になります。 1つのマルチテキスト内で、1つの言語につき最大1つのフォームまでしか許可されません。それ以外の場合、`sil-lift`は`duplicate-form-lang`という警告を出します。 + +XMLのエスケープ処理こそが、唯一、正確さが極めて重要となる部分です。 要素のテキスト内では、`&`、`<`, and `>` はエスケープする必要があります(`&`、`<`、`>`)。属性値内では、引用符も同様にエスケープする必要があります。 `sil-lift`の作者はまさにこれらのルールを適用しており、``内の空白を一切変更しません。そこではインデントを追加しないのは、そうすることで字句データが破損してしまうためです。 その出力を再現したい場合は、本格的なXMLシリアライザのエスケープ処理を再利用し(`&`を忘れるような手作りの置換処理は避ける)、`` のコンテンツはソースにあるまま、バイト単位でそのまま残してください。 From b0f2d112bd7426a3a7b0eacffd635ed86629d08e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:01 -0600 Subject: [PATCH 076/317] New translations lift-export-interop.md (Portuguese) [ci skip] --- docs/pt/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/pt/guides/lift-export-interop.md diff --git a/docs/pt/guides/lift-export-interop.md b/docs/pt/guides/lift-export-interop.md new file mode 100644 index 0000000..0105626 --- /dev/null +++ b/docs/pt/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Produção de LIFT em conformidade + +Este guia destina-se a quem estiver a desenvolver um _exportador_ LIFT — código em qualquer linguagem de programação que converta o modelo de dados de outra aplicação para o formato LIFT 0.13. O `sil-lift` desempenha duas funções nesse trabalho: uma verificação de conformidade que compara a saída com o esquema e com a semântica que o esquema não consegue expressar, e uma referência para as formas e regras de texto que a saída deve seguir. + +Escrever LIFT é muito mais fácil do que analisá-lo: um exportador apenas emite o subconjunto de construções que o seu próprio modelo produz e nunca se depara com todas as opções da especificação completa. A parte mais complicada são os detalhes — o complemento `.lift-ranges`, o texto específico para cada sistema de escrita, os identificadores estáveis e o escape de XML — e é precisamente isso que as verificações abaixo detetam. + +## Pacotes compactados + +O LIFT é normalmente transferido como um único ficheiro `.zip` — tanto o FieldWorks como o The Combine importam e exportam dessa forma — pelo que o `sil-lift` lê e grava pacotes compactados diretamente, independentemente do formato utilizado pelo ecossistema: os ficheiros na raiz do arquivo ou aninhados numa pasta de nível superior. + +- **Nota:** `sil_lift.load("package.zip")` extrai o conteúdo para um diretório temporário, localiza o único ficheiro `.lift` e carrega-o (os ficheiros complementares e os ficheiros multimédia são resolvidos como habitualmente). Os comandos da CLI `validate`, `stats`, `check-media` e `export` também aceitam um caminho `.zip`, pelo que o gate abaixo é executado diretamente sobre um pacote tal como está. A extração está protegida contra arquivos maliciosos — os elementos que permitem a travessia de caminhos são rejeitados, e o número de entradas e o tamanho total descompactado (10 GiB) estão limitados para evitar «zip bombs». +- **Escreva:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` compacta o ficheiro `.lift`, os seus `.lift-ranges` e todos os outros ficheiros da pasta de origem (multimédia, `WritingSystems/`, `consent/`, ...) num ficheiro zip. O `wrap_folder` tem, por predefinição, uma pasta de nível superior com o nome do ficheiro zip (conforme a convenção de importação do FieldWorks/Combine); passe `False` para obter um arquivo simples. + +Os ficheiros `.lift` e `.lift-ranges` mantêm a sua fidelidade ao nível do byte dentro do pacote; o próprio ficheiro zip não é reproduzível ao nível do byte. + +## Validar o resultado como um critério de conformidade + +Execute o comando `sil-lift validate` no ficheiro `.lift` gerado. Executa o RELAX NG (tanto no `.lift` como no seu complemento `.lift-ranges`) e realiza verificações semânticas que a gramática não consegue expressar: referências pendentes a `relation`/`variant`, GUIDs duplicados, integridade do elemento pai do intervalo, valores de características e de informação gramatical não definidos no respetivo intervalo e referências `range/@href` no cabeçalho que não remetem para nenhum elemento correspondente. + +No caso da CI, em caso de falha em qualquer etapa, gerar resultados legíveis por máquina: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- A opção `--strict` faz com que os avisos (e não apenas os erros) provoquem o falhanço da execução. +- A opção `--no-check-media` ignora a verificação da presença de suportes no sistema de ficheiros, cujos resultados de `missing-media` constituem ruído quando os ficheiros de áudio/fotografia não se encontram na mesma localização que o ficheiro `.lift` na CI. +- `--format json` apresenta um único objeto JSON (`{"problems": [...], "summary": {...}}`) em vez de texto legível; os seus códigos de saída e esquema constituem uma interface suportada e abrangida pela SemVer (ver [o guia da linha de comandos](cli.md)). +- `--require-ids` também apresenta erros em entradas que não tenham um `guid` ou que não tenham um `id` — útil quando uma reimportação posterior tiver de atualizar, em vez de duplicar. + +Proteja-se contra a perda silenciosa de dados (o modo de falha que torna a exportação em CSV simples propensa a perdas) verificando as contagens com o comando `stats --format json` no seu modelo de origem: + +``` +sil-lift stats export.lift --format json +``` + +Apresenta as contagens de «entradas», «significados», «exemplos», «referências multimédia», «idiomas» e «características» por nome. + +### Executar o gate sem o conjunto de ferramentas do Python + +A integração contínua (CI) de um projeto em TypeScript ou C# pode executar a mesma verificação sem instalar o Python, através da GitHub Action incluída: + +```yaml +- utiliza: sillsdev/python-sil-lift@v0.1.0 + com: + caminho: export.lift + rigoroso: "true" + sem verificação de mídia: "true" + formato: json +``` + +ou a imagem do contentor, criada a partir do ficheiro `Dockerfile` do repositório: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## O componente complementar `.lift-ranges` + +Os vocabulários controlados — classes gramaticais, domínios semânticos e qualquer outro conjunto de valores baseado em características — encontram-se num ficheiro `.lift-ranges` paralelo, referenciado a partir do ficheiro `
`: + +```xml +
+ + + + +
+``` + +O guia contém a definição completa de cada gama. Os valores são ``s; `parent` cria uma hierarquia; `label` / `abbrev` / `description` são multitexts: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +Uma entrada remete, então, para um valor através do seu identificador: a classe gramatical de um sentido é ``, e um domínio semântico é ``. O `sil-lift validate` emite um aviso (`undefined-range-value`) quando um valor não está definido no seu intervalo e um erro (`range-parent`) quando um `parent` não é um ID de elemento irmão — por isso, indique os intervalos que os seus dados utilizam efetivamente. Ver também [Intervalos e meios de comunicação](folder-media.md). + +Se criar a exportação em Python, as funções `Lexicon.add_ranges_file()`, `RangesFile.add_range()` e `Range.add_element()` criam o objeto complementar e adicionam as referências do cabeçalho automaticamente; `open_writer(..., ranges=...)` faz o mesmo no caminho de streaming. + +## Texto e multitexto + +Cada sequência de caracteres de uma língua humana no LIFT é um _multitexto_: um `
` por sistema de escrita, cada um envolvendo um ``: + +```xml + + kanga +
galinha
+
+``` + +Um modelo que indexa cadeias de caracteres pelo código do idioma (um `MultiString`, um `Record`, um `dict[str, str]`) estabelece uma correspondência um-para-um com este: cada entrada por chave corresponde a um `
`. É permitida, no máximo, uma forma por língua num único multitexto — caso contrário, o `sil-lift` emite um aviso de `duplicate-form-lang`. + +A codificação de escape em XML é a única parte em que a precisão é realmente fundamental. No texto dos elementos, os caracteres `&`, `<`, and `>` devem ser escapados (`&`, `<`, `>`); nos valores dos atributos, o caractere de aspas também deve ser escapado. O autor do `sil-lift` aplica exatamente estas regras e nunca altera os espaços em branco dentro de `` — não adiciona qualquer indentação nesse local, pois isso corromperia os dados lexicais. Se pretender obter o mesmo resultado, reutilize o processo de escape de um serializador XML verdadeiro (em vez de uma substituição feita manualmente que se esqueça do `&`) e mantenha o conteúdo de `` byte a byte, tal como aparece na sua fonte. From c1c5442345822b97f428ec84d29b03063fb213d6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:02 -0600 Subject: [PATCH 077/317] New translations lift-export-interop.md (Russian) [ci skip] --- docs/ru/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/ru/guides/lift-export-interop.md diff --git a/docs/ru/guides/lift-export-interop.md b/docs/ru/guides/lift-export-interop.md new file mode 100644 index 0000000..53edc50 --- /dev/null +++ b/docs/ru/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Создание LIFT, соответствующего требованиям + +Данное руководство предназначено для всех, кто разрабатывает _экспортер_ LIFT — программу на любом языке программирования, преобразующую модель данных другого приложения в формат LIFT 0.13. `sil-lift` выполняет в этой работе две функции: служит механизмом проверки соответствия, который сравнивает выходные данные со схемой и учитывает семантику, которую схема не может выразить, а также выступает в качестве эталона для форм и правил оформления текста, которым должны соответствовать выходные данные. + +Писать LIFT гораздо проще, чем его анализировать: экспортер генерирует только подмножество конструкций, которые создает его собственная модель, и никогда не сталкивается с опциональностью полной спецификации. Самое сложное — это детали: сопутствующий элемент `.lift-ranges`, текст для каждой системы письма, стабильные идентификаторы и экранирование XML — и именно их и выявляют приведенные ниже проверки. + +## Пакеты с застежкой-молнией + +LIFT обычно передаётся в виде одного файла `.zip` — программы FieldWorks и The Combine импортируют и экспортируют данные именно таким образом — поэтому `sil-lift` напрямую считывает и записывает заархивированные пакеты в любом из двух форматов, используемых в этой экосистеме: либо файлы находятся в корневом каталоге архива, либо вложены в одну папку верхнего уровня. + +- **Примечание:** Команда `sil_lift.load("package.zip")` распаковывает файл в временный каталог, находит единственный файл `.lift` и загружает его (сопутствующие файлы и мультимедиа обрабатываются как обычно). Команды CLI `validate`, `stats`, `check-media` и `export` также принимают путь к файлу `.zip`, поэтому приведенный ниже скрипт запускается для пакета в том виде, в котором он есть. Функция извлечения защищена от вредоносных архивов — элементы, позволяющие переходить по пути, отклоняются, а количество записей и общий размер в несжатом виде (10 ГиБ) ограничены для защиты от «zip-бомб». +- **Напишите:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` упаковывает файл `.lift`, его файлы `.lift-ranges`, а также все остальные файлы из исходной папки (медиафайлы, `WritingSystems/`, `consent/`, ...) в архив ZIP. По умолчанию `wrap_folder` — это папка верхнего уровня, названная в соответствии с именем ZIP-архива (согласно соглашению об импорте FieldWorks/Combine); для создания плоского архива передайте значение `False`. + +Файлы `.lift` и `.lift-ranges` сохраняют точность воспроизведения на уровне байтов внутри пакета; сам контейнер zip не обеспечивает точность воспроизведения на уровне байтов. + +## Validate the output as a conformance gate + +Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. + +For CI, fail on anything and emit machine-readable findings: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- `--strict` makes warnings (not just errors) fail the run. +- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. +- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). +- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. + +Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: + +``` +sil-lift stats export.lift --format json +``` + +It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. + +### Running the gate without a Python toolchain + +A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +or the container image, built from the repo's `Dockerfile`: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## The `.lift-ranges` companion + +Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: + +```xml +
+ + + + +
+``` + +The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). + +If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. + +## Text and multitext + +Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: + +```xml + + kanga +
galinha
+
+``` + +A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. + +XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. From d7e2085bf8a8d45cbf9229e3b26016c8991425c6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:04 -0600 Subject: [PATCH 078/317] New translations lift-export-interop.md (Chinese Simplified) [ci skip] --- docs/zh/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/zh/guides/lift-export-interop.md diff --git a/docs/zh/guides/lift-export-interop.md b/docs/zh/guides/lift-export-interop.md new file mode 100644 index 0000000..cf046b5 --- /dev/null +++ b/docs/zh/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Producing conformant LIFT + +This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. + +Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. + +## Zipped packages + +LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. + +- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. +- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. + +The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. + +## Validate the output as a conformance gate + +Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. + +For CI, fail on anything and emit machine-readable findings: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- `--strict` makes warnings (not just errors) fail the run. +- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. +- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). +- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. + +Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: + +``` +sil-lift stats export.lift --format json +``` + +It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. + +### Running the gate without a Python toolchain + +A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +or the container image, built from the repo's `Dockerfile`: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## The `.lift-ranges` companion + +Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: + +```xml +
+ + + + +
+``` + +The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). + +If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. + +## Text and multitext + +Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: + +```xml + + kanga +
galinha
+
+``` + +A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. + +XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. From 4d750cdfeedb587112fbac0f01a003320a8d3f8a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:06 -0600 Subject: [PATCH 079/317] New translations lift-export-interop.md (Hindi) [ci skip] --- docs/hi/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/hi/guides/lift-export-interop.md diff --git a/docs/hi/guides/lift-export-interop.md b/docs/hi/guides/lift-export-interop.md new file mode 100644 index 0000000..cf046b5 --- /dev/null +++ b/docs/hi/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Producing conformant LIFT + +This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. + +Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. + +## Zipped packages + +LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. + +- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. +- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. + +The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. + +## Validate the output as a conformance gate + +Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. + +For CI, fail on anything and emit machine-readable findings: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- `--strict` makes warnings (not just errors) fail the run. +- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. +- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). +- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. + +Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: + +``` +sil-lift stats export.lift --format json +``` + +It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. + +### Running the gate without a Python toolchain + +A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +or the container image, built from the repo's `Dockerfile`: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## The `.lift-ranges` companion + +Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: + +```xml +
+ + + + +
+``` + +The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). + +If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. + +## Text and multitext + +Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: + +```xml + + kanga +
galinha
+
+``` + +A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. + +XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. From 33f7385cc69ea201bfa2058d03e95c5ab6fe25ba Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:08 -0600 Subject: [PATCH 080/317] New translations lift-export-interop.md (Swahili) [ci skip] --- docs/sw/guides/lift-export-interop.md | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/sw/guides/lift-export-interop.md diff --git a/docs/sw/guides/lift-export-interop.md b/docs/sw/guides/lift-export-interop.md new file mode 100644 index 0000000..cf046b5 --- /dev/null +++ b/docs/sw/guides/lift-export-interop.md @@ -0,0 +1,108 @@ +# Producing conformant LIFT + +This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. + +Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. + +## Zipped packages + +LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. + +- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. +- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. + +The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. + +## Validate the output as a conformance gate + +Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. + +For CI, fail on anything and emit machine-readable findings: + +``` +sil-lift validate export.lift --strict --no-check-media --format json +``` + +- `--strict` makes warnings (not just errors) fail the run. +- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. +- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). +- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. + +Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: + +``` +sil-lift stats export.lift --format json +``` + +It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. + +### Running the gate without a Python toolchain + +A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: + +```yaml +- uses: sillsdev/python-sil-lift@v0.1.0 + with: + path: export.lift + strict: "true" + no-check-media: "true" + format: json +``` + +or the container image, built from the repo's `Dockerfile`: + +``` +docker build -t sil-lift . +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +``` + +## The `.lift-ranges` companion + +Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: + +```xml +
+ + + + +
+``` + +The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: + +```xml + + + + + +
n
+
+
+ + + + + +
+``` + +An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). + +If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. + +## Text and multitext + +Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: + +```xml + + kanga +
galinha
+
+``` + +A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. + +XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. From 80f1a0fd82a442dd091b686fb2193bd8625203e9 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:09 -0600 Subject: [PATCH 081/317] New translations read-edit-write.md (French) [ci skip] --- docs/fr/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/fr/guides/read-edit-write.md diff --git a/docs/fr/guides/read-edit-write.md b/docs/fr/guides/read-edit-write.md new file mode 100644 index 0000000..7613c22 --- /dev/null +++ b/docs/fr/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Lire, modifier, rédiger + +## Chargement en cours + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +La fonction `load()` accepte tout document LIFT **0.13** correctement formé, y compris les fichiers réels dont le schéma n'est pas valide. Tout ce qui n'est pas défini par le modèle (éléments ou attributs inconnus, commentaires) est conservé sans perte dans le compartiment opaque `extra` de chaque nœud. Les autres versions de LIFT génèrent une exception `LiftParseError` indiquant le nom de la version. + +## Le modèle + +Chaque élément de LIFT est une classe de données typée : `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, etc. Un texte multilingue est un `Multitext`, qui se comporte comme une correspondance entre un code de langue et un `Text` : + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # les chaînes de caractères brutes sont converties +"en" in entry.citation # False +``` + +Le `Texte` est structuré — il s'agit d'une liste ordonnée de fragments `str` et `Span` — car `` peut contenir des balises `` imbriquées. `str(text)` convertit le contenu en texte brut ; les fragments conservent le balisage pour permettre la conversion aller-retour. + +Dans LIFT, les glosses ont la forme d’une _forme_ (chaque `` possède son propre langage) ; ainsi, un sens est défini par `glosses: list[Form]` et dispose d’une fonction d’aide : + +```python +sense = entry.senses[0] +sense.gloss("en") # Texte | None +entry.gloss_langs() # {"en", "id"} +``` + +## Enregistrement + +```python +lex.save() # retour à l'emplacement d'où il a été chargé +lex.save("elsewhere.lift") +``` + +Les entrées que vous n'avez pas modifiées sont réécrites **à l'octet près** ; un document que vous n'avez pas du tout modifié est identique à l'octet près, du premier au dernier octet. Pour consulter le contrat dans son intégralité, voir [Garanties Fidelity](../fidelity.md). + +## Construire à partir de zéro + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Tri canonique + +```python +lex.sort() # entrées classées par (guid, id) ; plages/définitions de champs par id/balise +lex.save() # les entrées inchangées conservent exactement les mêmes octets, dans le nouvel ordre + +sil_lift.canonicalize("in.lift", "out.lift") # entièrement resérialisé, prêt pour la comparaison des différences +``` + +Voir aussi : [Exemple pratique : modification groupée des gloses](bulk-edit-glosses.md). From 3836d02668b65e92015af21c6cc5387ff0727e69 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:10 -0600 Subject: [PATCH 082/317] New translations read-edit-write.md (Spanish) [ci skip] --- docs/es/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/es/guides/read-edit-write.md diff --git a/docs/es/guides/read-edit-write.md b/docs/es/guides/read-edit-write.md new file mode 100644 index 0000000..dc07d1c --- /dev/null +++ b/docs/es/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Leer, editar, escribir + +## Cargando + +```python +import sil_lift + +; lex = sil_lift.load("dictionary.lift") +``` + +La función `load()` admite cualquier documento LIFT **0.13** bien formado, incluidos los archivos reales que no cumplen con el esquema. Todo aquello que el modelo no defina (elementos o atributos desconocidos, comentarios) se transmite sin pérdida de información en el campo opaco `extra` de cada nodo. Otras versiones de LIFT generan un error `LiftParseError` indicando la versión. + +## El modelo + +Cada elemento de LIFT es una clase de datos tipada: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, etc. Un texto multilingüe es un `Multitext`, que se comporta como una correspondencia entre un código de idioma y un `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # las cadenas simples se convierten +"en" in entry.citation # False +``` + +El `texto` está estructurado —una lista ordenada de fragmentos `str` y `Span`— porque `` puede contener marcado anidado ``. `str(text)` convierte el contenido en texto sin formato; los fragmentos conservan el marcado para facilitar la conversión de ida y vuelta. + +En LIFT, los glosas tienen forma de _forma_ (cada `` tiene su propio lenguaje), por lo que un sentido tiene `glosses: list[Form]`, además de una función auxiliar: + +```python +sense = entry.senses[0] +sense.gloss("en") # Texto | None +entry.gloss_langs() # {"en", "id"} +``` + +## Ahorro + +```python +lex.save() # volver al lugar desde donde se cargó +lex.save("elsewhere.lift") +``` + +Las entradas que no hayas modificado se vuelven a escribir **con los mismos bytes**; un documento que no hayas modificado en absoluto es idéntico, byte a byte, desde el primer byte hasta el último. Consulta [las garantías de Fidelity](../fidelity.md) para conocer los términos exactos del contrato. + +## Construir desde cero + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Ordenación canónica + +```python +lex.sort() # entradas ordenadas por (guid, id); rangos/definiciones de campos por id/etiqueta +lex.save() # las entradas no modificadas conservan sus bytes exactos, en el nuevo orden + +sil_lift.canonicalize("in.lift", "out.lift") # totalmente reserializado, listo para la comparación de diferencias +``` + +Véase también: [Ejemplo práctico: edición masiva de glosas](bulk-edit-glosses.md). From a5b0fd1dc2066ff192ab227ea5314db5c2878432 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:12 -0600 Subject: [PATCH 083/317] New translations read-edit-write.md (Arabic) [ci skip] --- docs/ar/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/ar/guides/read-edit-write.md diff --git a/docs/ar/guides/read-edit-write.md b/docs/ar/guides/read-edit-write.md new file mode 100644 index 0000000..755de82 --- /dev/null +++ b/docs/ar/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# القراءة، التحرير، الكتابة + +## جاري التحميل + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +تقبل الدالة `load()` أي مستند LIFT **0.13** صحيح التكوين — بما في ذلك الملفات الواقعية التي لا تتوافق مع المخطط. يتم نقل أي شيء لا يحدده النموذج (العناصر/السمات غير المعروفة، التعليقات) دون أي فقدان للبيانات في حاوية `extra` غير الشفافة لكل عقدة. أما الإصدارات الأخرى من LIFT، فتُحدث استثناءً من نوع `LiftParseError` مع ذكر اسم الإصدار. + +## النموذج + +كل عنصر في LIFT هو فئة بيانات محددة النوع: `Entry`، `Sense`، `Example`، `Pronunciation`، `Variant`، `Relation`، `Etymology`، `Reversal`، وهكذا دواليك. النص متعدد اللغات هو كائن من نوع `Multitext`، والذي يعمل كخريطة تربط رمز اللغة بكائن من نوع `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # يتم تحويل السلاسل العادية +"en" in entry.citation # False +``` + +يتم تنظيم `Text` — كقائمة مرتبة من أجزاء `str` و`Span` — لأن `` يمكن أن تحتوي على علامات `` متداخلة. يُحول `str(text)` النص إلى نص عادي؛ بينما تحتفظ الأجزاء بعلامات الترميز لضمان إمكانية العودة إلى الصيغة الأصلية. + +تكون «التفسيرات» _على شكل صيغ_ في LIFT (حيث يحمل كل `` لغته الخاصة)، لذا فإن «المعنى» يحتوي على `glosses: list[Form]` بالإضافة إلى دالة مساعدة: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## الحفظ + +```python +lex.save() # العودة إلى المكان الذي تم التحميل منه +lex.save("elsewhere.lift") +``` + +يتم إعادة كتابة الإدخالات التي لم تقم بتعديلها **بشكل مطابق تمامًا على مستوى البايت**؛ أما المستند الذي لم تقم بتعديله على الإطلاق، فهو مطابق تمامًا على مستوى البايت من البايت الأول وحتى الأخير. انظر [ضمانات فيديليتي](../fidelity.md) للاطلاع على نص العقد الدقيق. + +## البناء من الصفر + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## الترتيب القياسي + +```python +lex.sort() # ترتيب الإدخالات حسب (guid، id)؛ النطاقات/تعريفات الحقول حسب id/tag +lex.save() # تحتفظ الإدخالات التي لم يتم التعديل عليها ببايتاتها بالضبط، بالترتيب الجديد + +sil_lift.canonicalize("in.lift", "out.lift") # أعيد تسلسلها بالكامل، وجاهزة للمقارنة +``` + +انظر أيضًا: [مثال توضيحي: التحرير الجماعي للتعليقات التوضيحية](bulk-edit-glosses.md). From 04d71fa1506af3376114ac4d64ce2b4b1bbd053a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:13 -0600 Subject: [PATCH 084/317] New translations read-edit-write.md (German) [ci skip] --- docs/de/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/de/guides/read-edit-write.md diff --git a/docs/de/guides/read-edit-write.md b/docs/de/guides/read-edit-write.md new file mode 100644 index 0000000..29338f0 --- /dev/null +++ b/docs/de/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Lesen, bearbeiten, schreiben + +## Wird geladen + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +`load()` akzeptiert jedes wohlgeformte LIFT-**0.13**-Dokument – einschließlich schemaverstossender Dateien aus der Praxis. Alles, was das Modell nicht definiert (unbekannte Elemente/Attribute, Kommentare), wird verlustfrei im undurchsichtigen `extra`-Bereich jedes Knotens übertragen. Andere LIFT-Versionen lösen einen `LiftParseError` aus, in dem die Version angegeben wird. + +## Das Modell + +Jedes LIFT-Element ist eine typisierte Datenklasse: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal` und so weiter. Mehrsprachiger Text ist ein `Multitext`, der sich wie eine Zuordnung vom Sprachcode zu `Text` verhält: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # einfache Zeichenketten werden umgewandelt +"en" in entry.citation # False +``` + +`Text` ist strukturiert – eine geordnete Liste aus `str`- und `Span`-Fragmenten –, da `` verschachtelte ``-Markups enthalten kann. `str(text)` wandelt den Text in reinen Text um; die Fragmente behalten das Markup für den Hin- und Rücktransport bei. + +Glossare sind in LIFT _form-förmig_ (jedes `` enthält eine eigene Sprache), daher hat ein Sense `glosses: list[Form]` sowie eine Hilfsfunktion: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## Speichern + +```python +lex.save() # zurück an den Ort, von dem es geladen wurde +lex.save("elsewhere.lift") +``` + +Einträge, die Sie nicht geändert haben, werden **byte-identisch** zurückgeschrieben; ein Dokument, das Sie überhaupt nicht geändert haben, ist vom ersten bis zum letzten Byte byte-identisch. Den genauen Vertragsinhalt finden Sie unter [Fidelity-Garantien](../fidelity.md). + +## Von Grund auf neu aufbauen + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Kanonische Sortierung + +```python +lex.sort() # Einträge nach (GUID, ID); Bereiche/Felddefinitionen nach ID/Tag +lex.save() # Unveränderte Einträge behalten ihre exakten Bytes in der neuen Reihenfolge + +sil_lift.canonicalize("in.lift", "out.lift") # vollständig neu serialisiert, bereit für den Vergleich +``` + +Siehe auch: [Beispiel: Massenbearbeitung von Glossaren](bulk-edit-glosses.md). From 6dab5d082e620930f0541c5faa7b0b3d2b8cc07d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:15 -0600 Subject: [PATCH 085/317] New translations read-edit-write.md (Japanese) [ci skip] --- docs/ja/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/ja/guides/read-edit-write.md diff --git a/docs/ja/guides/read-edit-write.md b/docs/ja/guides/read-edit-write.md new file mode 100644 index 0000000..7498900 --- /dev/null +++ b/docs/ja/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# 読む、編集する、書く + +## 読み込み中 + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +`load()` は、スキーマに準拠していない実世界のファイルを含め、形式が正しい LIFT **0.13** ドキュメントであればどれでも受け付けます。 モデルで定義されていないもの(未知の要素や属性、コメントなど)は、各ノードの不透明な `extra` バケットにロスレスで格納されます。 その他の LIFT バージョンでは、そのバージョン名を指定した `LiftParseError` が発生します。 + +## モデル + +LIFTの各要素は、型付きデータクラスです。具体的には、`Entry`、`Sense`、`Example`、`Pronunciation`、`Variant`、`Relation`、`Etymology`、`Reversal`などがあります。 多言語テキストは `Multitext` であり、言語コードから `Text` へのマッピングのように動作します: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # プレーン文字列は型変換される +"en" in entry.citation # False +``` + +`Text` は、`str` および `Span` のフラグメントからなる順序付きリストとして構成されています。これは、`` にネストされた `` マークアップが含まれる可能性があるためです。 `str(text)` はプレーンテキストに変換されますが、フラグメントは往復処理のためにマークアップを維持します。 + +LIFT では、グロスは _Form 型_ です(各 `` は独自の言語を持ちます)。したがって、センスには `glosses: list[Form]` と、ヘルパー関数が定義されています: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## 保存 + +```python +lex.save() # 読み込まれた場所に戻す +lex.save("elsewhere.lift") +``` + +変更を加えなかったエントリは、**バイト単位で同一**な状態で書き戻されます。まったく変更を加えなかったドキュメントは、最初のバイトから最後のバイトまでバイト単位で同一です。 契約の詳細については、[フィデリティの保証](../fidelity.md)をご覧ください。 + +## ゼロから構築する + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## 規範的順序付け + +```python +lex.sort() # エントリを (guid, id) の順に並べ替え; ID/タグごとの範囲/フィールド定義 +lex.save() # 変更されていないエントリは、新しい順序のまま正確なバイトデータを保持します + +sil_lift.canonicalize("in.lift", "out.lift") # 完全に再シリアル化され、差分比較の準備が整いました +``` + +関連項目:[実践例:用語の一括編集](bulk-edit-glosses.md)。 From 0fcf9c8ccf5da3d2ef2a1ecf937bfabeac17d9e5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:16 -0600 Subject: [PATCH 086/317] New translations read-edit-write.md (Portuguese) [ci skip] --- docs/pt/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/pt/guides/read-edit-write.md diff --git a/docs/pt/guides/read-edit-write.md b/docs/pt/guides/read-edit-write.md new file mode 100644 index 0000000..8005f52 --- /dev/null +++ b/docs/pt/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Ler, editar, escrever + +## A carregar + +```python +import sil_lift + +; lex = sil_lift.load("dictionary.lift") +``` + +A função `load()` aceita qualquer documento LIFT **0.13** bem formado — incluindo ficheiros reais que não estejam em conformidade com o esquema. Tudo o que o modelo não definir (elementos/atributos desconhecidos, comentários) é transportado sem perdas no compartimento opaco `extra` de cada nó. Outras versões do LIFT provocam um `LiftParseError` indicando a versão. + +## O modelo + +Cada elemento do LIFT é uma classe de dados tipada: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, e assim por diante. Um texto multilingue é um `Multitext`, que funciona como um mapeamento de um código de idioma para `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # as cadeias de caracteres simples são convertidas +"en" in entry.citation # False +``` + +O `Text` está estruturado — uma lista ordenada de fragmentos `str` e `Span` — porque `` pode conter marcação aninhada ``. `str(text)` converte o texto em texto simples; os fragmentos mantêm a marcação para permitir a conversão de ida e volta. + +No LIFT, as glossas têm a forma de _Form_ (cada `` contém a sua própria linguagem), pelo que um sentido tem `glosses: list[Form]`, além de uma função auxiliar: + +```python +sense = entry.senses[0] +sense.gloss("en") # Texto | None +entry.gloss_langs() # {"en", "id"} +``` + +## Poupança + +```python +lex.save() # voltar para o local de onde foi carregado +lex.save("elsewhere.lift") +``` + +As entradas que não foram modificadas são gravadas de volta **identicamente, ao nível do byte**; um documento que não tenha sido modificado de todo é idêntico, ao nível do byte, desde o primeiro byte até ao último. Consulte [Garantias da Fidelity](../fidelity.md) para conhecer o contrato na íntegra. + +## Construir do zero + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Ordenação canónica + +```python +lex.sort() # entradas por (guid, id); intervalos/definições de campos por id/tag +lex.save() # as entradas não alteradas mantêm os seus bytes exatos, na nova ordem + +sil_lift.canonicalize("in.lift", "out.lift") # totalmente resserializado, pronto para comparação de diferenças +``` + +Ver também: [Exemplo prático: edição em massa de glossários](bulk-edit-glosses.md). From 72466ff816cb40b6c44629d37f42d6fcefde62e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:18 -0600 Subject: [PATCH 087/317] New translations read-edit-write.md (Russian) [ci skip] --- docs/ru/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/ru/guides/read-edit-write.md diff --git a/docs/ru/guides/read-edit-write.md b/docs/ru/guides/read-edit-write.md new file mode 100644 index 0000000..a4b9e1d --- /dev/null +++ b/docs/ru/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Читать, редактировать, писать + +## Загрузка + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +Функция `load()` принимает любой корректно сформированный документ LIFT **0.13** — в том числе реальные файлы, не соответствующие схеме. Все, что не определено в модели (неизвестные элементы/атрибуты, комментарии), без потерь передается в непрозрачный контейнер `extra` каждого узла. Другие версии LIFT вызывают исключение `LiftParseError`, указывая номер версии. + +## Модель + +Каждый элемент LIFT представляет собой типизированный класс данных: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal` и т. д. Многоязычный текст представляет собой объект `Multitext`, который работает как отображение кода языка на объект `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # простые строки преобразуются +"en" in entry.citation # False +``` + +`Text` имеет структуру — это упорядоченный список фрагментов `str` и `Span` — поскольку `` может содержать вложенную разметку ``. `str(text)` преобразует текст в обычный текст; фрагменты сохраняют разметку для обратного преобразования. + +В LIFT глоссы имеют форму _form_ (каждый `` содержит свой собственный язык), поэтому сенс имеет `glosses: list[Form]`, а также вспомогательную функцию: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## Сохранение + +```python +lex.save() # сохранить в том же месте, откуда было загружено +lex.save("elsewhere.lift") +``` + +Записи, которые вы не изменяли, записываются обратно **байт за байтом**; документ, который вы не изменяли вообще, остается байт за байтом идентичным от первого до последнего байта. Точные условия договора см. в разделе [Гарантии Fidelity](../fidelity.md). + +## Создание с нуля + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Каноническая сортировка + +```python +lex.sort() # записи по (guid, id); диапазоны/определения полей по id/тегу +lex.save() # неизменённые записи сохраняют свои точные байты в новом порядке + +sil_lift.canonicalize("in.lift", "out.lift") # полностью пересериализовано, готово к сравнению +``` + +См. также: [Пример с решением: массовое редактирование глосс](bulk-edit-glosses.md). From e63cedff93b5ec4e4f0698043af5bbe3c587e98a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:19 -0600 Subject: [PATCH 088/317] New translations read-edit-write.md (Chinese Simplified) [ci skip] --- docs/zh/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/zh/guides/read-edit-write.md diff --git a/docs/zh/guides/read-edit-write.md b/docs/zh/guides/read-edit-write.md new file mode 100644 index 0000000..140f6c0 --- /dev/null +++ b/docs/zh/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Read, edit, write + +## Loading + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. + +## The model + +Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # plain strings are coerced +"en" in entry.citation # False +``` + +`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. + +Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## Saving + +```python +lex.save() # back to where it was loaded from +lex.save("elsewhere.lift") +``` + +Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. 具体合同条款请参见[富达保证](../fidelity.md)。 + +## Building from scratch + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## 规范排序 + +```python +lex.sort() # entries by (guid, id); ranges/field defs by id/tag +lex.save() # untouched entries keep their exact bytes, in the new order + +sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +``` + +See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). From c2cd057af842f549c98865b4ab000e8047add41f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:21 -0600 Subject: [PATCH 089/317] New translations read-edit-write.md (Hindi) [ci skip] --- docs/hi/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/hi/guides/read-edit-write.md diff --git a/docs/hi/guides/read-edit-write.md b/docs/hi/guides/read-edit-write.md new file mode 100644 index 0000000..74921e9 --- /dev/null +++ b/docs/hi/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Read, edit, write + +## Loading + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. + +## The model + +Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # plain strings are coerced +"en" in entry.citation # False +``` + +`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. + +Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## Saving + +```python +lex.save() # back to where it was loaded from +lex.save("elsewhere.lift") +``` + +Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. See [Fidelity guarantees](../fidelity.md) for the precise contract. + +## Building from scratch + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Canonical sorting + +```python +lex.sort() # entries by (guid, id); ranges/field defs by id/tag +lex.save() # untouched entries keep their exact bytes, in the new order + +sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +``` + +See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). From 06cdb693da5ca7896b2515aac485dfd6e6d6410f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:22 -0600 Subject: [PATCH 090/317] New translations read-edit-write.md (Swahili) [ci skip] --- docs/sw/guides/read-edit-write.md | 66 +++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 docs/sw/guides/read-edit-write.md diff --git a/docs/sw/guides/read-edit-write.md b/docs/sw/guides/read-edit-write.md new file mode 100644 index 0000000..74921e9 --- /dev/null +++ b/docs/sw/guides/read-edit-write.md @@ -0,0 +1,66 @@ +# Read, edit, write + +## Loading + +```python +import sil_lift + +lex = sil_lift.load("dictionary.lift") +``` + +`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. + +## The model + +Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: + +```python +entry = lex.find(id="abat") + +str(entry.lexical_unit["seh"]) # "abat" +entry.lexical_unit["en"] = "grove" # plain strings are coerced +"en" in entry.citation # False +``` + +`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. + +Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: + +```python +sense = entry.senses[0] +sense.gloss("en") # Text | None +entry.gloss_langs() # {"en", "id"} +``` + +## Saving + +```python +lex.save() # back to where it was loaded from +lex.save("elsewhere.lift") +``` + +Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. See [Fidelity guarantees](../fidelity.md) for the precise contract. + +## Building from scratch + +```python +lex = sil_lift.Lexicon(producer="my-script 1.0") +entry = sil_lift.Entry(id="hello", guid="...") +entry.lexical_unit["en"] = "hello" +sense = sil_lift.Sense() +sense.glosses.append(sil_lift.Form("fr", sil_lift.Text(["bonjour"]))) +entry.senses.append(sense) +lex.entries.append(entry) +lex.save("new.lift") +``` + +## Canonical sorting + +```python +lex.sort() # entries by (guid, id); ranges/field defs by id/tag +lex.save() # untouched entries keep their exact bytes, in the new order + +sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +``` + +See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). From 70b295d265be2c7e907f615f417fccccd8b032e7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:24 -0600 Subject: [PATCH 091/317] New translations validate.md (French) [ci skip] --- docs/fr/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/fr/guides/validate.md diff --git a/docs/fr/guides/validate.md b/docs/fr/guides/validate.md new file mode 100644 index 0000000..8898dca --- /dev/null +++ b/docs/fr/guides/validate.md @@ -0,0 +1,36 @@ +# Valider + +La validation est toujours explicite : le chargement et l'enregistrement n'entraînent jamais de validation implicite. + +```python +import sil_lift + +# Approche exhaustive : un flux paresseux de problèmes (schéma + couches sémantiques). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # erreur [dangling-ref] dictionary.lift:88 (entrée apu) : la référence « nope » correspond à... + +# Détection rapide des erreurs : lève une exception LiftValidationError dès le premier problème de niveau d'erreur. +sil_lift.validate_file("dictionary.lift") + +# État en mémoire (sérialisation préalable — un coût documenté pour les grands lexiques) : +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Chaque « problème » comporte un « niveau » (« erreur »/« avertissement »), un « code » fixe, un « message » et une adresse : « fichier », « id_entrée », « guid », « ligne ». + +## Les couches + +1. **RELAX NG** par rapport à la grammaire LIFT 0.13 (fournie par lift-standard). +2. **Schéma Ranges** — le fichier `lift-ranges-0.13.rng` de ce projet — s'applique à tous les compagnons `.lift-ranges` suivis. +3. **Vérifications sémantiques** que la grammaire ne permet pas d'exprimer : `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Résultats concrets de FieldWorks (FLEx) + +FieldWorks génère systématiquement certains contenus qui sont rejetés par des outils de validation rigoureux. Voici la politique de sil-lift, afin que les véritables lexiques puissent être validés de manière utile : + +- Les liens `file://C:/...` (URI non valides) sont signalés comme des **avertissements** (`uri-not-rfc`), et non comme des erreurs de schéma — le validateur C# ne les a jamais rejetés. +- Les éléments enfants légalement entrelacés (par exemple, « champ, note, champ, note » en quelque sorte) ne sont **pas** signalés, ce qui permet de contourner un faux positif dans libxml2. +- Les valeurs de plage sont comparées selon la normalisation Unicode NFC — FLEx écrit le fichier `.lift` en NFC, mais le fichier `.lift-ranges` en NFD au sein de la même exportation. +- Les extensions `trait`/`field` de FLEx à l'intérieur de `range-element` **sont** signalées (erreurs de schéma par rapport au schéma des plages) : il s'agit de véritables écarts par rapport à la spécification. From f7b7764a803f415dc012dc0b1a731ad6e5d2f0c2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:25 -0600 Subject: [PATCH 092/317] New translations validate.md (Spanish) [ci skip] --- docs/es/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/es/guides/validate.md diff --git a/docs/es/guides/validate.md b/docs/es/guides/validate.md new file mode 100644 index 0000000..d009e1e --- /dev/null +++ b/docs/es/guides/validate.md @@ -0,0 +1,36 @@ +# Validar + +La validación siempre es explícita: las operaciones de carga y guardado nunca realizan una validación implícita. + +```python +import sil_lift + +# Exhaustivo: un flujo diferido de problemas (esquema + capas semánticas). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # error [dangling-ref] dictionary.lift:88 (entrada apu): la referencia «nope» coincide con... + +# Detección rápida de errores: lanza un LiftValidationError ante el primer problema de nivel de error. +sil_lift.validate_file("dictionary.lift") + +# Estado en memoria (se serializa primero — un coste documentado en léxicos grandes): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Cada «Problema» incluye un «nivel» («error»/«advertencia»), un «código» fijo, un «mensaje» y una dirección: «archivo», «id_entrada», «guid» y «línea». + +## Las capas + +1. **RELAX NG** con respecto a la gramática LIFT 0.13 (incluida en lift-standard). +2. **Esquema de rangos** —el archivo `lift-ranges-0.13.rng` de este proyecto— sobre cada complemento `.lift-ranges` al que se realiza un seguimiento. +3. **Comprobaciones semánticas** que la gramática no puede expresar: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Resultados de FieldWorks (FLEx) en el mundo real + +FieldWorks genera de forma sistemática cierto contenido que las herramientas más estrictas rechazan. A continuación se expone la política de sil-lift, para que los léxicos reales resulten útiles: + +- Los enlaces `file://C:/...` (URI no válidos) se señalan como **advertencias** (`uri-not-rfc`), no como errores de esquema; el validador de C# nunca los ha rechazado. +- Los elementos secundarios intercalados legalmente (por ejemplo, «campo, nota, campo, nota», en cierto sentido) **no** se marcan, lo que permite evitar un falso positivo en libxml2. +- Los valores de rango se comparan según la normalización NFC de Unicode: FLEx escribe el archivo `.lift` en NFC, pero el `.lift-ranges` en NFD dentro de la misma exportación. +- Las extensiones `trait`/`field` de FLEx dentro de `range-element` **sí** se señalan (como errores de esquema respecto al esquema de rangos): se trata de auténticas desviaciones respecto a la especificación. From 92e2048b242223fcf3e23d6105b79ad1c5d68157 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:27 -0600 Subject: [PATCH 093/317] New translations validate.md (Arabic) [ci skip] --- docs/ar/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/ar/guides/validate.md diff --git a/docs/ar/guides/validate.md b/docs/ar/guides/validate.md new file mode 100644 index 0000000..3e31967 --- /dev/null +++ b/docs/ar/guides/validate.md @@ -0,0 +1,36 @@ +# التحقق من الصحة + +يكون التحقق من الصحة دائمًا صريحًا — فلا يتم التحقق من صحة عمليات التحميل والحفظ أبدًا بشكل ضمني. + +```python +import sil_lift + +# شامل: دفق كسول من المشكلات (المخطط + الطبقات الدلالية). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # خطأ [dangling-ref] dictionary.lift:88 (entry apu): المرجع 'nope' يطابق ... + +# الفشل السريع: يثير استثناء LiftValidationError عند أول مشكلة على مستوى الخطأ. +sil_lift.validate_file("dictionary.lift") + +# الحالة في الذاكرة (يتم التسلسل أولاً — تكلفة موثقة في المعاجم الكبيرة): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +تحتوي كل «مشكلة» على «مستوى» («خطأ»/«تحذير») و«رمز» ثابت و«رسالة» وعنوان: «ملف»، «معرف_المدخل»، «معرف_فريد»، «سطر». + +## الطبقات + +1. **RELAX NG** وفقًا لقواعد النحو LIFT 0.13 (المُدرجة في مكتبة lift-standard). +2. **مخطط النطاقات** — ملف `lift-ranges-0.13.rng` الخاص بهذا المشروع — على كل مرفق `.lift-ranges` يتم تتبعه. +3. **التحققات الدلالية** التي لا يمكن للقواعد النحوية التعبير عنها: `duplicate-guid`، `dangling-ref`، `range-parent`، `undefined-range-value`، `duplicate-form-lang`، `missing-media`. + +## نتائج برنامج FieldWorks (FLEx) في الواقع الميداني + +يقوم برنامج FieldWorks بشكل منهجي بكتابة بعض المحتوى الذي ترفضه الأدوات الصارمة. فيما يلي سياسة «sil-lift»، بحيث يتم التحقق من صحة المعاجم الحقيقية بشكل مفيد: + +- يتم الإبلاغ عن روابط href من النوع `file://C:/...` (عناوين URI غير صالحة) على أنها **تحذيرات** (`uri-not-rfc`)، وليست أخطاء في المخطط — ولم يرفضها أداة التحقق من صحة C# مطلقًا. +- لا يتم وضع علامة على العناصر الفرعية المتداخلة بشكل قانوني (مثل `field, note, field, note` بمعنى ما)، وذلك لتجنب حدوث نتيجة إيجابية خاطئة في مكتبة libxml2. +- تتم مقارنة قيم النطاقات وفقًا لتوحيد Unicode NFC — حيث يقوم FLEx بكتابة ملف `.lift` بتنسيق NFC، بينما يكتب ملف `.lift-ranges` بتنسيق NFD ضمن نفس التصدير. +- يتم الإبلاغ عن امتدادات `trait`/`field` الخاصة بـ FLEx داخل `range-element` \*\*(\*\*أخطاء في المخطط مقابل مخطط النطاقات): فهي انحرافات حقيقية عن المواصفات. From 9563615b2f5ae809f9db9e710e3151ac776566c7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:28 -0600 Subject: [PATCH 094/317] New translations validate.md (German) [ci skip] --- docs/de/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/de/guides/validate.md diff --git a/docs/de/guides/validate.md b/docs/de/guides/validate.md new file mode 100644 index 0000000..1bfc68c --- /dev/null +++ b/docs/de/guides/validate.md @@ -0,0 +1,36 @@ +# Überprüfen + +Die Validierung erfolgt immer explizit – beim Laden und Speichern findet niemals eine implizite Validierung statt. + +```python +import sil_lift + +# Vollständig: ein „lazy“ Stream von Problemen (Schema + semantische Ebenen). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # Fehler [dangling-ref] dictionary.lift:88 (Eintrag apu): ref 'nope' passt zu ... + +# Fail-fast: Löst bei dem ersten Problem auf Fehler-Ebene einen LiftValidationError aus. +sil_lift.validate_file("dictionary.lift") + +# In-Memory-Zustand (wird zunächst serialisiert – ein dokumentierter Mehraufwand bei großen Lexika): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Jedes `Problem` enthält einen `Level` (`"error"`/`"warning"`), einen festen `Code`, eine `Meldung` sowie folgende Angaben: `Datei`, `Eintrags-ID`, `GUID`, `Zeile`. + +## Die Schichten + +1. **RELAX NG** im Vergleich zur LIFT 0.13-Grammatik (aus „lift-standard“ bezogen). +2. **Ranges-Schema** – in diesem Projekt `lift-ranges-0.13.rng` – für jeden erfassten `.lift-ranges`-Begleiter. +3. **Semantische Prüfungen**, die die Grammatik nicht ausdrücken kann: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Praktische FieldWorks (FLEx)-Ergebnisse + +FieldWorks schreibt systematisch bestimmte Inhalte, die von strengen Validierungstools abgelehnt werden. Hier sind die Richtlinien von sil-lift, damit echte Lexika sinnvoll validiert werden können: + +- `file://C:/...`-href-Attribute (ungültige URIs) werden als **Warnungen** (`uri-not-rfc`) gemeldet, nicht als Schemafehler – der C#-Validator hat sie nie abgelehnt. +- Rechtmäßig verschachtelte Kinder (z. B. in gewisser Weise `field, note, field, note`) werden **nicht** markiert, wodurch ein Fehlalarm in libxml2 umgangen wird. +- Bereichswerte werden unter der Unicode-NFC-Normalisierung verglichen – FLEx schreibt die `.lift`-Daten in NFC, die `.lift-ranges`-Daten jedoch in NFD innerhalb desselben Exports. +- Die `trait`/`field`-Erweiterungen von FLEx innerhalb von `range-element` **werden** gemeldet (Schemafehler in Bezug auf das Ranges-Schema): Es handelt sich dabei um echte Abweichungen von der Spezifikation. From 65526d65571d162c023b5cc378e7c68213bec4a6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:30 -0600 Subject: [PATCH 095/317] New translations validate.md (Japanese) [ci skip] --- docs/ja/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/ja/guides/validate.md diff --git a/docs/ja/guides/validate.md b/docs/ja/guides/validate.md new file mode 100644 index 0000000..3ecd15b --- /dev/null +++ b/docs/ja/guides/validate.md @@ -0,0 +1,36 @@ +# 検証 + +検証は常に明示的に行われます。読み込みや保存の際、暗黙的に検証が行われることはありません。 + +```python +import sil_lift + +# 網羅的:Problem(スキーマ層+セマンティック層)の遅延ストリーム。 +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # エラー [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches ... + +# フェイルファースト:最初のエラーレベルの問題で LiftValidationError を発生させます。 +sil_lift.validate_file("dictionary.lift") + +# メモリ内状態(最初にシリアライズされる — 大規模な辞書では、ドキュメントに記載されているようにコストがかかる): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +各 `Problem` には、`level`(`"error"`/`"warning"`)、一意の `code`、`message`、および `file`、`entry_id`、`guid`、`line` というアドレス情報が含まれています。 + +## レイヤー + +1. **RELAX NG** を、LIFT 0.13 の文法(lift-standard からベンダー提供されているもの)に対して適用します。 +2. **Rangesスキーマ** — このプロジェクトの `lift-ranges-0.13.rng` — は、追跡対象のすべての `.lift-ranges` コンパニオンに対して適用されます。 +3. **文法では表現できないセマンティックチェック**:`duplicate-guid`、`dangling-ref`、`range-parent`、`undefined-range-value`、`duplicate-form-lang`、`missing-media`。 + +## 実環境におけるFieldWorks(FLEx)の出力結果 + +FieldWorksは、厳格なツールによって拒否されるようなコンテンツを体系的に生成してしまう。 実際の辞書が有用に検証されるよう、sil-liftの方針は以下の通りです: + +- `file://C:/...` という href(無効な URI)は、スキーマエラーではなく**警告**(`uri-not-rfc`)として報告されます。C# バリデータはこれらを拒否したことはありません。 +- 法的に交互に配置された子要素(ある意味では `field, note, field, note` など)にはフラグが付けられず、これにより libxml2 における誤検知を回避しています。 +- 範囲値は、UnicodeのNFC正規化に基づいて比較されます。FLExは、同じエクスポート内で`.lift`をNFCで記述しますが、`.lift-ranges`はNFDで記述します。 +- `range-element` 内の FLEx の `trait`/`field` 拡張は、**報告される**(range スキーマに対するスキーマエラーとして):これらは紛れもない仕様からの逸脱である。 From 2d7b31e285df8987ebfff73477e036b2da2cfa18 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:31 -0600 Subject: [PATCH 096/317] New translations validate.md (Portuguese) [ci skip] --- docs/pt/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/pt/guides/validate.md diff --git a/docs/pt/guides/validate.md b/docs/pt/guides/validate.md new file mode 100644 index 0000000..18e2cac --- /dev/null +++ b/docs/pt/guides/validate.md @@ -0,0 +1,36 @@ +# Validar + +A validação é sempre explícita — o carregamento e o guardamento nunca validam implicitamente. + +```python +import sil_lift + +# Exaustivo: um fluxo preguiçoso de Problemas (esquema + camadas semânticas). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # erro [dangling-ref] dictionary.lift:88 (entrada apu): a referência 'nope' corresponde a ... + +# Falha rápida: lança um LiftValidationError no primeiro problema de nível de erro. +sil_lift.validate_file("dictionary.lift") + +# Estado na memória (serializa primeiro — um custo documentado em léxicos de grande dimensão): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Cada `Problema` contém um `nível` (`"erro"`/`"aviso"`), um `código` fixo, uma `mensagem` e um endereço: `ficheiro`, `entry_id`, `guid`, `linha`. + +## As camadas + +1. **RELAX NG** em relação à gramática LIFT 0.13 (fornecida pelo lift-standard). +2. **Esquema de intervalos** — o ficheiro `lift-ranges-0.13.rng` deste projeto — sobre todos os companheiros `.lift-ranges` monitorizados. +3. **Verificações semânticas** que a gramática não consegue expressar: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Resultados do FieldWorks (FLEx) em condições reais + +O FieldWorks cria sistematicamente algum conteúdo que as ferramentas de verificação rigorosas rejeitam. Eis a política do sil-lift, para que os léxicos reais sejam validados de forma útil: + +- Os hrefs do tipo `file://C:/...` (URIs inválidas) são assinalados como **avisos** (`uri-not-rfc`), e não como erros de esquema — o validador C# nunca os rejeitou. +- Os elementos filhos intercalados legalmente (por exemplo, `field, note, field, note`, de certa forma) **não** são assinalados, o que permite contornar um falso positivo na libxml2. +- Os valores dos intervalos são comparados de acordo com a normalização NFC do Unicode — o FLEx grava o ficheiro `.lift` em NFC, mas o ficheiro `.lift-ranges` em NFD, dentro da mesma exportação. +- As extensões `trait`/`field` do FLEx dentro de `range-element` **são** assinaladas (erros de esquema em relação ao esquema de intervalos): tratam-se de verdadeiros desvios em relação à especificação. From fd22c5fd7009859f7fcac63538eb52c2d85763b8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:32 -0600 Subject: [PATCH 097/317] New translations validate.md (Russian) [ci skip] --- docs/ru/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/ru/guides/validate.md diff --git a/docs/ru/guides/validate.md b/docs/ru/guides/validate.md new file mode 100644 index 0000000..571516e --- /dev/null +++ b/docs/ru/guides/validate.md @@ -0,0 +1,36 @@ +# Проверить + +Проверка всегда выполняется явно — при загрузке и сохранении проверка никогда не выполняется неявно. + +```python +import sil_lift + +# Исчерпывающий подход: ленивый поток объектов Problems (схема + семантические слои). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # ошибка [dangling-ref] dictionary.lift:88 (запись apu): ссылка 'nope' совпадает с ... + +# Быстрая остановка при ошибке: генерирует LiftValidationError при первой проблеме уровня ошибки. +sil_lift.validate_file("dictionary.lift") + +# Состояние в памяти (сначала сериализуется — задокументированная нагрузка при работе с большими лексиконами): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Каждая `Problem` содержит `level` (`"error"`/`"warning"`), постоянный `code`, `message` и адрес: `file`, `entry_id`, `guid`, `line`. + +## Слои + +1. **RELAX NG** в сопоставлении с грамматикой LIFT 0.13 (включенной из пакета lift-standard). +2. **Схема диапазонов** — файл `lift-ranges-0.13.rng` данного проекта — для каждого отслеживаемого компаньона `.lift-ranges`. +3. **Семантические проверки**, которые не могут быть выражены с помощью грамматики: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Реальные результаты работы FieldWorks (FLEx) + +FieldWorks систематически генерирует контент, который отклоняется строгой системой проверки. Вот правила sil-lift, позволяющие обеспечить эффективную проверку подлинности лексиконов: + +- Ссылки `file://C:/...` (недопустимые URI) фиксируются как **предупреждения** (`uri-not-rfc`), а не как ошибки схемы — валидатор C# никогда их не отклонял. +- Дети, чередующиеся в соответствии с правилами (например, в некотором смысле `field, note, field, note`), **не** помечаются, что позволяет обойти ложное срабатывание в libxml2. +- Значения диапазонов сравниваются с использованием нормализации Unicode NFC — FLEx записывает файл `.lift` в формате NFC, а файл `.lift-ranges` — в формате NFD в рамках одного и того же экспорта. +- Расширения `trait`/`field` из FLEx внутри `range-element` **упоминаются** (ошибки схемы по отношению к схеме диапазонов): это настоящие отклонения от спецификации. From 9206b609725ab6a1d2b8f17e82861a13ddf6be05 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:34 -0600 Subject: [PATCH 098/317] New translations validate.md (Chinese Simplified) [ci skip] --- docs/zh/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/zh/guides/validate.md diff --git a/docs/zh/guides/validate.md b/docs/zh/guides/validate.md new file mode 100644 index 0000000..16f7702 --- /dev/null +++ b/docs/zh/guides/validate.md @@ -0,0 +1,36 @@ +# 验证 + +验证总是显式的——加载和保存操作绝不会进行隐式验证。 + +```python +import sil_lift + +# 穷举:一个由问题(模式层 + 语义层)组成的惰性流。 +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # 错误 [悬空引用] dictionary.lift:88 (条目 apu):引用 'nope' 与 ... 匹配 + +# 快速失败:在遇到第一个错误级别的问题时抛出 LiftValidationError。 +sil_lift.validate_file("dictionary.lift") + +# 内存状态(先进行序列化——这是大型词典中已记录的开销): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +每个 `Problem` 包含 `level`(`"error"`/`"warning"`)、一个固定的 `code`、`message` 以及一个地址:`file`、`entry_id`、`guid`、`line`。 + +## 各层 + +1. **RELAX NG** 基于 LIFT 0.13 语法(从 lift-standard 引入)。 +2. **范围模式** —— 本项目的 `lift-ranges-0.13.rng` —— 适用于所有被追踪的 `.lift-ranges` 伴生类。 +3. **语义检查**:语法无法表达以下情况:`duplicate-guid`、`dangling-ref`、`range-parent`、`undefined-range-value`、`duplicate-form-lang`、`missing-media`。 + +## FieldWorks(FLEx)的实际应用输出 + +FieldWorks 会系统性地生成一些会被严格工具过滤掉的内容。 以下是 sil-lift 的政策,旨在确保真实的词汇表能够发挥实际作用: + +- `file://C:/...` 格式的 href(无效的 URI)会被报告为 **警告**(`uri-not-rfc`),而非模式错误——C# 验证器从未拒绝过此类 URI。 +- 合法交错的子元素(例如,某种意义上的 `field, note, field, note`)**不会**被标记,以此规避 libxml2 中的误报问题。 +- 范围值的比较是在 Unicode NFC 规范化下进行的——FLEx 在同一导出文件中将 `.lift` 写为 NFC 格式,而将 `.lift-ranges` 写为 NFD 格式。 +- FLEx 在 `range-element` 中的 `trait`/`field` 扩展 **会被** 报告(针对范围模式的模式错误):这些确实是规范偏差。 From 0761e776f82f7848260af535c5741c6a867a8e6d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:35 -0600 Subject: [PATCH 099/317] New translations validate.md (Hindi) [ci skip] --- docs/hi/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/hi/guides/validate.md diff --git a/docs/hi/guides/validate.md b/docs/hi/guides/validate.md new file mode 100644 index 0000000..718c402 --- /dev/null +++ b/docs/hi/guides/validate.md @@ -0,0 +1,36 @@ +# Validate + +Validation is always explicit — loading and saving never validate implicitly. + +```python +import sil_lift + +# Exhaustive: a lazy stream of Problems (schema + semantic layers). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches ... + +# Fail-fast: raises LiftValidationError on the first error-level problem. +sil_lift.validate_file("dictionary.lift") + +# In-memory state (serializes first — a documented cost on large lexicons): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Each `Problem` carries `level` (`"error"`/`"warning"`), a stable `code`, `message`, and an address: `file`, `entry_id`, `guid`, `line`. + +## The layers + +1. **RELAX NG** against the LIFT 0.13 grammar (vendored from lift-standard). +2. **Ranges schema** — this project's `lift-ranges-0.13.rng` — over every tracked `.lift-ranges` companion. +3. **Semantic checks** the grammar cannot express: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Real-world FieldWorks (FLEx) output + +FieldWorks systematically writes some content that strict tooling rejects. Here is sil-lift's policy, so that real lexicons validate usefully: + +- `file://C:/...` hrefs (invalid URIs) are reported as **warnings** (`uri-not-rfc`), not schema errors — the C# validator never rejected them. +- Legally interleaved children (e.g. `field, note, field, note` in a sense) are **not** flagged, working around a false positive in libxml2. +- Range values are compared under Unicode NFC normalization — FLEx writes the `.lift` in NFC but the `.lift-ranges` in NFD within the same export. +- FLEx's `trait`/`field` extensions inside `range-element` **are** reported (schema errors against the ranges schema): they are genuine spec deviations. From 2c9f710182015c259cce6a84e46c3982d19c82dc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:37 -0600 Subject: [PATCH 100/317] New translations validate.md (Swahili) [ci skip] --- docs/sw/guides/validate.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 docs/sw/guides/validate.md diff --git a/docs/sw/guides/validate.md b/docs/sw/guides/validate.md new file mode 100644 index 0000000..718c402 --- /dev/null +++ b/docs/sw/guides/validate.md @@ -0,0 +1,36 @@ +# Validate + +Validation is always explicit — loading and saving never validate implicitly. + +```python +import sil_lift + +# Exhaustive: a lazy stream of Problems (schema + semantic layers). +for problem in sil_lift.iter_problems("dictionary.lift"): + print(problem) + # error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches ... + +# Fail-fast: raises LiftValidationError on the first error-level problem. +sil_lift.validate_file("dictionary.lift") + +# In-memory state (serializes first — a documented cost on large lexicons): +lex = sil_lift.load("dictionary.lift") +problems = list(lex.iter_problems()) +``` + +Each `Problem` carries `level` (`"error"`/`"warning"`), a stable `code`, `message`, and an address: `file`, `entry_id`, `guid`, `line`. + +## The layers + +1. **RELAX NG** against the LIFT 0.13 grammar (vendored from lift-standard). +2. **Ranges schema** — this project's `lift-ranges-0.13.rng` — over every tracked `.lift-ranges` companion. +3. **Semantic checks** the grammar cannot express: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. + +## Real-world FieldWorks (FLEx) output + +FieldWorks systematically writes some content that strict tooling rejects. Here is sil-lift's policy, so that real lexicons validate usefully: + +- `file://C:/...` hrefs (invalid URIs) are reported as **warnings** (`uri-not-rfc`), not schema errors — the C# validator never rejected them. +- Legally interleaved children (e.g. `field, note, field, note` in a sense) are **not** flagged, working around a false positive in libxml2. +- Range values are compared under Unicode NFC normalization — FLEx writes the `.lift` in NFC but the `.lift-ranges` in NFD within the same export. +- FLEx's `trait`/`field` extensions inside `range-element` **are** reported (schema errors against the ranges schema): they are genuine spec deviations. From ecd09b568043a934887ccfd08d1f7609b696a48c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:38 -0600 Subject: [PATCH 101/317] New translations index.md (French) [ci skip] --- docs/fr/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/fr/index.md diff --git a/docs/fr/index.md b/docs/fr/index.md new file mode 100644 index 0000000..a65b0bc --- /dev/null +++ b/docs/fr/index.md @@ -0,0 +1,32 @@ +# sil-lift + +Bibliothèque Python pour [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13 : lecture/écriture sans perte du dossier LIFT (`.lift` + `.lift-ranges` + références multimédias), validation du schéma et de la sémantique, et tri canonique — avec des API de streaming pour les grands lexiques. + +**Statut : version préliminaire, en cours de développement.** + +## Installer + +Extrait de [PyPI](https://pypi.org/project/sil-lift/) : + +``` +pip install sil-lift # bibliothèque + la commande sil-lift +``` + +Nécessite Python 3.11 ou une version ultérieure. La seule dépendance d'exécution est lxml. + +## La visite guidée de 30 secondes + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # suit également les entrées associées aux plages .lift + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # ou lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # les entrées non modifiées restent identiques au niveau des octets ; l'entrée modifiée est resérialisée +``` From 194315a5cdc330f5a6ab371731c9deceeb47bf0c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:40 -0600 Subject: [PATCH 102/317] New translations index.md (Spanish) [ci skip] --- docs/es/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/es/index.md diff --git a/docs/es/index.md b/docs/es/index.md new file mode 100644 index 0000000..1703f92 --- /dev/null +++ b/docs/es/index.md @@ -0,0 +1,32 @@ +# sil-lift + +Una biblioteca de Python para [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: lectura y escritura sin pérdidas de la carpeta LIFT (`.lift` + `.lift-ranges` + referencias a medios), validación del esquema y semántica, y ordenación canónica, con API de streaming para léxicos de gran tamaño. + +**Estado: versión preliminar, en fase de desarrollo activo.** + +## Instalar + +De [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # biblioteca + el comando sil-lift +``` + +Requiere Python 3.11 o superior. La única dependencia de ejecución es lxml. + +## El recorrido de 30 segundos + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # también rastrea los términos asociados a los rangos .lift + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # o lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # las entradas no modificadas son idénticas a nivel de bytes; la entrada editada se vuelve a serializar +``` From daea3830dfccdb462933571b66b11ca2da85a1af Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:41 -0600 Subject: [PATCH 103/317] New translations index.md (Arabic) [ci skip] --- docs/ar/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/ar/index.md diff --git a/docs/ar/index.md b/docs/ar/index.md new file mode 100644 index 0000000..9792499 --- /dev/null +++ b/docs/ar/index.md @@ -0,0 +1,32 @@ +# سيل-ليفت + +مكتبة لغة بايثون لـ [LIFT](https://github.com/sillsdev/lift-standard) (تنسيق تبادل المعاجم) الإصدار 0.13: قراءة وكتابة ملفات مجلد LIFT دون فقدان البيانات (`.lift` + `.lift-ranges` + مراجع الوسائط)، والتحقق من صحة المخطط الدلالي والمعاني، والفرز القياسي — مع واجهات برمجة تطبيقات (API) للتدفق المباشر للمعاجم الكبيرة. + +**الحالة: إصدار تجريبي، قيد التطوير النشط.** + +## تثبيت + +من [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # المكتبة + الأمر sil-lift +``` + +يتطلب إصدار Python 3.11 أو أحدث. التبعية الوحيدة في وقت التشغيل هي lxml. + +## جولة مدتها 30 ثانية + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # يتتبع أيضًا المرادفات ذات النطاقات .lift + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # أو lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # المدخلات التي لم يتم تعديلها متطابقة من حيث البايتات؛ أما المدخلات التي تم تعديلها فقد أعيد تسلسلها +``` From cb05120f0720eae0771423c7bd23ac43991b96e9 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:43 -0600 Subject: [PATCH 104/317] New translations index.md (German) [ci skip] --- docs/de/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/de/index.md diff --git a/docs/de/index.md b/docs/de/index.md new file mode 100644 index 0000000..c6e3649 --- /dev/null +++ b/docs/de/index.md @@ -0,0 +1,32 @@ +# sil-lift + +Eine Python-Bibliothek für [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: verlustfreies Lesen und Schreiben des LIFT-Ordners (`.lift` + `.lift-ranges` + Medienverweise), Schema- und semantische Validierung sowie kanonische Sortierung – mit Streaming-APIs für große Lexika. + +**Status: Vorabversion, befindet sich in aktiver Entwicklung.** + +## Installieren + +Aus [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # Bibliothek + der Befehl „sil-lift“ +``` + +Erfordert Python 3.11 oder höher. Die einzige Laufzeitabhängigkeit ist lxml. + +## Die 30-Sekunden-Tour + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # erfasst auch Begleitbegriffe aus .lift-Bereichen + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # oder lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # Unveränderte Einträge sind byteweise identisch; bearbeitete Einträge werden neu serialisiert +``` From 472c5951ddce53a74b2c89049cf746d00fdad612 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:44 -0600 Subject: [PATCH 105/317] New translations index.md (Japanese) [ci skip] --- docs/ja/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/ja/index.md diff --git a/docs/ja/index.md b/docs/ja/index.md new file mode 100644 index 0000000..baadab1 --- /dev/null +++ b/docs/ja/index.md @@ -0,0 +1,32 @@ +# シルリフト + +[LIFT](https://github.com/sillsdev/lift-standard)(Lexicon Interchange Format)0.13 用の Python ライブラリ:LIFT フォルダ(`.lift` + `.lift-ranges` + メディア参照)のロスレスな読み書き、スキーマおよびセマンティック検証、正規ソート機能に加え、大規模な辞書向けのストリーミング API を備えています。 + +**ステータス:プレリリース版、現在開発中。** + +## インストール + +[PyPI](https://pypi.org/project/sil-lift/)より: + +``` +pip install sil-lift # ライブラリ + sil-lift コマンド +``` + +Python 3.11 以降が必要です。 実行時の依存関係は lxml のみです。 + +## 30秒のツアー + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # .lift-ranges のコンパニオンも追跡する + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # または lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # 変更のないエントリはバイト単位で同一のまま。編集されたエントリは再シリアル化される +``` From f49c1835748d467986f593d539fdbf1bc03e5663 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:46 -0600 Subject: [PATCH 106/317] New translations index.md (Portuguese) [ci skip] --- docs/pt/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/pt/index.md diff --git a/docs/pt/index.md b/docs/pt/index.md new file mode 100644 index 0000000..e4c922d --- /dev/null +++ b/docs/pt/index.md @@ -0,0 +1,32 @@ +# sil-lift + +Uma biblioteca Python para o [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: leitura e escrita sem perdas da pasta LIFT (`.lift` + `.lift-ranges` + referências de meios), validação do esquema e semântica, e ordenação canónica — com APIs de streaming para léxicos de grande dimensão. + +**Estado: pré-lançamento, em desenvolvimento ativo.** + +## Instalar + +Extraído do [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # biblioteca + o comando sil-lift +``` + +Requer o Python 3.11 ou superior. A única dependência de execução é o lxml. + +## A visita guiada de 30 segundos + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # também rastreia os companheiros dos intervalos .lift + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # ou lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # as entradas não alteradas mantêm-se idênticas em termos de bytes; a entrada editada é novamente serializada +``` From 09dfd73d4c924c756fabe6af5668b3b9a6da2fa6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:47 -0600 Subject: [PATCH 107/317] New translations index.md (Russian) [ci skip] --- docs/ru/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/ru/index.md diff --git a/docs/ru/index.md b/docs/ru/index.md new file mode 100644 index 0000000..a7e851a --- /dev/null +++ b/docs/ru/index.md @@ -0,0 +1,32 @@ +# sil-lift + +Библиотека Python для [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) версии 0.13: чтение и запись папки LIFT без потерь (файлы `.lift`, `.lift-ranges` и ссылки на медиафайлы), проверка соответствия схеме и семантике, а также каноническая сортировка — с потоковыми API для больших лексиконов. + +**Статус: предварительная версия, ведётся активная разработка.** + +## Установить + +С сайта [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # библиотека + команда sil-lift +``` + +Требуется Python версии 3.11 или выше. Единственной зависимостью на этапе выполнения является lxml. + +## 30-секундная экскурсия + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # также отслеживает сопутствующие элементы с расширениями .lift + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # или lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # неизменённые записи остаются байтово идентичными; отредактированная запись сериализуется заново +``` From 4ffc33717cad99e5ac488efe78b4b5a0f0ff0610 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:49 -0600 Subject: [PATCH 108/317] New translations index.md (Chinese Simplified) [ci skip] --- docs/zh/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/zh/index.md diff --git a/docs/zh/index.md b/docs/zh/index.md new file mode 100644 index 0000000..a907a75 --- /dev/null +++ b/docs/zh/index.md @@ -0,0 +1,32 @@ +# sil-lift + +一个用于 [LIFT](https://github.com/sillsdev/lift-standard)(词汇表交换格式)0.13 的 Python 库:支持 LIFT 文件夹(`.lift` + `.lift-ranges` + 媒体引用)的无损读写、模式和语义验证,以及规范排序——并为大型词汇表提供了流式 API。 + +**状态:预发布版,正在积极开发中。** + +## 安装 + +摘自 [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # 安装库及 sil-lift 命令 +``` + +需要 Python 3.11 及以上版本。 唯一的运行时依赖项是 lxml。 + +## 30秒导览 + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # 同时追踪 .lift-ranges 关联项 + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # 或 lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # 未修改的条目字节内容相同;已编辑的条目将重新序列化 +``` From 465b0082eeff38955a5599bdbd7cd269b8cc998b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:50 -0600 Subject: [PATCH 109/317] New translations index.md (Hindi) [ci skip] --- docs/hi/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/hi/index.md diff --git a/docs/hi/index.md b/docs/hi/index.md new file mode 100644 index 0000000..c30b999 --- /dev/null +++ b/docs/hi/index.md @@ -0,0 +1,32 @@ +# सिल-लिफ्ट + +[LIFT](https://github.com/sillsdev/lift-standard) (लेक्सिकन इंटरचेंज फॉर्मेट) 0.13 के लिए एक पाइथन लाइब्रेरी: LIFT फ़ोल्डर (`.lift` + `.lift-ranges` + मीडिया संदर्भ) का बिना हानि के रीड/राइट, स्कीमा और सेमांटिक सत्यापन, तथा कैनोनिकल सॉर्टिंग — बड़े लेक्सिकन के लिए स्ट्रीमिंग एपीआई के साथ। + +स्थिति: प्री-रिलीज़, सक्रिय विकास के अधीन। + +## स्थापित करें + +[PyPI](https://pypi.org/project/sil-lift/) से: + +``` +pip install sil-lift # लाइब्रेरी + sil-lift कमांड +``` + +पाइथन 3.11+ आवश्यक है। एकमात्र रनटाइम निर्भरता lxml है। + +## 30-सेकंड का दौरा + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # tracks .lift-ranges companions too + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # या lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (शरीर रचना)" + +lex.save() # बिना छुए प्रविष्टियाँ बाइट-समान; संपादित प्रविष्टि पुनः सीरियलाइज़्ड +``` From 3975b1ef8344851028f6df3a5adf2087d67f9b6d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:52 -0600 Subject: [PATCH 110/317] New translations index.md (Swahili) [ci skip] --- docs/sw/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 docs/sw/index.md diff --git a/docs/sw/index.md b/docs/sw/index.md new file mode 100644 index 0000000..e6e9923 --- /dev/null +++ b/docs/sw/index.md @@ -0,0 +1,32 @@ +# sil-lift + +A Python library for [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: lossless read/write of the LIFT folder (`.lift` + `.lift-ranges` + media references), schema and semantic validation, and canonical sorting — with streaming APIs for large lexicons. + +**Status: pre-release, under active development.** + +## Install + +From [PyPI](https://pypi.org/project/sil-lift/): + +``` +pip install sil-lift # library + the sil-lift command +``` + +Requires Python 3.11+. The only runtime dependency is lxml. + +## The 30-second tour + +```python +import sil_lift + +lex = sil_lift.load("thesaurus.lift") # tracks .lift-ranges companions too + +for entry in lex.entries: + if "en" not in entry.gloss_langs(): + print(entry.id, str(entry.lexical_unit.get("seh") or "")) + +entry = lex.find(guid="0f5a9c3e-...") # or lex.find(id="hoofd_a1b2") +entry.senses[0].definition["en"] = "head (anatomy)" + +lex.save() # untouched entries byte-identical; edited entry re-serialized +``` From fb790473c69e7b093e06daf717975a2b8d2b6086 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:53 -0600 Subject: [PATCH 111/317] New translations reference.md (French) [ci skip] --- docs/fr/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/fr/reference.md diff --git a/docs/fr/reference.md b/docs/fr/reference.md new file mode 100644 index 0000000..58b2986 --- /dev/null +++ b/docs/fr/reference.md @@ -0,0 +1,9 @@ +# Référence de l'API + +L'API publique correspond exactement à ce que `sil_lift` réexporte au niveau supérieur ; les modules préfixés par un trait de soulignement relèvent des détails d'implémentation. + +::: sil_lift +options : +show_root_heading : false +show_source : false +members_order : source From f1a7b6a95ec96c21e8032abd3d725e018ca040ec Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:55 -0600 Subject: [PATCH 112/317] New translations reference.md (Spanish) [ci skip] --- docs/es/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/es/reference.md diff --git a/docs/es/reference.md b/docs/es/reference.md new file mode 100644 index 0000000..bf824cb --- /dev/null +++ b/docs/es/reference.md @@ -0,0 +1,9 @@ +# Referencia de la API + +La API pública es exactamente lo que `sil_lift` reexporta en el nivel superior; los módulos con el prefijo «_» son detalles de implementación. + +::: sil_lift +opciones: +mostrar_título_raíz: false +mostrar_fuente: false +orden_miembros: fuente From 5c2cb54b73ad62ef3d0e31bba95e94894caeb09e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:56 -0600 Subject: [PATCH 113/317] New translations reference.md (Arabic) [ci skip] --- docs/ar/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/ar/reference.md diff --git a/docs/ar/reference.md b/docs/ar/reference.md new file mode 100644 index 0000000..714761a --- /dev/null +++ b/docs/ar/reference.md @@ -0,0 +1,9 @@ +# مرجع واجهة برمجة التطبيقات (API) + +واجهة برمجة التطبيقات العامة (API) هي بالضبط ما يعيد `sil_lift` تصديره على المستوى الأعلى؛ أما الوحدات النمطية التي تبدأ بعلامة التسطير السفلي فهي تفاصيل تتعلق بالتنفيذ. + +::: sil_lift +options: +show_root_heading: false +show_source: false +members_order: source From 0f12ad247f73dc2ba6a040d5c76cb03a3b73def3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:58 -0600 Subject: [PATCH 114/317] New translations reference.md (German) [ci skip] --- docs/de/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/de/reference.md diff --git a/docs/de/reference.md b/docs/de/reference.md new file mode 100644 index 0000000..c82ad48 --- /dev/null +++ b/docs/de/reference.md @@ -0,0 +1,9 @@ +# API-Referenz + +Die öffentliche API entspricht genau dem, was `sil_lift` auf der obersten Ebene erneut exportiert; Module mit einem Unterstrich als Präfix sind Implementierungsdetails. + +::: sil_lift +options: +show_root_heading: false +show_source: false +members_order: source From ed9fdad16d2cb31682bce0ba0df476c69dbe6131 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:20:59 -0600 Subject: [PATCH 115/317] New translations reference.md (Japanese) [ci skip] --- docs/ja/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/ja/reference.md diff --git a/docs/ja/reference.md b/docs/ja/reference.md new file mode 100644 index 0000000..34eba16 --- /dev/null +++ b/docs/ja/reference.md @@ -0,0 +1,9 @@ +# APIリファレンス + +パブリックAPIとは、まさに`sil_lift`が最上位レベルで再エクスポートしているものであり、アンダースコアで始まるモジュールは実装上の詳細です。 + +::: sil_lift +options: +show_root_heading: false +show_source: false +members_order: source From f7c2d96b71d809ab6760ef4010250b05f7f08df8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:21:00 -0600 Subject: [PATCH 116/317] New translations reference.md (Portuguese) [ci skip] --- docs/pt/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/pt/reference.md diff --git a/docs/pt/reference.md b/docs/pt/reference.md new file mode 100644 index 0000000..de8544b --- /dev/null +++ b/docs/pt/reference.md @@ -0,0 +1,9 @@ +# Referência da API + +A API pública é exatamente o que o `sil_lift` reexporta ao nível superior; os módulos com o prefixo «_» são detalhes de implementação. + +::: sil_lift +options: +show_root_heading: false +show_source: false +members_order: source From 22dbbd3564e7637c5bc73ea9a6ca814385254429 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:21:02 -0600 Subject: [PATCH 117/317] New translations reference.md (Russian) [ci skip] --- docs/ru/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/ru/reference.md diff --git a/docs/ru/reference.md b/docs/ru/reference.md new file mode 100644 index 0000000..e2fa4d0 --- /dev/null +++ b/docs/ru/reference.md @@ -0,0 +1,9 @@ +# Справочник по API + +Публичный API — это именно то, что `sil_lift` реэкспортирует на верхнем уровне; модули с префиксом «_» относятся к деталям реализации. + +::: sil_lift +options: +show_root_heading: false +show_source: false +members_order: source From ff10e1778ea7cfaa7288242799191124a407c422 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:21:03 -0600 Subject: [PATCH 118/317] New translations reference.md (Chinese Simplified) [ci skip] --- docs/zh/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/zh/reference.md diff --git a/docs/zh/reference.md b/docs/zh/reference.md new file mode 100644 index 0000000..f1151a4 --- /dev/null +++ b/docs/zh/reference.md @@ -0,0 +1,9 @@ +# API 参考文档 + +公共 API 正是 `sil_lift` 在顶层重新导出的内容;以下划线为前缀的模块属于实现细节。 + +::: sil_lift +选项: +show_root_heading: false +show_source: false +members_order: source From 47ad00e50e1ddd20f55f67226abac0181e92fe4c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:21:05 -0600 Subject: [PATCH 119/317] New translations reference.md (Hindi) [ci skip] --- docs/hi/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/hi/reference.md diff --git a/docs/hi/reference.md b/docs/hi/reference.md new file mode 100644 index 0000000..b49e3d8 --- /dev/null +++ b/docs/hi/reference.md @@ -0,0 +1,9 @@ +# एपीआई संदर्भ + +सार्वजनिक एपीआई बिल्कुल वही है जिसे `sil_lift` शीर्ष स्तर पर पुनः निर्यात करता है; अंडरस्कोर-पूर्वप्रत्यय वाले मॉड्यूल कार्यान्वयन विवरण हैं। + +::: sil_lift +विकल्प: +show_root_heading: false +show_source: false +सदस्यों_क्रम: स्रोत From 8311ef17b87914d1fea1dcfbef9c6d4a03ad9833 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 28 Jul 2026 11:21:06 -0600 Subject: [PATCH 120/317] New translations reference.md (Swahili) [ci skip] --- docs/sw/reference.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/sw/reference.md diff --git a/docs/sw/reference.md b/docs/sw/reference.md new file mode 100644 index 0000000..445d00a --- /dev/null +++ b/docs/sw/reference.md @@ -0,0 +1,9 @@ +# Rejea ya API + +API ya umma ni hasa kile `sil_lift` inachore-eksporti katika ngazi ya juu; moduli zilizo na viambishi awali vya 'underscore' ni maelezo ya utekelezaji. + +::: sil_lift +chaguzi: +show_root_heading: false +show_source: false +members_order: source From 5af314097bf9535bc2f1be3bdea4909df205ed0c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:39 -0600 Subject: [PATCH 121/317] New translations csharp-differences.md (French) [ci skip] --- docs/fr/csharp-differences.md | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/fr/csharp-differences.md b/docs/fr/csharp-differences.md index 39dd18a..6c8187d 100644 --- a/docs/fr/csharp-differences.md +++ b/docs/fr/csharp-differences.md @@ -4,49 +4,49 @@ sil-lift s'apparente vaguement aux outils LIFT de SIL en C# — principalement ` ## Champ d'application -| Capacité | Bibliothèques C# | sil-lift | -| -------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | -| Versions de LIFT | 0,10–0,13 (migration intégrée) | **0.13 uniquement** ; les versions antérieures sont rejetées et génèrent une erreur claire | -| Migration de version | `Migrator` (chaîne XSLT) | aucun — utiliser les fichiers XSLT du répertoire « lift-standard » pour les mises à jour ponctuelles | -| Fusion / synchronisation à trois voies | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| Capacité | Bibliothèques C# | sil-lift | +| -------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| Versions de LIFT | 0,10–0,13 (migration intégrée) | **0.13 uniquement** ; les versions antérieures sont rejetées et génèrent une erreur claire | +| Migration de version | `Migrator` (chaîne XSLT) | aucun — utiliser les fichiers XSLT du répertoire « lift-standard » pour les mises à jour ponctuelles | +| Fusion / synchronisation à trois voies | Refrain | hors du champ d'application | +| Validation | RELAX NG uniquement (`Validator`) | RELAX NG + vérifications du schéma et de la sémantique | +| Streaming | analyse syntaxique interne à granularité d'entrée | API publique `open_reader` / `open_writer` | -## API shape +## Forme de l'API -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +Le parseur de `SIL.Lift` fonctionne par callbacks (`ILexiconMerger`) : il transmet les événements d'analyse à un consommateur. sil-lift renvoie en revanche un simple graphe d'objets — des classes de données typées pour chaque élément LIFT — car les développeurs Python souhaitent des objets, et non des callbacks. `SIL.DictionaryServices` superpose effectivement un modèle d'objets `LexEntry`/`LexSense` à `SIL.Lift`, mais en tant que modèle d’application, il ne représente que les constructions utilisées par ces applications — par conséquent, la resérialisation via ce modèle ne permet pas de préserver le contenu hors modèle de la même manière que le font la capture des résidus et la fidélité au niveau des octets de sil-lift (voir ci-dessous). L'API de streaming renvoie le _même_ type `Entry` ; il n'existe donc pas de modèle jumeau aux capacités réduites. -## Round-trip fidelity +## Fidélité aller-retour -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +La différence la plus marquée et la plus délibérée. L'enregistrement avec `SIL.Lift` entraîne la resérialisation de l'intégralité du document. sil-lift garantit : -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- un document inchangé est enregistré **avec une taille en octets identique**, et +- Les entrées non modifiées conservent exactement les mêmes octets source, même lorsque d'autres entrées changent (segmentation en blocs d'octets de type « Chorus », appliquée automatiquement). -See [Fidelity guarantees](fidelity.md). +Consultez les [garanties de fidélité](fidelity.md). ## Validation -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +Le `Validator` C# effectue un passage RELAX NG et renvoie les premières erreurs sous forme de chaînes de caractères. sil-lift déclare un flux « Problem » structuré, avec adressage par entrée/ligne, et sa couche de schéma présente sciemment trois divergences : -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **Les URI non valides constituent des avertissements, et non des erreurs.** Le moteur RELAX NG de C# n'a jamais imposé le type de données `anyURI` ; c'est pourquoi FieldWorks (FLEx) insère depuis des années des liens `file://C:/...` dans des lexiques réels. Le rejet de ces fichiers entraînerait le marquage de pratiquement toutes les exportations FLEx. +- **Les règles Schematron sont appliquées** (sous forme de vérifications sémantiques) : les langages de formulaire en double et les co-contraintes similaires présentes dans la grammaire LIFT étaient ignorés sans avertissement tant par la validation en C# que par celle effectuée directement avec lxml. +- **Les comparaisons entre fichiers sont normalisées selon la norme Unicode**, car FLEx enregistre le fichier `.lift` en NFC et le fichier associé `.lift-ranges` en NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift valide également les fichiers `.lift-ranges` associés à un lexique chargé par rapport à un schéma destiné aux documents de plages autonomes (fourni par `lift-standard` avec la grammaire LIFT de base) — chaque fichier de plages externe suivi est vérifié à chaque validation du `.lift` — alors qu’il n’existe aucun schéma (ni vérification) de ce type dans l’univers C#. (Il n'existe aucun moyen de valider un fichier `.lift-ranges` isolément, sans qu'il soit associé à un fichier `.lift`.) -## Canonical sorting +## Tri canonique -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +La méthode `Lexicon.sort()` reprend les règles fondamentales de `LiftSorter` (entrées classées par GUID sans distinction de majuscules/minuscules ; plages et éléments de plage classés par ID ; définitions des champs d'en-tête classées par balise ; sens conservés dans l'ordre du fichier ; espaces à l'intérieur de `` jamais modifiés), à trois différences près : -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- Les entrées sans GUID sont triées de manière déterministe par ID (la classe `LiftSorter` part du principe qu'un GUID est présent) ; +- l'ordre est indépendant des paramètres régionaux (points de code sans distinction de casse, et non le classement « invariant-culture » de .NET) ; +- Les listes de même type, telles que les notes, les relations et les formulaires, conservent leur ordre d'origine dans le document au lieu d'être triées à nouveau par clé — le regroupement est déjà déterministe, et les réorganiser ne ferait qu'ajouter du bruit aux différences. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +Le fichier `canonicalizeLift.xsl` du dépôt de spécifications n'est absolument pas utilisé : il supprime les espaces blancs à l'intérieur du texte lexical (opération destructive) et les identifiants qu'il génère varient à chaque exécution. -## Not carried over +## Non reporté -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- Fonctionnalités spécifiques à WeSay (tableau de bord / gestion des paramètres liés aux fichiers LIFT). +- `SynchronicMerger` (fusion des mises à jour Chorus) — le principe du découpage en blocs d'octets est conservé dans la couche de fidélité, mais pas celui de la fusion. +- Analyse syntaxique du système d'écriture LDML : les fichiers situés dans le répertoire `WritingSystems/` sont considérés comme du contenu de dossier opaque. From 0ab7e64032709655b7a02fa1fc1de8f63fb9cc75 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:41 -0600 Subject: [PATCH 122/317] New translations csharp-differences.md (Spanish) [ci skip] --- docs/es/csharp-differences.md | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/es/csharp-differences.md b/docs/es/csharp-differences.md index 506f1d2..5e2a367 100644 --- a/docs/es/csharp-differences.md +++ b/docs/es/csharp-differences.md @@ -4,49 +4,49 @@ sil-lift es, a grandes rasgos, análogo a las herramientas LIFT de SIL para C# ## Ámbito de aplicación -| Capacidad | Bibliotecas de C# | sil-lift | -| ----------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------- | -| Versiones de LIFT | 0,10–0,13 (migración incluida) | **Solo 0,13**; las versiones anteriores se rechazan con un error claro | -| Migración de versiones | `Migrator` (cadena XSLT) | ninguna — utiliza los XSLT de «lift-standard» para actualizaciones puntuales | -| Fusión/sincronización a tres bandas | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| Capacidad | Bibliotecas de C# | sil-lift | +| ----------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------- | +| Versiones de LIFT | 0,10–0,13 (migración incluida) | **Solo 0,13**; las versiones anteriores se rechazan con un error claro | +| Migración de versiones | `Migrator` (cadena XSLT) | ninguna — utiliza los XSLT de «lift-standard» para actualizaciones puntuales | +| Fusión/sincronización a tres bandas | Estribillo | fuera del ámbito de aplicación | +| Validación | Solo RELAX NG (`Validator`) | RELAX NG + comprobaciones de esquema y semánticas | +| Streaming | análisis sintáctico interno con granularidad de entrada | API pública `open_reader` / `open_writer` | -## API shape +## Formato de la API -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +El analizador de `SIL.Lift` funciona mediante callbacks (`ILexiconMerger`): envía eventos de análisis a un consumidor. En cambio, sil-lift devuelve un grafo de objetos simple —clases de datos tipadas para cada elemento LIFT—, ya que los programadores de Python quieren objetos, no funciones de devolución de llamada. `SIL.DictionaryServices` superpone un modelo de objetos `LexEntry`/`LexSense` sobre `SIL.Lift`, pero, como modelo de aplicación, solo representa las construcciones que utilizan esas aplicaciones; por lo tanto, la reserialización a través de él no puede conservar el contenido ajeno al modelo de la misma forma que lo hacen la captura de residuos y la fidelidad de bytes de sil-lift (véase más abajo). La API de streaming devuelve el _mismo_ tipo `Entry`, por lo que no existe un modelo equivalente con capacidades reducidas. -## Round-trip fidelity +## Fidelidad de ida y vuelta -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +La diferencia más marcada y deliberada. Al guardar con `SIL.Lift`, se vuelve a serializar todo el documento. sil-lift garantiza: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- un documento que no ha sufrido modificaciones se guarda **con los mismos bytes**, y +- Las entradas que no se modifican conservan sus bytes de origen exactos, incluso cuando cambian otras entradas (división en bloques de bytes de nivel «Chorus», aplicada automáticamente). -See [Fidelity guarantees](fidelity.md). +Consulta [las garantías de Fidelity](fidelity.md). -## Validation +## Validación -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +El `Validator` de C# ejecuta una pasada de RELAX NG y devuelve los primeros errores en forma de cadenas de caracteres. sil-lift describe un flujo «Problem» estructurado, con entradas y direcciones de línea, y su capa de esquema presenta tres divergencias deliberadas: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **Los URI no válidos son advertencias, no errores.** El motor RELAX NG de C# nunca ha aplicado el tipo de datos `anyURI`, por lo que FieldWorks (FLEx) lleva años incluyendo enlaces `file://C:/...` en léxicos reales. Si se rechazaran esos archivos, se marcarían prácticamente todas las exportaciones de FLEx. +- **Se aplican las reglas de Schematron** (como comprobaciones semánticas): tanto la validación en C# como la validación directa con lxml ignoraban silenciosamente los lenguajes de formulario duplicados y las coconstricciones similares en la gramática LIFT. +- **Las comparaciones entre archivos están normalizadas según Unicode**, ya que FLEx guarda el archivo `.lift` en NFC y el archivo complementario `.lift-ranges` en NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift también valida los archivos complementarios `.lift-ranges` de un léxico cargado comparándolos con un esquema para documentos de rangos independientes (proporcionado por `lift-standard` junto con la gramática LIFT básica) — cada archivo de rangos externo del que se realiza un seguimiento se comprueba cada vez que se valida el `.lift` — sin que exista dicho esquema (ni dicha comprobación) en el entorno de C#. (No existe ningún punto de entrada para validar un archivo `.lift-ranges` por sí solo, sin estar vinculado a un archivo `.lift`.) -## Canonical sorting +## Ordenación canónica -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` refleja las reglas básicas de `LiftSorter` (las entradas se ordenan por GUID sin distinguir entre mayúsculas y minúsculas; los rangos y los elementos de los rangos, por ID; las definiciones de los campos de encabezado, por etiqueta; los significados se mantienen en el orden del archivo; los espacios en blanco dentro de `` nunca se modifican), con tres diferencias: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- Las entradas sin un GUID se ordenan de forma determinista por ID (`LiftSorter` da por hecho que existe un GUID); +- el orden es independiente de la configuración regional (puntos de código con mayúsculas y minúsculas ignoradas, no la clasificación de «cultura invariante» de .NET); +- Las listas del mismo tipo, como notas, relaciones y formularios, mantienen el orden del documento en lugar de volver a ordenarse por clave; la agrupación ya es determinista, y reordenarlas solo añade ruido a las diferencias. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +El archivo `canonicalizeLift.xsl` del repositorio de especificaciones no se utiliza en absoluto: elimina los espacios en blanco dentro del texto léxico (de forma destructiva) y los identificadores que genera varían en cada ejecución. -## Not carried over +## No se ha trasladado -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- Funcionalidades específicas de WeSay (panel de control y gestión de la configuración relacionada con los archivos LIFT). +- `SynchronicMerger` (fusión de actualizaciones de Chorus): la idea de la segmentación en bloques de bytes se mantiene en la capa de fidelidad, pero la fusión no. +- Análisis sintáctico del sistema de escritura LDML: los archivos de la carpeta `WritingSystems/` se tratan como contenido opaco de la carpeta. From 79935f6e1acdd4b7de631557cb1c43c792dc09c4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:43 -0600 Subject: [PATCH 123/317] New translations csharp-differences.md (Arabic) [ci skip] --- docs/ar/csharp-differences.md | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/ar/csharp-differences.md b/docs/ar/csharp-differences.md index 567c2bb..160c1c5 100644 --- a/docs/ar/csharp-differences.md +++ b/docs/ar/csharp-differences.md @@ -8,45 +8,45 @@ | ----------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | إصدارات LIFT | 0.10–0.13 (مع ميزة الترحيل المدمجة) | **0.13 فقط**؛ يتم رفض الإصدارات الأقدم مع ظهور خطأ واضح | | ترحيل الإصدار | `Migrator` (سلسلة XSLT) | لا شيء — استخدم ملفات XSLT الموجودة في «lift-standard» لإجراء عمليات الترقية لمرة واحدة | -| دمج/مزامنة ثلاثية | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| دمج/مزامنة ثلاثية | الكورس | خارج النطاق | +| التحقق من الصحة | RELAX NG فقط (`Validator`) | RELAX NG + نطاقات المخطط + الفحوصات الدلالية | +| البث المباشر | التحليل الداخلي على مستوى العناصر الفردية | واجهة برمجة التطبيقات العامة `open_reader` / `open_writer` | -## API shape +## شكل واجهة برمجة التطبيقات (API) -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +يعمل محلل `SIL.Lift` على أساس آلية الاستدعاء المرتد (`ILexiconMerger`): فهو يقوم بدفع أحداث التحليل إلى المستلم. بدلاً من ذلك، تُرجع «sil-lift» مخطط كائنات عادي — فئات بيانات مُحددة النوع لكل عنصر من عناصر LIFT — لأن مبرمجي بايثون يفضلون الكائنات، وليس دالات الاستدعاء. تقوم `SIL.DictionaryServices` بتركيب نموذج كائنات `LexEntry`/`LexSense` فوق `SIL.Lift`، ولكنه كنموذج تطبيق لا يمثل سوى البنيات التي تستخدمها تلك التطبيقات — لذا فإن إعادة التسلسل من خلاله لا يمكنها الحفاظ على المحتوى خارج النموذج بالطريقة التي تقوم بها ميزة التقاط البقايا ودقة البايت في sil-lift (انظر أدناه). تُنتج واجهة برمجة التطبيقات (API) الخاصة بالتدفق النوع _نفسه_ من `Entry`، لذا لا يوجد نموذج توأمي محدود القدرات. -## Round-trip fidelity +## دقة النقل في كلا الاتجاهين -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +أقوى اختلاف متعمد. يؤدي الحفظ باستخدام `SIL.Lift` إلى إعادة تسلسل المستند بأكمله. تضمن شركة «سيل-ليفت» ما يلي: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- يتم حفظ المستند الذي لم يطرأ عليه تغيير **بشكل مطابق تمامًا من حيث البايتات**، و +- تحتفظ الإدخالات التي لم يتم التعديل عليها ببايتات المصدر الدقيقة الخاصة بها حتى عند تغير الإدخالات الأخرى (تقسيم البايتات على مستوى «Chorus»، يُطبق تلقائيًا). -See [Fidelity guarantees](fidelity.md). +انظر [ضمانات فيديليتي](fidelity.md). -## Validation +## التحقق من الصحة -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +يقوم `Validator` في لغة C# بتنفيذ دورة واحدة من RELAX NG ويُبلغ عن الأخطاء الأولى في شكل سلاسل نصية. تُبلغ sil-lift عن دفق «مشكلة» منظم ومُحدد حسب الإدخال/السطر، وتختلف طبقة مخططها عن قصد في ثلاثة مواضع: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **عناوين URI غير الصالحة تُعتبر تحذيرات وليست أخطاء.** لم يفرض محرك C# RELAX NG أبدًا نوع البيانات `anyURI`، لذا ظل برنامج FieldWorks (FLEx) لسنوات عديدة يدرج روابط href من النوع `file://C:/...` في المعاجم الفعلية. إن رفض تلك الملفات سيؤدي إلى وضع علامة على كل ملفات التصدير من FLEx تقريبًا. +- **يتم تطبيق قواعد Schematron** (كعمليات تدقيق دلالية): تم تجاهل لغات النماذج المكررة والقيود المشتركة المماثلة في قواعد LIFT دون إشعار من قبل كل من عملية التحقق من صحة C# وعملية التحقق من صحة lxml الخام. +- **يتم توحيد المقارنات بين الملفات وفقًا لمعايير يونيكود**، لأن برنامج FLEx يكتب ملف `.lift` بتنسيق NFC، بينما يكتب الملف المصاحب `.lift-ranges` بتنسيق NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +يقوم sil-lift أيضًا بالتحقق من صحة الملفات المصاحبة `.lift-ranges` الخاصة بالمعجم الذي تم تحميله، مقارنةً بمخطط خاص بوثائق النطاقات المستقلة (المقدمة من `lift-standard` جنبًا إلى جنب مع قواعد LIFT الأساسية) — يتم فحص كل ملف نطاقات خارجي يتم تتبعه عند كل عملية التحقق من صحة ملف `.lift` — في حين لا يوجد مثل هذا المخطط (أو الفحص) في بيئة C#. (لا توجد نقطة دخول للتحقق من صحة ملف `.lift-ranges` بمفرده، بمعزل عن ملف `.lift`.) -## Canonical sorting +## الترتيب القياسي -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +تعكس دالة `Lexicon.sort()` القواعد الأساسية لـ `LiftSorter` (المدخلات حسب معرّف فريد (GUID) دون التمييز بين الأحرف الكبيرة والصغيرة؛ النطاقات وعناصر النطاقات حسب المعرّف (ID)؛ تعريفات حقول الرؤوس حسب العلامة (tag)؛ يتم الحفاظ على المعاني حسب ترتيبها في الملف؛ ولا يتم المساس أبدًا بالمسافات البيضاء داخل ``)، مع وجود ثلاثة اختلافات: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- يتم فرز الإدخالات التي لا تحتوي على معرّف فريد (GUID) بشكل حتمي حسب المعرّف (ID) (يفترض `LiftSorter` وجود معرّف فريد (GUID))؛ +- الترتيب مستقل عن الإعدادات المحلية (نقاط الرموز بعد إزالة التمييز بين الأحرف الكبيرة والصغيرة، وليس ترتيب .NET المستقل عن الثقافة)؛ +- تحتفظ القوائم من نفس النوع — مثل الملاحظات والعلاقات والنماذج — بترتيبها في المستند بدلاً من إعادة فرزها حسب المفتاح — فالترتيب في مجموعات أمر حتمي بالفعل، وإعادة ترتيبها لا يؤدي إلا إلى زيادة التشويش في ملفات المقارنة. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +لا يتم استخدام ملف `canonicalizeLift.xsl` الموجود في مستودع المواصفات على الإطلاق: فهو يدمج المسافات البيضاء داخل النص اللغوي (عملية تدميرية)، كما أن المعرّفات التي يولدها تختلف في كل عملية تشغيل. -## Not carried over +## لم يتم ترحيله -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- الميزات الخاصة بـ WeSay (لوحة التحكم/إدارة الإعدادات المتعلقة بملفات LIFT). +- `SynchronicMerger` (دمج تحديثات Chorus) — فكرة تقسيم البيانات إلى مقاطع بايت لا تزال قائمة في طبقة الدقة، أما عملية الدمج فلم تعد موجودة. +- تحليل نظام الكتابة LDML: تُعامل الملفات الموجودة في `WritingSystems/` على أنها محتوى مجلد غير شفاف. From ccf745aa5201fb882d93d23a5b1ace54bf34aac6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:45 -0600 Subject: [PATCH 124/317] New translations fidelity.md (Spanish) [ci skip] --- docs/es/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/es/fidelity.md b/docs/es/fidelity.md index bb4e858..666fe84 100644 --- a/docs/es/fidelity.md +++ b/docs/es/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# Garantías de Fidelity -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT es un formato de _intercambio_: la regla fundamental es **no descartar nunca lo que no se entiende**. El contrato de `sil-lift`, verificado por el conjunto de pruebas en cada ejecución (archivos del corpus más generación basada en propiedades): -## Reading +## Lectura -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +Cualquier documento LIFT 0.13 bien formado se carga, incluso si el contenido no cumple con el esquema. Todo aquello que el modelo no defina se almacena en el contenedor opaco `Extras` del nodo más cercano: atributos y elementos desconocidos, comentarios XML e instrucciones de procesamiento, texto aislado y atributos tipados con formato incorrecto (una fecha incorrecta se mantiene como la cadena original en `Extras`; el campo tipado es `None`). -## Saving an unchanged document +## Guardar un documento sin modificaciones -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()` sin modificaciones genera una **salida idéntica a nivel de bytes**: sin reformateo, sin reescapado, sin reordenación, incluyendo las marcas de orden de bytes y las declaraciones XML. Actualmente no hay ninguna lista de normalización: la identidad es exacta. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +Excepciones (el escritor recurre a la serialización canónica completa, que es semánticamente completa pero no conserva los bytes): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- la codificación de origen no es compatible con ASCII (no es UTF-8/US-ASCII), o +- el código fuente contiene un DOCTYPE, o +- el escáner de bytes y el analizador sintáctico no coinciden en cuanto a la estructura de nivel superior del documento —por ejemplo, un segundo `
` que no cumple con la especificación, que el analizador sintáctico conserva solo una vez (el escáner es deliberadamente cauteloso: ante cualquier duda, no captura ningún byte del código fuente)—, o +- El código fuente se compiló en memoria, en lugar de cargarse desde un archivo. -## Saving an edited document +## Guardar un documento editado -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **Las entradas no modificadas se emiten tal cual, a partir de sus bytes originales.** Una entrada se considera modificada si alguna parte de su objeto de modelo ha cambiado desde el análisis (lo cual se detecta mediante una instantánea de serialización canónica, no mediante un indicador de cambios). +- **Las entradas modificadas se vuelven a serializar de forma canónica y completa**: UTF-8, sangría de 2 espacios _fuera_ del contenido mixto (los espacios en blanco dentro de `` y `` nunca se modifican), una agrupación de elementos secundarios documentada por cada elemento (p. ej., entrada: unidad léxica, cita, pronunciaciones, variantes, acepciones, notas, relaciones, etimologías, anotaciones, rasgos, campos), orden fijo de los atributos, fechas en formato ISO-8601 (`Z` para UTC). Todos los residuos se vuelven a emitir; su posición se restablece en el índice secundario original, vinculada a la nueva lista secundaria (se trata de una aproximación: las posiciones exactas en bytes solo se garantizan para las entradas que no se han modificado). +- Al añadir, eliminar o reordenar entradas, se vuelve a serializar la estructura del documento, pero se siguen emitiendo tal cual los bytes de cada entrada que no haya sufrido cambios. -## Known approximations (touched nodes only) +## Aproximaciones conocidas (solo nodos tocados) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- Los comentarios que se encuentran _dentro_ de una ejecución de `` se conservan, pero se desplazan hasta situarse junto a la ejecución, y no en su posición exacta según el número de caracteres. +- El orden de subelementos de tipo «cross» dentro de un elemento editado se normaliza según la agrupación canónica (la propiedad `interleave` del esquema LIFT hace que este orden carezca de importancia semántica). +- Un elemento multitexto que está presente pero que no contiene nada —ni formas, ni residuos—, por ejemplo, ``, no se vuelve a emitir. El modelo representa estos campos como un `Multitext` siempre presente (`lexical-unit`, `citation`, `definition`, el `usage` de una relación y `label` / `abreviatura` / `descripción` en referencias URL, rangos, elementos de rango y el encabezado), por lo que uno vacío es indistinguible de uno ausente tras el análisis sintáctico. No se pierde nada a nivel semántico. From 0dabc0418833c5d3e9a7b79d8cf7efe7de19a85a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:47 -0600 Subject: [PATCH 125/317] New translations fidelity.md (Arabic) [ci skip] --- docs/ar/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/ar/fidelity.md b/docs/ar/fidelity.md index bb4e858..fe799a7 100644 --- a/docs/ar/fidelity.md +++ b/docs/ar/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# ضمانات فيديليتي -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT هو تنسيق _تبادل_: والقاعدة الأساسية هي **ألا تتجاهل أبدًا ما لا تفهمه**. عقد `sil-lift`، الذي يتم التحقق من صحته بواسطة مجموعة الاختبارات في كل عملية تشغيل (ملفات المجموعة بالإضافة إلى التوليد القائم على الخصائص): -## Reading +## القراءة -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +يتم تحميل أي مستند LIFT 0.13 صحيح التكوين — بما في ذلك المحتوى غير المتوافق مع المخطط. كل ما لا يحدده النموذج يتم نقله إلى حاوية `Extras` غير الشفافة في أقرب عقدة: السمات والعناصر غير المعروفة، وتعليقات XML وتعليمات المعالجة، والنصوص المتناثرة، والسمات المحددة النوع ذات التنسيق الخاطئ (يُحتفظ بالتاريخ غير الصحيح كسلسلة نصية أصلية في `Extras`؛ ويكون الحقل المحدد النوع هو `None`). -## Saving an unchanged document +## حفظ مستند لم يتم تغييره -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +تؤدي وظيفة `load()` → `save()` دون إجراء أي تعديلات إلى كتابة **مخرجات متطابقة على مستوى البايت** — دون إعادة تنسيق، أو إعادة ترميز، أو إعادة ترتيب، مع تضمين علامات ترتيب البايت وإعلانات XML. لا توجد حاليًا قائمة تطبيع: الهوية دقيقة. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +الاستثناءات (يلجأ الكاتب إلى التسلسل القياسي الكامل، الذي يعتبر كاملاً من الناحية الدلالية ولكنه لا يحافظ على البايتات): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- ترميز المصدر غير متوافق مع ASCII (ليس UTF-8/US-ASCII)، أو +- يحتوي الملف المصدر على تعريف نوع المستند (DOCTYPE)، أو +- يختلف كل من الماسح البايت والمحلل حول البنية العليا للوثيقة — على سبيل المثال، وجود `
` ثانية خارج المواصفات، والتي يحتفظ بها المحلل مرة واحدة فقط (أما الماسح فيتخذ موقفًا متشككًا عن عمد: فأي شك يعني عدم التقاط أي بايتات من المصدر على الإطلاق)، أو +- تم إنشاء المصدر في الذاكرة بدلاً من تحميله من ملف. -## Saving an edited document +## حفظ مستند تم تحريره -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **يتم إخراج الإدخالات التي لم يتم التعديل عليها حرفياً من البايتات الأصلية.** يُعتبر الإدخال قد تم التعديل عليه إذا تغير أي جزء من كائن النموذج الخاص به منذ عملية التحليل (يتم الكشف عن ذلك من خلال لقطة التسلسل القياسي، وليس من خلال علامة التغيير).\*\* +- **يتم إعادة تسلسل المدخلات التي تم تعديلها بشكل قياسي وكامل**: UTF-8، مسافة بادئة بمقدار مسافتين _خارج_ المحتوى المختلط (لا يتم تغيير المسافات البيضاء داخل `` و`` أبدًا)، وتجميع فرعي موثق لكل عنصر (على سبيل المثال، المدخل: الوحدة اللغوية، الاقتباس، طرق النطق، المتغيرات، المعاني، الملاحظات، العلاقات، أصول الكلمات، التعليقات التوضيحية، السمات، الحقول)، ترتيب ثابت للسمات، التواريخ وفقًا لمعيار ISO-8601 (حرف `Z` لـ UTC). يتم إعادة إصدار جميع البقايا؛ ويتم إعادة وضعها في الفهرس الفرعي الأصلي، مع ربطها بالقائمة الفرعية الجديدة (وهذا تقريب — فالمواضع الدقيقة بالبايت مضمونة فقط للمدخلات التي لم يتم التعديل فيها). +- تؤدي إضافة العناصر أو حذفها أو إعادة ترتيبها إلى إعادة تسلسل بنية المستند، لكنها تظل تُخرج بايتات كل عنصر لم يتغير حرفياً. -## Known approximations (touched nodes only) +## التقريبات المعروفة (العقد التي تم لمسها فقط) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- يتم الاحتفاظ بالتعليقات الموجودة _داخل_ عملية تشغيل ``، ولكن يتم رفعها لتظهر بجوار عملية التشغيل، وليس في موضعها الدقيق من حيث عدد الأحرف. +- يتم توحيد ترتيب العناصر الفرعية من النوع «المتقاطع» داخل عنصر تم تعديله وفقًا للتجميع القياسي (تجعل خاصية `interleave` في مخطط LIFT هذا الترتيب غير ذي أهمية من الناحية الدلالية). +- لا يتم إعادة إصدار عنصر متعدد النصوص موجود ولكنه لا يحمل أي شيء — لا نماذج ولا بقايا، على سبيل المثال `` —. يمثل النموذج هذه الحقول على شكل `Multitext` موجود دائمًا (`lexical-unit`، و`citation`، و`definition`، و`usage` للعلاقة، و`label` / `abbrev` / `description` في مراجع عناوين الويب، والنطاقات، وعناصر النطاق، والعنوان)، لذا لا يمكن التمييز بين النموذج الفارغ والنموذج الغائب بعد التحليل. لا يُفقد أي شيء من الناحية الدلالية. From 1e06efb57336bb6050869e9138eb40fb401a4f29 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:49 -0600 Subject: [PATCH 126/317] New translations build-export.md (French) [ci skip] --- docs/fr/guides/build-export.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/fr/guides/build-export.md b/docs/fr/guides/build-export.md index 965b73a..9c9299a 100644 --- a/docs/fr/guides/build-export.md +++ b/docs/fr/guides/build-export.md @@ -90,18 +90,18 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") - Intervenante : Ana + Speaker: Ana - poulet + chicken
- volaille élevée pour ses œufs et sa viande + a domestic fowl kept for its eggs and meat
@@ -110,14 +110,14 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="")
- Je veux un poulet. + I want a chicken.
@@ -137,7 +137,7 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") @@ -146,7 +146,7 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") From bcd7cca53099de4864ad5ff0153eb9ae0545b9ed Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:51 -0600 Subject: [PATCH 127/317] New translations build-export.md (Spanish) [ci skip] --- docs/es/guides/build-export.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/es/guides/build-export.md b/docs/es/guides/build-export.md index 37a5597..0359e41 100644 --- a/docs/es/guides/build-export.md +++ b/docs/es/guides/build-export.md @@ -85,23 +85,23 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") nkhuku
- gallina + galinha
- Hablante: Ana + Speaker: Ana
- gallina + chicken
- ave doméstica criada por sus huevos y su carne + a domestic fowl kept for its eggs and meat
@@ -110,14 +110,14 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="")
- Quiero un pollo. + I want a chicken.
@@ -130,14 +130,14 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="")
-=== aves.gamas de peso === +=== birds.lift-ranges === @@ -146,7 +146,7 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") From abbabd59e421d2f85240da884c7cd9519f61074e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:53 -0600 Subject: [PATCH 128/317] New translations build-export.md (Arabic) [ci skip] --- docs/ar/guides/build-export.md | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/ar/guides/build-export.md b/docs/ar/guides/build-export.md index ce13b26..b4d269e 100644 --- a/docs/ar/guides/build-export.md +++ b/docs/ar/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# مثال عملي: إنشاء عملية تصدير LIFT من البداية -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +إذا كنت تقوم بتصدير بيانات تطبيق آخر بتنسيق LIFT — وهي المهمة التي تقف وراء [إنشاء ملفات LIFT متوافقة](lift-export-interop.md) — فيمكن لـ `sil-lift` إنشاء المستند كائنًا تلو الآخر وتسلسله، بدلاً من إنشاء ملف XML يدويًّا. يشرح هذا المثال أحد البرامج النصية التي تقوم بإنشاء مدخل يتضمن العناصر التي يتألف منها القاموس الفعلي (أنظمة كتابة متعددة، ونطق، ومعنى مع مثال، ورسم توضيحي، وسمة المجال الدلالي، وحقل خاص بالتطبيق)، وتقوم بكتابة المفردات المحددة في ملف مصاحب بتنسيق `.lift-ranges`، ثم تتحقق من صحتها، وتحفظها. -## The script +## النص ```python from pathlib import Path @@ -11,13 +11,13 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# إدخال واحد، تم إنشاؤه من النموذج المصدر. entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "المتحدث: آنا" # اتفاقية تسمية المتحدث في "The Combine" pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) @@ -39,22 +39,22 @@ sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # حقل إضافي خاص بالتطبيق scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# المفردات المراقبة التي يشير إليها الإدخال، في ملف .lift-ranges مصاحب. ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# التحقق من صحة ما ستكتبه save()، قبل الكتابة على القرص. problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"التحقق من الصحة: {len(problems)} مشكلة (مشاكل)") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## ما الذي تنتجه -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`التحقق من الصحة: 0 مشكلة(مشاكل)`، ثم `.lift` وما يرافقه جنبًا إلى جنب: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## ملاحظات حول واجهة برمجة التطبيقات (API) -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a `
`. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- الحقول متعددة النصوص (`lexical_unit`، `definition`، تسمية `Form`/`URLRef`، محتوى `Field`، ...) يتم أخذ سلسلة واحدة لكل نظام كتابة عبر واجهة التعيين: `entry.lexical_unit["seh"] = "nkhuku"` تضيف ``. ويتم تعيين نموذج المصدر الذي يربط السلاسل برموز اللغات مباشرةً إلى هذا النموذج. +- `RangesFile.add_range()` / `Range.add_element()` تُنشئ المفردات المُحددة، و`Lexicon.add_ranges_file(ranges, href=...)` تُرفق الملف المصاحب وتضيف رأس الملف `` — بحيث يتم تحويل `` و`` الخاصين بالمدخل إلى النطاقات التي حددتها. +- `URLRef` هو رابط href مصحوب بنص متعدد اختياري للتعليق أو التسمية — ويُستخدم لكل من `` (الصوت) و`` (الصور). يتبع النطق هنا قاعدة «ذا كومباين» الخاصة بالصيغة «en» التي تُقرأ على النحو التالي: «المتحدث: ». +- البيانات الخاصة بالتطبيق التي لا تحتوي على رحلات LIFT محلية كـ « » (أو « »): يقرأ تطبيق FieldWorks هذه البيانات كحقول مخصصة، ويحتفظ تطبيق The Combine بها. +- قم بتعيين `guid` حقيقي وثابت لكل إدخال (على سبيل المثال، من `uuid.uuid4()`، مع إعادة استخدامه عبر عمليات التصدير) — حيث تؤدي عملية إعادة الاستيراد لاحقًا إلى تحديث الإدخال في مكانه بدلاً من تكراره. يضمن الأمر `sil-lift validate --require-ids` تطبيق ذلك. +- تقوم الدالة `lex.iter_problems()` بالتحقق من صحة المستند الموجود في الذاكرة (ما ستقوم الدالة `save()` بكتابته) قبل أن يتم تسجيل أي شيء على القرص؛ وهو هنا خالٍ من الأخطاء. نظرًا لعدم وجود مجلد للمعجم حتى الآن، يتم تخطي فحوصات وجود الوسائط ورابط الملف المصاحب — قم بتشغيل [`sil-lift validate`](cli.md) على المخرجات المحفوظة (أو باستخدام الخيار `--no-check-media`) بمجرد توفر ملفات الصوت والصور. -## Packaging +## التغليف -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +يؤدي الأمر `lex.save("export/birds.lift")` إلى كتابة المجلد بالصيغة التالية (ملفان `.lift` و`.lift-ranges` جنبًا إلى جنب). لإنشاء حزمة مضغوطة واحدة يمكن لبرنامجي FieldWorks و The Combine استيرادها مباشرةً، استخدم `lex.save_zip("birds.zip")` بدلاً من ذلك — انظر [إنتاج ملفات LIFT متوافقة](lift-export-interop.md). From 930fc6de52ffdb03f947adac0ede3351d8c84e72 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:22:58 -0600 Subject: [PATCH 129/317] New translations csharp-differences.md (German) [ci skip] --- docs/de/csharp-differences.md | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/de/csharp-differences.md b/docs/de/csharp-differences.md index 6e84fac..2dbafe2 100644 --- a/docs/de/csharp-differences.md +++ b/docs/de/csharp-differences.md @@ -8,45 +8,45 @@ sil-lift ist in etwa vergleichbar mit den C#-LIFT-Tools von SIL – vor allem mi | ----------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------- | | LIFT-Versionen | 0,10–0,13 (Migration integriert) | **nur 0.13**; ältere Versionen werden mit einer eindeutigen Fehlermeldung abgelehnt | | Versionsmigration | `Migrator` (XSLT-Kette) | keine — Verwenden Sie die XSLT-Dateien aus „lift-standard“ für einmalige Upgrades | -| 3-Wege-Zusammenführung / Synchronisierung | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| 3-Wege-Zusammenführung / Synchronisierung | Refrain | fällt nicht in den Geltungsbereich | +| Validierung | Nur RELAX NG (`Validator`) | RELAX NG + Schema- und Semantikprüfungen | +| Streaming | interne Analyse auf Eintragsebene | Öffentliche `open_reader`-/`open_writer`-API | -## API shape +## API-Form -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +Der Parser von `SIL.Lift` ist callback-gesteuert (`ILexiconMerger`): Er übergibt Parsing-Ereignisse an einen Verbraucher. sil-lift gibt stattdessen einen einfachen Objektgraphen zurück – typisierte Dataklassen für jedes LIFT-Element –, da Python-Skriptentwickler Objekte und keine Callbacks wünschen. `SIL.DictionaryServices` legt zwar ein `LexEntry`/`LexSense`-Objektmodell über `SIL.Lift“, doch als Anwendungsmodell repräsentiert es lediglich die Konstrukte, die diese Anwendungen verwenden – daher können bei einer erneuten Serialisierung über dieses Modell Inhalte, die außerhalb des Modells liegen, nicht in derselben Weise erhalten bleiben wie bei der Residue-Erfassung und der Byte-Fidelity von sil-lift (siehe unten). Die Streaming-API liefert denselben `Entry\`-Typ, daher gibt es kein Modell mit eingeschränkten Funktionen. -## Round-trip fidelity +## Round-Trip-Genauigkeit -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +Der deutlichste bewusste Unterschied. Beim Speichern mit `SIL.Lift` wird das gesamte Dokument erneut serialisiert. sil-lift garantiert: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- Ein unverändertes Dokument wird **byte-identisch** gespeichert, und +- Unveränderte Einträge behalten ihre exakten Quellbytes bei, auch wenn sich andere Einträge ändern (Byte-Chunking auf Chorus-Ebene, wird automatisch angewendet). -See [Fidelity guarantees](fidelity.md). +Siehe [Garantien zur Richtigkeit](fidelity.md). -## Validation +## Validierung -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +Der C#-`Validator` führt einen RELAX-NG-Durchlauf durch und gibt die ersten Fehler als Zeichenfolgen zurück. sil-lift meldet einen strukturierten, nach Einträgen/Zeilen adressierten `Problem`-Stream, und seine Schemaebene weicht an drei Stellen bewusst davon ab: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **Ungültige URIs sind Warnungen, keine Fehler.** Die C#-RELAX-NG-Engine hat den Datentyp `anyURI` nie erzwungen, weshalb FieldWorks (FLEx) seit Jahren `file://C:/...`-href-Links in echte Lexika schreibt. Würden diese Dateien abgelehnt, würde dies praktisch jeden FLEx-Export als fehlerhaft kennzeichnen. +- **Schematron-Regeln werden durchgesetzt** (als semantische Prüfungen): Doppelte Formularsprachen und ähnliche Ko-Einschränkungen in der LIFT-Grammatik wurden sowohl bei der C#-Validierung als auch bei der reinen lxml-Validierung stillschweigend ignoriert. +- **Dateiübergreifende Vergleiche sind Unicode-normalisiert**, da FLEx die `.lift`-Datei in NFC und die zugehörige `.lift-ranges`-Datei in NFD schreibt. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift validiert außerdem die `.lift-ranges`-Begleitdateien eines geladenen Lexikons anhand eines Schemas für eigenständige Bereichsdokumente (das zusammen mit der LIFT-Basisgrammatik aus `lift-standard` bereitgestellt wird) — jede nachverfolgte externe Bereichsdatei wird bei jeder Validierung der `.lift`-Datei überprüft — während es in der C#-Welt kein solches Schema (oder keine solche Überprüfung) gibt. (Es gibt keine Möglichkeit, eine `.lift-ranges`-Datei für sich allein, losgelöst von einer `.lift`-Datei, zu validieren.) -## Canonical sorting +## Kanonische Sortierung -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` spiegelt die Kernregeln von `LiftSorter` wider (Einträge nach GUID ohne Berücksichtigung der Groß-/Kleinschreibung; Bereiche und Bereichselemente nach ID; Definitionen von Header-Feldern nach Tag; Bedeutungen werden in der Reihenfolge der Datei beibehalten; Leerzeichen innerhalb von `` werden nie verändert), mit drei Unterschieden: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- Einträge ohne GUID werden deterministisch nach ID sortiert (`LiftSorter` geht davon aus, dass eine GUID vorhanden ist); +- Die Sortierreihenfolge ist lokalisierungsunabhängig (reine, groß-/kleinschreibungsunabhängige Codepunkte, nicht die .NET-Sortierreihenfolge für kulturunabhängige Sortierung); +- Listen desselben Typs wie Notizen, Beziehungen und Formulare behalten ihre Reihenfolge im Dokument bei, anstatt nach dem Schlüssel neu sortiert zu werden – die Gruppierung ist bereits deterministisch, und eine Neuanordnung würde nur unnötiges Rauschen verursachen. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +Die Datei `canonicalizeLift.xsl` aus dem Spec-Repo wird überhaupt nicht verwendet: Sie komprimiert Leerzeichen innerhalb des lexikalischen Texts (destruktiv) und die von ihr generierten IDs unterscheiden sich bei jedem Durchlauf. -## Not carried over +## Nicht übernommen -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- WeSay-spezifische Funktionen (Dashboard/Konfiguration im Zusammenhang mit LIFT-Dateien). +- `SynchronicMerger` (Zusammenführung von Chorus-Updates) – das Konzept der Byte-Chunks lebt in der Fidelity-Schicht weiter, die Zusammenführung hingegen nicht. +- LDML-Schriftsystem-Analyse: Dateien im Verzeichnis `WritingSystems/` werden als undurchsichtiger Ordnerinhalt behandelt. From 93f5df97f9bc588b8fc0d66987d853c8265eda09 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:00 -0600 Subject: [PATCH 130/317] New translations csharp-differences.md (Japanese) [ci skip] --- docs/ja/csharp-differences.md | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/ja/csharp-differences.md b/docs/ja/csharp-differences.md index 840d476..5303242 100644 --- a/docs/ja/csharp-differences.md +++ b/docs/ja/csharp-differences.md @@ -8,45 +8,45 @@ sil-lift は、SIL の C# LIFT ツール群――主に [libpalaso](https://gith | ---------- | -------------------------------------------------------- | ---------------------------------------------------- | | LIFTのバージョン | 0.10–0.13(移行機能が組み込まれている) | **0.13のみ**;それより古いバージョンは明確なエラーで拒否されます | | バージョンの移行 | `Migrator`(XSLTチェーン) | なし — 単発のアップグレードには、lift-standardに含まれるXSLTを使用してください | -| 3ウェイマージ/同期 | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| 3ウェイマージ/同期 | コーラス | 対象外 | +| 検証 | RELAX NG のみ(`Validator`) | RELAX NG + スキーマおよびセマンティックチェックの範囲 | +| ストリーミング | エントリ単位の内部解析 | パブリック `open_reader` / `open_writer` API | -## API shape +## APIの形状 -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +`SIL.Lift`のパーサーはコールバック駆動型(`ILexiconMerger`)であり、解析イベントをコンシューマーにプッシュします。 その代わりに、sil-lift は単純なオブジェクトグラフ(LIFT の各要素に対応する型付きデータクラス)を返します。これは、Python スクリプト作成者がコールバックではなくオブジェクトを求めているためです。 `SIL.DictionaryServices` は、`SIL.Lift`の上に`LexEntry`/`LexSense`オブジェクトモデルを重ねていますが、アプリケーションモデルとして、それはそれらのアプリが使用する構造のみを表しています。そのため、これを通じて再シリアライズを行っても、sil-liftの残留値のキャプチャやバイト単位の忠実度のように、モデル外のコンテンツを保持することはできません(以下を参照)。 ストリーミングAPIは_同じ_ `Entry` 型を返すため、機能が制限されたツインモデルは存在しません。 -## Round-trip fidelity +## 往復の忠実度 -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +最も顕著な意図的な違い。 `SIL.Lift` を使用して保存すると、ドキュメント全体が再シリアル化されます。 sil-liftの保証: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- 変更のないドキュメントは**バイト単位で同一**に保存され、 +- 変更されていないエントリは、他のエントリが変更された場合でも、ソースのバイトを正確に保持します(Chorusレベルのバイト単位のチャンキングが自動的に適用されます)。 -See [Fidelity guarantees](fidelity.md). +[フィデリティの保証](fidelity.md)をご覧ください。 -## Validation +## 検証 -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +C#の`Validator`は、RELAX NGによる検証を1回実行し、最初に検出されたエラーを文字列として報告します。 sil-lift は、構造化された、エントリ/行単位でアドレス指定される `Problem` ストリームを報告しており、そのスキーマ層は意図的に 3 箇所で異なる仕様となっています: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **無効なURIはエラーではなく警告です。** C#のRELAX NGエンジンは`anyURI`データ型を強制したことがなかったため、FieldWorks (FLEx) では長年にわたり、実際のレキシコンに`file://C:/...`というhrefを記述してきました。 それらのファイルを拒否すると、事実上すべてのFLExエクスポートにフラグが立てられてしまいます。 +- **Schematronルールが適用されます**(セマンティックチェックとして):LIFT文法における重複するフォーム言語や類似の共制約は、C#および生のlxmlによる検証のいずれにおいても、黙って無視されていました。 +- **ファイル間の比較はUnicode正規化されています**。これは、FLExが`.lift`ファイルをNFC形式で、関連する`.lift-ranges`ファイルをNFD形式で書き出すためです。 -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift は、読み込まれたレキシコンの `.lift-ranges` コンパニオンを、スタンドアロンの範囲ドキュメント用のスキーマ(ベースとなる LIFT 文法とともに `lift-standard` から提供されているもの)に対して検証します — `.lift` の検証が行われるたびに、追跡対象となっているすべての外部レンジファイルがチェックされます — C#の世界には、このようなスキーマ(またはチェック)は存在しません。 (`.lift` ファイルから切り離された状態で、`.lift-ranges` ファイル単体を検証するためのエントリポイントは存在しません。) -## Canonical sorting +## 規範的順序付け -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` は、`LiftSorter` の基本ルール(エントリは大文字小文字を区別しない GUID 順、範囲および範囲要素は ID 順、ヘッダーフィールドの定義はタグ順、意味の並びはファイル順のまま、`` 内の空白は一切変更しない)を踏襲していますが、3つの違いがあります: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- GUID を持たないエントリは、ID に基づいて決定論的にソートされます(`LiftSorter` は GUID が存在することを前提としています)。 +- 順序付けはロケールに依存しません(大文字小文字を区別しないコードポイントに基づくものであり、.NET の不変文化ソート順序ではありません)。 +- ノート、関係、フォームなどの同種のリストは、キーに基づいて再ソートされるのではなく、ドキュメント内の順序を維持します。グループ化はすでに決定論的であり、順序を変更しても差分のノイズが増えるだけです。 -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +仕様リポジトリの `canonicalizeLift.xsl` はまったく使用されていません。このXSLは、字句テキスト内の空白を削除してしまう(破壊的)うえ、生成されるIDが実行のたびに異なるからです。 -## Not carried over +## 繰り越されなかった -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- WeSay特有の利便性(ダッシュボード/LIFTファイルに関する設定処理)。 +- `SynchronicMerger`(Chorusの更新マージ)— バイト単位のチャンク化という考え方はフィデリティ層で引き継がれているが、マージ機能自体は引き継がれていない。 +- LDMLの表記体系の解析:`WritingSystems/` ディレクトリ内のファイルは、不透明なフォルダ内容として扱われます。 From 4ba1ca776e10fbb6b157888e8939a6434dfcdba6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:02 -0600 Subject: [PATCH 131/317] New translations csharp-differences.md (Portuguese) [ci skip] --- docs/pt/csharp-differences.md | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/pt/csharp-differences.md b/docs/pt/csharp-differences.md index 7c87b09..df9fe95 100644 --- a/docs/pt/csharp-differences.md +++ b/docs/pt/csharp-differences.md @@ -4,49 +4,49 @@ O sil-lift é, de certa forma, análogo às ferramentas LIFT da SIL para C# — ## Âmbito -| Capacidade | Bibliotecas C# | sil-lift | -| ------------------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------- | -| Versões do LIFT | 0,10–0,13 (migração integrada) | **Apenas 0.13**; as versões mais antigas são rejeitadas com um erro claro | -| Migração de versão | `Migrator` (cadeia XSLT) | nenhuma — utilizar os XSLT do «lift-standard» para atualizações pontuais | -| Fusão/sincronização a três vias | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| Capacidade | Bibliotecas C# | sil-lift | +| ------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------- | +| Versões do LIFT | 0,10–0,13 (migração integrada) | **Apenas 0.13**; as versões mais antigas são rejeitadas com um erro claro | +| Migração de versão | `Migrator` (cadeia XSLT) | nenhuma — utilizar os XSLT do «lift-standard» para atualizações pontuais | +| Fusão/sincronização a três vias | Refrão | fora do âmbito | +| Validação | Apenas RELAX NG (`Validator`) | RELAX NG + verificações de esquema e semânticas | +| Streaming | análise sintática com granularidade interna das entradas | API pública `open_reader` / `open_writer` | -## API shape +## Estrutura da API -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +O analisador do `SIL.Lift` é orientado por callbacks (`ILexiconMerger`): envia eventos de análise a um consumidor. Em vez disso, o sil-lift devolve um gráfico de objetos simples — classes de dados tipadas para cada elemento LIFT — porque os programadores de Python querem objetos, e não callbacks. O `SIL.DictionaryServices` sobrepõe um modelo de objetos `LexEntry`/`LexSense` ao `SIL.Lift`, mas, enquanto modelo de aplicação, representa apenas as construções que essas aplicações utilizam — pelo que a resserialização através dele não consegue preservar o conteúdo fora do modelo da mesma forma que a captura de resíduos e a fidelidade de bytes do sil-lift o fazem (ver abaixo). A API de streaming devolve o _mesmo_ tipo `Entry`, pelo que não existe um modelo duplo com funcionalidades reduzidas. -## Round-trip fidelity +## Fidelidade de ida e volta -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +A diferença deliberada mais marcante. Ao guardar com o `SIL.Lift`, todo o documento é novamente serializado. A sil-lift garante: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- um documento inalterado é guardado com **identidade de bytes**, e +- As entradas não alteradas mantêm os seus bytes de origem exatos, mesmo quando outras entradas são alteradas (divisão em blocos de bytes ao nível do Chorus, aplicada automaticamente). -See [Fidelity guarantees](fidelity.md). +Consulte [Garantias da Fidelity](fidelity.md). -## Validation +## Validação -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +O `Validator` do C# executa uma passagem RELAX NG e apresenta os primeiros erros sob a forma de cadeias de caracteres. O sil-lift reporta um fluxo `Problem` estruturado, endereçado por entrada/linha, e a sua camada de esquema diverge deliberadamente em três pontos: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **Os URIs inválidos são avisos, não erros.** O motor RELAX NG do C# nunca impôs o tipo de dados `anyURI`, pelo que o FieldWorks (FLEx) tem vindo a inserir hrefs do tipo `file://C:/...` em léxicos reais há anos. A rejeição desses ficheiros faria com que praticamente todas as exportações do FLEx fossem sinalizadas. +- **As regras do Schematron são aplicadas** (como verificações semânticas): as linguagens de formulário duplicadas e as co-restrições semelhantes na gramática LIFT foram ignoradas silenciosamente tanto pela validação em C# como pela validação direta do lxml. +- **As comparações entre ficheiros são normalizadas segundo o Unicode**, uma vez que o FLEx grava o ficheiro `.lift` em NFC e o ficheiro associado `.lift-ranges` em NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +O sil-lift também valida os ficheiros `.lift-ranges` associados a um léxico carregado, comparando-os com um esquema para documentos de intervalos autónomos (fornecido pelo `lift-standard` juntamente com a gramática LIFT de base) — todos os ficheiros de intervalos externos monitorizados são verificados sempre que o `.lift` é validado — sem que exista tal esquema (ou verificação) no mundo do C#. (Não existe um ponto de entrada para validar um ficheiro `.lift-ranges` por si só, separado de um ficheiro `.lift`.) -## Canonical sorting +## Ordenação canónica -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +O `Lexicon.sort()` reflete as regras fundamentais do `LiftSorter` (entradas por GUID, sem distinção entre maiúsculas e minúsculas; intervalos e elementos de intervalo por ID; definições de campos de cabeçalho por etiqueta; significados mantidos na ordem do ficheiro; espaços em branco dentro de `` nunca são alterados), com três diferenças: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- as entradas sem um GUID são ordenadas de forma determinística por ID (o `LiftSorter` pressupõe a existência de um GUID); +- a ordenação é independente da configuração regional (pontos de código com maiúsculas e minúsculas ignoradas, e não a ordenação de cultura invariante do .NET); +- As listas do mesmo tipo, como notas, relações e formulários, mantêm a ordem do documento em vez de serem reordenadas por chave — o agrupamento já é determinístico e reordená-las apenas acrescenta ruído às diferenças. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +O ficheiro `canonicalizeLift.xsl` do repositório de especificações não é utilizado de todo: elimina os espaços em branco no texto lexical (de forma destrutiva) e os identificadores gerados variam em cada execução. -## Not carried over +## Não transitado -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- Funcionalidades específicas do WeSay (painel de controlo/gestão de configurações relacionadas com ficheiros LIFT). +- `SynchronicMerger` (fusão de atualizações do Chorus) — o conceito de divisão em blocos de bytes mantém-se na camada de fidelidade, mas a fusão já não. +- Análise do sistema de escrita LDML: os ficheiros na pasta `WritingSystems/` são tratados como conteúdo opaco da pasta. From 53f0320b887f263b4afeb9fc6ab1151dfee9282a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:04 -0600 Subject: [PATCH 132/317] New translations csharp-differences.md (Russian) [ci skip] --- docs/ru/csharp-differences.md | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/ru/csharp-differences.md b/docs/ru/csharp-differences.md index 01b9867..e6bcc95 100644 --- a/docs/ru/csharp-differences.md +++ b/docs/ru/csharp-differences.md @@ -4,49 +4,49 @@ sil-lift в общих чертах аналогичен инструмента ## Область применения -| Возможности | Библиотеки C# | sil-lift | -| ----------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------- | -| Версии LIFT | 0,10–0,13 (с учётом миграции) | **Только версия 0.13**; более старые версии отклоняются с явной ошибкой | -| Переход на новую версию | `Migrator` (цепочка XSLT) | нет — использовать XSLT-файлы из пакета lift-standard для разовых обновлений | -| 3-стороннее слияние / синхронизация | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| Возможности | Библиотеки C# | sil-lift | +| ----------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| Версии LIFT | 0,10–0,13 (с учётом миграции) | **Только версия 0.13**; более старые версии отклоняются с явной ошибкой | +| Переход на новую версию | `Migrator` (цепочка XSLT) | нет — использовать XSLT-файлы из пакета lift-standard для разовых обновлений | +| 3-стороннее слияние / синхронизация | Припев | выходит за рамки | +| Валидация | Только RELAX NG (`Validator`) | RELAX NG + проверки схемы и семантики | +| Потоковое вещание | внутренний синтаксический анализ с гранулярностью на уровне элементов | публичный API `open_reader` / `open_writer` | -## API shape +## Формат API -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +Парсер `SIL.Lift` работает на основе обратных вызовов (`ILexiconMerger`): он передаёт события разбора потребителю. Вместо этого sil-lift возвращает простой граф объектов — типизированные классы данных для каждого элемента LIFT — поскольку разработчики скриптов на Python нуждаются в объектах, а не в обратных вызовах. `SIL.DictionaryServices` действительно накладывает объектную модель `LexEntry`/`LexSense` на `SIL.Lift`, но как прикладная модель она представляет только те конструкции, которые используют эти приложения — поэтому повторная сериализация через неё не может сохранить контент, выходящий за пределы модели, так же, как это делают функции захвата остатков и точной передачи байтов в sil-lift (см. ниже). API потоковой обработки возвращает _тот же самый_ тип `Entry`, поэтому не существует модели-близнеца с ограниченными возможностями. -## Round-trip fidelity +## Точность воспроизведения в обоих направлениях -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +Самое явное намеренное отличие. При сохранении с помощью `SIL.Lift` происходит повторная сериализация всего документа. Компания «Sil-Lift» гарантирует: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- неизменённый документ сохраняется **с идентичным количеством байтов**, и +- Неизмененные записи сохраняют свои исходные байты в точности, даже если другие записи изменяются (байтовое разбиение уровня Chorus, применяется автоматически). -See [Fidelity guarantees](fidelity.md). +См. [Гарантии Fidelity](fidelity.md). -## Validation +## Валидация -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +Валидатор `Validator` на языке C# выполняет один проход по RELAX NG и возвращает первые ошибки в виде строк. sil-lift предоставляет структурированный по записям и строкам поток `Problem`, и его схема сознательно отличается в трёх местах: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **Недопустимые URI являются предупреждениями, а не ошибками.** Движок C# RELAX NG никогда не обеспечивал соблюдение типа данных `anyURI`, поэтому FieldWorks (FLEx) на протяжении многих лет записывает ссылки `file://C:/...` в реальные лексиконы. Отказ от этих файлов привёл бы к отметке практически каждого экспорта из FLEx. +- **Применяются правила Schematron** (в качестве семантических проверок): дублирующиеся языки форм и аналогичные совместные ограничения в грамматике LIFT без предупреждения игнорировались как при валидации на C#, так и при валидации с помощью исходного lxml. +- **Сравнения между файлами нормализованы в соответствии со стандартом Unicode**, поскольку FLEx записывает файл `.lift` в формате NFC, а сопутствующий файл `.lift-ranges` — в формате NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift также проверяет соответствие файлов `.lift-ranges`, сопутствующих загруженному лексикону, схеме для автономных документов диапазонов (поставляемой из `lift-standard` вместе с базовой грамматикой LIFT) — каждый отслеживаемый внешний файл диапазонов проверяется при каждой валидации `.lift` — в то время как в среде C# такой схемы (или проверки) нет. (Не существует отдельной точки входа для проверки файла `.lift-ranges`, не связанного с файлом `.lift`.) -## Canonical sorting +## Каноническая сортировка -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` повторяет основные правила `LiftSorter` (записи сортируются по GUID без учета регистра; диапазоны и элементы диапазонов — по ID; определения полей заголовка — по тегам; значения слов сохраняются в том же порядке, что и в файле; пробелы внутри `` никогда не изменяются), за исключением трёх отличий: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- записи без GUID сортируются детерминированно по ID (класс `LiftSorter` предполагает наличие GUID); +- порядок сортировки не зависит от локали (используются кодовые точки без учета регистра, а не сортировка с инвариантной культурой в .NET); +- Списки одного типа, такие как заметки, связи и формы, сохраняют порядок, в котором они были в документе, а не пересортировываются по ключу — группировка и так является детерминированной, а их переупорядочение лишь увеличивает объем данных сравнения. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +Файл `canonicalizeLift.xsl` из репозитория спецификаций вообще не используется: он сжимает пробелы внутри лексического текста (деструктивно), а сгенерированные им идентификаторы при каждом запуске отличаются друг от друга. -## Not carried over +## Не перенесено -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- Удобства, характерные для WeSay (работа с панелью управления и настройками, связанными с файлами LIFT). +- `SynchronicMerger` (объединение обновлений Chorus) — идея разбиения на байтовые блоки сохраняется в уровне точности, а сам процесс объединения — нет. +- Анализ систем письма LDML: файлы в папке `WritingSystems/` рассматриваются как непрозрачное содержимое папки. From 97ad3346c602c455467ad4c9d869ac7683af489b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:05 -0600 Subject: [PATCH 133/317] New translations csharp-differences.md (Chinese Simplified) [ci skip] --- docs/zh/csharp-differences.md | 60 +++++++++++++++++------------------ 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/zh/csharp-differences.md b/docs/zh/csharp-differences.md index 6153ffd..b198e5d 100644 --- a/docs/zh/csharp-differences.md +++ b/docs/zh/csharp-differences.md @@ -4,49 +4,49 @@ sil-lift 与 SIL 的 C# LIFT 工具集大致类似——主要包括 [libpalaso] ## 范围 -| 能力 | C# 库 | sil-lift | -| ---------- | ------------------------------------------------- | ------------------------------------------ | -| LIFT 版本 | 0.10–0.13(内置迁移功能) | **仅限 0.13 版**;旧版本将被明确拒绝 | -| 版本迁移 | `Migrator`(XSLT 链) | 无 — 对于一次性升级,请使用 lift-standard 中的 XSLT 文件 | -| 三向合并/同步 | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| 能力 | C# 库 | sil-lift | +| ------- | ------------------------------------------------- | ---------------------------------------- | +| LIFT 版本 | 0.10–0.13(内置迁移功能) | **仅限 0.13 版**;旧版本将被明确拒绝 | +| 版本迁移 | `Migrator`(XSLT 链) | 无 — 对于一次性升级,请使用 lift-standard 中的 XSLT 文件 | +| 三向合并/同步 | 合唱 | 超出范围 | +| 验证 | 仅限 RELAX NG(`Validator`) | RELAX NG + 范围模式 + 语义检查 | +| 流媒体 | 内部条目级别的解析 | 公共 `open_reader` / `open_writer` API | -## API shape +## API 结构 -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +`SIL.Lift` 的解析器采用回调驱动模式(`ILexiconMerger`):它会将解析事件推送给消费者。 sil-lift 反而返回一个普通的对象图——每个 LIFT 元素对应一个带类型的数据类——因为 Python 脚本开发者需要的是对象,而不是回调函数。 `SIL.DictionaryServices` 确实在 `SIL.Lift`之上构建了一个 `LexEntry`/`LexSense` 对象模型,但作为应用程序模型,它仅代表这些应用程序所使用的结构——因此,通过它进行重新序列化无法像 sil-lift 的残留捕获和字节保真度那样保留模型之外的内容(详见下文)。 流式处理 API 返回的是_相同的_ `Entry` 类型,因此不存在功能受限的双生模型。 -## Round-trip fidelity +## 往返保真度 -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +最显著的刻意差异。 使用 `SIL.Lift` 保存时,会将整个文档重新序列化。 sil-lift 保证: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- 未发生更改的文档在存储时**字节完全一致**,并且 +- 未被修改的条目即使在其他条目发生变化时,也会保留其原始字节内容(采用Chorus级别的字节分块技术,自动应用)。 -See [Fidelity guarantees](fidelity.md). +请参阅[富达保证](fidelity.md)。 -## Validation +## 验证 -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +C# 的 `Validator` 会执行一次 RELAX NG 验证,并将首次检测到的错误以字符串形式返回。 sil-lift 报告了一个结构化、按条目/行寻址的 `Problem` 流,其模式层在三个地方存在有意设计上的差异: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **无效的 URI 属于警告,而非错误。** C# RELAX NG 引擎从未强制执行 `anyURI` 数据类型,因此 FieldWorks (FLEx) 多年来一直将 `file://C:/...` 格式的 href 写入实际词汇表中。 如果拒绝这些文件,几乎所有 FLEx 导出文件都会被标记。 +- **Schematron 规则已强制执行**(作为语义检查):LIFT 语法中重复的表单语言和类似的协同约束,在 C# 和原生 lxml 验证中均被静默忽略。 +- **跨文件比较已进行 Unicode 标准化**,因为 FLEx 将 `.lift` 文件以 NFC 格式写入,而配套的 `.lift-ranges` 文件则以 NFD 格式写入。 -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift 还会根据独立范围文档的模式(该模式与基础 LIFT 语法一同由 `lift-standard` 提供)来验证已加载词汇表的 `.lift-ranges` 伴随文件 —— 每次验证 `.lift` 文件时,都会检查所有被追踪的外部范围文件 —— 而 C# 领域中则不存在此类模式(或检查)。 (目前尚无独立于 `.lift` 文件之外、专门用于验证 `.lift-ranges` 文件的入口点。) -## Canonical sorting +## 规范排序 -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` 遵循 `LiftSorter` 的核心规则(条目按不区分大小写的 GUID 排序;范围和范围元素按 ID 排序;标头字段定义按标签排序;词义按文件顺序排列;`` 内的空格绝不被修改),但有三点不同: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- 没有 GUID 的条目将按 ID 进行确定性排序(`LiftSorter` 假设存在 GUID); +- 排序与区域设置无关(采用纯大写/小写转换后的码点,而非 .NET 的“不变文化”排序规则); +- 同类列表(如笔记、关系和表单)会保留其文档顺序,而非按键值重新排序——分组本身已是确定性的,重新排序只会增加差异噪声。 -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +规范代码库中的 `canonicalizeLift.xsl` 完全未被使用:它会压缩词法文本中的空白(破坏性操作),且每次运行生成的 ID 都不相同。 -## Not carried over +## 未结转 -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- WeSay 特有的便捷功能(围绕 LIFT 文件的仪表盘/配置管理)。 +- `SynchronicMerger`(Chorus 更新合并)——字节分块的理念在保真层中得以延续,但合并操作已不复存在。 +- LDML 书写系统解析:`WritingSystems/` 目录下的文件将被视为不透明的文件夹内容。 From b2cea61df00792a004f994dd49333ffeaba612f3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:07 -0600 Subject: [PATCH 134/317] New translations csharp-differences.md (Hindi) [ci skip] --- docs/hi/csharp-differences.md | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/hi/csharp-differences.md b/docs/hi/csharp-differences.md index 8a2cdc9..a83703c 100644 --- a/docs/hi/csharp-differences.md +++ b/docs/hi/csharp-differences.md @@ -8,45 +8,45 @@ sil-lift मोटे तौर पर SIL के C# LIFT टूलिंग क | ------------------- | ------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | | लिफ्ट संस्करण | 0.10–0.13 (स्थानांतरण अंतर्निहित) | केवल **0.13**; पुराने संस्करणों को एक स्पष्ट त्रुटि के साथ अस्वीकार कर दिया जाता है। | | संस्करण माइग्रेशन | `Migrator` (XSLT श्रृंखला) | कोई नहीं — एकमुश्त अपग्रेड के लिए लिफ्ट-स्टैंडर्ड में मौजूद XSLTs का उपयोग करें। | -| 3-तरफ़ा मर्ज / सिंक | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| 3-तरफ़ा मर्ज / सिंक | कोरस | दायरे से बाहर | +| प्रमाणीकरण | केवल RELAX NG (`Validator`) | RELAX NG + रेंज स्कीमा + सेमांटिक जाँच | +| स्ट्रीमिंग | आंतरिक प्रविष्टि-कणिकीय पार्सिंग | सार्वजनिक `open_reader` / `open_writer` एपीआई | -## API shape +## एपीआई आकार -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +`SIL.Lift` का पार्सर कॉलबैक-चालित (`ILexiconMerger`) है: यह पार्स इवेंट्स को एक कंज्यूमर पर पुश करता है। sil-lift इसके बजाय एक सादा ऑब्जेक्ट ग्राफ़ लौटाता है — प्रत्येक LIFT एलिमेंट के लिए टाइप्ड डेटाक्लासेस — क्योंकि पाइथन स्क्रिप्टर को कॉलबैक नहीं, ऑब्जेक्ट्स चाहिए। `SIL.DictionaryServices` `SIL.` पर एक `LexEntry`/`LexSense` ऑब्जेक्ट मॉडल की परत चढ़ाता है।Lift`पर एक`LexEntry`/`LexSense`ऑब्जेक्ट मॉडल की परत चढ़ाता है, लेकिन एक एप्लिकेशन मॉडल के रूप में यह केवल उन संरचनाओं का प्रतिनिधित्व करता है जिनका उपयोग वे ऐप्स करते हैं — इसलिए इसके माध्यम से पुनः सीरियलाइज़ करने पर मॉडल के बाहर की सामग्री को उसी तरह संरक्षित नहीं किया जा सकता जैसे sil-lift का अवशेष कैप्चर और बाइट निष्ठा करते हैं (नीचे देखें)। स्ट्रीमिंग एपीआई समान`Entry\` प्रकार ही प्रदान करता है, इसलिए कोई क्षमता-घटाया हुआ ट्विन मॉडल नहीं है। -## Round-trip fidelity +## गमन-आगमन निष्ठा -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +सबसे मजबूत जानबूझकर किया गया अंतर। `SIL.Lift` के साथ सेव करने पर पूरा दस्तावेज़ पुनः सीरियलाइज़ हो जाता है। सिल-लिफ्ट गारंटियाँ: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- एक अपरिवर्तित दस्तावेज़ **बाइट-समान रूप से** सहेजता है, और +- अछूटी प्रविष्टियाँ अपना सटीक स्रोत बाइट्स तब भी बनाए रखती हैं जब अन्य प्रविष्टियाँ बदलती हैं (कोरस-ग्रेड बाइट चंकिंग, स्वचालित रूप से लागू)। -See [Fidelity guarantees](fidelity.md). +देखें [फिडेलिटी गारंटी](fidelity.md)। -## Validation +## प्रमाणीकरण -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +C# `Validator` एक RELAX NG पास चलाता है और पहली त्रुटियों को स्ट्रिंग्स के रूप में रिपोर्ट करता है। sil-lift एक संरचित, प्रविष्टि/पंक्ति-पते वाली `Problem` स्ट्रीम की रिपोर्ट करता है, और इसकी स्कीमा परत जानबूझकर तीन स्थानों पर विचलित होती है: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- अमान्य URI चेतावनियाँ हैं, त्रुटियाँ नहीं। C# RELAX NG इंजन ने कभी भी `anyURI` डेटाटाइप को लागू नहीं किया, इसलिए FieldWorks (FLEx) वर्षों से वास्तविक शब्दकोशों में `file://C:/...` hrefs लिख रहा है। उन फ़ाइलों को अस्वीकार करने से लगभग हर FLEx एक्सपोर्ट पर निशान लग जाएगा। +- **Schematron नियम लागू किए जाते हैं** (सेमांटिक जांच के रूप में): LIFT व्याकरण में डुप्लिकेट फॉर्म भाषाओं और समान सह-बाधाओं को C# और कच्चे lxml सत्यापन दोनों द्वारा चुपचाप अनदेखा किया गया था। +- क्रॉस-फ़ाइल तुलनाएँ यूनिकोड-नॉर्मलाइज़्ड होती हैं, क्योंकि FLEx `.lift` को NFC में और साथी `.lift-ranges` को NFD में लिखता है। -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift एक लोडेड लेक्सिकन के `.lift-ranges` साथियों को स्टैंडअलोन रेंज दस्तावेज़ों के लिए एक स्कीमा के विरुद्ध भी मान्य करता है (जो बेस LIFT व्याकरण के साथ `lift-standard` से विकी हुई है) — हर ट्रैक की गई बाहरी रेंज फ़ाइल की जाँच तब की जाती है जब भी `.lift` का मान्यकरण किया जाता है — C# दुनिया में ऐसा कोई स्कीमा (या जाँच) नहीं है। (`.lift` से अलग, अकेले `.lift-ranges` फ़ाइल को मान्य करने का कोई एंट्री पॉइंट नहीं है।) -## Canonical sorting +## कैनोनिकल क्रमबद्धकरण -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` `LiftSorter` के मुख्य नियमों का पालन करता है (प्रविष्टियाँ केस-असंवेदनशील GUID द्वारा; रेंज और रेंज-तत्व ID द्वारा; हेडर फ़ील्ड परिभाषाएँ टैग द्वारा; अर्थ फ़ाइल क्रम में रखे जाते हैं; `` के अंदर की रिक्त स्थान को कभी भी छुआ नहीं जाता), तीन अंतरों के साथ: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- guid के बिना प्रविष्टियाँ id के अनुसार क्रमबद्ध रूप से व्यवस्थित होती हैं (`LiftSorter` मानता है कि guid मौजूद है); +- ऑर्डरिंग लोकेल-स्वतंत्र है (साधारण केस-फोल्ड किए गए कोड पॉइंट्स, .NET इन्वेरिएंट-कल्चर कोलेशन नहीं); +- नोट्स, रिलेशन्स, और फॉर्म जैसी समान-प्रकार की सूचियाँ अपनी दस्तावेज़ व्यवस्था बनाए रखती हैं, बजाय इसके कि उन्हें कुंजी के अनुसार फिर से क्रमबद्ध किया जाए — समूहबद्धता पहले से ही निर्धारक है, और उन्हें पुनः क्रमबद्ध करने से केवल diff शोर बढ़ता है। -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +spec रिपॉजिटरी का `canonicalizeLift.xsl` बिल्कुल भी उपयोग नहीं किया जाता है: यह लेक्सिकल टेक्स्ट के भीतर रिक्त स्थान को संकुचित कर देता है (विनाशकारी) और इसके उत्पन्न आईडी हर रन पर भिन्न होते हैं। -## Not carried over +## आगे नहीं बढ़ाया गया -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- WeSay-विशिष्ट सुविधाएँ (LIFT फ़ाइलों के संबंध में डैशबोर्ड/कॉन्फ़िग हैंडलिंग) +- `SynchronicMerger` (कोरस अपडेट मर्जिंग) — बाइट-चंकिंग का विचार फिडेलिटी लेयर में जीवित है, मर्जिंग नहीं। +- LDML लेखन-प्रणाली पार्सिंग: `WritingSystems/` में मौजूद फ़ाइलों को अपारदर्शी फ़ोल्डर सामग्री के रूप में माना जाता है। From 4c038903a1b86ba83e4b19c7eb31b2fb062b44bf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:09 -0600 Subject: [PATCH 135/317] New translations csharp-differences.md (Swahili) [ci skip] --- docs/sw/csharp-differences.md | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/sw/csharp-differences.md b/docs/sw/csharp-differences.md index 78a9a58..5237a55 100644 --- a/docs/sw/csharp-differences.md +++ b/docs/sw/csharp-differences.md @@ -8,45 +8,45 @@ sil-lift ni mfano hafifu wa zana za LIFT za C# za SIL — hasa `SIL.Lift` katika | ----------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | | Toleo za LIFT | 0.10–0.13 (uhamiaji umejengewa ndani) | **0.13 tu**; matoleo ya zamani yanakataliwa kwa kosa dhahiri | | Uhamishaji wa toleo | `Migrator` (mnyororo wa XSLT) | Hakuna — tumia XSLTs katika lifti-kawaida kwa ajili ya masasisho ya mara moja | -| Muunganiko/Ulinganisho wa njia tatu | Chorus | out of scope | -| Validation | RELAX NG only (`Validator`) | RELAX NG + ranges schema + semantic checks | -| Streaming | internal entry-granularity parsing | public `open_reader` / `open_writer` API | +| Muunganiko/Ulinganisho wa njia tatu | Kwaya | Nje ya wigo | +| Uthibitishaji | RELAX NG tu (`Validator`) | RELAX NG + masanduku ya schema + ukaguzi wa semantiki | +| Utiririshaji | Uchanganuzi wa ndani wa kiwango cha kuingia | API ya umma `open_reader` / `open_writer` | -## API shape +## Umbo la API -`SIL.Lift`'s parser is callback-driven (`ILexiconMerger`): it pushes parse events at a consumer. sil-lift instead returns a plain object graph — typed dataclasses for every LIFT element — because Python scripters want objects, not callbacks. `SIL.DictionaryServices` does layer a `LexEntry`/`LexSense` object model over `SIL.Lift`, but as an application model it represents only the constructs those apps use — so re-serializing through it can't preserve out-of-model content the way sil-lift's residue capture and byte fidelity do (see below). The streaming API yields the _same_ `Entry` type, so there is no capability-reduced twin model. +Parser ya `SIL.Lift` inaendeshwa na callback (`ILexiconMerger`): inasukuma matukio ya uchanganuzi kwa mtumiaji. sil-lift badala yake hurudisha grafu ya vitu ya kawaida — dataclasses zilizotengwa aina kwa kila kipengele cha LIFT — kwa sababu watunzi wa skripti za Python wanataka vitu, si callbacks. `SIL.DictionaryServices` huweka juu ya `SIL.` mfano wa kitu wa `LexEntry`/`LexSense`Lift`, lakini kama mfano wa programu unawakilisha tu miundo ambayo programu hizo hutumia — hivyo kuirudisha tena katika muundo kupitia kwake haiwezi kuhifadhi maudhui yaliyo nje ya mfano kama vile sil-lift inavyofanya kwa kunasa mabaki na uaminifu wa baiti (tazama hapa chini). API ya utiririshaji hutoa aina ile ile ya `Entry\`, kwa hivyo hakuna mfano wa pacha uliopunguzwa uwezo. -## Round-trip fidelity +## Uaminifu wa safari ya kwenda na kurudi -The strongest deliberate difference. Saving with `SIL.Lift` re-serializes the whole document. sil-lift guarantees: +Tofauti iliyokusudiwa yenye nguvu zaidi. Kuhifadhi kwa kutumia `SIL.Lift` kunaserialisha tena hati nzima. sil-lift inahakikisha: -- an unchanged document saves **byte-identically**, and -- untouched entries keep their exact source bytes even when other entries change (Chorus-grade byte chunking, applied automatically). +- Hati isiyobadilika huhifadhi **byte-identically**, na +- Ningizo zisizoguswa huhifadhi baiti zao halisi za chanzo hata wakati nyingo zingine zinabadilika (Ugawaji wa baiti wa kiwango cha Chorus, unaotumika kiotomatiki). -See [Fidelity guarantees](fidelity.md). +Tazama [Dhamana za Fidelity](fidelity.md). -## Validation +## Uthibitishaji -The C# `Validator` runs one RELAX NG pass and reports the first errors as strings. sil-lift reports a structured, entry/line-addressed `Problem` stream, and its schema layer knowingly diverges in three places: +Validator ya C# hufanya upitaji mmoja wa RELAX NG na kuripoti makosa ya kwanza kama nyuzi. sil-lift inaripoti mtiririko wa `Problem` uliopangiliwa, wa kuingia/anwani-ya-mstari, na safu yake ya schema inakwenda njia tofauti kwa makusudi katika sehemu tatu: -- **Invalid URIs are warnings, not errors.** The C# RELAX NG engine never enforced the `anyURI` datatype, so FieldWorks (FLEx) has been writing `file://C:/...` hrefs into real lexicons for years. Rejecting those files would flag virtually every FLEx export. -- **Schematron rules are enforced** (as semantic checks): duplicate form languages and similar co-constraints in the LIFT grammar were silently ignored by both C# and raw lxml validation. -- **Cross-file comparisons are Unicode-normalized**, because FLEx writes the `.lift` in NFC and the companion `.lift-ranges` in NFD. +- **URI zisizo halali ni maonyo, si makosa.** Injini ya C# RELAX NG haijawahi kulazimisha aina ya data `anyURI`, hivyo FieldWorks (FLEx) imekuwa ikiandika hrefs za `file://C:/...` katika kamusi halisi kwa miaka mingi. Kukataa faili hizo kungeweka alama karibu kila toleo la FLEx. +- **Kanuni za Schematron zinatekelezwa** (kama ukaguzi wa kisemantiki): lugha za fomu zilizorudiwa na vikwazo vinavyofanana katika sarufi ya LIFT vilipuuzwa kimya kimya na C# na uthibitishaji wa lxml ghafi. +- Ulinganisho wa faili-msalaba ume-normalishwa kwa Unicode, kwa sababu FLEx huandika `.lift` katika NFC na faili mwenza `.lift-ranges` katika NFD. -sil-lift also validates the `.lift-ranges` companions of a loaded lexicon against a schema for standalone ranges documents (vendored from `lift-standard` alongside the base LIFT grammar) — every tracked external ranges file is checked whenever the `.lift` is validated — with no such schema (or check) in the C# world. (There is no entry point for validating a `.lift-ranges` file on its own, detached from a `.lift`.) +sil-lift pia huthibitisha faili za `.lift-ranges` zinazohusiana na kamusi iliyopakiwa dhidi ya skema ya nyaraka huru za masafa (zilizotolewa kutoka `lift-standard` pamoja na sarufi ya msingi ya LIFT) — kila faili ya masafa ya nje inayofuatiliwa hukaguliwa kila wakati `.lift` inapothibitishwa — bila mpangilio kama huo (au ukaguzi) katika ulimwengu wa C#. Hakuna njia ya kuthibitisha faili ya `.lift-ranges` peke yake, bila kuwa na faili ya `.lift`. -## Canonical sorting +## Upangaji rasmi -`Lexicon.sort()` mirrors `LiftSorter`'s core rules (entries by case-insensitive guid; ranges and range-elements by id; header field definitions by tag; senses kept in file order; whitespace inside `` never touched), with three differences: +`Lexicon.sort()` inaakisi kanuni za msingi za `LiftSorter` (vipengele kwa `guid` isiyozingatia herufi kubwa/ndogo; viwango na vipengele vya kiwango kwa `id`; ufafanuzi wa nyanja za kichwa kwa `tag`; maana zinahifadhiwa kulingana na mpangilio wa faili; nafasi tupu ndani ya `` haibadilishwi kamwe), na tofauti tatu: -- entries without a guid sort deterministically by id (`LiftSorter` assumes a guid is present); -- ordering is locale-independent (plain case-folded code points, not .NET invariant-culture collation); -- same-type lists such as notes, relations, and forms keep their document order rather than being re-sorted by key — grouping is already deterministic, and reordering them only adds diff noise. +- Ingizo bila guid huorodheshwa kwa utaratibu wa uhakika kulingana na id (`LiftSorter` huchukulia kuwa guid ipo); +- Uagizaji hautegemei eneo (alama za kawaida zilizopinduliwa kwa herufi, si upangaji wa .NET wa utamaduni usiobadilika); +- Orodha za aina moja kama vile dondoo, mahusiano, na fomu zinadumisha mpangilio wao wa hati badala ya kupangwa upya kwa kutumia funguo — upangaji wa makundi tayari ni wa uhakika, na kuzipanga upya kunazidisha tu kelele za utofauti. -The spec repo's `canonicalizeLift.xsl` is not used at all: it collapses whitespace inside lexical text (destructive) and its generated ids differ on every run. +`canonicalizeLift.xsl` ya repo ya spec haitumiki kabisa: inafuta nafasi tupu ndani ya maandishi ya kileksiki (huharibu) na vitambulisho vyake vinavyotengenezwa hutofautiana kila inapotekelezwa. -## Not carried over +## Haijahamishwa -- WeSay-specific conveniences (dashboard/config handling around LIFT files). -- `SynchronicMerger` (Chorus update merging) — the byte-chunking idea lives on in the fidelity layer, the merging does not. -- LDML writing-system parsing: files in `WritingSystems/` are treated as opaque folder content. +- Vifaa maalum vya WeSay (udhibiti wa dashibodi/usanidi kuhusu faili za LIFT). +- `SynchronicMerger` (Uunganishaji wa masasisho ya kwaya) — wazo la kugawanya baiti katika vipande linaendelea kuishi katika safu ya uaminifu, lakini uunganishaji wenyewe hauendelei. +- Uchanganuzi wa mfumo wa uandishi wa LDML: faili zilizo katika `WritingSystems/` zinachukuliwa kama yaliyomo yasiyoonekana ya folda. From 945fd6752cd58444837b35635d8a594934d5aa72 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:11 -0600 Subject: [PATCH 136/317] New translations fidelity.md (German) [ci skip] --- docs/de/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/de/fidelity.md b/docs/de/fidelity.md index bb4e858..8438436 100644 --- a/docs/de/fidelity.md +++ b/docs/de/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# Fidelity-Garantien -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT ist ein _Austauschformat_: Die oberste Regel lautet: **Lass niemals etwas weg, was du nicht verstehst**. Der Vertrag von `sil-lift`, der bei jedem Durchlauf durch die Testsuite überprüft wird (Korpusdateien sowie eigenschaftsbasierte Generierung): -## Reading +## Lesen -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +Jedes wohlgeformte LIFT 0.13-Dokument wird geladen – auch Inhalte, die nicht dem Schema entsprechen. Alles, was das Modell nicht definiert, wird im „Extras“-Bereich des nächstgelegenen Knotens gespeichert: unbekannte Attribute und Elemente, XML-Kommentare und Verarbeitungsanweisungen, überflüssiger Text sowie fehlerhaft formatierte typisierte Attribute (ein fehlerhaftes Datum bleibt als ursprüngliche Zeichenkette in „Extras“ erhalten; das typisierte Feld ist „None“). -## Saving an unchanged document +## Ein unverändertes Dokument speichern -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()` ohne Änderungen erzeugt eine **byte-identische Ausgabe** – keine Neuformatierung, kein erneutes Escaping, keine Neuanordnung, einschließlich Byte-Order-Markierungen und XML-Deklarationen. Derzeit gibt es keine Normalisierungsliste: Die Identität ist exakt. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +Ausnahmen (der Writer greift auf die vollständige kanonische Serialisierung zurück, die zwar semantisch vollständig, jedoch nicht bytekonsistent ist): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- die Quellkodierung ist nicht ASCII-kompatibel (nicht UTF-8/US-ASCII) oder +- der Quelltext enthält einen DOCTYPE oder +- Der Byte-Scanner und der Parser sind sich hinsichtlich der obersten Struktur des Dokuments nicht einig – beispielsweise bei einem nicht spezifikationskonformen zweiten `
`, den der Parser nur einmal beibehält (der Scanner ist bewusst misstrauisch: Bei jedem Zweifel werden überhaupt keine Quellbytes erfasst), oder +- Der Quellcode wurde im Speicher erstellt und nicht aus einer Datei geladen. -## Saving an edited document +## Ein bearbeitetes Dokument speichern -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **Unveränderte Einträge werden wortwörtlich aus ihren ursprünglichen Bytes ausgegeben.** Ein Eintrag gilt als verändert, wenn sich seit dem Parsen ein beliebiger Teil seines Modellobjekts geändert hat (erkannt anhand eines Snapshots der kanonischen Serialisierung, nicht anhand eines „Dirty“-Flags). +- **Die bearbeiteten Einträge werden kanonisch und vollständig neu serialisiert**: UTF-8, Einrückung mit zwei Leerzeichen _außerhalb_ von gemischtem Inhalt (Leerzeichen innerhalb von `` und `` werden niemals verändert), eine dokumentierte Untergruppierung pro Element (z. B. Eintrag: lexikalische Einheit, Zitat, Aussprachen, Varianten, Bedeutungen, Anmerkungen, Beziehungen, Etymologien, Annotationen, Merkmale, Felder), feste Attributreihenfolge, Datumsangaben nach ISO-8601 (`Z` für UTC). Alle Reste werden erneut ausgegeben; ihre Position wird auf den ursprünglichen Unterindex zurückgesetzt und an die neue Unterliste angepasst (eine Annäherung – exakte Byte-Positionen sind nur für unveränderte Einträge garantiert). +- Das Hinzufügen, Entfernen oder Neuanordnen von Einträgen führt zu einer erneuten Serialisierung der Dokumentstruktur, wobei die Bytes jedes unveränderten Eintrags jedoch unverändert ausgegeben werden. -## Known approximations (touched nodes only) +## Bekannte Näherungswerte (nur berührte Knoten) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- Kommentare _innerhalb_ eines ``-Laufs bleiben erhalten, werden jedoch neben den Lauf verschoben und nicht an ihrer genauen Zeichenposition angezeigt. +- Die kreuzförmige Reihenfolge der untergeordneten Elemente innerhalb eines bearbeiteten Elements wird auf die kanonische Gruppierung normiert (durch das `interleave`-Schema des LIFT-Schemas wird diese Reihenfolge semantisch irrelevant). +- Ein Multitext-Element, das zwar vorhanden ist, aber nichts enthält – weder Formen noch Reste, z. B. `` – wird nicht erneut ausgegeben. Das Modell stellt diese Felder als stets vorhandenes `Multitext` dar (`lexical-unit`, `citation`, `definition`, die `usage` einer Relation sowie `label` / `abbrev` / `description` bei URL-Verweisen, Bereichen, Bereichselementen und der Kopfzeile) dar, sodass sich ein leeres Feld nach der Analyse nicht von einem fehlenden unterscheiden lässt. Es geht keine semantische Information verloren. From d0aafc9dc91aa076dbd33dbf72c5370790aab1e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:12 -0600 Subject: [PATCH 137/317] New translations fidelity.md (Japanese) [ci skip] --- docs/ja/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/ja/fidelity.md b/docs/ja/fidelity.md index bb4e858..ea97f18 100644 --- a/docs/ja/fidelity.md +++ b/docs/ja/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# フィデリティの保証 -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFTは_相互運用_フォーマットです。その鉄則は、**理解できないものは決して削除しない**ということです。 `sil-lift`の契約。これは、実行のたびにテストスイートによって検証されます(コーパスファイルおよびプロパティベースの生成)。 -## Reading +## 読書 -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +正しく構成された LIFT 0.13 ドキュメントであれば、スキーマに違反するコンテンツが含まれていても読み込まれます。 モデルで定義されていないものはすべて、最も近いノードの不透明な `Extras` バケットに格納されます。これには、未知の属性や要素、XML コメントや処理命令、不要なテキスト、および形式不備の型付き属性などが含まれます(不正な日付は、`Extras` 内に元の文字列のまま残され、型付きフィールドは `None` となります)。 -## Saving an unchanged document +## 変更のない文書を保存する -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +編集を行わずに `load()` → `save()` を実行すると、**バイト単位で同一の出力**が生成されます。つまり、再フォーマット、再エスケープ、順序の変更は行われず、バイト順マークやXML宣言も含まれます。 現在、正規化リストは存在しません。恒等式は厳密です。 -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +例外(ライターは完全なカノニカルシリアライゼーションにフォールバックします。これは意味的には完全ですが、バイト単位の整合性は保たれません): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- ソースのエンコーディングがASCII互換ではない(UTF-8/US-ASCIIではない)、または +- ソースにDOCTYPEが含まれているか、または +- バイトスキャナとパーサーの間で、ドキュメントの最上位構造に関する認識が一致しない――例えば、仕様外の2つ目の `
` などである。パーサーはこれを1回だけ保持するが(スキャナは意図的に慎重であり、少しでも疑わしい場合はソースバイトを一切取得しない)、あるいは +- ソースはファイルから読み込まれるのではなく、メモリ上で構築されました。 -## Saving an edited document +## 編集したドキュメントの保存 -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **変更されていないエントリは、元のバイト列そのままが出力されます。** エントリのモデルオブジェクトのいずれかの部分が parse 以降に変更された場合、そのエントリは変更済みとみなされます(これは、ダーティフラグではなく、正規シリアライゼーションのスナップショットによって検出されます)。 +- **変更されたエントリは、標準的な形式で完全に再シリアライズされます**:UTF-8、混合コンテンツの_外部_での2スペースのインデント(``および``内部の空白は一切変更されません)、要素ごとの文書化された子要素のグループ化(例:エントリ: 語彙単位、引用、発音、異形、意味、注釈、関係、語源、注釈、特徴、分野)、固定された属性順序、ISO-8601形式の日付(UTCの場合は`Z`)。 すべての残余データは再出力され、その位置は元の子インデックスに戻され、新しい子リストにクリップされます(これは近似処理であり、変更されていないエントリについてのみ、正確なバイト位置が保証されます)。 +- エントリの追加、削除、または順序変更を行うと、ドキュメント構造は再シリアル化されますが、変更されていないエントリのバイトデータはすべてそのまま出力されます。 -## Known approximations (touched nodes only) +## 既知の近似値(接触したノードのみ) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- `` の実行の `内部` にあるコメントは保持されますが、正確な文字オフセットの位置ではなく、その実行のすぐ隣に持ち上げられます。 +- 編集対象の要素内におけるクロス型の子要素の順序は、正規のグループ化に正規化されます(LIFTスキーマの `interleave` により、この順序は意味的に無意味となります)。 +- 存在はするが、フォームも残留物も一切含まないマルチテキスト要素(例:``)は、再出力されません。 このモデルでは、これらのフィールドを常に存在する `Multitext` として表現しています(`lexical-unit`、`citation`、`definition`、関係の `usage`、およびヘッダーの `label` / `abbrev` / `description`)として常に存在する `Multitext` として表現しているため、解析後は空の `Multitext` と存在しない `Multitext` を区別することができません。 意味的な情報は一切失われません。 From 5691e9506779123c6c9b4d76c21b9d0304327f0f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:14 -0600 Subject: [PATCH 138/317] New translations fidelity.md (Portuguese) [ci skip] --- docs/pt/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/pt/fidelity.md b/docs/pt/fidelity.md index bb4e858..f96dc5b 100644 --- a/docs/pt/fidelity.md +++ b/docs/pt/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# Garantias de fidelidade -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +O LIFT é um formato de _intercâmbio_: a regra fundamental é **nunca descartar aquilo que não se compreende**. O contrato do `sil-lift`, verificado pelo conjunto de testes em cada execução (ficheiros de corpus e geração baseada em propriedades): -## Reading +## Leitura -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +Qualquer documento LIFT 0.13 bem formado é carregado — mesmo que inclua conteúdo inválido em termos de esquema. Tudo o que o modelo não definir é transportado para o conjunto opaco `Extras` do nó mais próximo: atributos e elementos desconhecidos, comentários XML e instruções de processamento, texto disperso e atributos tipados com formato incorreto (uma data inválida permanece como a cadeia de caracteres original em `Extras`; o campo tipado é `None`). -## Saving an unchanged document +## Guardar um documento sem alterações -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()`, sem alterações, gera uma **saída byte a byte idêntica** — sem reformatação, sem reescapamento, sem reordenação, incluindo marcas de ordem de bytes e declarações XML. De momento, não existe nenhuma lista de normalização: a identidade é exata. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +Exceções (o gravador recorre à serialização canónica completa, que é semanticamente completa, mas não preserva os bytes): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- a codificação da fonte não é compatível com ASCII (não é UTF-8/US-ASCII), ou +- o código-fonte contém um DOCTYPE, ou +- o scanner de bytes e o analisador não estão de acordo quanto à estrutura de nível superior do documento — por exemplo, um segundo `
` fora das especificações, que o analisador mantém apenas uma vez (o scanner é deliberadamente cauteloso: qualquer dúvida significa não capturar nenhum byte da fonte), ou +- o código-fonte foi compilado na memória, em vez de ser carregado a partir de um ficheiro. -## Saving an edited document +## Guardar um documento editado -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **As entradas não alteradas são emitidas tal como estão, a partir dos seus bytes originais.** Uma entrada é considerada alterada se alguma parte do seu objeto-modelo tiver sido alterada desde a análise (detetada através de um instantâneo de serialização canónica, e não por um indicador de alteração). +- **As entradas alteradas são re-serializadas de forma canónica e completa**: UTF-8, indentação com 2 espaços _fora_ do conteúdo misto (os espaços dentro de `` e `` nunca são alterados), um agrupamento de elementos filhos documentado por elemento (por exemplo, entrada: unidade lexical, citação, pronúncias, variantes, sentidos, notas, relações, etimologias, anotações, características, campos), ordem fixa dos atributos, datas em ISO-8601 (`Z` para UTC). Todos os resíduos são reemitidos; a sua posição é restaurada no índice filho original, limitada à nova lista de filhos (uma aproximação — as posições exatas em bytes só são garantidas para entradas que não foram alteradas). +- Adicionar, remover ou reordenar entradas faz com que a estrutura do documento seja novamente serializada, mas continua a emitir, tal como estão, os bytes de todas as entradas que não sofreram alterações. -## Known approximations (touched nodes only) +## Aproximações conhecidas (apenas nós tocados) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- Os comentários _dentro_ de uma execução `` são preservados, mas são deslocados para junto da execução, e não para a sua posição exata em termos de caracteres. +- A ordem cruzada de elementos filhos dentro de um elemento editado é normalizada para o agrupamento canónico (o `interleave` do esquema LIFT torna esta ordem semanticamente insignificante). +- Um elemento multitext que esteja presente mas que não contenha nada — nem formas, nem resíduos, por exemplo, `` — não é reemitido. O modelo representa estes campos como um `Multitext` sempre presente (`unidade-lexical`, `citação`, `definição`, o `uso` de uma relação e `rótulo` / `abbrev` / `description` em referências de URL, intervalos, elementos de intervalo e no cabeçalho), pelo que um campo vazio é indistinguível de um ausente após a análise. Não se perde nada em termos semânticos. From 49c28cfe188993f6970c815536ef95ec36728fdb Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:15 -0600 Subject: [PATCH 139/317] New translations fidelity.md (Russian) [ci skip] --- docs/ru/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/ru/fidelity.md b/docs/ru/fidelity.md index bb4e858..217c404 100644 --- a/docs/ru/fidelity.md +++ b/docs/ru/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# Гарантии Fidelity -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT — это формат _обмена данными_: главное правило — **никогда не удалять то, чего не понимаешь**. Контракт `sil-lift`, проверка которого осуществляется набором тестов при каждом запуске (файлы корпуса плюс генерация на основе свойств): -## Reading +## Чтение -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +Загружается любой корректно сформированный документ LIFT 0.13 — включая контент, не соответствующий схеме. Все, что не определено в модели, помещается в непрозрачный контейнер `Extras` ближайшего узла: неизвестные атрибуты и элементы, XML-комментарии и инструкции обработки, случайный текст, а также атрибуты с неверным типом (неправильная дата сохраняется в `Extras` в виде исходной строки; поле типа имеет значение `None`). -## Saving an unchanged document +## Сохранение документа без изменений -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()` без изменений записывает **байтово идентичный вывод** — без переформатирования, без повторного экранирования, без изменения порядка, с сохранением маркеров порядка байтов и деклараций XML. В настоящее время список нормализации отсутствует: тождество является точным. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +Исключения (автор переходит к полной канонической сериализации, которая является семантически полной, но не сохраняет байтовую структуру): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- кодировка исходного текста не совместима с ASCII (не UTF-8/US-ASCII), или +- источник содержит DOCTYPE, либо +- сканер байтов и синтаксический анализатор расходятся во мнениях относительно структуры верхнего уровня документа — например, в случае второго символа `
`, не предусмотренного спецификацией, который синтаксический анализатор сохраняет только один раз (сканер же намеренно проявляет настороженность: при любом сомнении он не фиксирует ни одного байта исходного кода), или +- исходный код был скомпилирован в памяти, а не загружен из файла. -## Saving an edited document +## Сохранение отредактированного документа -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **Неизмененные записи выводятся дословно из исходных байтов.** Запись считается измененной, если какая-либо часть её объекта модели изменилась с момента синтаксического анализа (что определяется по моментальному снимку канонической сериализации, а не по флагу «dirty»). +- **Измененные записи повторно сериализуются канонически и полностью**: UTF-8, отступ в 2 пробела _вне_ смешанного контента (пробелы внутри `` и `` никогда не изменяются), задокументированная группировка дочерних элементов для каждой записи (например, запись: лексическая единица, цитата, варианты произношения, варианты, значения, примечания, связи, этимологии, аннотации, характеристики, поля), фиксированный порядок атрибутов, даты в формате ISO-8601 (`Z` для UTC). Все оставшиеся элементы повторно выводятся; их позиции восстанавливаются в исходном списке дочерних элементов, привязываясь к новому списку дочерних элементов (это приблизительное значение — точные позиции в байтах гарантируются только для нетронутых записей). +- Добавление, удаление или изменение порядка записей приводит к повторной сериализации структуры документа, однако байты каждой неизменённой записи по-прежнему выводятся дословно. -## Known approximations (touched nodes only) +## Известные приближения (только затронутые узлы) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- Комментарии, расположенные _внутри_ блока ``, сохраняются, но перемещаются рядом с этим блоком, а не на точное место по количеству символов. +- Крестообразный порядок дочерних элементов внутри редактируемого элемента приводится в соответствие с канонической группировкой (параметр `interleave` схемы LIFT делает этот порядок семантически несущественным). +- Элемент «multitext», который присутствует, но не содержит ничего — ни форм, ни остаточных элементов, например, ``, — не повторно выводится. Модель представляет эти поля в виде всегда присутствующего объекта `Multitext` (`lexical-unit`, `citation`, `definition`, `usage` отношения и `label` / `abbrev` / `description` для ссылок на URL, диапазонов, элементов диапазона и заголовка), поэтому пустое поле после синтаксического анализа неотличимо от отсутствующего. Ничего из семантики не теряется. From eb138664cbdc8ed507b0fe2bcbd2e7f34ac27f72 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:17 -0600 Subject: [PATCH 140/317] New translations fidelity.md (Chinese Simplified) [ci skip] --- docs/zh/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/zh/fidelity.md b/docs/zh/fidelity.md index bb4e858..b0af42d 100644 --- a/docs/zh/fidelity.md +++ b/docs/zh/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# 富达保证 -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT 是一种_交换_格式:其首要原则是**绝不舍弃你不理解的内容**。 `sil-lift` 的契约,在每次运行时均由测试套件进行验证(包括语料库文件以及基于属性的生成): -## Reading +## 阅读 -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +任何格式正确的 LIFT 0.13 文档都能加载——即使其中包含不符合模式的内容。 模型未定义的内容将存放在最近节点的不透明 `Extras` 桶中:未知属性和元素、XML 注释和处理指令、散落的文本,以及格式错误的类型化属性(错误的日期将作为原始字符串保存在 `Extras` 中;其类型化字段为 `None`)。 -## Saving an unchanged document +## 保存未作修改的文档 -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()`(未进行任何编辑)将生成**字节完全相同的输出**——不进行重新格式化、不进行重新转义、不重新排序,并包含字节序标记和XML声明。 目前没有规范化列表:恒等式是精确的。 -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +例外情况(写入器将回退到完整的规范序列化,这种序列化在语义上完整,但无法保留字节顺序): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- 源编码与 ASCII 不兼容(非 UTF-8/US-ASCII),或者 +- 源文件中包含 DOCTYPE 声明,或者 +- 字节扫描器和解析器对文档的顶级结构存在分歧——例如,出现了一个不符合规范的第二个 `
`,解析器只保留一次(扫描器则采取了刻意谨慎的态度:一旦产生怀疑,就完全不捕获源代码字节),或者 +- 源代码是在内存中构建的,而不是从文件中加载的。 -## Saving an edited document +## 保存已编辑的文档 -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- \*\*未被修改的条目将按其原始字节内容原样输出。\*\*如果条目的模型对象自解析以来有任何部分发生变化(通过规范序列化快照检测,而非通过“已修改”标志),则该条目被视为已被修改。 +- **被修改的条目将按照规范进行完全重新序列化**:UTF-8 编码,混合内容_外部_采用双空格缩进(`` 和 `` 内部的空格绝不更改),每个元素均按文档规定进行子元素分组(例如条目: 词汇单元、引用、发音、变体、词义、注释、关联、词源、标注、特征、领域),固定的属性顺序,日期采用 ISO-8601 格式(`Z` 表示 UTC)。 所有残留项都会被重新发出;其位置将恢复到原始子索引处,并限定在新的子列表范围内(这是一种近似处理——只有未被修改的条目才能保证精确的字节位置)。 +- 添加、删除或重新排序条目会重新序列化文档结构,但仍会原样输出每个未更改条目的字节。 -## Known approximations (touched nodes only) +## 已知的近似值(仅限已访问节点) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- 在 `` 运行块`内部`的注释会被保留,但会被提升到运行块旁边,而不是保留在它们的精确字符偏移量位置。 +- 在已编辑元素内的交叉型子元素顺序会被规范化为规范分组(LIFT 模式中的 `interleave` 使得该顺序在语义上不具意义)。 +- 一个虽然存在但不包含任何内容(既无形式,也无残留)的多文本元素——例如 `` ——不会被重新输出。 该模型将这些字段表示为始终存在的 `Multitext`(包括 `lexical-unit`、`citation`、`definition`、关系的 `usage` 以及 `label` / `abbrev` / `description`,这些字段分别位于 URL 引用、范围、范围元素以及标题中),因此解析后,空字段与缺失字段无法区分。 没有任何语义上的损失。 From d84919bde0513abb31979d576c5ff88807c18ace Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:19 -0600 Subject: [PATCH 141/317] New translations fidelity.md (Hindi) [ci skip] --- docs/hi/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/hi/fidelity.md b/docs/hi/fidelity.md index bb4e858..1be39cc 100644 --- a/docs/hi/fidelity.md +++ b/docs/hi/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# फिडेलिटी गारंटी -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT एक _इंटरचेंज_ प्रारूप है: मुख्य नियम है **जिस चीज़ को आप नहीं समझते, उसे कभी न छोड़ें**। `sil-lift` का कॉन्ट्रैक्ट, जिसे हर रन पर टेस्ट सूट (कॉर्पस फ़ाइलें और प्रॉपर्टी-आधारित जेनरेशन) द्वारा सत्यापित किया जाता है: -## Reading +## पढ़ना -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +कोई भी अच्छी तरह से निर्मित LIFT 0.13 दस्तावेज़ लोड हो जाता है — स्कीमा-अमान्य सामग्री सहित। जो कुछ भी मॉडल परिभाषित नहीं करता है, वह निकटतम नोड के अपारदर्शी `Extras` बकेट में रखा जाता है: अज्ञात गुण और तत्व, XML टिप्पणियाँ और प्रसंस्करण निर्देश, बिखरा हुआ पाठ, और गलत प्रकार के गुण (एक गलत दिनांक `Extras` में मूल स्ट्रिंग के रूप में बनी रहती है; प्रकार का क्षेत्र `None` होता है)। -## Saving an unchanged document +## बिना बदले दस्तावेज़ को सहेजें -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()` बिना किसी संपादन के **बाइट-समान आउटपुट** लिखता है — कोई पुनः स्वरूपण नहीं, कोई पुनः एस्केपिंग नहीं, कोई पुनर्विन्यास नहीं, बाइट-ऑर्डर मार्क और XML घोषणाएँ शामिल हैं। वर्तमान में कोई सामान्यीकरण सूची नहीं है: पहचान सटीक है। -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +अपवाद (लेखक पूर्ण कैनोनिकल सीरियलाइज़ेशन पर वापस चला जाता है, जो अर्थगत रूप से पूर्ण है लेकिन बाइट-संरक्षण नहीं करता): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- स्रोत एन्कोडिंग ASCII-संगत नहीं है (UTF-8/US-ASCII नहीं), या +- स्रोत में एक DOCTYPE है, या +- बाइट स्कैनर और पार्सर दस्तावेज़ की शीर्ष-स्तरीय संरचना को लेकर असहमत हैं — उदाहरण के लिए विनिर्देश के बाहर का दूसरा `
`, जिसे पार्सर केवल एक बार रखता है (स्कैनर जानबूझकर अविश्वासी है: कोई भी संदेह होने पर वह कोई भी स्रोत बाइट नहीं पकड़ता), या +- स्रोत फ़ाइल से लोड करने के बजाय मेमोरी में बनाया गया था। -## Saving an edited document +## संपादित दस्तावेज़ सहेजें -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **अछूटी प्रविष्टियाँ उनके मूल बाइट्स से शब्दशः उत्सर्जित की जाती हैं।** एक प्रविष्टि को तब छूई हुई माना जाता है यदि पार्स के बाद उसके मॉडल ऑब्जेक्ट का कोई भी भाग बदला गया हो (यह कैनोनिकल-सीरियलाइजेशन स्नैपशॉट द्वारा पता लगाया जाता है, डर्टी फ्लैग द्वारा नहीं)। +- स्पर्शित प्रविष्टियाँ मानक रूप से और पूरी तरह से पुनः सीरियलाइज़ की जाती हैं: UTF-8, मिश्रित सामग्री के बाहर 2-स्पेस इंडेंटेशन (`` और `` के अंदर रिक्त स्थान कभी नहीं बदला जाता), प्रत्येक तत्व के लिए एक प्रलेखित उपसमूह (उदाहरण के लिए प्रविष्टि: शब्द-इकाई, उद्धरण, उच्चारण, रूप, अर्थ, टिप्पणियाँ, संबंध, व्युत्पत्तियाँ, टिप्पणियाँ, विशेषताएँ, क्षेत्र), निश्चित गुणक्रम, ISO-8601 में दिनांक (`Z` UTC के लिए)। सभी अवशेष पुनः उत्सर्जित किए जाते हैं; इसकी स्थिति मूल चाइल्ड इंडेक्स पर पुनर्स्थापित की जाती है, और इसे नई चाइल्ड सूची से क्लैम्प किया जाता है (एक अनुमान — सटीक बाइट स्थितियाँ केवल अछूती प्रविष्टियों के लिए ही गारंटी की जाती हैं)। +- प्रविष्टियाँ जोड़ने, हटाने या पुनर्व्यवस्थित करने से दस्तावेज़ की संरचना पुनः अनुक्रमित होती है, लेकिन फिर भी हर अपरिवर्तित प्रविष्टि के बाइट्स को शब्दशः उत्सर्जित किया जाता है। -## Known approximations (touched nodes only) +## ज्ञात अनुमान (केवल स्पर्श किए गए नोड्स) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- `` रन के अंदर की टिप्पणियाँ संरक्षित रहती हैं, लेकिन इन्हें उनके सटीक वर्ण-ऑफसेट पर नहीं, बल्कि रन के बगल में ऊपर ला दिया जाता है। +- संपादित तत्व के भीतर क्रॉस-टाइप बाल क्रम को मानक समूहबद्धता में सामान्यीकृत किया जाता है (LIFT स्कीमा का `interleave` इस क्रम को अर्थगत रूप से महत्वहीन बना देता है)। +- एक मल्टीटेक्स्ट तत्व जो मौजूद तो है लेकिन कुछ भी नहीं ले जाता — न कोई फॉर्म, न कोई अवशेष, उदाहरण के लिए `` — पुनः उत्सर्जित नहीं होता। मॉडल इन फ़ील्ड्स को हमेशा मौजूद `Multitext` (`lexical-unit`, `citation`, `definition`, किसी संबंध का `usage`, और `label` / `abbrev` / `description` url-refs, रेंज, रेंज-एलिमेंट्स और हेडर पर), इसलिए पार्सिंग के बाद एक खाली फ़ील्ड का अभाव वाले फ़ील्ड से कोई अंतर नहीं किया जा सकता। कोई भी अर्थपूर्ण बात खोई नहीं है। From 96036d79a08f36740855adae33a70d8f36d3c9b2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:21 -0600 Subject: [PATCH 142/317] New translations fidelity.md (Swahili) [ci skip] --- docs/sw/fidelity.md | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/docs/sw/fidelity.md b/docs/sw/fidelity.md index bb4e858..ea45796 100644 --- a/docs/sw/fidelity.md +++ b/docs/sw/fidelity.md @@ -1,30 +1,30 @@ -# Fidelity guarantees +# Dhamana za uaminifu -LIFT is an _interchange_ format: the cardinal rule is **never drop what you do not understand**. `sil-lift`'s contract, verified by the test suite on every run (corpus files plus property-based generation): +LIFT ni muundo wa kubadilishana: kanuni kuu ni **usitupe kile usichokielewa**. Mkataba wa `sil-lift`, uliothibitishwa na mkusanyiko wa majaribio katika kila utekelezaji (faili za koropusi pamoja na uundaji unaotegemea sifa): -## Reading +## Kusoma -Any well-formed LIFT 0.13 document loads — schema-invalid content included. Whatever the model does not define is carried in the nearest node's opaque `Extras` bucket: unknown attributes and elements, XML comments and processing instructions, stray text, and malformed typed attributes (a bad date stays as the original string in `Extras`; the typed field is `None`). +Hati yoyote ya LIFT 0.13 iliyoundwa vizuri hupakiwa — ikijumuisha maudhui yasiyoendana na skema. Chochote ambacho mfano haujafafanua huhifadhiwa kwenye baketi isiyoeleweka ya `Extras` ya nodi iliyo karibu zaidi: sifa na vipengele visivyojulikana, maoni ya XML na maagizo ya usindikaji, maandishi yaliyotapakaa, na sifa za aina zisizojengwa ipasavyo (tarehe isiyo sahihi inabaki kama msururu wa awali katika `Extras`; uwanja wa aina ni `None`). -## Saving an unchanged document +## Kuhifadhi hati bila mabadiliko -`load()` → `save()` with no edits writes **byte-identical output** — no reformatting, no re-escaping, no reordering, byte-order marks and XML declarations included. There is currently no normalization list: identity is exact. +`load()` → `save()` bila mabadiliko huandika **matokeo yanayofanana kabisa kwa baiti** — hakuna kupanga upya muundo, hakuna kurejesha tena alama za kutoroka, hakuna kupanga upya mpangilio, alama za mpangilio wa baiti na matangazo ya XML zimejumuishwa. Kwa sasa hakuna orodha ya kawaida: utambulisho ni sahihi kabisa. -Exceptions (the writer falls back to full canonical serialization, which is semantically complete but not byte-preserving): +Vilevyo vya kipekee (mwandishi anarudi kwenye mfululizo kamili wa kanoniki, ambao kimaana ni kamili lakini hauhifadhi baiti): -- the source encoding is not ASCII-compatible (not UTF-8/US-ASCII), or -- the source contains a DOCTYPE, or -- the byte scanner and the parser disagree about the document's top-level structure — for instance an out-of-spec second `
`, which the parser keeps only once (the scanner is deliberately distrustful: any doubt means capturing no source bytes at all), or -- the source was built in memory rather than loaded from a file. +- Ukodishaji wa chanzo hauendani na ASCII (sio UTF-8/US-ASCII), au +- chanzo kina DOCTYPE, au +- kikagua baiti na mchanganuzi havikubaliani kuhusu muundo wa ngazi ya juu wa hati — kwa mfano `
` ya pili isiyoendana na vipimo, ambayo mchanganuzi huihifadhi mara moja tu (kikagua baiti hakiamini kwa makusudi: shaka yoyote inamaanisha hakuna baiti za chanzo zinazoshikiliwa kabisa), au +- Chanzo kilijengwa kwenye kumbukumbu badala ya kupakiwa kutoka kwenye faili. -## Saving an edited document +## Kuhifadhi hati iliyohaririwa -- **Untouched entries are emitted verbatim from their original bytes.** An entry counts as touched if any part of its model object changed since parse (detected by canonical-serialization snapshot, not a dirty flag). -- **Touched entries are re-serialized canonically and completely**: UTF-8, 2-space indentation _outside_ mixed content (whitespace inside `` and `` is never altered), a documented child grouping per element (e.g. entry: lexical-unit, citation, pronunciations, variants, senses, notes, relations, etymologies, annotations, traits, fields), fixed attribute order, dates in ISO-8601 (`Z` for UTC). All residue is re-emitted; its position is restored to the original child index, clamped to the new child list (an approximation — exact byte positions are only guaranteed for untouched entries). -- Adding, removing, or reordering entries re-serializes the document structure but still emits every unchanged entry's bytes verbatim. +- **Maingizo yasiyoguswa hutolewa neno kwa neno kutoka kwa baiti zao za awali.** Ingizo linahesabiwa kuwa limeguswa ikiwa sehemu yoyote ya kitu chake cha mfano imebadilika tangu uchanganuzi (inagunduliwa na picha ya kanonali-serialization, si bendera ya uchafu). +- **Maingizo yaliyoguswa yanaserializwa tena kwa kanuni na kikamilifu**: UTF-8, uingizaji wa nafasi mbili _nje_ ya maudhui mchanganyiko (nafasi tupu ndani ya `` na `` haibadilishwi kamwe), upangaji wa vikundi vya watoto uliodokumentishwa kwa kila kipengele (mfano: ingizo: kitengo-cha-msamiati, nukuu, matamshi, aina-tofauti, maana, dondoo, uhusiano, asili-ya-neno, maelezo-ya-nyongeza, sifa, nyanja), mpangilio thabiti wa sifa, tarehe kwa ISO-8601 (`Z` kwa UTC). Baki yote inatolewa tena; nafasi yake inarejeshwa kwenye kiashiria cha awali cha mtoto, na kufungwa kwenye orodha mpya ya watoto (ni makadirio — nafasi halisi za baiti zinahakikishwa tu kwa vipengee visivyoguswa). +- Kuongeza, kuondoa, au kupanga upya maingizo kunasababisha muundo wa hati kusiriwa upya kwa mpangilio wa mfululizo, lakini bado hutoa baiti za kila kiingizo kisichobadilika neno kwa neno. -## Known approximations (touched nodes only) +## Makadirio yanayojulikana (nodsi zilizoguswa pekee) -- Comments _inside_ a `` run are preserved but hoisted next to the run, not at their exact character offset. -- Cross-type child order within an edited element is normalized to the canonical grouping (the LIFT schema's `interleave` makes this order semantically insignificant). -- A multitext element that is present but carries nothing — no forms, no residue, e.g. `` — is not re-emitted. The model represents these fields as an always-present `Multitext` (`lexical-unit`, `citation`, `definition`, a relation's `usage`, and `label` / `abbrev` / `description` on url-refs, ranges, range-elements and the header), so an empty one is indistinguishable from an absent one after parsing. Nothing semantic is lost. +- Maoni ndani ya utekelezaji wa `` yanahifadhiwa lakini huwekwa juu kando ya utekelezaji, badala ya mahali pao halisi pa herufi. +- Agizo la mtoto la aina ya msalaba ndani ya kipengele kilichohaririwa linawekwa katika muundo wa kawaida wa makundi (shemia ya LIFT `interleave` hufanya mpangilio huu usiwe na maana kimaana). +- Kipengele cha multitext kilichopo lakini hakibebi chochote — hakuna fomu, hakuna mabaki, mfano `` — hakitolewa tena. Mfano unawakilisha nyanja hizi kama `Multitext` inayopatikana kila wakati (`lexical-unit`, `citation`, `definition`, `usage` ya uhusiano, na `label` / `abbrev` / `description` kwenye marejeleo ya URL, vipimo, vipengele vya kipimo na kichwa), hivyo tupu haiwezi kutofautishwa na kutokuwepo baada ya uchanganuzi. Hakuna kitu cha kisemantiki kinachopotea. From 3a4c90442920a1cfac058cfc838f4001b7b523a6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:23 -0600 Subject: [PATCH 143/317] New translations build-export.md (German) [ci skip] --- docs/de/guides/build-export.md | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/de/guides/build-export.md b/docs/de/guides/build-export.md index ce13b26..9c0f08f 100644 --- a/docs/de/guides/build-export.md +++ b/docs/de/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# Beispiel: Erstellung eines LIFT-Exports von Grund auf -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +Wenn Sie die Daten einer anderen Anwendung als LIFT exportieren – die Aufgabe, die hinter [Erstellung konformer LIFT-Dateien](lift-export-interop.md) steht –, kann `sil-lift` das Dokument Objekt für Objekt aufbauen und serialisieren, anstatt XML manuell zu generieren. Hier wird ein Skript Schritt für Schritt erläutert, das einen Eintrag mit den Bestandteilen eines echten Wörterbuchs erstellt (mehrere Schriftsysteme, eine Aussprache, eine Bedeutung mit einem Beispiel, eine Illustration, ein Merkmal des semantischen Bereichs und ein anwendungsspezifisches Feld), die kontrollierten Vokabulare in eine zugehörige `.lift-ranges`-Datei schreibt, die Daten validiert und speichert. -## The script +## Das Drehbuch ```python from pathlib import Path @@ -11,20 +11,20 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# Ein Eintrag, der aus dem Quellmodell erstellt wurde. entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Sprecher: Ana" # Die Konvention des Combine für Sprecherbezeichnungen pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) sense = sil_lift.Sense(id="kanga_s1") sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) -sense.definition["en"] = "a domestic fowl kept for its eggs and meat" +sense.definition["en"] = "ein Hausgeflügel, das wegen seiner Eier und seines Fleisches gehalten wird" example = sil_lift.Example() example.forms["seh"] = "Ndinafuna nkhuku." @@ -34,27 +34,27 @@ example.translations.append(translation) sense.examples.append(example) photo = sil_lift.URLRef(href="pictures/hen.jpg") -photo.label["en"] = "A hen" +photo.label["en"] = "Eine Henne" sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # ein anwendungsspezifisches Zusatzfeld scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# Die kontrollierten Vokabulare, auf die sich der Eintrag bezieht, in einer zugehörigen .lift-ranges-Datei. ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# Überprüfe, was save() schreiben würde, bevor die Datei auf die Festplatte geschrieben wird. problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"validation: {len(problems)} Problem(e)") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## Was dabei entsteht -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`Validierung: 0 Problem(e)`, dann das `.lift` und sein Begleitelement nebeneinander: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## Hinweise zur API -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- Multitext-Felder (`lexical_unit`, `definition`, eine `Form`/`URLRef`-Bezeichnung, der Inhalt eines `Field`s, ...) Über die Mapping-Schnittstelle wird pro Schriftsystem eine Zeichenfolge übernommen: `entry.lexical_unit["seh"] = "nkhuku"` fügt ein `` hinzu. Ein Quellmodell, das Zeichenfolgen anhand des Sprachcodes zuordnet, lässt sich direkt darauf abbilden. +- `RangesFile.add_range()` / `Range.add_element()` erstellen die kontrollierten Vokabulare, und `Lexicon.add_ranges_file(ranges, href=...)` fügt das zugehörige Dokument hinzu und ergänzt die Header-Referenzen `` – sodass die Einträge `` und `` auf die von Ihnen definierten Bereiche verweisen. +- Ein `URLRef` besteht aus einem `href` sowie einem optionalen Multitext für eine Beschriftung oder Bezeichnung – er wird sowohl für `` (Audio) als auch für `` (Fotos) verwendet. Die Aussprache folgt hier der Konvention von „The Combine“, wonach die „en“-Form wie folgt ausgesprochen wird: „Sprecher: “. +- App-spezifische Daten ohne native LIFT-Heimfahrten als „ “ (oder „ “): FieldWorks interpretiert diese als benutzerdefinierte Felder, und The Combine behält sie bei. +- Weisen Sie jedem Eintrag eine echte, stabile `guid` zu (z. B. aus `uuid.uuid4()`, die bei allen Exporten wiederverwendet wird) – bei einem späteren Reimport wird der Eintrag an Ort und Stelle aktualisiert, anstatt ihn zu duplizieren. `sil-lift validate --require-ids` sorgt dafür, dass dies eingehalten wird. +- `lex.iter_problems()` überprüft das Dokument im Arbeitsspeicher (das, was `save()` schreiben würde), bevor Daten auf die Festplatte geschrieben werden; hier ist es fehlerfrei. Da das Lexikon noch keinen Ordner hat, werden die Überprüfungen auf Medienpräsenz und Companion-Href übersprungen – führen Sie [`sil-lift validate`](cli.md) auf der gespeicherten Ausgabe aus (oder mit `--no-check-media`), sobald die Audio- und Fotodateien vorhanden sind. -## Packaging +## Verpackung -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` schreibt die Ordnerstruktur (`.lift` + `.lift-ranges` nebeneinander). Um ein einzelnes ZIP-Paket zu erstellen, das von FieldWorks und The Combine direkt importiert werden kann, verwenden Sie stattdessen `lex.save_zip("birds.zip")` – siehe [Erstellung konformer LIFT-Dateien](lift-export-interop.md). From 1d7efd9c175658a14b48d0d920cc845e3acea5e6 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:24 -0600 Subject: [PATCH 144/317] New translations build-export.md (Japanese) [ci skip] --- docs/ja/guides/build-export.md | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/ja/guides/build-export.md b/docs/ja/guides/build-export.md index ce13b26..280bb86 100644 --- a/docs/ja/guides/build-export.md +++ b/docs/ja/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# 実践例:LIFTエクスポートをゼロから作成する -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +他のアプリケーションのデータをLIFTとしてエクスポートする場合――これは[準拠したLIFTの生成](lift-export-interop.md)で説明されている作業です――`sil-lift`を使用すれば、手動でXMLを生成する代わりに、ドキュメントをオブジェクト単位で構築してシリアライズすることができます。 ここでは、実際の辞書に含まれる要素(複数の表記体系、発音、例文付きの語義、イラスト、意味領域の特徴、およびアプリケーション固有のフィールド)を用いて項目を構築し、管理語彙を `.lift-ranges` コンパニオンに書き出し、検証を行い、保存するスクリプトの手順を解説します。 -## The script +## 脚本 ```python from pathlib import Path @@ -11,13 +11,13 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# ソースモデルから構築された1つのエントリ。 entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # The Combine の話者ラベルの規則 pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) @@ -39,22 +39,22 @@ sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # アプリ固有の追加フィールド scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# エントリが参照する統制語彙(付随する .lift-ranges 内に記述)。 ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# ディスクに書き込む前に、save() が書き込む内容を検証します。 problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"validation: {len(problems)} 個の問題") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## どのような成果が得られるか -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`validation: 0 problem(s)` と表示されたら、`.lift` とそのコンパニオンを並べて表示します: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## APIに関する注意事項 -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- マルチテキストフィールド(`lexical_unit`、`definition`、`Form`/`URLRef`のラベル、`Field`の内容など) マッピングインターフェースを通じて、各文字体系ごとに1つの文字列を取り込みます。`entry.lexical_unit["seh"] = "nkhuku"` とすると、`` が追加されます。 言語コードをキーとする文字列を含むソースモデルは、これにそのまま対応します。 +- `RangesFile.add_range()` / `Range.add_element()` によって制御語彙が構築され、`Lexicon.add_ranges_file(ranges, href=...)` によってコンパニオンが紐付けられ、ヘッダー `` の参照が追加されます。これにより、エントリの `` および `` は、定義した範囲に対して解決されるようになります。 +- `URLRef` とは、href にオプションのキャプションやラベルなどのマルチテキストを加えたもので、``(音声)と ``(写真)の両方で使用されます。 ここでの発音は、The Combine の慣例に従い、`en` 形式で「 」と読みます。 +- ネイティブのLIFTホームライドが含まれないアプリ固有のデータは、``(または``)として指定されます。FieldWorksはこれらをカスタムフィールドとして読み取り、The Combineはそれらを保持します。 +- すべてのエントリに、実際の安定した `guid`(例:`uuid.uuid4()` から生成し、エクスポート間で再利用)を割り当ててください。そうすれば、後で再インポートした際に、エントリが複製されることなく、その場で更新されます。 `sil-lift validate --require-ids` はこのルールを強制します。 +- `lex.iter_problems()` は、データがディスクに書き込まれる前に、メモリ内のドキュメント(`save()` が書き込む内容)の整合性を検証します。ここでは、そのドキュメントに問題はありません。 この辞書にはまだフォルダが存在しないため、media-presence および companion-href のチェックはスキップされます。音声ファイルと写真ファイルが所定の場所に配置されたら、保存された出力に対して [`sil-lift validate`](cli.md) を実行してください(または `--no-check-media` オプションを指定して実行してください)。 -## Packaging +## パッケージ -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` を実行すると、フォルダ形式(`.lift` と `.lift-ranges` を並べて配置)で保存されます。 FieldWorks や The Combine が直接インポートできる単一の ZIP パッケージを出力するには、代わりに `lex.save_zip("birds.zip")` を使用してください。詳細は [準拠した LIFT の生成](lift-export-interop.md) を参照してください。 From 9f57ccd95fa8fc78ffb9b98156ad21e03ff0e72f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:26 -0600 Subject: [PATCH 145/317] New translations build-export.md (Portuguese) [ci skip] --- docs/pt/guides/build-export.md | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/docs/pt/guides/build-export.md b/docs/pt/guides/build-export.md index ce13b26..0dd291c 100644 --- a/docs/pt/guides/build-export.md +++ b/docs/pt/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# Exemplo prático: criar uma exportação LIFT a partir do zero -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +Se estiver a exportar dados de outra aplicação no formato LIFT — a tarefa subjacente a [Produção de LIFT em conformidade](lift-export-interop.md) — o `sil-lift` pode construir o documento objeto a objeto e serializá-lo, em vez de gerar XML manualmente. Este guia explica passo a passo um script que cria uma entrada com os elementos que um dicionário real possui (vários sistemas de escrita, uma pronúncia, um significado com um exemplo, uma ilustração, uma característica do domínio semântico e um campo específico da aplicação), grava os vocabulários controlados num ficheiro complementar `.lift-ranges`, valida e guarda. -## The script +## O guião ```python from pathlib import Path @@ -11,20 +11,20 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# Uma entrada, criada a partir do modelo de origem. entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # A convenção de rotulagem de falantes do Combine pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) sense = sil_lift.Sense(id="kanga_s1") -sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Substantivo") sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) -sense.definition["en"] = "a domestic fowl kept for its eggs and meat" +sense.definition["en"] = "uma ave doméstica criada pelos seus ovos e carne" example = sil_lift.Example() example.forms["seh"] = "Ndinafuna nkhuku." @@ -34,27 +34,27 @@ example.translations.append(translation) sense.examples.append(example) photo = sil_lift.URLRef(href="pictures/hen.jpg") -photo.label["en"] = "A hen" +photo.label["en"] = "Uma galinha" sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # um campo extra específico da aplicação scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# Os vocabulários controlados a que a entrada se refere, num ficheiro .lift-ranges. ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# Validar o que o save() escreveria, antes de gravar no disco. problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"validação: {len(problems)} problema(s)") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## O que produz -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`validação: 0 problema(s)`, e, em seguida, o `.lift` e o seu equivalente lado a lado: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## Notas sobre a API -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- Campos multitexto (`lexical_unit`, `definition`, um rótulo de `Form`/`URLRef`, o conteúdo de um `Field`, ...) selecione uma sequência por sistema de escrita através da interface de mapeamento: `entry.lexical_unit["seh"] = "nkhuku"` adiciona um ``. Um modelo de origem que indexa cadeias de caracteres pelo código do idioma corresponde diretamente a isto. +- `RangesFile.add_range()` / `Range.add_element()` criam os vocabulários controlados, e `Lexicon.add_ranges_file(ranges, href=...)` associa o vocabulário complementar e adiciona as referências de cabeçalho `` — para que os campos `` e `` da entrada sejam resolvidos de acordo com os intervalos que definiu. +- Um `URLRef` é um href acompanhado de um texto múltiplo opcional (legenda/rótulo) — utilizado tanto para `` (áudio) como para `` (fotografias). A pronúncia aqui segue a convenção do The Combine, que prevê uma forma «en» que se lê «Orador: ». +- Dados específicos da aplicação que não incluam viagens de regresso a casa nativas do LIFT, como « » (ou « »): o FieldWorks interpreta-os como campos personalizados e o The Combine preserva-os. +- Atribua a cada entrada um `guid` válido e estável (por exemplo, gerado por `uuid.uuid4()`, reutilizado em todas as exportações) — uma reimportação posterior atualiza a entrada no local, em vez de a duplicar. O comando `sil-lift validate --require-ids` garante que isso seja cumprido. +- A função `lex.iter_problems()` valida o documento na memória (o que a função `save()` iria gravar) antes de qualquer coisa ser gravada no disco; neste caso, está correto. Como o léxico ainda não tem nenhuma pasta, as verificações de «media-presence» e «companion-href» são ignoradas — execute [`sil-lift validate`](cli.md) na saída guardada (ou com `--no-check-media`) assim que os ficheiros de áudio e de fotografias estiverem no local. -## Packaging +## Embalagem -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` grava a estrutura da pasta (ficheiros `.lift` e `.lift-ranges` lado a lado). Para gerar um único pacote compactado que o FieldWorks e o The Combine importem diretamente, utilize `lex.save_zip("birds.zip")` — consulte [Produção de LIFT em conformidade](lift-export-interop.md). From 6c1070761e0ad78c386ddf01d61a0ae016cf9638 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:28 -0600 Subject: [PATCH 146/317] New translations build-export.md (Russian) [ci skip] --- docs/ru/guides/build-export.md | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/ru/guides/build-export.md b/docs/ru/guides/build-export.md index ce13b26..9ec97a6 100644 --- a/docs/ru/guides/build-export.md +++ b/docs/ru/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# Пример с расчетами: создание экспорта LIFT с нуля -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +Если вы экспортируете данные другого приложения в формате LIFT — что и является целью задачи [Создание LIFT-документов, соответствующих стандарту](lift-export-interop.md) — `sil-lift` может сформировать документ объект за объектом и сериализовать его, вместо того чтобы вручную генерировать XML. Здесь подробно описан один скрипт, который формирует запись, содержащую все элементы, присущие реальному словарю (несколько систем письма, произношение, значение с примером, иллюстрацию, характеристику семантической области и поле, специфичное для приложения), записывает контролируемые словари в сопутствующий файл `.lift-ranges`, проверяет их на корректность и сохраняет. -## The script +## Сценарий ```python from pathlib import Path @@ -11,13 +11,13 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# Одна запись, построенная на основе исходной модели. entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # Конвенция Combine для обозначения говорящего pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) @@ -34,27 +34,27 @@ example.translations.append(translation) sense.examples.append(example) photo = sil_lift.URLRef(href="pictures/hen.jpg") -photo.label["en"] = "A hen" +photo.label["en"] = "Курица" sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # дополнительное поле, специфичное для приложения scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# Контролируемые словари, на которые ссылается запись, в сопутствующем файле .lift-ranges. ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# Проверить, что запишет функция save(), прежде чем записывать на диск. problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"validation: {len(problems)} проблема(ы)") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## Что он производит -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`validation: 0 problem(s)`, а затем `.lift` и его сопутствующий код рядом: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## Примечания по API -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- Поля с несколькими текстами (`lexical_unit`, `definition`, метка `Form`/`URLRef`, содержимое `Field`, ...) Через интерфейс сопоставления передать по одной строке для каждой системы письма: `entry.lexical_unit["seh"] = "nkhuku"` добавляет ``. Модель исходных данных, в которой строки индексируются по коду языка, напрямую соответствует этой схеме. +- `RangesFile.add_range()` / `Range.add_element()` формируют контролируемые словари, а `Lexicon.add_ranges_file(ranges, href=...)` присоединяет сопутствующий файл и добавляет ссылки в заголовок `` — таким образом, ссылки `` и `` в записи разрешаются в соответствии с заданными вами диапазонами. +- `URLRef` — это атрибут `href` с дополнительным многострочным текстом подписи или метки (необязательным) — используется как для `` (аудио), так и для `` (фотографии). Произношение здесь соответствует принятой в «The Combine» конвенции, согласно которой форма «en» читается как «Speaker: ». +- Данные, специфичные для приложения, не содержащие данных о поездках домой по системе LIFT, в формате `` (или ``): FieldWorks интерпретирует их как пользовательские поля, а The Combine сохраняет их. +- Присваивайте каждой записи уникальный и стабильный `guid` (например, с помощью `uuid.uuid4()`, который используется повторно при всех экспортах) — при последующем повторном импорте запись будет обновлена на месте, а не дублирована. Команда `sil-lift validate --require-ids` обеспечивает соблюдение этого требования. +- Функция `lex.iter_problems()` проверяет документ, хранящийся в памяти (то, что записала бы функция `save()`), прежде чем какие-либо данные поступят на диск; в данном случае он находится в исправном состоянии. Поскольку для лексикона пока не создана папка, проверки наличия медиафайлов и ссылок на сопутствующие ресурсы пропускаются — запустите команду [`sil-lift validate`](cli.md) на сохраненном выводе (или с параметром `--no-check-media`), как только аудио- и фотофайлы будут размещены в соответствующих папках. -## Packaging +## Упаковка -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +Команда `lex.save("export/birds.lift")` записывает папку в формате (файлы `.lift` и `.lift-ranges`, расположенные рядом). Чтобы сгенерировать единый ZIP-архив, который программы FieldWorks и The Combine могут импортировать напрямую, вместо этого используйте `lex.save_zip("birds.zip")` — см. [Создание LIFT-файлов, соответствующих стандарту](lift-export-interop.md). From 72be654c044e14bfe3cb50f41d13c82b18095512 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:29 -0600 Subject: [PATCH 147/317] New translations build-export.md (Chinese Simplified) [ci skip] --- docs/zh/guides/build-export.md | 40 +++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/zh/guides/build-export.md b/docs/zh/guides/build-export.md index ce13b26..1e70529 100644 --- a/docs/zh/guides/build-export.md +++ b/docs/zh/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# 示例:从零开始构建 LIFT 导出 -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +如果你正在将另一个应用程序的数据导出为 LIFT 格式——这正是 [生成符合规范的 LIFT](lift-export-interop.md) 背后的任务——`sil-lift` 可以逐个构建文档对象并将其序列化,而无需手动生成 XML。 本文将逐步演示一个脚本,该脚本利用真实词典所包含的各项要素(多种书写系统、发音、带例句的词义、插图、语义领域特征以及应用程序特定字段)来构建词条,将受控词汇写入 `.lift-ranges` 伴生文件,进行验证并保存。 -## The script +## 剧本 ```python from pathlib import Path @@ -11,13 +11,13 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# 一个条目,基于源模型构建。 entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # Combine 的说话人标签约定 pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) @@ -39,22 +39,22 @@ sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # 一个应用程序专用的额外字段 scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# 该词条所引用的受控词汇表,位于配套的 .lift-ranges 中。 ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# 在写入磁盘之前,验证 save() 会写入什么内容。 problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"validation: {len(problems)} 个问题") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## 其产出 -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`验证结果:0 个问题`,然后是 `.lift` 及其配套代码的并列展示: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## API说明 -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- 多文本字段(`lexical_unit`、`definition`、`Form`/`URLRef` 的标签、`Field` 的内容等) 通过映射接口,为每个书写系统取一条字符串:`entry.lexical_unit["seh"] = "nkhuku"` 会添加一个 ``。 一个以语言代码为键对字符串进行索引的源模型可以直接映射到此处。 +- `RangesFile.add_range()` / `Range.add_element()` 用于构建受控词汇表,而 `Lexicon.add_ranges_file(ranges, href=...)` 则关联相应的范围文件并添加 `` 引用——这样,条目的 `` 和 `` 就能解析为您定义的范围。 +- `URLRef` 由 href 以及可选的标题/标签多文本组成——既适用于 ``(音频),也适用于 ``(照片)。 此处的发音遵循“The Combine”的惯例,即采用读作“ ”的`en`形式。 +- 不包含原生 LIFT 回家行程的应用程序专用数据,格式为 ``(或 ``):FieldWorks 会将其识别为自定义字段,而 The Combine 会保留这些数据。 +- 为每个条目分配一个真实且稳定的 `guid`(例如通过 `uuid.uuid4()` 生成,并在不同导出之间复用)——这样,后续重新导入时会就地更新该条目,而非创建重复条目。 `sil-lift validate --require-ids` 会强制执行此要求。 +- `lex.iter_problems()` 会在任何数据写入磁盘之前,对内存中的文档(即 `save()` 会写入的内容)进行验证;此时该文档是干净的。 由于词汇表目前还没有文件夹,因此会跳过媒体存在性检查和关联链接检查——待音频和照片文件就位后,请对保存的输出结果运行 [`sil-lift validate`](cli.md)(或使用 `--no-check-media` 选项)。 -## Packaging +## 包装 -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` 会生成文件夹结构(`.lift` 和 `.lift-ranges` 并列存放)。 若要生成一个可被 FieldWorks 和 The Combine 直接导入的单个压缩包,请改用 `lex.save_zip("birds.zip")` —— 参见 [生成符合规范的 LIFT 文件](lift-export-interop.md)。 From 4370a0f25db5fcd0171d9e29c2ce5634c84eb992 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:31 -0600 Subject: [PATCH 148/317] New translations build-export.md (Hindi) [ci skip] --- docs/hi/guides/build-export.md | 44 +++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/hi/guides/build-export.md b/docs/hi/guides/build-export.md index ce13b26..90dc1aa 100644 --- a/docs/hi/guides/build-export.md +++ b/docs/hi/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# कार्य उदाहरण: शून्य से LIFT एक्सपोर्ट बनाना -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +यदि आप किसी अन्य एप्लिकेशन का डेटा LIFT के रूप में निर्यात कर रहे हैं — [अनुरूप LIFT उत्पन्न करने](lift-export-interop.md) के पीछे का कार्य — तो `sil-lift` दस्तावेज़ के प्रत्येक ऑब्जेक्ट को क्रमबद्ध करके उसे सीरियलाइज़ कर सकता है, बजाय इसके कि आप XML को हाथ से उत्पन्न करें। यह एक स्क्रिप्ट के माध्यम से दिखाता है कि कैसे एक प्रविष्टि तैयार की जाती है, जिसमें एक वास्तविक शब्दकोश के सभी घटक होते हैं (कई लेखन प्रणालियाँ, उच्चारण, एक अर्थ उदाहरण के साथ, एक चित्रण, एक अर्थ-क्षेत्रीय गुण, और एक ऐप-विशिष्ट फ़ील्ड), नियंत्रित शब्दावलियों को `.lift-ranges` साथी फ़ाइल में लिखा जाता है, सत्यापित किया जाता है, और सहेजा जाता है। -## The script +## पटकथा ```python from pathlib import Path @@ -11,48 +11,48 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# एक प्रविष्टि, स्रोत मॉडल से निर्मित। entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # द कंबाइन का स्पीकर-लेबल कन्वेंशन pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) sense = sil_lift.Sense(id="kanga_s1") -sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="संज्ञा") sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) sense.definition["en"] = "a domestic fowl kept for its eggs and meat" example = sil_lift.Example() example.forms["seh"] = "Ndinafuna nkhuku." translation = sil_lift.Translation() -translation.forms["en"] = "I want a chicken." +translation.forms["en"] = "मुझे एक मुर्गी चाहिए।" example.translations.append(translation) sense.examples.append(example) photo = sil_lift.URLRef(href="pictures/hen.jpg") -photo.label["en"] = "A hen" +photo.label["en"] = "एक मुर्गी" sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # एक ऐप-विशिष्ट अतिरिक्त फ़ील्ड scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# एंट्री जिन नियंत्रित शब्दावलियों का संदर्भ देती है, एक साथी .lift-ranges में। ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# डिस्क पर लिखने से पहले save() क्या लिखेगा, इसकी जांच करें। problems = list(lex.iter_problems()) print(f"validation: {len(problems)} problem(s)") @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## यह क्या उत्पन्न करता है -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`validation: 0 problem(s)`, फिर `.lift` और उसका साथी एक साथ: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## एपीआई पर नोट्स -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- मल्टीटेक्स्ट फ़ील्ड (`lexical_unit`, `definition`, एक `Form`/`URLRef` लेबल, एक `Field` की सामग्री, ...) लेखन प्रणाली के लिए एक स्ट्रिंग मैपिंग इंटरफ़ेस के माध्यम से लें: `entry.lexical_unit["seh"] = "nkhuku"` एक `` जोड़ता है। एक स्रोत मॉडल जो भाषा कोड के आधार पर स्ट्रिंग्स को मैप करता है, सीधे इस पर लागू होता है। +- `RangesFile.add_range()` / `Range.add_element()` नियंत्रित शब्दावलियाँ बनाती हैं, और `Lexicon.add_ranges_file(ranges, href=...)` साथी फ़ाइल को जोड़ती है और हेडर `` संदर्भ जोड़ती है — ताकि प्रविष्टि के `` और `` आपके द्वारा परिभाषित रेंज के अनुसार हल हों। +- `URLRef` एक href और एक वैकल्पिक कैप्शन/लेबल मल्टीटेक्स्ट है — जो `` (ऑडियो) और `` (फ़ोटो) दोनों के लिए उपयोग किया जाता है। यहाँ का उच्चारण द कॉम्बाइन की परंपरा का पालन करता है, जिसमें `en` रूप को `Speaker: ` के रूप में पढ़ा जाता है। +- ऐप-विशिष्ट डेटा जिसमें कोई नेटिव LIFT होम राइड्स नहीं होतीं, एक `` (या ``) के रूप में: FieldWorks इन्हें कस्टम फ़ील्ड्स के रूप में पढ़ता है और The Combine इन्हें संरक्षित करता है। +- प्रत्येक प्रविष्टि को एक वास्तविक, स्थिर `guid` दें (उदाहरण के लिए `uuid.uuid4()` से, जो एक्सपोर्ट्स में पुन: उपयोग किया जाता है) — बाद में पुनः आयात करने पर यह प्रविष्टि को डुप्लिकेट करने के बजाय उसी स्थान पर अपडेट कर देता है। `sil-lift validate --require-ids` इसे लागू करता है। +- `lex.iter_problems()` मेमोरी में मौजूद दस्तावेज़ (जिसे `save()` लिखता) को डिस्क पर लिखने से पहले सत्यापित करता है; यहाँ यह सही है। चूंकि लेक्सिकॉन में अभी तक कोई फ़ोल्डर नहीं है, इसलिए मीडिया-उपस्थिति और साथी-href जांच छोड़ दी जाती हैं — ऑडियो और फोटो फ़ाइलें तैयार होने पर सहेजे गए आउटपुट पर [`sil-lift validate`](cli.md) चलाएँ (या `--no-check-media` के साथ)। -## Packaging +## पैकेजिंग -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` फ़ोल्डर फ़ॉर्म (`.lift` + `.lift-ranges` एक साथ) लिखता है। FieldWorks और The Combine द्वारा सीधे आयात किए जाने वाले एकल ज़िप पैकेज को उत्पन्न करने के लिए, इसके बजाय `lex.save_zip("birds.zip")` का उपयोग करें — देखें [अनुरूप LIFT का उत्पादन](lift-export-interop.md)। From ff98a0ec6683cdcc300ba6117618096684c17853 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:33 -0600 Subject: [PATCH 149/317] New translations build-export.md (Swahili) [ci skip] --- docs/sw/guides/build-export.md | 48 +++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/sw/guides/build-export.md b/docs/sw/guides/build-export.md index ce13b26..45024b4 100644 --- a/docs/sw/guides/build-export.md +++ b/docs/sw/guides/build-export.md @@ -1,8 +1,8 @@ -# Worked example: building a LIFT export from scratch +# Mfano uliofanyiwa kazi: kujenga usafirishaji wa LIFT kutoka mwanzo -If you are exporting another application's data as LIFT — the task behind [Producing conformant LIFT](lift-export-interop.md) — `sil-lift` can build the document object by object and serialize it, instead of emitting XML by hand. This walks through one script that constructs an entry with the pieces a real dictionary has (multiple writing systems, a pronunciation, a sense with an example, an illustration, a semantic-domain trait, and an app-specific field), writes the controlled vocabularies into a `.lift-ranges` companion, validates, and saves. +Ikiwa unatuma data za programu nyingine kama LIFT — kazi iliyopo nyuma ya [Kutengeneza LIFT inayokidhi viwango](lift-export-interop.md) — `sil-lift` inaweza kujenga kipengee cha hati kipengee kwa kipengee na kukisierializa, badala ya kutoa XML kwa mkono. Hii inaelezea hatua kwa hatua skripti moja inayounda kipengee chenye vipengele ambavyo kamusi halisi ina (mifumo mingi ya uandishi, matamshi, maana yenye mfano, mfano wa picha, sifa ya eneo la semanti, na sehemu maalum kwa programu), inaandika kamusi zilizodhibitiwa katika faili mwandani la `.lift-ranges`, inathibitisha, na huhifadhi. -## The script +## Maandishi ```python from pathlib import Path @@ -11,50 +11,50 @@ import sil_lift lex = sil_lift.Lexicon(producer="my-exporter") -# One entry, built from the source model. +# Kuingia moja, iliyojengwa kutoka kwa mfano wa chanzo. entry = sil_lift.Entry(id="kanga", guid="6b9e7c2a-3f4d-4a1b-8c5e-2d9f0a1b2c3d") entry.lexical_unit["seh"] = "nkhuku" entry.lexical_unit["pt"] = "galinha" pron = sil_lift.Pronunciation() -pron.forms["en"] = "Speaker: Ana" # The Combine's speaker-label convention +pron.forms["en"] = "Speaker: Ana" # Kanuni ya lebo ya mzungumzaji ya Combine pron.media.append(sil_lift.URLRef(href="audio/nkhuku.wav")) entry.pronunciations.append(pron) sense = sil_lift.Sense(id="kanga_s1") -sense.grammatical_info = sil_lift.GrammaticalInfo(value="Noun") +sense.grammatical_info = sil_lift.GrammaticalInfo(value="Nomino") sense.glosses.append(sil_lift.Form(lang="en", text=sil_lift.Text(["chicken"]))) sense.definition["en"] = "a domestic fowl kept for its eggs and meat" example = sil_lift.Example() example.forms["seh"] = "Ndinafuna nkhuku." translation = sil_lift.Translation() -translation.forms["en"] = "I want a chicken." +translation.forms["en"] = "Nataka kuku." example.translations.append(translation) sense.examples.append(example) photo = sil_lift.URLRef(href="pictures/hen.jpg") -photo.label["en"] = "A hen" +photo.label["en"] = "Kuku" sense.illustrations.append(photo) sense.traits.append(sil_lift.Trait(name="semantic-domain-ddp4", value="1.6.1.2")) -scientific = sil_lift.Field(type="scientific-name") # an app-specific extra field +scientific = sil_lift.Field(type="scientific-name") # uwanja wa ziada maalum kwa programu scientific.content["en"] = "Gallus gallus domesticus" sense.fields.append(scientific) entry.senses.append(sense) lex.entries.append(entry) -# The controlled vocabularies the entry refers to, in a companion .lift-ranges. +# Vichwa vya maneno vilivyodhibitiwa ambavyo kipengee kinavyorejelea, katika .lift-ranges. ranges = sil_lift.RangesFile() ranges.add_range("grammatical-info").add_element("Noun").label["en"] = "noun" -ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Bird" +ranges.add_range("semantic-domain-ddp4").add_element("1.6.1.2").label["en"] = "Ndege" lex.add_ranges_file(ranges, href="birds.lift-ranges") -# Validate what save() would write, before touching the disk. +# Thibitisha kile save() itaandika, kabla ya kugusa diski. problems = list(lex.iter_problems()) -print(f"validation: {len(problems)} problem(s)") +print(f"uthibitishaji: {len(problems)} problem(s)") out = Path("export") out.mkdir(exist_ok=True) @@ -65,9 +65,9 @@ print("=== birds.lift-ranges ===") print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## What it produces +## Kinachozalisha -`validation: 0 problem(s)`, then the `.lift` and its companion side by side: +`uthibitishaji: 0 matatizo`, kisha `.lift` na mwenzake kando kwa kando: ``` === birds.lift === @@ -154,15 +154,15 @@ print((out / "birds.lift-ranges").read_text(encoding="utf-8"), end="") ``` -## Notes on the API +## Maelezo kuhusu API -- Multitext fields (`lexical_unit`, `definition`, a `Form`/`URLRef` label, a `Field`'s content, ...) take one string per writing system through the mapping interface: `entry.lexical_unit["seh"] = "nkhuku"` adds a ``. A source model that keys strings by language code maps straight onto this. -- `RangesFile.add_range()` / `Range.add_element()` build the controlled vocabularies, and `Lexicon.add_ranges_file(ranges, href=...)` attaches the companion and adds the header `` references — so the entry's `` and `` resolve against the ranges you defined. -- A `URLRef` is an href plus an optional caption/label multitext — used for both `` (audio) and `` (photos). The pronunciation here follows The Combine's convention of an `en` form reading `Speaker: `. -- App-specific data with no native LIFT home rides as a `` (or ``): FieldWorks reads these as custom fields and The Combine preserves them. -- Give every entry a real, stable `guid` (e.g. from `uuid.uuid4()`, reused across exports) — a later re-import updates the entry in place rather than duplicating it. `sil-lift validate --require-ids` enforces this. -- `lex.iter_problems()` validates the in-memory document (what `save()` would write) before anything hits disk; here it is clean. Because the lexicon has no folder yet, the media-presence and companion-href checks are skipped — run [`sil-lift validate`](cli.md) on the saved output (or with `--no-check-media`) once the audio and photo files are in place. +- Maeneo ya maandishi mengi (`lexical_unit`, `definition`, lebo ya `Form`/`URLRef`, yaliyomo ya `Field`, ...) Chukua mnyororo mmoja kwa kila mfumo wa uandishi kupitia kiolesura cha upangaji: `entry.lexical_unit["seh"] = "nkhuku"` huongeza ``. Mfano wa chanzo unaotumia misimbo ya lugha kupanga nyuzi unaendana moja kwa moja na hili. +- `RangesFile.add_range()` / `Range.add_element()` hujenga vokabularia zilizodhibitiwa, na `Lexicon.add_ranges_file(ranges, href=...)` huunganisha faili ya ziada na kuongeza kichwa `` kwa marejeleo — hivyo `` na `` za kipengee hurejelea masafa uliyoyabainisha. +- URLRef ni href pamoja na maandishi mengi ya kichwa/lebo ya hiari — hutumika kwa `` (sauti) na `` (picha). Matamshi hapa yanafuata kanuni ya The Combine ya aina ya 'en', kama inavyosomwa na msemaji: +- Data maalum kwa programu bila safari za nyumbani za LIFT za asili kama `` (au ``): FieldWorks husoma hizi kama viwanja maalum na The Combine huzihifadhi. +- Panga kila kipengee na `guid` halisi, thabiti (kwa mfano kutoka `uuid.uuid4()`), inayotumika tena katika usafirishaji wa data — kuingiza tena baadaye husasisha kipengee mahali pake badala ya kuunda nakala yake. `sil-lift validate --require-ids` inahakikisha hili. +- `lex.iter_problems()` inathibitisha hati iliyopo kwenye kumbukumbu (kile ambacho `save()` ingeandika) kabla chochote haijawekwa kwenye diski; hapa iko safi. Kwa sababu kamusi bado haina folda, ukaguzi wa media-presence na companion-href umeachwa — endesha [`sil-lift validate`](cli.md) kwenye matokeo yaliyohifadhiwa (au kwa kutumia `--no-check-media`) mara tu faili za sauti na picha zitakapokuwa zimewekwa. -## Packaging +## Ufungashaji -`lex.save("export/birds.lift")` writes the folder form (`.lift` + `.lift-ranges` side by side). To emit a single zipped package that FieldWorks and The Combine import directly, use `lex.save_zip("birds.zip")` instead — see [Producing conformant LIFT](lift-export-interop.md). +`lex.save("export/birds.lift")` huandika muundo wa saraka (`.lift` + `.lift-ranges` kando kando). Ili kutoa kifurushi kimoja cha zip ambacho FieldWorks na The Combine huingiza moja kwa moja, tumia `lex.save_zip("birds.zip")` badala yake — angalia [Kutengeneza LIFT inayofuata viwango](lift-export-interop.md). From fd10c7579e8160f76757fb1d5694a0100d4431a8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:34 -0600 Subject: [PATCH 150/317] New translations bulk-edit-glosses.md (German) [ci skip] --- docs/de/guides/bulk-edit-glosses.md | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/de/guides/bulk-edit-glosses.md b/docs/de/guides/bulk-edit-glosses.md index e00876c..caa9d42 100644 --- a/docs/de/guides/bulk-edit-glosses.md +++ b/docs/de/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# Anwendungsbeispiel: Massenbearbeitung von Glossaren -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +Eine häufige Wartungsaufgabe: Die Schreibweise aller englischen Begriffserklärungen in einem Lexikon vereinheitlichen (britisch → amerikanisch oder umgekehrt), ohne dabei andere Teile der Datei zu verändern. Hier wird ein Skript Schritt für Schritt erläutert, das Daten lädt, bearbeitet, validiert und speichert – dabei wird gezeigt, wie die Bearbeitungs-API und die Genauigkeitsgarantie zusammenwirken. -## The script +## Das Drehbuch ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Gibt jede Bedeutung zurück, einschließlich Unterbedeutungen (rekursiv).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,32 +39,32 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"Abbruch: {len(errors)} Validierungsfehler, nichts gespeichert") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f" {edited_glosses} -Glossare in {len(touched_entries)} Einträgen bearbeitet") ``` -A few things worth noting: +Ein paar Dinge, die es zu beachten gilt: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` ist selbst eine `list[Sense]`, daher wird sie von `iter_senses` rekursiv durchlaufen – eine Massenbearbeitung, die nur `entry.senses` durchläuft, würde alle unter einer Unterbedeutung verschachtelten Erläuterungen stillschweigend überspringen. +- `gloss.text` ist ein `Text` und keine einfache Zeichenkette: `str(gloss.text)` wandelt ihn für den Abgleich in eine Zeichenkette um, und die Ersetzung wird mit `sil_lift.Text([new])` zurückgeschrieben, anstatt die Zeichenkette direkt zu ändern. +- Bei der Validierung im Arbeitsspeicher (`lex.iter_problems()`) wird der bearbeitete Zustand zunächst serialisiert, sodass er die Änderungen korrekt widerspiegelt, bevor Daten auf die Festplatte geschrieben werden. Ein Abbruch bei jedem `"error"`-Level-`Problem` – Warnungen werden dem Aufrufer zur Beurteilung überlassen – bedeutet, dass eine fehlerhafte Bearbeitung niemals `save()` erreicht. -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +Nicht nur Glanzlacke lassen sich auf diese Weise gut auftragen. Die gleiche `Multitext`-Zuordnungsfläche gilt für Definitionen und alle anderen mehrsprachigen Felder eines Eintrags oder einer Bedeutung: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "die Farbe eines Gegenstands" ``` -## Running it +## Ausführen -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +Führen Sie eine Suche in einem kleinen Lexikon durch, in dem sowohl die Erläuterung als auch die Unterbedeutung mit „Farbe“ angegeben sind: ``` -edited 2 gloss(es) across 1 entry(ies) +2 Begriffserklärungen in 1 Eintrag bearbeitet ``` -## The fidelity payoff +## Der Lohn der Treue -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +Die Garantie gilt pro _Eintrag_: Ein Eintrag, dessen Modell sich nicht geändert hat, wird **byte-identisch** so zurückgegeben, wie er eingelesen wurde, und nur die Einträge, die Sie tatsächlich bearbeitet haben, werden erneut serialisiert. In der obigen Ausführung wurden bei einem Eintrag die Glossen bearbeitet – alle anderen Einträge in der Datei behielten ihre exakten Bytes bei. (Beachten Sie die Detailgenauigkeit: Wenn Sie einen beliebigen Teil eines Eintrags bearbeiten, wird der gesamte Eintrag neu serialisiert, einschließlich der davon nicht betroffenen verwandten Bedeutungen.) Das Bearbeiten eines Eintrags in einem Lexikon mit 50.000 Einträgen führt daher zu einer Diff-Datei, die nur einen Eintrag betrifft, und nicht zu einer neu formatierten Datei. Den genauen Vertragsinhalt finden Sie unter [Fidelity-Garantien](../fidelity.md). From 0518d8c78b4af4c0a059b82c8f15d2573b71eb9f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:36 -0600 Subject: [PATCH 151/317] New translations bulk-edit-glosses.md (Japanese) [ci skip] --- docs/ja/guides/bulk-edit-glosses.md | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/ja/guides/bulk-edit-glosses.md b/docs/ja/guides/bulk-edit-glosses.md index e00876c..07275fd 100644 --- a/docs/ja/guides/bulk-edit-glosses.md +++ b/docs/ja/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# 実践例:注釈の一括編集 -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +よくあるメンテナンス作業:辞書内のすべての英語用語について、ファイル内の他の部分を一切変更することなく、綴りを統一すること(英国式→米国式、またはその逆)。 ここでは、読み込み、編集、検証、保存を行う1つのスクリプトの手順を解説します。これにより、編集APIとフィデリティ保証が連携して機能する様子を確認できます。 -## The script +## 脚本 ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """すべての意味(サブセンスを含む)を再帰的にイテレートする。""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -45,26 +45,26 @@ lex.save() print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") ``` -A few things worth noting: +いくつか注目すべき点があります: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` 自体は `list[Sense]` であるため、`iter_senses` はこのリストを再帰的に処理します。もし `entry.senses` のみを走査する一括編集を行った場合、サブセンスの下にネストされた語義は、何の警告もなくスキップされてしまいます。 +- `gloss.text` は単なる文字列ではなく `Text` です。`str(gloss.text)` は照合のためにこれを平坦化し、置換結果は文字列そのものを変更するのではなく、`sil_lift.Text([new])` を使って書き戻されます。 +- メモリ内での検証(`lex.iter_problems()`)では、まず編集後の状態をシリアル化するため、ディスクへの書き込みが行われる前に、編集内容が正しく反映されます。 `"error"` レベルの `Problem` が発生した場合は処理を中止します(警告は呼び出し側が判断できるよう残されます)。これにより、不正な編集内容が `save()` に到達することはありません。 -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +この方法で触れてみる価値があるのは、グロスだけではありません。 この `Multitext` マッピング領域は、定義や、エントリや意味に含まれるその他のすべての多言語フィールドにも同様に適用されます: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "物体の色" ``` -## Running it +## 実行する -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +「colour」と記載された語義説明と、その下位意味の語義説明の両方が含まれる小規模な語彙リストに対して照合を行う: ``` -edited 2 gloss(es) across 1 entry(ies) +1件のエントリに含まれる2つの用語を編集しました ``` -## The fidelity payoff +## 忠実度の見返り -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +この保証は「エントリ」単位で適用されます。モデルが変更されていないエントリは、読み込まれたときと**バイト単位で同一**な状態で返され、実際に変更を加えたエントリのみが再シリアル化されます。 上記の実行では、1つのエントリの注釈が編集されましたが、ファイル内のその他のエントリはすべて、バイト単位でそのままの状態で保持されました。 (粒度に注意してください:エントリの任意の部分を編集すると、変更されていない同義語を含め、そのエントリ全体が再シリアライズされます。) したがって、5万項目の辞書にある1つの用語を編集しても、再フォーマットされたファイルが生成されるのではなく、1つの項目に影響する差分が生成されるだけである。 契約の詳細については、[フィデリティの保証](../fidelity.md)をご覧ください。 From 2d36e77e4f90a10b46586d2c438850f276ae0d6a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:38 -0600 Subject: [PATCH 152/317] New translations bulk-edit-glosses.md (Portuguese) [ci skip] --- docs/pt/guides/bulk-edit-glosses.md | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/pt/guides/bulk-edit-glosses.md b/docs/pt/guides/bulk-edit-glosses.md index e00876c..c6442e9 100644 --- a/docs/pt/guides/bulk-edit-glosses.md +++ b/docs/pt/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# Exemplo prático: edição em massa de glossários -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +Uma tarefa de manutenção comum: uniformizar a ortografia em todas as entradas em inglês de um léxico (britânica → americana, ou vice-versa) sem alterar qualquer outro aspeto do ficheiro. Este exemplo apresenta um script que carrega, edita, valida e guarda — demonstrando como a API de edição e a garantia de fidelidade funcionam em conjunto. -## The script +## O guião ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Retorna todos os sentidos, incluindo os sub-sentidos (recursivo).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,32 +39,32 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"a interromper: {len(errors)} erro(s) de validação, nada guardado") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f" {edited_glosses} gloss(es) editado(s) em {len(touched_entries)} entrada(s)") ``` -A few things worth noting: +Algumas coisas que vale a pena referir: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` é, por si só, uma `list[Sense]`, pelo que `iter_senses` a percorre de forma recursiva — uma edição em massa que apenas percorresse `entry.senses` ignoraria silenciosamente qualquer gloss aninhado sob um subsense. +- `gloss.text` é um `Text`, não uma string simples: `str(gloss.text)` simplifica-o para efeitos de correspondência, e a substituição é gravada novamente com `sil_lift.Text([new])`, em vez de alterar a string no local. +- A validação na memória (`lex.iter_problems()`) serializa primeiro o estado editado, para que este reflita corretamente a edição antes de qualquer coisa ser gravada no disco. Interromper a execução perante qualquer `Problem` de nível `"error"` — os avisos são deixados para que o chamador os avalie — significa que uma edição incorreta nunca chega à função `save()`. -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +Os glosses não são a única coisa que vale a pena tratar desta forma. A mesma superfície de mapeamento `Multitext` aplica-se às definições e a todos os outros campos multilingues de uma entrada ou significado: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "a cor de uma coisa" ``` -## Running it +## Executá-lo -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +Execute a pesquisa com um pequeno léxico que contenha uma entrada e uma subentrada cujos significados sejam ambos «cor»: ``` -edited 2 gloss(es) across 1 entry(ies) +editou 2 glossários em 1 entrada(s) ``` -## The fidelity payoff +## A recompensa pela fidelidade -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +A garantia aplica-se a cada _entrada_: uma entrada cujo modelo não tenha sido alterado é devolvida **identicamente em termos de bytes** à forma como foi lida, e apenas as entradas em que se interveio efetivamente são resserializadas. Na execução acima, foram editadas as anotações de uma entrada — todas as outras entradas do ficheiro mantiveram os seus bytes exatos. (Repare na granularidade: a edição de qualquer parte de uma entrada faz com que toda a entrada seja novamente serializada, incluindo os significados associados que não foram alterados.) A edição de uma definição num léxico com 50 000 entradas resulta, portanto, num ficheiro «diff» que afeta apenas uma entrada, e não num ficheiro reformatado. Consulte [Garantias da Fidelity](../fidelity.md) para conhecer o contrato na íntegra. From 3bc5e975ec9f0bca2dba03bbdcf25fbeeb956b0c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:40 -0600 Subject: [PATCH 153/317] New translations bulk-edit-glosses.md (Russian) [ci skip] --- docs/ru/guides/bulk-edit-glosses.md | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/ru/guides/bulk-edit-glosses.md b/docs/ru/guides/bulk-edit-glosses.md index e00876c..2ca94ec 100644 --- a/docs/ru/guides/bulk-edit-glosses.md +++ b/docs/ru/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# Пример с решением: массовое редактирование глосс -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +Типичная задача по обслуживанию: привести правописание всех английских терминов в словаре к единому стандарту (британский → американский или наоборот), не затрагивая при этом остальные элементы файла. В этом примере подробно рассматривается один скрипт, который выполняет загрузку, редактирование, проверку и сохранение данных, демонстрируя совместную работу API редактирования и гарантии точности. -## The script +## Сценарий ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Выдает все значения, включая подзначения (рекурсивно).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,32 +39,32 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"прерывание: {len(errors)} ошибка(и) валидации, ничего не сохранено") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f"отредактировано {edited_glosses} глосса(рий) в {len(touched_entries)} записи(ях)") ``` -A few things worth noting: +Несколько моментов, на которые стоит обратить внимание: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` само по себе представляет собой `list[Sense]`, поэтому `iter_senses` выполняет рекурсию по нему — при массовом редактировании, которое бы просматривало только `entry.senses`, любые глоссы, вложенные под подзначениями, были бы незаметно пропущены. +- `gloss.text` — это объект типа `Text`, а не обычная строка: функция `str(gloss.text)` преобразует его в строку для сопоставления, а результат замены записывается обратно с помощью `sil_lift.Text([new])`, а не путем изменения исходной строки на месте. +- При проверке в памяти (`lex.iter_problems()`) сначала выполняется сериализация отредактированного состояния, благодаря чему оно правильно отражает внесенные изменения ещё до записи на диск. Прерывание при возникновении любого объекта `Problem` уровня `"error"` — предупреждения оставляются на усмотрение вызывающего кода — означает, что некорректное изменение никогда не доходит до вызова `save()`. -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +Не только глянцевые поверхности стоит обрабатывать таким образом. Та же самая поверхность сопоставления `Multitext` применяется к определениям и всем другим многоязычным полям в записи или значении: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "цвет предмета" ``` -## Running it +## Запуск программы -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +Проведите сравнение с небольшим лексиконом, в котором есть термин и его подзначение, обозначающие «цвет»: ``` -edited 2 gloss(es) across 1 entry(ies) +внесено 2 исправления в 1 запись ``` -## The fidelity payoff +## Выгода от точности воспроизведения -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +Гарантия распространяется на каждую отдельную запись: запись, модель которой не изменилась, возвращается в виде **байтово идентичного** копирования исходного содержимого, а повторная сериализация производится только для тех записей, в которые вы действительно вносили изменения. В приведенном выше фрагменте в одной записи были отредактированы глоссы — все остальные записи в файле сохранили свои байты без изменений. (Обратите внимание на степень детализации: при редактировании любой части записи происходит повторная сериализация всей записи целиком, включая нетронутые родственные значения.) Таким образом, при редактировании одного глоссария в словаре, содержащем 50 000 статей, создается файл diff, затрагивающий одну статью, а не переформатированный файл. Точные условия договора см. в разделе [Гарантии Fidelity](../fidelity.md). From 8b5eb52f513a084b62d05eb124b1bc0468e12509 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:41 -0600 Subject: [PATCH 154/317] New translations bulk-edit-glosses.md (Chinese Simplified) [ci skip] --- docs/zh/guides/bulk-edit-glosses.md | 34 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/zh/guides/bulk-edit-glosses.md b/docs/zh/guides/bulk-edit-glosses.md index e00876c..8975a23 100644 --- a/docs/zh/guides/bulk-edit-glosses.md +++ b/docs/zh/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# 示例:批量编辑释义 -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +一项常见的维护任务:将词汇表中所有英语释义的拼写统一为标准形式(英式英语 → 美式英语,或反之),同时不影响文件中的其他内容。 本文将逐步演示一个脚本,该脚本负责加载、编辑、验证和保存数据,从而展示编辑 API 与保真度保证如何协同工作。 -## The script +## 剧本 ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """返回每个词义,包括子词义(递归).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,32 +39,32 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"中止:{len(errors)} 个验证错误,未保存任何内容") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f"已编辑 {edited_glosses} 个释义,涉及{len(touched_entries)}个条目") ``` -A few things worth noting: +有几点值得注意: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` 本身是一个 `list[Sense]`,因此 `iter_senses` 会递归遍历它——如果批量编辑操作仅遍历 `entry.senses`,则会无提示地跳过任何嵌套在子义项下的释义。 +- `gloss.text` 是一个 `Text` 对象,而不是普通的字符串:`str(gloss.text)` 会将其扁平化以便进行匹配,而替换后的内容会通过 `sil_lift.Text([new])` 写回,而不是直接修改原字符串。 +- 内存验证(`lex.iter_problems()`)会先将编辑后的状态序列化,因此能在将任何内容写入磁盘之前,准确反映编辑后的状态。 一旦遇到任何 `"error"` 级别的 `Problem` 就终止处理——警告信息将留给调用方自行判断——这意味着错误的编辑操作永远不会进入 `save()` 方法。 -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +值得这样处理的不仅仅是光泽。 相同的 `Multitext` 映射规则同样适用于定义以及条目或词义中的所有其他多语言字段: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "事物的颜色" ``` -## Running it +## 运行它 -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +针对一个包含简短词汇表的小型词库进行比对,其中该词的释义和子义释义均显示为“colour”: ``` -edited 2 gloss(es) across 1 entry(ies) +编辑了 1 个条目中的 2 个释义 ``` -## The fidelity payoff +## 忠诚的回报 -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +该保证针对每个_条目_:模型未发生变化的条目,其输出与读取时的内容在**字节级**完全一致,且只有您实际修改过的条目才会被重新序列化。 在上面的处理过程中,有一个条目的注释被编辑了——文件中的其他所有条目都保留了原有的字节内容。 (请注意粒度:编辑条目中的任何部分都会导致整个条目重新序列化,包括未被修改的同级释义。) 因此,在一部包含50,000条目词典中编辑一条释义,生成的差异文件仅涉及一条条目,而非重新格式化的文件。 具体合同条款请参见[富达保证](../fidelity.md)。 From a12389222be1a63961d9a823ac4d9a84bd61bc35 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:43 -0600 Subject: [PATCH 155/317] New translations bulk-edit-glosses.md (Hindi) [ci skip] --- docs/hi/guides/bulk-edit-glosses.md | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/hi/guides/bulk-edit-glosses.md b/docs/hi/guides/bulk-edit-glosses.md index e00876c..ce4be3f 100644 --- a/docs/hi/guides/bulk-edit-glosses.md +++ b/docs/hi/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# कार्य किया गया उदाहरण: ग्लॉस का थोक-संपादन -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +एक सामान्य रखरखाव कार्य: शब्दकोश में प्रत्येक अंग्रेज़ी ग्लॉस में वर्तनी को सामान्य करना (ब्रिटिश → अमेरिकी, या इसके विपरीत), बिना फ़ाइल में किसी अन्य चीज़ को प्रभावित किए। यह एक स्क्रिप्ट के माध्यम से लोड, संपादन, सत्यापन और सहेजने की प्रक्रिया को दिखाता है — संपादन API और निष्ठा गारंटी को एक साथ काम करते हुए। -## The script +## पटकथा ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """प्रत्येक इंद्रिय, उप-इंद्रियों सहित (पुनरावर्ती) उत्पन्न करें।""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -45,26 +45,26 @@ lex.save() print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") ``` -A few things worth noting: +ध्यान देने योग्य कुछ बातें: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` स्वयं एक `list[Sense]` है, इसलिए `iter_senses` इसमें पुनरावृत्ति करता है — एक सामूहिक संपादन जो केवल `entry.senses` को ही चलाता है, वह किसी उपसंज्ञा के अंतर्गत निहित किसी भी परिभाषा को चुपचाप छोड़ देगा। +- `gloss.text` एक `Text` है, न कि एक साधारण स्ट्रिंग: `str(gloss.text)` इसे मिलान के लिए फ्लैटन करता है, और प्रतिस्थापन को स्ट्रिंग को वहीं पर बदलने के बजाय `sil_lift.Text([new])` के साथ वापस लिखा जाता है। +- मेमोरी में सत्यापन (`lex.iter_problems()`) पहले संपादित स्थिति को सीरियलाइज़ करता है, ताकि डिस्क पर कुछ भी लिखे जाने से पहले यह संपादन को सही ढंग से दर्शाए। किसी भी `"error"`-स्तर के `Problem` पर प्रक्रिया रद्द करने पर — चेतावनियाँ कॉल करने वाले पर छोड़ दी जाती हैं — इसका मतलब है कि एक खराब संपादन कभी भी `save()` तक नहीं पहुँचता। -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +इस तरह छूने लायक सिर्फ ग्लॉस ही नहीं हैं। एक ही `Multitext` मैपिंग सतह परिभाषाओं और किसी प्रविष्टि या अर्थ पर प्रत्येक अन्य बहुभाषी क्षेत्र पर लागू होती है: ```python -sense.definition["en"] = "the color of a thing" +sense.definition["en"] = "किसी वस्तु का रंग" ``` -## Running it +## इसे चलाना -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +एक छोटे शब्दकोश के खिलाफ चलाएँ, जिसमें एक परिभाषा और एक उप-अर्थ परिभाषा दोनों में "रंग" लिखा हो: ``` -edited 2 gloss(es) across 1 entry(ies) +1 प्रविष्टि(यों) में 2 ग्लॉस(स) संपादित ``` -## The fidelity payoff +## वफ़ादारी का इनाम -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +यह गारंटी प्रत्येक प्रविष्टि के लिए है: जिस प्रविष्टि का मॉडल नहीं बदला, वह बिल्कुल उसी रूप में वापस आती है जैसा पढ़ी गई थी, और केवल वे प्रविष्टियाँ जो वास्तव में बदली गई थीं, पुनः सीरियलाइज़ की जाती हैं। उपरोक्त रन में, एक प्रविष्टि के ग्लॉस संपादित किए गए थे — फ़ाइल में बाकी सभी प्रविष्टियों ने अपने सटीक बाइट्स बनाए रखे। (बारीकी पर ध्यान दें: प्रविष्टि के किसी भी भाग को संपादित करने पर वह पूरी प्रविष्टि पुनः अनुक्रमित हो जाती है, जिसमें उसके अप्रभावित सहोदर अर्थ भी शामिल हैं।) इसलिए 50,000 प्रविष्टियों वाले शब्दकोश में एक ग्लॉस का संपादन एक प्रविष्टि को प्रभावित करने वाला diff उत्पन्न करता है, न कि एक पुनः स्वरूपित फ़ाइल। सटीक अनुबंध के लिए [फिडेलिटी गारंटी](../fidelity.md) देखें। From 59735b3d12bf6d804ac1e402c3885d358511b06b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:45 -0600 Subject: [PATCH 156/317] New translations bulk-edit-glosses.md (Swahili) [ci skip] --- docs/sw/guides/bulk-edit-glosses.md | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/sw/guides/bulk-edit-glosses.md b/docs/sw/guides/bulk-edit-glosses.md index e00876c..a920d14 100644 --- a/docs/sw/guides/bulk-edit-glosses.md +++ b/docs/sw/guides/bulk-edit-glosses.md @@ -1,8 +1,8 @@ -# Worked example: bulk-editing glosses +# Mfano uliofanyiwa kazi: kuhariri kwa wingi tafsiri fupi -A common maintenance task: normalize spelling across every English gloss in a lexicon (British → American, or vice versa) without disturbing anything else in the file. This walks through one script that loads, edits, validates, and saves — showing the editing API and the fidelity guarantee working together. +Kazi ya kawaida ya matengenezo: kurekebisha tahajia ili iwe sawa katika kila fasili ya Kiingereza kwenye kamusi (kutoka Kiingereza cha Uingereza hadi Kiingereza cha Marekani, au kinyume chake) bila kuathiri chochote kingine katika faili. Hii inaelezea hatua kwa hatua skripti moja inayopakia, kuhariri, kuthibitisha, na kuhifadhi — ikionyesha API ya uhariri na dhamana ya uaminifu zikifanya kazi pamoja. -## The script +## Maandishi ```python import sys @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Yatoa kila hisia, ikiwa ni pamoja na hisia ndogo (kwa kujirudia).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -45,26 +45,26 @@ lex.save() print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") ``` -A few things worth noting: +Mambo machache ya kuzingatia: -- `Sense.subsenses` is itself a `list[Sense]`, so `iter_senses` recurses into it — a bulk edit that only walked `entry.senses` would silently skip any gloss nested under a subsense. -- `gloss.text` is a `Text`, not a plain string: `str(gloss.text)` flattens it for matching, and the replacement is written back with `sil_lift.Text([new])` rather than mutating the string in place. -- Validating in memory (`lex.iter_problems()`) serializes the edited state first, so it correctly reflects the edit before anything is written to disk. Aborting on any `"error"`-level `Problem` — warnings are left for the caller to judge — means a bad edit never reaches `save()`. +- `Sense.subsenses` ni `list[Sense]` yenyewe, kwa hivyo `iter_senses` inarudia ndani yake — uhariri wa jumla ambao ungepitia tu `entry.senses` ungeacha kimya kimya fasili yoyote iliyoko chini ya subsense. +- `gloss.text` ni `Text`, si mfululizo wa kawaida: `str(gloss.text)` huifanya iwe mfululizo wa kawaida kwa ajili ya kulinganisha, na mbadala huandikwa tena kwa kutumia `sil_lift.Text([new])` badala ya kubadilisha mfululizo mahali pake. +- Uhakiki katika kumbukumbu (`lex.iter_problems()`) huweka kwanza hali iliyohaririwa kwa mpangilio, hivyo inaonyesha kwa usahihi mabadiliko kabla ya chochote kuandikwa kwenye diski. Kukata shughuli kwa `Problem` yoyote ya kiwango cha `"error"` — maonyo huachwa kwa mtu anayeita ili ahukumu — kunamaanisha kuwa uhariri mbaya hauwahi kufikia `save()`. -Glosses aren't the only thing worth touching this way. The same `Multitext` mapping surface applies to definitions and every other multilingual field on an entry or sense: +Si glosi pekee ndizo zinazostahili kuguswa kwa njia hii. Uso uleule wa ramani wa `Multitext` unatumika kwa ufafanuzi na kila uwanja mwingine wa lugha nyingi kwenye kipengee au maana: ```python -sense.definition["en"] = "the color of a thing" +maana.fasili["en"] = "rangi ya kitu" ``` -## Running it +## Kuendesha -Run against a small lexicon with a gloss and a subsense gloss that both say "colour": +Fanya utafutaji dhidi ya kamusi ndogo yenye fasili na fasili ya aina ndogo, zote zikisema "rangi": ``` -edited 2 gloss(es) across 1 entry(ies) +Imehaririwa: tafsiri 2 katika kipengee 1 ``` -## The fidelity payoff +## Faida ya uaminifu -The guarantee is per _entry_: an entry whose model didn't change comes back out **byte-identical** to how it was read in, and only the entries you actually touched are re-serialized. In the run above, one entry had glosses edited — every other entry in the file kept its exact bytes. (Note the granularity: editing any part of an entry re-serializes that whole entry, including its untouched sibling senses.) Editing one gloss in a 50,000-entry lexicon therefore produces a diff touching one entry, not a reformatted file. See [Fidelity guarantees](../fidelity.md) for the precise contract. +Dhamana ni kwa kila _entry_: entry ambayo mfano wake haukubadilika hurudi **byte-identical** kama ilivyosomwa, na ni tu entries ulizogusa ndizo zinazotengenezwa tena. Katika mfululizo hapo juu, kipengee kimoja kilikuwa na tafsiri zilizohaririwa — kila kipengee kingine katika faili kilidumisha baiti zake hasa. (Kumbuka kiwango cha undani: kuhariri sehemu yoyote ya kumbukumbu kunasababisha kumbukumbu yote kusimbwa upya kwa mpangilio, ikiwemo hisia zake ndugu ambazo hazijaguswa.) Kurekebisha fasili moja katika kamusi yenye maingizo 50,000 kwa hivyo hutoa tofauti inayogusa kiingizo kimoja, si faili iliyopangwa upya. Tazama [Dhamana za Fidelity](../fidelity.md) kwa mkataba sahihi. From 9b1f8c84a5dd9e3f5353f72b20ca8d6f9144defc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:47 -0600 Subject: [PATCH 157/317] New translations cli.md (Japanese) [ci skip] --- docs/ja/guides/cli.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/ja/guides/cli.md b/docs/ja/guides/cli.md index 3f1401e..182b5b4 100644 --- a/docs/ja/guides/cli.md +++ b/docs/ja/guides/cli.md @@ -1,35 +1,35 @@ -# The command line +# コマンドライン -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +パッケージをインストールすると(`pip install sil-lift`)、`sil-lift` コマンドもインストールされます。これは、パッケージに同梱されている、LiftTools スタイルのサポート対象ツールです(また、`validate` については、ライブラリ API の実用例も含まれています)。 ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors + すべての問題、エントリ/行単位で対処;エラー時は終了コード 1 sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing + エントリ/センス/言語のカウント(ストリーミング;サイズ不問) +sil-lift sort PATH [-o OUT] 正規化されたソート済み、差分比較可能なコピー(デフォルト:その場更新) +sil-lift check-media PATH 欠落および孤立したメディアのレポート;欠落がある場合は 1 で終了 sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + リーフセンスごとに1行(サブセンスは平坦化)でCSV/TSV形式に出力(ストリーミング) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` を指定すると、CIや自動化処理で使用できるよう、単一のJSONオブジェクトが標準出力に書き出されます(それ以外は何も出力されません)。スキーマについては、以下の例を参照してください。 `--strict` オプションは、警告をエラーとして扱い、警告が見つかった場合は終了値 1 を返します。エラーだけでなく、ビルドが完全に正常であることを条件としてビルドを許可したい場合にこのオプションを使用してください。 `--no-check-media` オプションを指定すると、ファイルシステムのメディア存在確認がスキップされ(`missing-media` の検出結果が表示されなくなります)。これは、生成されたばかりのエクスポートを検証する際、オーディオや写真ファイルが別の場所にあり、ディスク上に同じ場所には存在しない場合に役立ちます。 `--require-ids` は、`guid` がないエントリや `id` がないセンスに対しても(`missing-id` エラーとして)失敗します。これは、安定した ID を使用して再インポートを行うワークフローにおいて、LIFT よりも厳格な仕様となっています。 パスとして `-` を指定すると、ドキュメントは標準入力(stdin)から読み込まれます(パイプで渡されたドキュメントにはフォルダがないため、それに付随する `.lift-ranges` やメディアは解決されません)。 `stats` も同様に `--format json` を受け付け、集計結果を単一の JSON オブジェクトとして出力します。 !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + `validate` の終了コードおよび `--format json` のスキーマは、サポートされている自動化インターフェースです。これらはいずれもテストの対象となっており、SemVer に基づいてのみ変更されます。 -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +`sort` は `.lift` ファイルのみを上書きします。関連する `.lift-ranges` ファイルは変更されません +(これらを並べ替えるには、`RangesFile` API を別途使用してください)。 -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +`validate`、`stats`、`check-media`、および `export` も、ZIP形式のLIFTパッケージ(アーカイブのルートにファイルが配置されている形式、またはトップレベルのフォルダの下にネストされている形式のいずれかの `.zip` ファイル)を受け付けます。このパッケージは一時ディレクトリに展開され、コマンドの実行完了後に削除されます。 -Examples: +例: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +エラー [dangling-ref] dictionary.lift:88 (エントリ apu): 参照 'nope' に一致するエントリ ID/GUID または意味 ID がありません +警告 [uri-not-rfc] dictionary.lift:6:: URI 権限として Windows ドライブ文字が使用されています (FLEx 形式の file://C:/) +エラー 1 件、警告 1 件 $ sil-lift validate dictionary.lift --format json { @@ -46,7 +46,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": URIの権限としてWindowsのドライブ文字が使用されています (FLEx形式の file://C:/)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -67,4 +67,4 @@ senses: 4541 $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +終了コード:`0`:成功(`--strict` オプションが指定されていない限り、警告は許容される)、`1`:問題が見つかった(検証エラー/メディアの欠落/`--strict` オプション指定時の警告)、`2`:入力が読み取れない。 From d50371de77f2e29e56821a647fb4789dfe03451f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:49 -0600 Subject: [PATCH 158/317] New translations cli.md (Portuguese) [ci skip] --- docs/pt/guides/cli.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/pt/guides/cli.md b/docs/pt/guides/cli.md index 3f1401e..f87d8f5 100644 --- a/docs/pt/guides/cli.md +++ b/docs/pt/guides/cli.md @@ -1,35 +1,35 @@ -# The command line +# A linha de comandos -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +Ao instalar o pacote (`pip install sil-lift`), é também instalado o comando `sil-lift` — uma ferramenta compatível com o estilo LiftTools que vem incluída no pacote (e, no caso de `validate`, um exemplo prático da API da biblioteca). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors + todos os problemas, tratados por entrada/linha; saída 1 em caso de erros sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing + contagens por entrada/sentido/língua (em fluxo; qualquer tamanho) +sil-lift sort PATH [-o OUT] cópia ordenada canonicamente, pronta para comparação (predefinição: no local) +sil-lift check-media PATH relatório de meios em falta e órfãos; sai com código 1 se houver meios em falta sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + uma linha por sentido folha (subsentidos achatados) para CSV/TSV (streaming) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` escreve um único objeto JSON na saída padrão (e nada mais) para utilização em CI/automatização; consulte o esquema no exemplo abaixo. A opção `--strict` trata os avisos como erros, devolvendo o valor 1 caso seja detetado algum — utilize-a para condicionar a conclusão da compilação à ausência total de problemas, em vez de apenas à ausência de erros. `--no-check-media` ignora a verificação da presença de suportes no sistema de ficheiros (suprimindo os resultados de `missing-media`), o que é útil ao validar uma exportação recém-gerada cujos ficheiros de áudio/fotografias se encontram noutro local e não estão armazenados no mesmo disco. `--require-ids` também falha (com um erro `missing-id`) em qualquer entrada que não tenha um `guid` ou em qualquer sentido que não tenha um `id` — sendo mais rigoroso do que o LIFT, para fluxos de trabalho que reimportam através de um id estável. Ao passar `-` como caminho, o documento é lido a partir do stdin (um documento transmitido por canalização não tem pasta, pelo que o ficheiro `.lift-ranges` associado e os ficheiros multimédia não são resolvidos). O `stats` também aceita a opção `--format json`, apresentando as contagens como um único objeto JSON. !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + Os códigos de saída do `validate` e o esquema `--format json` constituem uma interface de automatização suportada: ambos são abrangidos por testes e só sofrem alterações de acordo com a SemVer. -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +O `sort` reescreve apenas o ficheiro `.lift`; os ficheiros `.lift-ranges` associados permanecem inalterados +(organize-os separadamente com a API `RangesFile`). -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +Os comandos `validate`, `stats`, `check-media` e `export` também aceitam um pacote LIFT compactado (um ficheiro `.zip` com qualquer um dos dois formatos — ficheiros na raiz do arquivo ou aninhados numa pasta de nível superior); este é extraído para um diretório temporário e eliminado quando o comando termina. -Examples: +Exemplos: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +erro [dangling-ref] dictionary.lift:88 (entrada apu): a referência «nope» não corresponde a nenhum ID/GUID de entrada nem a nenhum ID de sentido +aviso [uri-not-rfc] dictionary.lift:6: : Letra de unidade do Windows utilizada como autoridade URI (estilo FLEx file://C:/) +1 erro(s), 1 aviso(s) $ sil-lift validate dictionary.lift --format json { @@ -37,7 +37,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "error", "code": "dangling-ref", - "message": "ref 'nope' matches no entry id/guid or sense id", + "message": "a referência 'nope' não corresponde a nenhum ID de entrada/GUID ou ID de sentido", "file": "dictionary.lift", "entry_id": "apu", "guid": null, @@ -46,7 +46,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": Letra de unidade do Windows utilizada como autoridade URI (file://C:/ ao estilo FLEx)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -60,11 +60,11 @@ $ sil-lift validate dictionary.lift --format json } $ sil-lift stats sango.lift -entries: 3507 -senses: 4541 +entradas: 3507 +sentidos: 4541 ... $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +Códigos de saída: `0` sucesso (são permitidos avisos, a menos que se utilize a opção `--strict`), `1` resultados (erros de validação / ficheiros multimédia em falta / avisos quando se utiliza a opção `--strict`), `2` entrada ilegível. From e86a8553b8ea2136f673684143f5e27f93d2a225 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:51 -0600 Subject: [PATCH 159/317] New translations cli.md (Russian) [ci skip] --- docs/ru/guides/cli.md | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/ru/guides/cli.md b/docs/ru/guides/cli.md index 3f1401e..5474323 100644 --- a/docs/ru/guides/cli.md +++ b/docs/ru/guides/cli.md @@ -1,35 +1,35 @@ -# The command line +# Командная строка -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +При установке пакета (`pip install sil-lift`) также устанавливается команда `sil-lift` — поддерживаемый инструмент в стиле LiftTools, входящий в состав пакета (а также, в случае команды `validate`, готовый пример использования API библиотеки). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors + все проблемы, с указанием записи/строки; выход 1 при ошибках sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing + подсчёт записей/значений/языков (потоково; любой размер) +sil-lift sort PATH [-o OUT] канонически отсортированная копия, готовая к сравнениям (по умолчанию: на месте) +sil-lift check-media PATH отчёт об отсутствующих и осиротевших медиа-файлах; выход с кодом 1 при отсутствии sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + одна строка на каждый листьевой сенс (подсенсы сглажены) в формат CSV/TSV (потоковая передача) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` выводит в stdout один объект JSON (и ничего больше) для использования в системах CI/автоматизации; схему см. в примере ниже. Параметр `--strict` рассматривает предупреждения как ошибки и возвращает значение 1 при обнаружении хотя бы одного из них — используйте его, чтобы сборочный процесс завершался только при полном отсутствии проблем, а не при наличии одних лишь ошибок. `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе (подавляя появление сообщений об ошибках `missing-media`), что полезно при проверке только что сгенерированного экспорта, аудио- и фотофайлы которого хранятся в другом месте и не находятся на том же диске. `--require-ids` дополнительно возвращает ошибку (`missing-id`) при обнаружении любой записи, в которой отсутствует `guid`, или сенса, в котором отсутствует `id` — это более строгий подход, чем в LIFT, и предназначен для рабочих процессов, в которых повторный импорт осуществляется по стабильному идентификатору. Если в качестве пути передать символ `-`, документ будет считываться из стандартного ввода (документ, передаваемый по конвейеру, не имеет папки, поэтому сопутствующий файл `.lift-ranges` и медиафайлы не определяются). Команда `stats` также поддерживает опцию `--format json`, выводя результаты подсчёта в виде одного объекта JSON. !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + Коды завершения функции `validate` и схема `--format json` представляют собой поддерживаемый интерфейс автоматизации: оба элемента проходят тестирование и изменяются только в соответствии с SemVer. -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +`sort` перезаписывает только файл `.lift`; сопутствующие файлы `.lift-ranges` остаются неизменными +(их следует сортировать отдельно с помощью API `RangesFile`). -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +Команды `validate`, `stats`, `check-media` и `export` также поддерживают заархивированный пакет LIFT (файл с расширением `.zip` в любом из двух вариантов структуры — с файлами в корневом каталоге архива или вложенными в одну папку верхнего уровня); он распаковывается во временный каталог и удаляется по завершении выполнения команды. -Examples: +Примеры: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +ошибка [dangling-ref] dictionary.lift:88 (запись apu): ссылка «nope» не соответствует ни одному идентификатору записи (ID/GUID), ни идентификатору значения (sense ID) +предупреждение [uri-not-rfc] dictionary.lift:6: : Буква диска Windows использована в качестве авторитета URI (file://C:/ в стиле FLEx) +1 ошибка, 1 предупреждение $ sil-lift validate dictionary.lift --format json { @@ -37,7 +37,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "error", "code": "dangling-ref", - "message": "ref 'nope' matches no entry id/guid or sense id", + "message": "ref 'nope' не соответствует ни одному id/guid записи или id значения", "file": "dictionary.lift", "entry_id": "apu", "guid": null, @@ -46,7 +46,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": В качестве авторитета URI использована буква диска Windows (file://C:/ в стиле FLEx)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -60,11 +60,11 @@ $ sil-lift validate dictionary.lift --format json } $ sil-lift stats sango.lift -entries: 3507 -senses: 4541 +записей: 3507 +значений: 4541 ... $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +Коды завершения: `0` — операция выполнена успешно (предупреждения допускаются, за исключением случая, когда задан параметр `--strict`), `1` — обнаружены проблемы (ошибки валидации / отсутствующие носители / предупреждения при использовании параметра `--strict`), `2` — входные данные нечитаемы. From 7c49311eeaf9a77c558ee3be5a6e8438ad574195 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:52 -0600 Subject: [PATCH 160/317] New translations cli.md (Chinese Simplified) [ci skip] --- docs/zh/guides/cli.md | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/zh/guides/cli.md b/docs/zh/guides/cli.md index 3f1401e..1e6c070 100644 --- a/docs/zh/guides/cli.md +++ b/docs/zh/guides/cli.md @@ -1,35 +1,35 @@ -# The command line +# 命令行 -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +安装该包(`pip install sil-lift`)时,还会一并安装 `sil-lift` 命令——这是一个随包附带的、受支持的 LiftTools 风格工具(对于 `validate` 而言,它还是该库 API 的一个示例)。 ``` -sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors +sil-lift 验证 PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] + 列出所有问题,按条目/行处理;出现错误时退出并返回 1 sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing + 条目/语义/语言计数(流式处理;任意大小) +sil-lift sort PATH [-o OUT] 规范排序、支持差异比较的副本(默认:就地操作) +sil-lift check-media PATH 缺失和孤立媒体报告;若存在缺失则退出并返回 1 sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + 将每个叶片感测单元(子感测单元已扁平化)按一行输出至 CSV/TSV 文件(流式输出) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` 会将单个 JSON 对象写入标准输出(且不输出其他内容),供持续集成(CI)和自动化流程使用;请参阅下例中的数据结构。 `--strict` 将警告视为错误,若发现任何警告则返回 1 —— 使用该选项可确保构建仅在系统状态完全正常时才通过,而不仅仅依赖于是否存在错误。 `--no-check-media` 会跳过文件系统的介质存在性检查(从而抑制 `missing-media` 检测结果),这在验证刚生成的导出文件时非常有用——此时音频/照片文件存储在其他位置,并未与导出文件位于同一磁盘上。 `--require-ids` 还会对任何缺少 `guid` 的条目或缺少 `id` 的语义返回错误(`missing-id` 错误)——这比 LIFT 更严格,适用于通过稳定 ID 重新导入的工作流。 将 `-` 作为路径参数传递时,系统将从标准输入(stdin)读取文档(通过管道传递的文档没有文件夹,因此其配套的 `.lift-ranges` 文件和媒体资源不会被解析)。 `stats` 同样支持 `--format json` 选项,将计数结果以单个 JSON 对象的形式输出。 !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + `validate` 的退出代码和 `--format json` 模式是一种受支持的自动化接口:两者均经过测试验证,且仅在遵循 SemVer 规范的情况下才会发生变更。 -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +`sort` 仅重写 `.lift` 文件;配套的 `.lift-ranges` 文件则保持不变 +(请使用 `RangesFile` API 单独对这些文件进行排序)。 -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +`validate`、`stats`、`check-media` 和 `export` 还支持接收压缩的 LIFT 包(以任何一种布局格式的 `.zip` 文件——文件位于归档根目录下,或嵌套在某个顶级文件夹下);该包会在命令执行完毕后解压到临时目录,并被自动删除。 -Examples: +示例: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +错误 [dangling-ref] dictionary.lift:88(条目 apu):引用 'nope' 未匹配任何条目 ID/GUID 或词义 ID +警告 [uri-not-rfc] dictionary.lift:6: :将 Windows 驱动器盘符用作 URI 权威部分(FLEx 风格的 file://C:/) +1 个错误,1 个警告 $ sil-lift validate dictionary.lift --format json { @@ -37,7 +37,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "error", "code": "dangling-ref", - "message": "ref 'nope' matches no entry id/guid or sense id", + "message": "引用 'nope' 未匹配任何条目 ID/GUID 或语义 ID", "file": "dictionary.lift", "entry_id": "apu", "guid": null, @@ -46,7 +46,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": 将 Windows 驱动器盘符用作 URI 权威部分(FLEx 风格的 file://C:/)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -60,11 +60,11 @@ $ sil-lift validate dictionary.lift --format json } $ sil-lift stats sango.lift -entries: 3507 -senses: 4541 +条目数: 3507 +词义数: 4541 ... $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +退出代码:`0` 成功(允许出现警告,除非启用了 `--strict` 选项),`1` 发现问题(验证错误/媒体文件缺失/在启用 `--strict` 选项时出现的警告),`2` 输入不可读。 From d766c69c62a3fb8c4a7e86ac5b8c96b53d795475 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:54 -0600 Subject: [PATCH 161/317] New translations cli.md (Hindi) [ci skip] --- docs/hi/guides/cli.md | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/hi/guides/cli.md b/docs/hi/guides/cli.md index 3f1401e..64bbf7e 100644 --- a/docs/hi/guides/cli.md +++ b/docs/hi/guides/cli.md @@ -1,35 +1,34 @@ -# The command line +# कमांड लाइन -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +पैकेज (`pip install sil-lift`) इंस्टॉल करने पर `sil-lift` कमांड भी इंस्टॉल हो जाता है — यह एक समर्थित LiftTools-शैली का टूल है जो पैकेज के साथ आता है (और `validate` के लिए लाइब्रेरी API का एक कार्यात्मक उदाहरण)। ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors + सभी समस्याएँ, प्रविष्टि/पंक्ति-पते; त्रुटियों पर 1 से बाहर निकलें sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing + प्रविष्टि/अर्थ/भाषा की गिनती (स्ट्रीमिंग; कोई भी आकार) +sil-lift sort PATH [-o OUT] मानक रूप से क्रमबद्ध, diff-तैयार प्रतिलिपि (डिफ़ॉल्ट: उसी स्थान पर) +sil-lift check-media PATH गुम और अनाथ मीडिया रिपोर्ट; यदि गुम हो तो 1 पर निकास sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + प्रत्येक लीफ़ सेंस के लिए एक पंक्ति (सबसेंस समतल) CSV/TSV में (स्ट्रीमिंग) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` CI/ऑटोमेशन के उपयोग के लिए stdout पर एक ही JSON ऑब्जेक्ट लिखता है (और कुछ नहीं); नीचे दिए गए उदाहरण में स्कीमा देखें। `--strict` चेतावनियों को त्रुटियों के रूप में मानता है, और कोई भी चेतावनी मिलने पर 1 पर बाहर निकल जाता है — इसका उपयोग केवल त्रुटियों के आधार पर नहीं, बल्कि एक स्वच्छ रिपोर्ट के आधार पर बिल्ड को नियंत्रित करने के लिए करें। `--no-check-media` फ़ाइलसिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है (`missing-media` निष्कर्षों को दबाते हुए), जो तब उपयोगी होता है जब किसी ताज़ा उत्पन्न निर्यात का सत्यापन किया जा रहा हो, जिसकी ऑडियो/फ़ोटो फ़ाइलें कहीं और स्थित हैं और डिस्क पर एक साथ नहीं हैं। `--require-ids` अतिरिक्त रूप से किसी भी ऐसी प्रविष्टि पर विफल होता है जिसमें `guid` न हो या किसी सेंस में `id` न हो — यह LIFT की तुलना में अधिक सख्त है, उन वर्कफ़्लो के लिए जो एक स्थिर id द्वारा पुनः आयात करते हैं। पथ के रूप में `-` पास करने पर दस्तावेज़ stdin से पढ़ा जाता है (एक पाइप्ड दस्तावेज़ का कोई फ़ोल्डर नहीं होता, इसलिए इसका साथी `.lift-ranges` और मीडिया हल नहीं होते)। `stats` भी `--format json` लेता है, और गिनतियों को एक ही JSON ऑब्जेक्ट के रूप में उत्पन्न करता है। !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + `validate` के एग्जिट कोड और `--format json` स्कीमा एक समर्थित ऑटोमेशन इंटरफ़ेस हैं: दोनों टेस्ट द्वारा कवर किए गए हैं और केवल SemVer के तहत ही बदलते हैं। -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +`sort` केवल `.lift` फ़ाइल को ही पुनः लिखता है; साथी `.lift-ranges` फ़ाइलें अछूती रह जाती हैं (उन्हें `RangesFile` API के साथ अलग से क्रमबद्ध करें)। -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +`validate`, `stats`, `check-media`, और `export` एक ज़िप किए गए LIFT पैकेज को भी स्वीकार करते हैं (दोनों लेआउट में एक `.zip` — आर्काइव रूट में फ़ाइलें, या एक टॉप-लेवल फ़ोल्डर के अंदर); इसे एक अस्थायी निर्देशिका में निकाला जाता है और कमांड समाप्त होने पर हटा दिया जाता है। -Examples: +उदाहरण: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +त्रुटि [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' किसी भी एंट्री आईडी/GUID या सेंस आईडी से मेल नहीं खाता +चेतावनी [uri-not-rfc] dictionary.lift:6: : URI प्राधिकरण के रूप में Windows ड्राइव अक्षर का उपयोग (FLEx-शैली file://C:/) +1 त्रुटि(एँ), 1 चेतावनी(एँ) $ sil-lift validate dictionary.lift --format json { @@ -46,7 +45,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": Windows ड्राइव अक्षर को URI प्राधिकरण के रूप में उपयोग किया गया (FLEx-शैली file://C:/)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -67,4 +66,4 @@ senses: 4541 $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +एग्जिट कोड: `0` सफलता (चेतावनियाँ अनुमत हैं, जब तक `--strict` न हो), `1` निष्कर्ष (मान्यकरण त्रुटियाँ / मीडिया अनुपस्थित / `--strict` के तहत चेतावनियाँ), `2` अपठनीय इनपुट। From 66e36e95fd58fea2b1e83fe323731271eabb7ac9 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:23:56 -0600 Subject: [PATCH 162/317] New translations cli.md (Swahili) [ci skip] --- docs/sw/guides/cli.md | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/docs/sw/guides/cli.md b/docs/sw/guides/cli.md index 3f1401e..e27414c 100644 --- a/docs/sw/guides/cli.md +++ b/docs/sw/guides/cli.md @@ -1,35 +1,34 @@ -# The command line +# Mstari wa amri -Installing the package (`pip install sil-lift`) also installs the `sil-lift` command — a supported LiftTools-style tool that ships with the package (and, for `validate`, a worked example of the library API). +Kusakinisha kifurushi (`pip install sil-lift`) pia husakinisha amri ya `sil-lift` — zana inayounga mkono mtindo wa LiftTools inayotolewa na kifurushi hicho (na, kwa `validate`, mfano uliofanyiwa kazi wa API ya maktaba). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - all problems, entry/line-addressed; exit 1 on errors + matatizo yote, yaliyotatuliwa kwa kipengee/anwani ya mstari; kutoka 1 kwa makosa sil-lift stats PATH [--format {text,json}] - entry/sense/language counts (streaming; any size) -sil-lift sort PATH [-o OUT] canonically sorted, diff-ready copy (default: in place) -sil-lift check-media PATH missing and orphaned media report; exit 1 if missing -sil-lift export PATH [-o OUT] [--langs L] [--tsv] - one row per leaf sense (subsenses flattened) to CSV/TSV (streaming) + idadi za kipengee/maana/lugha (mtiririko; ukubwa wowote) +sil-lift sort PATH [-o OUT] imepangwa kihalali, nakala tayari kwa tofauti (chaguo-msingi: mahali pake) +sil-lift check-media NJIA ripoti ya vyombo vilivyokosekana na vilivyoachwa peke yake; toa 1 ikiwa hakuna +sil-lift export NJIA [-o OUT] [--langs L] [--tsv] + safu moja kwa kila hisia ya majani (hisia ndogo zimepangwa wazi) kwa CSV/TSV (mtiririko) ``` -`--format json` writes a single JSON object to stdout (and nothing else) for CI/automation consumption; see the schema in the example below. `--strict` treats warnings as errors, exiting 1 if any are found — use it to gate a build on a clean bill of health rather than errors alone. `--no-check-media` skips the filesystem media-presence check (suppressing `missing-media` findings), which is useful when validating a freshly generated export whose audio/photo files live elsewhere and aren't colocated on disk. `--require-ids` additionally fails (a `missing-id` error) on any entry lacking a `guid` or sense lacking an `id` — stricter than LIFT, for workflows that re-import by a stable id. Passing `-` as the path reads the document from stdin (a piped document has no folder, so its companion `.lift-ranges` and media are not resolved). `stats` likewise takes `--format json`, emitting the counts as a single JSON object. +`--format json` huandika object moja ya JSON kwenye stdout (na hakuna kitu kingine) kwa matumizi ya CI/otomatishaji; tazama schema katika mfano hapa chini. `--strict` huchukulia maonyo kama makosa, na kutoka kwa nambari 1 endapo yoyote yatapatikana — itumie ili kuidhinisha ujenzi endapo hakuna matatizo, badala ya kutegemea makosa pekee. `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili (na hivyo kuficha matokeo ya `missing-media`), jambo ambalo ni muhimu wakati wa kuthibitisha toleo jipya lililotengenezwa ambalo faili zake za sauti/picha ziko mahali pengine na haziko kwenye diski pamoja. `--require-ids` pia hushindwa (kosa la `missing-id`) kwa kipengee chochote kinachokosa `guid` au sense kinachokosa `id` — ni kali zaidi kuliko LIFT, kwa mtiririko wa kazi unao-re-import tena kwa kutumia id thabiti. Kupitisha `-` kama njia husoma hati kutoka stdin (hati iliyopitishwa kwa bomba haina folda, hivyo faili zake za `.lift-ranges` na media hazitatatuliwa). `stats` vivyo hivyo huchukua `--format json`, na kutoa hesabu kama kitu kimoja cha JSON. !!! note - `validate`'s exit codes and `--format json` schema are a supported automation interface: both are covered by tests and change only under SemVer. + Misimbo ya kutoka ya `validate` na `--format json` schema ni kiolesura cha kiotomatiki kinachotumika: vyote vimejumuishwa katika majaribio na hubadilika tu kulingana na SemVer. -`sort` rewrites only the `.lift` file; companion `.lift-ranges` files are left -untouched (sort those separately with the `RangesFile` API). +`sort` inaandika upya tu faili ya `.lift`; faili zake washirika za `.lift-ranges` zinaachwa bila kuguswa (ziandike kwa mpangilio tofauti kwa kutumia API ya `RangesFile`). -`validate`, `stats`, `check-media`, and `export` also accept a zipped LIFT package (a `.zip` in either layout — files at the archive root, or nested under one top-level folder); it is extracted to a temporary directory and discarded when the command finishes. +`validate`, `stats`, `check-media`, na `export` pia hukubali kifurushi cha LIFT kilichobanwa (faili la `.zip` katika mpangilio wowote — faili zikiwa kwenye msingi wa hifadhi, au zimewekwa ndani ya folda moja ya ngazi ya juu); hutolewa kwenye saraka ya muda na kutupwa wakati amri inapomalizika. -Examples: +Mifano: ``` $ sil-lift validate dictionary.lift -error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches no entry id/guid or sense id -warning [uri-not-rfc] dictionary.lift:6: : Windows drive letter used as URI authority (FLEx-style file://C:/) -1 error(s), 1 warning(s) +kosa [dangling-ref] dictionary.lift:88 (kipengee apu): ref 'nope' haifanani na kitambulisho chochote cha kipengee au kitambulisho cha maana +onyo [uri-not-rfc] dictionary.lift:6: : Herufi ya diski ya Windows inatumiwa kama mamlaka ya URI (mtindo wa FLEx file://C:/) +1 kosa, 1 onyo $ sil-lift validate dictionary.lift --format json { @@ -37,7 +36,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "error", "code": "dangling-ref", - "message": "ref 'nope' matches no entry id/guid or sense id", + "message": "ref 'nope' inalingana na id/guid ya entry au sense id yoyote", "file": "dictionary.lift", "entry_id": "apu", "guid": null, @@ -46,7 +45,7 @@ $ sil-lift validate dictionary.lift --format json { "level": "warning", "code": "uri-not-rfc", - "message": ": Windows drive letter used as URI authority (FLEx-style file://C:/)", + "message": ": Herufi ya diski ya Windows inatumiwa kama mamlaka ya URI (mtindo wa FLEx file://C:/)", "file": "dictionary.lift", "entry_id": null, "guid": null, @@ -67,4 +66,4 @@ senses: 4541 $ sil-lift export dictionary.lift --langs en,fr -o dictionary.csv ``` -Exit codes: `0` success (warnings allowed, unless `--strict`), `1` findings (validation errors / missing media / warnings under `--strict`), `2` unreadable input. +Misimbo ya kutoka: `0` mafanikio (maonyo yanaruhusiwa, isipokuwa `--strict`), `1` matokeo (makosa ya uthibitishaji / vyombo vya habari vilivyokosekana / maonyo chini ya `--strict`), `2` ingizo lisilosomeka. From 857c052720cb1ffe3ae9cbff7bb2fc23a929d496 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:05 -0600 Subject: [PATCH 163/317] New translations read-edit-write.md (Spanish) [ci skip] --- docs/es/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/read-edit-write.md b/docs/es/guides/read-edit-write.md index dc07d1c..27820e8 100644 --- a/docs/es/guides/read-edit-write.md +++ b/docs/es/guides/read-edit-write.md @@ -5,7 +5,7 @@ ```python import sil_lift -; lex = sil_lift.load("dictionary.lift") +lex = sil_lift.load("dictionary.lift") ``` La función `load()` admite cualquier documento LIFT **0.13** bien formado, incluidos los archivos reales que no cumplen con el esquema. Todo aquello que el modelo no defina (elementos o atributos desconocidos, comentarios) se transmite sin pérdida de información en el campo opaco `extra` de cada nodo. Otras versiones de LIFT generan un error `LiftParseError` indicando la versión. From 1a95f7c4be74b9518e0dc55e67913a60e2f539f3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:10 -0600 Subject: [PATCH 164/317] New translations folder-media.md (Portuguese) [ci skip] --- docs/pt/guides/folder-media.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/pt/guides/folder-media.md b/docs/pt/guides/folder-media.md index 03355ec..ff54327 100644 --- a/docs/pt/guides/folder-media.md +++ b/docs/pt/guides/folder-media.md @@ -1,20 +1,20 @@ -# The LIFT folder: ranges and media +# A pasta LIFT: gamas e suportes -A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. +Um léxico LIFT é normalmente uma _pasta_: o ficheiro `.lift`, um ou mais ficheiros complementares `.lift-ranges` e os ficheiros multimédia nas pastas `audio/` e `pictures/`. -## Ranges +## Intervalos ```python -lex = sil_lift.load("dictionary.lift") # companions tracked automatically +lex = sil_lift.load("dictionary.lift") # companheiros rastreados automaticamente lex.ranges_files # {Path(...): RangesFile} -lex.all_ranges() # merged {id: Range} view +lex.all_ranges() # vista {id: Range} combinada lex.all_ranges()["grammatical-info"].elements ``` -Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. +A descoberta de ficheiros associados lida com o mundo real: é utilizado um `range/@href` que aponta para um ficheiro existente; Os hrefs absolutos «file://C:/...» do FieldWorks que não têm referência recuam para o nome base do href junto ao «.lift»; e o irmão convencional «.lift-ranges» é selecionado mesmo quando nada o referencia. -`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: +A função `lex.save()` grava o ficheiro `.lift` e todas as funções complementares monitorizadas em conjunto. As alterações feitas num `RangesFile` são guardadas no _seu_ ficheiro; os intervalos que não foram alterados mantêm os seus bytes exatos. Utilização autónoma: ```python ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") @@ -23,19 +23,19 @@ ranges.sort() ranges.save() ``` -Pass `resolve_ranges=False` to `load()` to skip companion discovery. +Passe `resolve_ranges=False` à função `load()` para ignorar a deteção de componentes associados. -## Media +## Meios de comunicação ```python -for ref in lex.media_refs(): # every and +for ref in lex.media_refs(): # todos os e print(ref.kind, ref.href, ref.entry_id) -lex.missing_media() # refs whose files don't exist +lex.missing_media() # referências cujos ficheiros não existem ``` -Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. +A resolução segue o esquema convencional: um link «href» relativo é verificado tal como fornecido (barras invertidas normalizadas — o WeSay escreve «pictures\photo with space.png») e na pasta «audio/» (para ficheiros de pronúncia) ou «pictures/» (para ilustrações). Os links «href» remotos/absolutos não podem ser verificados e são ignorados. -## Other folder contents +## Outros conteúdos da pasta -A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. +Uma pasta LIFT contém frequentemente ficheiros que o sil-lift não modela — o sistema de escrita LDML em `WritingSystems/`, os ficheiros de áudio/imagem relativos ao consentimento dos oradores do Combine em `consent/`, e outros semelhantes; As funções `load()`/`save()` não alteram estes ficheiros, e [`Lexicon.save_zip()`](lift-export-interop.md) transfere-os na íntegra ao empacotar a pasta. From a240d2c253ee157683d579622bfa80d027f2a7ed Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:12 -0600 Subject: [PATCH 165/317] New translations folder-media.md (Russian) [ci skip] --- docs/ru/guides/folder-media.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/ru/guides/folder-media.md b/docs/ru/guides/folder-media.md index 03355ec..78ae627 100644 --- a/docs/ru/guides/folder-media.md +++ b/docs/ru/guides/folder-media.md @@ -1,20 +1,20 @@ -# The LIFT folder: ranges and media +# Папка LIFT: диапазоны и носители -A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. +Лексикон LIFT обычно представляет собой _папку_: файл `.lift`, один или несколько сопутствующих файлов `.lift-ranges`, а также мультимедийные файлы в папках `audio/` и `pictures/`. -## Ranges +## Диапазоны ```python -lex = sil_lift.load("dictionary.lift") # companions tracked automatically +lex = sil_lift.load("dictionary.lift") # сопутствующие файлы отслеживаются автоматически lex.ranges_files # {Path(...): RangesFile} -lex.all_ranges() # merged {id: Range} view +lex.all_ranges() # объединенное представление {id: Range} lex.all_ranges()["grammatical-info"].elements ``` -Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. +Механизм обнаружения сопутствующих файлов учитывает особенности реального мира: используется атрибут `range/@href`, указывающий на существующий файл; незавершенные абсолютные ссылки `file://C:/...` в FieldWorks перенаправляются на базовое имя ссылки рядом с расширением `.lift`; а стандартный соседний файл `.lift-ranges` подбирается даже в том случае, если на него ничто не ссылается. -`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: +Функция `lex.save()` записывает файл `.lift` и все отслеживаемые сопутствующие файлы одновременно. Изменения, внесенные в файл `RangesFile`, сохраняются обратно в _этот_ файл; неизмененные диапазоны сохраняют свои точные байты. Использование в автономном режиме: ```python ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") @@ -23,19 +23,19 @@ ranges.sort() ranges.save() ``` -Pass `resolve_ranges=False` to `load()` to skip companion discovery. +Передайте параметр `resolve_ranges=False` в функцию `load()`, чтобы пропустить поиск сопутствующих объектов. -## Media +## СМИ ```python -for ref in lex.media_refs(): # every and - print(ref.kind, ref.href, ref.entry_id) +for ref in lex.media_refs(): # все ссылки типа « » и « + » print(ref.kind, ref.href, ref.entry_id) -lex.missing_media() # refs whose files don't exist +lex.missing_media() # ссылки, файлы которых отсутствуют ``` -Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. +Определение следует стандартной схеме: относительный ссылочный адрес проверяется в том виде, в котором он указан (обратные косые черты нормализуются — WeSay записывает `pictures\photo with space.png`), и находится в каталоге `audio/` (для аудиофайлов с произношением) или `pictures/` (для иллюстраций). Удаленные/абсолютные ссылки не поддаются проверке и пропускаются. -## Other folder contents +## Другое содержимое папки -A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. +В папке LIFT часто хранятся файлы, которые sil-lift не моделирует — LDML для систем письма в каталоге `WritingSystems/`, аудио- и изобразительные файлы с согласием говорящих из проекта «The Combine» в каталоге `consent/` и т. п.; Функции `load()`/`save()` оставляют их без изменений, а [`Lexicon.save_zip()`](lift-export-interop.md) переносит их без изменений при упаковке папки. From 816dc7c68e2000d3358cbed6cf8674d89777153a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:14 -0600 Subject: [PATCH 166/317] New translations folder-media.md (Chinese Simplified) [ci skip] --- docs/zh/guides/folder-media.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/zh/guides/folder-media.md b/docs/zh/guides/folder-media.md index 03355ec..ada11ae 100644 --- a/docs/zh/guides/folder-media.md +++ b/docs/zh/guides/folder-media.md @@ -1,20 +1,20 @@ -# The LIFT folder: ranges and media +# LIFT 文件夹:范围与媒体 -A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. +一个 LIFT 词汇表通常是一个 _文件夹_:包含一个 `.lift` 文件、一个或多个配套的 `.lift-ranges` 文件,以及 `audio/` / `pictures/` 目录中的媒体文件。 -## Ranges +## 范围 ```python -lex = sil_lift.load("dictionary.lift") # companions tracked automatically +lex = sil_lift.load("dictionary.lift") # 自动追踪伴随对象 lex.ranges_files # {Path(...): RangesFile} -lex.all_ranges() # merged {id: Range} view +lex.all_ranges() # 合并后的 {id: Range} 视图 lex.all_ranges()["grammatical-info"].elements ``` -Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. +Companion discovery 处理现实情况:使用指向现有文件的 `range/@href`; FieldWorks 中悬空的绝对 `file://C:/...` href 会回退到 href 的基名,并将其附加在 `.lift` 之后;而常规的 `.lift-ranges` 同级文件,即使没有任何引用,也会被识别出来。 -`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: +`lex.save()` 会将 `.lift` 以及所有被追踪的伴生类一起写入。 对 `RangesFile` 进行的修改将保存回该文件;未修改的范围将保留其精确的字节数据。 独立使用: ```python ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") @@ -23,19 +23,19 @@ ranges.sort() ranges.save() ``` -Pass `resolve_ranges=False` to `load()` to skip companion discovery. +向 `load()` 传递 `resolve_ranges=False` 参数,以跳过伴侣节点发现。 -## Media +## 媒体 ```python -for ref in lex.media_refs(): # every and +for ref in lex.media_refs(): # 所有 print(ref.kind, ref.href, ref.entry_id) -lex.missing_media() # refs whose files don't exist +lex.missing_media() # 文件不存在的引用 ``` -Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. +解析遵循常规布局:对相对 href 进行原样检查(反斜杠已规范化——WeSay 写的是 `pictures\photo with space.png`),并检查其是否位于 `audio/`(用于发音媒体)或 `pictures/`(用于插图)目录下。 无法验证远程/绝对 href,因此会跳过这些链接。 -## Other folder contents +## 其他文件夹内容 -A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. +LIFT 文件夹通常包含 sil-lift 未建模的文件——例如 `WritingSystems/` 下的书写系统 LDML、`consent/` 下的 The Combine 发言人同意书的音频/图像文件等; `load()`/`save()` 不会对这些文件进行任何操作,而 [`Lexicon.save_zip()`](lift-export-interop.md) 在打包文件夹时会原样保留这些文件。 From 9206b594a1875a1c650eaacc3e9af67010b232aa Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:15 -0600 Subject: [PATCH 167/317] New translations folder-media.md (Hindi) [ci skip] --- docs/hi/guides/folder-media.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/hi/guides/folder-media.md b/docs/hi/guides/folder-media.md index 03355ec..c8e0c47 100644 --- a/docs/hi/guides/folder-media.md +++ b/docs/hi/guides/folder-media.md @@ -1,20 +1,20 @@ -# The LIFT folder: ranges and media +# LIFT फ़ोल्डर: श्रेणियाँ और मीडिया -A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. +एक LIFT शब्दकोश आमतौर पर एक _फ़ोल्डर_ होता है: `.lift` फ़ाइल, एक या अधिक `.lift-ranges` साथी, और `audio/` / `pictures/` मीडिया। -## Ranges +## दायरे ```python -lex = sil_lift.load("dictionary.lift") # companions tracked automatically -lex.ranges_files # {Path(...): RangesFile} -lex.all_ranges() # merged {id: Range} view +lex = sil_lift.load("dictionary.lift") # साथी स्वचालित रूप से ट्रैक किए जाते हैं + +lex.ranges_files # {Path(...): RangesFile} view lex.all_ranges()["grammatical-info"].elements ``` -Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. +साथी खोज वास्तविक दुनिया को संभालती है: एक `range/@href` जिसका संदर्भ किसी मौजूदा फ़ाइल की ओर है, का उपयोग किया जाता है; FieldWorks के dangling absolute `file://C:/...` hrefs `.lift` के पास होने पर href के basename पर वापस आ जाते हैं; और पारंपरिक `.lift-ranges` sibling तब भी लिया जाता है जब कोई भी इसे संदर्भित नहीं करता। -`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: +`lex.save()` `.lift` और प्रत्येक ट्रैक किए गए साथी को एक साथ लिखता है। `RangesFile` में किए गए संपादन _उसकी_ फ़ाइल में वापस सहेजे जाते हैं; बिना बदले रेंज अपने सटीक बाइट्स बनाए रखते हैं। स्वतंत्र उपयोग: ```python ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") @@ -23,19 +23,19 @@ ranges.sort() ranges.save() ``` -Pass `resolve_ranges=False` to `load()` to skip companion discovery. +साथी खोज को छोड़ने के लिए `load()` को `resolve_ranges=False` पास करें। -## Media +## माध्यम ```python -for ref in lex.media_refs(): # every and +for ref in lex.media_refs(): # हर और print(ref.kind, ref.href, ref.entry_id) -lex.missing_media() # refs whose files don't exist +lex.missing_media() # उन रेफ़रेंसों के लिए जिनकी फाइलें मौजूद नहीं हैं ``` -Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. +रिज़ॉल्यूशन पारंपरिक लेआउट का अनुसरण करता है: एक सापेक्ष href को दिए गए रूप में जांचा जाता है (बैकस्लैश को सामान्यीकृत किया गया — WeSay लिखता है `pictures\photo with space.png`) और `audio/` (उच्चारण मीडिया के लिए) या `pictures/` (चित्रण के लिए) के अंतर्गत। रिमोट/एब्सोल्यूट hrefs की जाँच नहीं की जा सकती और उन्हें छोड़ दिया जाता है। -## Other folder contents +## अन्य फ़ोल्डर की सामग्री -A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. +एक LIFT फ़ोल्डर में अक्सर ऐसी फ़ाइलें होती हैं जिन्हें sil-lift मॉडल नहीं करता — जैसे `WritingSystems/` के अंतर्गत लेखन-प्रणाली LDML, `consent/` के अंतर्गत The Combine के वक्ता सहमति ऑडियो/छवि फ़ाइलें, और इसी तरह की अन्य फ़ाइलें; `load()`/`save()` इन्हें बिना छुए छोड़ देते हैं, और [`Lexicon.save_zip()`](lift-export-interop.md) फ़ोल्डर को पैकेज करते समय इन्हें शब्दशः शामिल करता है। From 8a340cac02fef0a380232483e733289d8f643b8f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:17 -0600 Subject: [PATCH 168/317] New translations folder-media.md (Swahili) [ci skip] --- docs/sw/guides/folder-media.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/sw/guides/folder-media.md b/docs/sw/guides/folder-media.md index 03355ec..520e57f 100644 --- a/docs/sw/guides/folder-media.md +++ b/docs/sw/guides/folder-media.md @@ -1,20 +1,20 @@ -# The LIFT folder: ranges and media +# Folda ya LIFT: masafa na vyombo vya habari -A LIFT lexicon is usually a _folder_: the `.lift` file, one or more `.lift-ranges` companions, and `audio/` / `pictures/` media. +Kamusi ya LIFT kawaida ni _folda_: faili ya `.lift`, moja au zaidi ya faili za `.lift-ranges` zinazohusiana, na media za `audio/` / `pictures/`. -## Ranges +## Vipimo ```python -lex = sil_lift.load("dictionary.lift") # companions tracked automatically +lex = sil_lift.load("dictionary.lift") # wenzao hufuatiliwa kiotomatiki lex.ranges_files # {Path(...): RangesFile} -lex.all_ranges() # merged {id: Range} view +lex.all_ranges() # mtazamo uliounganishwa wa {id: Range} lex.all_ranges()["grammatical-info"].elements ``` -Companion discovery handles the real world: a `range/@href` that points at an existing file is used; FieldWorks' dangling absolute `file://C:/...` hrefs fall back to the href's basename next to the `.lift`; and the conventional `.lift-ranges` sibling is picked up even when nothing references it. +Ugunduzi wa Companion unashughulikia ulimwengu halisi: `range/@href` inayoelekeza kwenye faili iliyopo hutumika; Viungo kamili vilivyokatika vya FieldWorks (`file://C:/...`) hurudi kwenye jina la msingi la faili lililo kwenye `.lift`; na ndugu wa kawaida `.lift-ranges` huchukuliwa hata kama hakuna kinachorejelea. -`lex.save()` writes the `.lift` and every tracked companion together. Edits to a `RangesFile` save back to _its_ file; untouched ranges keep their exact bytes. Standalone use: +`lex.save()` huandika `.lift` na kila mwandani aliyefuatiliwa pamoja. Marekebisho kwenye `RangesFile` huhifadhiwa tena kwenye faili yake; vipimo visivyoguswa hubaki na baiti zao halisi. Matumizi ya peke yake: ```python ranges = sil_lift.RangesFile.load("dictionary.lift-ranges") @@ -23,19 +23,19 @@ ranges.sort() ranges.save() ``` -Pass `resolve_ranges=False` to `load()` to skip companion discovery. +Pitisha `resolve_ranges=False` kwenye `load()` ili kupuuza ugunduzi wa vifaa viendani. -## Media +## Vyombo vya habari ```python -for ref in lex.media_refs(): # every and +kwa ref katika lex.media_refs(): # kila na print(ref.kind, ref.href, ref.entry_id) -lex.missing_media() # refs whose files don't exist +lex.missing_media() # marejeleo ambayo faili zao hazipo ``` -Resolution follows the conventional layout: a relative href is checked as given (backslashes normalized — WeSay writes `pictures\photo with space.png`) and under `audio/` (for pronunciation media) or `pictures/` (for illustrations). Remote/absolute hrefs can't be checked and are skipped. +Resolution inafuata mpangilio wa kawaida: href ya jamaa inachunguzwa kama ilivyo (backslashes zimewekwa sawa — WeSay inaandika `pictures\photo with space.png`) na chini ya `audio/` (kwa vyombo vya matamshi) au `pictures/` (kwa michoro). Href za mbali/kamili haziwezi kukaguliwa na hupitishwa. -## Other folder contents +## Maudhui mengine ya folda -A LIFT folder often holds files sil-lift doesn't model — writing-system LDML under `WritingSystems/`, The Combine's speaker consent audio/image files under `consent/`, and the like; `load()`/`save()` leave these untouched, and [`Lexicon.save_zip()`](lift-export-interop.md) carries them through verbatim when packaging the folder. +Folda ya LIFT mara nyingi huwa na faili ambazo sil-lift haizifanyi modeli — LDML ya mfumo wa uandishi chini ya `WritingSystems/`, faili za sauti/picha za idhini za The Combine chini ya `consent/`, na kadhalika; `load()`/`save()` hazibadilishi hizi, na [`Lexicon.save_zip()`](lift-export-interop.md) huzihamisha neno kwa neno wakati wa kufunga folda. From 79835205689a6cb94fde7282cffa456710312158 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:21 -0600 Subject: [PATCH 169/317] New translations large-files.md (Russian) [ci skip] --- docs/ru/guides/large-files.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/ru/guides/large-files.md b/docs/ru/guides/large-files.md index 32f0881..5faab2b 100644 --- a/docs/ru/guides/large-files.md +++ b/docs/ru/guides/large-files.md @@ -1,13 +1,13 @@ -# Large files (streaming) +# Крупные файлы (потоковая передача) -`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. +Функция `load()` создаёт весь граф объектов. В случае лексиконов объёмом в несколько сотен МБ потоковый API обрабатывает по одной записи за раз в ограниченном объёме памяти — при этом используется тот же тип `Entry`, поэтому код, написанный для одного режима, работает и в другом. ```python import sil_lift with sil_lift.open_reader("big.lift") as reader: - header = reader.header # parsed up front (precedes entries) - for entry in reader: # lazy Iterator[Entry] + header = reader.header # проанализировано заранее (расположено перед записями) + for entry in reader: # ленивый итератор Iterator[Entry] ... ``` @@ -16,12 +16,12 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( "out.lift", header=reader.header, producer="my-script" ) as writer: for entry in reader: - if not entry.date_deleted: # e.g. drop tombstones + if not entry.date_deleted: # например, удалить «могильные камни» writer.write(entry) ``` -Notes: +Примечания: -- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. -- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. -- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. +- Результат работы этого модуля полностью соответствует тому, что выдал бы канонический сериализатор полного документа для того же самого контента — эти два режима никогда не расходятся. +- В режиме потоковой передачи отсутствует уровень пропуска байтов: выходные данные всегда имеют канонический вид. Остаточные данные корневого уровня — комментарии между записями и атрибуты, выходящие за пределы схемы, в файле `` — не передаются; записи и заголовок передаются в полном виде, включая остаточные данные. +- Если в теле блока `open_writer` происходит исключение, файл остается видимо незавершенным (без закрывающего ``) — частично записанный лексикон не должен выглядеть завершенным. From 27542dfd0f4f7832cd678cb214bb18dc43da420a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:22 -0600 Subject: [PATCH 170/317] New translations large-files.md (Chinese Simplified) [ci skip] --- docs/zh/guides/large-files.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/zh/guides/large-files.md b/docs/zh/guides/large-files.md index 32f0881..f0278a8 100644 --- a/docs/zh/guides/large-files.md +++ b/docs/zh/guides/large-files.md @@ -1,27 +1,27 @@ -# Large files (streaming) +# 大文件(流式传输) -`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. +`load()` 会构建整个对象图。 对于大小达数百MB的词典,流式处理 API 会在有限的内存中逐条处理条目——由于采用的是相同的 `Entry` 类型,因此针对一种模式编写的代码在另一种模式下同样适用。 ```python import sil_lift with sil_lift.open_reader("big.lift") as reader: - header = reader.header # parsed up front (precedes entries) - for entry in reader: # lazy Iterator[Entry] + header = reader.header # 提前解析(位于条目之前) + for entry in reader: # 惰性 Iterator[Entry] ... ``` ```python -with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( +使用 sil_lift.open_reader("big.lift") 作为读取器,sil_lift.open_writer( "out.lift", header=reader.header, producer="my-script" -) as writer: +) 作为写入器: for entry in reader: - if not entry.date_deleted: # e.g. drop tombstones + if not entry.date_deleted: # 例如:删除坟墓石 writer.write(entry) ``` -Notes: +注: -- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. -- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. -- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. +- 该写入器的输出结果与全文档规范序列化器针对相同内容生成的结果完全一致——这两种模式的结果始终保持一致。 +- 流式传输模式没有字节直通层:输出始终是规范格式。 根级残留内容——即条目之间的注释以及 `` 上超出模式范围的属性——不会被传递;条目和头部内容是完整的,其中包含残留内容。 +- 如果 `open_writer` 代码块内部抛出异常,该文件将被标记为未终止(即没有关闭的 ``)——一个只写了一半的词汇表绝不能看起来像是完整的。 From 64e04500abb6e17f666acd03419772f91613d7dc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:24 -0600 Subject: [PATCH 171/317] New translations large-files.md (Hindi) [ci skip] --- docs/hi/guides/large-files.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/hi/guides/large-files.md b/docs/hi/guides/large-files.md index 32f0881..e8e1cdb 100644 --- a/docs/hi/guides/large-files.md +++ b/docs/hi/guides/large-files.md @@ -1,13 +1,13 @@ -# Large files (streaming) +# बड़ी फ़ाइलें (स्ट्रीमिंग) -`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. +`load()` पूरे ऑब्जेक्ट ग्राफ़ का निर्माण करता है। सैकड़ों एमबी के शब्दकोशों के लिए, स्ट्रीमिंग एपीआई सीमित मेमोरी में एक समय में एक प्रविष्टि को संसाधित करता है — वही `Entry` प्रकार, इसलिए एक मोड के लिए लिखा गया कोड दूसरे मोड में भी काम करता है। ```python import sil_lift with sil_lift.open_reader("big.lift") as reader: - header = reader.header # parsed up front (precedes entries) - for entry in reader: # lazy Iterator[Entry] + header = reader.header # पहले से पार्स किया गया (एंट्रीज़ से पहले) + for entry in reader: # लेज़ी Iterator[Entry] ... ``` @@ -16,12 +16,12 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( "out.lift", header=reader.header, producer="my-script" ) as writer: for entry in reader: - if not entry.date_deleted: # e.g. drop tombstones + if not entry.date_deleted: # उदाहरण के लिए टॉम्बस्टोन हटाएँ writer.write(entry) ``` -Notes: +टिप्पणियाँ: -- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. -- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. -- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. +- लेखक का आउटपुट बिल्कुल वैसा ही होता है जैसा पूर्ण-दस्तावेज़ कैनोनिकल सीरियलाइज़र उसी सामग्री के लिए उत्पन्न करेगा — दोनों मोड कभी अलग नहीं होते। +- स्ट्रीमिंग मोड में बाइट-पासथ्रू लेयर नहीं होती: आउटपुट हमेशा मानक होता है। रूट-स्तर का अवशेष — प्रविष्टियों के बीच और स्कीमा-बाहर के गुणों वाले `` पर टिप्पणियाँ — शामिल नहीं किया जाता; प्रविष्टियाँ और हेडर अवशेष सहित पूर्ण होते हैं। +- यदि `open_writer` ब्लॉक के शरीर में raise होता है, तो फ़ाइल स्पष्ट रूप से अधूरी छोड़ दी जाती है (कोई समापन `` नहीं) — एक आधा लिखा गया शब्दकोश पूर्ण नहीं दिखना चाहिए। From 74579ab7eb3a9a9161d538e636abfc65d1ef8028 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:26 -0600 Subject: [PATCH 172/317] New translations large-files.md (Swahili) [ci skip] --- docs/sw/guides/large-files.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/sw/guides/large-files.md b/docs/sw/guides/large-files.md index 32f0881..8363524 100644 --- a/docs/sw/guides/large-files.md +++ b/docs/sw/guides/large-files.md @@ -1,12 +1,12 @@ -# Large files (streaming) +# Faili kubwa (mtiririko) -`load()` builds the whole object graph. For multi-hundred-MB lexicons, the streaming API processes one entry at a time in bounded memory — the same `Entry` type, so code written against one mode works in the other. +`load()` huunda grafu nzima ya vitu. Kwa kamusi zenye mamia ya MB, API ya mtiririko huchakata kipengee kimoja kwa wakati katika kumbukumbu yenye ukomo — aina ile ile ya `Entry`, hivyo msimbo ulioandikwa kwa njia moja unafanya kazi katika njia nyingine. ```python import sil_lift with sil_lift.open_reader("big.lift") as reader: - header = reader.header # parsed up front (precedes entries) + header = reader.header # imeparswa mapema (kabla ya entries) for entry in reader: # lazy Iterator[Entry] ... ``` @@ -16,12 +16,12 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( "out.lift", header=reader.header, producer="my-script" ) as writer: for entry in reader: - if not entry.date_deleted: # e.g. drop tombstones + if not entry.date_deleted: # mfano, ondoa tombstones writer.write(entry) ``` -Notes: +Maelezo: -- The writer's output is exactly what the full-document canonical serializer would produce for the same content — the two modes never drift apart. -- Streaming mode has no byte-passthrough layer: output is always canonical. Root-level residue — comments between entries and out-of-schema attributes on `` — is not carried; entries and the header are complete, residue included. -- If the body of an `open_writer` block raises, the file is left visibly unterminated (no closing ``) — a half-written lexicon must not look complete. +- Matokeo ya mwandishi ni sawa kabisa na kile ambacho serializer kanoniki kamili ya hati ingetengeneza kwa maudhui yale yale — modi hizo mbili haziwahi kutofautiana. +- Modi ya utiririshaji haina safu ya kupitisha baiti: pato daima ni kanoniki. Baki ya kiwango cha mizizi — maoni kati ya vitu na sifa zisizo za mpangilio kwenye `` — hazibebwi; vitu na kichwa ni kamili, ikijumuisha baki. +- Ikiwa bloku ya `open_writer` itapandishwa, faili inabaki haijakamilika wazi (bila `` ya kufunga) — kamusi iliyoandikwa nusu haipaswi kuonekana imekamilika. From 92eb801fe220f8af587f8f09e8562f0ed07a816e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:29 -0600 Subject: [PATCH 173/317] New translations lift-export-interop.md (Russian) [ci skip] --- docs/ru/guides/lift-export-interop.md | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/ru/guides/lift-export-interop.md b/docs/ru/guides/lift-export-interop.md index 53edc50..40935ee 100644 --- a/docs/ru/guides/lift-export-interop.md +++ b/docs/ru/guides/lift-export-interop.md @@ -13,32 +13,32 @@ LIFT обычно передаётся в виде одного файла `.zip Файлы `.lift` и `.lift-ranges` сохраняют точность воспроизведения на уровне байтов внутри пакета; сам контейнер zip не обеспечивает точность воспроизведения на уровне байтов. -## Validate the output as a conformance gate +## Проверить выходные данные в качестве контрольного критерия соответствия -Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. +Укажите команде `sil-lift validate` путь к сгенерированному файлу `.lift`. Он выполняет проверку с помощью RELAX NG (как над `.lift`, так и над его сопутствующим элементом `.lift-ranges`), а также семантические проверки, которые не могут быть выражены с помощью грамматики: незавершенные ссылки на `relation`/`variant`, дубликаты GUID, целостность родительских элементов диапазона, значения черт и грамматической информации, не определённые в их диапазоне, а также ссылки в заголовке `range/@href`, которые не указывают на сопутствующий элемент. -For CI, fail on anything and emit machine-readable findings: +Для CI: в случае любой ошибки выдавать результаты в машиночитаемом формате: ``` sil-lift validate export.lift --strict --no-check-media --format json ``` -- `--strict` makes warnings (not just errors) fail the run. -- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. -- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). -- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. +- Параметр `--strict` приводит к сбою выполнения даже при появлении предупреждений (а не только ошибок). +- `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе, поскольку результаты проверки `missing-media` являются ложными срабатываниями, если аудио- и фотофайлы не находятся в одном каталоге с файлом `.lift` в CI. +- `--format json` выводит один объект JSON (`{"problems": [...], "summary": {...}}`) вместо текста, понятного человеку; его коды завершения и схема представляют собой поддерживаемый интерфейс, на который распространяется спецификация SemVer (см. [руководство по командной строке](cli.md)). +- `--require-ids` дополнительно выдает ошибку при обнаружении записей, в которых отсутствует `guid`, или при обнаружении элементов, в которых отсутствует `id` — это полезно, когда при последующем повторном импорте необходимо обновить данные, а не дублировать их. -Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: +Защититесь от незаметной потери данных (типа сбоя, приводящего к потере информации при экспорте в плоский формат CSV), проверив статистику с помощью команды `stats --format json` для вашей исходной модели: ``` sil-lift stats export.lift --format json ``` -It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. +В нём приводятся данные о количестве «записей», «значений», «примеров», «ссылок на мультимедиа», «языков», а также «характеристик» для каждого названия. -### Running the gate without a Python toolchain +### Запуск gate без инструментария Python -A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: +В рамках непрерывной интеграции (CI) проекта на TypeScript или C# эту же проверку можно выполнить без установки Python с помощью встроенного GitHub Action: ```yaml - uses: sillsdev/python-sil-lift@v0.1.0 @@ -49,16 +49,16 @@ A TypeScript or C# project's CI can run the same check without installing Python format: json ``` -or the container image, built from the repo's `Dockerfile`: +или образ контейнера, скомпилированный на основе файла `Dockerfile` из репозитория: ``` docker build -t sil-lift . docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict ``` -## The `.lift-ranges` companion +## Сопутствующий элемент `.lift-ranges` -Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: +Контролируемые словари — части речи, семантические домены и любые другие наборы значений, организованные по признакам — хранятся в отдельном файле `.lift-ranges`, на который есть ссылка в файле `
`: ```xml
@@ -69,40 +69,40 @@ Controlled vocabularies — parts of speech, semantic domains, and any other tra
``` -The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: +В справочнике приводится полное определение каждого диапазона. Значения представляют собой ``; `parent` формирует иерархию; `label` / `abbrev` / `description` являются мультитекстами: ```xml - -
n
+ +
существительное
- +
``` -An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). +Затем в записи происходит ссылка на значение по идентификатору: часть речи значения — ``, а семантическая область — ``. Команда `sil-lift validate` выдает предупреждение (`undefined-range-value`), если значение не определено в соответствующем диапазоне, и ошибку (`range-parent`), если `parent` не является идентификатором элемента одного уровня — поэтому указывайте диапазоны, которые фактически используются в ваших данных. См. также [Диапазоны и носители](folder-media.md). -If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. +Если вы создаете экспорт на Python, функции `Lexicon.add_ranges_file()`, `RangesFile.add_range()` и `Range.add_element()` автоматически формируют сопутствующий объект и добавляют ссылки на заголовки; `open_writer(..., ranges=...)` выполняет то же самое для потокового пути. -## Text and multitext +## Текст и несколько текстов -Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: +Каждая строка на одном из человеческих языков в LIFT представляет собой _мультитекст_: по одному `` для каждой системы письма, каждая из которых содержит ``: ```xml kanga -
galinha
+
курица
``` -A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. +Модель, в которой строки индексируются по коду языка (тип `MultiString`, `Record`, `dict[str, str]`), отображается на эту модель в соотношении «один к одному»: каждая запись по ключу преобразуется в один объект ``. В одном мультитексте допускается не более одной формы на каждый язык — в противном случае `sil-lift` выдает предупреждение `duplicate-form-lang`. -XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. +Экранирование XML — это единственная часть, в которой действительно важно соблюдать точность. В тексте элемента символы `&`, `<`, and `>` должны быть экранированы (`&`, `<`, `>`); в значениях атрибутов также необходимо экранировать символ кавычки. Программа `sil-lift` строго следует этим правилам и никогда не изменяет пробелы внутри `` — она не добавляет там отступов, поскольку это привело бы к повреждению лексических данных. Если вы хотите добиться такого же результата, используйте экранирование, предусмотренное настоящим XML-сериализатором (а не самодельную замену, в которой упускается символ `&`), и оставьте содержимое `` без изменений, байт за байтом, так как оно есть в исходном коде. From a21787394e1a1637933edfd5dfe6dac8b880e32d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:31 -0600 Subject: [PATCH 174/317] New translations lift-export-interop.md (Chinese Simplified) [ci skip] --- docs/zh/guides/lift-export-interop.md | 66 +++++++++++++-------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/zh/guides/lift-export-interop.md b/docs/zh/guides/lift-export-interop.md index cf046b5..acabc46 100644 --- a/docs/zh/guides/lift-export-interop.md +++ b/docs/zh/guides/lift-export-interop.md @@ -1,44 +1,44 @@ -# Producing conformant LIFT +# 生成符合规范的 LIFT -This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. +本指南适用于任何编写 LIFT _导出器_ 的开发者——即使用任何编程语言编写、将其他应用程序的数据模型转换为 LIFT 0.13 格式的代码。 在该工作中,`sil-lift` 承担着双重作用:一是作为符合性检查机制,既验证输出是否符合模式规范,又处理模式无法表达的语义;二是作为输出必须遵循的形状和文本规则的参考标准。 -Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. +编写 LIFT 要比解析它容易得多:导出器只会输出其自身模型生成的子集结构,而无需处理完整规范中的可选项。 难点在于细节——`.lift-ranges` 伴生组件、针对各书写系统的文本、稳定的标识符以及 XML 转义——而下文中的检查项正是针对这些细节的。 -## Zipped packages +## 压缩包 -LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. +LIFT 通常以单个 `.zip` 文件的形式进行传输——FieldWorks 和 The Combine 都采用这种方式进行导入和导出——因此 `sil-lift` 可以直接读取和写入压缩包,无论采用生态系统中哪种布局:文件位于归档根目录下,还是嵌套在某个顶级文件夹之下。 -- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. -- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. +- **说明:** `sil_lift.load("package.zip")` 会将文件解压到临时目录中,定位唯一的 `.lift` 文件,并将其加载(相关文件和媒体资源将按常规方式解析)。 `validate`、`stats`、`check-media` 和 `export` 命令行命令也支持 `.zip` 路径,因此下面的门控脚本可直接对该包进行处理。 提取功能已针对恶意归档文件进行了加固——拒绝路径遍历操作,并对条目数量和总未压缩大小(10 GiB)设置了上限,以防范ZIP炸弹攻击。 +- **编写:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` 会将 `.lift`、其 `.lift-ranges` 以及源文件夹中的所有其他文件(media、`WritingSystems/`、`consent/` 等)打包在一起 打包成zip文件。 `wrap_folder` 的默认行为是创建一个以压缩包命名的顶级文件夹(遵循 FieldWorks/Combine 的导入规范);若要生成扁平化归档,请传入 `False`。 -The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. +`.lift` 和 `.lift-ranges` 在包内部保持字节级精确性;而 zip 容器本身无法实现字节级还原。 -## Validate the output as a conformance gate +## 将输出作为符合性检查点进行验证 -Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. +将 `sil-lift validate` 指向生成的 `.lift` 文件。 它运行 RELAX NG(同时针对 `.lift` 及其配套的 `.lift-ranges`),并执行语法无法表达的语义检查: 悬空的 `relation`/`variant` 引用、重复的 GUID、范围元素父元素的完整性、在所属范围内未定义的性状和语法信息值,以及解析后未找到对应伴侣的 `range/@href` 引用。 -For CI, fail on anything and emit machine-readable findings: +对于持续集成(CI),只要出现任何问题就应报错,并输出机器可读的检测结果: ``` sil-lift validate export.lift --strict --no-check-media --format json ``` -- `--strict` makes warnings (not just errors) fail the run. -- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. -- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). -- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. +- `--strict` 会使警告(而不仅仅是错误)导致运行失败。 +- `--no-check-media` 会跳过文件系统的媒体存在性检查;当音频/照片文件在持续集成(CI)环境中未与 `.lift` 文件位于同一位置时,该检查产生的 `missing-media` 错误提示属于误报。 +- `--format json` 会输出一个 JSON 对象(`{"problems": [...], "summary": {...}}`),而非可读文本;其退出代码和模式构成一个受支持且符合 SemVer 规范的接口(参见 [命令行指南](cli.md))。 +- `--require-ids` 还会针对缺少 `guid` 的条目或缺少 `id` 的字段报错——这在后续重新导入时需要更新而非重复导入的情况下非常有用。 -Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: +通过使用 `stats --format json` 对源模型进行计数验证,以防范“隐性数据丢失”(即导致平面 CSV 导出出现数据丢失的故障模式): ``` -sil-lift stats export.lift --format json +sil-lift 统计数据导出:export.lift --format json ``` -It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. +它报告了`条目`、`释义`、`例句`、`媒体引用`、`语言`以及按名称划分的`特征`数量。 -### Running the gate without a Python toolchain +### 在不使用 Python 工具链的情况下运行 Gate -A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: +TypeScript 或 C# 项目的持续集成(CI)可以通过内置的 GitHub Action 运行相同的检查,而无需安装 Python: ```yaml - uses: sillsdev/python-sil-lift@v0.1.0 @@ -49,16 +49,16 @@ A TypeScript or C# project's CI can run the same check without installing Python format: json ``` -or the container image, built from the repo's `Dockerfile`: +或者由仓库中的 `Dockerfile` 构建的容器镜像: ``` docker build -t sil-lift . docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict ``` -## The `.lift-ranges` companion +## `.lift-ranges` 伴生组件 -Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: +受控词汇表——包括词性、语义领域以及任何其他基于特征的键值对集——存储在同级的 `.lift-ranges` 文件中,并在 `
` 中引用该文件: ```xml
@@ -69,40 +69,40 @@ Controlled vocabularies — parts of speech, semantic domains, and any other tra
``` -The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: +该手册收录了各系列产品的完整定义。 这些值是 ``;`parent` 构建层次结构;`label` / `abbrev` / `description` 是多文本: ```xml - +
n
- +
``` -An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). +随后,条目通过 ID 引用该值:词类的 ID 为 ``,语义领域的 ID 为 ``。 当某个值未在其范围内定义时,`sil-lift validate` 会发出警告(`undefined-range-value`);当 `parent` 不是同级 ID 时,会报错(`range-parent`)——因此请仅输出数据实际使用的范围。 另请参阅 [频段与传输介质](folder-media.md)。 -If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. +如果你使用 Python 构建导出文件,`Lexicon.add_ranges_file()`、`RangesFile.add_range()` 和 `Range.add_element()` 会自动为你构建关联对象并添加头文件引用; `open_writer(..., ranges=...)` 则在流式路径上执行相同操作。 -## Text and multitext +## 文本和多文本 -Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: +LIFT 中的每条人类语言字符串都是一个 _多文本_:每个书写系统对应一个 ``,每个 ` ` 都包含一个 ``: ```xml kanga -
galinha
+
小鸡
``` -A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. +一个按语言代码对字符串进行索引的模型(`MultiString`、`Record` 或 `dict[str, str]`)与该模型之间存在一对一映射:每个键对应一个条目,即一个 ``。 在单个多文本中,每种语言最多允许出现一个形式——否则,`sil-lift` 会发出 `duplicate-form-lang` 警告。 -XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. +XML转义是唯一真正需要严格确保正确性的部分。 在元素文本中,`&`、`<`, and `>` 必须进行转义(`&`、`<`、`>`);在属性值中,引号字符也必须进行转义。 `sil-lift` 的编写者严格遵循这些规则,绝不会修改 `` 内的空白字符——它不会在此处添加任何缩进,因为那样会破坏词法数据。 如果你希望生成与源数据完全一致的输出,请复用真正的 XML 序列化器的转义处理(而不是那种会遗漏 `&` 的自制替换方案),并将 `` 内容按字节原样保留,与源数据保持完全一致。 From 63ce750e4cf63cab325b3e690e1a20f82c92fecf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:33 -0600 Subject: [PATCH 175/317] New translations lift-export-interop.md (Hindi) [ci skip] --- docs/hi/guides/lift-export-interop.md | 82 +++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/docs/hi/guides/lift-export-interop.md b/docs/hi/guides/lift-export-interop.md index cf046b5..91b7758 100644 --- a/docs/hi/guides/lift-export-interop.md +++ b/docs/hi/guides/lift-export-interop.md @@ -1,64 +1,64 @@ -# Producing conformant LIFT +# अनुरूप LIFT का उत्पादन -This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. +यह मार्गदर्शिका उन सभी के लिए है जो LIFT _एक्सपोर्टर_ लिख रहे हैं — किसी भी भाषा में ऐसा कोड जो किसी अन्य एप्लिकेशन के डेटा मॉडल को LIFT 0.13 में परिवर्तित करता है। `sil-lift` उस कार्य के लिए दो भूमिकाएँ निभाता है: एक अनुपालन द्वार जो आउटपुट की जाँच स्कीमा और उन अर्थों के अनुसार करता है जिन्हें स्कीमा व्यक्त नहीं कर सकती, और आउटपुट द्वारा अनुसरण किए जाने वाले आकारों और पाठ नियमों के लिए एक संदर्भ। -Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. +LIFT लिखना इसे पार्स करने से कहीं आसान है: एक एक्सपोर्टर केवल उन संरचनाओं का उपसमूह उत्पन्न करता है जिन्हें उसका अपना मॉडल उत्पन्न करता है, और कभी भी पूरी विशिष्टता की वैकल्पिकताओं का सामना नहीं करता। कठिन हिस्सा विवरणों में है — `.lift-ranges` साथी, लेखन-प्रणाली-विशिष्ट पाठ, स्थिर आईडी, और XML एस्केपिंग — और ठीक इन्हीं को नीचे दिए गए चेक पकड़ते हैं। -## Zipped packages +## ज़िप किए गए पैकेज -LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. +LIFT आमतौर पर एक ही `.zip` फ़ाइल के रूप में स्थानांतरित किया जाता है — FieldWorks और The Combine दोनों इसी तरह आयात और निर्यात करते हैं — इसलिए `sil-lift` सीधे ज़िप किए गए पैकेज पढ़ता और लिखता है, चाहे इकोसिस्टम किसी भी लेआउट का उपयोग करे: आर्काइव रूट में फ़ाइलें, या एक शीर्ष-स्तरीय फ़ोल्डर के अंतर्गत नेस्टेड। -- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. -- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. +- **पढ़ें:** `sil_lift.load("package.zip")` एक अस्थायी निर्देशिका में निकालता है, एकल `.lift` को ढूंढता है, और उसे लोड करता है (साथी और मीडिया सामान्य रूप से हल हो जाते हैं)। `validate`, `stats`, `check-media`, और `export` CLI कमांड्स `.zip` पथ भी स्वीकार करते हैं, इसलिए नीचे दिया गया गेट बिना किसी बदलाव के पैकेज पर चलता है। एक्सट्रैक्शन को शत्रुतापूर्ण आर्काइव्स के खिलाफ मजबूत किया गया है — पाथ-ट्रैवर्सल सदस्यों को अस्वीकार कर दिया जाता है, और एंट्री काउंट तथा कुल अनकंप्रेस्ड आकार (10 जीबी) को ज़िप बॉम्ब्स के खिलाफ सीमित किया गया है। +- `Write:` `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` `.lift`, इसके `.lift-ranges`, और सोर्स फ़ोल्डर (media, `WritingSystems/`, `consent/`, ...) की हर दूसरी फ़ाइल को पैकेज करता है। एक ज़िप में `wrap_folder` डिफ़ॉल्ट रूप से ज़िप के नाम पर एक शीर्ष-स्तरीय फ़ोल्डर बनाता है (FieldWorks/Combine आयात कन्वेंशन); फ़्लैट आर्काइव के लिए `False` पास करें। -The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. +`.lift` और `.lift-ranges` पैकेज के भीतर अपनी बाइट-निष्ठा बनाए रखते हैं; ज़िप कंटेनर स्वयं बाइट-पुनरुत्पादन योग्य नहीं है। -## Validate the output as a conformance gate +## आउटपुट को एक अनुपालन गेट के रूप में मान्य करें। -Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. +उत्पादित `.lift` फ़ाइल पर `sil-lift validate` पॉइंट करें। यह RELAX NG चलाता है (`.lift` और इसके `.lift-ranges` साथी दोनों पर) साथ ही ऐसी अर्थपूर्ण जाँचें भी करता है जिन्हें व्याकरण व्यक्त नहीं कर सकता: लटकते `relation`/`variant` संदर्भ, डुप्लिकेट GUIDs, रेंज-एलिमेंट के पैरेंट की अखंडता, उनके रेंज में परिभाषित नहीं किए गए trait और व्याकरण-सूचना मान, और हेडर `range/@href` संदर्भ जो किसी साथी पर हल नहीं होते। -For CI, fail on anything and emit machine-readable findings: +CI के लिए, किसी भी चीज़ में विफल होने पर मशीन-पठनीय निष्कर्ष उत्पन्न करें: ``` sil-lift validate export.lift --strict --no-check-media --format json ``` -- `--strict` makes warnings (not just errors) fail the run. -- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. -- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). -- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. +- `--strict` चेतावनियों (केवल त्रुटियों नहीं) के कारण रन विफल हो जाता है। +- `--no-check-media` फ़ाइलसिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है, जिसकी `missing-media` निष्कर्षों से शोर होता है जब ऑडियो/फ़ोटो फ़ाइलें CI में `.lift` के साथ एक साथ नहीं होती हैं। +- `--format json` मानव-पठनीय टेक्स्ट के बजाय एक एकल JSON ऑब्जेक्ट (`{"problems": [...], "summary": {...}}`) प्रिंट करता है; इसके एग्जिट कोड और स्कीमा एक समर्थित, SemVer-आच्छादित इंटरफ़ेस हैं (देखें [कमांड लाइन गाइड](cli.md))। +- `--require-ids` अतिरिक्त रूप से उन प्रविष्टियों पर त्रुटि दिखाता है जिनमें `guid` नहीं है या उन सेंसों में जिनमें `id` नहीं है — यह तब उपयोगी होता है जब बाद में पुनः-आयात को डुप्लिकेट करने के बजाय अपडेट करना हो। -Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: +मौन डेटा हानि (वह विफलता मोड जो फ्लैट CSV निर्यात को हानिकारक बना देता है) से बचने के लिए अपने स्रोत मॉडल पर `stats --format json` के साथ काउंट्स की पुष्टि करें: ``` sil-lift stats export.lift --format json ``` -It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. +यह `entries`, `senses`, `examples`, `media_refs`, `languages` और प्रत्येक नाम के `traits` की संख्या रिपोर्ट करता है। -### Running the gate without a Python toolchain +### पाइथन टूलचेन के बिना गेट चलाना -A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: +एक TypeScript या C# प्रोजेक्ट का CI, बंडल किए गए GitHub Action के माध्यम से, Python इंस्टॉल किए बिना ही वही जाँच चला सकता है: ```yaml -- uses: sillsdev/python-sil-lift@v0.1.0 - with: - path: export.lift - strict: "true" - no-check-media: "true" - format: json +- उपयोग: sillsdev/python-sil-lift@v0.1.0 + के साथ: + पथ: export.lift + सख्त: "true" + नो-चेक-मीडिया: "true" + प्रारूप: json ``` -or the container image, built from the repo's `Dockerfile`: +या रिपो के `Dockerfile` से बनी कंटेनर इमेज: ``` docker build -t sil-lift . -docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict +docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict ``` -## The `.lift-ranges` companion +## `.lift-ranges` साथी -Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: +नियंत्रित शब्दावलियाँ — शब्द-प्रकार, अर्थगत क्षेत्र, और कोई भी अन्य गुण-आधारित मान-समूह — एक सहोदर `.lift-ranges` फ़ाइल में रहती हैं, जिसे `
` से संदर्भित किया जाता है: ```xml
@@ -69,40 +69,40 @@ Controlled vocabularies — parts of speech, semantic domains, and any other tra
``` -The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: +सहायक प्रत्येक श्रेणी की पूरी परिभाषा वहन करता है। मूल्य `` हैं; `parent` एक पदानुक्रम बनाता है; `label` / `abbrev` / `description` बहुपाठ हैं: ```xml - -
n
+ +
संज्ञा
- +
``` -An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). +तब एक प्रविष्टि आईडी द्वारा एक मान को संदर्भित करती है: एक सेंस का शब्द-प्रकार `` है, और एक सेमांटिक डोमेन `` है। `sil-lift validate` चेतावनी (`undefined-range-value`) देता है जब कोई मान अपनी सीमा में परिभाषित नहीं होता है, और त्रुटि (`range-parent`) देता है जब कोई `parent` सहोदर आईडी नहीं होता — इसलिए अपनी डेटा द्वारा वास्तव में उपयोग की जाने वाली सीमाएँ ही उत्सर्जित करें। यह भी देखें [दायरे और मीडिया](folder-media.md). -If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. +यदि आप पाइथन में एक्सपोर्ट बनाते हैं, तो `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, और `Range.add_element()` साथी (companion) का निर्माण करते हैं और आपके लिए हेडर संदर्भ जोड़ते हैं; `open_writer(..., ranges=...)` स्ट्रीमिंग पथ पर भी यही करता है। -## Text and multitext +## पाठ और बहु-पाठ -Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: +LIFT में प्रत्येक मानव-भाषा स्ट्रिंग एक _मल्टीटेक्स्ट_ है: प्रत्येक लेखन प्रणाली के लिए एक ``, जो प्रत्येक एक `` को लपेटता है: ```xml - kanga -
galinha
+
कंगा
+
मुर्गी
``` -A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. +एक मॉडल जो स्ट्रिंग्स को भाषा कोड के आधार पर मैप करता है (एक `MultiString`, एक `Record`, एक `dict[str, str]`) इस एक-से-एक मैपिंग में बदल जाता है: प्रत्येक कुंजी के लिए एक प्रविष्टि एक `` बन जाती है। एक ही मल्टीटेक्स्ट में प्रति भाषा अधिकतम एक फॉर्म की अनुमति है — अन्यथा `sil-lift` `duplicate-form-lang` चेतावनी देता है। -XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. +XML एस्केपिंग ही एकमात्र वास्तव में शुद्धता-संवेदनशील हिस्सा है। एलिमेंट टेक्स्ट में `&`, `<`, and `>` को एस्केप करना होगा (`&`, `<`, `>`); एट्रिब्यूट मानों में उद्धरण चिह्न को भी। `sil-lift` के लेखक ठीक इन्हीं नियमों का पालन करते हैं और `` के भीतर कभी भी रिक्त स्थान (whitespace) को नहीं बदलते — यह वहाँ कोई इंडेंटेशन नहीं जोड़ता, क्योंकि इससे लेक्सिकल डेटा खराब हो जाएगा। यदि आप इसके आउटपुट से मेल खाने का लक्ष्य रखते हैं, तो एक वास्तविक XML सीरियलाइज़र की एस्केपिंग का पुन: उपयोग करें (स्वयं लिखित प्रतिस्थापन नहीं जो `&` को भूल जाता है) और `` सामग्री को बाइट-दर-बाइट उसी रूप में छोड़ दें जैसा आपके स्रोत में है। From c560811bca07ddc9c38802d5d9e497d8b55d67ff Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:35 -0600 Subject: [PATCH 176/317] New translations lift-export-interop.md (Swahili) [ci skip] --- docs/sw/guides/lift-export-interop.md | 76 +++++++++++++-------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/docs/sw/guides/lift-export-interop.md b/docs/sw/guides/lift-export-interop.md index cf046b5..e25cb89 100644 --- a/docs/sw/guides/lift-export-interop.md +++ b/docs/sw/guides/lift-export-interop.md @@ -1,64 +1,64 @@ -# Producing conformant LIFT +# Kutengeneza LIFT inayokidhi viwango -This guide is for anyone writing a LIFT _exporter_ — code in any language that turns another application's data model into LIFT 0.13. `sil-lift` serves two roles for that work: a conformance gate that checks the output against the schema and the semantics a schema can't express, and a reference for the shapes and text rules the output must follow. +Mwongozo huu ni kwa yeyote anayeandika _exporter_ ya LIFT — msimbo katika lugha yoyote unaobadilisha muundo wa data wa programu nyingine kuwa LIFT 0.13. `sil-lift` ina majukumu mawili katika kazi hiyo: lango la utimilifu linalokagua pato dhidi ya skema na semantiki ambazo skema haiwezi kueleza, na rejea ya maumbo na kanuni za maandishi ambazo pato linapaswa kufuata. -Writing LIFT is much easier than parsing it: an exporter only emits the subset of constructs its own model produces, and never faces the full spec's optionality. The hard part is the details — the `.lift-ranges` companion, per-writing-system text, stable ids, and XML escaping — and those are exactly what the checks below catch. +Kuandika LIFT ni rahisi zaidi kuliko kuchanganua: kiendeshaji cha kusafirisha hutoa tu sehemu ndogo ya miundo ambayo mfano wake wenyewe huzalisha, na kamwe hakikabiliwi na chaguzi zote za kiwango kamili. Sehemu ngumu ni maelezo — `.lift-ranges` companion, maandishi kulingana na mfumo wa uandishi, vitambulisho thabiti, na kuepuka XML — na hayo ndiyo hasa yanayokamatwa na ukaguzi hapa chini. -## Zipped packages +## Vifurushi vilivyosimbwa -LIFT is usually moved around as a single `.zip` — FieldWorks and The Combine both import and export that way — so `sil-lift` reads and writes zipped packages directly, in either layout the ecosystem uses: the files at the archive root, or nested under one top-level folder. +LIFT kawaida huhamishwa kama faili moja ya `.zip` — FieldWorks na The Combine zote huingiza na kusafirisha kwa njia hiyo — hivyo `sil-lift` husoma na kuandika vifurushi vilivyofungwa kwa `zip` moja kwa moja, katika mpangilio wowote ambao mfumo unatumia: faili ziko mizizi ya hifadhi, au zimepangwa ndani ya folda moja kuu. -- **Read:** `sil_lift.load("package.zip")` extracts to a temp directory, locates the single `.lift`, and loads it (companions and media resolve as usual). The `validate`, `stats`, `check-media`, and `export` CLI commands accept a `.zip` path too, so the gate below runs against a package as-is. Extraction is hardened against hostile archives — path-traversal members are refused, and the entry count and total uncompressed size (10 GiB) are capped against zip bombs. -- **Write:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packages the `.lift`, its `.lift-ranges`, and every other file in the source folder (media, `WritingSystems/`, `consent/`, ...) into a zip. `wrap_folder` defaults to a top-level folder named after the zip (the FieldWorks/Combine import convention); pass `False` for a flat archive. +- Soma: `sil_lift.load("package.zip")` hutoa maudhui kwenye saraka ya muda, hupata faili moja la `.lift`, na kulipakia (viendani na vyombo vya habari hutatuliwa kama kawaida). Amri za CLI `validate`, `stats`, `check-media`, na `export` pia zinakubali njia ya `.zip`, hivyo lango hapa chini linafanya kazi dhidi ya kifurushi kama kilivyo. Utoaji umeimarishwa dhidi ya hifadhidata hatari — vipengele vya kupita njia vinakataliwa, na idadi ya kuingia na ukubwa wote bila kubanwa (10 GiB) vimewekewa kikomo dhidi ya mabomu ya zip. +- **Andika:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` hufunga `.lift`, `.lift-ranges` zake, na kila faili nyingine katika folda ya chanzo (media, `WritingSystems/`, `consent/`, ...) katika zipu `wrap_folder` kwa chaguo-msingi huunda folda ya ngazi ya juu inayopewa jina la faili la zip (utaratibu wa kuingiza wa FieldWorks/Combine); toa `False` ili kupata hifadhi tambarare. -The `.lift` and `.lift-ranges` keep their byte-fidelity inside the package; the zip container itself is not byte-reproducible. +`.lift` na `.lift-ranges` huhifadhi uaminifu wa baiti ndani ya kifurushi; chombo cha zip chenyewe hakiruhusu kurejesha baiti kikamilifu. -## Validate the output as a conformance gate +## Thibitisha pato kama lango la utii -Point `sil-lift validate` at the produced `.lift` file. It runs RELAX NG (over both the `.lift` and its `.lift-ranges` companion) plus semantic checks the grammar can't express: dangling `relation`/`variant` references, duplicate GUIDs, range-element parent integrity, trait and grammatical-info values not defined in their range, and header `range/@href` references that resolve to no companion. +Lenga `sil-lift validate` kwenye faili ya `.lift` iliyotengenezwa. Inatekeleza RELAX NG (kupitia `.lift` na mwenza wake `.lift-ranges`) pamoja na ukaguzi wa kisemantiki ambao sarufi haiwezi kueleza: marejeleo ya `relation`/`variant` yasiyo na kiungo, GUID zilizorudiwa, uadilifu wa wazazi wa vipengele vya safu, thamani za sifa na taarifa za kisarufi ambazo hazijaelezwa katika safu zao, na marejeleo ya `range/@href` katika kichwa yanayotatua hadi kwa mwandani asiye na muunganisho. -For CI, fail on anything and emit machine-readable findings: +Kwa CI, shindwa katika chochote na kutoa matokeo yanayosomeka na mashine: ``` sil-lift validate export.lift --strict --no-check-media --format json ``` -- `--strict` makes warnings (not just errors) fail the run. -- `--no-check-media` skips the filesystem media-presence check, whose `missing-media` findings are noise when the audio/photo files aren't colocated with the `.lift` in CI. -- `--format json` prints a single JSON object (`{"problems": [...], "summary": {...}}`) instead of human text; its exit codes and schema are a supported, SemVer-covered interface (see [the command line guide](cli.md)). -- `--require-ids` additionally errors on entries missing a `guid` or senses missing an `id` — useful when a later re-import must update rather than duplicate. +- `--strict` hufanya maonyo (sio tu makosa) kusababisha utekelezaji kushindikana. +- `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili, ambao matokeo yake ya `missing-media` ni kelele tu wakati faili za sauti/picha haziko pamoja na `.lift` katika CI. +- `--format json` huchapisha kitu kimoja cha JSON (`{"problems": [...], "summary": {...}}`) badala ya maandishi ya kawaida; misimbo yake ya kutoka na schema ni kiolesura kinachotumika kinachofunikwa na SemVer (tazama [mwongozo wa mstari wa amri](cli.md)). +- `--require-ids` pia hutoa hitilafu kwa maingizo yanayokosa `guid` au `id` — ni muhimu wakati uingizaji upya wa baadaye unapaswa kusasisha badala ya kurudia. -Guard against silent data loss (the failure mode that makes flat CSV export lossy) by asserting counts with `stats --format json` against your source model: +Jikinga dhidi ya upotevu wa data kimya (mtindo wa kushindwa unaofanya usafirishaji wa CSV wa kawaida upoteze data) kwa kuthibitisha idadi kwa kutumia `stats --format json` dhidi ya mfano wako wa chanzo: ``` -sil-lift stats export.lift --format json +sil-lift takwimu toa.lift --format json ``` -It reports `entries`, `senses`, `examples`, `media_refs`, `languages`, and per-name `traits` counts. +Inaripoti idadi ya `entries`, `senses`, `examples`, `media_refs`, `languages`, na `traits` kwa kila jina. -### Running the gate without a Python toolchain +### Kuendesha lango bila mnyororo wa zana za Python -A TypeScript or C# project's CI can run the same check without installing Python, via the bundled GitHub Action: +CI ya mradi wa TypeScript au C# inaweza kufanya ukaguzi uleule bila kusakinisha Python, kupitia GitHub Action iliyojumuishwa: ```yaml -- uses: sillsdev/python-sil-lift@v0.1.0 - with: - path: export.lift - strict: "true" - no-check-media: "true" +- matumizi: sillsdev/python-sil-lift@v0.1.0 + na: + njia: export.lift + strict: "kweli" + no-check-media: "kweli" format: json ``` -or the container image, built from the repo's `Dockerfile`: +au picha ya kontena, iliyojengwa kutoka kwa `Dockerfile` ya repo: ``` docker build -t sil-lift . docker run --rm -v "$PWD:/work" -w /work sil-lift validate export.lift --strict ``` -## The `.lift-ranges` companion +## Mwandani wa `.lift-ranges` -Controlled vocabularies — parts of speech, semantic domains, and any other trait-keyed value set — live in a sibling `.lift-ranges` file, referenced from the `
`: +Vibainishi vilivyodhibitiwa — aina za maneno, nyanja za maana, na seti nyingine yoyote ya thamani zilizo na ufunguo wa sifa — huishi katika faili ndugu ya `.lift-ranges`, inayorejelewa kutoka kwenye `
`: ```xml
@@ -69,40 +69,40 @@ Controlled vocabularies — parts of speech, semantic domains, and any other tra
``` -The companion carries each range's full definition. Values are ``s; `parent` builds a hierarchy; `label` / `abbrev` / `description` are multitexts: +Kiambatisho kinabeba ufafanuzi kamili wa kila safu. Thamani ni ``; `parent` huunda ngazi; `label` / `abbrev` / `description` ni maandishi mengi: ```xml - +
n
- +
``` -An entry then refers to a value by id: a sense's part of speech is ``, and a semantic domain is ``. `sil-lift validate` warns (`undefined-range-value`) when a value isn't defined in its range and errors (`range-parent`) when a `parent` isn't a sibling id — so emit the ranges your data actually uses. See also [Ranges and media](folder-media.md). +Kisha, kila kipengee kinarejelea thamani kwa kutumia ID: sehemu ya hotuba ya hisia ni ``, na uwanja wa semantiki ni ``. `sil-lift validate` inatoa onyo (`undefined-range-value`) wakati thamani haijafafanuliwa katika upeo wake na makosa (`range-parent`) wakati `parent` si id ya ndugu — kwa hivyo toa upeo ambao data yako inatumia kweli. Tazama pia [Vipimo na vyombo vya habari](folder-media.md). -If you build the export in Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, and `Range.add_element()` construct the companion and add the header references for you; `open_writer(..., ranges=...)` does the same on the streaming path. +Ukijenga toleo la kusafirisha kwa kutumia Python, `Lexicon.add_ranges_file()`, `RangesFile.add_range()`, na `Range.add_element()` huunda kiambatisho na kuongeza marejeleo ya kichwa kwa niaba yako; `open_writer(..., ranges=...)` hufanya vivyo hivyo kwenye njia ya utiririshaji. -## Text and multitext +## Maandishi na maandishi mengi -Every human-language string in LIFT is a _multitext_: one `
` per writing system, each wrapping a ``: +Kila mfululizo wa lugha ya kibinadamu katika LIFT ni _multitext_: `` moja kwa kila mfumo wa uandishi, kila moja ikizunguka ``: ```xml kanga -
galinha
+
kuku
``` -A model that keys strings by language code (a `MultiString`, a `Record`, a `dict[str, str]`) maps onto this one-to-one: one entry per key becomes one `
`. At most one form per language is allowed in a single multitext — `sil-lift` warns `duplicate-form-lang` otherwise. +Mfano unaopanga nyuzi kwa msimbo wa lugha (MultiString, Record, dict[str, str]) unaakisi uwiano wa moja kwa moja: kila kipengee kwa kila ufunguo kinakuwa moja. Kila lugha inaweza kuwa na fomu moja tu katika maandishi mengi — vinginevyo `sil-lift` itatoa onyo la `duplicate-form-lang`. -XML escaping is the one genuinely correctness-sensitive part. In element text, `&`, `<`, and `>` must be escaped (`&`, `<`, `>`); in attribute values, the quote character too. `sil-lift`'s writer applies exactly these rules and never alters whitespace inside `` — it adds no indentation there, because that would corrupt the lexical data. If you aim to match its output, reuse a real XML serializer's escaping (not a hand-rolled replace that forgets `&`) and leave `` content byte-for-byte as your source has it. +Utoaji wa XML ni sehemu pekee inayohitaji usahihi hasa. Katika maandishi ya elementi, `&`, `<`, and `>` lazima ziwekwe kwa alama za kutoroka (`&`, `<`, `>`); katika thamani za sifa, pia alama ya nukuu. Mwandishi wa `sil-lift` hutumia kanuni hizi hasa na kamwe haibadilishi nafasi tupu ndani ya `` — haiongezi nafasi ya kuanzishia hapo, kwa sababu hilo lingeharibu data ya kisemaji. Ikiwa unalenga kuendana na matokeo yake, tumia tena mbinu halisi ya serializer ya XML ya kuepuka alama (sio uingizaji uliofanywa kwa mkono unaosahau `&`) na acha maudhui ya `` byte kwa byte kama chanzo chako kilivyo. From 708ee58f098bbdba056eb2744fd8e1e378fb9a92 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:45 -0600 Subject: [PATCH 177/317] New translations read-edit-write.md (Portuguese) [ci skip] --- docs/pt/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/read-edit-write.md b/docs/pt/guides/read-edit-write.md index 8005f52..58826a6 100644 --- a/docs/pt/guides/read-edit-write.md +++ b/docs/pt/guides/read-edit-write.md @@ -5,7 +5,7 @@ ```python import sil_lift -; lex = sil_lift.load("dictionary.lift") +lex = sil_lift.load("dictionary.lift") ``` A função `load()` aceita qualquer documento LIFT **0.13** bem formado — incluindo ficheiros reais que não estejam em conformidade com o esquema. Tudo o que o modelo não definir (elementos/atributos desconhecidos, comentários) é transportado sem perdas no compartimento opaco `extra` de cada nó. Outras versões do LIFT provocam um `LiftParseError` indicando a versão. From 38f0805bdf4d7fee320aaec9f814544f5468d412 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:47 -0600 Subject: [PATCH 178/317] New translations read-edit-write.md (Chinese Simplified) [ci skip] --- docs/zh/guides/read-edit-write.md | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/zh/guides/read-edit-write.md b/docs/zh/guides/read-edit-write.md index 140f6c0..8298e1e 100644 --- a/docs/zh/guides/read-edit-write.md +++ b/docs/zh/guides/read-edit-write.md @@ -1,6 +1,6 @@ -# Read, edit, write +# 阅读、编辑、撰写 -## Loading +## 正在加载 ```python import sil_lift @@ -8,23 +8,23 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. +`load()` 接受任何格式正确的 LIFT **0.13** 文档——包括那些不符合模式规范的实际文件。 模型未定义的任何内容(未知元素/属性、注释)都会以无损方式保存在每个节点的不透明 `extra` 存储区中。 其他 LIFT 版本会抛出一个名称中包含该版本号的 `LiftParseError` 异常。 -## The model +## 该模型 -Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: +每个 LIFT 元素都是一个带类型的数据类:`Entry`、`Sense`、`Example`、`Pronunciation`、`Variant`、`Relation`、`Etymology`、`Reversal` 等。 多语言文本是一个 `Multitext`,其行为类似于从语言代码到 `Text` 的映射: ```python entry = lex.find(id="abat") str(entry.lexical_unit["seh"]) # "abat" -entry.lexical_unit["en"] = "grove" # plain strings are coerced +entry.lexical_unit["en"] = "grove" # 普通字符串会被强制转换 "en" in entry.citation # False ``` -`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. +`Text` 具有结构化特征——即由 `str` 和 `Span` 片段组成的有序列表——因为 `` 可能包含嵌套的 `` 标记。 `str(text)` 会将其转换为纯文本;这些片段保留了标记,以便进行往返转换。 -Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: +在 LIFT 中,释义是 _Form 类型的_(每个 `` 都承载着自己的语言),因此一个语义具有 `glosses: list[Form]` 以及一个辅助函数: ```python sense = entry.senses[0] @@ -32,16 +32,16 @@ sense.gloss("en") # Text | None entry.gloss_langs() # {"en", "id"} ``` -## Saving +## 保存 ```python -lex.save() # back to where it was loaded from +lex.save() # 保存回原始加载位置 lex.save("elsewhere.lift") ``` -Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. 具体合同条款请参见[富达保证](../fidelity.md)。 +未修改的条目将以**字节完全一致**的方式写回;完全未修改的文档从第一个字节到最后一个字节都与原文档字节完全一致。 具体合同条款请参见[富达保证](../fidelity.md)。 -## Building from scratch +## 从零开始构建 ```python lex = sil_lift.Lexicon(producer="my-script 1.0") @@ -57,10 +57,10 @@ lex.save("new.lift") ## 规范排序 ```python -lex.sort() # entries by (guid, id); ranges/field defs by id/tag -lex.save() # untouched entries keep their exact bytes, in the new order +lex.sort() # 按 (guid, id) 对条目进行排序; 按 id/tag 划分的范围/字段定义 +lex.save() # 未修改的条目保留其精确字节值,并按新顺序排列 -sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +sil_lift.canonicalize("in.lift", "out.lift") # 完全重新序列化,已准备好进行差异比较 ``` -See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). +另请参阅:[示例:批量编辑释义](bulk-edit-glosses.md)。 From 9496de4899ed9375ac034ba978ca5cc3158ee729 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:49 -0600 Subject: [PATCH 179/317] New translations read-edit-write.md (Hindi) [ci skip] --- docs/hi/guides/read-edit-write.md | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/hi/guides/read-edit-write.md b/docs/hi/guides/read-edit-write.md index 74921e9..b0e5a6e 100644 --- a/docs/hi/guides/read-edit-write.md +++ b/docs/hi/guides/read-edit-write.md @@ -1,6 +1,6 @@ -# Read, edit, write +# पढ़ें, संपादित करें, लिखें -## Loading +## लोड हो रहा है ```python import sil_lift @@ -8,23 +8,23 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. +`load()` कोई भी सुव्यवस्थित LIFT **0.13** दस्तावेज़ स्वीकार करता है — जिसमें स्कीमा-अमान्य वास्तविक-विश्व फ़ाइलें भी शामिल हैं। मॉडल द्वारा परिभाषित नहीं की गई कोई भी चीज़ (अज्ञात तत्व/गुणधर्म, टिप्पणियाँ) प्रत्येक नोड के अपारदर्शी `extra` बकेट में बिना किसी हानि के रखी जाती है। अन्य LIFT संस्करण संस्करण का नाम बताते हुए `LiftParseError` उत्पन्न करते हैं। -## The model +## मॉडल -Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: +प्रत्येक LIFT तत्व एक प्रकारित डेटाक्लास है: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, आदि। बहुभाषी पाठ एक `Multitext` है, जो भाषा कोड से `Text` तक एक मैपिंग की तरह व्यवहार करता है: ```python entry = lex.find(id="abat") str(entry.lexical_unit["seh"]) # "abat" -entry.lexical_unit["en"] = "grove" # plain strings are coerced +entry.lexical_unit["en"] = "grove" # साधारण स्ट्रिंग्स को कोअर्स्ड किया जाता है "en" in entry.citation # False ``` -`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. +`Text` संरचित है — `str` और `Span` खंडों की एक क्रमबद्ध सूची — क्योंकि `` में घिरी हुई `` मार्कअप हो सकती है। `str(text)` सादे पाठ में बदल देता है; खंड राउंड-ट्रिपिंग के लिए मार्कअप बनाए रखते हैं। -Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: +LIFT में ग्लॉसेज़ _फॉर्म-आकार के_ होते हैं (प्रत्येक `` अपनी भाषा स्वयं साथ ले चलता है), इसलिए एक सेंस में `glosses: list[Form]` होता है और साथ ही एक हेल्पर भी: ```python sense = entry.senses[0] @@ -32,16 +32,16 @@ sense.gloss("en") # Text | None entry.gloss_langs() # {"en", "id"} ``` -## Saving +## बचत ```python -lex.save() # back to where it was loaded from +lex.save() # उस स्थान पर वापस जहाँ से इसे लोड किया गया था lex.save("elsewhere.lift") ``` -Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. See [Fidelity guarantees](../fidelity.md) for the precise contract. +आपने जिन प्रविष्टियों में कोई बदलाव नहीं किया, वे बाइट-समान रूप से वापस लिखी जाती हैं; एक ऐसा दस्तावेज़ जिसे आपने बिल्कुल भी संशोधित नहीं किया, वह पहले बाइट से लेकर आखिरी बाइट तक बाइट-समान होता है। सटीक अनुबंध के लिए [फिडेलिटी गारंटी](../fidelity.md) देखें। -## Building from scratch +## शुरू से निर्माण ```python lex = sil_lift.Lexicon(producer="my-script 1.0") @@ -54,13 +54,13 @@ lex.entries.append(entry) lex.save("new.lift") ``` -## Canonical sorting +## कैनोनिकल क्रमबद्धकरण ```python -lex.sort() # entries by (guid, id); ranges/field defs by id/tag -lex.save() # untouched entries keep their exact bytes, in the new order +lex.sort() # प्रविष्टियाँ (guid, id) के अनुसार; id/tag द्वारा रेंज/फ़ील्ड परिभाषाएँ +lex.save() # बिना बदले प्रविष्टियाँ अपने सटीक बाइट्स बनाए रखती हैं, नई व्यवस्था में -sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +sil_lift.canonicalize("in.lift", "out.lift") # पूरी तरह से पुनः-सीरियलाइज़्ड, diff-तैयार ``` -See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). +यह भी देखें: [कार्य-उदाहरण: ग्लॉसेज़ के थोक-संपादन](bulk-edit-glosses.md)। From 3367120d50839dcd9fb81038eedce814c2f0acb4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:51 -0600 Subject: [PATCH 180/317] New translations read-edit-write.md (Swahili) [ci skip] --- docs/sw/guides/read-edit-write.md | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/sw/guides/read-edit-write.md b/docs/sw/guides/read-edit-write.md index 74921e9..5bbb5d6 100644 --- a/docs/sw/guides/read-edit-write.md +++ b/docs/sw/guides/read-edit-write.md @@ -1,6 +1,6 @@ -# Read, edit, write +# Soma, hariri, andika -## Loading +## Inapakia ```python import sil_lift @@ -8,23 +8,23 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` accepts any well-formed LIFT **0.13** document — including schema-invalid real-world files. Anything the model doesn't define (unknown elements/attributes, comments) is carried losslessly in each node's opaque `extra` bucket. Other LIFT versions raise `LiftParseError` naming the version. +`load()` hukubali hati yoyote ya LIFT **0.13** iliyopangwa vizuri — ikiwa ni pamoja na faili halisi zisizoendana na skema. Chochote ambacho mfano haujatambua (vipengele/sifa zisizojulikana, maoni) huhifadhiwa bila kupoteza katika kikapu kisichoeleweka cha `extra` cha kila node. Toleo zingine za LIFT hutoa `LiftParseError` ikitaja toleo. -## The model +## Mfano -Every LIFT element is a typed dataclass: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, and so on. Multilingual text is a `Multitext`, which behaves like a mapping from language code to `Text`: +Kila kipengele cha LIFT ni dataclass iliyotengwa aina: `Entry`, `Sense`, `Example`, `Pronunciation`, `Variant`, `Relation`, `Etymology`, `Reversal`, na kadhalika. Maandishi ya lugha nyingi ni `Multitext`, ambayo hufanya kazi kama uhusiano kutoka kwa msimbo wa lugha hadi `Text`: ```python entry = lex.find(id="abat") str(entry.lexical_unit["seh"]) # "abat" -entry.lexical_unit["en"] = "grove" # plain strings are coerced -"en" in entry.citation # False +entry.lexical_unit["en"] = "grove" # nyuzi rahisi zinageuzwa +"en" in entry.citation # Si kweli ``` -`Text` is structured — an ordered list of `str` and `Span` fragments — because `` can contain nested `` markup. `str(text)` flattens to plain text; the fragments keep the markup for round-tripping. +`Text` imepangwa — orodha iliyopangwa ya vipande vya `str` na `Span` — kwa sababu `` inaweza kuwa na markup ya `` iliyojificha ndani yake. `str(text)` inageuza kuwa maandishi ya kawaida; vipande vinabaki na alama za uandishi ili kuruhusu kurudi nyuma. -Glosses are _form-shaped_ in LIFT (each `` carries its own language), so a sense has `glosses: list[Form]` plus a helper: +Glosses ni _form-shaped_ katika LIFT (kila `` lina lugha yake mwenyewe), hivyo sense ina `glosses: list[Form]` pamoja na kisaidizi: ```python sense = entry.senses[0] @@ -32,16 +32,16 @@ sense.gloss("en") # Text | None entry.gloss_langs() # {"en", "id"} ``` -## Saving +## Akiba ```python -lex.save() # back to where it was loaded from +lex.save() # kurudi mahali ilipopakiwa kutoka lex.save("elsewhere.lift") ``` -Entries you didn't modify are written back **byte-identical**; a document you didn't modify at all is byte-identical from the first byte to the last. See [Fidelity guarantees](../fidelity.md) for the precise contract. +Maingizo ambayo hukuyabadilisha yamerudishwa **sawa kwa baiti**; hati ambayo hukuyabadilisha kabisa ni sawa kwa baiti kuanzia baiti ya kwanza hadi ya mwisho. Tazama [Dhamana za Fidelity](../fidelity.md) kwa mkataba sahihi. -## Building from scratch +## Kujenga kutoka mwanzo ```python lex = sil_lift.Lexicon(producer="my-script 1.0") @@ -54,13 +54,13 @@ lex.entries.append(entry) lex.save("new.lift") ``` -## Canonical sorting +## Upangaji rasmi ```python -lex.sort() # entries by (guid, id); ranges/field defs by id/tag -lex.save() # untouched entries keep their exact bytes, in the new order +lex.sort() # maingizo kwa (guid, id); vipimo/ufafanuzi wa uwanja kwa id/tag +lex.save() # maingizo yasiyoguswa yanabaki na baiti zao halisi, katika mpangilio mpya -sil_lift.canonicalize("in.lift", "out.lift") # fully re-serialized, diff-ready +sil_lift.canonicalize("in.lift", "out.lift") # imepangwa tena kikamilifu, tayari kwa tofauti ``` -See also: [Worked example: bulk-editing glosses](bulk-edit-glosses.md). +Tazama pia: [Mfano uliofanyiwa kazi: kuhariri kwa wingi tafsiri fupi](bulk-edit-glosses.md). From e7cd2d3e5c1e3aab4156bc5ac84f39d9257ba7e4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:56 -0600 Subject: [PATCH 181/317] New translations validate.md (Hindi) [ci skip] --- docs/hi/guides/validate.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/hi/guides/validate.md b/docs/hi/guides/validate.md index 718c402..04f26b6 100644 --- a/docs/hi/guides/validate.md +++ b/docs/hi/guides/validate.md @@ -1,36 +1,36 @@ -# Validate +# सत्यापित करें -Validation is always explicit — loading and saving never validate implicitly. +प्रमाणीकरण हमेशा स्पष्ट होता है — लोडिंग और सेविंग कभी भी निहित रूप से प्रमाणीकरण नहीं करते। ```python import sil_lift -# Exhaustive: a lazy stream of Problems (schema + semantic layers). +# Exhaustive: समस्याओं की एक लेज़ी स्ट्रीम (स्कीमा + सेमंटिक लेयर्स). for problem in sil_lift.iter_problems("dictionary.lift"): print(problem) # error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches ... -# Fail-fast: raises LiftValidationError on the first error-level problem. +# Fail-fast: पहली त्रुटि-स्तर की समस्या पर LiftValidationError उठाता है। sil_lift.validate_file("dictionary.lift") -# In-memory state (serializes first — a documented cost on large lexicons): +# इन-मेमोरी स्थिति (पहले सीरियलाइज़ होती है — बड़े शब्दकोशों पर एक दस्तावेजीकृत लागत): lex = sil_lift.load("dictionary.lift") problems = list(lex.iter_problems()) ``` -Each `Problem` carries `level` (`"error"`/`"warning"`), a stable `code`, `message`, and an address: `file`, `entry_id`, `guid`, `line`. +प्रत्येक `Problem` में `level` (`"error"`/`"warning"`), एक स्थिर `code`, `message`, और एक पता होता है: `file`, `entry_id`, `guid`, `line`. -## The layers +## परतें -1. **RELAX NG** against the LIFT 0.13 grammar (vendored from lift-standard). -2. **Ranges schema** — this project's `lift-ranges-0.13.rng` — over every tracked `.lift-ranges` companion. -3. **Semantic checks** the grammar cannot express: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. +1. LIFT 0.13 व्याकरण (lift-standard से विक्रेता) के विरुद्ध RELAX NG। +2. **रेंज स्कीमा** — इस प्रोजेक्ट का `lift-ranges-0.13.rng` — प्रत्येक ट्रैक किए गए `.lift-ranges` साथी पर। +3. **सेमांटिक जाँचें** जिन्हें व्याकरण व्यक्त नहीं कर सकता: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`। -## Real-world FieldWorks (FLEx) output +## वास्तविक-विश्व फील्डवर्क्स (FLEx) आउटपुट -FieldWorks systematically writes some content that strict tooling rejects. Here is sil-lift's policy, so that real lexicons validate usefully: +FieldWorks व्यवस्थित रूप से कुछ सामग्री लिखता है जिसे सख्त टूलिंग अस्वीकार कर देती है। यहाँ sil-lift की नीति है, ताकि वास्तविक शब्दकोश उपयोगी रूप से मान्य हों: -- `file://C:/...` hrefs (invalid URIs) are reported as **warnings** (`uri-not-rfc`), not schema errors — the C# validator never rejected them. -- Legally interleaved children (e.g. `field, note, field, note` in a sense) are **not** flagged, working around a false positive in libxml2. -- Range values are compared under Unicode NFC normalization — FLEx writes the `.lift` in NFC but the `.lift-ranges` in NFD within the same export. -- FLEx's `trait`/`field` extensions inside `range-element` **are** reported (schema errors against the ranges schema): they are genuine spec deviations. +- `file://C:/...` hrefs (अमान्य URI) को स्कीमा त्रुटियों के रूप में नहीं, बल्कि **चेतावनियाँ** (`uri-not-rfc`) के रूप में रिपोर्ट किया जाता है — C# वैलिडेटर ने उन्हें कभी अस्वीकार नहीं किया। +- कानूनी रूप से इंटरलीव किए गए चाइल्ड एलिमेंट्स (उदाहरण के लिए, एक तरह से `field, note, field, note`) को **फ्लैग नहीं** किया जाता है, जो libxml2 में एक फॉलस पॉजिटिव से बचने का काम करता है। +- रेंज मानों की तुलना यूनिकोड NFC सामान्यीकरण के तहत की जाती है — FLEx एक ही एक्सपोर्ट में `.lift` को NFC में और `.lift-ranges` को NFD में लिखता है। +- FLEx के `trait`/`field` एक्सटेंशन `range-element` के अंदर रिपोर्ट किए जाते हैं (रेंज स्कीमा के खिलाफ स्कीमा त्रुटियाँ): ये वास्तव में विनिर्देश से विचलन हैं। From 29a769fb9ebc7abb675a4058b1812292581d87ec Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:24:58 -0600 Subject: [PATCH 182/317] New translations validate.md (Swahili) [ci skip] --- docs/sw/guides/validate.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/sw/guides/validate.md b/docs/sw/guides/validate.md index 718c402..6357ffe 100644 --- a/docs/sw/guides/validate.md +++ b/docs/sw/guides/validate.md @@ -1,36 +1,36 @@ -# Validate +# Thibitisha -Validation is always explicit — loading and saving never validate implicitly. +Uthibitishaji daima ni wazi — kupakia na kuhifadhi kamwe havithibitishi kwa njia fiche. ```python import sil_lift -# Exhaustive: a lazy stream of Problems (schema + semantic layers). +# Exhaustive: mtiririko wa vigezo (schema + tabaka za semantiki). for problem in sil_lift.iter_problems("dictionary.lift"): print(problem) - # error [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' matches ... + # kosa [dangling-ref] dictionary.lift:88 (entry apu): ref 'nope' inalingana ... -# Fail-fast: raises LiftValidationError on the first error-level problem. +# Fail-fast: inasababisha LiftValidationError kwenye tatizo la kwanza la kiwango cha kosa. sil_lift.validate_file("dictionary.lift") -# In-memory state (serializes first — a documented cost on large lexicons): +# Hali ya kumbukumbu (inayosafirishwa kwanza — gharama iliyoorodheshwa kwa kamusi kubwa): lex = sil_lift.load("dictionary.lift") problems = list(lex.iter_problems()) ``` -Each `Problem` carries `level` (`"error"`/`"warning"`), a stable `code`, `message`, and an address: `file`, `entry_id`, `guid`, `line`. +Kila `Problem` ina `level` (`"error"`/`"warning"`), `code` thabiti, `message`, na anwani: `file`, `entry_id`, `guid`, `line`. -## The layers +## Tabaka -1. **RELAX NG** against the LIFT 0.13 grammar (vendored from lift-standard). -2. **Ranges schema** — this project's `lift-ranges-0.13.rng` — over every tracked `.lift-ranges` companion. -3. **Semantic checks** the grammar cannot express: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. +1. **RELAX NG** dhidi ya sarufi ya LIFT 0.13 (iliyotolewa na lift-standard). +2. **Rangi za schema** — `lift-ranges-0.13.rng` ya mradi huu — juu ya kila kiambatisho cha `.lift-ranges` kinachofuatiliwa. +3. **Ukaguzi wa semantiki** ambao sarufi haiwezi kuonyesha: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. -## Real-world FieldWorks (FLEx) output +## Matokeo halisi ya FieldWorks (FLEx) -FieldWorks systematically writes some content that strict tooling rejects. Here is sil-lift's policy, so that real lexicons validate usefully: +FieldWorks kwa utaratibu huandika baadhi ya maudhui ambayo zana kali hupinga. Hapa kuna sera ya sil-lift, ili kamusi halisi ziwe na manufaa: -- `file://C:/...` hrefs (invalid URIs) are reported as **warnings** (`uri-not-rfc`), not schema errors — the C# validator never rejected them. -- Legally interleaved children (e.g. `field, note, field, note` in a sense) are **not** flagged, working around a false positive in libxml2. -- Range values are compared under Unicode NFC normalization — FLEx writes the `.lift` in NFC but the `.lift-ranges` in NFD within the same export. -- FLEx's `trait`/`field` extensions inside `range-element` **are** reported (schema errors against the ranges schema): they are genuine spec deviations. +- Viungo vya `file://C:/...` (URI zisizofaa) huripotiwa kama **maonyo** (`uri-not-rfc`), si makosa ya skema — mhakiki wa C# haujawahi kuzikataa. +- Watoto waliopangwa kisheria (kwa mfano `field, note, field, note`) hawapati alama, hivyo kuepuka matokeo ya uongo chanya katika libxml2. +- Thamani za masafa zinalinganishwa chini ya usawa wa Unicode NFC — FLEx huandika `.lift` katika NFC lakini `.lift-ranges` katika NFD ndani ya usafirishaji uleule. +- Nyongeza za `trait`/`field` za FLEx ndani ya `range-element` zinaripotiwa (makosa ya schema dhidi ya schema ya rangi): ni upotovu halisi wa vipimo. From 84526049e243f085bd8152fb0604d4f60d9e5b41 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:00 -0600 Subject: [PATCH 183/317] New translations index.md (French) [ci skip] --- docs/fr/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/index.md b/docs/fr/index.md index a65b0bc..4bea817 100644 --- a/docs/fr/index.md +++ b/docs/fr/index.md @@ -1,6 +1,6 @@ # sil-lift -Bibliothèque Python pour [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13 : lecture/écriture sans perte du dossier LIFT (`.lift` + `.lift-ranges` + références multimédias), validation du schéma et de la sémantique, et tri canonique — avec des API de streaming pour les grands lexiques. +Une bibliothèque Python pour [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13 : lecture/écriture sans perte du dossier LIFT (`.lift` + `.lift-ranges` + références multimédias), validation du schéma et de la sémantique, et tri canonique — avec des API de streaming pour les grands lexiques. **Statut : version préliminaire, en cours de développement.** From e042fe986636c37794505a9dc7b047d0fd2bd1f5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:01 -0600 Subject: [PATCH 184/317] New translations index.md (Spanish) [ci skip] --- docs/es/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/index.md b/docs/es/index.md index 1703f92..50678f9 100644 --- a/docs/es/index.md +++ b/docs/es/index.md @@ -1,6 +1,6 @@ # sil-lift -Una biblioteca de Python para [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: lectura y escritura sin pérdidas de la carpeta LIFT (`.lift` + `.lift-ranges` + referencias a medios), validación del esquema y semántica, y ordenación canónica, con API de streaming para léxicos de gran tamaño. +Una biblioteca de Python para [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: lectura y escritura sin pérdidas de la carpeta LIFT (`.lift` + `.lift-ranges` + referencias a medios), validación semántica y del esquema, y ordenación canónica, con API de streaming para léxicos de gran tamaño. **Estado: versión preliminar, en fase de desarrollo activo.** From 5a30a3b03495d766a7f1657ee9282b30fa4c0fcd Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:03 -0600 Subject: [PATCH 185/317] New translations reference.md (French) [ci skip] --- docs/fr/reference.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/fr/reference.md b/docs/fr/reference.md index 58b2986..1964b24 100644 --- a/docs/fr/reference.md +++ b/docs/fr/reference.md @@ -3,7 +3,7 @@ L'API publique correspond exactement à ce que `sil_lift` réexporte au niveau supérieur ; les modules préfixés par un trait de soulignement relèvent des détails d'implémentation. ::: sil_lift -options : -show_root_heading : false -show_source : false -members_order : source +options: +show_root_heading: false +show_source: false +members_order: source From 20db25766218b02edb6a4b9695c732f594e4ab20 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:05 -0600 Subject: [PATCH 186/317] New translations reference.md (Spanish) [ci skip] --- docs/es/reference.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/es/reference.md b/docs/es/reference.md index bf824cb..05ea450 100644 --- a/docs/es/reference.md +++ b/docs/es/reference.md @@ -3,7 +3,7 @@ La API pública es exactamente lo que `sil_lift` reexporta en el nivel superior; los módulos con el prefijo «_» son detalles de implementación. ::: sil_lift -opciones: -mostrar_título_raíz: false -mostrar_fuente: false -orden_miembros: fuente +options: +show_root_heading: false +show_source: false +members_order: source From 66c6cffa2b33a899b3d266639c54d568ef57556f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:06 -0600 Subject: [PATCH 187/317] New translations index.md (Arabic) [ci skip] --- docs/ar/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/index.md b/docs/ar/index.md index 9792499..5a1bd6a 100644 --- a/docs/ar/index.md +++ b/docs/ar/index.md @@ -1,6 +1,6 @@ # سيل-ليفت -مكتبة لغة بايثون لـ [LIFT](https://github.com/sillsdev/lift-standard) (تنسيق تبادل المعاجم) الإصدار 0.13: قراءة وكتابة ملفات مجلد LIFT دون فقدان البيانات (`.lift` + `.lift-ranges` + مراجع الوسائط)، والتحقق من صحة المخطط الدلالي والمعاني، والفرز القياسي — مع واجهات برمجة تطبيقات (API) للتدفق المباشر للمعاجم الكبيرة. +مكتبة Python لـ [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: قراءة/كتابة بدون فقدان البيانات لمجلد LIFT (`.lift` + `.lift-ranges` + مراجع الوسائط)، والتحقق من صحة المخطط والسمات الدلالية، والفرز القياسي — مع واجهات برمجة تطبيقات (APIs) للتدفق المباشر للمعاجم الكبيرة. **الحالة: إصدار تجريبي، قيد التطوير النشط.** From e3b952a11f1da4cf13b83b36b64cb78e6bfaf2bf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:08 -0600 Subject: [PATCH 188/317] New translations index.md (German) [ci skip] --- docs/de/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/index.md b/docs/de/index.md index c6e3649..c6ec627 100644 --- a/docs/de/index.md +++ b/docs/de/index.md @@ -1,6 +1,6 @@ # sil-lift -Eine Python-Bibliothek für [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: verlustfreies Lesen und Schreiben des LIFT-Ordners (`.lift` + `.lift-ranges` + Medienverweise), Schema- und semantische Validierung sowie kanonische Sortierung – mit Streaming-APIs für große Lexika. +Eine Python-Bibliothek für [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: verlustfreies Lesen und Schreiben des LIFT-Ordners (`.lift` + `.lift-ranges` + Medienverweise), Schema- und semantische Validierung sowie kanonische Sortierung – mit Streaming-APIs für große Lexika. **Status: Vorabversion, befindet sich in aktiver Entwicklung.** From 543881072d28f31d0ca16278642a085580761cf3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:10 -0600 Subject: [PATCH 189/317] New translations index.md (Japanese) [ci skip] --- docs/ja/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/index.md b/docs/ja/index.md index baadab1..708a57a 100644 --- a/docs/ja/index.md +++ b/docs/ja/index.md @@ -1,6 +1,6 @@ # シルリフト -[LIFT](https://github.com/sillsdev/lift-standard)(Lexicon Interchange Format)0.13 用の Python ライブラリ:LIFT フォルダ(`.lift` + `.lift-ranges` + メディア参照)のロスレスな読み書き、スキーマおよびセマンティック検証、正規ソート機能に加え、大規模な辞書向けのストリーミング API を備えています。 +[LIFT](https://github.com/sillsdev/lift-standard) 用の Python ライブラリ (Lexicon Interchange FormaT) 0.13: LIFTフォルダ(`.lift` + `.lift-ranges` + メディア参照)のロスレスな読み書き、スキーマおよびセマンティック検証、正規ソート機能 — 大規模なレキシコン向けのストリーミングAPIを搭載。 **ステータス:プレリリース版、現在開発中。** From 47d0d4d48c17752c5ba32e4509f931ccbecacdcd Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:12 -0600 Subject: [PATCH 190/317] New translations index.md (Portuguese) [ci skip] --- docs/pt/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/index.md b/docs/pt/index.md index e4c922d..8620e4d 100644 --- a/docs/pt/index.md +++ b/docs/pt/index.md @@ -1,6 +1,6 @@ # sil-lift -Uma biblioteca Python para o [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: leitura e escrita sem perdas da pasta LIFT (`.lift` + `.lift-ranges` + referências de meios), validação do esquema e semântica, e ordenação canónica — com APIs de streaming para léxicos de grande dimensão. +Uma biblioteca Python para o [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: leitura e gravação sem perdas da pasta LIFT (`.lift` + `.lift-ranges` + referências de multimédia), validação do esquema e semântica, e ordenação canónica — com APIs de streaming para léxicos de grande dimensão. **Estado: pré-lançamento, em desenvolvimento ativo.** From 3f59214f7e8fc315c35429c629b21bb24924d1e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:13 -0600 Subject: [PATCH 191/317] New translations index.md (Russian) [ci skip] --- docs/ru/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/index.md b/docs/ru/index.md index a7e851a..4a0984b 100644 --- a/docs/ru/index.md +++ b/docs/ru/index.md @@ -1,6 +1,6 @@ # sil-lift -Библиотека Python для [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) версии 0.13: чтение и запись папки LIFT без потерь (файлы `.lift`, `.lift-ranges` и ссылки на медиафайлы), проверка соответствия схеме и семантике, а также каноническая сортировка — с потоковыми API для больших лексиконов. +Библиотека на языке Python для [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: чтение и запись папки LIFT без потерь (`.lift` + `.lift-ranges` + ссылки на медиафайлы), проверка схемы и семантики, а также каноническая сортировка — с потоковыми API для больших лексиконов. **Статус: предварительная версия, ведётся активная разработка.** From be138c2132dc0c5df98ddb90ec4e880f851d2340 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:15 -0600 Subject: [PATCH 192/317] New translations index.md (Chinese Simplified) [ci skip] --- docs/zh/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/index.md b/docs/zh/index.md index a907a75..1a651c7 100644 --- a/docs/zh/index.md +++ b/docs/zh/index.md @@ -1,6 +1,6 @@ # sil-lift -一个用于 [LIFT](https://github.com/sillsdev/lift-standard)(词汇表交换格式)0.13 的 Python 库:支持 LIFT 文件夹(`.lift` + `.lift-ranges` + 媒体引用)的无损读写、模式和语义验证,以及规范排序——并为大型词汇表提供了流式 API。 +一个用于 [LIFT](https://github.com/sillsdev/lift-standard) 的 Python 库 (词典交换格式) 0.13:支持 LIFT 文件夹(`.lift` + `.lift-ranges` + 媒体引用)的无损读写、模式和语义验证以及规范排序——并为大型词典提供了流式 API。 **状态:预发布版,正在积极开发中。** From 5eff92a7cf116e63f278e739e836bc319ae1e4bd Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:16 -0600 Subject: [PATCH 193/317] New translations index.md (Hindi) [ci skip] --- docs/hi/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/index.md b/docs/hi/index.md index c30b999..3abd5c7 100644 --- a/docs/hi/index.md +++ b/docs/hi/index.md @@ -1,6 +1,6 @@ # सिल-लिफ्ट -[LIFT](https://github.com/sillsdev/lift-standard) (लेक्सिकन इंटरचेंज फॉर्मेट) 0.13 के लिए एक पाइथन लाइब्रेरी: LIFT फ़ोल्डर (`.lift` + `.lift-ranges` + मीडिया संदर्भ) का बिना हानि के रीड/राइट, स्कीमा और सेमांटिक सत्यापन, तथा कैनोनिकल सॉर्टिंग — बड़े लेक्सिकन के लिए स्ट्रीमिंग एपीआई के साथ। +[LIFT](https://github.com/sillsdev/lift-standard) के लिए एक पाइथन लाइब्रेरी (लेक्सिकन इंटरचेंज फॉर्मैट) 0.13: LIFT फ़ोल्डर (`.lift` + `.lift-ranges` + मीडिया संदर्भ) का बिना हानि के रीड/राइट, स्कीमा और सेमांटिक सत्यापन, तथा मानक क्रमबद्धकरण — बड़े शब्दकोशों के लिए स्ट्रीमिंग एपीआई के साथ। स्थिति: प्री-रिलीज़, सक्रिय विकास के अधीन। From 03f4f05992f747a9a89c0f984e399d80001bb366 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:18 -0600 Subject: [PATCH 194/317] New translations index.md (Swahili) [ci skip] --- docs/sw/index.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/sw/index.md b/docs/sw/index.md index e6e9923..a1f114e 100644 --- a/docs/sw/index.md +++ b/docs/sw/index.md @@ -1,32 +1,32 @@ # sil-lift -A Python library for [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange Format) 0.13: lossless read/write of the LIFT folder (`.lift` + `.lift-ranges` + media references), schema and semantic validation, and canonical sorting — with streaming APIs for large lexicons. +Maktaba ya Python kwa [LIFT](https://github.com/sillsdev/lift-standard) (Lexicon Interchange FormaT) 0.13: kusoma/kuandika bila kupoteza data ya folda ya LIFT (`.lift` + `.lift-ranges` + marejeleo ya media), uthibitishaji wa schema na semantiki, na upangaji sahihi — na API za mtiririko kwa kamusi kubwa. -**Status: pre-release, under active development.** +Hali: kabla ya kutolewa, inatengenezwa. -## Install +## Sakinisha -From [PyPI](https://pypi.org/project/sil-lift/): +Kutoka [PyPI](https://pypi.org/project/sil-lift/): ``` -pip install sil-lift # library + the sil-lift command +pip install sil-lift # maktaba + amri ya sil-lift ``` -Requires Python 3.11+. The only runtime dependency is lxml. +Inahitaji Python 3.11 na zaidi. Utegemezi pekee wakati wa utekelezaji ni lxml. -## The 30-second tour +## Ziara ya sekunde 30 ```python import sil_lift -lex = sil_lift.load("thesaurus.lift") # tracks .lift-ranges companions too +lex = sil_lift.load("thesaurus.lift") # inafuatilia .lift-ranges na wenza pia for entry in lex.entries: if "en" not in entry.gloss_langs(): print(entry.id, str(entry.lexical_unit.get("seh") or "")) -entry = lex.find(guid="0f5a9c3e-...") # or lex.find(id="hoofd_a1b2") +entry = lex.find(guid="0f5a9c3e-...") # au lex.find(id="hoofd_a1b2") entry.senses[0].definition["en"] = "head (anatomy)" -lex.save() # untouched entries byte-identical; edited entry re-serialized +lex.save() # entries zisizoguswa ni sawa kwa baiti; entry iliyohaririwa imehifadhiwa tena ``` From a0629a137cbb437f5e156f6a8191b49b125df99c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:23 -0600 Subject: [PATCH 195/317] New translations reference.md (Chinese Simplified) [ci skip] --- docs/zh/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/reference.md b/docs/zh/reference.md index f1151a4..66ff4fb 100644 --- a/docs/zh/reference.md +++ b/docs/zh/reference.md @@ -3,7 +3,7 @@ 公共 API 正是 `sil_lift` 在顶层重新导出的内容;以下划线为前缀的模块属于实现细节。 ::: sil_lift -选项: +options: show_root_heading: false show_source: false members_order: source From 36173868ee7f49944fd850dd9903f03822a1888c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:25 -0600 Subject: [PATCH 196/317] New translations reference.md (Hindi) [ci skip] --- docs/hi/reference.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/hi/reference.md b/docs/hi/reference.md index b49e3d8..7add820 100644 --- a/docs/hi/reference.md +++ b/docs/hi/reference.md @@ -3,7 +3,7 @@ सार्वजनिक एपीआई बिल्कुल वही है जिसे `sil_lift` शीर्ष स्तर पर पुनः निर्यात करता है; अंडरस्कोर-पूर्वप्रत्यय वाले मॉड्यूल कार्यान्वयन विवरण हैं। ::: sil_lift -विकल्प: +options: show_root_heading: false show_source: false -सदस्यों_क्रम: स्रोत +members_order: source From d3c7ae76c7a2f0d91abe672ea90a95349320d57e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 29 Jul 2026 11:25:27 -0600 Subject: [PATCH 197/317] New translations reference.md (Swahili) [ci skip] --- docs/sw/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/reference.md b/docs/sw/reference.md index 445d00a..b41d4b5 100644 --- a/docs/sw/reference.md +++ b/docs/sw/reference.md @@ -3,7 +3,7 @@ API ya umma ni hasa kile `sil_lift` inachore-eksporti katika ngazi ya juu; moduli zilizo na viambishi awali vya 'underscore' ni maelezo ya utekelezaji. ::: sil_lift -chaguzi: +options: show_root_heading: false show_source: false members_order: source From 1c5559ad348dda2b57132e761a01ea8e01817cca Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:05 -0600 Subject: [PATCH 198/317] New translations bulk-edit-glosses.md (French) [ci skip] --- docs/fr/guides/bulk-edit-glosses.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/fr/guides/bulk-edit-glosses.md b/docs/fr/guides/bulk-edit-glosses.md index 2b5b683..bb43fa0 100644 --- a/docs/fr/guides/bulk-edit-glosses.md +++ b/docs/fr/guides/bulk-edit-glosses.md @@ -21,7 +21,6 @@ def iter_senses(senses): edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -30,25 +29,35 @@ for entry in lex.entries: continue old = str(gloss.text) new = old.replace("colour", "color") - if new != old: + if new != old : gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] -if errors: +if errors : for problem in errors: print(problem) - sys.exit(f"Interruption : {len(errors)} erreur(s) de validation, rien n'a été enregistré") + sys.exit(f"interruption : {len(errors)} erreur(s) de validation, rien n'a été enregistré") lex.save() -print(f" {edited_glosses} s de glosses modifiés sur {len(touched_entries)} entrée(s)"") +print(f" {edited_glosses} glossaire(s) modifié(s) sur {len(changed)} entrée(s)") ``` Quelques points à retenir : - `Sense.subsenses` est lui-même une `list[Sense]` ; ainsi, `iter_senses` effectue une itération récursive sur cet élément — une modification groupée qui ne parcourrait que `entry.senses` omettrait sans avertissement tout glossaire imbriqué sous un sens secondaire. - `gloss.text` est un objet `Text`, et non une simple chaîne de caractères : `str(gloss.text)` l'aplatit pour permettre la correspondance, et le remplacement est réécrit à l'aide de `sil_lift.Text([new])` plutôt que de modifier la chaîne en place. +- La fonction `lex.changed_entries()` indique quelles entrées diffèrent du fichier tel qu'il a été chargé. Étant donné que le résumé d'une entrée couvre l'ensemble de sa sous-arborescence, toute modification apportée à une sous-signification imbriquée se répercute sur l'entrée qui la contient. + - Comme il compare du contenu sérialisé, le fait d'attribuer à un champ la valeur qu'il avait déjà n'est pas signalé. + - Elle ne signale que les modifications de contenu ; les fonctions `lex.added_entries()` et `lex.removed_entries()` concernent les entrées qui sont apparues ou ont disparu depuis le chargement. + - Elle renvoie les entrées elles-mêmes, sans tenir compte du fait que l'`id` puisse être dupliqué ou absent (ce que permet LIFT). + - En tant que chiffre, il n'a de sens que s'il existe un élément de comparaison. Lorsque la couche de transit refuse d'effectuer un balayage octet par octet de la source — en raison d'un encodage non compatible ASCII ou d'un désaccord entre le scanner et l'analyseur —, il n'y a pas de référence, et la fonction `changed_entries()` signale _toutes_ les entrées. C'est la réponse honnête concernant la protection en écriture, puisque `save()` resérialise l'intégralité du fichier dans ce cas, mais cela signifie que le nombre correspond à la taille du lexique plutôt qu'à celle de la modification. +- La fonction `lex.changes()` indique si le document a subi la moindre modification. Cela concerne non seulement les entrées, mais aussi l'en-tête, l'élément racine et tous les éléments associés à `.lift-ranges`. + - Cette condition n'est fausse que lorsque la fonction `save()` reproduirait les octets source, ce qui fait que `if not lex.changes(): ...` est la bonne façon d'éviter une écriture inutile. Cette garantie fonctionne dans un seul sens : elle ne signale jamais « rien à écrire » pour un document qui serait réécrit, tandis qu'une modification imposant une resérialisation complète peut aboutir aux mêmes octets d'origine et être tout de même signalée. + - Comme cette fonction compare le contenu et non la destination, utilisez-la uniquement pour enregistrer le document à l'emplacement actuel : `lex.save(some_other_dir / "dictionary.lift")` écrit le document et ses fichiers associés dans un emplacement encore vide, qu'il y ait eu des modifications ou non. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - La validation en mémoire (`lex.iter_problems()`) sérialise d'abord l'état modifié, ce qui permet de s'assurer qu'il reflète correctement les modifications avant que quoi que ce soit ne soit écrit sur le disque. L'interruption en cas de `Problem` de niveau « erreur » — les avertissements sont laissés à l'appréciation de l'appelant — garantit qu'une modification incorrecte n'atteindra jamais la fonction `save()`. Les gloss ne sont pas les seuls produits qui méritent d'être appliqués de cette manière. La même surface de mappage `Multitext` s'applique aux définitions et à tous les autres champs multilingues d'une entrée ou d'un sens : From 46d2902d764690fba641a19bf1a8d35ed66c17e7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:07 -0600 Subject: [PATCH 199/317] New translations bulk-edit-glosses.md (Spanish) [ci skip] --- docs/es/guides/bulk-edit-glosses.md | 31 +++++++++++++++++++---------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/docs/es/guides/bulk-edit-glosses.md b/docs/es/guides/bulk-edit-glosses.md index 331746f..182b509 100644 --- a/docs/es/guides/bulk-edit-glosses.md +++ b/docs/es/guides/bulk-edit-glosses.md @@ -21,34 +21,43 @@ def iter_senses(senses): edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): - for gloss in sense.glosses: - if gloss.lang != "en": + for glosa en sentido.glosas: + if glosa.idioma != "en": continue - old = str(gloss.text) - new = old.replace("colour", "color") - if new != old: + antiguo = str(glosa.texto) + nuevo = antiguo.replace("colour", "color") + si new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) -errors = [p for p in lex.iter_problems() if p.level == "error"] -if errors: +changed = lex.changed_entries() + +errors = [p for p in lex.iter_problems() si p.level == "error"] +si hay errores: for problem in errors: print(problem) - sys.exit(f"interrupción: {len(errors)} error(es) de validación, nada guardado") + sys.exit(f"abortando: {len(errors)} error(es) de validación, nada guardado") lex.save() -print(f" {edited_glosses} de glosas editadas en {len(touched_entries)} entrada(s)") +print(f"glosa(s) editada(s) {edited_glosses} en {len(changed)} entrada(s)") ``` Algunas cosas que conviene destacar: - `Sense.subsenses` es en sí mismo una `lista[Sense]`, por lo que `iter_senses` recorre su contenido de forma recursiva; una edición masiva que solo recorriera `entry.senses` omitiría sin avisar cualquier glosa anidada bajo un subsentido. - `gloss.text` es un `Text`, no una cadena simple: `str(gloss.text)` lo convierte en una cadena para la búsqueda de coincidencias, y la sustitución se vuelve a escribir con `sil_lift.Text([new])` en lugar de modificar la cadena in situ. +- `lex.changed_entries()` indica qué entradas difieren del archivo tal y como se ha cargado. Dado que el resumen de una entrada abarca todo su subárbol, cualquier modificación en un subsignificado anidado se refleja en la entrada que lo contiene. + - Comparando contenido serializado, no se registra el hecho de asignar a un campo el valor que ya tenía. + - Solo informa de los cambios en el contenido; `lex.added_entries()` y `lex.removed_entries()` recogen las entradas que han aparecido o desaparecido desde que se cargó la página. + - Devuelve las propias entradas, sin que les afecte que el `id` esté duplicado o falte (algo que permite LIFT). + - Como recuento, solo tiene sentido cuando hay algo con lo que compararlo. Cuando la capa de paso directo se niega a realizar un escaneo byte a byte del código fuente —ya sea por una codificación incompatible con ASCII o por una discrepancia entre el escáner y el analizador—, no existe una línea de referencia, y `changed_entries()` informa de _todas_ las entradas. Esa es la respuesta sincera en lo que respecta a la protección contra escritura, ya que `save()` vuelve a serializar todo el archivo en ese caso, pero eso significa que el recuento corresponde al tamaño del léxico y no al tamaño de la modificación. +- `lex.changes()` indica si el documento ha sufrido algún cambio _en absoluto_. Abarca no solo las entradas, sino también el encabezado, el elemento raíz y todos los elementos asociados a `.lift-ranges`. + - Solo es falso cuando `save()` reproduciría los bytes originales, lo que hace que `if not lex.changes(): ...` sea la forma correcta de omitir una escritura innecesaria. La garantía funciona en un solo sentido: nunca indica «nada que escribir» para un documento que se reescribiría, mientras que un cambio que obligue a una reserialización completa puede volver a los bytes originales y seguir indicándose. + - Compara el contenido, no el destino, por lo que solo debes utilizarlo para guardar en el mismo lugar: `lex.save(some_other_dir / "dictionary.lift")` escribe el documento y sus archivos asociados en una ubicación que aún está vacía, independientemente de si se ha producido algún cambio o no. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - La validación en memoria (`lex.iter_problems()`) serializa primero el estado editado, de modo que este refleje correctamente los cambios antes de que se guarde nada en el disco. Interrumpir la operación ante cualquier `Problem` de nivel «error» —las advertencias se dejan a criterio de quien realiza la llamada— significa que una edición incorrecta nunca llega a `save()`. Los brillos no son lo único que merece la pena tratar de esta manera. La misma superficie de asignación `Multitext` se aplica a las definiciones y a cualquier otro campo multilingüe de una entrada o un significado: From fd48696277a39194651d2397feed7052cc14e189 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:09 -0600 Subject: [PATCH 200/317] New translations bulk-edit-glosses.md (Arabic) [ci skip] --- docs/ar/guides/bulk-edit-glosses.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/ar/guides/bulk-edit-glosses.md b/docs/ar/guides/bulk-edit-glosses.md index e24749d..47e16cf 100644 --- a/docs/ar/guides/bulk-edit-glosses.md +++ b/docs/ar/guides/bulk-edit-glosses.md @@ -21,7 +21,6 @@ def iter_senses(senses): edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,7 +32,8 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: @@ -42,13 +42,22 @@ if errors: sys.exit(f"إلغاء العملية: {len(errors)} خطأ (أخطاء) في التحقق من الصحة، لم يتم حفظ أي شيء") lex.save() -print(f"تم تحرير {edited_glosses} تعريف (تعريفات) عبر {len(touched_entries)} مدخل (مداخل)") +print(f"تم تحرير {edited_glosses} التعريفات في {len(changed)} مدخل (مداخل)") ``` بعض النقاط الجديرة بالملاحظة: - تعد `Sense.subsenses` بحد ذاتها `list[Sense]`، لذا فإن `iter_senses` تتكرر بداخلها — أما عملية التحرير الجماعي التي تقتصر على `entry.senses` فستتجاهل بصمت أي تفسير متداخل تحت معنى فرعي. - `gloss.text` هو كائن من نوع `Text`، وليس سلسلة نصية عادية: تعمل الدالة `str(gloss.text)` على تحويله إلى سلسلة نصية عادية لأغراض المطابقة، ويتم كتابة النص البديل باستخدام `sil_lift.Text([new])` بدلاً من تعديل السلسلة في مكانها. +- تُظهر الدالة `lex.changed_entries()` المدخلات التي تختلف عن الملف كما تم تحميله. نظرًا لأن ملخص المدخل يغطي شجرته الفرعية بأكملها، فإن أي تعديل يُجرى على معنى فرعي متداخل يُبلغ المدخل الذي يحتوي عليه. + - إنها تقارن المحتوى المُسلسل، لذا فإن تعيين قيمة كان الحقل يحملها بالفعل لا يتم الإبلاغ عنه. + - وهي تُبلغ عن التغييرات في المحتوى فقط؛ أما `lex.added_entries()` و`lex.removed_entries()` فتشملان المدخلات التي ظهرت أو اختفت منذ بدء التحميل. + - تُرجع هذه الدالة السجلات نفسها، دون أن يتأثر ذلك بتكرار قيمة `id` أو عدم وجودها (وهو ما يسمح به LIFT). + - كإحصاء، لا يكون لهذا معنى إلا إذا كان هناك ما يُقارن به. عندما ترفض طبقة التمرير إجراء مسح بايت للمصدر — سواء بسبب ترميز غير متوافق مع ASCII، أو بسبب خلاف بين الماسح والمحلل — لا يكون هناك خط أساس، وتقوم الدالة `changed_entries()` بالإبلاغ عن _كل_ إدخال. هذه هي الإجابة الصادقة فيما يتعلق بـ«حارس الكتابة»، حيث إن دالة `save()` تعيد تسلسل الملف بأكمله في تلك الحالة، لكن هذا يعني أن العدد يمثل حجم المعجم بدلاً من حجم التعديل. +- تُبيّن الدالة `lex.changes()` ما إذا كان المستند قد تغير _على الإطلاق_. وهو لا يشمل العناصر فحسب، بل يشمل أيضًا العنصر الرئيسي والعنصر الجذري وكل عنصر مصاحب من نوع `.lift-ranges`. + - ولا يكون ذلك خطأً إلا عندما تعيد دالة `save()` إنتاج البايتات الأصلية، مما يجعل `if not lex.changes(): ...` الطريقة الصحيحة لتخطي عملية كتابة غير ضرورية. هذا الضمان يعمل في اتجاه واحد: فهو لا يُبلغ أبدًا بوجود «لا شيء لتدوينه» بالنسبة لمستند من المقرر إعادة كتابته، في حين أن التغيير الذي يفرض إعادة تسلسل كاملة قد يعود إلى البايتات الأصلية ويُبلغ عنه مع ذلك. + - فهي تقارن المحتوى، وليس الوجهة، لذا لا تستخدمها إلا لحفظ الملف في مكانه الأصلي: `lex.save(some_other_dir / "dictionary.lift")` تكتب المستند وملحقاته إلى موقع لا يحتوي على أي شيء بعد، بغض النظر عما إذا كان قد طرأ أي تغيير أم لا. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - تقوم عملية التحقق من الصحة في الذاكرة (`lex.iter_problems()`) بتسلسل الحالة التي تم تعديلها أولاً، بحيث تعكس التعديل بشكل صحيح قبل كتابة أي شيء على القرص. إن إيقاف العملية عند حدوث أي `"خطأ"` من فئة `Problem` — حيث تُترك التحذيرات للمستدعي ليحكم عليها — يعني أن عملية التحرير الخاطئة لن تصل أبدًا إلى `save()`. اللمعان ليس الشيء الوحيد الذي يستحق أن نلمسه بهذه الطريقة. ينطبق سطح التعيين «Multitext» نفسه على التعريفات وعلى كل حقل متعدد اللغات آخر في أي مدخل أو معنى: From bc55dde94801bc91cc10486ff28dfc018c1c5f18 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:11 -0600 Subject: [PATCH 201/317] New translations bulk-edit-glosses.md (German) [ci skip] --- docs/de/guides/bulk-edit-glosses.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/de/guides/bulk-edit-glosses.md b/docs/de/guides/bulk-edit-glosses.md index caa9d42..bc4f1e6 100644 --- a/docs/de/guides/bulk-edit-glosses.md +++ b/docs/de/guides/bulk-edit-glosses.md @@ -21,7 +21,6 @@ def iter_senses(senses): edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,7 +32,8 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: @@ -42,13 +42,22 @@ if errors: sys.exit(f"Abbruch: {len(errors)} Validierungsfehler, nichts gespeichert") lex.save() -print(f" {edited_glosses} -Glossare in {len(touched_entries)} Einträgen bearbeitet") +print(f"Bearbeitete {edited_glosses} Glossare in {len(changed)} Einträgen") ``` Ein paar Dinge, die es zu beachten gilt: - `Sense.subsenses` ist selbst eine `list[Sense]`, daher wird sie von `iter_senses` rekursiv durchlaufen – eine Massenbearbeitung, die nur `entry.senses` durchläuft, würde alle unter einer Unterbedeutung verschachtelten Erläuterungen stillschweigend überspringen. - `gloss.text` ist ein `Text` und keine einfache Zeichenkette: `str(gloss.text)` wandelt ihn für den Abgleich in eine Zeichenkette um, und die Ersetzung wird mit `sil_lift.Text([new])` zurückgeschrieben, anstatt die Zeichenkette direkt zu ändern. +- `lex.changed_entries()` gibt an, welche Einträge sich von der geladenen Datei unterscheiden. Da die Zusammenfassung eines Eintrags dessen gesamten Teilbaum abdeckt, wird bei einer Bearbeitung einer verschachtelten Teilbedeutung der Eintrag gemeldet, in dem diese enthalten ist. + - Da serialisierte Inhalte verglichen werden, wird die Zuweisung eines Werts zu einem Feld, den dieses bereits hatte, nicht gemeldet. + - Es werden ausschließlich inhaltliche Änderungen gemeldet; `lex.added_entries()` und `lex.removed_entries()` erfassen Einträge, die seit dem Laden hinzugekommen sind bzw. verschwunden sind. + - Es gibt die Einträge selbst zurück, unabhängig davon, ob `id` doppelt vorhanden ist oder fehlt (was LIFT zulässt). + - Als Zahl ist sie nur dann aussagekräftig, wenn es etwas gibt, mit dem man sie vergleichen kann. Wenn die Passthrough-Schicht den Byte-Scan der Quelle ablehnt – beispielsweise aufgrund einer nicht ASCII-kompatiblen Kodierung oder einer Diskrepanz zwischen Scanner und Parser –, gibt es keine Basislinie, und `changed_entries()` meldet _jeden_ Eintrag. Das ist die ehrliche Antwort in Bezug auf einen Schreibschutz, da `save()` in diesem Fall die gesamte Datei erneut serialisiert; das bedeutet jedoch, dass der Wert der Größe des Lexikons entspricht und nicht der Größe der Bearbeitung. +- `lex.changes()` gibt an, ob sich das Dokument _überhaupt_ geändert hat. Es umfasst nicht nur die Einträge, sondern auch die Kopfzeile, das Stammelement und jedes `.lift-ranges`-Element. + - Es ist nur dann falsch, wenn `save()` die Quellbytes reproduzieren würde; daher ist `if not lex.changes(): ...` der richtige Weg, um einen unnötigen Schreibvorgang zu überspringen. Die Garantie gilt nur in eine Richtung: Bei einem Dokument, das neu geschrieben würde, wird niemals „nichts zu schreiben“ gemeldet, während eine Änderung, die eine vollständige Neuserialisierung erzwingt, wieder zu den ursprünglichen Bytes führen kann und dennoch gemeldet wird. + - Da dabei der Inhalt und nicht der Speicherort verglichen wird, sollten Sie damit nur das Speichern am aktuellen Speicherort absichern: `lex.save(some_other_dir / "dictionary.lift")` schreibt das Dokument und die zugehörigen Dateien an einen Speicherort, der noch leer ist – unabhängig davon, ob sich etwas geändert hat oder nicht. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - Bei der Validierung im Arbeitsspeicher (`lex.iter_problems()`) wird der bearbeitete Zustand zunächst serialisiert, sodass er die Änderungen korrekt widerspiegelt, bevor Daten auf die Festplatte geschrieben werden. Ein Abbruch bei jedem `"error"`-Level-`Problem` – Warnungen werden dem Aufrufer zur Beurteilung überlassen – bedeutet, dass eine fehlerhafte Bearbeitung niemals `save()` erreicht. Nicht nur Glanzlacke lassen sich auf diese Weise gut auftragen. Die gleiche `Multitext`-Zuordnungsfläche gilt für Definitionen und alle anderen mehrsprachigen Felder eines Eintrags oder einer Bedeutung: From 109bb9f71b5e6e48003ddd695177503c296090b0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:13 -0600 Subject: [PATCH 202/317] New translations bulk-edit-glosses.md (Japanese) [ci skip] --- docs/ja/guides/bulk-edit-glosses.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/ja/guides/bulk-edit-glosses.md b/docs/ja/guides/bulk-edit-glosses.md index 07275fd..69e1211 100644 --- a/docs/ja/guides/bulk-edit-glosses.md +++ b/docs/ja/guides/bulk-edit-glosses.md @@ -14,14 +14,13 @@ lex = sil_lift.load(path) def iter_senses(senses): - """すべての意味(サブセンスを含む)を再帰的にイテレートする。""" + """すべての意味(サブ意味を含む)を再帰的にイテレートする。""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,7 +32,8 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: @@ -42,13 +42,22 @@ if errors: sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") ``` いくつか注目すべき点があります: - `Sense.subsenses` 自体は `list[Sense]` であるため、`iter_senses` はこのリストを再帰的に処理します。もし `entry.senses` のみを走査する一括編集を行った場合、サブセンスの下にネストされた語義は、何の警告もなくスキップされてしまいます。 - `gloss.text` は単なる文字列ではなく `Text` です。`str(gloss.text)` は照合のためにこれを平坦化し、置換結果は文字列そのものを変更するのではなく、`sil_lift.Text([new])` を使って書き戻されます。 +- `lex.changed_entries()` は、読み込まれたファイルと異なるエントリを報告します。 エントリのダイジェストはそのサブツリー全体を網羅しているため、ネストされたサブセンスを編集すると、そのサブセンスを含むエントリが報告されます。 + - シリアライズされたコンテンツを比較するため、フィールドに以前と同じ値を割り当てても、そのことは報告されません。 + - これはコンテンツの変更のみを報告します。`lex.added_entries()` および `lex.removed_entries()` は、読み込み以降に追加または削除されたエントリを対象としています。 + - `id` が重複していたり、存在しなかったりしても(LIFT ではこれが許可されています)、エントリそのものを返します。 + - 「数」として意味を持つのは、比較対象となるものが存在する場合に限られる。 パススルー層がソースのバイトスキャンを拒否した場合(ASCII互換ではないエンコーディングや、スキャナーとパーサーの不一致など)、基準となる状態が存在しないため、`changed_entries()` は _すべての_ エントリを報告します。 これはライトガードに関する正直な答えです。なぜなら、その場合は `save()` がファイル全体を再シリアル化するためですが、その結果、カウント値は編集部分のサイズではなく、レキシコンのサイズになってしまうからです。 +- `lex.changes()` は、ドキュメントに _何らかの変更_ があったかどうかを報告します。 これは、エントリだけでなく、ヘッダー、ルート要素、およびすべての `.lift-ranges` コンパニオンも対象としています。 + - これは、`save()` がソースバイトを再現する場合にのみ偽となるため、不要な書き込みをスキップするには `if not lex.changes(): ...` という書き方が正しい。 この保証は一方向のみ有効です。つまり、書き換えられるはずのドキュメントについては「書き込む内容なし」と報告されることは決してありませんが、完全な再シリアル化を余儀なくされる変更であっても、元のバイト列に戻った場合でも、依然として報告されることがあります。 + - これは保存先ではなく内容を比較するため、この方法ではインプレース保存のみを保護するようにしてください。`lex.save(some_other_dir / "dictionary.lift")` は、変更の有無にかかわらず、まだ何も格納されていない場所にドキュメントとその関連ファイルを書き込みます。 + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - メモリ内での検証(`lex.iter_problems()`)では、まず編集後の状態をシリアル化するため、ディスクへの書き込みが行われる前に、編集内容が正しく反映されます。 `"error"` レベルの `Problem` が発生した場合は処理を中止します(警告は呼び出し側が判断できるよう残されます)。これにより、不正な編集内容が `save()` に到達することはありません。 この方法で触れてみる価値があるのは、グロスだけではありません。 この `Multitext` マッピング領域は、定義や、エントリや意味に含まれるその他のすべての多言語フィールドにも同様に適用されます: From ebc7c22e027be8209bef3cddc21ace3062ef0028 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:15 -0600 Subject: [PATCH 203/317] New translations bulk-edit-glosses.md (Portuguese) [ci skip] --- docs/pt/guides/bulk-edit-glosses.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/pt/guides/bulk-edit-glosses.md b/docs/pt/guides/bulk-edit-glosses.md index c6442e9..b88045c 100644 --- a/docs/pt/guides/bulk-edit-glosses.md +++ b/docs/pt/guides/bulk-edit-glosses.md @@ -21,7 +21,6 @@ def iter_senses(senses): edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,22 +32,32 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"a interromper: {len(errors)} erro(s) de validação, nada guardado") + sys.exit(f"interrupção: {len(errors)} erro(s) de validação, nada guardado") lex.save() -print(f" {edited_glosses} gloss(es) editado(s) em {len(touched_entries)} entrada(s)") +print(f"gloss(es) editado(s) {edited_glosses} em {len(changed)} entrada(s)") ``` Algumas coisas que vale a pena referir: - `Sense.subsenses` é, por si só, uma `list[Sense]`, pelo que `iter_senses` a percorre de forma recursiva — uma edição em massa que apenas percorresse `entry.senses` ignoraria silenciosamente qualquer gloss aninhado sob um subsense. - `gloss.text` é um `Text`, não uma string simples: `str(gloss.text)` simplifica-o para efeitos de correspondência, e a substituição é gravada novamente com `sil_lift.Text([new])`, em vez de alterar a string no local. +- A função `lex.changed_entries()` indica quais as entradas que diferem do ficheiro tal como foi carregado. Uma vez que o resumo de uma entrada abrange toda a sua subárvore, uma alteração num sub-significado aninhado é comunicada à entrada que o contém. + - Como compara conteúdo serializado, a atribuição a um campo do valor que este já possuía não é registada. + - Apresenta apenas alterações de conteúdo; as funções `lex.added_entries()` e `lex.removed_entries()` abrangem as entradas que surgiram ou desapareceram desde o carregamento. + - Devolve as próprias entradas, sem que a existência de `id` duplicados ou ausentes (o que o LIFT permite) tenha qualquer influência. + - Enquanto contagem, só faz sentido quando há algo com que comparar. Quando a camada de passagem se recusa a efetuar a análise byte a byte da fonte — seja devido a uma codificação não compatível com ASCII, seja devido a uma discrepância entre o scanner e o analisador —, não existe uma linha de base e a função `changed_entries()` reporta _todas_ as entradas. Essa é a resposta correta no que diz respeito à proteção contra gravação, uma vez que, nesse caso, o `save()` volta a serializar o ficheiro na íntegra, mas isso significa que a contagem corresponde ao tamanho do léxico e não ao tamanho da edição. +- A função `lex.changes()` indica se o documento sofreu _alguma_ alteração. Abrange não só as entradas, mas também o cabeçalho, o elemento raiz e todos os elementos com a classe `.lift-ranges`. + - Só é falso quando a função `save()` reproduz os bytes de origem, o que faz com que `if not lex.changes(): ...` seja a forma correta de evitar uma gravação desnecessária. A garantia funciona num único sentido: nunca indica «nada para registar» relativamente a um documento que seria reescrito, enquanto que uma alteração que obrigue a uma resseriação completa pode resultar nos mesmos bytes originais e, mesmo assim, ser registada. + - Como compara o conteúdo e não o destino, utilize-o apenas para guardar no próprio local: `lex.save(some_other_dir / "dictionary.lift")` grava o documento e os seus ficheiros associados num local que ainda não contém nada, independentemente de ter havido ou não alterações. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - A validação na memória (`lex.iter_problems()`) serializa primeiro o estado editado, para que este reflita corretamente a edição antes de qualquer coisa ser gravada no disco. Interromper a execução perante qualquer `Problem` de nível `"error"` — os avisos são deixados para que o chamador os avalie — significa que uma edição incorreta nunca chega à função `save()`. Os glosses não são a única coisa que vale a pena tratar desta forma. A mesma superfície de mapeamento `Multitext` aplica-se às definições e a todos os outros campos multilingues de uma entrada ou significado: From 4f2ae24b1b03130d1b171cc7ab387ea84a657252 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:16 -0600 Subject: [PATCH 204/317] New translations bulk-edit-glosses.md (Russian) [ci skip] --- docs/ru/guides/bulk-edit-glosses.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/ru/guides/bulk-edit-glosses.md b/docs/ru/guides/bulk-edit-glosses.md index 2ca94ec..e002e3f 100644 --- a/docs/ru/guides/bulk-edit-glosses.md +++ b/docs/ru/guides/bulk-edit-glosses.md @@ -14,14 +14,13 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Выдает все значения, включая подзначения (рекурсивно).""" + """Yield every sense, including subsenses (recursive).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,22 +32,32 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"прерывание: {len(errors)} ошибка(и) валидации, ничего не сохранено") + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") lex.save() -print(f"отредактировано {edited_glosses} глосса(рий) в {len(touched_entries)} записи(ях)") +print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") ``` Несколько моментов, на которые стоит обратить внимание: - `Sense.subsenses` само по себе представляет собой `list[Sense]`, поэтому `iter_senses` выполняет рекурсию по нему — при массовом редактировании, которое бы просматривало только `entry.senses`, любые глоссы, вложенные под подзначениями, были бы незаметно пропущены. - `gloss.text` — это объект типа `Text`, а не обычная строка: функция `str(gloss.text)` преобразует его в строку для сопоставления, а результат замены записывается обратно с помощью `sil_lift.Text([new])`, а не путем изменения исходной строки на месте. +- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. + - It compares serialized content, so assigning a field the value it already had isn't reported. + - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. + - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). + - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. +- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. + - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. + - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - При проверке в памяти (`lex.iter_problems()`) сначала выполняется сериализация отредактированного состояния, благодаря чему оно правильно отражает внесенные изменения ещё до записи на диск. Прерывание при возникновении любого объекта `Problem` уровня `"error"` — предупреждения оставляются на усмотрение вызывающего кода — означает, что некорректное изменение никогда не доходит до вызова `save()`. Не только глянцевые поверхности стоит обрабатывать таким образом. Та же самая поверхность сопоставления `Multitext` применяется к определениям и всем другим многоязычным полям в записи или значении: From 3ddb2b17a0cddf8a3edf52d50255d6b61f742e5a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:18 -0600 Subject: [PATCH 205/317] New translations bulk-edit-glosses.md (Chinese Simplified) [ci skip] --- docs/zh/guides/bulk-edit-glosses.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/zh/guides/bulk-edit-glosses.md b/docs/zh/guides/bulk-edit-glosses.md index 8975a23..cf1b5a1 100644 --- a/docs/zh/guides/bulk-edit-glosses.md +++ b/docs/zh/guides/bulk-edit-glosses.md @@ -14,14 +14,13 @@ lex = sil_lift.load(path) def iter_senses(senses): - """返回每个词义,包括子词义(递归).""" + """Yield every sense, including subsenses (recursive).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,22 +32,32 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"中止:{len(errors)} 个验证错误,未保存任何内容") + sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") lex.save() -print(f"已编辑 {edited_glosses} 个释义,涉及{len(touched_entries)}个条目") +print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") ``` 有几点值得注意: - `Sense.subsenses` 本身是一个 `list[Sense]`,因此 `iter_senses` 会递归遍历它——如果批量编辑操作仅遍历 `entry.senses`,则会无提示地跳过任何嵌套在子义项下的释义。 - `gloss.text` 是一个 `Text` 对象,而不是普通的字符串:`str(gloss.text)` 会将其扁平化以便进行匹配,而替换后的内容会通过 `sil_lift.Text([new])` 写回,而不是直接修改原字符串。 +- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. + - It compares serialized content, so assigning a field the value it already had isn't reported. + - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. + - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). + - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. +- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. + - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. + - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - 内存验证(`lex.iter_problems()`)会先将编辑后的状态序列化,因此能在将任何内容写入磁盘之前,准确反映编辑后的状态。 一旦遇到任何 `"error"` 级别的 `Problem` 就终止处理——警告信息将留给调用方自行判断——这意味着错误的编辑操作永远不会进入 `save()` 方法。 值得这样处理的不仅仅是光泽。 相同的 `Multitext` 映射规则同样适用于定义以及条目或词义中的所有其他多语言字段: From b8d020d70a9266e2326aa5b1a0abafb4ce566b0e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:20 -0600 Subject: [PATCH 206/317] New translations bulk-edit-glosses.md (Hindi) [ci skip] --- docs/hi/guides/bulk-edit-glosses.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/hi/guides/bulk-edit-glosses.md b/docs/hi/guides/bulk-edit-glosses.md index ce4be3f..cfdb5c3 100644 --- a/docs/hi/guides/bulk-edit-glosses.md +++ b/docs/hi/guides/bulk-edit-glosses.md @@ -14,14 +14,13 @@ lex = sil_lift.load(path) def iter_senses(senses): - """प्रत्येक इंद्रिय, उप-इंद्रियों सहित (पुनरावर्ती) उत्पन्न करें।""" + """Yield every sense, including subsenses (recursive).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,7 +32,8 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: @@ -42,13 +42,22 @@ if errors: sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") ``` ध्यान देने योग्य कुछ बातें: - `Sense.subsenses` स्वयं एक `list[Sense]` है, इसलिए `iter_senses` इसमें पुनरावृत्ति करता है — एक सामूहिक संपादन जो केवल `entry.senses` को ही चलाता है, वह किसी उपसंज्ञा के अंतर्गत निहित किसी भी परिभाषा को चुपचाप छोड़ देगा। - `gloss.text` एक `Text` है, न कि एक साधारण स्ट्रिंग: `str(gloss.text)` इसे मिलान के लिए फ्लैटन करता है, और प्रतिस्थापन को स्ट्रिंग को वहीं पर बदलने के बजाय `sil_lift.Text([new])` के साथ वापस लिखा जाता है। +- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. + - It compares serialized content, so assigning a field the value it already had isn't reported. + - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. + - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). + - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. +- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. + - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. + - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - मेमोरी में सत्यापन (`lex.iter_problems()`) पहले संपादित स्थिति को सीरियलाइज़ करता है, ताकि डिस्क पर कुछ भी लिखे जाने से पहले यह संपादन को सही ढंग से दर्शाए। किसी भी `"error"`-स्तर के `Problem` पर प्रक्रिया रद्द करने पर — चेतावनियाँ कॉल करने वाले पर छोड़ दी जाती हैं — इसका मतलब है कि एक खराब संपादन कभी भी `save()` तक नहीं पहुँचता। इस तरह छूने लायक सिर्फ ग्लॉस ही नहीं हैं। एक ही `Multitext` मैपिंग सतह परिभाषाओं और किसी प्रविष्टि या अर्थ पर प्रत्येक अन्य बहुभाषी क्षेत्र पर लागू होती है: From d1e3b23e2d64a5a263874ad91626bacf1fd1b98b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Tue, 11 Aug 2026 12:33:22 -0600 Subject: [PATCH 207/317] New translations bulk-edit-glosses.md (Swahili) [ci skip] --- docs/sw/guides/bulk-edit-glosses.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/docs/sw/guides/bulk-edit-glosses.md b/docs/sw/guides/bulk-edit-glosses.md index a920d14..fc77cd7 100644 --- a/docs/sw/guides/bulk-edit-glosses.md +++ b/docs/sw/guides/bulk-edit-glosses.md @@ -14,14 +14,13 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yatoa kila hisia, ikiwa ni pamoja na hisia ndogo (kwa kujirudia).""" + """Yield every sense, including subsenses (recursive).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) edited_glosses = 0 -touched_entries = set() for entry in lex.entries: for sense in iter_senses(entry.senses): @@ -33,7 +32,8 @@ for entry in lex.entries: if new != old: gloss.text = sil_lift.Text([new]) edited_glosses += 1 - touched_entries.add(entry.id) + +changed = lex.changed_entries() errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: @@ -42,13 +42,22 @@ if errors: sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(touched_entries)} entry(ies)") +print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") ``` Mambo machache ya kuzingatia: - `Sense.subsenses` ni `list[Sense]` yenyewe, kwa hivyo `iter_senses` inarudia ndani yake — uhariri wa jumla ambao ungepitia tu `entry.senses` ungeacha kimya kimya fasili yoyote iliyoko chini ya subsense. - `gloss.text` ni `Text`, si mfululizo wa kawaida: `str(gloss.text)` huifanya iwe mfululizo wa kawaida kwa ajili ya kulinganisha, na mbadala huandikwa tena kwa kutumia `sil_lift.Text([new])` badala ya kubadilisha mfululizo mahali pake. +- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. + - It compares serialized content, so assigning a field the value it already had isn't reported. + - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. + - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). + - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. +- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. + - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. + - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. + - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. - Uhakiki katika kumbukumbu (`lex.iter_problems()`) huweka kwanza hali iliyohaririwa kwa mpangilio, hivyo inaonyesha kwa usahihi mabadiliko kabla ya chochote kuandikwa kwenye diski. Kukata shughuli kwa `Problem` yoyote ya kiwango cha `"error"` — maonyo huachwa kwa mtu anayeita ili ahukumu — kunamaanisha kuwa uhariri mbaya hauwahi kufikia `save()`. Si glosi pekee ndizo zinazostahili kuguswa kwa njia hii. Uso uleule wa ramani wa `Multitext` unatumika kwa ufafanuzi na kila uwanja mwingine wa lugha nyingi kwenye kipengee au maana: From 8dbb0a91c8eac27bb2f765c51b1d9fd9a39eadcf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:23 -0600 Subject: [PATCH 208/317] New translations csharp-differences.md (French) [ci skip] --- docs/fr/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fr/csharp-differences.md b/docs/fr/csharp-differences.md index 6c8187d..f05d019 100644 --- a/docs/fr/csharp-differences.md +++ b/docs/fr/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift s'apparente vaguement aux outils LIFT de SIL en C# — principalement ` ## Forme de l'API -Le parseur de `SIL.Lift` fonctionne par callbacks (`ILexiconMerger`) : il transmet les événements d'analyse à un consommateur. sil-lift renvoie en revanche un simple graphe d'objets — des classes de données typées pour chaque élément LIFT — car les développeurs Python souhaitent des objets, et non des callbacks. `SIL.DictionaryServices` superpose effectivement un modèle d'objets `LexEntry`/`LexSense` à `SIL.Lift`, mais en tant que modèle d’application, il ne représente que les constructions utilisées par ces applications — par conséquent, la resérialisation via ce modèle ne permet pas de préserver le contenu hors modèle de la même manière que le font la capture des résidus et la fidélité au niveau des octets de sil-lift (voir ci-dessous). L'API de streaming renvoie le _même_ type `Entry` ; il n'existe donc pas de modèle jumeau aux capacités réduites. +Le parseur de `SIL.Lift` fonctionne par callbacks (`ILexiconMerger`) : il transmet les événements d'analyse à un consommateur. sil-lift renvoie en revanche un simple graphe d'objets — des classes de données typées pour chaque élément LIFT — car les développeurs Python souhaitent des objets, et non des callbacks. `SIL.DictionaryServices` superpose effectivement un modèle d'objets `LexEntry`/`LexSense` à `SIL.Lift`, mais en tant que modèle d’application, il ne représente que les constructions utilisées par ces applications — par conséquent, la resérialisation via ce modèle ne permet pas de préserver le contenu hors modèle, contrairement à la gestion des résidus LIFT et à la fidélité au niveau des octets offertes par sil-lift (voir ci-dessous). L'API de streaming renvoie le _même_ type `Entry` ; il n'y a donc pas de deuxième modèle simplifié à apprendre. ## Fidélité aller-retour La différence la plus marquée et la plus délibérée. L'enregistrement avec `SIL.Lift` entraîne la resérialisation de l'intégralité du document. sil-lift garantit : - un document inchangé est enregistré **avec une taille en octets identique**, et -- Les entrées non modifiées conservent exactement les mêmes octets source, même lorsque d'autres entrées changent (segmentation en blocs d'octets de type « Chorus », appliquée automatiquement). +- Les entrées inchangées conservent exactement les mêmes octets source, même lorsque d'autres entrées sont modifiées — il s'agit du même découpage en blocs d'octets par entrée que celui utilisé par Chorus, appliqué automatiquement. Consultez les [garanties de fidélité](fidelity.md). ## Validation -Le `Validator` C# effectue un passage RELAX NG et renvoie les premières erreurs sous forme de chaînes de caractères. sil-lift déclare un flux « Problem » structuré, avec adressage par entrée/ligne, et sa couche de schéma présente sciemment trois divergences : +Le `Validator` C# effectue un passage RELAX NG et renvoie les premières erreurs sous forme de chaînes de caractères. sil-lift génère un flux structuré de « problèmes », chacun contenant le fichier, l'entrée et la ligne concernés, et son schéma présente sciemment trois divergences : - **Les URI non valides constituent des avertissements, et non des erreurs.** Le moteur RELAX NG de C# n'a jamais imposé le type de données `anyURI` ; c'est pourquoi FieldWorks (FLEx) insère depuis des années des liens `file://C:/...` dans des lexiques réels. Le rejet de ces fichiers entraînerait le marquage de pratiquement toutes les exportations FLEx. - **Les règles Schematron sont appliquées** (sous forme de vérifications sémantiques) : les langages de formulaire en double et les co-contraintes similaires présentes dans la grammaire LIFT étaient ignorés sans avertissement tant par la validation en C# que par celle effectuée directement avec lxml. From 2e266648f12409c84b5d191f35d350879ea69f19 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:24 -0600 Subject: [PATCH 209/317] New translations csharp-differences.md (Spanish) [ci skip] --- docs/es/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/es/csharp-differences.md b/docs/es/csharp-differences.md index 5e2a367..74b41da 100644 --- a/docs/es/csharp-differences.md +++ b/docs/es/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift es, a grandes rasgos, análogo a las herramientas LIFT de SIL para C# ## Formato de la API -El analizador de `SIL.Lift` funciona mediante callbacks (`ILexiconMerger`): envía eventos de análisis a un consumidor. En cambio, sil-lift devuelve un grafo de objetos simple —clases de datos tipadas para cada elemento LIFT—, ya que los programadores de Python quieren objetos, no funciones de devolución de llamada. `SIL.DictionaryServices` superpone un modelo de objetos `LexEntry`/`LexSense` sobre `SIL.Lift`, pero, como modelo de aplicación, solo representa las construcciones que utilizan esas aplicaciones; por lo tanto, la reserialización a través de él no puede conservar el contenido ajeno al modelo de la misma forma que lo hacen la captura de residuos y la fidelidad de bytes de sil-lift (véase más abajo). La API de streaming devuelve el _mismo_ tipo `Entry`, por lo que no existe un modelo equivalente con capacidades reducidas. +El analizador de `SIL.Lift` funciona mediante callbacks (`ILexiconMerger`): envía eventos de análisis a un consumidor. En cambio, sil-lift devuelve un grafo de objetos simple —clases de datos tipadas para cada elemento LIFT—, ya que los programadores de Python quieren objetos, no funciones de devolución de llamada. `SIL.DictionaryServices` superpone un modelo de objetos `LexEntry`/`LexSense` sobre `SIL.Lift`, pero, como modelo de aplicación, solo representa las construcciones que utilizan esas aplicaciones; por lo tanto, la reserialización a través de él no puede conservar el contenido ajeno al modelo de la misma forma que lo hacen el manejo de residuos LIFT y la fidelidad de bytes de sil-lift (véase más abajo). La API de streaming devuelve el _mismo_ tipo `Entry`, por lo que no hay que aprender un segundo modelo simplificado. ## Fidelidad de ida y vuelta La diferencia más marcada y deliberada. Al guardar con `SIL.Lift`, se vuelve a serializar todo el documento. sil-lift garantiza: - un documento que no ha sufrido modificaciones se guarda **con los mismos bytes**, y -- Las entradas que no se modifican conservan sus bytes de origen exactos, incluso cuando cambian otras entradas (división en bloques de bytes de nivel «Chorus», aplicada automáticamente). +- Las entradas que no se modifican conservan sus bytes de origen exactos incluso cuando cambian otras entradas: se trata del mismo sistema de fragmentación en bloques de bytes por entrada que utiliza Chorus, que se aplica automáticamente. Consulta [las garantías de Fidelity](fidelity.md). ## Validación -El `Validator` de C# ejecuta una pasada de RELAX NG y devuelve los primeros errores en forma de cadenas de caracteres. sil-lift describe un flujo «Problem» estructurado, con entradas y direcciones de línea, y su capa de esquema presenta tres divergencias deliberadas: +El `Validator` de C# ejecuta una pasada de RELAX NG y devuelve los primeros errores en forma de cadenas de caracteres. sil-lift genera un flujo estructurado de «Problemas», cada uno de los cuales incluye el archivo, la entrada y la línea a los que se refiere, y su capa de esquema presenta tres divergencias deliberadas: - **Los URI no válidos son advertencias, no errores.** El motor RELAX NG de C# nunca ha aplicado el tipo de datos `anyURI`, por lo que FieldWorks (FLEx) lleva años incluyendo enlaces `file://C:/...` en léxicos reales. Si se rechazaran esos archivos, se marcarían prácticamente todas las exportaciones de FLEx. - **Se aplican las reglas de Schematron** (como comprobaciones semánticas): tanto la validación en C# como la validación directa con lxml ignoraban silenciosamente los lenguajes de formulario duplicados y las coconstricciones similares en la gramática LIFT. From 26d3d9a59b9c40fd7bc907fa3b24b7ed94387a81 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:26 -0600 Subject: [PATCH 210/317] New translations csharp-differences.md (Arabic) [ci skip] --- docs/ar/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ar/csharp-differences.md b/docs/ar/csharp-differences.md index 160c1c5..43009ee 100644 --- a/docs/ar/csharp-differences.md +++ b/docs/ar/csharp-differences.md @@ -14,20 +14,20 @@ ## شكل واجهة برمجة التطبيقات (API) -يعمل محلل `SIL.Lift` على أساس آلية الاستدعاء المرتد (`ILexiconMerger`): فهو يقوم بدفع أحداث التحليل إلى المستلم. بدلاً من ذلك، تُرجع «sil-lift» مخطط كائنات عادي — فئات بيانات مُحددة النوع لكل عنصر من عناصر LIFT — لأن مبرمجي بايثون يفضلون الكائنات، وليس دالات الاستدعاء. تقوم `SIL.DictionaryServices` بتركيب نموذج كائنات `LexEntry`/`LexSense` فوق `SIL.Lift`، ولكنه كنموذج تطبيق لا يمثل سوى البنيات التي تستخدمها تلك التطبيقات — لذا فإن إعادة التسلسل من خلاله لا يمكنها الحفاظ على المحتوى خارج النموذج بالطريقة التي تقوم بها ميزة التقاط البقايا ودقة البايت في sil-lift (انظر أدناه). تُنتج واجهة برمجة التطبيقات (API) الخاصة بالتدفق النوع _نفسه_ من `Entry`، لذا لا يوجد نموذج توأمي محدود القدرات. +يعمل محلل `SIL.Lift` على أساس آلية الاستدعاء المرتد (`ILexiconMerger`): فهو يقوم بدفع أحداث التحليل إلى المستلم. بدلاً من ذلك، تُرجع «sil-lift» مخطط كائنات عادي — فئات بيانات مُحددة النوع لكل عنصر من عناصر LIFT — لأن مبرمجي بايثون يفضلون الكائنات، وليس دالات الاستدعاء. تقوم `SIL.DictionaryServices` بتركيب نموذج كائنات `LexEntry`/`LexSense` فوق `SIL.Lift`، ولكنه كنموذج تطبيق لا يمثل سوى البنيات التي تستخدمها تلك التطبيقات — لذا فإن إعادة التسلسل من خلاله لا يمكنها الحفاظ على المحتوى خارج النموذج بالطريقة التي تتبعها معالجة بقايا LIFT ودقة البايت في sil-lift (انظر أدناه). تُنتج واجهة برمجة التطبيقات (API) الخاصة بالتدفق النوع _نفسه_ من `Entry`، لذا لا يوجد نموذج ثانٍ مبسط يتعين تعلمه. ## دقة النقل في كلا الاتجاهين أقوى اختلاف متعمد. يؤدي الحفظ باستخدام `SIL.Lift` إلى إعادة تسلسل المستند بأكمله. تضمن شركة «سيل-ليفت» ما يلي: - يتم حفظ المستند الذي لم يطرأ عليه تغيير **بشكل مطابق تمامًا من حيث البايتات**، و -- تحتفظ الإدخالات التي لم يتم التعديل عليها ببايتات المصدر الدقيقة الخاصة بها حتى عند تغير الإدخالات الأخرى (تقسيم البايتات على مستوى «Chorus»، يُطبق تلقائيًا). +- تحتفظ الإدخالات التي لم يتم التعديل عليها ببايتات المصدر الدقيقة الخاصة بها حتى عند تغيير الإدخالات الأخرى — وهو نفس أسلوب تقسيم البايتات لكل إدخال الذي يستخدمه «Chorus»، ويتم تطبيقه تلقائيًا. انظر [ضمانات فيديليتي](fidelity.md). ## التحقق من الصحة -يقوم `Validator` في لغة C# بتنفيذ دورة واحدة من RELAX NG ويُبلغ عن الأخطاء الأولى في شكل سلاسل نصية. تُبلغ sil-lift عن دفق «مشكلة» منظم ومُحدد حسب الإدخال/السطر، وتختلف طبقة مخططها عن قصد في ثلاثة مواضع: +يقوم `Validator` في لغة C# بتنفيذ دورة واحدة من RELAX NG ويُبلغ عن الأخطاء الأولى في شكل سلاسل نصية. يُبلغ sil-lift عن دفق منظم من «المشكلات» (Problem)، يحمل كل منها الملف والمدخل والسطر الذي يتعلق به، وتختلف طبقة مخططه عن قصد في ثلاثة مواضع: - **عناوين URI غير الصالحة تُعتبر تحذيرات وليست أخطاء.** لم يفرض محرك C# RELAX NG أبدًا نوع البيانات `anyURI`، لذا ظل برنامج FieldWorks (FLEx) لسنوات عديدة يدرج روابط href من النوع `file://C:/...` في المعاجم الفعلية. إن رفض تلك الملفات سيؤدي إلى وضع علامة على كل ملفات التصدير من FLEx تقريبًا. - **يتم تطبيق قواعد Schematron** (كعمليات تدقيق دلالية): تم تجاهل لغات النماذج المكررة والقيود المشتركة المماثلة في قواعد LIFT دون إشعار من قبل كل من عملية التحقق من صحة C# وعملية التحقق من صحة lxml الخام. From db1e731d9b101b1e1cce9938c6a6225364bd29db Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:28 -0600 Subject: [PATCH 211/317] New translations csharp-differences.md (German) [ci skip] --- docs/de/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/de/csharp-differences.md b/docs/de/csharp-differences.md index 2dbafe2..57aa6f0 100644 --- a/docs/de/csharp-differences.md +++ b/docs/de/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift ist in etwa vergleichbar mit den C#-LIFT-Tools von SIL – vor allem mi ## API-Form -Der Parser von `SIL.Lift` ist callback-gesteuert (`ILexiconMerger`): Er übergibt Parsing-Ereignisse an einen Verbraucher. sil-lift gibt stattdessen einen einfachen Objektgraphen zurück – typisierte Dataklassen für jedes LIFT-Element –, da Python-Skriptentwickler Objekte und keine Callbacks wünschen. `SIL.DictionaryServices` legt zwar ein `LexEntry`/`LexSense`-Objektmodell über `SIL.Lift“, doch als Anwendungsmodell repräsentiert es lediglich die Konstrukte, die diese Anwendungen verwenden – daher können bei einer erneuten Serialisierung über dieses Modell Inhalte, die außerhalb des Modells liegen, nicht in derselben Weise erhalten bleiben wie bei der Residue-Erfassung und der Byte-Fidelity von sil-lift (siehe unten). Die Streaming-API liefert denselben `Entry\`-Typ, daher gibt es kein Modell mit eingeschränkten Funktionen. +Der Parser von `SIL.Lift` ist callback-gesteuert (`ILexiconMerger`): Er übergibt Parsing-Ereignisse an einen Verbraucher. sil-lift gibt stattdessen einen einfachen Objektgraphen zurück – typisierte Dataklassen für jedes LIFT-Element –, da Python-Skriptentwickler Objekte und keine Callbacks wünschen. `SIL.DictionaryServices` legt zwar ein `LexEntry`/`LexSense`-Objektmodell über `SIL.Lift“, doch als Anwendungsmodell repräsentiert es lediglich die Konstrukte, die diese Anwendungen verwenden – daher kann bei einer erneuten Serialisierung über dieses Modell hinweg der Inhalt außerhalb des Modells nicht in derselben Weise erhalten bleiben, wie dies bei der Behandlung von LIFT-Resten und der Byte-Genauigkeit von sil-lift der Fall ist (siehe unten). Die Streaming-API liefert denselben `Entry\`-Typ, sodass kein zweites, vereinfachtes Modell erlernt werden muss. ## Round-Trip-Genauigkeit Der deutlichste bewusste Unterschied. Beim Speichern mit `SIL.Lift` wird das gesamte Dokument erneut serialisiert. sil-lift garantiert: - Ein unverändertes Dokument wird **byte-identisch** gespeichert, und -- Unveränderte Einträge behalten ihre exakten Quellbytes bei, auch wenn sich andere Einträge ändern (Byte-Chunking auf Chorus-Ebene, wird automatisch angewendet). +- Unveränderte Einträge behalten ihre exakten Quellbytes bei, auch wenn sich andere Einträge ändern – es handelt sich um dieselbe, pro Eintrag erfolgende Byte-Aufteilung, die Chorus verwendet und die automatisch angewendet wird. Siehe [Garantien zur Richtigkeit](fidelity.md). ## Validierung -Der C#-`Validator` führt einen RELAX-NG-Durchlauf durch und gibt die ersten Fehler als Zeichenfolgen zurück. sil-lift meldet einen strukturierten, nach Einträgen/Zeilen adressierten `Problem`-Stream, und seine Schemaebene weicht an drei Stellen bewusst davon ab: +Der C#-`Validator` führt einen RELAX-NG-Durchlauf durch und gibt die ersten Fehler als Zeichenfolgen zurück. sil-lift meldet einen strukturierten `Problem`-Stream, wobei jeder Eintrag die betreffende Datei, den Eintrag und die Zeile enthält, und seine Schemaebene weicht bewusst an drei Stellen ab: - **Ungültige URIs sind Warnungen, keine Fehler.** Die C#-RELAX-NG-Engine hat den Datentyp `anyURI` nie erzwungen, weshalb FieldWorks (FLEx) seit Jahren `file://C:/...`-href-Links in echte Lexika schreibt. Würden diese Dateien abgelehnt, würde dies praktisch jeden FLEx-Export als fehlerhaft kennzeichnen. - **Schematron-Regeln werden durchgesetzt** (als semantische Prüfungen): Doppelte Formularsprachen und ähnliche Ko-Einschränkungen in der LIFT-Grammatik wurden sowohl bei der C#-Validierung als auch bei der reinen lxml-Validierung stillschweigend ignoriert. From 35e70fab552fef66e74aed2d6403570c3abdd7e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:29 -0600 Subject: [PATCH 212/317] New translations csharp-differences.md (Japanese) [ci skip] --- docs/ja/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ja/csharp-differences.md b/docs/ja/csharp-differences.md index 5303242..ef300ec 100644 --- a/docs/ja/csharp-differences.md +++ b/docs/ja/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift は、SIL の C# LIFT ツール群――主に [libpalaso](https://gith ## APIの形状 -`SIL.Lift`のパーサーはコールバック駆動型(`ILexiconMerger`)であり、解析イベントをコンシューマーにプッシュします。 その代わりに、sil-lift は単純なオブジェクトグラフ(LIFT の各要素に対応する型付きデータクラス)を返します。これは、Python スクリプト作成者がコールバックではなくオブジェクトを求めているためです。 `SIL.DictionaryServices` は、`SIL.Lift`の上に`LexEntry`/`LexSense`オブジェクトモデルを重ねていますが、アプリケーションモデルとして、それはそれらのアプリが使用する構造のみを表しています。そのため、これを通じて再シリアライズを行っても、sil-liftの残留値のキャプチャやバイト単位の忠実度のように、モデル外のコンテンツを保持することはできません(以下を参照)。 ストリーミングAPIは_同じ_ `Entry` 型を返すため、機能が制限されたツインモデルは存在しません。 +`SIL.Lift`のパーサーはコールバック駆動型(`ILexiconMerger`)であり、解析イベントをコンシューマーにプッシュします。 その代わりに、sil-lift は単純なオブジェクトグラフ(LIFT の各要素に対応する型付きデータクラス)を返します。これは、Python スクリプト作成者がコールバックではなくオブジェクトを求めているためです。 `SIL.DictionaryServices` は、`SIL.Lift`の上に`LexEntry`/`LexSense`オブジェクトモデルを重ねていますが、アプリケーションモデルとしては、それらのアプリが使用する構造のみを表しています。そのため、これを通じて再シリアル化を行っても、sil-liftのLIFT残余処理やバイト単位の忠実度処理(後述)のように、モデル外のコンテンツを保持することはできません。 ストリーミングAPIは_同じ_ `Entry` 型を返すため、別途学習すべき簡略化されたモデルは存在しません。 ## 往復の忠実度 最も顕著な意図的な違い。 `SIL.Lift` を使用して保存すると、ドキュメント全体が再シリアル化されます。 sil-liftの保証: - 変更のないドキュメントは**バイト単位で同一**に保存され、 -- 変更されていないエントリは、他のエントリが変更された場合でも、ソースのバイトを正確に保持します(Chorusレベルのバイト単位のチャンキングが自動的に適用されます)。 +- 変更されていないエントリは、他のエントリが変更された場合でも、ソースのバイトデータをそのまま保持します。これは、Chorus が採用しているエントリ単位のバイトチャンキングと同じ仕組みであり、自動的に適用されます。 [フィデリティの保証](fidelity.md)をご覧ください。 ## 検証 -C#の`Validator`は、RELAX NGによる検証を1回実行し、最初に検出されたエラーを文字列として報告します。 sil-lift は、構造化された、エントリ/行単位でアドレス指定される `Problem` ストリームを報告しており、そのスキーマ層は意図的に 3 箇所で異なる仕様となっています: +C#の`Validator`は、RELAX NGによる検証を1回実行し、最初に検出されたエラーを文字列として報告します。 sil-lift は、構造化された `Problem` ストリームを報告します。各ストリームには、対象となるファイル、エントリ、行が含まれており、そのスキーマ層は意図的に 3 箇所で異なる仕様となっています: - **無効なURIはエラーではなく警告です。** C#のRELAX NGエンジンは`anyURI`データ型を強制したことがなかったため、FieldWorks (FLEx) では長年にわたり、実際のレキシコンに`file://C:/...`というhrefを記述してきました。 それらのファイルを拒否すると、事実上すべてのFLExエクスポートにフラグが立てられてしまいます。 - **Schematronルールが適用されます**(セマンティックチェックとして):LIFT文法における重複するフォーム言語や類似の共制約は、C#および生のlxmlによる検証のいずれにおいても、黙って無視されていました。 From a9ff74eaeba5fdbc67763313e7d53fd0358b4bd1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:31 -0600 Subject: [PATCH 213/317] New translations csharp-differences.md (Portuguese) [ci skip] --- docs/pt/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pt/csharp-differences.md b/docs/pt/csharp-differences.md index df9fe95..49ac0ba 100644 --- a/docs/pt/csharp-differences.md +++ b/docs/pt/csharp-differences.md @@ -14,20 +14,20 @@ O sil-lift é, de certa forma, análogo às ferramentas LIFT da SIL para C# — ## Estrutura da API -O analisador do `SIL.Lift` é orientado por callbacks (`ILexiconMerger`): envia eventos de análise a um consumidor. Em vez disso, o sil-lift devolve um gráfico de objetos simples — classes de dados tipadas para cada elemento LIFT — porque os programadores de Python querem objetos, e não callbacks. O `SIL.DictionaryServices` sobrepõe um modelo de objetos `LexEntry`/`LexSense` ao `SIL.Lift`, mas, enquanto modelo de aplicação, representa apenas as construções que essas aplicações utilizam — pelo que a resserialização através dele não consegue preservar o conteúdo fora do modelo da mesma forma que a captura de resíduos e a fidelidade de bytes do sil-lift o fazem (ver abaixo). A API de streaming devolve o _mesmo_ tipo `Entry`, pelo que não existe um modelo duplo com funcionalidades reduzidas. +O analisador do `SIL.Lift` é orientado por callbacks (`ILexiconMerger`): envia eventos de análise a um consumidor. Em vez disso, o sil-lift devolve um gráfico de objetos simples — classes de dados tipadas para cada elemento LIFT — porque os programadores de Python querem objetos, e não callbacks. O `SIL.DictionaryServices` sobrepõe um modelo de objetos `LexEntry`/`LexSense` ao `SIL.Lift`, mas, enquanto modelo de aplicação, representa apenas as construções que essas aplicações utilizam — pelo que a resserialização através dele não consegue preservar o conteúdo fora do modelo da mesma forma que o tratamento de resíduos LIFT e a fidelidade de bytes do sil-lift o fazem (ver abaixo). A API de streaming devolve o _mesmo_ tipo `Entry`, pelo que não há um segundo modelo simplificado para aprender. ## Fidelidade de ida e volta A diferença deliberada mais marcante. Ao guardar com o `SIL.Lift`, todo o documento é novamente serializado. A sil-lift garante: - um documento inalterado é guardado com **identidade de bytes**, e -- As entradas não alteradas mantêm os seus bytes de origem exatos, mesmo quando outras entradas são alteradas (divisão em blocos de bytes ao nível do Chorus, aplicada automaticamente). +- As entradas não alteradas mantêm os seus bytes de origem exatos, mesmo quando outras entradas são alteradas — trata-se do mesmo agrupamento de bytes por entrada que o Chorus utiliza, aplicado automaticamente. Consulte [Garantias da Fidelity](fidelity.md). ## Validação -O `Validator` do C# executa uma passagem RELAX NG e apresenta os primeiros erros sob a forma de cadeias de caracteres. O sil-lift reporta um fluxo `Problem` estruturado, endereçado por entrada/linha, e a sua camada de esquema diverge deliberadamente em três pontos: +O `Validator` do C# executa uma passagem RELAX NG e apresenta os primeiros erros sob a forma de cadeias de caracteres. O sil-lift apresenta um fluxo estruturado de `Problemas`, cada um contendo o ficheiro, a entrada e a linha a que se refere, e a sua camada de esquema diverge deliberadamente em três pontos: - **Os URIs inválidos são avisos, não erros.** O motor RELAX NG do C# nunca impôs o tipo de dados `anyURI`, pelo que o FieldWorks (FLEx) tem vindo a inserir hrefs do tipo `file://C:/...` em léxicos reais há anos. A rejeição desses ficheiros faria com que praticamente todas as exportações do FLEx fossem sinalizadas. - **As regras do Schematron são aplicadas** (como verificações semânticas): as linguagens de formulário duplicadas e as co-restrições semelhantes na gramática LIFT foram ignoradas silenciosamente tanto pela validação em C# como pela validação direta do lxml. From e731b4abfe1c43cf1c7f2a2e8c3963c9ee110dc1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:33 -0600 Subject: [PATCH 214/317] New translations csharp-differences.md (Russian) [ci skip] --- docs/ru/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ru/csharp-differences.md b/docs/ru/csharp-differences.md index e6bcc95..745826c 100644 --- a/docs/ru/csharp-differences.md +++ b/docs/ru/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift в общих чертах аналогичен инструмента ## Формат API -Парсер `SIL.Lift` работает на основе обратных вызовов (`ILexiconMerger`): он передаёт события разбора потребителю. Вместо этого sil-lift возвращает простой граф объектов — типизированные классы данных для каждого элемента LIFT — поскольку разработчики скриптов на Python нуждаются в объектах, а не в обратных вызовах. `SIL.DictionaryServices` действительно накладывает объектную модель `LexEntry`/`LexSense` на `SIL.Lift`, но как прикладная модель она представляет только те конструкции, которые используют эти приложения — поэтому повторная сериализация через неё не может сохранить контент, выходящий за пределы модели, так же, как это делают функции захвата остатков и точной передачи байтов в sil-lift (см. ниже). API потоковой обработки возвращает _тот же самый_ тип `Entry`, поэтому не существует модели-близнеца с ограниченными возможностями. +Парсер `SIL.Lift` работает на основе обратных вызовов (`ILexiconMerger`): он передаёт события разбора потребителю. Вместо этого sil-lift возвращает простой граф объектов — типизированные классы данных для каждого элемента LIFT — поскольку разработчики скриптов на Python нуждаются в объектах, а не в обратных вызовах. `SIL.DictionaryServices` действительно накладывает объектную модель `LexEntry`/`LexSense` на `SIL.Lift`, однако как прикладная модель она представляет только те конструкции, которые используют эти приложения — поэтому повторная сериализация через неё не может сохранить контент, выходящий за пределы модели, так же, как это делают обработка остатков LIFT и точность на уровне байтов в sil-lift (см. ниже). API потоковой обработки возвращает _тот же самый_ тип `Entry`, поэтому нет необходимости осваивать вторую, упрощённую модель. ## Точность воспроизведения в обоих направлениях Самое явное намеренное отличие. При сохранении с помощью `SIL.Lift` происходит повторная сериализация всего документа. Компания «Sil-Lift» гарантирует: - неизменённый документ сохраняется **с идентичным количеством байтов**, и -- Неизмененные записи сохраняют свои исходные байты в точности, даже если другие записи изменяются (байтовое разбиение уровня Chorus, применяется автоматически). +- неизмененные записи сохраняют свои исходные байты в точности, даже если другие записи изменяются — это тот же принцип разбиения на байтовые блоки для каждой записи, который использует Chorus, и который применяется автоматически. См. [Гарантии Fidelity](fidelity.md). ## Валидация -Валидатор `Validator` на языке C# выполняет один проход по RELAX NG и возвращает первые ошибки в виде строк. sil-lift предоставляет структурированный по записям и строкам поток `Problem`, и его схема сознательно отличается в трёх местах: +Валидатор `Validator` на языке C# выполняет один проход по RELAX NG и возвращает первые ошибки в виде строк. sil-lift передаёт структурированный поток `Problem`, каждый элемент которого содержит информацию о файле, записи и строке, к которым он относится, при этом его схема намеренно отличается в трёх местах: - **Недопустимые URI являются предупреждениями, а не ошибками.** Движок C# RELAX NG никогда не обеспечивал соблюдение типа данных `anyURI`, поэтому FieldWorks (FLEx) на протяжении многих лет записывает ссылки `file://C:/...` в реальные лексиконы. Отказ от этих файлов привёл бы к отметке практически каждого экспорта из FLEx. - **Применяются правила Schematron** (в качестве семантических проверок): дублирующиеся языки форм и аналогичные совместные ограничения в грамматике LIFT без предупреждения игнорировались как при валидации на C#, так и при валидации с помощью исходного lxml. From 22f69e6bafb61320b38bc4589061c17087262b21 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:34 -0600 Subject: [PATCH 215/317] New translations csharp-differences.md (Chinese Simplified) [ci skip] --- docs/zh/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/zh/csharp-differences.md b/docs/zh/csharp-differences.md index b198e5d..9e8ab57 100644 --- a/docs/zh/csharp-differences.md +++ b/docs/zh/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift 与 SIL 的 C# LIFT 工具集大致类似——主要包括 [libpalaso] ## API 结构 -`SIL.Lift` 的解析器采用回调驱动模式(`ILexiconMerger`):它会将解析事件推送给消费者。 sil-lift 反而返回一个普通的对象图——每个 LIFT 元素对应一个带类型的数据类——因为 Python 脚本开发者需要的是对象,而不是回调函数。 `SIL.DictionaryServices` 确实在 `SIL.Lift`之上构建了一个 `LexEntry`/`LexSense` 对象模型,但作为应用程序模型,它仅代表这些应用程序所使用的结构——因此,通过它进行重新序列化无法像 sil-lift 的残留捕获和字节保真度那样保留模型之外的内容(详见下文)。 流式处理 API 返回的是_相同的_ `Entry` 类型,因此不存在功能受限的双生模型。 +`SIL.Lift` 的解析器采用回调驱动模式(`ILexiconMerger`):它会将解析事件推送给消费者。 sil-lift 反而返回一个普通的对象图——每个 LIFT 元素对应一个带类型的数据类——因为 Python 脚本开发者需要的是对象,而不是回调函数。 `SIL.DictionaryServices` 确实在 `SIL.Lift`之上构建了一个 `LexEntry`/`LexSense` 对象模型,但作为应用程序模型,它仅代表这些应用程序所使用的结构——因此,通过它进行重新序列化无法像 sil-lift 的 LIFT 残留处理和字节保真度那样保留模型之外的内容(详见下文)。 流式处理 API 返回的是_相同的_ `Entry` 类型,因此无需学习第二个精简版模型。 ## 往返保真度 最显著的刻意差异。 使用 `SIL.Lift` 保存时,会将整个文档重新序列化。 sil-lift 保证: - 未发生更改的文档在存储时**字节完全一致**,并且 -- 未被修改的条目即使在其他条目发生变化时,也会保留其原始字节内容(采用Chorus级别的字节分块技术,自动应用)。 +- 即使其他条目发生变化,未被修改的条目仍会保留其原始字节内容——这正是 Chorus 采用的、针对每个条目自动应用的字节分块机制。 请参阅[富达保证](fidelity.md)。 ## 验证 -C# 的 `Validator` 会执行一次 RELAX NG 验证,并将首次检测到的错误以字符串形式返回。 sil-lift 报告了一个结构化、按条目/行寻址的 `Problem` 流,其模式层在三个地方存在有意设计上的差异: +C# 的 `Validator` 会执行一次 RELAX NG 验证,并将首次检测到的错误以字符串形式返回。 sil-lift 报告了一个结构化的 `Problem` 流,其中每个 `Problem` 都包含其相关的文件、条目和行,且其模式层在三个地方有意进行了差异化处理: - **无效的 URI 属于警告,而非错误。** C# RELAX NG 引擎从未强制执行 `anyURI` 数据类型,因此 FieldWorks (FLEx) 多年来一直将 `file://C:/...` 格式的 href 写入实际词汇表中。 如果拒绝这些文件,几乎所有 FLEx 导出文件都会被标记。 - **Schematron 规则已强制执行**(作为语义检查):LIFT 语法中重复的表单语言和类似的协同约束,在 C# 和原生 lxml 验证中均被静默忽略。 From 6d88673c835eaffebd5d9beec4bbe661e77eb119 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:36 -0600 Subject: [PATCH 216/317] New translations csharp-differences.md (Hindi) [ci skip] --- docs/hi/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/hi/csharp-differences.md b/docs/hi/csharp-differences.md index a83703c..6e7719e 100644 --- a/docs/hi/csharp-differences.md +++ b/docs/hi/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift मोटे तौर पर SIL के C# LIFT टूलिंग क ## एपीआई आकार -`SIL.Lift` का पार्सर कॉलबैक-चालित (`ILexiconMerger`) है: यह पार्स इवेंट्स को एक कंज्यूमर पर पुश करता है। sil-lift इसके बजाय एक सादा ऑब्जेक्ट ग्राफ़ लौटाता है — प्रत्येक LIFT एलिमेंट के लिए टाइप्ड डेटाक्लासेस — क्योंकि पाइथन स्क्रिप्टर को कॉलबैक नहीं, ऑब्जेक्ट्स चाहिए। `SIL.DictionaryServices` `SIL.` पर एक `LexEntry`/`LexSense` ऑब्जेक्ट मॉडल की परत चढ़ाता है।Lift`पर एक`LexEntry`/`LexSense`ऑब्जेक्ट मॉडल की परत चढ़ाता है, लेकिन एक एप्लिकेशन मॉडल के रूप में यह केवल उन संरचनाओं का प्रतिनिधित्व करता है जिनका उपयोग वे ऐप्स करते हैं — इसलिए इसके माध्यम से पुनः सीरियलाइज़ करने पर मॉडल के बाहर की सामग्री को उसी तरह संरक्षित नहीं किया जा सकता जैसे sil-lift का अवशेष कैप्चर और बाइट निष्ठा करते हैं (नीचे देखें)। स्ट्रीमिंग एपीआई समान`Entry\` प्रकार ही प्रदान करता है, इसलिए कोई क्षमता-घटाया हुआ ट्विन मॉडल नहीं है। +`SIL.Lift` का पार्सर कॉलबैक-चालित (`ILexiconMerger`) है: यह पार्स इवेंट्स को एक कंज्यूमर पर पुश करता है। sil-lift इसके बजाय एक सादा ऑब्जेक्ट ग्राफ़ लौटाता है — प्रत्येक LIFT एलिमेंट के लिए टाइप्ड डेटाक्लासेस — क्योंकि पाइथन स्क्रिप्टर को कॉलबैक नहीं, ऑब्जेक्ट्स चाहिए। `SIL.DictionaryServices` `SIL.` पर एक `LexEntry`/`LexSense` ऑब्जेक्ट मॉडल की परत चढ़ाता है।Lift`पर एक`LexEntry`/`LexSense`ऑब्जेक्ट मॉडल की परत चढ़ाता है, लेकिन एक एप्लिकेशन मॉडल के रूप में यह केवल उन संरचनाओं का प्रतिनिधित्व करता है जिनका उपयोग वे एप्लिकेशन करते हैं — इसलिए इसके माध्यम से पुनः सीरियलाइज़ करने पर मॉडल के बाहर की सामग्री को sil-lift के LIFT अवशेष प्रबंधन और बाइट निष्ठा की तरह संरक्षित नहीं किया जा सकता (नीचे देखें)। स्ट्रीमिंग एपीआई वही`Entry\` प्रकार देता है, इसलिए सीखने के लिए कोई दूसरा, संक्षिप्त मॉडल नहीं है। ## गमन-आगमन निष्ठा सबसे मजबूत जानबूझकर किया गया अंतर। `SIL.Lift` के साथ सेव करने पर पूरा दस्तावेज़ पुनः सीरियलाइज़ हो जाता है। सिल-लिफ्ट गारंटियाँ: - एक अपरिवर्तित दस्तावेज़ **बाइट-समान रूप से** सहेजता है, और -- अछूटी प्रविष्टियाँ अपना सटीक स्रोत बाइट्स तब भी बनाए रखती हैं जब अन्य प्रविष्टियाँ बदलती हैं (कोरस-ग्रेड बाइट चंकिंग, स्वचालित रूप से लागू)। +- अछूटी प्रविष्टियाँ अपने सटीक स्रोत बाइट्स को तब भी बनाए रखती हैं जब अन्य प्रविष्टियाँ बदलती हैं — वही प्रति-प्रविष्टि बाइट चंकिंग जो Chorus उपयोग करता है, स्वचालित रूप से लागू होती है। देखें [फिडेलिटी गारंटी](fidelity.md)। ## प्रमाणीकरण -C# `Validator` एक RELAX NG पास चलाता है और पहली त्रुटियों को स्ट्रिंग्स के रूप में रिपोर्ट करता है। sil-lift एक संरचित, प्रविष्टि/पंक्ति-पते वाली `Problem` स्ट्रीम की रिपोर्ट करता है, और इसकी स्कीमा परत जानबूझकर तीन स्थानों पर विचलित होती है: +C# `Validator` एक RELAX NG पास चलाता है और पहली त्रुटियों को स्ट्रिंग्स के रूप में रिपोर्ट करता है। sil-lift एक संरचित `Problem` स्ट्रीम रिपोर्ट करता है, जिनमें से प्रत्येक में संबंधित फ़ाइल, प्रविष्टि और पंक्ति होती है, और इसकी स्कीमा परत जानबूझकर तीन स्थानों पर विचलित होती है: - अमान्य URI चेतावनियाँ हैं, त्रुटियाँ नहीं। C# RELAX NG इंजन ने कभी भी `anyURI` डेटाटाइप को लागू नहीं किया, इसलिए FieldWorks (FLEx) वर्षों से वास्तविक शब्दकोशों में `file://C:/...` hrefs लिख रहा है। उन फ़ाइलों को अस्वीकार करने से लगभग हर FLEx एक्सपोर्ट पर निशान लग जाएगा। - **Schematron नियम लागू किए जाते हैं** (सेमांटिक जांच के रूप में): LIFT व्याकरण में डुप्लिकेट फॉर्म भाषाओं और समान सह-बाधाओं को C# और कच्चे lxml सत्यापन दोनों द्वारा चुपचाप अनदेखा किया गया था। From cd29c36c4e7db942a5fc6d3aea4504848b551b17 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:38 -0600 Subject: [PATCH 217/317] New translations csharp-differences.md (Swahili) [ci skip] --- docs/sw/csharp-differences.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/sw/csharp-differences.md b/docs/sw/csharp-differences.md index 5237a55..53a05c7 100644 --- a/docs/sw/csharp-differences.md +++ b/docs/sw/csharp-differences.md @@ -14,20 +14,20 @@ sil-lift ni mfano hafifu wa zana za LIFT za C# za SIL — hasa `SIL.Lift` katika ## Umbo la API -Parser ya `SIL.Lift` inaendeshwa na callback (`ILexiconMerger`): inasukuma matukio ya uchanganuzi kwa mtumiaji. sil-lift badala yake hurudisha grafu ya vitu ya kawaida — dataclasses zilizotengwa aina kwa kila kipengele cha LIFT — kwa sababu watunzi wa skripti za Python wanataka vitu, si callbacks. `SIL.DictionaryServices` huweka juu ya `SIL.` mfano wa kitu wa `LexEntry`/`LexSense`Lift`, lakini kama mfano wa programu unawakilisha tu miundo ambayo programu hizo hutumia — hivyo kuirudisha tena katika muundo kupitia kwake haiwezi kuhifadhi maudhui yaliyo nje ya mfano kama vile sil-lift inavyofanya kwa kunasa mabaki na uaminifu wa baiti (tazama hapa chini). API ya utiririshaji hutoa aina ile ile ya `Entry\`, kwa hivyo hakuna mfano wa pacha uliopunguzwa uwezo. +Parser ya `SIL.Lift` inaendeshwa na callback (`ILexiconMerger`): inasukuma matukio ya uchanganuzi kwa mtumiaji. sil-lift badala yake hurudisha grafu ya vitu ya kawaida — dataclasses zilizotengwa aina kwa kila kipengele cha LIFT — kwa sababu watunzi wa skripti za Python wanataka vitu, si callbacks. `SIL.DictionaryServices` huweka juu ya `SIL.` mfano wa kitu wa `LexEntry`/`LexSense`Lift`, lakini kama mfano wa programu unawakilisha tu miundo inayotumiwa na programu hizo — hivyo kuirudisha tena katika muundo huu haiwezi kuhifadhi yaliyomo nje ya mfano kama vile usimamizi wa mabaki ya LIFT na uaminifu wa baiti wa sil-lift unavyofanya (tazama hapa chini). API ya utiririshaji hutoa aina ile ile ya `Entry\`, kwa hivyo hakuna modeli ya pili iliyopunguzwa ya kujifunza. ## Uaminifu wa safari ya kwenda na kurudi Tofauti iliyokusudiwa yenye nguvu zaidi. Kuhifadhi kwa kutumia `SIL.Lift` kunaserialisha tena hati nzima. sil-lift inahakikisha: - Hati isiyobadilika huhifadhi **byte-identically**, na -- Ningizo zisizoguswa huhifadhi baiti zao halisi za chanzo hata wakati nyingo zingine zinabadilika (Ugawaji wa baiti wa kiwango cha Chorus, unaotumika kiotomatiki). +- Maingizo yasiyoguswa huhifadhi baiti zao halisi za chanzo hata wakati maingizo mengine yanapobadilika — ni ukataji sawa wa baiti kwa kila ingizo unaotumiwa na Chorus, unaotumika kiotomatiki. Tazama [Dhamana za Fidelity](fidelity.md). ## Uthibitishaji -Validator ya C# hufanya upitaji mmoja wa RELAX NG na kuripoti makosa ya kwanza kama nyuzi. sil-lift inaripoti mtiririko wa `Problem` uliopangiliwa, wa kuingia/anwani-ya-mstari, na safu yake ya schema inakwenda njia tofauti kwa makusudi katika sehemu tatu: +Validator ya C# hufanya upitaji mmoja wa RELAX NG na kuripoti makosa ya kwanza kama nyuzi. sil-lift inaripoti mtiririko uliopangiliwa wa `Problem`, kila mmoja ukiwa na faili, kipengee, na mstari unaohusika, na safu yake ya skema inakwenda kinyume kwa makusudi katika sehemu tatu: - **URI zisizo halali ni maonyo, si makosa.** Injini ya C# RELAX NG haijawahi kulazimisha aina ya data `anyURI`, hivyo FieldWorks (FLEx) imekuwa ikiandika hrefs za `file://C:/...` katika kamusi halisi kwa miaka mingi. Kukataa faili hizo kungeweka alama karibu kila toleo la FLEx. - **Kanuni za Schematron zinatekelezwa** (kama ukaguzi wa kisemantiki): lugha za fomu zilizorudiwa na vikwazo vinavyofanana katika sarufi ya LIFT vilipuuzwa kimya kimya na C# na uthibitishaji wa lxml ghafi. From 44c84ba076edd92c1df22897c4f26c997df9e001 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:39 -0600 Subject: [PATCH 218/317] New translations fidelity.md (French) [ci skip] --- docs/fr/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/fr/fidelity.md b/docs/fr/fidelity.md index c8241af..0be4e1b 100644 --- a/docs/fr/fidelity.md +++ b/docs/fr/fidelity.md @@ -1,10 +1,10 @@ # Garanties de fidélité -LIFT est un format d'_échange_ : la règle d'or est de **ne jamais omettre ce que l'on ne comprend pas**. Le contrat de `sil-lift`, vérifié par la suite de tests à chaque exécution (fichiers de corpus et génération basée sur les propriétés) : +LIFT est un format d'_échange_ ; la première règle est donc de **ne jamais ignorer ce que vous ne comprenez pas**. Le contrat de `sil-lift`, vérifié par la suite de tests à chaque exécution (fichiers de corpus et génération basée sur les propriétés) : ## Lecture -Tout document LIFT 0.13 bien formé se charge, même s'il contient du contenu non conforme au schéma. Tout ce qui n'est pas défini par le modèle est stocké dans le compartiment opaque `Extras` du nœud le plus proche : attributs et éléments inconnus, commentaires XML et instructions de traitement, texte isolé, ainsi que les attributs typés mal formés (une date incorrecte reste sous forme de chaîne d'origine dans `Extras` ; le champ typé prend la valeur `None`). +Tout document LIFT 0.13 bien formé se charge, même s'il contient du contenu non conforme au schéma. Tout ce qui n’est pas défini par le modèle est transféré dans le conteneur opaque `Extras` du nœud le plus proche sous la forme d’un « résidu LIFT » — nom donné par FieldWorks à ce concept, qu’il stocke dans un champ `LiftResidue` : attributs et éléments inconnus, commentaires XML et instructions de traitement, texte parasite et attributs typés mal formés (une date incorrecte reste sous forme de chaîne d’origine dans `Extras` ; le champ de type est `None`). ## Enregistrer un document sans modification @@ -14,7 +14,7 @@ Exceptions (le programme de lecture revient à la sérialisation canonique compl - le codage source n'est pas compatible ASCII (il ne s'agit ni d'UTF-8 ni d'US-ASCII), ou - le code source contient une déclaration DOCTYPE, ou -- le scanner d'octets et l'analyseur syntaxique ne s'accordent pas sur la structure de premier niveau du document — par exemple, un deuxième `
` non conforme à la spécification, que l'analyseur syntaxique ne conserve qu'une seule fois (le scanner se montre délibérément méfiant : le moindre doute l'amène à ne capturer aucun octet source), ou +- le scanner d'octets et l'analyseur syntaxique ne s'accordent pas sur la structure de haut niveau du document — par exemple, un deuxième `
` non conforme à la spécification, que l'analyseur syntaxique ne conserve qu'une seule fois (le scanner est délibérément prudent : en cas de doute, il ne capture aucun octet de la source), ou - le code source a été généré en mémoire plutôt que chargé à partir d'un fichier. ## Enregistrer un document modifié @@ -23,8 +23,11 @@ Exceptions (le programme de lecture revient à la sérialisation canonique compl - **Les entrées modifiées sont resérialisées de manière canonique et complète** : UTF-8, indentation à 2 espaces _en dehors_ du contenu mixte (les espaces à l'intérieur de `` et `` ne sont jamais modifiés), un regroupement des éléments enfants documenté pour chaque élément (par exemple, entrée : unité lexicale, citation, prononciations, variantes, sens, notes, relations, étymologies, annotations, traits, champs), ordre fixe des attributs, dates au format ISO-8601 (`Z` pour l'UTC). Tous les résidus sont réémis ; leur position est rétablie dans l'index enfant d'origine, en étant ancrée à la nouvelle liste des enfants (il s'agit d'une approximation — les positions exactes en octets ne sont garanties que pour les entrées non modifiées). - L'ajout, la suppression ou le réordonnancement d'entrées entraîne une nouvelle sérialisation de la structure du document, mais les octets de chaque entrée inchangée sont toujours restitués à l'identique. +!!! note ""Le fichier XML canonique" ne fait référence à aucun autre fichier XML canonique." + Sur cette page, on entend par « forme canonique » la forme propre à `sil-lift`, telle qu'elle est décrite dans l'un des points ci-dessus. Cela n'a aucun rapport avec le processus « Canonical XML (C14N) » du W3C. Cela n'a aucun rapport avec la classe `CanonicalXmlSettings` de `SIL.Core`. + ## Approximations connues (nœuds touchés uniquement) -- Les commentaires situés _à l'intérieur_ d'une exécution `` sont conservés, mais déplacés à côté de l'exécution, et non à leur position exacte en caractères. +- Les commentaires situés _à l'intérieur_ d'une exécution `` sont conservés, mais déplacés à côté de l'exécution, et non pas maintenus à leur position exacte dans le texte. - L'ordre croisé des enfants au sein d'un élément modifié est normalisé selon le regroupement canonique (la propriété `interleave` du schéma LIFT rend cet ordre sans importance sur le plan sémantique). - Un élément multitext présent mais ne contenant rien — ni forme, ni résidu, par exemple `` — n'est pas réémis. Le modèle représente ces champs sous la forme d'un `Multitext` toujours présent (`lexical-unit`, `citation`, `definition`, l'`usage` d'une relation et `label` / `abbrev` / `description` sur les références URL, les intervalles, les éléments d’intervalle et l’en-tête), de sorte qu’un champ vide est impossible à distinguer d’un champ absent après analyse. Il n'y a aucune perte sémantique. From 24627082bb25683b834bf48264874cdf7e3a810c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:41 -0600 Subject: [PATCH 219/317] New translations fidelity.md (Spanish) [ci skip] --- docs/es/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/es/fidelity.md b/docs/es/fidelity.md index 666fe84..d7e7874 100644 --- a/docs/es/fidelity.md +++ b/docs/es/fidelity.md @@ -1,10 +1,10 @@ # Garantías de Fidelity -LIFT es un formato de _intercambio_: la regla fundamental es **no descartar nunca lo que no se entiende**. El contrato de `sil-lift`, verificado por el conjunto de pruebas en cada ejecución (archivos del corpus más generación basada en propiedades): +LIFT es un formato de _intercambio_, por lo que la primera regla es **no descartar nunca lo que no entiendas**. El contrato de `sil-lift`, verificado por el conjunto de pruebas en cada ejecución (archivos del corpus más generación basada en propiedades): ## Lectura -Cualquier documento LIFT 0.13 bien formado se carga, incluso si el contenido no cumple con el esquema. Todo aquello que el modelo no defina se almacena en el contenedor opaco `Extras` del nodo más cercano: atributos y elementos desconocidos, comentarios XML e instrucciones de procesamiento, texto aislado y atributos tipados con formato incorrecto (una fecha incorrecta se mantiene como la cadena original en `Extras`; el campo tipado es `None`). +Cualquier documento LIFT 0.13 bien formado se carga, incluso si el contenido no cumple con el esquema. Todo aquello que el modelo no defina se traslada al contenedor opaco `Extras` del nodo más cercano como _residuo LIFT_ —nombre que utiliza FieldWorks para referirse a este mismo concepto, y que almacena en un campo `LiftResidue`—: atributos y elementos desconocidos, comentarios XML e instrucciones de procesamiento, texto extrañado y atributos tipificados mal formados (una fecha incorrecta se mantiene como la cadena original en `Extras`; el campo tipado es `None`). ## Guardar un documento sin modificaciones @@ -14,7 +14,7 @@ Excepciones (el escritor recurre a la serialización canónica completa, que es - la codificación de origen no es compatible con ASCII (no es UTF-8/US-ASCII), o - el código fuente contiene un DOCTYPE, o -- el escáner de bytes y el analizador sintáctico no coinciden en cuanto a la estructura de nivel superior del documento —por ejemplo, un segundo `
` que no cumple con la especificación, que el analizador sintáctico conserva solo una vez (el escáner es deliberadamente cauteloso: ante cualquier duda, no captura ningún byte del código fuente)—, o +- el escáner de bytes y el analizador sintáctico no coinciden en cuanto a la estructura de nivel superior del documento —por ejemplo, un segundo `
` que no cumple con las especificaciones, que el analizador sintáctico conserva solo una vez (el escáner es deliberadamente conservador: ante cualquier duda, no captura ningún byte del código fuente)—, o - El código fuente se compiló en memoria, en lugar de cargarse desde un archivo. ## Guardar un documento editado @@ -23,8 +23,11 @@ Excepciones (el escritor recurre a la serialización canónica completa, que es - **Las entradas modificadas se vuelven a serializar de forma canónica y completa**: UTF-8, sangría de 2 espacios _fuera_ del contenido mixto (los espacios en blanco dentro de `` y `` nunca se modifican), una agrupación de elementos secundarios documentada por cada elemento (p. ej., entrada: unidad léxica, cita, pronunciaciones, variantes, acepciones, notas, relaciones, etimologías, anotaciones, rasgos, campos), orden fijo de los atributos, fechas en formato ISO-8601 (`Z` para UTC). Todos los residuos se vuelven a emitir; su posición se restablece en el índice secundario original, vinculada a la nueva lista secundaria (se trata de una aproximación: las posiciones exactas en bytes solo se garantizan para las entradas que no se han modificado). - Al añadir, eliminar o reordenar entradas, se vuelve a serializar la estructura del documento, pero se siguen emitiendo tal cual los bytes de cada entrada que no haya sufrido cambios. +!!! note ""El XML canónico" que aparece aquí no está relacionado con ningún otro XML canónico." + En esta página, por «forma canónica» se entiende la forma documentada propia de «sil-lift», descrita en uno de los puntos anteriores. No guarda relación alguna con el proceso «Canonical XML (C14N)» del W3C. No tiene nada que ver con la clase `CanonicalXmlSettings` de `SIL.Core`. + ## Aproximaciones conocidas (solo nodos tocados) -- Los comentarios que se encuentran _dentro_ de una ejecución de `` se conservan, pero se desplazan hasta situarse junto a la ejecución, y no en su posición exacta según el número de caracteres. +- Los comentarios que se encuentran _dentro_ de una ejecución de `` se conservan, pero se trasladan junto a la ejecución, en lugar de mantenerse en su posición exacta en caracteres. - El orden de subelementos de tipo «cross» dentro de un elemento editado se normaliza según la agrupación canónica (la propiedad `interleave` del esquema LIFT hace que este orden carezca de importancia semántica). - Un elemento multitexto que está presente pero que no contiene nada —ni formas, ni residuos—, por ejemplo, ``, no se vuelve a emitir. El modelo representa estos campos como un `Multitext` siempre presente (`lexical-unit`, `citation`, `definition`, el `usage` de una relación y `label` / `abreviatura` / `descripción` en referencias URL, rangos, elementos de rango y el encabezado), por lo que uno vacío es indistinguible de uno ausente tras el análisis sintáctico. No se pierde nada a nivel semántico. From 951dbe499ab15091144560cc9c9c2ab425fa09fb Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:43 -0600 Subject: [PATCH 220/317] New translations fidelity.md (Arabic) [ci skip] --- docs/ar/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/ar/fidelity.md b/docs/ar/fidelity.md index fe799a7..ca15f5a 100644 --- a/docs/ar/fidelity.md +++ b/docs/ar/fidelity.md @@ -1,10 +1,10 @@ # ضمانات فيديليتي -LIFT هو تنسيق _تبادل_: والقاعدة الأساسية هي **ألا تتجاهل أبدًا ما لا تفهمه**. عقد `sil-lift`، الذي يتم التحقق من صحته بواسطة مجموعة الاختبارات في كل عملية تشغيل (ملفات المجموعة بالإضافة إلى التوليد القائم على الخصائص): +LIFT هو تنسيق _تبادل_، لذا فإن القاعدة الأولى هي **ألا تتجاهل أبدًا ما لا تفهمه**. عقد `sil-lift`، الذي يتم التحقق من صحته بواسطة مجموعة الاختبارات في كل عملية تشغيل (ملفات المجموعة بالإضافة إلى التوليد القائم على الخصائص): ## القراءة -يتم تحميل أي مستند LIFT 0.13 صحيح التكوين — بما في ذلك المحتوى غير المتوافق مع المخطط. كل ما لا يحدده النموذج يتم نقله إلى حاوية `Extras` غير الشفافة في أقرب عقدة: السمات والعناصر غير المعروفة، وتعليقات XML وتعليمات المعالجة، والنصوص المتناثرة، والسمات المحددة النوع ذات التنسيق الخاطئ (يُحتفظ بالتاريخ غير الصحيح كسلسلة نصية أصلية في `Extras`؛ ويكون الحقل المحدد النوع هو `None`). +يتم تحميل أي مستند LIFT 0.13 صحيح التكوين — بما في ذلك المحتوى غير المتوافق مع المخطط. كل ما لا يحدده النموذج يتم نقله في حاوية `Extras` غير الشفافة الخاصة بالعقدة الأقرب باعتباره _بقايا LIFT_ — وهو الاسم الذي تستخدمه FieldWorks للإشارة إلى نفس المفهوم، والذي يتم تخزينه في حقل `LiftResidue`: السمات والعناصر غير المعروفة، وتعليقات XML وتعليمات المعالجة، والنصوص المتناثرة، والسمات المكتوبة ذات التنسيق الخاطئ (يُحتفظ بالتاريخ غير الصحيح كسلسلة نصية أصلية في `Extras`؛ ويكون الحقل المكتوب `None`). ## حفظ مستند لم يتم تغييره @@ -14,7 +14,7 @@ LIFT هو تنسيق _تبادل_: والقاعدة الأساسية هي **أل - ترميز المصدر غير متوافق مع ASCII (ليس UTF-8/US-ASCII)، أو - يحتوي الملف المصدر على تعريف نوع المستند (DOCTYPE)، أو -- يختلف كل من الماسح البايت والمحلل حول البنية العليا للوثيقة — على سبيل المثال، وجود `
` ثانية خارج المواصفات، والتي يحتفظ بها المحلل مرة واحدة فقط (أما الماسح فيتخذ موقفًا متشككًا عن عمد: فأي شك يعني عدم التقاط أي بايتات من المصدر على الإطلاق)، أو +- يختلف كل من الماسح البايت والمحلل حول البنية العليا للوثيقة — على سبيل المثال، وجود `
` ثانية خارج المواصفات، والتي يحتفظ بها المحلل مرة واحدة فقط (أما الماسح فهو متحفظ عن عمد: ففي حالة وجود أي شك، لا يلتقط أي بايتات من المصدر على الإطلاق)، أو - تم إنشاء المصدر في الذاكرة بدلاً من تحميله من ملف. ## حفظ مستند تم تحريره @@ -23,8 +23,11 @@ LIFT هو تنسيق _تبادل_: والقاعدة الأساسية هي **أل - **يتم إعادة تسلسل المدخلات التي تم تعديلها بشكل قياسي وكامل**: UTF-8، مسافة بادئة بمقدار مسافتين _خارج_ المحتوى المختلط (لا يتم تغيير المسافات البيضاء داخل `` و`` أبدًا)، وتجميع فرعي موثق لكل عنصر (على سبيل المثال، المدخل: الوحدة اللغوية، الاقتباس، طرق النطق، المتغيرات، المعاني، الملاحظات، العلاقات، أصول الكلمات، التعليقات التوضيحية، السمات، الحقول)، ترتيب ثابت للسمات، التواريخ وفقًا لمعيار ISO-8601 (حرف `Z` لـ UTC). يتم إعادة إصدار جميع البقايا؛ ويتم إعادة وضعها في الفهرس الفرعي الأصلي، مع ربطها بالقائمة الفرعية الجديدة (وهذا تقريب — فالمواضع الدقيقة بالبايت مضمونة فقط للمدخلات التي لم يتم التعديل فيها). - تؤدي إضافة العناصر أو حذفها أو إعادة ترتيبها إلى إعادة تسلسل بنية المستند، لكنها تظل تُخرج بايتات كل عنصر لم يتغير حرفياً. +!!! note ""ملف XML القياسي" المذكور هنا لا علاقة له بأي ملف XML قياسي آخر" + يُقصد بالصيغة القياسية في هذه الصفحة الشكل الموثق الخاص بـ «sil-lift»، والموصوف في إحدى النقاط أعلاه. ولا علاقة له بعملية «Canonical XML (C14N)» التابعة لـ W3C. ولا علاقة له بفئة `CanonicalXmlSettings` التابعة لـ `SIL.Core`. + ## التقريبات المعروفة (العقد التي تم لمسها فقط) -- يتم الاحتفاظ بالتعليقات الموجودة _داخل_ عملية تشغيل ``، ولكن يتم رفعها لتظهر بجوار عملية التشغيل، وليس في موضعها الدقيق من حيث عدد الأحرف. +- يتم الاحتفاظ بالتعليقات الموجودة _داخل_ عملية تشغيل ``، لكن يتم نقلها إلى جانب عملية التشغيل، ولا يتم الاحتفاظ بها في موضعها الدقيق من حيث عدد الأحرف. - يتم توحيد ترتيب العناصر الفرعية من النوع «المتقاطع» داخل عنصر تم تعديله وفقًا للتجميع القياسي (تجعل خاصية `interleave` في مخطط LIFT هذا الترتيب غير ذي أهمية من الناحية الدلالية). - لا يتم إعادة إصدار عنصر متعدد النصوص موجود ولكنه لا يحمل أي شيء — لا نماذج ولا بقايا، على سبيل المثال `` —. يمثل النموذج هذه الحقول على شكل `Multitext` موجود دائمًا (`lexical-unit`، و`citation`، و`definition`، و`usage` للعلاقة، و`label` / `abbrev` / `description` في مراجع عناوين الويب، والنطاقات، وعناصر النطاق، والعنوان)، لذا لا يمكن التمييز بين النموذج الفارغ والنموذج الغائب بعد التحليل. لا يُفقد أي شيء من الناحية الدلالية. From 18529ab0641ff112ee60e1c5dc708e55f09e86d2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:44 -0600 Subject: [PATCH 221/317] New translations fidelity.md (German) [ci skip] --- docs/de/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/de/fidelity.md b/docs/de/fidelity.md index 8438436..f01deb2 100644 --- a/docs/de/fidelity.md +++ b/docs/de/fidelity.md @@ -1,10 +1,10 @@ # Fidelity-Garantien -LIFT ist ein _Austauschformat_: Die oberste Regel lautet: **Lass niemals etwas weg, was du nicht verstehst**. Der Vertrag von `sil-lift`, der bei jedem Durchlauf durch die Testsuite überprüft wird (Korpusdateien sowie eigenschaftsbasierte Generierung): +LIFT ist ein _Austauschformat_, daher lautet die erste Regel: **Lass niemals etwas weg, was du nicht verstehst**. Der Vertrag von `sil-lift`, der bei jedem Durchlauf durch die Testsuite überprüft wird (Korpusdateien sowie eigenschaftsbasierte Generierung): ## Lesen -Jedes wohlgeformte LIFT 0.13-Dokument wird geladen – auch Inhalte, die nicht dem Schema entsprechen. Alles, was das Modell nicht definiert, wird im „Extras“-Bereich des nächstgelegenen Knotens gespeichert: unbekannte Attribute und Elemente, XML-Kommentare und Verarbeitungsanweisungen, überflüssiger Text sowie fehlerhaft formatierte typisierte Attribute (ein fehlerhaftes Datum bleibt als ursprüngliche Zeichenkette in „Extras“ erhalten; das typisierte Feld ist „None“). +Jedes wohlgeformte LIFT 0.13-Dokument wird geladen – auch Inhalte, die nicht dem Schema entsprechen. Alles, was das Modell nicht definiert, wird im opaken `Extras`-Container des nächstgelegenen Knotens als _LIFT-Residuum_ gespeichert – so nennt FieldWorks dieses Konzept, das in einem `LiftResidue`-Feld abgelegt wird: unbekannte Attribute und Elemente, XML-Kommentare und Verarbeitungsanweisungen, verstreuter Text sowie fehlerhaft formatierte typisierte Attribute (ein fehlerhaftes Datum verbleibt als ursprüngliche Zeichenkette in `Extras`; das typisierte Feld ist `None`). ## Ein unverändertes Dokument speichern @@ -14,7 +14,7 @@ Ausnahmen (der Writer greift auf die vollständige kanonische Serialisierung zur - die Quellkodierung ist nicht ASCII-kompatibel (nicht UTF-8/US-ASCII) oder - der Quelltext enthält einen DOCTYPE oder -- Der Byte-Scanner und der Parser sind sich hinsichtlich der obersten Struktur des Dokuments nicht einig – beispielsweise bei einem nicht spezifikationskonformen zweiten `
`, den der Parser nur einmal beibehält (der Scanner ist bewusst misstrauisch: Bei jedem Zweifel werden überhaupt keine Quellbytes erfasst), oder +- Der Byte-Scanner und der Parser sind sich hinsichtlich der obersten Struktur des Dokuments nicht einig – beispielsweise bei einem nicht spezifikationskonformen zweiten `
`, den der Parser nur einmal beibehält (der Scanner ist bewusst konservativ: Im Zweifelsfall erfasst er überhaupt keine Quell-Bytes), oder - Der Quellcode wurde im Speicher erstellt und nicht aus einer Datei geladen. ## Ein bearbeitetes Dokument speichern @@ -23,8 +23,11 @@ Ausnahmen (der Writer greift auf die vollständige kanonische Serialisierung zur - **Die bearbeiteten Einträge werden kanonisch und vollständig neu serialisiert**: UTF-8, Einrückung mit zwei Leerzeichen _außerhalb_ von gemischtem Inhalt (Leerzeichen innerhalb von `` und `` werden niemals verändert), eine dokumentierte Untergruppierung pro Element (z. B. Eintrag: lexikalische Einheit, Zitat, Aussprachen, Varianten, Bedeutungen, Anmerkungen, Beziehungen, Etymologien, Annotationen, Merkmale, Felder), feste Attributreihenfolge, Datumsangaben nach ISO-8601 (`Z` für UTC). Alle Reste werden erneut ausgegeben; ihre Position wird auf den ursprünglichen Unterindex zurückgesetzt und an die neue Unterliste angepasst (eine Annäherung – exakte Byte-Positionen sind nur für unveränderte Einträge garantiert). - Das Hinzufügen, Entfernen oder Neuanordnen von Einträgen führt zu einer erneuten Serialisierung der Dokumentstruktur, wobei die Bytes jedes unveränderten Eintrags jedoch unverändert ausgegeben werden. +!!! note ""Die Canonical-" -Datei hier steht in keinem Zusammenhang mit anderen Canonical-XML-Dateien." + Unter „kanonischer Form“ wird auf dieser Seite die in einem der obigen Aufzählungspunkte beschriebene, von `sil-lift` selbst dokumentierte Form verstanden. Dies steht in keinem Zusammenhang mit dem „Canonical XML (C14N)“-Prozess des W3C. Es steht in keinem Zusammenhang mit der Klasse `CanonicalXmlSettings` von `SIL.Core`. + ## Bekannte Näherungswerte (nur berührte Knoten) -- Kommentare _innerhalb_ eines ``-Laufs bleiben erhalten, werden jedoch neben den Lauf verschoben und nicht an ihrer genauen Zeichenposition angezeigt. +- Kommentare _innerhalb_ eines ``-Laufs bleiben erhalten, werden jedoch neben den Lauf verschoben und nicht an ihrer genauen Zeichenposition beibehalten. - Die kreuzförmige Reihenfolge der untergeordneten Elemente innerhalb eines bearbeiteten Elements wird auf die kanonische Gruppierung normiert (durch das `interleave`-Schema des LIFT-Schemas wird diese Reihenfolge semantisch irrelevant). - Ein Multitext-Element, das zwar vorhanden ist, aber nichts enthält – weder Formen noch Reste, z. B. `` – wird nicht erneut ausgegeben. Das Modell stellt diese Felder als stets vorhandenes `Multitext` dar (`lexical-unit`, `citation`, `definition`, die `usage` einer Relation sowie `label` / `abbrev` / `description` bei URL-Verweisen, Bereichen, Bereichselementen und der Kopfzeile) dar, sodass sich ein leeres Feld nach der Analyse nicht von einem fehlenden unterscheiden lässt. Es geht keine semantische Information verloren. From 7e2e46d48e3df9dc80551fd83c4e16cc78f1abb2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:46 -0600 Subject: [PATCH 222/317] New translations fidelity.md (Japanese) [ci skip] --- docs/ja/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/ja/fidelity.md b/docs/ja/fidelity.md index ea97f18..e3dcde2 100644 --- a/docs/ja/fidelity.md +++ b/docs/ja/fidelity.md @@ -1,10 +1,10 @@ # フィデリティの保証 -LIFTは_相互運用_フォーマットです。その鉄則は、**理解できないものは決して削除しない**ということです。 `sil-lift`の契約。これは、実行のたびにテストスイートによって検証されます(コーパスファイルおよびプロパティベースの生成)。 +LIFTは_相互運用_フォーマットであるため、最初のルールは**理解できないものは決して削除しない**ことです。 `sil-lift`の契約。これは、実行のたびにテストスイートによって検証されます(コーパスファイルおよびプロパティベースの生成)。 ## 読書 -正しく構成された LIFT 0.13 ドキュメントであれば、スキーマに違反するコンテンツが含まれていても読み込まれます。 モデルで定義されていないものはすべて、最も近いノードの不透明な `Extras` バケットに格納されます。これには、未知の属性や要素、XML コメントや処理命令、不要なテキスト、および形式不備の型付き属性などが含まれます(不正な日付は、`Extras` 内に元の文字列のまま残され、型付きフィールドは `None` となります)。 +正しく構成された LIFT 0.13 ドキュメントであれば、スキーマに違反するコンテンツが含まれていても読み込まれます。 モデルで定義されていないものはすべて、最も近いノードの不透明な `Extras` コンテナに _LIFT 残余_ として格納されます。これは FieldWorks が同じ概念に対して用いる名称であり、`LiftResidue` フィールドに保存されます。これには、未知の属性や要素、XML コメントや処理命令、不要なテキスト、および形式不備の型付き属性などが含まれます (不正な日付は、`Extras`内に元の文字列のまま残され、型付きフィールドは`None`となります)。 ## 変更のない文書を保存する @@ -14,7 +14,7 @@ LIFTは_相互運用_フォーマットです。その鉄則は、**理解でき - ソースのエンコーディングがASCII互換ではない(UTF-8/US-ASCIIではない)、または - ソースにDOCTYPEが含まれているか、または -- バイトスキャナとパーサーの間で、ドキュメントの最上位構造に関する認識が一致しない――例えば、仕様外の2つ目の `
` などである。パーサーはこれを1回だけ保持するが(スキャナは意図的に慎重であり、少しでも疑わしい場合はソースバイトを一切取得しない)、あるいは +- バイトスキャナとパーサーの間で、ドキュメントの最上位構造に関する認識に相違がある。例えば、仕様外の2つ目の `
` がある場合、パーサーはこれを1回だけ保持するが(スキャナは意図的に保守的であり、疑わしい場合はソースバイトを一切取得しない)、あるいは - ソースはファイルから読み込まれるのではなく、メモリ上で構築されました。 ## 編集したドキュメントの保存 @@ -23,8 +23,11 @@ LIFTは_相互運用_フォーマットです。その鉄則は、**理解でき - **変更されたエントリは、標準的な形式で完全に再シリアライズされます**:UTF-8、混合コンテンツの_外部_での2スペースのインデント(``および``内部の空白は一切変更されません)、要素ごとの文書化された子要素のグループ化(例:エントリ: 語彙単位、引用、発音、異形、意味、注釈、関係、語源、注釈、特徴、分野)、固定された属性順序、ISO-8601形式の日付(UTCの場合は`Z`)。 すべての残余データは再出力され、その位置は元の子インデックスに戻され、新しい子リストにクリップされます(これは近似処理であり、変更されていないエントリについてのみ、正確なバイト位置が保証されます)。 - エントリの追加、削除、または順序変更を行うと、ドキュメント構造は再シリアル化されますが、変更されていないエントリのバイトデータはすべてそのまま出力されます。 +!!! note ""ここでいう「Canonical" 」は、他のどのCanonical XMLとも関係ありません。" + このページにおける「標準形」とは、上記の箇条書きで説明されている、`sil-lift`独自の文書化された形状を指します。 これは、W3CのCanonical XML(C14N)プロセスとは無関係です。 これは、`SIL.Core` の `CanonicalXmlSettings` クラスとは無関係です。 + ## 既知の近似値(接触したノードのみ) -- `` の実行の `内部` にあるコメントは保持されますが、正確な文字オフセットの位置ではなく、その実行のすぐ隣に持ち上げられます。 +- `` の実行の `内部` にあるコメントは保持されますが、正確な文字オフセットの位置には残されず、その実行の隣に移動されます。 - 編集対象の要素内におけるクロス型の子要素の順序は、正規のグループ化に正規化されます(LIFTスキーマの `interleave` により、この順序は意味的に無意味となります)。 - 存在はするが、フォームも残留物も一切含まないマルチテキスト要素(例:``)は、再出力されません。 このモデルでは、これらのフィールドを常に存在する `Multitext` として表現しています(`lexical-unit`、`citation`、`definition`、関係の `usage`、およびヘッダーの `label` / `abbrev` / `description`)として常に存在する `Multitext` として表現しているため、解析後は空の `Multitext` と存在しない `Multitext` を区別することができません。 意味的な情報は一切失われません。 From 8a53b0f837af3ecdefc8b8f815887526076de40c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:48 -0600 Subject: [PATCH 223/317] New translations fidelity.md (Portuguese) [ci skip] --- docs/pt/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/pt/fidelity.md b/docs/pt/fidelity.md index f96dc5b..51c71b3 100644 --- a/docs/pt/fidelity.md +++ b/docs/pt/fidelity.md @@ -1,10 +1,10 @@ # Garantias de fidelidade -O LIFT é um formato de _intercâmbio_: a regra fundamental é **nunca descartar aquilo que não se compreende**. O contrato do `sil-lift`, verificado pelo conjunto de testes em cada execução (ficheiros de corpus e geração baseada em propriedades): +O LIFT é um formato de _intercâmbio_, pelo que a primeira regra é **nunca ignorar aquilo que não compreendes**. O contrato do `sil-lift`, verificado pelo conjunto de testes em cada execução (ficheiros de corpus e geração baseada em propriedades): ## Leitura -Qualquer documento LIFT 0.13 bem formado é carregado — mesmo que inclua conteúdo inválido em termos de esquema. Tudo o que o modelo não definir é transportado para o conjunto opaco `Extras` do nó mais próximo: atributos e elementos desconhecidos, comentários XML e instruções de processamento, texto disperso e atributos tipados com formato incorreto (uma data inválida permanece como a cadeia de caracteres original em `Extras`; o campo tipado é `None`). +Qualquer documento LIFT 0.13 bem formado é carregado — mesmo que inclua conteúdo inválido em termos de esquema. Tudo o que o modelo não definir é transportado no contentor opaco `Extras` do nó mais próximo como _resíduo LIFT_ — nome dado pelo FieldWorks a este conceito, que é armazenado num campo `LiftResidue`: atributos e elementos desconhecidos, comentários XML e instruções de processamento, texto disperso e atributos tipados malformados (uma data inválida permanece como a cadeia de caracteres original em `Extras`; o campo tipado é `None`). ## Guardar um documento sem alterações @@ -14,7 +14,7 @@ Exceções (o gravador recorre à serialização canónica completa, que é sema - a codificação da fonte não é compatível com ASCII (não é UTF-8/US-ASCII), ou - o código-fonte contém um DOCTYPE, ou -- o scanner de bytes e o analisador não estão de acordo quanto à estrutura de nível superior do documento — por exemplo, um segundo `
` fora das especificações, que o analisador mantém apenas uma vez (o scanner é deliberadamente cauteloso: qualquer dúvida significa não capturar nenhum byte da fonte), ou +- o scanner de bytes e o analisador não estão de acordo quanto à estrutura de nível superior do documento — por exemplo, um segundo `
` fora das especificações, que o analisador mantém apenas uma vez (o scanner é deliberadamente conservador: em caso de dúvida, não captura quaisquer bytes da fonte), ou - o código-fonte foi compilado na memória, em vez de ser carregado a partir de um ficheiro. ## Guardar um documento editado @@ -23,8 +23,11 @@ Exceções (o gravador recorre à serialização canónica completa, que é sema - **As entradas alteradas são re-serializadas de forma canónica e completa**: UTF-8, indentação com 2 espaços _fora_ do conteúdo misto (os espaços dentro de `` e `` nunca são alterados), um agrupamento de elementos filhos documentado por elemento (por exemplo, entrada: unidade lexical, citação, pronúncias, variantes, sentidos, notas, relações, etimologias, anotações, características, campos), ordem fixa dos atributos, datas em ISO-8601 (`Z` para UTC). Todos os resíduos são reemitidos; a sua posição é restaurada no índice filho original, limitada à nova lista de filhos (uma aproximação — as posições exatas em bytes só são garantidas para entradas que não foram alteradas). - Adicionar, remover ou reordenar entradas faz com que a estrutura do documento seja novamente serializada, mas continua a emitir, tal como estão, os bytes de todas as entradas que não sofreram alterações. +!!! note ""O XML canónico" aqui apresentado não está relacionado com nenhum outro XML canónico" + A forma canónica nesta página refere-se à forma documentada do próprio `sil-lift`, descrita num ponto anterior. Não tem qualquer relação com o processo «Canonical XML» (C14N) do W3C. Não tem qualquer relação com a classe `CanonicalXmlSettings` do `SIL.Core`. + ## Aproximações conhecidas (apenas nós tocados) -- Os comentários _dentro_ de uma execução `` são preservados, mas são deslocados para junto da execução, e não para a sua posição exata em termos de caracteres. +- Os comentários _dentro_ de uma execução `` são preservados, mas são movidos para junto da execução, não sendo mantidos na sua posição exata em termos de caracteres. - A ordem cruzada de elementos filhos dentro de um elemento editado é normalizada para o agrupamento canónico (o `interleave` do esquema LIFT torna esta ordem semanticamente insignificante). - Um elemento multitext que esteja presente mas que não contenha nada — nem formas, nem resíduos, por exemplo, `` — não é reemitido. O modelo representa estes campos como um `Multitext` sempre presente (`unidade-lexical`, `citação`, `definição`, o `uso` de uma relação e `rótulo` / `abbrev` / `description` em referências de URL, intervalos, elementos de intervalo e no cabeçalho), pelo que um campo vazio é indistinguível de um ausente após a análise. Não se perde nada em termos semânticos. From ab04d1148efa9558d44b28e2d35ba8c416b38bab Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:49 -0600 Subject: [PATCH 224/317] New translations fidelity.md (Russian) [ci skip] --- docs/ru/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/ru/fidelity.md b/docs/ru/fidelity.md index 217c404..9069ff1 100644 --- a/docs/ru/fidelity.md +++ b/docs/ru/fidelity.md @@ -1,10 +1,10 @@ # Гарантии Fidelity -LIFT — это формат _обмена данными_: главное правило — **никогда не удалять то, чего не понимаешь**. Контракт `sil-lift`, проверка которого осуществляется набором тестов при каждом запуске (файлы корпуса плюс генерация на основе свойств): +LIFT — это _промежуточный_ формат, поэтому первое правило гласит: **никогда не удаляйте то, чего не понимаете**. Контракт `sil-lift`, проверка которого осуществляется набором тестов при каждом запуске (файлы корпуса плюс генерация на основе свойств): ## Чтение -Загружается любой корректно сформированный документ LIFT 0.13 — включая контент, не соответствующий схеме. Все, что не определено в модели, помещается в непрозрачный контейнер `Extras` ближайшего узла: неизвестные атрибуты и элементы, XML-комментарии и инструкции обработки, случайный текст, а также атрибуты с неверным типом (неправильная дата сохраняется в `Extras` в виде исходной строки; поле типа имеет значение `None`). +Загружается любой корректно сформированный документ LIFT 0.13 — включая контент, не соответствующий схеме. Все, что не определено в модели, передается в непрозрачный контейнер `Extras` ближайшего узла в качестве _остатка LIFT_ — так в FieldWorks называется аналогичная концепция, которая хранится в поле `LiftResidue`: неизвестные атрибуты и элементы, комментарии XML и инструкции по обработке, случайный текст, а также некорректно сформированные типизированные атрибуты (неправильная дата сохраняется в виде исходной строки в `Extras`; типизированное поле имеет значение `None`). ## Сохранение документа без изменений @@ -14,7 +14,7 @@ LIFT — это формат _обмена данными_: главное пр - кодировка исходного текста не совместима с ASCII (не UTF-8/US-ASCII), или - источник содержит DOCTYPE, либо -- сканер байтов и синтаксический анализатор расходятся во мнениях относительно структуры верхнего уровня документа — например, в случае второго символа `
`, не предусмотренного спецификацией, который синтаксический анализатор сохраняет только один раз (сканер же намеренно проявляет настороженность: при любом сомнении он не фиксирует ни одного байта исходного кода), или +- сканер байтов и синтаксический анализатор не сходятся во мнениях относительно структуры верхнего уровня документа — например, в случае второго символа `
`, не предусмотренного спецификацией, который синтаксический анализатор сохраняет только один раз (сканер действует намеренно консервативно: при любом сомнении он не фиксирует исходные байты вообще), или - исходный код был скомпилирован в памяти, а не загружен из файла. ## Сохранение отредактированного документа @@ -23,8 +23,11 @@ LIFT — это формат _обмена данными_: главное пр - **Измененные записи повторно сериализуются канонически и полностью**: UTF-8, отступ в 2 пробела _вне_ смешанного контента (пробелы внутри `` и `` никогда не изменяются), задокументированная группировка дочерних элементов для каждой записи (например, запись: лексическая единица, цитата, варианты произношения, варианты, значения, примечания, связи, этимологии, аннотации, характеристики, поля), фиксированный порядок атрибутов, даты в формате ISO-8601 (`Z` для UTC). Все оставшиеся элементы повторно выводятся; их позиции восстанавливаются в исходном списке дочерних элементов, привязываясь к новому списку дочерних элементов (это приблизительное значение — точные позиции в байтах гарантируются только для нетронутых записей). - Добавление, удаление или изменение порядка записей приводит к повторной сериализации структуры документа, однако байты каждой неизменённой записи по-прежнему выводятся дословно. +!!! note ""Канонический XML-файл" , приведенный здесь, не связан с каким-либо другим каноническим XML-файлом" + Под «канонической формой» на этой странице понимается собственная, задокументированная форма `sil-lift`, описанная в одном из пунктов выше. Это не имеет отношения к процессу W3C по стандарту Canonical XML (C14N). Это не имеет отношения к классу `CanonicalXmlSettings` из `SIL.Core`. + ## Известные приближения (только затронутые узлы) -- Комментарии, расположенные _внутри_ блока ``, сохраняются, но перемещаются рядом с этим блоком, а не на точное место по количеству символов. +- Комментарии, расположенные _внутри_ блока ``, сохраняются, но перемещаются рядом с этим блоком, а не остаются на прежнем месте с точным смещением по символам. - Крестообразный порядок дочерних элементов внутри редактируемого элемента приводится в соответствие с канонической группировкой (параметр `interleave` схемы LIFT делает этот порядок семантически несущественным). - Элемент «multitext», который присутствует, но не содержит ничего — ни форм, ни остаточных элементов, например, ``, — не повторно выводится. Модель представляет эти поля в виде всегда присутствующего объекта `Multitext` (`lexical-unit`, `citation`, `definition`, `usage` отношения и `label` / `abbrev` / `description` для ссылок на URL, диапазонов, элементов диапазона и заголовка), поэтому пустое поле после синтаксического анализа неотличимо от отсутствующего. Ничего из семантики не теряется. From b566e3a45eaa3a748b4c989f053521d851656d4c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:51 -0600 Subject: [PATCH 225/317] New translations fidelity.md (Chinese Simplified) [ci skip] --- docs/zh/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/zh/fidelity.md b/docs/zh/fidelity.md index b0af42d..35648d5 100644 --- a/docs/zh/fidelity.md +++ b/docs/zh/fidelity.md @@ -1,10 +1,10 @@ # 富达保证 -LIFT 是一种_交换_格式:其首要原则是**绝不舍弃你不理解的内容**。 `sil-lift` 的契约,在每次运行时均由测试套件进行验证(包括语料库文件以及基于属性的生成): +LIFT 是一种_交换_格式,因此第一条规则是:**切勿省略你不理解的内容**。 `sil-lift` 的契约,在每次运行时均由测试套件进行验证(包括语料库文件以及基于属性的生成): ## 阅读 -任何格式正确的 LIFT 0.13 文档都能加载——即使其中包含不符合模式的内容。 模型未定义的内容将存放在最近节点的不透明 `Extras` 桶中:未知属性和元素、XML 注释和处理指令、散落的文本,以及格式错误的类型化属性(错误的日期将作为原始字符串保存在 `Extras` 中;其类型化字段为 `None`)。 +任何格式正确的 LIFT 0.13 文档都能加载——即使其中包含不符合模式的内容。 模型未定义的内容将作为_LIFT残余_存储在最近节点的非透明`Extras`容器中——这是FieldWorks对这一概念的称谓,它将这些内容存储在`LiftResidue`字段中:未知属性和元素、XML注释和处理指令、散落的文本以及格式错误的类型化属性 (一个无效的日期将作为原始字符串保留在 `Extras` 中;其类型化字段为 `None`)。 ## 保存未作修改的文档 @@ -14,7 +14,7 @@ LIFT 是一种_交换_格式:其首要原则是**绝不舍弃你不理解的 - 源编码与 ASCII 不兼容(非 UTF-8/US-ASCII),或者 - 源文件中包含 DOCTYPE 声明,或者 -- 字节扫描器和解析器对文档的顶级结构存在分歧——例如,出现了一个不符合规范的第二个 `
`,解析器只保留一次(扫描器则采取了刻意谨慎的态度:一旦产生怀疑,就完全不捕获源代码字节),或者 +- 字节扫描器和解析器对文档的顶级结构存在分歧——例如,出现了一个不符合规范的第二个 `
`,解析器只保留了其中一个(扫描器则故意采取保守策略:一旦有疑问,它就完全不捕获任何源代码字节),或者 - 源代码是在内存中构建的,而不是从文件中加载的。 ## 保存已编辑的文档 @@ -23,8 +23,11 @@ LIFT 是一种_交换_格式:其首要原则是**绝不舍弃你不理解的 - **被修改的条目将按照规范进行完全重新序列化**:UTF-8 编码,混合内容_外部_采用双空格缩进(`` 和 `` 内部的空格绝不更改),每个元素均按文档规定进行子元素分组(例如条目: 词汇单元、引用、发音、变体、词义、注释、关联、词源、标注、特征、领域),固定的属性顺序,日期采用 ISO-8601 格式(`Z` 表示 UTC)。 所有残留项都会被重新发出;其位置将恢复到原始子索引处,并限定在新的子列表范围内(这是一种近似处理——只有未被修改的条目才能保证精确的字节位置)。 - 添加、删除或重新排序条目会重新序列化文档结构,但仍会原样输出每个未更改条目的字节。 +!!! note ""此处的规范" 与任何其他规范XML均无关" + 本页所指的“规范形式”是指 `sil-lift` 自身文档中记载的形态,如上文项目符号中所述。 这与 W3C 的规范 XML(C14N)流程无关。 这与 `SIL.Core` 中的 `CanonicalXmlSettings` 类无关。 + ## 已知的近似值(仅限已访问节点) -- 在 `` 运行块`内部`的注释会被保留,但会被提升到运行块旁边,而不是保留在它们的精确字符偏移量位置。 +- `` 运行块`内部`的注释会被保留,但会移至运行块旁边,而非保留在原有的精确字符偏移位置。 - 在已编辑元素内的交叉型子元素顺序会被规范化为规范分组(LIFT 模式中的 `interleave` 使得该顺序在语义上不具意义)。 - 一个虽然存在但不包含任何内容(既无形式,也无残留)的多文本元素——例如 `` ——不会被重新输出。 该模型将这些字段表示为始终存在的 `Multitext`(包括 `lexical-unit`、`citation`、`definition`、关系的 `usage` 以及 `label` / `abbrev` / `description`,这些字段分别位于 URL 引用、范围、范围元素以及标题中),因此解析后,空字段与缺失字段无法区分。 没有任何语义上的损失。 From d860e47eb672e92001c8c269a520fab5e66307b1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:53 -0600 Subject: [PATCH 226/317] New translations fidelity.md (Hindi) [ci skip] --- docs/hi/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/hi/fidelity.md b/docs/hi/fidelity.md index 1be39cc..b001dcf 100644 --- a/docs/hi/fidelity.md +++ b/docs/hi/fidelity.md @@ -1,10 +1,10 @@ # फिडेलिटी गारंटी -LIFT एक _इंटरचेंज_ प्रारूप है: मुख्य नियम है **जिस चीज़ को आप नहीं समझते, उसे कभी न छोड़ें**। `sil-lift` का कॉन्ट्रैक्ट, जिसे हर रन पर टेस्ट सूट (कॉर्पस फ़ाइलें और प्रॉपर्टी-आधारित जेनरेशन) द्वारा सत्यापित किया जाता है: +LIFT एक _इंटरचेंज_ प्रारूप है, इसलिए पहला नियम है **जो आप नहीं समझते उसे कभी न छोड़ें**। `sil-lift` का कॉन्ट्रैक्ट, जिसे हर रन पर टेस्ट सूट (कॉर्पस फ़ाइलें और प्रॉपर्टी-आधारित जेनरेशन) द्वारा सत्यापित किया जाता है: ## पढ़ना -कोई भी अच्छी तरह से निर्मित LIFT 0.13 दस्तावेज़ लोड हो जाता है — स्कीमा-अमान्य सामग्री सहित। जो कुछ भी मॉडल परिभाषित नहीं करता है, वह निकटतम नोड के अपारदर्शी `Extras` बकेट में रखा जाता है: अज्ञात गुण और तत्व, XML टिप्पणियाँ और प्रसंस्करण निर्देश, बिखरा हुआ पाठ, और गलत प्रकार के गुण (एक गलत दिनांक `Extras` में मूल स्ट्रिंग के रूप में बनी रहती है; प्रकार का क्षेत्र `None` होता है)। +कोई भी अच्छी तरह से निर्मित LIFT 0.13 दस्तावेज़ लोड हो जाता है — स्कीमा-अमान्य सामग्री सहित। जो कुछ भी मॉडल परिभाषित नहीं करता है, उसे निकटतम नोड के अपारदर्शी `Extras` कंटेनर में _LIFT अवशेष_ के रूप में रखा जाता है — FieldWorks द्वारा इसी विचार के लिए दिया गया नाम, जिसे यह `LiftResidue` फ़ील्ड में संग्रहीत करता है: अज्ञात गुण और तत्व, XML टिप्पणियाँ और प्रसंस्करण निर्देश, बिखरा हुआ पाठ, और दूषित प्रकारित गुण (एक खराब तारीख `Extras` में मूल स्ट्रिंग के रूप में बनी रहती है; टाइप्ड फ़ील्ड `None` होता है)। ## बिना बदले दस्तावेज़ को सहेजें @@ -14,7 +14,7 @@ LIFT एक _इंटरचेंज_ प्रारूप है: मुख - स्रोत एन्कोडिंग ASCII-संगत नहीं है (UTF-8/US-ASCII नहीं), या - स्रोत में एक DOCTYPE है, या -- बाइट स्कैनर और पार्सर दस्तावेज़ की शीर्ष-स्तरीय संरचना को लेकर असहमत हैं — उदाहरण के लिए विनिर्देश के बाहर का दूसरा `
`, जिसे पार्सर केवल एक बार रखता है (स्कैनर जानबूझकर अविश्वासी है: कोई भी संदेह होने पर वह कोई भी स्रोत बाइट नहीं पकड़ता), या +- बाइट स्कैनर और पार्सर दस्तावेज़ की शीर्ष-स्तरीय संरचना को लेकर असहमत हैं — उदाहरण के लिए विनिर्देश के बाहर का दूसरा `
`, जिसे पार्सर केवल एक बार रखता है (स्कैनर जानबूझकर सतर्क है: किसी भी संदेह पर यह कोई भी स्रोत बाइट नहीं पकड़ता), या - स्रोत फ़ाइल से लोड करने के बजाय मेमोरी में बनाया गया था। ## संपादित दस्तावेज़ सहेजें @@ -23,8 +23,11 @@ LIFT एक _इंटरचेंज_ प्रारूप है: मुख - स्पर्शित प्रविष्टियाँ मानक रूप से और पूरी तरह से पुनः सीरियलाइज़ की जाती हैं: UTF-8, मिश्रित सामग्री के बाहर 2-स्पेस इंडेंटेशन (`` और `` के अंदर रिक्त स्थान कभी नहीं बदला जाता), प्रत्येक तत्व के लिए एक प्रलेखित उपसमूह (उदाहरण के लिए प्रविष्टि: शब्द-इकाई, उद्धरण, उच्चारण, रूप, अर्थ, टिप्पणियाँ, संबंध, व्युत्पत्तियाँ, टिप्पणियाँ, विशेषताएँ, क्षेत्र), निश्चित गुणक्रम, ISO-8601 में दिनांक (`Z` UTC के लिए)। सभी अवशेष पुनः उत्सर्जित किए जाते हैं; इसकी स्थिति मूल चाइल्ड इंडेक्स पर पुनर्स्थापित की जाती है, और इसे नई चाइल्ड सूची से क्लैम्प किया जाता है (एक अनुमान — सटीक बाइट स्थितियाँ केवल अछूती प्रविष्टियों के लिए ही गारंटी की जाती हैं)। - प्रविष्टियाँ जोड़ने, हटाने या पुनर्व्यवस्थित करने से दस्तावेज़ की संरचना पुनः अनुक्रमित होती है, लेकिन फिर भी हर अपरिवर्तित प्रविष्टि के बाइट्स को शब्दशः उत्सर्जित किया जाता है। +!!! note ""यहाँ का कैनोनिकल" किसी अन्य कैनोनिकल XML से संबंधित नहीं है।" + इस पृष्ठ पर कैनोनिकल रूप का अर्थ है `sil-lift` का अपना प्रलेखित स्वरूप, जिसे ऊपर एक बुलेट में वर्णित किया गया है। यह W3C की कैनोनिकल XML (C14N) प्रक्रिया से असंबंधित है। यह `SIL.Core` की `CanonicalXmlSettings` क्लास से असंबंधित है। + ## ज्ञात अनुमान (केवल स्पर्श किए गए नोड्स) -- `` रन के अंदर की टिप्पणियाँ संरक्षित रहती हैं, लेकिन इन्हें उनके सटीक वर्ण-ऑफसेट पर नहीं, बल्कि रन के बगल में ऊपर ला दिया जाता है। +- \` रन के अंदर की टिप्पणियाँ संरक्षित रहती हैं, लेकिन उन्हें रन के ठीक कैरेक्टर ऑफ़सेट पर रखने के बजाय रन के बगल में स्थानांतरित कर दिया जाता है। - संपादित तत्व के भीतर क्रॉस-टाइप बाल क्रम को मानक समूहबद्धता में सामान्यीकृत किया जाता है (LIFT स्कीमा का `interleave` इस क्रम को अर्थगत रूप से महत्वहीन बना देता है)। - एक मल्टीटेक्स्ट तत्व जो मौजूद तो है लेकिन कुछ भी नहीं ले जाता — न कोई फॉर्म, न कोई अवशेष, उदाहरण के लिए `` — पुनः उत्सर्जित नहीं होता। मॉडल इन फ़ील्ड्स को हमेशा मौजूद `Multitext` (`lexical-unit`, `citation`, `definition`, किसी संबंध का `usage`, और `label` / `abbrev` / `description` url-refs, रेंज, रेंज-एलिमेंट्स और हेडर पर), इसलिए पार्सिंग के बाद एक खाली फ़ील्ड का अभाव वाले फ़ील्ड से कोई अंतर नहीं किया जा सकता। कोई भी अर्थपूर्ण बात खोई नहीं है। From 6a4c9bbd0df89759b2a0bc457f4c9544d295b84b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:55 -0600 Subject: [PATCH 227/317] New translations fidelity.md (Swahili) [ci skip] --- docs/sw/fidelity.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/sw/fidelity.md b/docs/sw/fidelity.md index ea45796..5393600 100644 --- a/docs/sw/fidelity.md +++ b/docs/sw/fidelity.md @@ -1,10 +1,10 @@ # Dhamana za uaminifu -LIFT ni muundo wa kubadilishana: kanuni kuu ni **usitupe kile usichokielewa**. Mkataba wa `sil-lift`, uliothibitishwa na mkusanyiko wa majaribio katika kila utekelezaji (faili za koropusi pamoja na uundaji unaotegemea sifa): +LIFT ni muundo wa kubadilishana, kwa hivyo kanuni ya kwanza ni **kamwe usitupe kile usichokielewa**. Mkataba wa `sil-lift`, uliothibitishwa na mkusanyiko wa majaribio katika kila utekelezaji (faili za koropusi pamoja na uundaji unaotegemea sifa): ## Kusoma -Hati yoyote ya LIFT 0.13 iliyoundwa vizuri hupakiwa — ikijumuisha maudhui yasiyoendana na skema. Chochote ambacho mfano haujafafanua huhifadhiwa kwenye baketi isiyoeleweka ya `Extras` ya nodi iliyo karibu zaidi: sifa na vipengele visivyojulikana, maoni ya XML na maagizo ya usindikaji, maandishi yaliyotapakaa, na sifa za aina zisizojengwa ipasavyo (tarehe isiyo sahihi inabaki kama msururu wa awali katika `Extras`; uwanja wa aina ni `None`). +Hati yoyote ya LIFT 0.13 iliyoundwa vizuri hupakiwa — ikijumuisha maudhui yasiyoendana na skema. Chochote ambacho mfano haujafafanua huhifadhiwa kwenye kontena la `Extras` lisilo wazi la nodi iliyo karibu zaidi kama _baki ya LIFT_ — jina la FieldWorks kwa wazo lile lile, ambalo huhifadhiwa katika uwanja wa `LiftResidue`: sifa na vipengele visivyojulikana, maoni ya XML na maagizo ya usindikaji, maandishi yaliyotapakaa, na sifa za aina zisizojengwa ipasavyo (tarehe isiyo sahihi hubaki kama msururu wa awali katika `Extras`; uwanja uliopangwa ni `None`). ## Kuhifadhi hati bila mabadiliko @@ -14,7 +14,7 @@ Vilevyo vya kipekee (mwandishi anarudi kwenye mfululizo kamili wa kanoniki, amba - Ukodishaji wa chanzo hauendani na ASCII (sio UTF-8/US-ASCII), au - chanzo kina DOCTYPE, au -- kikagua baiti na mchanganuzi havikubaliani kuhusu muundo wa ngazi ya juu wa hati — kwa mfano `
` ya pili isiyoendana na vipimo, ambayo mchanganuzi huihifadhi mara moja tu (kikagua baiti hakiamini kwa makusudi: shaka yoyote inamaanisha hakuna baiti za chanzo zinazoshikiliwa kabisa), au +- Kichanganuzi cha baiti na kichanganaji havikubaliani kuhusu muundo wa ngazi ya juu wa hati — kwa mfano `
` ya pili isiyoendana na vigezo, ambayo kichanganaji huihifadhi mara moja tu (kichanganuzi cha baiti kinajihifadhi kwa tahadhari: kinapokuwa na shaka hakichukui baiti zozote za chanzo), au - Chanzo kilijengwa kwenye kumbukumbu badala ya kupakiwa kutoka kwenye faili. ## Kuhifadhi hati iliyohaririwa @@ -23,8 +23,11 @@ Vilevyo vya kipekee (mwandishi anarudi kwenye mfululizo kamili wa kanoniki, amba - **Maingizo yaliyoguswa yanaserializwa tena kwa kanuni na kikamilifu**: UTF-8, uingizaji wa nafasi mbili _nje_ ya maudhui mchanganyiko (nafasi tupu ndani ya `` na `` haibadilishwi kamwe), upangaji wa vikundi vya watoto uliodokumentishwa kwa kila kipengele (mfano: ingizo: kitengo-cha-msamiati, nukuu, matamshi, aina-tofauti, maana, dondoo, uhusiano, asili-ya-neno, maelezo-ya-nyongeza, sifa, nyanja), mpangilio thabiti wa sifa, tarehe kwa ISO-8601 (`Z` kwa UTC). Baki yote inatolewa tena; nafasi yake inarejeshwa kwenye kiashiria cha awali cha mtoto, na kufungwa kwenye orodha mpya ya watoto (ni makadirio — nafasi halisi za baiti zinahakikishwa tu kwa vipengee visivyoguswa). - Kuongeza, kuondoa, au kupanga upya maingizo kunasababisha muundo wa hati kusiriwa upya kwa mpangilio wa mfululizo, lakini bado hutoa baiti za kila kiingizo kisichobadilika neno kwa neno. +!!! note """ rasmi hapa haihusiani na XML rasmi nyingine yoyote." + Fomu kanoniki kwenye ukurasa huu inamaanisha umbo halisi lililoandikwa la `sil-lift`, lililoelezwa katika nukta hapo juu. Haifungamani na mchakato wa W3C wa Canonical XML (C14N). Haijahusiana na darasa la `CanonicalXmlSettings` la `SIL.Core`. + ## Makadirio yanayojulikana (nodsi zilizoguswa pekee) -- Maoni ndani ya utekelezaji wa `` yanahifadhiwa lakini huwekwa juu kando ya utekelezaji, badala ya mahali pao halisi pa herufi. +- Maoni ndani ya utekelezaji wa `` huhifadhiwa lakini huhamishwa kando ya utekelezaji, badala ya kuwekwa mahali pake hasa kulingana na nafasi ya herufi. - Agizo la mtoto la aina ya msalaba ndani ya kipengele kilichohaririwa linawekwa katika muundo wa kawaida wa makundi (shemia ya LIFT `interleave` hufanya mpangilio huu usiwe na maana kimaana). - Kipengele cha multitext kilichopo lakini hakibebi chochote — hakuna fomu, hakuna mabaki, mfano `` — hakitolewa tena. Mfano unawakilisha nyanja hizi kama `Multitext` inayopatikana kila wakati (`lexical-unit`, `citation`, `definition`, `usage` ya uhusiano, na `label` / `abbrev` / `description` kwenye marejeleo ya URL, vipimo, vipengele vya kipimo na kichwa), hivyo tupu haiwezi kutofautishwa na kutokuwepo baada ya uchanganuzi. Hakuna kitu cha kisemantiki kinachopotea. From 1648a2e9b2fae96b70079d006215e055c162e096 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:57 -0600 Subject: [PATCH 228/317] New translations bulk-edit-glosses.md (French) [ci skip] --- docs/fr/guides/bulk-edit-glosses.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/fr/guides/bulk-edit-glosses.md b/docs/fr/guides/bulk-edit-glosses.md index bb43fa0..af7585d 100644 --- a/docs/fr/guides/bulk-edit-glosses.md +++ b/docs/fr/guides/bulk-edit-glosses.md @@ -53,11 +53,11 @@ Quelques points à retenir : - Comme il compare du contenu sérialisé, le fait d'attribuer à un champ la valeur qu'il avait déjà n'est pas signalé. - Elle ne signale que les modifications de contenu ; les fonctions `lex.added_entries()` et `lex.removed_entries()` concernent les entrées qui sont apparues ou ont disparu depuis le chargement. - Elle renvoie les entrées elles-mêmes, sans tenir compte du fait que l'`id` puisse être dupliqué ou absent (ce que permet LIFT). - - En tant que chiffre, il n'a de sens que s'il existe un élément de comparaison. Lorsque la couche de transit refuse d'effectuer un balayage octet par octet de la source — en raison d'un encodage non compatible ASCII ou d'un désaccord entre le scanner et l'analyseur —, il n'y a pas de référence, et la fonction `changed_entries()` signale _toutes_ les entrées. C'est la réponse honnête concernant la protection en écriture, puisque `save()` resérialise l'intégralité du fichier dans ce cas, mais cela signifie que le nombre correspond à la taille du lexique plutôt qu'à celle de la modification. + - En tant que chiffre, il n'a de sens que s'il existe un élément de comparaison. Lorsque le scanner d'octets refuse de lire la source — en raison d'un encodage non compatible ASCII ou d'un désaccord entre le scanner et l'analyseur —, il n'y a pas de référence, et la fonction `changed_entries()` signale _toutes_ les entrées. C'est la réponse honnête concernant la protection en écriture, puisque `save()` resérialise l'intégralité du fichier dans ce cas, mais cela signifie que le nombre correspond à la taille du lexique plutôt qu'à celle de la modification. - La fonction `lex.changes()` indique si le document a subi la moindre modification. Cela concerne non seulement les entrées, mais aussi l'en-tête, l'élément racine et tous les éléments associés à `.lift-ranges`. - Cette condition n'est fausse que lorsque la fonction `save()` reproduirait les octets source, ce qui fait que `if not lex.changes(): ...` est la bonne façon d'éviter une écriture inutile. Cette garantie fonctionne dans un seul sens : elle ne signale jamais « rien à écrire » pour un document qui serait réécrit, tandis qu'une modification imposant une resérialisation complète peut aboutir aux mêmes octets d'origine et être tout de même signalée. - Comme cette fonction compare le contenu et non la destination, utilisez-la uniquement pour enregistrer le document à l'emplacement actuel : `lex.save(some_other_dir / "dictionary.lift")` écrit le document et ses fichiers associés dans un emplacement encore vide, qu'il y ait eu des modifications ou non. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. + - Il s'agit d'une mesure de sécurité, pas d'un gain de vitesse : l'exécution de cette commande analyse chaque entrée, ce qui correspond au travail effectué par la fonction `save()` pour déterminer quels octets source peuvent être réutilisés. Ce que vous évitez, c'est donc l'écriture proprement dite (une date de modification du fichier inchangée, pas de différence erronée), et non l'effort de prise de décision. - La validation en mémoire (`lex.iter_problems()`) sérialise d'abord l'état modifié, ce qui permet de s'assurer qu'il reflète correctement les modifications avant que quoi que ce soit ne soit écrit sur le disque. L'interruption en cas de `Problem` de niveau « erreur » — les avertissements sont laissés à l'appréciation de l'appelant — garantit qu'une modification incorrecte n'atteindra jamais la fonction `save()`. Les gloss ne sont pas les seuls produits qui méritent d'être appliqués de cette manière. La même surface de mappage `Multitext` s'applique aux définitions et à tous les autres champs multilingues d'une entrée ou d'un sens : From 769d5e273e57ddc03dba1350b7683dd0f2c5f85b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:31:59 -0600 Subject: [PATCH 229/317] New translations bulk-edit-glosses.md (Spanish) [ci skip] --- docs/es/guides/bulk-edit-glosses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/es/guides/bulk-edit-glosses.md b/docs/es/guides/bulk-edit-glosses.md index 182b509..bb53b97 100644 --- a/docs/es/guides/bulk-edit-glosses.md +++ b/docs/es/guides/bulk-edit-glosses.md @@ -53,12 +53,12 @@ Algunas cosas que conviene destacar: - Comparando contenido serializado, no se registra el hecho de asignar a un campo el valor que ya tenía. - Solo informa de los cambios en el contenido; `lex.added_entries()` y `lex.removed_entries()` recogen las entradas que han aparecido o desaparecido desde que se cargó la página. - Devuelve las propias entradas, sin que les afecte que el `id` esté duplicado o falte (algo que permite LIFT). - - Como recuento, solo tiene sentido cuando hay algo con lo que compararlo. Cuando la capa de paso directo se niega a realizar un escaneo byte a byte del código fuente —ya sea por una codificación incompatible con ASCII o por una discrepancia entre el escáner y el analizador—, no existe una línea de referencia, y `changed_entries()` informa de _todas_ las entradas. Esa es la respuesta sincera en lo que respecta a la protección contra escritura, ya que `save()` vuelve a serializar todo el archivo en ese caso, pero eso significa que el recuento corresponde al tamaño del léxico y no al tamaño de la modificación. + - Como recuento, solo tiene sentido cuando hay algo con lo que compararlo. Cuando el escáner de bytes no puede leer la fuente —ya sea por una codificación incompatible con ASCII o por una discrepancia entre el escáner y el analizador—, no existe una línea de referencia, y `changed_entries()` muestra _todas_ las entradas. Esa es la respuesta sincera en lo que respecta a la protección contra escritura, ya que `save()` vuelve a serializar todo el archivo en ese caso, pero eso significa que el recuento corresponde al tamaño del léxico y no al tamaño de la modificación. - `lex.changes()` indica si el documento ha sufrido algún cambio _en absoluto_. Abarca no solo las entradas, sino también el encabezado, el elemento raíz y todos los elementos asociados a `.lift-ranges`. - Solo es falso cuando `save()` reproduciría los bytes originales, lo que hace que `if not lex.changes(): ...` sea la forma correcta de omitir una escritura innecesaria. La garantía funciona en un solo sentido: nunca indica «nada que escribir» para un documento que se reescribiría, mientras que un cambio que obligue a una reserialización completa puede volver a los bytes originales y seguir indicándose. - Compara el contenido, no el destino, por lo que solo debes utilizarlo para guardar en el mismo lugar: `lex.save(some_other_dir / "dictionary.lift")` escribe el documento y sus archivos asociados en una ubicación que aún está vacía, independientemente de si se ha producido algún cambio o no. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- La validación en memoria (`lex.iter_problems()`) serializa primero el estado editado, de modo que este refleje correctamente los cambios antes de que se guarde nada en el disco. Interrumpir la operación ante cualquier `Problem` de nivel «error» —las advertencias se dejan a criterio de quien realiza la llamada— significa que una edición incorrecta nunca llega a `save()`. + - Se trata de una medida de seguridad, no de una optimización: al ejecutarla, se procesan todas las entradas, lo cual equivale al trabajo que realiza `save()` para decidir qué bytes de origen puede reutilizar; por lo tanto, lo que se omite es la propia escritura (sin cambios en la fecha de modificación del archivo, sin diferencias espurias), no el esfuerzo de tomar esa decisión. +- La validación en memoria (`lex.iter_problems()`) serializa primero el estado editado, de modo que este refleje correctamente los cambios antes de que se guarde nada en el disco. Interrumpir la operación ante cualquier `Problem` de nivel `"error"` —las advertencias se dejan a criterio de quien realiza la llamada— significa que una edición incorrecta nunca llega a `save()`. Los brillos no son lo único que merece la pena tratar de esta manera. La misma superficie de asignación `Multitext` se aplica a las definiciones y a cualquier otro campo multilingüe de una entrada o un significado: From f9efee294a2fb22101717978e9e4b215ac26642f Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:00 -0600 Subject: [PATCH 230/317] New translations bulk-edit-glosses.md (Arabic) [ci skip] --- docs/ar/guides/bulk-edit-glosses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ar/guides/bulk-edit-glosses.md b/docs/ar/guides/bulk-edit-glosses.md index 47e16cf..7359cef 100644 --- a/docs/ar/guides/bulk-edit-glosses.md +++ b/docs/ar/guides/bulk-edit-glosses.md @@ -53,12 +53,12 @@ print(f"تم تحرير {edited_glosses} التعريفات في {len(changed)} - إنها تقارن المحتوى المُسلسل، لذا فإن تعيين قيمة كان الحقل يحملها بالفعل لا يتم الإبلاغ عنه. - وهي تُبلغ عن التغييرات في المحتوى فقط؛ أما `lex.added_entries()` و`lex.removed_entries()` فتشملان المدخلات التي ظهرت أو اختفت منذ بدء التحميل. - تُرجع هذه الدالة السجلات نفسها، دون أن يتأثر ذلك بتكرار قيمة `id` أو عدم وجودها (وهو ما يسمح به LIFT). - - كإحصاء، لا يكون لهذا معنى إلا إذا كان هناك ما يُقارن به. عندما ترفض طبقة التمرير إجراء مسح بايت للمصدر — سواء بسبب ترميز غير متوافق مع ASCII، أو بسبب خلاف بين الماسح والمحلل — لا يكون هناك خط أساس، وتقوم الدالة `changed_entries()` بالإبلاغ عن _كل_ إدخال. هذه هي الإجابة الصادقة فيما يتعلق بـ«حارس الكتابة»، حيث إن دالة `save()` تعيد تسلسل الملف بأكمله في تلك الحالة، لكن هذا يعني أن العدد يمثل حجم المعجم بدلاً من حجم التعديل. + - كإحصاء، لا يكون لهذا معنى إلا إذا كان هناك ما يُقارن به. عندما يرفض الماسح البايت قراءة المصدر — سواء بسبب ترميز غير متوافق مع ASCII، أو بسبب خلاف بين الماسح والمحلل — لا يكون هناك خط أساس، وتقوم الدالة `changed_entries()` بالإبلاغ عن _كل_ إدخال. هذه هي الإجابة الصادقة فيما يتعلق بـ«حارس الكتابة»، حيث إن دالة `save()` تعيد تسلسل الملف بأكمله في تلك الحالة، لكن هذا يعني أن العدد يمثل حجم المعجم بدلاً من حجم التعديل. - تُبيّن الدالة `lex.changes()` ما إذا كان المستند قد تغير _على الإطلاق_. وهو لا يشمل العناصر فحسب، بل يشمل أيضًا العنصر الرئيسي والعنصر الجذري وكل عنصر مصاحب من نوع `.lift-ranges`. - ولا يكون ذلك خطأً إلا عندما تعيد دالة `save()` إنتاج البايتات الأصلية، مما يجعل `if not lex.changes(): ...` الطريقة الصحيحة لتخطي عملية كتابة غير ضرورية. هذا الضمان يعمل في اتجاه واحد: فهو لا يُبلغ أبدًا بوجود «لا شيء لتدوينه» بالنسبة لمستند من المقرر إعادة كتابته، في حين أن التغيير الذي يفرض إعادة تسلسل كاملة قد يعود إلى البايتات الأصلية ويُبلغ عنه مع ذلك. - فهي تقارن المحتوى، وليس الوجهة، لذا لا تستخدمها إلا لحفظ الملف في مكانه الأصلي: `lex.save(some_other_dir / "dictionary.lift")` تكتب المستند وملحقاته إلى موقع لا يحتوي على أي شيء بعد، بغض النظر عما إذا كان قد طرأ أي تغيير أم لا. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- تقوم عملية التحقق من الصحة في الذاكرة (`lex.iter_problems()`) بتسلسل الحالة التي تم تعديلها أولاً، بحيث تعكس التعديل بشكل صحيح قبل كتابة أي شيء على القرص. إن إيقاف العملية عند حدوث أي `"خطأ"` من فئة `Problem` — حيث تُترك التحذيرات للمستدعي ليحكم عليها — يعني أن عملية التحرير الخاطئة لن تصل أبدًا إلى `save()`. + - إنها عملية حماية، وليست عملية تسريع — فالاستجابة لها تتطلب معالجة كل إدخال، وهو نفس العمل الذي تقوم به وظيفة `save()` لتحديد البايتات المصدرية التي يمكن إعادة استخدامها؛ لذا فإن ما تتخطاه هو عملية الكتابة نفسها (أي بقاء وقت تعديل الملف دون تغيير، وعدم ظهور فروق زائفة)، وليس الجهد المبذول في عملية التحديد. +- تقوم عملية التحقق من الصحة في الذاكرة (`lex.iter_problems()`) بتسلسل الحالة التي تم تعديلها أولاً، بحيث تعكس التعديل بشكل صحيح قبل كتابة أي شيء على القرص. إن إيقاف العملية عند حدوث أي `"خطأ"` من فئة `Problem` — حيث تُترك التحذيرات للمستدعي لاتخاذ القرار بشأنها — يعني أن عملية التحرير الخاطئة لن تصل أبدًا إلى `save()`. اللمعان ليس الشيء الوحيد الذي يستحق أن نلمسه بهذه الطريقة. ينطبق سطح التعيين «Multitext» نفسه على التعريفات وعلى كل حقل متعدد اللغات آخر في أي مدخل أو معنى: From 380c3843aaafad9e4402658c4870e6bf974677e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:02 -0600 Subject: [PATCH 231/317] New translations bulk-edit-glosses.md (German) [ci skip] --- docs/de/guides/bulk-edit-glosses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/de/guides/bulk-edit-glosses.md b/docs/de/guides/bulk-edit-glosses.md index bc4f1e6..ef5943d 100644 --- a/docs/de/guides/bulk-edit-glosses.md +++ b/docs/de/guides/bulk-edit-glosses.md @@ -53,12 +53,12 @@ Ein paar Dinge, die es zu beachten gilt: - Da serialisierte Inhalte verglichen werden, wird die Zuweisung eines Werts zu einem Feld, den dieses bereits hatte, nicht gemeldet. - Es werden ausschließlich inhaltliche Änderungen gemeldet; `lex.added_entries()` und `lex.removed_entries()` erfassen Einträge, die seit dem Laden hinzugekommen sind bzw. verschwunden sind. - Es gibt die Einträge selbst zurück, unabhängig davon, ob `id` doppelt vorhanden ist oder fehlt (was LIFT zulässt). - - Als Zahl ist sie nur dann aussagekräftig, wenn es etwas gibt, mit dem man sie vergleichen kann. Wenn die Passthrough-Schicht den Byte-Scan der Quelle ablehnt – beispielsweise aufgrund einer nicht ASCII-kompatiblen Kodierung oder einer Diskrepanz zwischen Scanner und Parser –, gibt es keine Basislinie, und `changed_entries()` meldet _jeden_ Eintrag. Das ist die ehrliche Antwort in Bezug auf einen Schreibschutz, da `save()` in diesem Fall die gesamte Datei erneut serialisiert; das bedeutet jedoch, dass der Wert der Größe des Lexikons entspricht und nicht der Größe der Bearbeitung. + - Als Zahl ist sie nur dann aussagekräftig, wenn es etwas gibt, mit dem man sie vergleichen kann. Wenn der Byte-Scanner das Lesen der Quelle verweigert – sei es aufgrund einer nicht ASCII-kompatiblen Kodierung oder einer Diskrepanz zwischen Scanner und Parser –, gibt es keine Basislinie, und `changed_entries()` meldet _jeden_ Eintrag. Das ist die ehrliche Antwort in Bezug auf einen Schreibschutz, da `save()` in diesem Fall die gesamte Datei erneut serialisiert; das bedeutet jedoch, dass der Wert der Größe des Lexikons entspricht und nicht der Größe der Bearbeitung. - `lex.changes()` gibt an, ob sich das Dokument _überhaupt_ geändert hat. Es umfasst nicht nur die Einträge, sondern auch die Kopfzeile, das Stammelement und jedes `.lift-ranges`-Element. - Es ist nur dann falsch, wenn `save()` die Quellbytes reproduzieren würde; daher ist `if not lex.changes(): ...` der richtige Weg, um einen unnötigen Schreibvorgang zu überspringen. Die Garantie gilt nur in eine Richtung: Bei einem Dokument, das neu geschrieben würde, wird niemals „nichts zu schreiben“ gemeldet, während eine Änderung, die eine vollständige Neuserialisierung erzwingt, wieder zu den ursprünglichen Bytes führen kann und dennoch gemeldet wird. - Da dabei der Inhalt und nicht der Speicherort verglichen wird, sollten Sie damit nur das Speichern am aktuellen Speicherort absichern: `lex.save(some_other_dir / "dictionary.lift")` schreibt das Dokument und die zugehörigen Dateien an einen Speicherort, der noch leer ist – unabhängig davon, ob sich etwas geändert hat oder nicht. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- Bei der Validierung im Arbeitsspeicher (`lex.iter_problems()`) wird der bearbeitete Zustand zunächst serialisiert, sodass er die Änderungen korrekt widerspiegelt, bevor Daten auf die Festplatte geschrieben werden. Ein Abbruch bei jedem `"error"`-Level-`Problem` – Warnungen werden dem Aufrufer zur Beurteilung überlassen – bedeutet, dass eine fehlerhafte Bearbeitung niemals `save()` erreicht. + - Es handelt sich um eine Sicherheitsmaßnahme, nicht um eine Beschleunigung – die Ausführung dieses Befehls wertet jeden Eintrag aus, was dem Aufwand entspricht, den `save()` betreibt, um zu entscheiden, welche Quellbytes wiederverwendet werden können. Was Sie also überspringen, ist der Schreibvorgang selbst (unveränderter Zeitpunkt der Dateiänderung, kein falscher Diff), nicht der Aufwand für die Entscheidung. +- Bei der Validierung im Arbeitsspeicher (`lex.iter_problems()`) wird der bearbeitete Zustand zunächst serialisiert, sodass er die Änderungen korrekt widerspiegelt, bevor Daten auf die Festplatte geschrieben werden. Ein Abbruch bei jedem `"error"`-Level-`Problem` – Warnungen werden dem Aufrufer zur Entscheidung überlassen – bedeutet, dass eine fehlerhafte Bearbeitung niemals die Funktion `save()` erreicht. Nicht nur Glanzlacke lassen sich auf diese Weise gut auftragen. Die gleiche `Multitext`-Zuordnungsfläche gilt für Definitionen und alle anderen mehrsprachigen Felder eines Eintrags oder einer Bedeutung: From d3534f3c7ec4928ff1b3cc14c5fc9322b6b37d39 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:04 -0600 Subject: [PATCH 232/317] New translations bulk-edit-glosses.md (Japanese) [ci skip] --- docs/ja/guides/bulk-edit-glosses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/ja/guides/bulk-edit-glosses.md b/docs/ja/guides/bulk-edit-glosses.md index 69e1211..5f3b1c7 100644 --- a/docs/ja/guides/bulk-edit-glosses.md +++ b/docs/ja/guides/bulk-edit-glosses.md @@ -53,12 +53,12 @@ print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") - シリアライズされたコンテンツを比較するため、フィールドに以前と同じ値を割り当てても、そのことは報告されません。 - これはコンテンツの変更のみを報告します。`lex.added_entries()` および `lex.removed_entries()` は、読み込み以降に追加または削除されたエントリを対象としています。 - `id` が重複していたり、存在しなかったりしても(LIFT ではこれが許可されています)、エントリそのものを返します。 - - 「数」として意味を持つのは、比較対象となるものが存在する場合に限られる。 パススルー層がソースのバイトスキャンを拒否した場合(ASCII互換ではないエンコーディングや、スキャナーとパーサーの不一致など)、基準となる状態が存在しないため、`changed_entries()` は _すべての_ エントリを報告します。 これはライトガードに関する正直な答えです。なぜなら、その場合は `save()` がファイル全体を再シリアル化するためですが、その結果、カウント値は編集部分のサイズではなく、レキシコンのサイズになってしまうからです。 + - 「数」として意味を持つのは、比較対象となるものが存在する場合に限られる。 バイトスキャナがソースの読み取りを拒否した場合(ASCII互換ではないエンコーディングや、スキャナとパーサーの不一致など)、基準となる状態が存在しないため、`changed_entries()` は _すべての_ エントリを報告します。 これはライトガードに関する正直な答えです。なぜなら、その場合は `save()` がファイル全体を再シリアル化するためですが、その結果、カウント値は編集部分のサイズではなく、レキシコンのサイズになってしまうからです。 - `lex.changes()` は、ドキュメントに _何らかの変更_ があったかどうかを報告します。 これは、エントリだけでなく、ヘッダー、ルート要素、およびすべての `.lift-ranges` コンパニオンも対象としています。 - これは、`save()` がソースバイトを再現する場合にのみ偽となるため、不要な書き込みをスキップするには `if not lex.changes(): ...` という書き方が正しい。 この保証は一方向のみ有効です。つまり、書き換えられるはずのドキュメントについては「書き込む内容なし」と報告されることは決してありませんが、完全な再シリアル化を余儀なくされる変更であっても、元のバイト列に戻った場合でも、依然として報告されることがあります。 - これは保存先ではなく内容を比較するため、この方法ではインプレース保存のみを保護するようにしてください。`lex.save(some_other_dir / "dictionary.lift")` は、変更の有無にかかわらず、まだ何も格納されていない場所にドキュメントとその関連ファイルを書き込みます。 - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- メモリ内での検証(`lex.iter_problems()`)では、まず編集後の状態をシリアル化するため、ディスクへの書き込みが行われる前に、編集内容が正しく反映されます。 `"error"` レベルの `Problem` が発生した場合は処理を中止します(警告は呼び出し側が判断できるよう残されます)。これにより、不正な編集内容が `save()` に到達することはありません。 + - これはガードであり、処理を高速化するものではありません。この処理に応答するとすべてのエントリが処理されますが、これは`save()`がどのソースバイトを再利用できるかを判断するために行う作業と同じです。したがって、省略されるのは書き込みそのもの(ファイルの最終更新時刻が変わらず、不要な差分が発生しない)であり、判断にかかる労力ではありません。 +- メモリ内での検証(`lex.iter_problems()`)では、まず編集後の状態をシリアル化するため、ディスクへの書き込みが行われる前に、編集内容が正しく反映されます。 `"error"` レベルの `Problem` が発生した場合は処理を中止します(警告については呼び出し側が判断することになります)。これにより、不正な編集内容が `save()` に到達することはありません。 この方法で触れてみる価値があるのは、グロスだけではありません。 この `Multitext` マッピング領域は、定義や、エントリや意味に含まれるその他のすべての多言語フィールドにも同様に適用されます: From 68326fd11c0841317de065845ea0c5e133890ab0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:05 -0600 Subject: [PATCH 233/317] New translations bulk-edit-glosses.md (Portuguese) [ci skip] --- docs/pt/guides/bulk-edit-glosses.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/pt/guides/bulk-edit-glosses.md b/docs/pt/guides/bulk-edit-glosses.md index b88045c..3402a28 100644 --- a/docs/pt/guides/bulk-edit-glosses.md +++ b/docs/pt/guides/bulk-edit-glosses.md @@ -53,12 +53,12 @@ Algumas coisas que vale a pena referir: - Como compara conteúdo serializado, a atribuição a um campo do valor que este já possuía não é registada. - Apresenta apenas alterações de conteúdo; as funções `lex.added_entries()` e `lex.removed_entries()` abrangem as entradas que surgiram ou desapareceram desde o carregamento. - Devolve as próprias entradas, sem que a existência de `id` duplicados ou ausentes (o que o LIFT permite) tenha qualquer influência. - - Enquanto contagem, só faz sentido quando há algo com que comparar. Quando a camada de passagem se recusa a efetuar a análise byte a byte da fonte — seja devido a uma codificação não compatível com ASCII, seja devido a uma discrepância entre o scanner e o analisador —, não existe uma linha de base e a função `changed_entries()` reporta _todas_ as entradas. Essa é a resposta correta no que diz respeito à proteção contra gravação, uma vez que, nesse caso, o `save()` volta a serializar o ficheiro na íntegra, mas isso significa que a contagem corresponde ao tamanho do léxico e não ao tamanho da edição. + - Enquanto contagem, só faz sentido quando há algo com que comparar. Quando o analisador de bytes não consegue ler a fonte — seja por se tratar de uma codificação não compatível com ASCII, seja devido a uma incompatibilidade entre o analisador e o parser —, não existe uma linha de base e a função `changed_entries()` reporta _todas_ as entradas. Essa é a resposta correta no que diz respeito à proteção contra gravação, uma vez que, nesse caso, o `save()` volta a serializar o ficheiro na íntegra, mas isso significa que a contagem corresponde ao tamanho do léxico e não ao tamanho da edição. - A função `lex.changes()` indica se o documento sofreu _alguma_ alteração. Abrange não só as entradas, mas também o cabeçalho, o elemento raiz e todos os elementos com a classe `.lift-ranges`. - Só é falso quando a função `save()` reproduz os bytes de origem, o que faz com que `if not lex.changes(): ...` seja a forma correta de evitar uma gravação desnecessária. A garantia funciona num único sentido: nunca indica «nada para registar» relativamente a um documento que seria reescrito, enquanto que uma alteração que obrigue a uma resseriação completa pode resultar nos mesmos bytes originais e, mesmo assim, ser registada. - Como compara o conteúdo e não o destino, utilize-o apenas para guardar no próprio local: `lex.save(some_other_dir / "dictionary.lift")` grava o documento e os seus ficheiros associados num local que ainda não contém nada, independentemente de ter havido ou não alterações. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- A validação na memória (`lex.iter_problems()`) serializa primeiro o estado editado, para que este reflita corretamente a edição antes de qualquer coisa ser gravada no disco. Interromper a execução perante qualquer `Problem` de nível `"error"` — os avisos são deixados para que o chamador os avalie — significa que uma edição incorreta nunca chega à função `save()`. + - Trata-se de uma medida de proteção, não de um acelerador — ao responder a esta chamada, todas as entradas são processadas, o que corresponde ao trabalho que a função `save()` realiza para determinar quais os bytes de origem que pode reutilizar; assim, o que se salta é a própria gravação (sem alteração na data de modificação do ficheiro, sem diferenças espúrias), e não o esforço de tomar essa decisão. +- A validação na memória (`lex.iter_problems()`) serializa primeiro o estado editado, para que este reflita corretamente a edição antes de qualquer coisa ser gravada no disco. A interrupção ao ocorrer qualquer `Problem` de nível `"error"` — os avisos são deixados para que quem chamou a função decida o que fazer — significa que uma edição incorreta nunca chega à função `save()`. Os glosses não são a única coisa que vale a pena tratar desta forma. A mesma superfície de mapeamento `Multitext` aplica-se às definições e a todos os outros campos multilingues de uma entrada ou significado: From fff2ce6bbac1bc282f86b00e8ff8fd0c0830c6e0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:07 -0600 Subject: [PATCH 234/317] New translations bulk-edit-glosses.md (Russian) [ci skip] --- docs/ru/guides/bulk-edit-glosses.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/ru/guides/bulk-edit-glosses.md b/docs/ru/guides/bulk-edit-glosses.md index e002e3f..16ad85a 100644 --- a/docs/ru/guides/bulk-edit-glosses.md +++ b/docs/ru/guides/bulk-edit-glosses.md @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Выдает все значения, включая подзначения (рекурсивно).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,26 +39,26 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"прерывание: {len(errors)} ошибка(и) проверки, ничего не сохранено") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") +print(f"отредактировано {edited_glosses} глосса(рий) в {len(changed)} записи(ях)") ``` Несколько моментов, на которые стоит обратить внимание: - `Sense.subsenses` само по себе представляет собой `list[Sense]`, поэтому `iter_senses` выполняет рекурсию по нему — при массовом редактировании, которое бы просматривало только `entry.senses`, любые глоссы, вложенные под подзначениями, были бы незаметно пропущены. - `gloss.text` — это объект типа `Text`, а не обычная строка: функция `str(gloss.text)` преобразует его в строку для сопоставления, а результат замены записывается обратно с помощью `sil_lift.Text([new])`, а не путем изменения исходной строки на месте. -- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. - - It compares serialized content, so assigning a field the value it already had isn't reported. - - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. - - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). - - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. -- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. - - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. - - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- При проверке в памяти (`lex.iter_problems()`) сначала выполняется сериализация отредактированного состояния, благодаря чему оно правильно отражает внесенные изменения ещё до записи на диск. Прерывание при возникновении любого объекта `Problem` уровня `"error"` — предупреждения оставляются на усмотрение вызывающего кода — означает, что некорректное изменение никогда не доходит до вызова `save()`. +- Функция `lex.changed_entries()` выводит список записей, которые отличаются от содержимого загруженного файла. Поскольку дайджест записи охватывает всё её поддерево, при внесении изменений во вложенное подзначение об этом получает уведомление запись, в которой оно содержится. + - Он сравнивает сериализованные данные, поэтому присвоение полю значения, которое у него уже было, не фиксируется. + - Она сообщает только об изменениях в содержимом; функции `lex.added_entries()` и `lex.removed_entries()` охватывают записи, которые появились или исчезли с момента загрузки. + - Он возвращает сами записи, при этом не учитывая дубликаты или отсутствие `id` (что допускается в LIFT). + - В качестве показателя это имеет смысл только в том случае, если есть с чем сравнивать. Когда байтовый сканер отказывается считывать исходный код — из-за кодировки, несовместимой с ASCII, или из-за несогласованности между сканером и парсером — базовая линия отсутствует, и функция `changed_entries()` сообщает о _каждой_ записи. Это честный ответ в отношении защиты от записи, поскольку в данном случае функция `save()` повторно сериализует весь файл, но это означает, что подсчитанное значение отражает размер лексикона, а не размер внесенных изменений. +- Функция `lex.changes()` сообщает, изменился ли документ _хотя бы немного_. Он охватывает не только записи, но и заголовок, корневой элемент, а также все элементы с классом `.lift-ranges`. + - Это будет ложным только в том случае, если `save()` воспроизводит исходные байты, что делает `if not lex.changes(): ...` правильным способом пропустить ненужную запись. Гарантия действует в одном направлении: она никогда не возвращает сообщение «нет данных для записи» для документа, который подлежит перезаписи, в то время как изменение, вызывающее полную повторную сериализацию, может привести к возврату исходных байтов и все равно будет отражено в отчете. + - Он сравнивает содержимое, а не место назначения, поэтому используйте его только для сохранения на месте: `lex.save(some_other_dir / "dictionary.lift")` записывает документ и сопутствующие файлы в пустое место, независимо от того, были ли внесены изменения. + - Это защитная мера, а не ускорение — при обработке этого вызова анализируется каждая запись, что соответствует той же работе, которую выполняет `save()` для определения, какие исходные байты можно повторно использовать. Таким образом, вы пропускаете именно саму запись (время изменения файла не изменяется, не возникает ложных различий), а не процесс принятия решения. +- При проверке в памяти (`lex.iter_problems()`) сначала выполняется сериализация отредактированного состояния, благодаря чему оно правильно отражает внесенные изменения ещё до записи на диск. Прерывание при возникновении любого объекта `Problem` уровня `"error"` — предупреждения оставляются на усмотрение вызывающего модуля — означает, что некорректное изменение никогда не доходит до вызова `save()`. Не только глянцевые поверхности стоит обрабатывать таким образом. Та же самая поверхность сопоставления `Multitext` применяется к определениям и всем другим многоязычным полям в записи или значении: From 6e650b36797feb70a216f0eac80eaf3930456579 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:09 -0600 Subject: [PATCH 235/317] New translations bulk-edit-glosses.md (Chinese Simplified) [ci skip] --- docs/zh/guides/bulk-edit-glosses.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/zh/guides/bulk-edit-glosses.md b/docs/zh/guides/bulk-edit-glosses.md index cf1b5a1..613b837 100644 --- a/docs/zh/guides/bulk-edit-glosses.md +++ b/docs/zh/guides/bulk-edit-glosses.md @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """返回每个词义,包括子词义(递归)。”"" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -39,26 +39,26 @@ errors = [p for p in lex.iter_problems() if p.level == "error"] if errors: for problem in errors: print(problem) - sys.exit(f"aborting: {len(errors)} validation error(s), nothing saved") + sys.exit(f"中止:{len(errors)} 个验证错误,未保存任何内容") lex.save() -print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") +print(f"已编辑 {edited_glosses} {len(changed)} 个条目中的释义") ``` 有几点值得注意: - `Sense.subsenses` 本身是一个 `list[Sense]`,因此 `iter_senses` 会递归遍历它——如果批量编辑操作仅遍历 `entry.senses`,则会无提示地跳过任何嵌套在子义项下的释义。 - `gloss.text` 是一个 `Text` 对象,而不是普通的字符串:`str(gloss.text)` 会将其扁平化以便进行匹配,而替换后的内容会通过 `sil_lift.Text([new])` 写回,而不是直接修改原字符串。 -- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. - - It compares serialized content, so assigning a field the value it already had isn't reported. - - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. - - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). - - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. -- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. - - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. - - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- 内存验证(`lex.iter_problems()`)会先将编辑后的状态序列化,因此能在将任何内容写入磁盘之前,准确反映编辑后的状态。 一旦遇到任何 `"error"` 级别的 `Problem` 就终止处理——警告信息将留给调用方自行判断——这意味着错误的编辑操作永远不会进入 `save()` 方法。 +- `lex.changed_entries()` 会报告哪些条目与加载的文件存在差异。 由于条目的摘要涵盖了其整个子树,因此对嵌套的子义项进行编辑时,系统会报告包含该子义项的条目。 + - 它会比较序列化的内容,因此将某个字段赋值为其原有的值时,系统不会报告该操作。 + - 它仅报告内容变更;`lex.added_entries()` 和 `lex.removed_entries()` 涵盖自加载以来新增或删除的条目。 + - 它返回条目本身,不受 `id` 重复或缺失的影响(LIFT 允许这种情况)。 + - 作为一种计数方式,只有在有可比较对象的情况下才有意义。 当字节扫描器无法读取源数据时(例如编码与 ASCII 不兼容,或者扫描器与解析器之间存在分歧),由于缺乏基准,`changed_entries()` 会报告 _所有_ 条目。 对于写保护而言,这确实是一个诚实的答案,因为在这种情况下 `save()` 会重新序列化整个文件,但这意味着计数值代表的是词汇表的大小,而不是编辑内容的大小。 +- `lex.changes()` 用于判断文档是否_有任何_更改。 它不仅涵盖了条目,还包括页眉、根元素以及所有 `.lift-ranges` 关联元素。 + - 只有当 `save()` 能重现源字节时,该条件才会为假,因此 `if not lex.changes(): ...` 才是跳过不必要写入的正确方法。 该保证是单向的:对于本应被重写的文档,它绝不会报告“无内容可写”;而那些会触发完整重新序列化的更改,即使最终结果与原始字节完全一致,仍会被报告。 + - 它比较的是内容,而非目标路径,因此仅应将其用于就地保存:`lex.save(some_other_dir / "dictionary.lift")` 会将文档及其相关文件写入一个目前尚无内容的目录,无论内容是否发生变化。 + - 这是一种保护机制,而非加速手段——调用该函数会处理每个条目,这与 `save()` 决定哪些源字节可以复用的工作完全相同,因此你跳过的只是写入操作本身(文件修改时间保持不变,不会产生虚假差异),而非决策过程。 +- 内存验证(`lex.iter_problems()`)会先将编辑后的状态序列化,因此能在将任何内容写入磁盘之前,准确反映编辑后的状态。 一旦遇到任何 `"error"` 级别的 `Problem` 就会中止处理——警告信息将保留给调用方自行决定如何处理——这意味着错误的编辑操作永远不会进入 `save()` 方法。 值得这样处理的不仅仅是光泽。 相同的 `Multitext` 映射规则同样适用于定义以及条目或词义中的所有其他多语言字段: From 80aa0d7258a51f4971025766b8167bfabfe6cd57 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:10 -0600 Subject: [PATCH 236/317] New translations bulk-edit-glosses.md (Hindi) [ci skip] --- docs/hi/guides/bulk-edit-glosses.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/hi/guides/bulk-edit-glosses.md b/docs/hi/guides/bulk-edit-glosses.md index cfdb5c3..1b7dcee 100644 --- a/docs/hi/guides/bulk-edit-glosses.md +++ b/docs/hi/guides/bulk-edit-glosses.md @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """प्रत्येक अर्थ, उप-अर्थों सहित (पुनरावर्ती) उत्पन्न करें।""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -49,16 +49,16 @@ print(f"edited {edited_glosses} gloss(es) across {len(changed)} entry(ies)") - `Sense.subsenses` स्वयं एक `list[Sense]` है, इसलिए `iter_senses` इसमें पुनरावृत्ति करता है — एक सामूहिक संपादन जो केवल `entry.senses` को ही चलाता है, वह किसी उपसंज्ञा के अंतर्गत निहित किसी भी परिभाषा को चुपचाप छोड़ देगा। - `gloss.text` एक `Text` है, न कि एक साधारण स्ट्रिंग: `str(gloss.text)` इसे मिलान के लिए फ्लैटन करता है, और प्रतिस्थापन को स्ट्रिंग को वहीं पर बदलने के बजाय `sil_lift.Text([new])` के साथ वापस लिखा जाता है। -- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. - - It compares serialized content, so assigning a field the value it already had isn't reported. - - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. - - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). - - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. -- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. - - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. - - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- मेमोरी में सत्यापन (`lex.iter_problems()`) पहले संपादित स्थिति को सीरियलाइज़ करता है, ताकि डिस्क पर कुछ भी लिखे जाने से पहले यह संपादन को सही ढंग से दर्शाए। किसी भी `"error"`-स्तर के `Problem` पर प्रक्रिया रद्द करने पर — चेतावनियाँ कॉल करने वाले पर छोड़ दी जाती हैं — इसका मतलब है कि एक खराब संपादन कभी भी `save()` तक नहीं पहुँचता। +- `lex.changed_entries()` रिपोर्ट करता है कि लोड की गई फ़ाइल से कौन-सी प्रविष्टियाँ भिन्न हैं। चूंकि एक प्रविष्टि का डाइजेस्ट उसके पूरे सबट्री को कवर करता है, एक नेस्टेड सबसेंस में संपादन उस प्रविष्टि की रिपोर्ट करता है जिसमें वह शामिल है। + - यह सीरियलाइज़्ड सामग्री की तुलना करता है, इसलिए किसी फ़ील्ड को उसका पूर्व मान वापस असाइन करने पर यह रिपोर्ट नहीं होता। + - यह केवल सामग्री में हुए परिवर्तनों की रिपोर्ट करता है; `lex.added_entries()` और `lex.removed_entries()` उन प्रविष्टियों को कवर करते हैं जो लोड होने के बाद से दिखाई दीं या गायब हो गईं। + - यह प्रविष्टियों को स्वयं लौटाता है, चाहे `id` दोहराया गया हो या अनुपस्थित हो (जिसकी अनुमति LIFT देता है)। + - एक गणना के रूप में, यह केवल तभी सार्थक होती है जब तुलना करने के लिए कुछ मौजूद हो। जब बाइट स्कैनर स्रोत पढ़ने से इनकार करता है — ऐसी एन्कोडिंग जो ASCII-संगत नहीं है, या स्कैनर/पार्सर के बीच असहमति — तब कोई आधार रेखा नहीं होती, और `changed_entries()` हर प्रविष्टि की रिपोर्ट करता है। WriteGuard के लिए यह ईमानदार उत्तर है, क्योंकि `save()` उस स्थिति में पूरी फ़ाइल को फिर से सीरियलाइज़ करता है, लेकिन इसका मतलब है कि काउंट संपादन के आकार के बजाय शब्दकोश के आकार के बराबर होता है। +- `lex.changes()` यह रिपोर्ट करता है कि दस्तावेज़ में _बिल्कुल भी_ बदलाव हुआ है या नहीं। यह केवल प्रविष्टियों को ही नहीं, बल्कि हेडर, रूट एलिमेंट और प्रत्येक `.lift-ranges` साथी को भी कवर करता है। + - यह केवल तब फर्सी होता है जब `save()` स्रोत बाइट्स को पुन: उत्पन्न कर सके, जो `if not lex.changes(): ...` को अनावश्यक लेखन छोड़ने का सही तरीका बनाता है। गारंटी एकतरफा है: यह कभी भी उस दस्तावेज़ के लिए "लिखने के लिए कुछ नहीं" रिपोर्ट नहीं करती जिसे फिर से लिखा जाएगा, जबकि एक ऐसा परिवर्तन जो पूरी पुनः-सीरियलाइज़ेशन को मजबूर करता है, मूल बाइट्स पर वापस आ सकता है और फिर भी रिपोर्ट किया जा सकता है। + - यह सामग्री की तुलना करता है, गंतव्य की नहीं, इसलिए इसके साथ केवल उसी स्थान पर सहेजें: `lex.save(some_other_dir / "dictionary.lift")` दस्तावेज़ और उसके साथियों को एक ऐसी जगह पर लिखता है जहाँ अभी तक कुछ भी नहीं है, चाहे कुछ बदला हो या नहीं। + - यह एक गार्ड है, स्पीड-अप नहीं — इसे कॉल करने पर यह हर एंट्री को प्रोसेस करता है, जो वही काम है जो `save()` यह तय करने के लिए करता है कि कौन से सोर्स बाइट्स को वह फिर से इस्तेमाल कर सकता है, इसलिए आप जो स्किप करते हैं वह निर्णय लेने का प्रयास नहीं, बल्कि स्वयं लेखन है (फाइल-संशोधन का समय अपरिवर्तित रहता है, कोई झूठा diff नहीं)। +- मेमोरी में सत्यापन (`lex.iter_problems()`) पहले संपादित स्थिति को सीरियलाइज़ करता है, ताकि डिस्क पर कुछ भी लिखे जाने से पहले यह संपादन को सही ढंग से दर्शाए। किसी भी `"error"`-स्तर के `Problem` पर रद्द करने का मतलब है — चेतावनियाँ कॉल करने वाले पर छोड़ दी जाती हैं ताकि वह निर्णय ले सके — कि एक खराब संपादन कभी भी `save()` तक नहीं पहुँचता। इस तरह छूने लायक सिर्फ ग्लॉस ही नहीं हैं। एक ही `Multitext` मैपिंग सतह परिभाषाओं और किसी प्रविष्टि या अर्थ पर प्रत्येक अन्य बहुभाषी क्षेत्र पर लागू होती है: From 2e7a9feebada30de56df8ffc671fb0e9aeac2d7d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:12 -0600 Subject: [PATCH 237/317] New translations bulk-edit-glosses.md (Swahili) [ci skip] --- docs/sw/guides/bulk-edit-glosses.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/sw/guides/bulk-edit-glosses.md b/docs/sw/guides/bulk-edit-glosses.md index fc77cd7..fbca531 100644 --- a/docs/sw/guides/bulk-edit-glosses.md +++ b/docs/sw/guides/bulk-edit-glosses.md @@ -14,7 +14,7 @@ lex = sil_lift.load(path) def iter_senses(senses): - """Yield every sense, including subsenses (recursive).""" + """Yeyeza kila hisia, ikiwa ni pamoja na hisia ndogo (kwa kujirudia).""" for sense in senses: yield sense yield from iter_senses(sense.subsenses) @@ -49,16 +49,16 @@ Mambo machache ya kuzingatia: - `Sense.subsenses` ni `list[Sense]` yenyewe, kwa hivyo `iter_senses` inarudia ndani yake — uhariri wa jumla ambao ungepitia tu `entry.senses` ungeacha kimya kimya fasili yoyote iliyoko chini ya subsense. - `gloss.text` ni `Text`, si mfululizo wa kawaida: `str(gloss.text)` huifanya iwe mfululizo wa kawaida kwa ajili ya kulinganisha, na mbadala huandikwa tena kwa kutumia `sil_lift.Text([new])` badala ya kubadilisha mfululizo mahali pake. -- `lex.changed_entries()` reports which entries differ from the file as loaded. Since an entry's digest covers its whole subtree, an edit to a nested subsense reports the entry that contains it. - - It compares serialized content, so assigning a field the value it already had isn't reported. - - It reports content changes only; `lex.added_entries()` and `lex.removed_entries()` cover entries that appeared or disappeared since loading. - - It returns the entries themselves, unaffected by `id` being duplicated or absent (which LIFT allows). - - As a count, it is meaningful only where there is something to compare against. When the passthrough layer declines to byte-scan the source — an encoding that is not ASCII-compatible, or a scanner/parser disagreement — there is no baseline, and `changed_entries()` reports _every_ entry. That is the honest answer for a write guard, since `save()` re-serializes the whole file in that case, but it means the count is the size of the lexicon rather than the size of the edit. -- `lex.changes()` reports whether the document changed _at all_. It covers not just the entries, but also the header, the root element, and every `.lift-ranges` companion. - - It is falsy only when `save()` would reproduce the source bytes, which makes `if not lex.changes(): ...` the right way to skip an unnecessary write. The guarantee runs one way: it never reports "nothing to write" for a document that would be rewritten, while a change that forces a full re-serialization can land back on the original bytes and still be reported. - - It compares content, not destination, so guard only an in-place save with it: `lex.save(some_other_dir / "dictionary.lift")` writes the document and its companions to a location that has nothing in it yet, whether or not anything changed. - - It is a guard, not a speed-up — answering it digests every entry, which is the same work `save()` does to decide passthrough, so what you skip is the write itself (an untouched mtime, no spurious diff), not the effort of deciding. -- Uhakiki katika kumbukumbu (`lex.iter_problems()`) huweka kwanza hali iliyohaririwa kwa mpangilio, hivyo inaonyesha kwa usahihi mabadiliko kabla ya chochote kuandikwa kwenye diski. Kukata shughuli kwa `Problem` yoyote ya kiwango cha `"error"` — maonyo huachwa kwa mtu anayeita ili ahukumu — kunamaanisha kuwa uhariri mbaya hauwahi kufikia `save()`. +- `lex.changed_entries()` huripoti ni vipengee gani vinatofautiana na faili kama ilivyoandaliwa. Kwa kuwa muhtasari wa kijumla wa kipengee unajumuisha tawi lake lote, uhariri wa kipengele kidogo kilichojumuishwa huripoti kipengee kinachokijumuisha. + - Inalinganisha maudhui yaliyopangwa kwa mfululizo, hivyo kutoa uwanja thamani yake ya awali hakuripotiwi. + - Inaripoti mabadiliko ya maudhui pekee; `lex.added_entries()` na `lex.removed_entries()` zinashughulikia maingizo yaliyoonekana au yaliyotoweka tangu kupakia. + - Inarudisha maingizo yenyewe, bila kuathiriwa na `id` kurudiwa au kutokuwepo (jambo ambalo LIFT inaruhusu). + - Kama hesabu, ina maana tu pale panapokuwa na kitu cha kulinganisha nacho. Wakati skana ya baiti inapokataa kusoma chanzo — kodishaji ambao hauendani na ASCII, au kutokubaliana kwa skana na mchanganuzi — hakuna msingi, na `changed_entries()` inaripoti kila kitu. Hiyo ndiyo jibu la kweli kwa kizuiaji cha kuandika, kwa kuwa `save()` inasababisha kusajili tena faili nzima katika kesi hiyo, lakini hiyo inamaanisha kuwa hesabu ni ukubwa wa kamusi badala ya ukubwa wa uhariri. +- `lex.changes()` huripoti kama hati imebadilika _kabisa_. Haijumuishi tu maingizo, bali pia kichwa, kipengele cha mizizi, na kila mwandani wa `.lift-ranges`. + - Ni uongo tu wakati `save()` ingezaa tena baiti za chanzo, jambo linalofanya `if not lex.changes(): ...` kuwa njia sahihi ya kuepuka uandishi usiohitajika. Dhamana inaendeshwa upande mmoja: hairipoti kamwe "hakuna cha kuandika" kwa hati ambayo ingeandikwa upya, wakati mabadiliko yanayolazimisha urekebishaji kamili wa mfululizo yanaweza kurudi kwenye baiti za awali na bado kuripotiwa. + - Inalinganisha yaliyomo, si mahali pa mwisho, kwa hivyo linda tu uhifadhi mahali pake: `lex.save(some_other_dir / "dictionary.lift")` huandika hati na viambatisho vyake kwenye eneo ambalo bado halina chochote, bila kujali kama kitu kimebadilika au la. + - Ni kizuizi, si kiongezi kasi — kujibu hufanyia uchambuzi kila kipengee, kazi ile ile ambayo `save()` hufanya ili kuamua ni baiti gani za chanzo inaweza kutumia tena, hivyo unachokikwepa ni uandishi wenyewe (muda wa mabadiliko ya faili haujabadilika, hakuna tofauti isiyo ya lazima), si jitihada za kuamua. +- Uhakiki katika kumbukumbu (`lex.iter_problems()`) huweka kwanza hali iliyohaririwa kwa mpangilio, hivyo inaonyesha kwa usahihi mabadiliko kabla ya chochote kuandikwa kwenye diski. Kukata shughuli kwa `Problem` yoyote ya kiwango cha `"error"` — maonyo huachwa kwa mtu anayeita ili aamue — kunamaanisha kuwa uhariri mbaya hautawahi kufikia `save()`. Si glosi pekee ndizo zinazostahili kuguswa kwa njia hii. Uso uleule wa ramani wa `Multitext` unatumika kwa ufafanuzi na kila uwanja mwingine wa lugha nyingi kwenye kipengee au maana: From 3439f0292f4565e26137bdabdb306cb14721e547 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:14 -0600 Subject: [PATCH 238/317] New translations cli.md (French) [ci skip] --- docs/fr/guides/cli.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/fr/guides/cli.md b/docs/fr/guides/cli.md index 5f8d4ac..3f7f121 100644 --- a/docs/fr/guides/cli.md +++ b/docs/fr/guides/cli.md @@ -1,10 +1,10 @@ # La ligne de commande -L'installation du paquet (`pip install sil-lift`) installe également la commande `sil-lift` — un outil de type LiftTools pris en charge et fourni avec le paquet (ainsi que, pour `validate`, un exemple concret d'utilisation de l'API de la bibliothèque). +L'installation du paquet (`pip install sil-lift`) installe également la commande `sil-lift` — un outil pris en charge, dans l'esprit de LiftTools, fourni avec le paquet (et, pour `validate`, un exemple concret d'utilisation de l'API de la bibliothèque). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - tous les problèmes, traités par entrée/ligne ; sortie 1 en cas d’erreurs + tous les problèmes, avec fichier/entrée/ligne ; sortie 1 en cas d’erreurs sil-lift stats CHEMIN [--format {text,json}] nombre d’entrées/sens/langues (en continu ; taille indifférente) sil-lift sort CHEMIN [-o SORTIE] copie triée de manière canonique, prête pour la comparaison (par défaut : sur place) @@ -13,7 +13,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] une ligne par sens de feuille (sous-sens aplatis) vers CSV/TSV (en continu) ``` -`--format json` écrit un seul objet JSON sur la sortie standard (et rien d'autre) à l'intention des outils d'intégration continue (CI) et d'automatisation ; voir le schéma dans l'exemple ci-dessous. L'option `--strict` traite les avertissements comme des erreurs et renvoie la valeur 1 si elle en détecte — utilisez-la pour valider une compilation uniquement si tout est en ordre, et non pas uniquement en cas d'erreurs. L'option `--no-check-media` permet de ne pas effectuer la vérification de la présence des médias dans le système de fichiers (ce qui supprime les messages d'erreur de type `missing-media`), ce qui est utile lors de la validation d'une exportation fraîchement générée dont les fichiers audio/photo se trouvent ailleurs et ne sont pas stockés sur le même disque. `--require-ids` génère également une erreur (`missing-id`) pour toute entrée ne disposant pas d'un `guid` ou pour tout sens ne disposant pas d'un `id` — cette règle est plus stricte que celle de LIFT, pour les flux de travail qui réimportent à l'aide d'un identifiant stable. En passant `-` comme chemin d'accès, le document est lu à partir de l'entrée standard (un document transmis par canalisation n'ayant pas de dossier, son fichier associé `.lift-ranges` et ses médias ne sont pas résolus). La commande `stats` accepte également l'option `--format json`, qui renvoie les statistiques sous la forme d'un objet JSON unique. +`--format json` écrit un seul objet JSON sur la sortie standard (et rien d'autre) à l'intention des outils d'intégration continue (CI) et d'automatisation ; voir le schéma dans l'exemple ci-dessous. L'option `--strict` traite les avertissements comme des erreurs et renvoie la valeur 1 si elle en détecte — utilisez-la pour conditionner la réussite d'une compilation à l'absence totale d'avertissements, plutôt qu'aux seules erreurs. L'option `--no-check-media` permet de ne pas effectuer la vérification de la présence des fichiers multimédias dans le système de fichiers (ce qui supprime les messages d'erreur de type `missing-media`), ce qui est utile lors de la validation d'une exportation fraîchement générée dont les fichiers audio et photos se trouvent ailleurs que dans le même dossier. `--require-ids` génère également une erreur (`missing-id`) pour toute entrée ne disposant pas d'un `guid` ou pour tout sens ne disposant pas d'un `id` — cette règle est plus stricte que celle de LIFT, pour les flux de travail qui réimportent à l'aide d'un identifiant stable. En passant `-` comme chemin d'accès, le document est lu à partir de l'entrée standard (un document transmis par canalisation n'ayant pas de dossier, son fichier associé `.lift-ranges` et ses médias ne sont pas résolus). La commande `stats` accepte également l'option `--format json`, qui renvoie les statistiques sous la forme d'un objet JSON unique. !!! note Les codes de sortie de `validate` et le schéma `--format json` constituent une interface d'automatisation prise en charge : ils font tous deux l'objet de tests et ne sont modifiés que dans le respect de la norme SemVer. From b6e81b620f4e7ef2d7b07b5506b5adf7528bef24 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:15 -0600 Subject: [PATCH 239/317] New translations cli.md (Spanish) [ci skip] --- docs/es/guides/cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/es/guides/cli.md b/docs/es/guides/cli.md index e6db0cc..990766e 100644 --- a/docs/es/guides/cli.md +++ b/docs/es/guides/cli.md @@ -1,19 +1,19 @@ # La línea de comandos -Al instalar el paquete (`pip install sil-lift`) también se instala el comando `sil-lift`, una herramienta compatible con el estilo de LiftTools que se incluye con el paquete (y, en el caso de `validate`, un ejemplo práctico de la API de la biblioteca). +Al instalar el paquete (`pip install sil-lift`) también se instala el comando `sil-lift`, una herramienta compatible con el espíritu de LiftTools que se incluye con el paquete (y, en el caso de `validate`, un ejemplo práctico de la API de la biblioteca). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - todos los problemas, por entrada/línea; salida 1 en caso de error + todos los problemas, con archivo/entrada/línea; salida 1 en caso de errores sil-lift stats PATH [--format {text,json}] - recuentos por entrada/sentido/idioma (en streaming; cualquier tamaño) -sil-lift sort PATH [-o OUT] copia ordenada canónicamente y lista para comparaciones (por defecto: in situ) + recuentos de entradas/significados/idiomas (en tiempo real; cualquier tamaño) +sil-lift sort PATH [-o OUT] copia ordenada canónicamente y lista para comparar diferencias (por defecto: in situ) sil-lift check-media PATH informe de medios que faltan y huérfanos; sale con código 1 si faltan sil-lift export PATH [-o OUT] [--langs L] [--tsv] una fila por sentido principal (subsentidos aplanados) a CSV/TSV (en streaming) ``` -`--format json` escribe un único objeto JSON en la salida estándar (y nada más) para su uso en CI/automatización; consulta el esquema del ejemplo que aparece a continuación. `--strict` trata las advertencias como errores y devuelve el valor 1 si se encuentra alguna; utilízalo para que la compilación solo se complete si todo está en orden, en lugar de basarte únicamente en los errores. `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos (suprimiendo los resultados de `missing-media`), lo cual resulta útil a la hora de validar una exportación recién generada cuyos archivos de audio o fotos se encuentran en otra ubicación y no están almacenados en el mismo disco. `--require-ids` también da error (un error de `missing-id`) en cualquier entrada que carezca de un `guid` o en cualquier sentido que carezca de un `id` — es más estricto que LIFT, para flujos de trabajo que vuelven a importar mediante un identificador estable. Si se pasa `-` como ruta, el documento se lee desde la entrada estándar (un documento transmitido por canalización no tiene carpeta, por lo que su archivo asociado `.lift-ranges` y los archivos multimedia no se resuelven). `stats` también admite la opción `--format json`, con lo que muestra los recuentos en forma de un único objeto JSON. +`--format json` escribe un único objeto JSON en la salida estándar (y nada más) para su uso en CI/automatización; consulta el esquema del ejemplo que aparece a continuación. `--strict` trata las advertencias como errores y devuelve el valor 1 si se encuentra alguna; utilízalo para condicionar la compilación a que no haya ninguna advertencia, en lugar de basarte únicamente en los errores. `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos (suprimiendo los resultados de `missing-media`), lo cual resulta útil a la hora de validar una exportación recién generada cuyos archivos de audio o fotos se encuentren en otra ubicación y no en la misma carpeta. `--require-ids` también da error (un error de `missing-id`) en cualquier entrada que carezca de un `guid` o en cualquier sentido que carezca de un `id` — es más estricto que LIFT, para flujos de trabajo que vuelven a importar mediante un identificador estable. Si se pasa `-` como ruta, el documento se lee desde la entrada estándar (un documento transmitido por canalización no tiene carpeta, por lo que su archivo asociado `.lift-ranges` y los archivos multimedia no se resuelven). `stats` también admite la opción `--format json`, con lo que muestra los recuentos en forma de un único objeto JSON. !!! note Los códigos de salida de `validate` y el esquema de `--format json` constituyen una interfaz de automatización compatible: ambos están cubiertos por pruebas y solo cambian según las normas de SemVer. From 32382b702f01aca4b1bd18f423ae686a21c62031 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:17 -0600 Subject: [PATCH 240/317] New translations cli.md (Arabic) [ci skip] --- docs/ar/guides/cli.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ar/guides/cli.md b/docs/ar/guides/cli.md index ff725f7..d36f3ca 100644 --- a/docs/ar/guides/cli.md +++ b/docs/ar/guides/cli.md @@ -1,19 +1,19 @@ # سطر الأوامر -يؤدي تثبيت الحزمة (`pip install sil-lift`) أيضًا إلى تثبيت الأمر `sil-lift` — وهي أداة مدعومة على غرار LiftTools وتأتي مرفقة مع الحزمة (بالإضافة إلى `validate`، وهو مثال عملي على واجهة برمجة تطبيقات المكتبة). +يؤدي تثبيت الحزمة (`pip install sil-lift`) أيضًا إلى تثبيت الأمر `sil-lift` — وهي أداة مدعومة تتماشى مع روح LiftTools وتأتي مرفقة مع الحزمة (كما أنها، بالنسبة لـ `validate`، تمثل مثالاً عمليًّا على واجهة برمجة تطبيقات المكتبة). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - جميع المشكلات، مع معالجة كل إدخال/سطر على حدة؛ الخروج 1 عند حدوث أخطاء + جميع المشكلات، مع الإشارة إلى الملف/المدخل/السطر؛ الخروج برمز 1 في حالة وجود أخطاء sil-lift stats PATH [--format {text,json}] - عدد الإدخالات/المعاني/اللغات (بشكل متواصل؛ أي حجم) + عدد المدخلات/المعاني/اللغات (بشكل متواصل؛ أي حجم) sil-lift sort PATH [-o OUT] نسخة مرتبة بشكل قياسي وجاهزة للمقارنة (الافتراضي: في المكان نفسه) sil-lift check-media PATH تقرير الوسائط المفقودة واليتيمة؛ الخروج برمز 1 في حالة وجود وسائط مفقودة sil-lift export PATH [-o OUT] [--langs L] [--tsv] صف واحد لكل معنى فرعي (تم تسطيح المعاني الفرعية) إلى CSV/TSV (بشكل متواصل) ``` -تقوم الخيار `--format json` بكتابة كائن JSON واحد إلى stdout (ولا شيء غير ذلك) لاستخدامه في عمليات التكامل المستمر (CI) والأتمتة؛ انظر المخطط في المثال أدناه. يعامل الخيار `--strict` التحذيرات كأخطاء، ويُخرج القيمة 1 في حالة العثور على أي منها — استخدمه لضمان أن يتم البناء فقط في حالة عدم وجود أي مشاكل، وليس بناءً على الأخطاء وحدها. تتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات (مما يؤدي إلى إخفاء نتائج `missing-media`)، وهو أمر مفيد عند التحقق من صحة ملف تصدير تم إنشاؤه حديثًا، حيث توجد ملفات الصوت/الصور الخاصة به في مكان آخر وليست موجودة في نفس موقع الملف على القرص. كما أن `--require-ids` تُسفر عن فشل (خطأ `missing-id`) في حالة أي إدخال يفتقر إلى `guid` أو أي معنى يفتقر إلى `id` — وهو أكثر صرامة من LIFT، وذلك بالنسبة لسير العمل التي تعيد الاستيراد باستخدام معرّف ثابت. عند تمرير `-` كمسار، يتم قراءة المستند من المدخل القياسي (لا يحتوي المستند الممرر عبر الأنابيب على مجلد، لذا لا يتم تحديد موقع ملف `.lift-ranges` المصاحب له والوسائط). كما تقبل `stats` الخيار `--format json`، حيث تُخرج الأعداد في شكل كائن JSON واحد. +تقوم الخيار `--format json` بكتابة كائن JSON واحد إلى stdout (ولا شيء غير ذلك) لاستخدامه في عمليات التكامل المستمر (CI) والأتمتة؛ انظر المخطط في المثال أدناه. يعامل الخيار `--strict` التحذيرات كأخطاء، ويُخرج القيمة 1 في حالة العثور على أي منها — استخدمه لضمان أن عملية البناء لا تتضمن أي تحذيرات على الإطلاق، بدلاً من الاكتفاء بالأخطاء وحدها. يتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات (مما يؤدي إلى إخفاء نتائج `missing-media`)، وهو أمر مفيد عند التحقق من صحة ملف تصدير تم إنشاؤه حديثًا وتوجد ملفات الصوت/الصور الخاصة به في مكان آخر وليس في نفس المجلد. كما أن `--require-ids` تُسفر عن فشل (خطأ `missing-id`) في حالة أي إدخال يفتقر إلى `guid` أو أي معنى يفتقر إلى `id` — وهو أكثر صرامة من LIFT، وذلك بالنسبة لسير العمل التي تعيد الاستيراد باستخدام معرّف ثابت. عند تمرير `-` كمسار، يتم قراءة المستند من المدخل القياسي (لا يحتوي المستند الممرر عبر الأنابيب على مجلد، لذا لا يتم تحديد موقع ملف `.lift-ranges` المصاحب له والوسائط). كما تقبل `stats` الخيار `--format json`، حيث تُخرج الأعداد في شكل كائن JSON واحد. !!! note تُعد رموز الخروج الخاصة بـ `validate` ومخطط `--format json` واجهة أتمتة مدعومة: حيث يخضع كلاهما للاختبارات ولا يتغيران إلا وفقًا لمعايير SemVer. From 35559b3f6c9d899078a6794d8419d5bc39fd6ca7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:18 -0600 Subject: [PATCH 241/317] New translations cli.md (German) [ci skip] --- docs/de/guides/cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/de/guides/cli.md b/docs/de/guides/cli.md index 238adc9..a93f4b3 100644 --- a/docs/de/guides/cli.md +++ b/docs/de/guides/cli.md @@ -1,19 +1,19 @@ # Die Befehlszeile -Durch die Installation des Pakets (`pip install sil-lift`) wird auch der Befehl `sil-lift` installiert – ein unterstütztes Tool im LiftTools-Stil, das im Paket enthalten ist (und im Fall von `validate` ein Beispiel für die Nutzung der Bibliotheks-API). +Durch die Installation des Pakets (`pip install sil-lift`) wird auch der Befehl `sil-lift` installiert – ein unterstütztes Tool im Stil von LiftTools, das im Lieferumfang des Pakets enthalten ist (und für `validate` ein Beispiel für die Anwendung der Bibliotheks-API). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - alle Probleme, nach Eintrag/Zeile aufgeschlüsselt; Beendigung mit 1 bei Fehlern + alle Probleme, mit Datei/Eintrag/Zeile; Beenden mit Status 1 bei Fehlern sil-lift stats PATH [--format {text,json}] - Anzahl der Einträge/Sinninhalte/Sprachen (Streaming; beliebige Größe) + Anzahl der Einträge/Bedeutungen/Sprachen (Streaming; beliebige Größe) sil-lift sort PATH [-o OUT] kanonisch sortierte, diff-fähige Kopie (Standard: an Ort und Stelle) -sil-lift check-media PATH Bericht über fehlende und verwaiste Medien; Beendet mit 1 bei Fehlern +sil-lift check-media PATH Bericht über fehlende und verwaiste Medien; Beendet mit 1, wenn Medien fehlen sil-lift export PATH [-o OUT] [--langs L] [--tsv] eine Zeile pro Blatt-Sense (Subsenses abgeflacht) in CSV/TSV (Streaming) ``` -`--format json` gibt ein einzelnes JSON-Objekt an die Standardausgabe aus (und sonst nichts), das für CI- und Automatisierungszwecke verwendet werden kann; siehe das Schema im folgenden Beispiel. `--strict` behandelt Warnungen als Fehler und gibt den Wert 1 zurück, wenn welche gefunden werden – verwenden Sie diese Option, um einen Build erst dann zuzulassen, wenn alles einwandfrei ist, und nicht nur bei Fehlern. `--no-check-media` überspringt die Überprüfung der Medienpräsenz im Dateisystem (wodurch `missing-media`-Fehler unterdrückt werden), was bei der Validierung eines frisch generierten Exports nützlich ist, dessen Audio- und Fotodateien an einem anderen Ort gespeichert sind und sich nicht auf derselben Festplatte befinden. `--require-ids` führt zudem zu einem Fehler (einem `missing-id`-Fehler), wenn bei einem Eintrag die `guid` fehlt oder bei einem Sense die `id` fehlt – dies ist strenger als bei LIFT und dient Workflows, bei denen der Reimport anhand einer stabilen ID erfolgt. Wird `-` als Pfad übergeben, wird das Dokument aus der Standard-Eingabe gelesen (ein über eine Pipe übermitteltes Dokument hat keinen Ordner, daher werden die zugehörige Datei `.lift-ranges` und die Medien nicht aufgelöst). `stats` akzeptiert ebenfalls die Option `--format json` und gibt die Zählwerte als einzelnes JSON-Objekt aus. +`--format json` gibt ein einzelnes JSON-Objekt an die Standardausgabe aus (und sonst nichts), das für CI- und Automatisierungszwecke verwendet werden kann; siehe das Schema im folgenden Beispiel. `--strict` behandelt Warnungen als Fehler und gibt den Wert 1 zurück, wenn welche gefunden werden – verwenden Sie diese Option, um einen Build davon abhängig zu machen, dass überhaupt keine Warnungen auftreten, anstatt nur von Fehlern. `--no-check-media` überspringt die Überprüfung des Vorhandenseins der Medien im Dateisystem (wodurch `missing-media`-Fehler unterdrückt werden), was bei der Validierung eines frisch generierten Exports nützlich ist, dessen Audio- und Fotodateien sich nicht im selben Ordner, sondern an einem anderen Speicherort befinden. `--require-ids` führt zudem zu einem Fehler (einem `missing-id`-Fehler), wenn bei einem Eintrag die `guid` fehlt oder bei einem Sense die `id` fehlt – dies ist strenger als bei LIFT und dient Workflows, bei denen der Reimport anhand einer stabilen ID erfolgt. Wird `-` als Pfad übergeben, wird das Dokument aus der Standard-Eingabe gelesen (ein über eine Pipe übermitteltes Dokument hat keinen Ordner, daher werden die zugehörige Datei `.lift-ranges` und die Medien nicht aufgelöst). `stats` akzeptiert ebenfalls die Option `--format json` und gibt die Zählwerte als einzelnes JSON-Objekt aus. !!! note Die Exit-Codes von `validate` und das Schema von `--format json` stellen eine unterstützte Automatisierungsschnittstelle dar: Beide werden durch Tests abgedeckt und ändern sich nur gemäß SemVer. From b82d8de962ab2be5110df1b9e03c4a0d23f6b8ea Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:20 -0600 Subject: [PATCH 242/317] New translations cli.md (Japanese) [ci skip] --- docs/ja/guides/cli.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/ja/guides/cli.md b/docs/ja/guides/cli.md index 182b5b4..bbcc9aa 100644 --- a/docs/ja/guides/cli.md +++ b/docs/ja/guides/cli.md @@ -1,19 +1,19 @@ # コマンドライン -パッケージをインストールすると(`pip install sil-lift`)、`sil-lift` コマンドもインストールされます。これは、パッケージに同梱されている、LiftTools スタイルのサポート対象ツールです(また、`validate` については、ライブラリ API の実用例も含まれています)。 +パッケージをインストールすると(`pip install sil-lift`)、`sil-lift` コマンドもインストールされます。これは、LiftTools の精神に基づいた、パッケージに同梱されているサポートツールです(また、`validate` については、ライブラリ API の実用例も含まれています)。 ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - すべての問題、エントリ/行単位で対処;エラー時は終了コード 1 + すべての問題(ファイル/エントリ/行を指定);エラー時は終了コード 1 sil-lift stats PATH [--format {text,json}] エントリ/センス/言語のカウント(ストリーミング;サイズ不問) -sil-lift sort PATH [-o OUT] 正規化されたソート済み、差分比較可能なコピー(デフォルト:その場更新) +sil-lift sort PATH [-o OUT] 正規順にソートされ、差分比較可能なコピー(デフォルト:その場で処理) sil-lift check-media PATH 欠落および孤立したメディアのレポート;欠落がある場合は 1 で終了 sil-lift export PATH [-o OUT] [--langs L] [--tsv] リーフセンスごとに1行(サブセンスは平坦化)でCSV/TSV形式に出力(ストリーミング) ``` -`--format json` を指定すると、CIや自動化処理で使用できるよう、単一のJSONオブジェクトが標準出力に書き出されます(それ以外は何も出力されません)。スキーマについては、以下の例を参照してください。 `--strict` オプションは、警告をエラーとして扱い、警告が見つかった場合は終了値 1 を返します。エラーだけでなく、ビルドが完全に正常であることを条件としてビルドを許可したい場合にこのオプションを使用してください。 `--no-check-media` オプションを指定すると、ファイルシステムのメディア存在確認がスキップされ(`missing-media` の検出結果が表示されなくなります)。これは、生成されたばかりのエクスポートを検証する際、オーディオや写真ファイルが別の場所にあり、ディスク上に同じ場所には存在しない場合に役立ちます。 `--require-ids` は、`guid` がないエントリや `id` がないセンスに対しても(`missing-id` エラーとして)失敗します。これは、安定した ID を使用して再インポートを行うワークフローにおいて、LIFT よりも厳格な仕様となっています。 パスとして `-` を指定すると、ドキュメントは標準入力(stdin)から読み込まれます(パイプで渡されたドキュメントにはフォルダがないため、それに付随する `.lift-ranges` やメディアは解決されません)。 `stats` も同様に `--format json` を受け付け、集計結果を単一の JSON オブジェクトとして出力します。 +`--format json` を指定すると、CIや自動化処理で使用できるよう、単一のJSONオブジェクトが標準出力に書き出されます(それ以外は何も出力されません)。スキーマについては、以下の例を参照してください。 `--strict` オプションは、警告をエラーとして扱い、警告が見つかった場合は終了値 1 を返します。エラーだけでなく、警告が一切ない場合にのみビルドを成功させるようにしたい場合にこのオプションを使用してください。 `--no-check-media` オプションを指定すると、ファイルシステムのメディア存在確認がスキップされ(`missing-media` の検出結果が表示されなくなります)。これは、生成されたばかりのエクスポートファイルに含まれる音声ファイルや写真ファイルが、同じフォルダ内ではなく別の場所に保存されている場合に、そのエクスポートファイルを検証する際に役立ちます。 `--require-ids` は、`guid` がないエントリや `id` がないセンスに対しても(`missing-id` エラーとして)失敗します。これは、安定した ID を使用して再インポートを行うワークフローにおいて、LIFT よりも厳格な仕様となっています。 パスとして `-` を指定すると、ドキュメントは標準入力(stdin)から読み込まれます(パイプで渡されたドキュメントにはフォルダがないため、それに付随する `.lift-ranges` やメディアは解決されません)。 `stats` も同様に `--format json` を受け付け、集計結果を単一の JSON オブジェクトとして出力します。 !!! note `validate` の終了コードおよび `--format json` のスキーマは、サポートされている自動化インターフェースです。これらはいずれもテストの対象となっており、SemVer に基づいてのみ変更されます。 From c3ac93908a93904932ca81219090cb168575ecd5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:21 -0600 Subject: [PATCH 243/317] New translations cli.md (Portuguese) [ci skip] --- docs/pt/guides/cli.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/pt/guides/cli.md b/docs/pt/guides/cli.md index f87d8f5..21ea7ea 100644 --- a/docs/pt/guides/cli.md +++ b/docs/pt/guides/cli.md @@ -1,19 +1,19 @@ # A linha de comandos -Ao instalar o pacote (`pip install sil-lift`), é também instalado o comando `sil-lift` — uma ferramenta compatível com o estilo LiftTools que vem incluída no pacote (e, no caso de `validate`, um exemplo prático da API da biblioteca). +A instalação do pacote (`pip install sil-lift`) instala também o comando `sil-lift` — uma ferramenta compatível, no espírito do LiftTools, que vem incluída no pacote (e, no caso do `validate`, um exemplo prático da API da biblioteca). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - todos os problemas, tratados por entrada/linha; saída 1 em caso de erros + todos os problemas, com indicação de ficheiro/entrada/linha; saída 1 em caso de erros sil-lift stats PATH [--format {text,json}] - contagens por entrada/sentido/língua (em fluxo; qualquer tamanho) -sil-lift sort PATH [-o OUT] cópia ordenada canonicamente, pronta para comparação (predefinição: no local) + contagens de entradas/sentidos/línguas (em fluxo; qualquer tamanho) +sil-lift sort PATH [-o OUT] cópia ordenada canonicamente, pronta para comparação (por predefinição: no local) sil-lift check-media PATH relatório de meios em falta e órfãos; sai com código 1 se houver meios em falta sil-lift export PATH [-o OUT] [--langs L] [--tsv] - uma linha por sentido folha (subsentidos achatados) para CSV/TSV (streaming) + uma linha por sentido folha (subsentidos achatados) para CSV/TSV (em fluxo) ``` -`--format json` escreve um único objeto JSON na saída padrão (e nada mais) para utilização em CI/automatização; consulte o esquema no exemplo abaixo. A opção `--strict` trata os avisos como erros, devolvendo o valor 1 caso seja detetado algum — utilize-a para condicionar a conclusão da compilação à ausência total de problemas, em vez de apenas à ausência de erros. `--no-check-media` ignora a verificação da presença de suportes no sistema de ficheiros (suprimindo os resultados de `missing-media`), o que é útil ao validar uma exportação recém-gerada cujos ficheiros de áudio/fotografias se encontram noutro local e não estão armazenados no mesmo disco. `--require-ids` também falha (com um erro `missing-id`) em qualquer entrada que não tenha um `guid` ou em qualquer sentido que não tenha um `id` — sendo mais rigoroso do que o LIFT, para fluxos de trabalho que reimportam através de um id estável. Ao passar `-` como caminho, o documento é lido a partir do stdin (um documento transmitido por canalização não tem pasta, pelo que o ficheiro `.lift-ranges` associado e os ficheiros multimédia não são resolvidos). O `stats` também aceita a opção `--format json`, apresentando as contagens como um único objeto JSON. +`--format json` escreve um único objeto JSON na saída padrão (e nada mais) para utilização em CI/automatização; consulte o esquema no exemplo abaixo. A opção `--strict` trata os avisos como erros, devolvendo o valor 1 caso seja detetado algum — utilize-a para condicionar a compilação à ausência total de avisos, em vez de apenas à ausência de erros. `--no-check-media` ignora a verificação da presença de ficheiros multimédia no sistema de ficheiros (suprimindo os resultados de `missing-media`), o que é útil ao validar uma exportação recém-gerada cujos ficheiros de áudio/fotografias se encontram noutro local e não na mesma pasta. `--require-ids` também falha (com um erro `missing-id`) em qualquer entrada que não tenha um `guid` ou em qualquer sentido que não tenha um `id` — sendo mais rigoroso do que o LIFT, para fluxos de trabalho que reimportam através de um id estável. Ao passar `-` como caminho, o documento é lido a partir do stdin (um documento transmitido por canalização não tem pasta, pelo que o ficheiro `.lift-ranges` associado e os ficheiros multimédia não são resolvidos). O `stats` também aceita a opção `--format json`, apresentando as contagens como um único objeto JSON. !!! note Os códigos de saída do `validate` e o esquema `--format json` constituem uma interface de automatização suportada: ambos são abrangidos por testes e só sofrem alterações de acordo com a SemVer. From 065fbe686d504c1cb660898770da76bfe037def5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:23 -0600 Subject: [PATCH 244/317] New translations cli.md (Russian) [ci skip] --- docs/ru/guides/cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/ru/guides/cli.md b/docs/ru/guides/cli.md index 5474323..17797e2 100644 --- a/docs/ru/guides/cli.md +++ b/docs/ru/guides/cli.md @@ -1,19 +1,19 @@ # Командная строка -При установке пакета (`pip install sil-lift`) также устанавливается команда `sil-lift` — поддерживаемый инструмент в стиле LiftTools, входящий в состав пакета (а также, в случае команды `validate`, готовый пример использования API библиотеки). +При установке пакета (`pip install sil-lift`) также устанавливается команда `sil-lift` — поддерживаемый инструмент в духе LiftTools, входящий в состав пакета (а также, в случае команды `validate`, готовый пример использования API библиотеки). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - все проблемы, с указанием записи/строки; выход 1 при ошибках + все проблемы с указанием файла/записи/строки; выход с кодом 1 при ошибках sil-lift stats PATH [--format {text,json}] подсчёт записей/значений/языков (потоково; любой размер) -sil-lift sort PATH [-o OUT] канонически отсортированная копия, готовая к сравнениям (по умолчанию: на месте) -sil-lift check-media PATH отчёт об отсутствующих и осиротевших медиа-файлах; выход с кодом 1 при отсутствии +sil-lift sort PATH [-o OUT] канонически отсортированная копия, готовая к сравнению (по умолчанию: на месте) +sil-lift check-media PATH отчёт об отсутствующих и осиротевших медиафайлах; завершение с кодом 1 при отсутствии sil-lift export PATH [-o OUT] [--langs L] [--tsv] одна строка на каждый листьевой сенс (подсенсы сглажены) в формат CSV/TSV (потоковая передача) ``` -`--format json` выводит в stdout один объект JSON (и ничего больше) для использования в системах CI/автоматизации; схему см. в примере ниже. Параметр `--strict` рассматривает предупреждения как ошибки и возвращает значение 1 при обнаружении хотя бы одного из них — используйте его, чтобы сборочный процесс завершался только при полном отсутствии проблем, а не при наличии одних лишь ошибок. `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе (подавляя появление сообщений об ошибках `missing-media`), что полезно при проверке только что сгенерированного экспорта, аудио- и фотофайлы которого хранятся в другом месте и не находятся на том же диске. `--require-ids` дополнительно возвращает ошибку (`missing-id`) при обнаружении любой записи, в которой отсутствует `guid`, или сенса, в котором отсутствует `id` — это более строгий подход, чем в LIFT, и предназначен для рабочих процессов, в которых повторный импорт осуществляется по стабильному идентификатору. Если в качестве пути передать символ `-`, документ будет считываться из стандартного ввода (документ, передаваемый по конвейеру, не имеет папки, поэтому сопутствующий файл `.lift-ranges` и медиафайлы не определяются). Команда `stats` также поддерживает опцию `--format json`, выводя результаты подсчёта в виде одного объекта JSON. +`--format json` выводит в stdout один объект JSON (и ничего больше) для использования в системах CI/автоматизации; схему см. в примере ниже. Параметр `--strict` рассматривает предупреждения как ошибки и возвращает код завершения 1 при обнаружении хотя бы одного из них — используйте его, чтобы остановить сборку при наличии даже одного предупреждения, а не только при ошибках. `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе (подавляя появление сообщений об ошибках `missing-media`), что полезно при проверке только что сгенерированного экспорта, аудио- и фотофайлы которого находятся не в той же папке, а в другом месте. `--require-ids` дополнительно возвращает ошибку (`missing-id`) при обнаружении любой записи, в которой отсутствует `guid`, или сенса, в котором отсутствует `id` — это более строгий подход, чем в LIFT, и предназначен для рабочих процессов, в которых повторный импорт осуществляется по стабильному идентификатору. Если в качестве пути передать символ `-`, документ будет считываться из стандартного ввода (документ, передаваемый по конвейеру, не имеет папки, поэтому сопутствующий файл `.lift-ranges` и медиафайлы не определяются). Команда `stats` также поддерживает опцию `--format json`, выводя результаты подсчёта в виде одного объекта JSON. !!! note Коды завершения функции `validate` и схема `--format json` представляют собой поддерживаемый интерфейс автоматизации: оба элемента проходят тестирование и изменяются только в соответствии с SemVer. From a310fe8f5a981e74dd18b87e40c48b658f915a20 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:25 -0600 Subject: [PATCH 245/317] New translations cli.md (Chinese Simplified) [ci skip] --- docs/zh/guides/cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/zh/guides/cli.md b/docs/zh/guides/cli.md index 1e6c070..d55df39 100644 --- a/docs/zh/guides/cli.md +++ b/docs/zh/guides/cli.md @@ -1,19 +1,19 @@ # 命令行 -安装该包(`pip install sil-lift`)时,还会一并安装 `sil-lift` 命令——这是一个随包附带的、受支持的 LiftTools 风格工具(对于 `validate` 而言,它还是该库 API 的一个示例)。 +安装该包(`pip install sil-lift`)时,还会一并安装 `sil-lift` 命令——这是一个遵循 LiftTools 理念的受支持工具,随包附带(对于 `validate` 而言,它还是该库 API 的一个示例)。 ``` sil-lift 验证 PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - 列出所有问题,按条目/行处理;出现错误时退出并返回 1 + 所有问题,包含文件/条目/行信息;出现错误时退出并返回 1 sil-lift stats PATH [--format {text,json}] 条目/语义/语言计数(流式处理;任意大小) -sil-lift sort PATH [-o OUT] 规范排序、支持差异比较的副本(默认:就地操作) +sil-lift sort PATH [-o OUT] 按规范排序、可进行差异比较的副本(默认:就地操作) sil-lift check-media PATH 缺失和孤立媒体报告;若存在缺失则退出并返回 1 sil-lift export PATH [-o OUT] [--langs L] [--tsv] - 将每个叶片感测单元(子感测单元已扁平化)按一行输出至 CSV/TSV 文件(流式输出) + 将每个叶片感测单元(子感测单元已扁平化)按行导出至 CSV/TSV 文件(流式输出) ``` -`--format json` 会将单个 JSON 对象写入标准输出(且不输出其他内容),供持续集成(CI)和自动化流程使用;请参阅下例中的数据结构。 `--strict` 将警告视为错误,若发现任何警告则返回 1 —— 使用该选项可确保构建仅在系统状态完全正常时才通过,而不仅仅依赖于是否存在错误。 `--no-check-media` 会跳过文件系统的介质存在性检查(从而抑制 `missing-media` 检测结果),这在验证刚生成的导出文件时非常有用——此时音频/照片文件存储在其他位置,并未与导出文件位于同一磁盘上。 `--require-ids` 还会对任何缺少 `guid` 的条目或缺少 `id` 的语义返回错误(`missing-id` 错误)——这比 LIFT 更严格,适用于通过稳定 ID 重新导入的工作流。 将 `-` 作为路径参数传递时,系统将从标准输入(stdin)读取文档(通过管道传递的文档没有文件夹,因此其配套的 `.lift-ranges` 文件和媒体资源不会被解析)。 `stats` 同样支持 `--format json` 选项,将计数结果以单个 JSON 对象的形式输出。 +`--format json` 会将单个 JSON 对象写入标准输出(且不输出其他内容),供持续集成(CI)和自动化流程使用;请参阅下例中的数据结构。 `--strict` 将警告视为错误,若发现任何警告则返回 1 —— 使用该选项可确保构建仅在完全没有警告的情况下通过,而非仅在没有错误的情况下通过。 `--no-check-media` 会跳过文件系统的媒体存在性检查(从而抑制 `missing-media` 错误提示),这在验证刚生成的导出文件时非常有用,尤其是当音频/照片文件位于其他位置而非同一文件夹内时。 `--require-ids` 还会对任何缺少 `guid` 的条目或缺少 `id` 的语义返回错误(`missing-id` 错误)——这比 LIFT 更严格,适用于通过稳定 ID 重新导入的工作流。 将 `-` 作为路径参数传递时,系统将从标准输入(stdin)读取文档(通过管道传递的文档没有文件夹,因此其配套的 `.lift-ranges` 文件和媒体资源不会被解析)。 `stats` 同样支持 `--format json` 选项,将计数结果以单个 JSON 对象的形式输出。 !!! note `validate` 的退出代码和 `--format json` 模式是一种受支持的自动化接口:两者均经过测试验证,且仅在遵循 SemVer 规范的情况下才会发生变更。 From bf3c4a9c1c147bb527102779924f2cfdc9b68bb3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:27 -0600 Subject: [PATCH 246/317] New translations cli.md (Hindi) [ci skip] --- docs/hi/guides/cli.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/hi/guides/cli.md b/docs/hi/guides/cli.md index 64bbf7e..293c6dc 100644 --- a/docs/hi/guides/cli.md +++ b/docs/hi/guides/cli.md @@ -1,19 +1,19 @@ # कमांड लाइन -पैकेज (`pip install sil-lift`) इंस्टॉल करने पर `sil-lift` कमांड भी इंस्टॉल हो जाता है — यह एक समर्थित LiftTools-शैली का टूल है जो पैकेज के साथ आता है (और `validate` के लिए लाइब्रेरी API का एक कार्यात्मक उदाहरण)। +पैकेज (`pip install sil-lift`) इंस्टॉल करने पर `sil-lift` कमांड भी इंस्टॉल हो जाता है — यह LiftTools की भावना में एक समर्थित टूल है जो पैकेज के साथ आता है (और `validate` के लिए लाइब्रेरी API का एक कार्यशील उदाहरण)। ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - सभी समस्याएँ, प्रविष्टि/पंक्ति-पते; त्रुटियों पर 1 से बाहर निकलें + सभी समस्याएँ, फ़ाइल/प्रविष्टि/पंक्ति के साथ; त्रुटियों पर 1 पर बाहर निकलें sil-lift stats PATH [--format {text,json}] प्रविष्टि/अर्थ/भाषा की गिनती (स्ट्रीमिंग; कोई भी आकार) -sil-lift sort PATH [-o OUT] मानक रूप से क्रमबद्ध, diff-तैयार प्रतिलिपि (डिफ़ॉल्ट: उसी स्थान पर) -sil-lift check-media PATH गुम और अनाथ मीडिया रिपोर्ट; यदि गुम हो तो 1 पर निकास +sil-lift sort PATH [-o OUT] मानकीकृत रूप से क्रमबद्ध, diff-तैयार प्रतिलिपि (डिफ़ॉल्ट: उसी स्थान पर) +sil-lift check-media PATH अनुपस्थित और अनाथ मीडिया रिपोर्ट; यदि अनुपस्थित हो तो 1 पर निकास sil-lift export PATH [-o OUT] [--langs L] [--tsv] प्रत्येक लीफ़ सेंस के लिए एक पंक्ति (सबसेंस समतल) CSV/TSV में (स्ट्रीमिंग) ``` -`--format json` CI/ऑटोमेशन के उपयोग के लिए stdout पर एक ही JSON ऑब्जेक्ट लिखता है (और कुछ नहीं); नीचे दिए गए उदाहरण में स्कीमा देखें। `--strict` चेतावनियों को त्रुटियों के रूप में मानता है, और कोई भी चेतावनी मिलने पर 1 पर बाहर निकल जाता है — इसका उपयोग केवल त्रुटियों के आधार पर नहीं, बल्कि एक स्वच्छ रिपोर्ट के आधार पर बिल्ड को नियंत्रित करने के लिए करें। `--no-check-media` फ़ाइलसिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है (`missing-media` निष्कर्षों को दबाते हुए), जो तब उपयोगी होता है जब किसी ताज़ा उत्पन्न निर्यात का सत्यापन किया जा रहा हो, जिसकी ऑडियो/फ़ोटो फ़ाइलें कहीं और स्थित हैं और डिस्क पर एक साथ नहीं हैं। `--require-ids` अतिरिक्त रूप से किसी भी ऐसी प्रविष्टि पर विफल होता है जिसमें `guid` न हो या किसी सेंस में `id` न हो — यह LIFT की तुलना में अधिक सख्त है, उन वर्कफ़्लो के लिए जो एक स्थिर id द्वारा पुनः आयात करते हैं। पथ के रूप में `-` पास करने पर दस्तावेज़ stdin से पढ़ा जाता है (एक पाइप्ड दस्तावेज़ का कोई फ़ोल्डर नहीं होता, इसलिए इसका साथी `.lift-ranges` और मीडिया हल नहीं होते)। `stats` भी `--format json` लेता है, और गिनतियों को एक ही JSON ऑब्जेक्ट के रूप में उत्पन्न करता है। +`--format json` CI/ऑटोमेशन के उपयोग के लिए stdout पर एक ही JSON ऑब्जेक्ट लिखता है (और कुछ नहीं); नीचे दिए गए उदाहरण में स्कीमा देखें। `--strict` चेतावनियों को त्रुटियों के रूप में मानता है, और कोई भी चेतावनी मिलने पर 1 पर बाहर निकल जाता है — इसका उपयोग बिल्ड को केवल त्रुटियों पर नहीं बल्कि बिल्कुल भी चेतावनी न होने पर रोकने के लिए करें। `--no-check-media` फ़ाइल सिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है (`missing-media` निष्कर्षों को दबाते हुए), जो तब उपयोगी होता है जब किसी ताज़ा उत्पन्न निर्यात का सत्यापन किया जा रहा हो, जिसकी ऑडियो/फ़ोटो फ़ाइलें उसी फ़ोल्डर में होने के बजाय कहीं और स्थित हों। `--require-ids` अतिरिक्त रूप से किसी भी ऐसी प्रविष्टि पर विफल होता है जिसमें `guid` न हो या किसी सेंस में `id` न हो — यह LIFT की तुलना में अधिक सख्त है, उन वर्कफ़्लो के लिए जो एक स्थिर id द्वारा पुनः आयात करते हैं। पथ के रूप में `-` पास करने पर दस्तावेज़ stdin से पढ़ा जाता है (एक पाइप्ड दस्तावेज़ का कोई फ़ोल्डर नहीं होता, इसलिए इसका साथी `.lift-ranges` और मीडिया हल नहीं होते)। `stats` भी `--format json` लेता है, और गिनतियों को एक ही JSON ऑब्जेक्ट के रूप में उत्पन्न करता है। !!! note `validate` के एग्जिट कोड और `--format json` स्कीमा एक समर्थित ऑटोमेशन इंटरफ़ेस हैं: दोनों टेस्ट द्वारा कवर किए गए हैं और केवल SemVer के तहत ही बदलते हैं। From c953059f6e7be58c5f95611b732aff7c195958b5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:28 -0600 Subject: [PATCH 247/317] New translations cli.md (Swahili) [ci skip] --- docs/sw/guides/cli.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sw/guides/cli.md b/docs/sw/guides/cli.md index e27414c..68fd55d 100644 --- a/docs/sw/guides/cli.md +++ b/docs/sw/guides/cli.md @@ -1,19 +1,19 @@ # Mstari wa amri -Kusakinisha kifurushi (`pip install sil-lift`) pia husakinisha amri ya `sil-lift` — zana inayounga mkono mtindo wa LiftTools inayotolewa na kifurushi hicho (na, kwa `validate`, mfano uliofanyiwa kazi wa API ya maktaba). +Kusakinisha kifurushi (`pip install sil-lift`) pia husakinisha amri ya `sil-lift` — zana inayoungwa mkono katika mtindo wa LiftTools inayokuja na kifurushi hicho (na, kwa `validate`, mfano uliofanyiwa kazi wa API ya maktaba). ``` sil-lift validate PATH [--format {text,json}] [--strict] [--no-check-media] [--require-ids] - matatizo yote, yaliyotatuliwa kwa kipengee/anwani ya mstari; kutoka 1 kwa makosa + matatizo yote, na faili/kipengee/mstari; kutoka 1 kwa makosa sil-lift stats PATH [--format {text,json}] idadi za kipengee/maana/lugha (mtiririko; ukubwa wowote) sil-lift sort PATH [-o OUT] imepangwa kihalali, nakala tayari kwa tofauti (chaguo-msingi: mahali pake) sil-lift check-media NJIA ripoti ya vyombo vilivyokosekana na vilivyoachwa peke yake; toa 1 ikiwa hakuna sil-lift export NJIA [-o OUT] [--langs L] [--tsv] - safu moja kwa kila hisia ya majani (hisia ndogo zimepangwa wazi) kwa CSV/TSV (mtiririko) + safu moja kwa kila hisia ya majani (hisia ndogo zimepandishwa) kwa CSV/TSV (mtiririko) ``` -`--format json` huandika object moja ya JSON kwenye stdout (na hakuna kitu kingine) kwa matumizi ya CI/otomatishaji; tazama schema katika mfano hapa chini. `--strict` huchukulia maonyo kama makosa, na kutoka kwa nambari 1 endapo yoyote yatapatikana — itumie ili kuidhinisha ujenzi endapo hakuna matatizo, badala ya kutegemea makosa pekee. `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili (na hivyo kuficha matokeo ya `missing-media`), jambo ambalo ni muhimu wakati wa kuthibitisha toleo jipya lililotengenezwa ambalo faili zake za sauti/picha ziko mahali pengine na haziko kwenye diski pamoja. `--require-ids` pia hushindwa (kosa la `missing-id`) kwa kipengee chochote kinachokosa `guid` au sense kinachokosa `id` — ni kali zaidi kuliko LIFT, kwa mtiririko wa kazi unao-re-import tena kwa kutumia id thabiti. Kupitisha `-` kama njia husoma hati kutoka stdin (hati iliyopitishwa kwa bomba haina folda, hivyo faili zake za `.lift-ranges` na media hazitatatuliwa). `stats` vivyo hivyo huchukua `--format json`, na kutoa hesabu kama kitu kimoja cha JSON. +`--format json` huandika object moja ya JSON kwenye stdout (na hakuna kitu kingine) kwa matumizi ya CI/otomatishaji; tazama schema katika mfano hapa chini. `--strict` huchukulia maonyo kama makosa, na kutoka kwa nambari 1 endapo yoyote yatapatikana — itumie ili kuidhinisha ujenzi endapo hakuna maonyo kabisa, badala ya kutegemea makosa pekee. `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili (na hivyo kuficha matokeo ya `missing-media`), jambo ambalo ni muhimu wakati wa kuthibitisha toleo jipya lililotengenezwa ambalo faili zake za sauti/picha ziko mahali pengine badala ya kwenye folda moja. `--require-ids` pia hushindwa (kosa la `missing-id`) kwa kipengee chochote kinachokosa `guid` au sense kinachokosa `id` — ni kali zaidi kuliko LIFT, kwa mtiririko wa kazi unao-re-import tena kwa kutumia id thabiti. Kupitisha `-` kama njia husoma hati kutoka stdin (hati iliyopitishwa kwa bomba haina folda, hivyo faili zake za `.lift-ranges` na media hazitatatuliwa). `stats` vivyo hivyo huchukua `--format json`, na kutoa hesabu kama kitu kimoja cha JSON. !!! note Misimbo ya kutoka ya `validate` na `--format json` schema ni kiolesura cha kiotomatiki kinachotumika: vyote vimejumuishwa katika majaribio na hubadilika tu kulingana na SemVer. From aa7780a70151262ebd5825f704f5457af8909401 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:30 -0600 Subject: [PATCH 248/317] New translations folder-media.md (French) [ci skip] --- docs/fr/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/folder-media.md b/docs/fr/guides/folder-media.md index f52ce4e..37711a5 100644 --- a/docs/fr/guides/folder-media.md +++ b/docs/fr/guides/folder-media.md @@ -1,6 +1,6 @@ # Le dossier LIFT : gammes et supports -Un lexique LIFT se présente généralement sous la forme d'un _dossier_ : le fichier `.lift`, un ou plusieurs fichiers associés `.lift-ranges`, ainsi que les fichiers multimédias contenus dans les dossiers `audio/` et `pictures/`. +Un lexique LIFT se présente généralement sous la forme d'un _dossier_ : le fichier `.lift`, un ou plusieurs fichiers associés `.lift-ranges` (fichiers « sidecar ») et les fichiers multimédias contenus dans les dossiers `audio/` et `pictures/`. ## Gammes From d4be8b8c389ffbea02d4289c05be6092505f317a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:32 -0600 Subject: [PATCH 249/317] New translations folder-media.md (Spanish) [ci skip] --- docs/es/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/folder-media.md b/docs/es/guides/folder-media.md index 346867a..f8f4772 100644 --- a/docs/es/guides/folder-media.md +++ b/docs/es/guides/folder-media.md @@ -1,6 +1,6 @@ # La carpeta LIFT: gamas y soportes -Un léxico de LIFT suele ser una _carpeta_: el archivo `.lift`, uno o varios archivos complementarios `.lift-ranges` y los archivos multimedia de las carpetas `audio/` y `pictures/`. +Un léxico de LIFT suele ser una _carpeta_: el archivo `.lift`, uno o varios archivos complementarios `.lift-ranges` (archivos «sidecar») y los archivos multimedia de las carpetas `audio/` y `pictures/`. ## Gamas From 55e7b286dda579f57d270f03126d493428c341e8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:33 -0600 Subject: [PATCH 250/317] New translations folder-media.md (Arabic) [ci skip] --- docs/ar/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/folder-media.md b/docs/ar/guides/folder-media.md index df43a04..19a35d5 100644 --- a/docs/ar/guides/folder-media.md +++ b/docs/ar/guides/folder-media.md @@ -1,6 +1,6 @@ # مجلد LIFT: النطاقات ووسائل الإعلام -عادةً ما يكون معجم LIFT عبارة عن _مجلد_: ملف `.lift`، وملف أو أكثر من ملفات `.lift-ranges` المصاحبة له، وملفات الوسائط الموجودة في مجلدي `audio/` و`pictures/`. +عادةً ما يكون معجم LIFT عبارة عن _مجلد_: ملف `.lift`، وملف واحد أو أكثر من ملفات `.lift-ranges` المصاحبة (ملفات sidecar)، وملفات الوسائط الموجودة في مجلدي `audio/` و`pictures/`. ## النطاقات From 0a9bbcd17654cf27fc7be91dff0c5fb57a29a81d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:35 -0600 Subject: [PATCH 251/317] New translations folder-media.md (German) [ci skip] --- docs/de/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/folder-media.md b/docs/de/guides/folder-media.md index 81a80a7..1de7af6 100644 --- a/docs/de/guides/folder-media.md +++ b/docs/de/guides/folder-media.md @@ -1,6 +1,6 @@ # Der LIFT-Ordner: Sortimente und Medien -Ein LIFT-Lexikon besteht in der Regel aus einem _Ordner_: der `.lift`-Datei, einer oder mehreren zugehörigen `.lift-ranges`-Dateien sowie den Medien in den Ordnern `audio/` und `pictures/`. +Ein LIFT-Lexikon besteht in der Regel aus einem _Ordner_: der `.lift`-Datei, einer oder mehreren zugehörigen `.lift-ranges`-Dateien (Sidecar-Dateien) sowie den Mediendateien im Verzeichnis `audio/` bzw. `pictures/`. ## Bereiche From 82ec57e231b68862add8c5566011a0b32878aaed Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:37 -0600 Subject: [PATCH 252/317] New translations folder-media.md (Japanese) [ci skip] --- docs/ja/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/folder-media.md b/docs/ja/guides/folder-media.md index 227cc62..b03fa72 100644 --- a/docs/ja/guides/folder-media.md +++ b/docs/ja/guides/folder-media.md @@ -1,6 +1,6 @@ # 「LIFT」フォルダ:範囲とメディア -LIFTのレキシコンは通常、_フォルダ_として構成されます。その中には、`.lift`ファイル、1つ以上の`.lift-ranges`ファイル、および`audio/` / `pictures/`フォルダ内のメディアファイルが含まれます。 +LIFTレキシコンは通常、_フォルダ_として構成されます。その中には、`.lift`ファイル、1つ以上の`.lift-ranges`ファイル(サイドカーファイル)、および`audio/` / `pictures/`フォルダ内のメディアファイルが含まれます。 ## 範囲 From 024cde2011b65f7eba7cf5348052bec7ea47c256 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:38 -0600 Subject: [PATCH 253/317] New translations folder-media.md (Portuguese) [ci skip] --- docs/pt/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/folder-media.md b/docs/pt/guides/folder-media.md index ff54327..4199934 100644 --- a/docs/pt/guides/folder-media.md +++ b/docs/pt/guides/folder-media.md @@ -1,6 +1,6 @@ # A pasta LIFT: gamas e suportes -Um léxico LIFT é normalmente uma _pasta_: o ficheiro `.lift`, um ou mais ficheiros complementares `.lift-ranges` e os ficheiros multimédia nas pastas `audio/` e `pictures/`. +Um léxico LIFT é normalmente uma _pasta_: o ficheiro `.lift`, um ou mais ficheiros complementares `.lift-ranges` (ficheiros «sidecar») e os ficheiros multimédia nas pastas `audio/` e `pictures/`. ## Intervalos From 0a37e551f530c7c884f30ace9de5c9217aedb968 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:40 -0600 Subject: [PATCH 254/317] New translations folder-media.md (Russian) [ci skip] --- docs/ru/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/folder-media.md b/docs/ru/guides/folder-media.md index 78ae627..37fc076 100644 --- a/docs/ru/guides/folder-media.md +++ b/docs/ru/guides/folder-media.md @@ -1,6 +1,6 @@ # Папка LIFT: диапазоны и носители -Лексикон LIFT обычно представляет собой _папку_: файл `.lift`, один или несколько сопутствующих файлов `.lift-ranges`, а также мультимедийные файлы в папках `audio/` и `pictures/`. +Лексикон LIFT обычно представляет собой _папку_: файл `.lift`, один или несколько сопутствующих файлов `.lift-ranges` (файлы-«сидкары») и мультимедийные файлы в папках `audio/` и `pictures/`. ## Диапазоны From 0107f6e0590a7b114aa451911a10ec73c0d254a5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:42 -0600 Subject: [PATCH 255/317] New translations folder-media.md (Chinese Simplified) [ci skip] --- docs/zh/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/folder-media.md b/docs/zh/guides/folder-media.md index ada11ae..860793f 100644 --- a/docs/zh/guides/folder-media.md +++ b/docs/zh/guides/folder-media.md @@ -1,6 +1,6 @@ # LIFT 文件夹:范围与媒体 -一个 LIFT 词汇表通常是一个 _文件夹_:包含一个 `.lift` 文件、一个或多个配套的 `.lift-ranges` 文件,以及 `audio/` / `pictures/` 目录中的媒体文件。 +一个 LIFT 词汇表通常是一个 _文件夹_:包含 `.lift` 文件、一个或多个 `.lift-ranges` 辅助文件(sidecar 文件),以及 `audio/` / `pictures/` 中的媒体文件。 ## 范围 From a71c95919d6e093d8dd8772922b6a6f4d04233b5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:43 -0600 Subject: [PATCH 256/317] New translations folder-media.md (Hindi) [ci skip] --- docs/hi/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/folder-media.md b/docs/hi/guides/folder-media.md index c8e0c47..af9b40f 100644 --- a/docs/hi/guides/folder-media.md +++ b/docs/hi/guides/folder-media.md @@ -1,6 +1,6 @@ # LIFT फ़ोल्डर: श्रेणियाँ और मीडिया -एक LIFT शब्दकोश आमतौर पर एक _फ़ोल्डर_ होता है: `.lift` फ़ाइल, एक या अधिक `.lift-ranges` साथी, और `audio/` / `pictures/` मीडिया। +एक LIFT शब्दकोश आमतौर पर एक _फ़ोल्डर_ होता है: `.lift` फ़ाइल, एक या अधिक `.lift-ranges` साथी (साइडकार फ़ाइलें), और `audio/` / `pictures/` मीडिया। ## दायरे From ea81734b9633c8d51bf28471275522ef1bc09946 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:45 -0600 Subject: [PATCH 257/317] New translations folder-media.md (Swahili) [ci skip] --- docs/sw/guides/folder-media.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/folder-media.md b/docs/sw/guides/folder-media.md index 520e57f..61561f2 100644 --- a/docs/sw/guides/folder-media.md +++ b/docs/sw/guides/folder-media.md @@ -1,6 +1,6 @@ # Folda ya LIFT: masafa na vyombo vya habari -Kamusi ya LIFT kawaida ni _folda_: faili ya `.lift`, moja au zaidi ya faili za `.lift-ranges` zinazohusiana, na media za `audio/` / `pictures/`. +Kamusi ya LIFT kawaida ni _folda_: faili ya `.lift`, moja au zaidi ya faili wasaidizi za `.lift-ranges` (faili za pembeni), na midia ya `audio/` / `pictures/`. ## Vipimo From 0c6f56220a280f89c2781b03548171657be2305b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:47 -0600 Subject: [PATCH 258/317] New translations large-files.md (French) [ci skip] --- docs/fr/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/large-files.md b/docs/fr/guides/large-files.md index 858fd21..f0da8a6 100644 --- a/docs/fr/guides/large-files.md +++ b/docs/fr/guides/large-files.md @@ -23,5 +23,5 @@ avec sil_lift.open_reader("big.lift") en tant que lecteur, sil_lift.open_writer( Remarques : - Le résultat généré par l'éditeur correspond exactement à ce que produirait le sérialiseur canonique « plein document » pour le même contenu — les deux modes ne divergent jamais. -- Le mode streaming ne comporte pas de couche de transfert d'octets : la sortie est toujours canonique. Les résidus de niveau racine — commentaires entre les entrées et attributs hors schéma sur `` — ne sont pas transférés ; les entrées et l'en-tête sont complets, résidus compris. +- Le mode streaming ne réutilise aucun octet source : la sortie est toujours canonique. Les résidus LIFT de niveau racine — commentaires entre les entrées et attributs hors schéma sur `` — ne sont pas transférés ; les entrées et l'en-tête sont complets, résidus compris. - Si une exception est levée dans le corps d'un bloc `open_writer`, le fichier reste visiblement inachevé (pas de commande de fermeture ``) — un lexique à moitié écrit ne doit pas donner l'impression d'être complet. From 42a0883774115840148f024cfbe0b8dbaf91e316 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:48 -0600 Subject: [PATCH 259/317] New translations large-files.md (Spanish) [ci skip] --- docs/es/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/large-files.md b/docs/es/guides/large-files.md index ac3d199..20a9cb7 100644 --- a/docs/es/guides/large-files.md +++ b/docs/es/guides/large-files.md @@ -23,5 +23,5 @@ con sil_lift.open_reader("big.lift") como reader, sil_lift.open_writer( Notas: - El resultado del escritor es exactamente el mismo que produciría el serializador canónico de documento completo para el mismo contenido; los dos modos nunca se desvían entre sí. -- El modo de transmisión en continuo no cuenta con una capa de paso directo de bytes: la salida es siempre canónica. Los residuos de nivel raíz —comentarios entre entradas y atributos fuera del esquema en ``— no se transfieren; las entradas y el encabezado están completos, incluidos los residuos. +- El modo de transmisión no reutiliza ningún byte de origen: la salida es siempre canónica. Los residuos LIFT de nivel raíz —comentarios entre entradas y atributos fuera del esquema en ``— no se transfieren; las entradas y el encabezado están completos, incluidos los residuos. - Si se produce un error en el cuerpo de un bloque `open_writer`, el archivo queda visiblemente sin terminar (sin el cierre ``); un léxico a medio escribir no debe parecer completo. From 1ab9d52a40a83ce4f8699dfa1a7023d6fada25bb Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:50 -0600 Subject: [PATCH 260/317] New translations large-files.md (Arabic) [ci skip] --- docs/ar/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/large-files.md b/docs/ar/guides/large-files.md index cf5dcd1..d2f086f 100644 --- a/docs/ar/guides/large-files.md +++ b/docs/ar/guides/large-files.md @@ -23,5 +23,5 @@ ملاحظات: - ما ينتجه الكاتب هو بالضبط ما سينتج عنه مُسلسل النص القياسي الكامل لنفس المحتوى — ولا يحدث أي تباين بين الوضعين أبدًا. -- لا يحتوي وضع البث على طبقة تمرير البايتات: يكون الإخراج دائمًا في صيغته القياسية. لا يتم نقل «البقايا على مستوى الجذر» — وهي التعليقات الموجودة بين البنود والسمات الخارجة عن المخطط في `` —؛ حيث تكون البنود والرأس كاملة، بما في ذلك البقايا. +- لا يعيد وضع البث استخدام أي بايتات من المصدر: يكون الإخراج دائمًا في صيغته القياسية. لا يتم نقل بقايا LIFT على مستوى الجذر — التعليقات الموجودة بين المدخلات والسمات الخارجة عن المخطط في `` —؛ فالمدخلات والرأس كاملة، بما في ذلك البقايا. - إذا حدث استثناء داخل كتلة `open_writer`، يُترك الملف في حالة غير مكتملة بشكل واضح (بدون `` ختامي) — فلا يجب أن يبدو المعجم الذي لم يكتمل كتابته بعد وكأنه مكتمل. From 262ccc3da8238f3da7234e67ec576e9a43e4cc99 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:52 -0600 Subject: [PATCH 261/317] New translations large-files.md (German) [ci skip] --- docs/de/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/large-files.md b/docs/de/guides/large-files.md index 23df7ee..6d1c8f9 100644 --- a/docs/de/guides/large-files.md +++ b/docs/de/guides/large-files.md @@ -23,5 +23,5 @@ mit sil_lift.open_reader("big.lift") als reader, sil_lift.open_writer( Anmerkungen: - Die Ausgabe des Writers entspricht genau dem, was der kanonische Serializer für das gesamte Dokument bei denselben Inhalten erzeugen würde – die beiden Modi weichen nie voneinander ab. -- Der Streaming-Modus verfügt über keine Byte-Passthrough-Schicht: Die Ausgabe erfolgt immer im kanonischen Format. Reste auf der obersten Ebene – Kommentare zwischen Einträgen und schemenfremde Attribute unter `` – werden nicht übertragen; Einträge und der Header sind vollständig, einschließlich der Reste. +- Im Streaming-Modus werden keine Quellbytes wiederverwendet: Die Ausgabe ist immer kanonisch. LIFT-Reste auf Root-Ebene – Kommentare zwischen Einträgen und schemenfremde Attribute unter `` – werden nicht übernommen; Einträge und der Header sind vollständig, einschließlich der Reste. - Wenn im Hauptteil eines `open_writer`-Blocks ein Fehler ausgelöst wird, bleibt die Datei sichtbar unvollständig (kein abschließendes ``) – ein nur zur Hälfte geschriebenes Lexikon darf nicht vollständig erscheinen. From 64c929188bf76f312820d6ee45412555c8806729 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:53 -0600 Subject: [PATCH 262/317] New translations large-files.md (Japanese) [ci skip] --- docs/ja/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/large-files.md b/docs/ja/guides/large-files.md index 3fa8c12..1b4065e 100644 --- a/docs/ja/guides/large-files.md +++ b/docs/ja/guides/large-files.md @@ -23,5 +23,5 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( 注記: - このライタの出力は、同じコンテンツに対してフルドキュメントの正規シリアライザが生成するものと完全に一致します。この2つのモードの間で結果にずれが生じることはありません。 -- ストリーミングモードにはバイトパススルー層が存在しないため、出力は常に正規化された形式となる。 ルートレベルの残余(エントリ間のコメントや、`` 上のスキーマ外属性)は転送されません。エントリとヘッダーは、残余を含めて完全な状態で転送されます。 +- ストリーミングモードでは、ソースのバイトは再利用されません。出力は常に正規化された状態になります。 ルートレベルのLIFT残余(``上のエントリ間のコメントやスキーマ外属性)は転送されません。エントリとヘッダーは、残余を含めて完全な状態で転送されます。 - `open_writer` ブロックの本体で例外が発生した場合、ファイルは明らかに未完了の状態(`` による閉じ処理が行われていない)のまま残されます。つまり、書きかけの辞書は完了しているように見えてはなりません。 From 98be8c3b972d6eb1b59b60a6fce6d86654576630 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:55 -0600 Subject: [PATCH 263/317] New translations large-files.md (Portuguese) [ci skip] --- docs/pt/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/large-files.md b/docs/pt/guides/large-files.md index 00c271b..ca9bd44 100644 --- a/docs/pt/guides/large-files.md +++ b/docs/pt/guides/large-files.md @@ -23,5 +23,5 @@ com sil_lift.open_reader("big.lift") como reader, sil_lift.open_writer( Notas: - O resultado gerado pelo escritor é exatamente o que o serializador canónico de documento completo produziria para o mesmo conteúdo — os dois modos nunca divergem. -- O modo de streaming não possui uma camada de passagem direta de bytes: a saída é sempre canónica. Os resíduos ao nível da raiz — comentários entre entradas e atributos fora do esquema em `` — não são transportados; as entradas e o cabeçalho estão completos, incluindo os resíduos. +- O modo de transmissão contínua não reutiliza bytes da fonte: a saída é sempre canónica. Os resíduos LIFT ao nível da raiz — comentários entre entradas e atributos fora do esquema em `` — não são transportados; as entradas e o cabeçalho estão completos, incluindo os resíduos. - Se ocorrer uma exceção no corpo de um bloco `open_writer`, o ficheiro fica visivelmente incompleto (sem o comando de fecho ``) — um léxico parcialmente escrito não deve parecer completo. From 3c538a1c11d358860df6291d0c9f90495e7c1128 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:57 -0600 Subject: [PATCH 264/317] New translations large-files.md (Russian) [ci skip] --- docs/ru/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/large-files.md b/docs/ru/guides/large-files.md index 5faab2b..31b9ced 100644 --- a/docs/ru/guides/large-files.md +++ b/docs/ru/guides/large-files.md @@ -23,5 +23,5 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( Примечания: - Результат работы этого модуля полностью соответствует тому, что выдал бы канонический сериализатор полного документа для того же самого контента — эти два режима никогда не расходятся. -- В режиме потоковой передачи отсутствует уровень пропуска байтов: выходные данные всегда имеют канонический вид. Остаточные данные корневого уровня — комментарии между записями и атрибуты, выходящие за пределы схемы, в файле `` — не передаются; записи и заголовок передаются в полном виде, включая остаточные данные. +- В режиме потоковой передачи байты исходных данных не используются повторно: выходные данные всегда являются каноническими. Остаточные данные LIFT на корневом уровне — комментарии между записями и атрибуты, выходящие за рамки схемы, на `` — не передаются; записи и заголовок являются полными, включая остаточные данные. - Если в теле блока `open_writer` происходит исключение, файл остается видимо незавершенным (без закрывающего ``) — частично записанный лексикон не должен выглядеть завершенным. From 72a7f1b69beddc146a8016bb2d55a88b4539bab8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:32:59 -0600 Subject: [PATCH 265/317] New translations large-files.md (Chinese Simplified) [ci skip] --- docs/zh/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/large-files.md b/docs/zh/guides/large-files.md index f0278a8..dc3a619 100644 --- a/docs/zh/guides/large-files.md +++ b/docs/zh/guides/large-files.md @@ -23,5 +23,5 @@ with sil_lift.open_reader("big.lift") as reader: 注: - 该写入器的输出结果与全文档规范序列化器针对相同内容生成的结果完全一致——这两种模式的结果始终保持一致。 -- 流式传输模式没有字节直通层:输出始终是规范格式。 根级残留内容——即条目之间的注释以及 `` 上超出模式范围的属性——不会被传递;条目和头部内容是完整的,其中包含残留内容。 +- 流式传输模式不复用源字节:输出始终是规范的。 根级 LIFT 残留数据——即 `` 中条目之间的注释以及不符合模式的属性——不会被保留;条目和头部信息是完整的,其中包含残留数据。 - 如果 `open_writer` 代码块内部抛出异常,该文件将被标记为未终止(即没有关闭的 ``)——一个只写了一半的词汇表绝不能看起来像是完整的。 From cbbb6149ff108f209314dc9a2141e8e50160ad4e Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:01 -0600 Subject: [PATCH 266/317] New translations large-files.md (Hindi) [ci skip] --- docs/hi/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/large-files.md b/docs/hi/guides/large-files.md index e8e1cdb..2af1d65 100644 --- a/docs/hi/guides/large-files.md +++ b/docs/hi/guides/large-files.md @@ -23,5 +23,5 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( टिप्पणियाँ: - लेखक का आउटपुट बिल्कुल वैसा ही होता है जैसा पूर्ण-दस्तावेज़ कैनोनिकल सीरियलाइज़र उसी सामग्री के लिए उत्पन्न करेगा — दोनों मोड कभी अलग नहीं होते। -- स्ट्रीमिंग मोड में बाइट-पासथ्रू लेयर नहीं होती: आउटपुट हमेशा मानक होता है। रूट-स्तर का अवशेष — प्रविष्टियों के बीच और स्कीमा-बाहर के गुणों वाले `` पर टिप्पणियाँ — शामिल नहीं किया जाता; प्रविष्टियाँ और हेडर अवशेष सहित पूर्ण होते हैं। +- स्ट्रीमिंग मोड किसी भी स्रोत बाइट का पुन: उपयोग नहीं करता: आउटपुट हमेशा मानक होता है। रूट-स्तर का LIFT अवशेष — प्रविष्टियों के बीच की टिप्पणियाँ और स्कीमा-बाहर के गुण `` पर — शामिल नहीं किया जाता; प्रविष्टियाँ और हेडर पूर्ण होते हैं, अवशेष सहित। - यदि `open_writer` ब्लॉक के शरीर में raise होता है, तो फ़ाइल स्पष्ट रूप से अधूरी छोड़ दी जाती है (कोई समापन `` नहीं) — एक आधा लिखा गया शब्दकोश पूर्ण नहीं दिखना चाहिए। From 03cd6bd1bb88db556b302e13e052d9d8a9aa724a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:02 -0600 Subject: [PATCH 267/317] New translations large-files.md (Swahili) [ci skip] --- docs/sw/guides/large-files.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/large-files.md b/docs/sw/guides/large-files.md index 8363524..c4e472f 100644 --- a/docs/sw/guides/large-files.md +++ b/docs/sw/guides/large-files.md @@ -23,5 +23,5 @@ with sil_lift.open_reader("big.lift") as reader, sil_lift.open_writer( Maelezo: - Matokeo ya mwandishi ni sawa kabisa na kile ambacho serializer kanoniki kamili ya hati ingetengeneza kwa maudhui yale yale — modi hizo mbili haziwahi kutofautiana. -- Modi ya utiririshaji haina safu ya kupitisha baiti: pato daima ni kanoniki. Baki ya kiwango cha mizizi — maoni kati ya vitu na sifa zisizo za mpangilio kwenye `` — hazibebwi; vitu na kichwa ni kamili, ikijumuisha baki. +- Modi ya utiririshaji haitumii tena baiti zozote za chanzo: pato daima ni sahihi. Baki ya LIFT ya kiwango cha mizizi — maoni kati ya vipengele na sifa zisizo za mpangilio kwenye `` — haibebwi; vipengele na kichwa ni kamili, ikijumuisha baki. - Ikiwa bloku ya `open_writer` itapandishwa, faili inabaki haijakamilika wazi (bila `` ya kufunga) — kamusi iliyoandikwa nusu haipaswi kuonekana imekamilika. From 84d19b382bb74b238b3d5ac91fdeeb3cb063b417 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:04 -0600 Subject: [PATCH 268/317] New translations lift-export-interop.md (French) [ci skip] --- docs/fr/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/lift-export-interop.md b/docs/fr/guides/lift-export-interop.md index ccfea47..29df823 100644 --- a/docs/fr/guides/lift-export-interop.md +++ b/docs/fr/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - L'option `--strict` fait en sorte que les avertissements (et pas seulement les erreurs) entraînent l'échec de l'exécution. -- L'option `--no-check-media` permet d'ignorer la vérification de la présence des médias dans le système de fichiers, dont les résultats indiquant « `missing-media` » constituent un faux positif lorsque les fichiers audio/photo ne se trouvent pas dans le même répertoire que le fichier `.lift` dans l'environnement de CI. +- L'option `--no-check-media` permet d'ignorer la vérification de la présence des médias dans le système de fichiers, dont les résultats indiquant « `missing-media` » constituent un faux positif lorsque les fichiers audio/photo ne se trouvent pas dans le même dossier que le fichier `.lift` dans l'environnement CI. - L'option `--format json` affiche un seul objet JSON (`{"problems": [...], "summary": {...}}`) au lieu d'un texte lisible par l'utilisateur ; ses codes de sortie et son schéma constituent une interface prise en charge et conforme à SemVer (voir [le guide de la ligne de commande](cli.md)). - `--require-ids` génère également des erreurs lorsque des entrées ne comportent pas de `guid` ou détecte l'absence d'un `id` — ce qui s'avère utile lorsqu'une réimportation ultérieure doit mettre à jour les données existantes plutôt que de les dupliquer. From 3ef91623e9a88be708f0d14646dda6f800377611 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:06 -0600 Subject: [PATCH 269/317] New translations lift-export-interop.md (Spanish) [ci skip] --- docs/es/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/lift-export-interop.md b/docs/es/guides/lift-export-interop.md index bcc351a..714e0ff 100644 --- a/docs/es/guides/lift-export-interop.md +++ b/docs/es/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - La opción `--strict` hace que las advertencias (y no solo los errores) provoquen el fallo de la ejecución. -- `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos, cuyos resultados de `missing-media` son irrelevantes cuando los archivos de audio o fotos no se encuentran en la misma ubicación que el archivo `.lift` en la integración continua (CI). +- `--no-check-media` omite la comprobación de la presencia de archivos multimedia en el sistema de archivos, cuyos resultados de `missing-media` son falsos positivos cuando los archivos de audio o fotos no se encuentran en la misma carpeta que el archivo `.lift` en la integración continua (CI). - `--format json` muestra un único objeto JSON (`{"problems": [...], "summary": {...}}`) en lugar de texto legible para el usuario; sus códigos de salida y su esquema constituyen una interfaz compatible y sujeta a SemVer (véase [la guía de la línea de comandos](cli.md)). - `--require-ids` genera además un error si hay entradas a las que les falte un `guid` o detecta que faltan `id`s; esto resulta útil cuando, en una reimportación posterior, es necesario actualizar los datos en lugar de duplicarlos. From 11568193f8c5a608a3bccf8a5fc5951a2d75a9db Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:07 -0600 Subject: [PATCH 270/317] New translations lift-export-interop.md (Arabic) [ci skip] --- docs/ar/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/lift-export-interop.md b/docs/ar/guides/lift-export-interop.md index 65ad49d..4d7bc2f 100644 --- a/docs/ar/guides/lift-export-interop.md +++ b/docs/ar/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - يؤدي الخيار `--strict` إلى إيقاف عملية التشغيل في حالة ظهور تحذيرات (وليس الأخطاء فقط). -- تتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات، حيث تُعد نتائج `missing-media` التي تظهرها هذه العملية مجرد تشويش عندما لا تكون ملفات الصوت/الصور موجودة في نفس الموقع مع ملف `.lift` في بيئة التكامل المستمر (CI). +- تتخطى الخيار `--no-check-media` عملية التحقق من وجود الوسائط في نظام الملفات، حيث تُعد نتائج `missing-media` التي تظهرها هذه العملية مجرد تشويش عندما لا تكون ملفات الصوت أو الصور موجودة في نفس المجلد الذي يوجد فيه ملف `.lift` في بيئة التكامل المستمر (CI). - يُخرج الأمر `--format json` كائن JSON واحد (`{"problems": [...], "summary": {...}}`) بدلاً من النص المقروء؛ وتشكل رموز الخروج الخاصة به ومخططه واجهة مدعومة وخاضعة لمعايير SemVer (انظر [دليل سطر الأوامر](cli.md)). - تُظهر `--require-ids` أخطاءً إضافيةً في حالة وجود إدخالات تفتقد إلى `guid` أو في حالة وجود إدخالات تفتقد إلى `id` — وهو أمر مفيد عندما يتعين عند إعادة الاستيراد لاحقًا تحديث البيانات بدلاً من تكرارها. From c029afeecb758b3bde846ac26a29eaeea58f5a55 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:09 -0600 Subject: [PATCH 271/317] New translations lift-export-interop.md (German) [ci skip] --- docs/de/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/lift-export-interop.md b/docs/de/guides/lift-export-interop.md index b3818b1..e4f816e 100644 --- a/docs/de/guides/lift-export-interop.md +++ b/docs/de/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - Mit `--strict` führen bereits Warnungen (nicht nur Fehler) zum Abbruch der Ausführung. -- `--no-check-media` überspringt die Überprüfung des Dateisystems auf das Vorhandensein von Medien, deren `missing-media`-Ergebnisse irreführend sind, wenn sich die Audio- und Fotodateien in der CI nicht am selben Speicherort wie die `.lift`-Datei befinden. +- `--no-check-media` überspringt die Überprüfung auf das Vorhandensein von Mediendateien im Dateisystem, deren `missing-media`-Funde irreführend sind, wenn sich die Audio- und Fotodateien in der CI nicht im selben Ordner wie die `.lift`-Datei befinden. - `--format json` gibt anstelle von lesbarem Text ein einzelnes JSON-Objekt aus (`{"problems": [...], "summary": {...}}`); die Rückgabecodes und das Schema bilden eine unterstützte, SemVer-konforme Schnittstelle (siehe [das Handbuch zur Befehlszeile](cli.md)). - `--require-ids` gibt zusätzlich Fehlermeldungen aus, wenn bei Einträgen eine `guid` fehlt oder bei Sensoren eine `id` fehlt – nützlich, wenn bei einem späteren erneuten Import die Einträge aktualisiert und nicht dupliziert werden sollen. From 3cad2cb9322f56d24984ced6f622a2d27caaa28a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:11 -0600 Subject: [PATCH 272/317] New translations lift-export-interop.md (Japanese) [ci skip] --- docs/ja/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/lift-export-interop.md b/docs/ja/guides/lift-export-interop.md index 292ec46..520e4a1 100644 --- a/docs/ja/guides/lift-export-interop.md +++ b/docs/ja/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - `--strict` を指定すると、エラーだけでなく警告も実行の失敗原因となります。 -- `--no-check-media` を指定すると、ファイルシステムのメディア存在確認がスキップされます。CI環境でオーディオファイルや写真ファイルが `.lift` ファイルと同じ場所に配置されていない場合、この確認で検出される `missing-media` の結果はノイズとなるためです。 +- `--no-check-media` を指定すると、ファイルシステムのメディア存在確認がスキップされます。CIにおいて、オーディオファイルや写真ファイルが `.lift` ファイルと同じフォルダにない場合、この確認で検出される `missing-media` の結果はノイズとなるためです。 - `--format json` を指定すると、人間が読みやすいテキストの代わりに単一の JSON オブジェクト (`{"problems": [...], "summary": {...}}`) が出力されます。その終了コードとスキーマは、SemVer に準拠したサポート対象のインターフェースとなっています([コマンドラインガイド](cli.md)を参照してください)。 - `--require-ids` オプションを指定すると、`guid` が欠落しているエントリや `id` が欠落しているエントリに対して追加でエラーが発生します。これは、後で再インポートを行う際に、重複を避けるために更新のみを行う必要がある場合に役立ちます。 From 2b87fa3e532d41f57fabe933d8ad5dd078853479 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:13 -0600 Subject: [PATCH 273/317] New translations lift-export-interop.md (Portuguese) [ci skip] --- docs/pt/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/lift-export-interop.md b/docs/pt/guides/lift-export-interop.md index 0105626..aae5286 100644 --- a/docs/pt/guides/lift-export-interop.md +++ b/docs/pt/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - A opção `--strict` faz com que os avisos (e não apenas os erros) provoquem o falhanço da execução. -- A opção `--no-check-media` ignora a verificação da presença de suportes no sistema de ficheiros, cujos resultados de `missing-media` constituem ruído quando os ficheiros de áudio/fotografia não se encontram na mesma localização que o ficheiro `.lift` na CI. +- `--no-check-media` ignora a verificação da presença de ficheiros multimédia no sistema de ficheiros, cujos resultados de `missing-media` são irrelevantes quando os ficheiros de áudio/fotografias não se encontram na mesma pasta que o ficheiro `.lift` na CI. - `--format json` apresenta um único objeto JSON (`{"problems": [...], "summary": {...}}`) em vez de texto legível; os seus códigos de saída e esquema constituem uma interface suportada e abrangida pela SemVer (ver [o guia da linha de comandos](cli.md)). - `--require-ids` também apresenta erros em entradas que não tenham um `guid` ou que não tenham um `id` — útil quando uma reimportação posterior tiver de atualizar, em vez de duplicar. From 2f524643e0e3c75b6ea41464c1a89711c0c9c51d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:14 -0600 Subject: [PATCH 274/317] New translations lift-export-interop.md (Russian) [ci skip] --- docs/ru/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/lift-export-interop.md b/docs/ru/guides/lift-export-interop.md index 40935ee..9c14b9e 100644 --- a/docs/ru/guides/lift-export-interop.md +++ b/docs/ru/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - Параметр `--strict` приводит к сбою выполнения даже при появлении предупреждений (а не только ошибок). -- `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе, поскольку результаты проверки `missing-media` являются ложными срабатываниями, если аудио- и фотофайлы не находятся в одном каталоге с файлом `.lift` в CI. +- `--no-check-media` пропускает проверку наличия медиафайлов в файловой системе, поскольку результаты проверки `missing-media` являются ложными срабатываниями, если аудио- и фотофайлы в CI находятся не в той же папке, что и файл `.lift`. - `--format json` выводит один объект JSON (`{"problems": [...], "summary": {...}}`) вместо текста, понятного человеку; его коды завершения и схема представляют собой поддерживаемый интерфейс, на который распространяется спецификация SemVer (см. [руководство по командной строке](cli.md)). - `--require-ids` дополнительно выдает ошибку при обнаружении записей, в которых отсутствует `guid`, или при обнаружении элементов, в которых отсутствует `id` — это полезно, когда при последующем повторном импорте необходимо обновить данные, а не дублировать их. From b5417d80f29ee8ea67f81f87d93846803def0a65 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:16 -0600 Subject: [PATCH 275/317] New translations lift-export-interop.md (Chinese Simplified) [ci skip] --- docs/zh/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/lift-export-interop.md b/docs/zh/guides/lift-export-interop.md index acabc46..c7cb270 100644 --- a/docs/zh/guides/lift-export-interop.md +++ b/docs/zh/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - `--strict` 会使警告(而不仅仅是错误)导致运行失败。 -- `--no-check-media` 会跳过文件系统的媒体存在性检查;当音频/照片文件在持续集成(CI)环境中未与 `.lift` 文件位于同一位置时,该检查产生的 `missing-media` 错误提示属于误报。 +- `--no-check-media` 会跳过文件系统的媒体存在性检查;当音频/照片文件与 CI 中的 `.lift` 文件不在同一文件夹时,该检查得出的 `missing-media` 结果属于误报。 - `--format json` 会输出一个 JSON 对象(`{"problems": [...], "summary": {...}}`),而非可读文本;其退出代码和模式构成一个受支持且符合 SemVer 规范的接口(参见 [命令行指南](cli.md))。 - `--require-ids` 还会针对缺少 `guid` 的条目或缺少 `id` 的字段报错——这在后续重新导入时需要更新而非重复导入的情况下非常有用。 From 38c6b6b8f9a0f837fe635b780f368eca7a9c0387 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:18 -0600 Subject: [PATCH 276/317] New translations lift-export-interop.md (Hindi) [ci skip] --- docs/hi/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/lift-export-interop.md b/docs/hi/guides/lift-export-interop.md index 91b7758..419b56e 100644 --- a/docs/hi/guides/lift-export-interop.md +++ b/docs/hi/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - `--strict` चेतावनियों (केवल त्रुटियों नहीं) के कारण रन विफल हो जाता है। -- `--no-check-media` फ़ाइलसिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है, जिसकी `missing-media` निष्कर्षों से शोर होता है जब ऑडियो/फ़ोटो फ़ाइलें CI में `.lift` के साथ एक साथ नहीं होती हैं। +- `--no-check-media` फ़ाइलसिस्टम मीडिया-उपस्थिति जाँच को छोड़ देता है, जिसकी `missing-media` निष्कर्षों से शोर होता है जब ऑडियो/फ़ोटो फ़ाइलें CI में `.lift` के साथ एक ही फ़ोल्डर में नहीं होती हैं। - `--format json` मानव-पठनीय टेक्स्ट के बजाय एक एकल JSON ऑब्जेक्ट (`{"problems": [...], "summary": {...}}`) प्रिंट करता है; इसके एग्जिट कोड और स्कीमा एक समर्थित, SemVer-आच्छादित इंटरफ़ेस हैं (देखें [कमांड लाइन गाइड](cli.md))। - `--require-ids` अतिरिक्त रूप से उन प्रविष्टियों पर त्रुटि दिखाता है जिनमें `guid` नहीं है या उन सेंसों में जिनमें `id` नहीं है — यह तब उपयोगी होता है जब बाद में पुनः-आयात को डुप्लिकेट करने के बजाय अपडेट करना हो। From 887bb52d45099f1703db06e3dd5de3638df0708d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:20 -0600 Subject: [PATCH 277/317] New translations lift-export-interop.md (Swahili) [ci skip] --- docs/sw/guides/lift-export-interop.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/lift-export-interop.md b/docs/sw/guides/lift-export-interop.md index e25cb89..ee87c7f 100644 --- a/docs/sw/guides/lift-export-interop.md +++ b/docs/sw/guides/lift-export-interop.md @@ -24,7 +24,7 @@ sil-lift validate export.lift --strict --no-check-media --format json ``` - `--strict` hufanya maonyo (sio tu makosa) kusababisha utekelezaji kushindikana. -- `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili, ambao matokeo yake ya `missing-media` ni kelele tu wakati faili za sauti/picha haziko pamoja na `.lift` katika CI. +- `--no-check-media` hupuuza ukaguzi wa uwepo wa media kwenye mfumo wa faili, ambao matokeo yake ya `missing-media` ni kelele tu wakati faili za sauti/picha haziko kwenye folda moja na `.lift` katika CI. - `--format json` huchapisha kitu kimoja cha JSON (`{"problems": [...], "summary": {...}}`) badala ya maandishi ya kawaida; misimbo yake ya kutoka na schema ni kiolesura kinachotumika kinachofunikwa na SemVer (tazama [mwongozo wa mstari wa amri](cli.md)). - `--require-ids` pia hutoa hitilafu kwa maingizo yanayokosa `guid` au `id` — ni muhimu wakati uingizaji upya wa baadaye unapaswa kusasisha badala ya kurudia. From 344354386f28af2043af7eb168f4cf7e7a66404d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:21 -0600 Subject: [PATCH 278/317] New translations read-edit-write.md (French) [ci skip] --- docs/fr/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/read-edit-write.md b/docs/fr/guides/read-edit-write.md index 7613c22..693c0f7 100644 --- a/docs/fr/guides/read-edit-write.md +++ b/docs/fr/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -La fonction `load()` accepte tout document LIFT **0.13** correctement formé, y compris les fichiers réels dont le schéma n'est pas valide. Tout ce qui n'est pas défini par le modèle (éléments ou attributs inconnus, commentaires) est conservé sans perte dans le compartiment opaque `extra` de chaque nœud. Les autres versions de LIFT génèrent une exception `LiftParseError` indiquant le nom de la version. +La fonction `load()` accepte tout document LIFT **0.13** correctement formé, y compris les fichiers réels dont le schéma n'est pas valide. Tout ce qui n'est pas défini par le modèle (éléments/attributs inconnus, commentaires) est conservé sans perte sous forme de résidu LIFT dans le champ opaque `extra` de chaque nœud. Les autres versions de LIFT génèrent une exception `LiftParseError` indiquant le nom de la version. ## Le modèle From 2c511e7847ee2e965cb460b57c302989f7bc77f2 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:23 -0600 Subject: [PATCH 279/317] New translations read-edit-write.md (Spanish) [ci skip] --- docs/es/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/read-edit-write.md b/docs/es/guides/read-edit-write.md index 27820e8..75bad19 100644 --- a/docs/es/guides/read-edit-write.md +++ b/docs/es/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -La función `load()` admite cualquier documento LIFT **0.13** bien formado, incluidos los archivos reales que no cumplen con el esquema. Todo aquello que el modelo no defina (elementos o atributos desconocidos, comentarios) se transmite sin pérdida de información en el campo opaco `extra` de cada nodo. Otras versiones de LIFT generan un error `LiftParseError` indicando la versión. +La función `load()` admite cualquier documento LIFT **0.13** bien formado, incluidos los archivos reales que no cumplen con el esquema. Todo aquello que el modelo no defina (elementos o atributos desconocidos, comentarios) se transmite sin pérdida de información como residuo LIFT en el campo opaco `extra` de cada nodo. Otras versiones de LIFT generan un error `LiftParseError` indicando la versión. ## El modelo From 7b6ae08490fc162914157f14613338ed915902d4 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:24 -0600 Subject: [PATCH 280/317] New translations read-edit-write.md (Arabic) [ci skip] --- docs/ar/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/read-edit-write.md b/docs/ar/guides/read-edit-write.md index 755de82..709737e 100644 --- a/docs/ar/guides/read-edit-write.md +++ b/docs/ar/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -تقبل الدالة `load()` أي مستند LIFT **0.13** صحيح التكوين — بما في ذلك الملفات الواقعية التي لا تتوافق مع المخطط. يتم نقل أي شيء لا يحدده النموذج (العناصر/السمات غير المعروفة، التعليقات) دون أي فقدان للبيانات في حاوية `extra` غير الشفافة لكل عقدة. أما الإصدارات الأخرى من LIFT، فتُحدث استثناءً من نوع `LiftParseError` مع ذكر اسم الإصدار. +تقبل الدالة `load()` أي مستند LIFT **0.13** صحيح التكوين — بما في ذلك الملفات الواقعية التي لا تتوافق مع المخطط. يتم نقل أي شيء لا يحدده النموذج (العناصر/السمات غير المعروفة، التعليقات) دون أي فقدان للبيانات باعتباره «بقايا LIFT» في الحقل غير الشفاف `extra` لكل عقدة. أما الإصدارات الأخرى من LIFT، فتُحدث استثناءً من نوع `LiftParseError` مع ذكر اسم الإصدار. ## النموذج From 422583f5af5941cd991f1a6389d99b8076a8754a Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:26 -0600 Subject: [PATCH 281/317] New translations read-edit-write.md (German) [ci skip] --- docs/de/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/read-edit-write.md b/docs/de/guides/read-edit-write.md index 29338f0..c16977d 100644 --- a/docs/de/guides/read-edit-write.md +++ b/docs/de/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` akzeptiert jedes wohlgeformte LIFT-**0.13**-Dokument – einschließlich schemaverstossender Dateien aus der Praxis. Alles, was das Modell nicht definiert (unbekannte Elemente/Attribute, Kommentare), wird verlustfrei im undurchsichtigen `extra`-Bereich jedes Knotens übertragen. Andere LIFT-Versionen lösen einen `LiftParseError` aus, in dem die Version angegeben wird. +`load()` akzeptiert jedes wohlgeformte LIFT-**0.13**-Dokument – einschließlich schemaverstossender Dateien aus der Praxis. Alles, was das Modell nicht definiert (unbekannte Elemente/Attribute, Kommentare), wird verlustfrei als LIFT-Rest im undurchsichtigen `extra`-Feld jedes Knotens übertragen. Andere LIFT-Versionen lösen einen `LiftParseError` aus, in dem die Version angegeben wird. ## Das Modell From 2badf4340a59d5698b738268df2398f0ff5f9145 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:27 -0600 Subject: [PATCH 282/317] New translations read-edit-write.md (Japanese) [ci skip] --- docs/ja/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/read-edit-write.md b/docs/ja/guides/read-edit-write.md index 7498900..0cd5de6 100644 --- a/docs/ja/guides/read-edit-write.md +++ b/docs/ja/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` は、スキーマに準拠していない実世界のファイルを含め、形式が正しい LIFT **0.13** ドキュメントであればどれでも受け付けます。 モデルで定義されていないもの(未知の要素や属性、コメントなど)は、各ノードの不透明な `extra` バケットにロスレスで格納されます。 その他の LIFT バージョンでは、そのバージョン名を指定した `LiftParseError` が発生します。 +`load()` は、スキーマに準拠していない実世界のファイルを含め、形式が正しい LIFT **0.13** ドキュメントであればどれでも受け付けます。 モデルで定義されていないもの(未知の要素や属性、コメントなど)は、各ノードの不透明な `extra` フィールドに LIFT 残余として、情報を失うことなく保持されます。 その他の LIFT バージョンでは、そのバージョン名を指定した `LiftParseError` が発生します。 ## モデル From c5d7fba690a9d07e62a095679ab31211c6ea8863 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:29 -0600 Subject: [PATCH 283/317] New translations read-edit-write.md (Portuguese) [ci skip] --- docs/pt/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/read-edit-write.md b/docs/pt/guides/read-edit-write.md index 58826a6..d25e5b1 100644 --- a/docs/pt/guides/read-edit-write.md +++ b/docs/pt/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -A função `load()` aceita qualquer documento LIFT **0.13** bem formado — incluindo ficheiros reais que não estejam em conformidade com o esquema. Tudo o que o modelo não definir (elementos/atributos desconhecidos, comentários) é transportado sem perdas no compartimento opaco `extra` de cada nó. Outras versões do LIFT provocam um `LiftParseError` indicando a versão. +A função `load()` aceita qualquer documento LIFT **0.13** bem formado — incluindo ficheiros reais que não estejam em conformidade com o esquema. Tudo o que o modelo não definir (elementos/atributos desconhecidos, comentários) é transportado sem perdas como resíduo LIFT no campo opaco `extra` de cada nó. Outras versões do LIFT provocam um `LiftParseError` indicando a versão. ## O modelo From 194da4983d7188c341be66a588070993cfcebed1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:30 -0600 Subject: [PATCH 284/317] New translations read-edit-write.md (Russian) [ci skip] --- docs/ru/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/read-edit-write.md b/docs/ru/guides/read-edit-write.md index a4b9e1d..0a1af59 100644 --- a/docs/ru/guides/read-edit-write.md +++ b/docs/ru/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -Функция `load()` принимает любой корректно сформированный документ LIFT **0.13** — в том числе реальные файлы, не соответствующие схеме. Все, что не определено в модели (неизвестные элементы/атрибуты, комментарии), без потерь передается в непрозрачный контейнер `extra` каждого узла. Другие версии LIFT вызывают исключение `LiftParseError`, указывая номер версии. +Функция `load()` принимает любой корректно сформированный документ LIFT **0.13** — в том числе реальные файлы, не соответствующие схеме. Все, что не определено в модели (неизвестные элементы/атрибуты, комментарии), передается без потерь в виде остаточного данных LIFT в непрозрачном поле `extra` каждого узла. Другие версии LIFT вызывают исключение `LiftParseError`, указывая номер версии. ## Модель From fb9eb10baf1b5bfd9a4e98c3bc54c75b26a63c34 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:32 -0600 Subject: [PATCH 285/317] New translations read-edit-write.md (Chinese Simplified) [ci skip] --- docs/zh/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/read-edit-write.md b/docs/zh/guides/read-edit-write.md index 8298e1e..1eda253 100644 --- a/docs/zh/guides/read-edit-write.md +++ b/docs/zh/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` 接受任何格式正确的 LIFT **0.13** 文档——包括那些不符合模式规范的实际文件。 模型未定义的任何内容(未知元素/属性、注释)都会以无损方式保存在每个节点的不透明 `extra` 存储区中。 其他 LIFT 版本会抛出一个名称中包含该版本号的 `LiftParseError` 异常。 +`load()` 接受任何格式正确的 LIFT **0.13** 文档——包括那些不符合模式规范的实际文件。 模型未定义的任何内容(未知元素/属性、注释)都会作为 LIFT 残余信息,无损地保存在每个节点的不透明 `extra` 字段中。 其他 LIFT 版本会抛出一个名称中包含该版本号的 `LiftParseError` 异常。 ## 该模型 From 28efa2fdfb2c356f1384fe394c07e4fc9888fdc5 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:34 -0600 Subject: [PATCH 286/317] New translations read-edit-write.md (Hindi) [ci skip] --- docs/hi/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/read-edit-write.md b/docs/hi/guides/read-edit-write.md index b0e5a6e..5cffeca 100644 --- a/docs/hi/guides/read-edit-write.md +++ b/docs/hi/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` कोई भी सुव्यवस्थित LIFT **0.13** दस्तावेज़ स्वीकार करता है — जिसमें स्कीमा-अमान्य वास्तविक-विश्व फ़ाइलें भी शामिल हैं। मॉडल द्वारा परिभाषित नहीं की गई कोई भी चीज़ (अज्ञात तत्व/गुणधर्म, टिप्पणियाँ) प्रत्येक नोड के अपारदर्शी `extra` बकेट में बिना किसी हानि के रखी जाती है। अन्य LIFT संस्करण संस्करण का नाम बताते हुए `LiftParseError` उत्पन्न करते हैं। +`load()` कोई भी सुव्यवस्थित LIFT **0.13** दस्तावेज़ स्वीकार करता है — जिसमें स्कीमा-अमान्य वास्तविक-विश्व फ़ाइलें भी शामिल हैं। मॉडल द्वारा परिभाषित न किए गए कोई भी तत्व (अज्ञात तत्व/गुणधर्म, टिप्पणियाँ) प्रत्येक नोड के अपारदर्शी `extra` फ़ील्ड में LIFT अवशेष के रूप में बिना किसी हानि के संचित किया जाता है। अन्य LIFT संस्करण संस्करण का नाम बताते हुए `LiftParseError` उत्पन्न करते हैं। ## मॉडल From 0d4514b26b41c03d92e288dc47ca33bdf5e69e01 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:35 -0600 Subject: [PATCH 287/317] New translations read-edit-write.md (Swahili) [ci skip] --- docs/sw/guides/read-edit-write.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/read-edit-write.md b/docs/sw/guides/read-edit-write.md index 5bbb5d6..cbb41ff 100644 --- a/docs/sw/guides/read-edit-write.md +++ b/docs/sw/guides/read-edit-write.md @@ -8,7 +8,7 @@ import sil_lift lex = sil_lift.load("dictionary.lift") ``` -`load()` hukubali hati yoyote ya LIFT **0.13** iliyopangwa vizuri — ikiwa ni pamoja na faili halisi zisizoendana na skema. Chochote ambacho mfano haujatambua (vipengele/sifa zisizojulikana, maoni) huhifadhiwa bila kupoteza katika kikapu kisichoeleweka cha `extra` cha kila node. Toleo zingine za LIFT hutoa `LiftParseError` ikitaja toleo. +`load()` hukubali hati yoyote ya LIFT **0.13** iliyopangwa vizuri — ikiwa ni pamoja na faili halisi zisizoendana na skema. Chochote ambacho mfano haujafafanua (vipengele/sifa zisizojulikana, maoni) huhifadhiwa bila kupoteza kama mabaki ya LIFT katika uwanja wa `extra` usio wazi wa kila node. Toleo zingine za LIFT hutoa `LiftParseError` ikitaja toleo. ## Mfano From 47cd15a75f8fc7243cf2b680dd1f6350401bf0ed Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:37 -0600 Subject: [PATCH 288/317] New translations validate.md (French) [ci skip] --- docs/fr/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/validate.md b/docs/fr/guides/validate.md index 8898dca..6cd62ea 100644 --- a/docs/fr/guides/validate.md +++ b/docs/fr/guides/validate.md @@ -22,7 +22,7 @@ Chaque « problème » comporte un « niveau » (« erreur »/« avertissement ## Les couches -1. **RELAX NG** par rapport à la grammaire LIFT 0.13 (fournie par lift-standard). +1. **RELAX NG** par rapport à la grammaire LIFT 0.13 (fournie par lift-standard — une copie identique au niveau des octets intégrée à ce paquet). 2. **Schéma Ranges** — le fichier `lift-ranges-0.13.rng` de ce projet — s'applique à tous les compagnons `.lift-ranges` suivis. 3. **Vérifications sémantiques** que la grammaire ne permet pas d'exprimer : `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From fa48b9d8ecb49eead6de60f0d629a14e7f939197 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:38 -0600 Subject: [PATCH 289/317] New translations validate.md (Spanish) [ci skip] --- docs/es/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/validate.md b/docs/es/guides/validate.md index d009e1e..8c94ab9 100644 --- a/docs/es/guides/validate.md +++ b/docs/es/guides/validate.md @@ -22,7 +22,7 @@ Cada «Problema» incluye un «nivel» («error»/«advertencia»), un «código ## Las capas -1. **RELAX NG** con respecto a la gramática LIFT 0.13 (incluida en lift-standard). +1. **RELAX NG** con respecto a la gramática LIFT 0.13 (incluida en lift-standard —una copia idéntica al byte, incorporada a este paquete). 2. **Esquema de rangos** —el archivo `lift-ranges-0.13.rng` de este proyecto— sobre cada complemento `.lift-ranges` al que se realiza un seguimiento. 3. **Comprobaciones semánticas** que la gramática no puede expresar: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From e6d874e7b22eaf56393c241c28bcef76ea0f5ecc Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:40 -0600 Subject: [PATCH 290/317] New translations validate.md (Arabic) [ci skip] --- docs/ar/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/validate.md b/docs/ar/guides/validate.md index 3e31967..4131e15 100644 --- a/docs/ar/guides/validate.md +++ b/docs/ar/guides/validate.md @@ -22,7 +22,7 @@ problems = list(lex.iter_problems()) ## الطبقات -1. **RELAX NG** وفقًا لقواعد النحو LIFT 0.13 (المُدرجة في مكتبة lift-standard). +1. **RELAX NG** وفقًا لقواعد النحو LIFT 0.13 (مأخوذة من lift-standard — وهي نسخة مطابقة تمامًا من حيث البايتات تم تضمينها في هذه الحزمة). 2. **مخطط النطاقات** — ملف `lift-ranges-0.13.rng` الخاص بهذا المشروع — على كل مرفق `.lift-ranges` يتم تتبعه. 3. **التحققات الدلالية** التي لا يمكن للقواعد النحوية التعبير عنها: `duplicate-guid`، `dangling-ref`، `range-parent`، `undefined-range-value`، `duplicate-form-lang`، `missing-media`. From 993f50780d530a46f9c8926443e014cc1d11eca0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:45 -0600 Subject: [PATCH 291/317] New translations validate.md (German) [ci skip] --- docs/de/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/validate.md b/docs/de/guides/validate.md index 1bfc68c..3e7ab1d 100644 --- a/docs/de/guides/validate.md +++ b/docs/de/guides/validate.md @@ -22,7 +22,7 @@ Jedes `Problem` enthält einen `Level` (`"error"`/`"warning"`), einen festen `Co ## Die Schichten -1. **RELAX NG** im Vergleich zur LIFT 0.13-Grammatik (aus „lift-standard“ bezogen). +1. **RELAX NG** gemäß der LIFT 0.13-Grammatik (aus „lift-standard“ übernommen – eine byteweise identische Kopie, die in dieses Paket integriert wurde). 2. **Ranges-Schema** – in diesem Projekt `lift-ranges-0.13.rng` – für jeden erfassten `.lift-ranges`-Begleiter. 3. **Semantische Prüfungen**, die die Grammatik nicht ausdrücken kann: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From 0e82be7ee74bdbdeeff603f2835c691b0ebb22a8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:47 -0600 Subject: [PATCH 292/317] New translations validate.md (Japanese) [ci skip] --- docs/ja/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/validate.md b/docs/ja/guides/validate.md index 3ecd15b..56a6bba 100644 --- a/docs/ja/guides/validate.md +++ b/docs/ja/guides/validate.md @@ -22,7 +22,7 @@ problems = list(lex.iter_problems()) ## レイヤー -1. **RELAX NG** を、LIFT 0.13 の文法(lift-standard からベンダー提供されているもの)に対して適用します。 +1. **RELAX NG** による LIFT 0.13 文法との照合(lift-standard からベンダー提供されたもの — 本パッケージにコミットされたバイト単位で同一のコピー)。 2. **Rangesスキーマ** — このプロジェクトの `lift-ranges-0.13.rng` — は、追跡対象のすべての `.lift-ranges` コンパニオンに対して適用されます。 3. **文法では表現できないセマンティックチェック**:`duplicate-guid`、`dangling-ref`、`range-parent`、`undefined-range-value`、`duplicate-form-lang`、`missing-media`。 From dc059e69135854b4b24a46aeb8933dc99a9f612c Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:52 -0600 Subject: [PATCH 293/317] New translations validate.md (Portuguese) [ci skip] --- docs/pt/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/validate.md b/docs/pt/guides/validate.md index 18e2cac..cb66815 100644 --- a/docs/pt/guides/validate.md +++ b/docs/pt/guides/validate.md @@ -22,7 +22,7 @@ Cada `Problema` contém um `nível` (`"erro"`/`"aviso"`), um `código` fixo, uma ## As camadas -1. **RELAX NG** em relação à gramática LIFT 0.13 (fornecida pelo lift-standard). +1. **RELAX NG** em relação à gramática LIFT 0.13 (fornecida pelo lift-standard — uma cópia byte a byte incorporada neste pacote). 2. **Esquema de intervalos** — o ficheiro `lift-ranges-0.13.rng` deste projeto — sobre todos os companheiros `.lift-ranges` monitorizados. 3. **Verificações semânticas** que a gramática não consegue expressar: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From 7d2fe4e6766582f174c823443ff639c5b6f47672 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:57 -0600 Subject: [PATCH 294/317] New translations validate.md (Russian) [ci skip] --- docs/ru/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/validate.md b/docs/ru/guides/validate.md index 571516e..e707f0f 100644 --- a/docs/ru/guides/validate.md +++ b/docs/ru/guides/validate.md @@ -22,7 +22,7 @@ problems = list(lex.iter_problems()) ## Слои -1. **RELAX NG** в сопоставлении с грамматикой LIFT 0.13 (включенной из пакета lift-standard). +1. **RELAX NG** в соответствии с грамматикой LIFT 0.13 (включенной из пакета lift-standard — это байт-идентичная копия, добавленная в данный пакет). 2. **Схема диапазонов** — файл `lift-ranges-0.13.rng` данного проекта — для каждого отслеживаемого компаньона `.lift-ranges`. 3. **Семантические проверки**, которые не могут быть выражены с помощью грамматики: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From 44de8f3e9c74cda7c4f9e8b0293e1552039ac34b Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:33:59 -0600 Subject: [PATCH 295/317] New translations validate.md (Chinese Simplified) [ci skip] --- docs/zh/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/validate.md b/docs/zh/guides/validate.md index 16f7702..0009ae7 100644 --- a/docs/zh/guides/validate.md +++ b/docs/zh/guides/validate.md @@ -22,7 +22,7 @@ problems = list(lex.iter_problems()) ## 各层 -1. **RELAX NG** 基于 LIFT 0.13 语法(从 lift-standard 引入)。 +1. **RELAX NG** 基于 LIFT 0.13 语法(从 lift-standard 引入——这是一个与本包中提交的版本字节级完全一致的副本)。 2. **范围模式** —— 本项目的 `lift-ranges-0.13.rng` —— 适用于所有被追踪的 `.lift-ranges` 伴生类。 3. **语义检查**:语法无法表达以下情况:`duplicate-guid`、`dangling-ref`、`range-parent`、`undefined-range-value`、`duplicate-form-lang`、`missing-media`。 From bb7ea04d02426ab61c42bc1933be6391674b17d8 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:34:01 -0600 Subject: [PATCH 296/317] New translations validate.md (Hindi) [ci skip] --- docs/hi/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/validate.md b/docs/hi/guides/validate.md index 04f26b6..69b903b 100644 --- a/docs/hi/guides/validate.md +++ b/docs/hi/guides/validate.md @@ -22,7 +22,7 @@ problems = list(lex.iter_problems()) ## परतें -1. LIFT 0.13 व्याकरण (lift-standard से विक्रेता) के विरुद्ध RELAX NG। +1. LIFT 0.13 व्याकरण के विरुद्ध RELAX NG (lift-standard से विक्रेता — इस पैकेज में प्रतिबद्ध एक बाइट-समान प्रति)। 2. **रेंज स्कीमा** — इस प्रोजेक्ट का `lift-ranges-0.13.rng` — प्रत्येक ट्रैक किए गए `.lift-ranges` साथी पर। 3. **सेमांटिक जाँचें** जिन्हें व्याकरण व्यक्त नहीं कर सकता: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`। From 3809afd8a22d8c3d028f22a78b146713b3ca74b1 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Wed, 12 Aug 2026 12:34:02 -0600 Subject: [PATCH 297/317] New translations validate.md (Swahili) [ci skip] --- docs/sw/guides/validate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/validate.md b/docs/sw/guides/validate.md index 6357ffe..9c2fb9a 100644 --- a/docs/sw/guides/validate.md +++ b/docs/sw/guides/validate.md @@ -22,7 +22,7 @@ Kila `Problem` ina `level` (`"error"`/`"warning"`), `code` thabiti, `message`, n ## Tabaka -1. **RELAX NG** dhidi ya sarufi ya LIFT 0.13 (iliyotolewa na lift-standard). +1. **RELAX NG** dhidi ya sarufi ya LIFT 0.13 (iliyotolewa kutoka lift-standard — nakala inayofanana byte kwa byte iliyowekwa katika kifurushi hiki). 2. **Rangi za schema** — `lift-ranges-0.13.rng` ya mradi huu — juu ya kila kiambatisho cha `.lift-ranges` kinachofuatiliwa. 3. **Ukaguzi wa semantiki** ambao sarufi haiwezi kuonyesha: `duplicate-guid`, `dangling-ref`, `range-parent`, `undefined-range-value`, `duplicate-form-lang`, `missing-media`. From b6af7f80acf2992f73f1a3f51a1556c2c7630ce0 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:01 -0600 Subject: [PATCH 298/317] New translations cli.md (French) [ci skip] --- docs/fr/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fr/guides/cli.md b/docs/fr/guides/cli.md index 3f7f121..82f159c 100644 --- a/docs/fr/guides/cli.md +++ b/docs/fr/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] La commande `sort` ne modifie que le fichier `.lift` ; les fichiers `.lift-ranges` associés restent inchangés (triez-les séparément à l'aide de l'API `RangesFile`). -Les commandes `validate`, `stats`, `check-media` et `export` acceptent également un paquet LIFT compressé (un fichier `.zip` dans l'une ou l'autre des structures suivantes : fichiers à la racine de l'archive ou imbriqués dans un dossier de niveau supérieur) ; celui-ci est extrait dans un répertoire temporaire puis supprimé une fois la commande terminée. +Les commandes `validate`, `stats`, `check-media` et `export` acceptent également un paquet LIFT compressé (un fichier `.zip` dans l'une ou l'autre des structures suivantes : fichiers à la racine de l'archive ou imbriqués dans un dossier de niveau supérieur) ; celui-ci est extrait dans un répertoire temporaire puis supprimé une fois la commande terminée. Les commandes de streaming `stats` et `export` n'extraient que le fichier `.lift` lui-même, ce qui leur permet de rester peu gourmandes en ressources pour les paquets contenant beaucoup de données multimédia ; les commandes `validate` et `check-media` ont besoin du dossier entier et l'extraient dans son intégralité. Exemples : From ebd338e353cefee72fd1aa0d3b99ad74101f65ed Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:02 -0600 Subject: [PATCH 299/317] New translations cli.md (Spanish) [ci skip] --- docs/es/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/es/guides/cli.md b/docs/es/guides/cli.md index 990766e..4ff7fbc 100644 --- a/docs/es/guides/cli.md +++ b/docs/es/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` solo reescribe el archivo `.lift`; los archivos complementarios `.lift-ranges` se mantienen sin modificar (ordénalos por separado con la API `RangesFile`). -`validate`, `stats`, `check-media` y `export` también admiten un paquete LIFT comprimido (un archivo `.zip` con cualquiera de las dos estructuras: archivos en la raíz del archivo comprimido o anidados dentro de una carpeta de nivel superior); este se extrae a un directorio temporal y se elimina una vez finalizado el comando. +`validate`, `stats`, `check-media` y `export` también admiten un paquete LIFT comprimido (un archivo `.zip` con cualquiera de las dos estructuras: archivos en la raíz del archivo comprimido o anidados dentro de una carpeta de nivel superior); este se extrae a un directorio temporal y se elimina una vez finalizado el comando. Los comandos de streaming `stats` y `export` extraen únicamente el archivo `.lift` en sí, por lo que su ejecución no consume muchos recursos en paquetes con gran cantidad de archivos multimedia; en cambio, `validate` y `check-media` necesitan la carpeta completa y la extraen en su totalidad. Ejemplos: From 7f42a3d66bcbe9406aa92c6ffbff13f8c7127681 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:04 -0600 Subject: [PATCH 300/317] New translations cli.md (Arabic) [ci skip] --- docs/ar/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ar/guides/cli.md b/docs/ar/guides/cli.md index d36f3ca..877e66a 100644 --- a/docs/ar/guides/cli.md +++ b/docs/ar/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] تقوم الأداة `sort` بإعادة كتابة ملف `.lift` فقط؛ أما الملفات المصاحبة `.lift-ranges` فتُترك كما هي (يمكن فرزها بشكل منفصل باستخدام واجهة برمجة التطبيقات `RangesFile`). -تقبل الأوامر `validate` و`stats` و`check-media` و`export` أيضًا حزمة LIFT مضغوطة (ملف `.zip` بأي من الترتيبين — الملفات في جذر الأرشيف، أو متداخلة ضمن مجلد واحد من المستوى الأعلى)؛ حيث يتم استخراجها إلى دليل مؤقت ثم يتم حذفها عند انتهاء تنفيذ الأمر. +تقبل الأوامر `validate` و`stats` و`check-media` و`export` أيضًا حزمة LIFT مضغوطة (ملف `.zip` بأي من الترتيبين — الملفات في جذر الأرشيف، أو متداخلة ضمن مجلد واحد من المستوى الأعلى)؛ حيث يتم استخراجها إلى دليل مؤقت ثم يتم حذفها عند انتهاء تنفيذ الأمر. تستخرج أوامر البث `stats` و`export` ملف `.lift` نفسه فقط، لذا فإنها لا تستهلك موارد كثيرة عند التعامل مع الحزم التي تحتوي على ملفات وسائط كثيرة؛ أما `validate` و`check-media` فتحتاجان إلى المجلد بأكمله وتستخرجان محتوياته بالكامل. أمثلة: From 46be3c36eeb817a5cb2a99611d8ff3fc40869712 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:06 -0600 Subject: [PATCH 301/317] New translations cli.md (German) [ci skip] --- docs/de/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/de/guides/cli.md b/docs/de/guides/cli.md index a93f4b3..f57f035 100644 --- a/docs/de/guides/cli.md +++ b/docs/de/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` schreibt nur die `.lift`-Datei neu; die zugehörigen `.lift-ranges`-Dateien bleiben unberührt (sortieren Sie diese separat mit der `RangesFile`-API). -`validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls ein komprimiertes LIFT-Paket (eine `.zip`-Datei in einem der beiden Layouts – entweder mit Dateien im Stammverzeichnis des Archivs oder verschachtelt unter einem Ordner der obersten Ebene); dieses wird in ein temporäres Verzeichnis entpackt und nach Abschluss des Befehls gelöscht. +`validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls ein komprimiertes LIFT-Paket (eine `.zip`-Datei in einem der beiden Layouts – entweder mit Dateien im Stammverzeichnis des Archivs oder verschachtelt unter einem Ordner der obersten Ebene); dieses wird in ein temporäres Verzeichnis entpackt und nach Abschluss des Befehls gelöscht. Die Streaming-Befehle `stats` und `export` extrahieren nur die `.lift`-Datei selbst, sodass sie bei datenintensiven Paketen ressourcenschonend bleiben; `validate` und `check-media` benötigen den gesamten Ordner und extrahieren dessen gesamten Inhalt. Beispiele: From e1d3a3aa8a6870f4892f996da8639454e702bb30 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:08 -0600 Subject: [PATCH 302/317] New translations cli.md (Japanese) [ci skip] --- docs/ja/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ja/guides/cli.md b/docs/ja/guides/cli.md index bbcc9aa..39a31e4 100644 --- a/docs/ja/guides/cli.md +++ b/docs/ja/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` は `.lift` ファイルのみを上書きします。関連する `.lift-ranges` ファイルは変更されません (これらを並べ替えるには、`RangesFile` API を別途使用してください)。 -`validate`、`stats`、`check-media`、および `export` も、ZIP形式のLIFTパッケージ(アーカイブのルートにファイルが配置されている形式、またはトップレベルのフォルダの下にネストされている形式のいずれかの `.zip` ファイル)を受け付けます。このパッケージは一時ディレクトリに展開され、コマンドの実行完了後に削除されます。 +`validate`、`stats`、`check-media`、および `export` も、ZIP形式のLIFTパッケージ(アーカイブのルートにファイルが配置されている形式、またはトップレベルのフォルダの下にネストされている形式のいずれかの `.zip` ファイル)を受け付けます。このパッケージは一時ディレクトリに展開され、コマンドの実行完了後に削除されます。 ストリーミングコマンド `stats` および `export` は `.lift` ファイルのみを抽出するため、メディアデータが大量に含まれるパッケージでも処理負荷が低くなります。一方、`validate` および `check-media` はフォルダ全体を必要とし、その内容をすべて抽出します。 例: From bfc8e2772d4c36ce2257e14532292a96af479f7d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:10 -0600 Subject: [PATCH 303/317] New translations cli.md (Portuguese) [ci skip] --- docs/pt/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pt/guides/cli.md b/docs/pt/guides/cli.md index 21ea7ea..8e6f951 100644 --- a/docs/pt/guides/cli.md +++ b/docs/pt/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] O `sort` reescreve apenas o ficheiro `.lift`; os ficheiros `.lift-ranges` associados permanecem inalterados (organize-os separadamente com a API `RangesFile`). -Os comandos `validate`, `stats`, `check-media` e `export` também aceitam um pacote LIFT compactado (um ficheiro `.zip` com qualquer um dos dois formatos — ficheiros na raiz do arquivo ou aninhados numa pasta de nível superior); este é extraído para um diretório temporário e eliminado quando o comando termina. +Os comandos `validate`, `stats`, `check-media` e `export` também aceitam um pacote LIFT compactado (um ficheiro `.zip` com qualquer um dos dois formatos — ficheiros na raiz do arquivo ou aninhados numa pasta de nível superior); este é extraído para um diretório temporário e eliminado quando o comando termina. Os comandos de streaming `stats` e `export` extraem apenas o próprio ficheiro `.lift`, pelo que o seu custo de execução é reduzido em pacotes com muitos ficheiros multimédia; os comandos `validate` e `check-media` necessitam da pasta completa e extraem todo o seu conteúdo. Exemplos: From b55dccc678ab595eec0e2198135ca9c97dfebb22 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:12 -0600 Subject: [PATCH 304/317] New translations cli.md (Russian) [ci skip] --- docs/ru/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ru/guides/cli.md b/docs/ru/guides/cli.md index 17797e2..2fadf45 100644 --- a/docs/ru/guides/cli.md +++ b/docs/ru/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` перезаписывает только файл `.lift`; сопутствующие файлы `.lift-ranges` остаются неизменными (их следует сортировать отдельно с помощью API `RangesFile`). -Команды `validate`, `stats`, `check-media` и `export` также поддерживают заархивированный пакет LIFT (файл с расширением `.zip` в любом из двух вариантов структуры — с файлами в корневом каталоге архива или вложенными в одну папку верхнего уровня); он распаковывается во временный каталог и удаляется по завершении выполнения команды. +Команды `validate`, `stats`, `check-media` и `export` также поддерживают заархивированный пакет LIFT (файл с расширением `.zip` в любом из двух вариантов структуры — с файлами в корневом каталоге архива или вложенными в одну папку верхнего уровня); он распаковывается во временный каталог и удаляется по завершении выполнения команды. Команды потоковой обработки `stats` и `export` извлекают только сам файл `.lift`, поэтому их выполнение не требует значительных ресурсов даже для пакетов с большим объемом мультимедиа; команды `validate` и `check-media` требуют доступ к всей папке и извлекают все её содержимое. Примеры: From 2ea52c273263faebef11402ae09e5f78709bdb87 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:14 -0600 Subject: [PATCH 305/317] New translations cli.md (Chinese Simplified) [ci skip] --- docs/zh/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/zh/guides/cli.md b/docs/zh/guides/cli.md index d55df39..ed3cecf 100644 --- a/docs/zh/guides/cli.md +++ b/docs/zh/guides/cli.md @@ -21,7 +21,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` 仅重写 `.lift` 文件;配套的 `.lift-ranges` 文件则保持不变 (请使用 `RangesFile` API 单独对这些文件进行排序)。 -`validate`、`stats`、`check-media` 和 `export` 还支持接收压缩的 LIFT 包(以任何一种布局格式的 `.zip` 文件——文件位于归档根目录下,或嵌套在某个顶级文件夹下);该包会在命令执行完毕后解压到临时目录,并被自动删除。 +`validate`、`stats`、`check-media` 和 `export` 还支持接收压缩的 LIFT 包(以任何一种布局格式的 `.zip` 文件——文件位于归档根目录下,或嵌套在某个顶级文件夹下);该包会在命令执行完毕后解压到临时目录,并被自动删除。 流式处理命令 `stats` 和 `export` 仅提取 `.lift` 文件本身,因此在处理媒体资源较多的包时,其开销较低;而 `validate` 和 `check-media` 则需要整个文件夹,并将其全部提取出来。 示例: From b227ab11ddddbb48c5550843200fb8d1dfb7ba70 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:16 -0600 Subject: [PATCH 306/317] New translations cli.md (Hindi) [ci skip] --- docs/hi/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hi/guides/cli.md b/docs/hi/guides/cli.md index 293c6dc..52bee0a 100644 --- a/docs/hi/guides/cli.md +++ b/docs/hi/guides/cli.md @@ -20,7 +20,7 @@ sil-lift export PATH [-o OUT] [--langs L] [--tsv] `sort` केवल `.lift` फ़ाइल को ही पुनः लिखता है; साथी `.lift-ranges` फ़ाइलें अछूती रह जाती हैं (उन्हें `RangesFile` API के साथ अलग से क्रमबद्ध करें)। -`validate`, `stats`, `check-media`, और `export` एक ज़िप किए गए LIFT पैकेज को भी स्वीकार करते हैं (दोनों लेआउट में एक `.zip` — आर्काइव रूट में फ़ाइलें, या एक टॉप-लेवल फ़ोल्डर के अंदर); इसे एक अस्थायी निर्देशिका में निकाला जाता है और कमांड समाप्त होने पर हटा दिया जाता है। +`validate`, `stats`, `check-media`, और `export` एक ज़िप किए गए LIFT पैकेज को भी स्वीकार करते हैं (दोनों लेआउट में एक `.zip` — आर्काइव रूट में फ़ाइलें, या एक टॉप-लेवल फ़ोल्डर के अंदर); इसे एक अस्थायी निर्देशिका में निकाला जाता है और कमांड समाप्त होने पर हटा दिया जाता है। स्ट्रीमिंग कमांड्स `stats` और `export` केवल `.lift` को ही एक्सट्रेक्ट करते हैं, इसलिए ये मीडिया-भारी पैकेजों पर सस्ते पड़ते हैं; `validate` और `check-media` को पूरे फ़ोल्डर की ज़रूरत होती है और वे सब कुछ एक्सट्रेक्ट करते हैं। उदाहरण: From 8884458fc8c518d9c76d923126e582106cd0c4ef Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:18 -0600 Subject: [PATCH 307/317] New translations cli.md (Swahili) [ci skip] --- docs/sw/guides/cli.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sw/guides/cli.md b/docs/sw/guides/cli.md index 68fd55d..ac55ded 100644 --- a/docs/sw/guides/cli.md +++ b/docs/sw/guides/cli.md @@ -20,7 +20,7 @@ sil-lift export NJIA [-o OUT] [--langs L] [--tsv] `sort` inaandika upya tu faili ya `.lift`; faili zake washirika za `.lift-ranges` zinaachwa bila kuguswa (ziandike kwa mpangilio tofauti kwa kutumia API ya `RangesFile`). -`validate`, `stats`, `check-media`, na `export` pia hukubali kifurushi cha LIFT kilichobanwa (faili la `.zip` katika mpangilio wowote — faili zikiwa kwenye msingi wa hifadhi, au zimewekwa ndani ya folda moja ya ngazi ya juu); hutolewa kwenye saraka ya muda na kutupwa wakati amri inapomalizika. +`validate`, `stats`, `check-media`, na `export` pia hukubali kifurushi cha LIFT kilichobanwa (faili la `.zip` katika mpangilio wowote — faili zikiwa kwenye msingi wa hifadhi, au zimewekwa ndani ya folda moja ya ngazi ya juu); hutolewa kwenye saraka ya muda na kutupwa wakati amri inapomalizika. Amri za streaming `stats` na `export` huchukua tu `.lift` yenyewe, hivyo zinabaki nafuu kwa vifurushi vyenye media nyingi; `validate` na `check-media` zinahitaji folda nzima na huchukua yote. Mifano: From 843348e4600a83221c8e89d0acdd27ed08986cbf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:20 -0600 Subject: [PATCH 308/317] New translations lift-export-interop.md (French) [ci skip] --- docs/fr/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/fr/guides/lift-export-interop.md b/docs/fr/guides/lift-export-interop.md index 29df823..2ccc51d 100644 --- a/docs/fr/guides/lift-export-interop.md +++ b/docs/fr/guides/lift-export-interop.md @@ -8,8 +8,12 @@ Ce guide s'adresse à toute personne développant un _exportateur_ LIFT — c'es LIFT est généralement transféré sous la forme d'un seul fichier `.zip` — FieldWorks et The Combine importent et exportent tous deux de cette manière — ; ainsi, `sil-lift` lit et écrit directement les paquets compressés, quelle que soit la structure utilisée par l'écosystème : les fichiers à la racine de l'archive ou imbriqués dans un dossier de premier niveau. -- **À noter :** la commande `sil_lift.load("package.zip")` extrait le contenu dans un répertoire temporaire, localise le fichier `.lift` unique et le charge (les fichiers associés et les médias sont traités comme d'habitude). Les commandes CLI `validate`, `stats`, `check-media` et `export` acceptent également un chemin d'accès à un fichier `.zip` ; ainsi, le script ci-dessous s'exécute directement sur un paquet tel quel. La fonction d'extraction est protégée contre les fichiers malveillants : les éléments impliquant un parcours de chemin sont refusés, et le nombre d'entrées ainsi que la taille totale non compressée (10 GiB) sont plafonnés afin d'empêcher les « bombes ZIP ». -- **Écrivez :** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` regroupe le fichier `.lift`, ses fichiers `.lift-ranges` et tous les autres fichiers du dossier source (media, `WritingSystems/`, `consent/`, …) dans un fichier zip. `wrap_folder` utilise par défaut un dossier de niveau supérieur portant le nom du fichier zip (conformément à la convention d'importation de FieldWorks/Combine) ; passez `False` pour obtenir une archive plate. +- **À noter :** la commande `sil_lift.load("package.zip")` extrait le contenu dans un répertoire temporaire, localise le fichier `.lift` unique et le charge (les fichiers associés et les médias sont traités comme d'habitude). + - Les commandes CLI `validate`, `stats`, `check-media` et `export` acceptent également un chemin d'accès à un fichier `.zip` ; ainsi, le script ci-dessous s'exécute directement sur un paquet tel quel. + - les flux `stats` et `export`, et n'extraire que le fichier `.lift` plutôt que l'ensemble du paquet — afin que l'opération reste peu coûteuse sur un support contenant beaucoup de données, et que la limite d'extraction s'applique uniquement au fichier `.lift` et non à tout ce qui se trouve à côté. + - L'extraction est limitée à 10 GiB et à 100 000 éléments ; tout paquet dépassant l'une ou l'autre de ces limites est rejeté avec une erreur `LiftParseError`, tout comme ceux dont les chemins d'accès aux éléments sortent du répertoire d'extraction. +- **Écrivez :** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` regroupe le fichier `.lift`, ses fichiers `.lift-ranges` et tous les autres fichiers du dossier source (media, `WritingSystems/`, `consent/`, …) dans un fichier zip. + - `wrap_folder` utilise par défaut un dossier de niveau supérieur portant le nom du fichier zip (conformément à la convention d'importation de FieldWorks/Combine) ; passez `False` pour obtenir une archive plate. Les fichiers `.lift` et `.lift-ranges` conservent leur fidélité au niveau de l'octet au sein du paquet ; le conteneur zip lui-même n'est pas reproductible au niveau de l'octet. From 33270326fc79e2d8d34cb77bc5881d1305630a6d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:22 -0600 Subject: [PATCH 309/317] New translations lift-export-interop.md (Spanish) [ci skip] --- docs/es/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/es/guides/lift-export-interop.md b/docs/es/guides/lift-export-interop.md index 714e0ff..88a62f4 100644 --- a/docs/es/guides/lift-export-interop.md +++ b/docs/es/guides/lift-export-interop.md @@ -8,8 +8,12 @@ Escribir en LIFT es mucho más fácil que analizarlo sintácticamente: un export LIFT suele transportarse como un único archivo `.zip` —tanto FieldWorks como The Combine importan y exportan de esa forma—, por lo que `sil-lift` lee y escribe paquetes comprimidos directamente, independientemente de la estructura que utilice el ecosistema: ya sea con los archivos en la raíz del archivo comprimido o anidados dentro de una carpeta de nivel superior. -- **Nota:** `sil_lift.load("package.zip")` descomprime el archivo en un directorio temporal, localiza el único archivo `.lift` y lo carga (los archivos complementarios y multimedia se resuelven como de costumbre). Los comandos de la CLI `validate`, `stats`, `check-media` y `export` también admiten una ruta `.zip`, por lo que el proceso que se muestra a continuación se ejecuta sobre un paquete tal cual. La extracción está protegida contra archivos maliciosos: se rechazan los elementos que permiten el recorrido de rutas, y se limitan el número de entradas y el tamaño total sin comprimir (10 GiB) para evitar las «bombas ZIP». -- **Escribe:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` empaqueta el archivo `.lift`, sus archivos `.lift-ranges` y todos los demás archivos de la carpeta de origen (archivos multimedia, `WritingSystems/`, `consent/`, ...) en un archivo zip. `wrap_folder` toma por defecto una carpeta de nivel superior cuyo nombre coincide con el del archivo zip (según la convención de importación de FieldWorks/Combine); pasa `False` para obtener un archivo comprimido sin subcarpetas. +- **Nota:** `sil_lift.load("package.zip")` descomprime el archivo en un directorio temporal, localiza el único archivo `.lift` y lo carga (los archivos complementarios y multimedia se resuelven como de costumbre). + - Los comandos de la CLI `validate`, `stats`, `check-media` y `export` también admiten una ruta `.zip`, por lo que el proceso que se muestra a continuación se ejecuta sobre un paquete tal cual. + - `stats` y `export`, y extraer solo el archivo `.lift` en lugar de todo el paquete, de modo que el coste siga siendo reducido en un paquete con gran volumen de datos multimedia, y el límite de extracción se aplique únicamente al archivo `.lift` y no al resto de elementos que lo rodean. + - La extracción tiene un límite máximo de 10 GiB y 100 000 elementos; cualquier paquete que supere cualquiera de estos límites se rechaza con un `LiftParseError`, al igual que aquellos cuyos caminos de acceso a los elementos se salgan del directorio de extracción. +- **Escribe:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` empaqueta el archivo `.lift`, sus archivos `.lift-ranges` y todos los demás archivos de la carpeta de origen (archivos multimedia, `WritingSystems/`, `consent/`, ...) en un archivo zip. + - `wrap_folder` toma por defecto una carpeta de nivel superior cuyo nombre coincide con el del archivo zip (según la convención de importación de FieldWorks/Combine); pasa `False` para obtener un archivo comprimido sin subcarpetas. Los archivos `.lift` y `.lift-ranges` conservan su fidelidad a nivel de byte dentro del paquete; el propio contenedor zip no es reproducible a nivel de byte. From 9641053ed678585566cfe0b35e00ac72a5bb9f9d Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:24 -0600 Subject: [PATCH 310/317] New translations lift-export-interop.md (Arabic) [ci skip] --- docs/ar/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/ar/guides/lift-export-interop.md b/docs/ar/guides/lift-export-interop.md index 4d7bc2f..271691e 100644 --- a/docs/ar/guides/lift-export-interop.md +++ b/docs/ar/guides/lift-export-interop.md @@ -8,8 +8,12 @@ عادةً ما يتم نقل LIFT كملف `.zip` واحد — حيث يقوم كل من FieldWorks و The Combine بالاستيراد والتصدير بهذه الطريقة — لذا فإن `sil-lift` يقرأ ويكتب الحزم المضغوطة مباشرةً، بأي من الترتيبين اللذين يستخدمهما النظام البيئي: الملفات الموجودة في جذر الأرشيف، أو الملفات المتداخلة ضمن مجلد واحد من المستوى الأعلى. -- **قراءة:** تقوم `sil_lift.load("package.zip")` باستخراج الملفات إلى دليل مؤقت، وتحديد موقع ملف `.lift` الوحيد، وتحميله (يتم تحليل الملفات المصاحبة والوسائط كالمعتاد). تقبل أوامر واجهة سطر الأوامر `validate` و`stats` و`check-media` و`export` مسار ملف `.zip` أيضًا، لذا فإن البرنامج التالي يعمل على الحزمة كما هي. تم تعزيز إجراءات الاستخراج لمواجهة الملفات الضارة — حيث يتم رفض العناصر التي تتضمن اجتياز المسار، كما تم وضع حد أقصى لعدد الإدخالات والحجم الإجمالي غير المضغوط (10 جيجابايت) للحماية من «قنابل ZIP». -- **اكتب:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` يقوم بتجميع ملف `.lift` وملفات `.lift-ranges` الخاصة به، بالإضافة إلى كل الملفات الأخرى الموجودة في المجلد المصدر (الوسائط، `WritingSystems/`، `consent/`، ...) في ملف مضغوط. يتم تعيين `wrap_folder` افتراضيًّا على مجلد من المستوى الأعلى يحمل اسم ملف الـ zip (وفقًا لقواعد الاستيراد في FieldWorks/Combine)؛ قم بتمرير `False` للحصول على أرشيف مسطح. +- **قراءة:** تقوم `sil_lift.load("package.zip")` باستخراج الملفات إلى دليل مؤقت، وتحديد موقع ملف `.lift` الوحيد، وتحميله (يتم تحليل الملفات المصاحبة والوسائط كالمعتاد). + - تقبل أوامر واجهة سطر الأوامر `validate` و`stats` و`check-media` و`export` مسار ملف `.zip` أيضًا، لذا فإن البرنامج التالي يعمل على الحزمة كما هي. + - دفقَي `stats` و`export`، واستخراج ملف `.lift` فقط بدلاً من الحزمة بأكملها — بحيث تظل عملية الاستخراج خفيفة في الحزم التي تحتوي على الكثير من الوسائط، ويُطبق حد الاستخراج على ملف `.lift` وحده وليس على كل ما عدا ذلك. + - يُحدد الحد الأقصى لعملية الاستخراج بـ 10 جيجابايت و100,000 عنصر؛ ويتم رفض أي حزمة تتجاوز أيًّا من هذين الحدين مع ظهور خطأ `LiftParseError`، وكذلك الحزمة التي تتجاوز مسارات عناصرها حدود دليل الاستخراج. +- **اكتب:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` يقوم بتجميع ملف `.lift` وملفات `.lift-ranges` الخاصة به، بالإضافة إلى كل الملفات الأخرى الموجودة في المجلد المصدر (الوسائط، `WritingSystems/`، `consent/`، ...) في ملف مضغوط. + - يتم تعيين `wrap_folder` افتراضيًّا على مجلد من المستوى الأعلى يحمل اسم ملف الـ zip (وفقًا لقواعد الاستيراد في FieldWorks/Combine)؛ قم بتمرير `False` للحصول على أرشيف مسطح. يحتفظ كل من `.lift` و`.lift-ranges` بدقة البايت داخل الحزمة؛ أما حاوية zip نفسها فهي غير قابلة لإعادة إنتاج البايتات. From 219d5d114cffa93e2b9daef751c66bd7403bc488 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:25 -0600 Subject: [PATCH 311/317] New translations lift-export-interop.md (German) [ci skip] --- docs/de/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/de/guides/lift-export-interop.md b/docs/de/guides/lift-export-interop.md index e4f816e..cbde2c7 100644 --- a/docs/de/guides/lift-export-interop.md +++ b/docs/de/guides/lift-export-interop.md @@ -8,8 +8,12 @@ Das Schreiben von LIFT ist viel einfacher als dessen Analyse: Ein Exporter gibt LIFT wird in der Regel als einzelne `.zip`-Datei weitergegeben – sowohl FieldWorks als auch The Combine importieren und exportieren auf diese Weise –, daher liest und schreibt `sil-lift` komprimierte Pakete direkt, und zwar in beiden vom Ökosystem verwendeten Strukturen: entweder mit den Dateien im Stammverzeichnis des Archivs oder verschachtelt unter einem Ordner der obersten Ebene. -- **Hinweis:** `sil_lift.load("package.zip")` entpackt die Datei in ein temporäres Verzeichnis, sucht die einzelne `.lift`-Datei und lädt sie (Begleitdateien und Medien werden wie gewohnt aufgelöst). Die CLI-Befehle `validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls einen `.zip`-Pfad, sodass das unten stehende Skript direkt auf ein Paket in seiner aktuellen Form angewendet werden kann. Die Extraktion ist gegen bösartige Archive abgesichert – Elemente, die eine Pfadüberquerung bewirken, werden abgelehnt, und die Anzahl der Einträge sowie die Gesamtgröße im unkomprimierten Zustand (10 GiB) sind zur Abwehr von ZIP-Bomben begrenzt. -- **Schreiben Sie:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packt die `.lift`-Datei, deren `.lift-ranges` sowie alle anderen Dateien im Quellordner (media, `WritingSystems/`, `consent/`, ...) zusammen. in eine ZIP-Datei. `wrap_folder` ist standardmäßig auf einen Ordner auf oberster Ebene eingestellt, der nach der ZIP-Datei benannt ist (gemäß der Importkonvention von FieldWorks/Combine); übergeben Sie `False`, um ein flaches Archiv zu erhalten. +- **Hinweis:** `sil_lift.load("package.zip")` entpackt die Datei in ein temporäres Verzeichnis, sucht die einzelne `.lift`-Datei und lädt sie (Begleitdateien und Medien werden wie gewohnt aufgelöst). + - Die CLI-Befehle `validate`, `stats`, `check-media` und `export` akzeptieren ebenfalls einen `.zip`-Pfad, sodass das unten stehende Skript direkt auf ein Paket in seiner aktuellen Form angewendet werden kann. + - die Streams `stats` und `export` und extrahieren Sie nur die `.lift`-Datei statt des gesamten Pakets – so bleibt der Aufwand bei medienintensiven Paketen gering, und die Extraktionsbeschränkung gilt nur für die `.lift`-Datei und nicht für alles andere daneben. + - Die Extraktion ist auf 10 GiB und 100.000 Elemente begrenzt; ein Paket, das eine dieser Grenzen überschreitet, wird mit einem `LiftParseError` abgelehnt, ebenso wie eines, dessen Elementpfade über das Extraktionsverzeichnis hinausgehen. +- **Schreiben Sie:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` packt die `.lift`-Datei, deren `.lift-ranges` sowie alle anderen Dateien im Quellordner (media, `WritingSystems/`, `consent/`, ...) zusammen. in eine ZIP-Datei. + - `wrap_folder` ist standardmäßig auf einen Ordner auf oberster Ebene eingestellt, der nach der ZIP-Datei benannt ist (gemäß der Importkonvention von FieldWorks/Combine); übergeben Sie `False`, um ein flaches Archiv zu erhalten. Die Dateien `.lift` und `.lift-ranges` behalten ihre Byte-Genauigkeit innerhalb des Pakets bei; der ZIP-Container selbst ist nicht byte-reproduzierbar. From 3904476e045b7c98461e94269791fbd427ac8ef7 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:27 -0600 Subject: [PATCH 312/317] New translations lift-export-interop.md (Japanese) [ci skip] --- docs/ja/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/ja/guides/lift-export-interop.md b/docs/ja/guides/lift-export-interop.md index 520e4a1..323f537 100644 --- a/docs/ja/guides/lift-export-interop.md +++ b/docs/ja/guides/lift-export-interop.md @@ -8,8 +8,12 @@ LIFTの記述は、その解析よりもはるかに簡単です。エクスポ LIFTは通常、単一の`.zip`ファイルとして移動されます(FieldWorksとThe Combineはどちらもこの形式でインポートおよびエクスポートを行います)。そのため、`sil-lift`は、エコシステムで使用されるいずれのレイアウト(アーカイブのルートにファイルが配置されている場合、またはトップレベルのフォルダの下にネストされている場合)においても、zip形式のパッケージを直接読み書きします。 -- **解説:** `sil_lift.load("package.zip")` は、一時ディレクトリに解凍を行い、単一の `.lift` ファイルを検出して読み込みます(コンパニオンやメディアは通常通り解決されます)。 `validate`、`stats`、`check-media`、および`export`の各CLIコマンドも`.zip`形式のパスを指定できるため、以下のゲートはパッケージをそのままの状態で実行します。 抽出処理は、悪意のあるアーカイブに対して強化されています。パストラバーサルを目的とした要素は拒否され、ZIPボム対策として、エントリ数および展開後の総サイズ(10 GiB)に上限が設けられています。 -- **記述例:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` とすると、`.lift`、その `.lift-ranges`、およびソースフォルダ内のその他のすべてのファイル(media、`WritingSystems/`、`consent/` など)がまとめてパッケージ化されます。 zipファイルにまとめる。 `wrap_folder` のデフォルト値は、zip ファイル名と同じ名前の最上位フォルダです(FieldWorks/Combine のインポート規約に従います)。フラットなアーカイブにする場合は、`False` を指定してください。 +- **解説:** `sil_lift.load("package.zip")` は、一時ディレクトリに解凍を行い、単一の `.lift` ファイルを検出して読み込みます(コンパニオンやメディアは通常通り解決されます)。 + - `validate`、`stats`、`check-media`、および`export`の各CLIコマンドも`.zip`形式のパスを指定できるため、以下のゲートはパッケージをそのままの状態で実行します。 + - `stats` および `export` ストリームから、パッケージ全体ではなく `.lift` のみを抽出します。これにより、メディアデータが大量に含まれるパッケージでも処理負荷を抑えることができ、抽出制限は `.lift` に対してのみ適用され、それ以外の部分には適用されません。 + - 抽出の上限は10 GiBおよび100,000個のメンバーです。いずれかの制限を超えるパッケージは、メンバーのパスが抽出ディレクトリの範囲外にある場合と同様に、`LiftParseError`が発生して拒否されます。 +- **記述例:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` とすると、`.lift`、その `.lift-ranges`、およびソースフォルダ内のその他のすべてのファイル(media、`WritingSystems/`、`consent/` など)がまとめてパッケージ化されます。 zipファイルにまとめる。 + - `wrap_folder` のデフォルト値は、zip ファイル名と同じ名前の最上位フォルダです(FieldWorks/Combine のインポート規約に従います)。フラットなアーカイブにする場合は、`False` を指定してください。 `.lift` および `.lift-ranges` は、パッケージ内ではバイト単位の忠実性を維持しますが、zip コンテナ自体はバイト単位で再現可能ではありません。 From 2b33e068793d89fb60ff04f528509fb46d62e653 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:33 -0600 Subject: [PATCH 313/317] New translations lift-export-interop.md (Portuguese) [ci skip] --- docs/pt/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/pt/guides/lift-export-interop.md b/docs/pt/guides/lift-export-interop.md index aae5286..104eecc 100644 --- a/docs/pt/guides/lift-export-interop.md +++ b/docs/pt/guides/lift-export-interop.md @@ -8,8 +8,12 @@ Escrever LIFT é muito mais fácil do que analisá-lo: um exportador apenas emit O LIFT é normalmente transferido como um único ficheiro `.zip` — tanto o FieldWorks como o The Combine importam e exportam dessa forma — pelo que o `sil-lift` lê e grava pacotes compactados diretamente, independentemente do formato utilizado pelo ecossistema: os ficheiros na raiz do arquivo ou aninhados numa pasta de nível superior. -- **Nota:** `sil_lift.load("package.zip")` extrai o conteúdo para um diretório temporário, localiza o único ficheiro `.lift` e carrega-o (os ficheiros complementares e os ficheiros multimédia são resolvidos como habitualmente). Os comandos da CLI `validate`, `stats`, `check-media` e `export` também aceitam um caminho `.zip`, pelo que o gate abaixo é executado diretamente sobre um pacote tal como está. A extração está protegida contra arquivos maliciosos — os elementos que permitem a travessia de caminhos são rejeitados, e o número de entradas e o tamanho total descompactado (10 GiB) estão limitados para evitar «zip bombs». -- **Escreva:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` compacta o ficheiro `.lift`, os seus `.lift-ranges` e todos os outros ficheiros da pasta de origem (multimédia, `WritingSystems/`, `consent/`, ...) num ficheiro zip. O `wrap_folder` tem, por predefinição, uma pasta de nível superior com o nome do ficheiro zip (conforme a convenção de importação do FieldWorks/Combine); passe `False` para obter um arquivo simples. +- **Nota:** `sil_lift.load("package.zip")` extrai o conteúdo para um diretório temporário, localiza o único ficheiro `.lift` e carrega-o (os ficheiros complementares e os ficheiros multimédia são resolvidos como habitualmente). + - Os comandos da CLI `validate`, `stats`, `check-media` e `export` também aceitam um caminho `.zip`, pelo que o gate abaixo é executado diretamente sobre um pacote tal como está. + - `stats` e `export`, e extrair apenas o `.lift` em vez de todo o pacote — para que continuem a ser eficientes num pacote com muitos ficheiros multimédia, e para que o limite de extração se aplique apenas ao `.lift`, em vez de a tudo o que o rodeia. + - A extração está limitada a 10 GiB e 100 000 elementos; um pacote que exceda qualquer um desses limites é rejeitado com um erro `LiftParseError`, tal como acontece com um pacote cujos caminhos dos elementos estejam fora do diretório de extração. +- **Escreva:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` compacta o ficheiro `.lift`, os seus `.lift-ranges` e todos os outros ficheiros da pasta de origem (multimédia, `WritingSystems/`, `consent/`, ...) num ficheiro zip. + - O `wrap_folder` tem, por predefinição, uma pasta de nível superior com o nome do ficheiro zip (conforme a convenção de importação do FieldWorks/Combine); passe `False` para obter um arquivo simples. Os ficheiros `.lift` e `.lift-ranges` mantêm a sua fidelidade ao nível do byte dentro do pacote; o próprio ficheiro zip não é reproduzível ao nível do byte. From 5bef554efe3f1c41341e1ec1771d264a4ed156ca Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:35 -0600 Subject: [PATCH 314/317] New translations lift-export-interop.md (Russian) [ci skip] --- docs/ru/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/ru/guides/lift-export-interop.md b/docs/ru/guides/lift-export-interop.md index 9c14b9e..d921047 100644 --- a/docs/ru/guides/lift-export-interop.md +++ b/docs/ru/guides/lift-export-interop.md @@ -8,8 +8,12 @@ LIFT обычно передаётся в виде одного файла `.zip` — программы FieldWorks и The Combine импортируют и экспортируют данные именно таким образом — поэтому `sil-lift` напрямую считывает и записывает заархивированные пакеты в любом из двух форматов, используемых в этой экосистеме: либо файлы находятся в корневом каталоге архива, либо вложены в одну папку верхнего уровня. -- **Примечание:** Команда `sil_lift.load("package.zip")` распаковывает файл в временный каталог, находит единственный файл `.lift` и загружает его (сопутствующие файлы и мультимедиа обрабатываются как обычно). Команды CLI `validate`, `stats`, `check-media` и `export` также принимают путь к файлу `.zip`, поэтому приведенный ниже скрипт запускается для пакета в том виде, в котором он есть. Функция извлечения защищена от вредоносных архивов — элементы, позволяющие переходить по пути, отклоняются, а количество записей и общий размер в несжатом виде (10 ГиБ) ограничены для защиты от «zip-бомб». -- **Напишите:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` упаковывает файл `.lift`, его файлы `.lift-ranges`, а также все остальные файлы из исходной папки (медиафайлы, `WritingSystems/`, `consent/`, ...) в архив ZIP. По умолчанию `wrap_folder` — это папка верхнего уровня, названная в соответствии с именем ZIP-архива (согласно соглашению об импорте FieldWorks/Combine); для создания плоского архива передайте значение `False`. +- **Примечание:** Команда `sil_lift.load("package.zip")` распаковывает файл в временный каталог, находит единственный файл `.lift` и загружает его (сопутствующие файлы и мультимедиа обрабатываются как обычно). + - Команды CLI `validate`, `stats`, `check-media` и `export` также принимают путь к файлу `.zip`, поэтому приведенный ниже скрипт запускается для пакета в том виде, в котором он есть. + - `stats` и `export`, а также извлекать только файл `.lift`, а не весь пакет — таким образом, их обработка останется малозатратной даже при большом объеме медиаданных, а ограничение на извлечение будет применяться только к файлу `.lift`, а не ко всему остальному. + - Максимальный размер извлечения ограничен 10 ГиБ и 100 000 элементов; пакет, превышающий любой из этих пределов, отклоняется с ошибкой `LiftParseError`, равно как и тот, пути к элементам которого выходят за пределы каталога извлечения. +- **Напишите:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` упаковывает файл `.lift`, его файлы `.lift-ranges`, а также все остальные файлы из исходной папки (медиафайлы, `WritingSystems/`, `consent/`, ...) в архив ZIP. + - По умолчанию `wrap_folder` — это папка верхнего уровня, названная в соответствии с именем ZIP-архива (согласно соглашению об импорте FieldWorks/Combine); для создания плоского архива передайте значение `False`. Файлы `.lift` и `.lift-ranges` сохраняют точность воспроизведения на уровне байтов внутри пакета; сам контейнер zip не обеспечивает точность воспроизведения на уровне байтов. From f781f8cbaeecae127d35dd12da403079432482e3 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:37 -0600 Subject: [PATCH 315/317] New translations lift-export-interop.md (Chinese Simplified) [ci skip] --- docs/zh/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/zh/guides/lift-export-interop.md b/docs/zh/guides/lift-export-interop.md index c7cb270..a5a9d11 100644 --- a/docs/zh/guides/lift-export-interop.md +++ b/docs/zh/guides/lift-export-interop.md @@ -8,8 +8,12 @@ LIFT 通常以单个 `.zip` 文件的形式进行传输——FieldWorks 和 The Combine 都采用这种方式进行导入和导出——因此 `sil-lift` 可以直接读取和写入压缩包,无论采用生态系统中哪种布局:文件位于归档根目录下,还是嵌套在某个顶级文件夹之下。 -- **说明:** `sil_lift.load("package.zip")` 会将文件解压到临时目录中,定位唯一的 `.lift` 文件,并将其加载(相关文件和媒体资源将按常规方式解析)。 `validate`、`stats`、`check-media` 和 `export` 命令行命令也支持 `.zip` 路径,因此下面的门控脚本可直接对该包进行处理。 提取功能已针对恶意归档文件进行了加固——拒绝路径遍历操作,并对条目数量和总未压缩大小(10 GiB)设置了上限,以防范ZIP炸弹攻击。 -- **编写:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` 会将 `.lift`、其 `.lift-ranges` 以及源文件夹中的所有其他文件(media、`WritingSystems/`、`consent/` 等)打包在一起 打包成zip文件。 `wrap_folder` 的默认行为是创建一个以压缩包命名的顶级文件夹(遵循 FieldWorks/Combine 的导入规范);若要生成扁平化归档,请传入 `False`。 +- **说明:** `sil_lift.load("package.zip")` 会将文件解压到临时目录中,定位唯一的 `.lift` 文件,并将其加载(相关文件和媒体资源将按常规方式解析)。 + - `validate`、`stats`、`check-media` 和 `export` 命令行命令也支持 `.zip` 路径,因此下面的门控脚本可直接对该包进行处理。 + - `stats` 和 `export` 流,并仅提取 `.lift` 文件而非整个包——这样在媒体资源密集的场景下仍能保持低开销,且提取限制仅适用于 `.lift` 文件本身,而不涉及其余内容。 + - 提取操作的上限为 10 GiB 和 100,000 个成员;超过任一限制的包将因 `LiftParseError` 而被拒绝,成员路径超出提取目录范围的包同样会被拒绝。 +- **编写:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` 会将 `.lift`、其 `.lift-ranges` 以及源文件夹中的所有其他文件(media、`WritingSystems/`、`consent/` 等)打包在一起 打包成zip文件。 + - `wrap_folder` 的默认行为是创建一个以压缩包命名的顶级文件夹(遵循 FieldWorks/Combine 的导入规范);若要生成扁平化归档,请传入 `False`。 `.lift` 和 `.lift-ranges` 在包内部保持字节级精确性;而 zip 容器本身无法实现字节级还原。 From 6edcf51f0f915101483f6dba03b076d9a610ce14 Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:39 -0600 Subject: [PATCH 316/317] New translations lift-export-interop.md (Hindi) [ci skip] --- docs/hi/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/hi/guides/lift-export-interop.md b/docs/hi/guides/lift-export-interop.md index 419b56e..d21718b 100644 --- a/docs/hi/guides/lift-export-interop.md +++ b/docs/hi/guides/lift-export-interop.md @@ -8,8 +8,12 @@ LIFT लिखना इसे पार्स करने से कहीं LIFT आमतौर पर एक ही `.zip` फ़ाइल के रूप में स्थानांतरित किया जाता है — FieldWorks और The Combine दोनों इसी तरह आयात और निर्यात करते हैं — इसलिए `sil-lift` सीधे ज़िप किए गए पैकेज पढ़ता और लिखता है, चाहे इकोसिस्टम किसी भी लेआउट का उपयोग करे: आर्काइव रूट में फ़ाइलें, या एक शीर्ष-स्तरीय फ़ोल्डर के अंतर्गत नेस्टेड। -- **पढ़ें:** `sil_lift.load("package.zip")` एक अस्थायी निर्देशिका में निकालता है, एकल `.lift` को ढूंढता है, और उसे लोड करता है (साथी और मीडिया सामान्य रूप से हल हो जाते हैं)। `validate`, `stats`, `check-media`, और `export` CLI कमांड्स `.zip` पथ भी स्वीकार करते हैं, इसलिए नीचे दिया गया गेट बिना किसी बदलाव के पैकेज पर चलता है। एक्सट्रैक्शन को शत्रुतापूर्ण आर्काइव्स के खिलाफ मजबूत किया गया है — पाथ-ट्रैवर्सल सदस्यों को अस्वीकार कर दिया जाता है, और एंट्री काउंट तथा कुल अनकंप्रेस्ड आकार (10 जीबी) को ज़िप बॉम्ब्स के खिलाफ सीमित किया गया है। -- `Write:` `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` `.lift`, इसके `.lift-ranges`, और सोर्स फ़ोल्डर (media, `WritingSystems/`, `consent/`, ...) की हर दूसरी फ़ाइल को पैकेज करता है। एक ज़िप में `wrap_folder` डिफ़ॉल्ट रूप से ज़िप के नाम पर एक शीर्ष-स्तरीय फ़ोल्डर बनाता है (FieldWorks/Combine आयात कन्वेंशन); फ़्लैट आर्काइव के लिए `False` पास करें। +- **पढ़ें:** `sil_lift.load("package.zip")` एक अस्थायी निर्देशिका में निकालता है, एकल `.lift` को ढूंढता है, और उसे लोड करता है (साथी और मीडिया सामान्य रूप से हल हो जाते हैं)। + - `validate`, `stats`, `check-media`, और `export` CLI कमांड्स `.zip` पथ भी स्वीकार करते हैं, इसलिए नीचे दिया गया गेट बिना किसी बदलाव के पैकेज पर चलता है। + - `stats` और `export` स्ट्रीम का उपयोग करें, और पूरे पैकेज के बजाय केवल `.lift` निकालें — ताकि मीडिया-भारी एक पर वे सस्ते रहें, और एक्सट्रैक्शन सीमा केवल `.lift` पर ही लागू हो, न कि इसके अलावा किसी और चीज़ पर। + - निकासी 10 जीआईबी और 100,000 सदस्यों तक सीमित है; किसी भी सीमा को पार करने वाले पैकेज को `LiftParseError` के साथ अस्वीकार कर दिया जाता है, ठीक वैसे ही जैसे उन पैकेजों को जिनके सदस्य पथ निकासी निर्देशिका से बाहर जाते हैं। +- `Write:` `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` `.lift`, इसके `.lift-ranges`, और सोर्स फ़ोल्डर (media, `WritingSystems/`, `consent/`, ...) की हर दूसरी फ़ाइल को पैकेज करता है। एक ज़िप में + - `wrap_folder` डिफ़ॉल्ट रूप से ज़िप के नाम पर एक शीर्ष-स्तरीय फ़ोल्डर बनाता है (FieldWorks/Combine आयात कन्वेंशन); फ़्लैट आर्काइव के लिए `False` पास करें। `.lift` और `.lift-ranges` पैकेज के भीतर अपनी बाइट-निष्ठा बनाए रखते हैं; ज़िप कंटेनर स्वयं बाइट-पुनरुत्पादन योग्य नहीं है। From 66dd0ae5bdef36857603d319a30e1f45195ee2cf Mon Sep 17 00:00:00 2001 From: "D. Ror." Date: Fri, 14 Aug 2026 13:58:40 -0600 Subject: [PATCH 317/317] New translations lift-export-interop.md (Swahili) [ci skip] --- docs/sw/guides/lift-export-interop.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/sw/guides/lift-export-interop.md b/docs/sw/guides/lift-export-interop.md index ee87c7f..e55619c 100644 --- a/docs/sw/guides/lift-export-interop.md +++ b/docs/sw/guides/lift-export-interop.md @@ -8,8 +8,12 @@ Kuandika LIFT ni rahisi zaidi kuliko kuchanganua: kiendeshaji cha kusafirisha hu LIFT kawaida huhamishwa kama faili moja ya `.zip` — FieldWorks na The Combine zote huingiza na kusafirisha kwa njia hiyo — hivyo `sil-lift` husoma na kuandika vifurushi vilivyofungwa kwa `zip` moja kwa moja, katika mpangilio wowote ambao mfumo unatumia: faili ziko mizizi ya hifadhi, au zimepangwa ndani ya folda moja kuu. -- Soma: `sil_lift.load("package.zip")` hutoa maudhui kwenye saraka ya muda, hupata faili moja la `.lift`, na kulipakia (viendani na vyombo vya habari hutatuliwa kama kawaida). Amri za CLI `validate`, `stats`, `check-media`, na `export` pia zinakubali njia ya `.zip`, hivyo lango hapa chini linafanya kazi dhidi ya kifurushi kama kilivyo. Utoaji umeimarishwa dhidi ya hifadhidata hatari — vipengele vya kupita njia vinakataliwa, na idadi ya kuingia na ukubwa wote bila kubanwa (10 GiB) vimewekewa kikomo dhidi ya mabomu ya zip. -- **Andika:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` hufunga `.lift`, `.lift-ranges` zake, na kila faili nyingine katika folda ya chanzo (media, `WritingSystems/`, `consent/`, ...) katika zipu `wrap_folder` kwa chaguo-msingi huunda folda ya ngazi ya juu inayopewa jina la faili la zip (utaratibu wa kuingiza wa FieldWorks/Combine); toa `False` ili kupata hifadhi tambarare. +- Soma: `sil_lift.load("package.zip")` hutoa maudhui kwenye saraka ya muda, hupata faili moja la `.lift`, na kulipakia (viendani na vyombo vya habari hutatuliwa kama kawaida). + - Amri za CLI `validate`, `stats`, `check-media`, na `export` pia zinakubali njia ya `.zip`, hivyo lango hapa chini linafanya kazi dhidi ya kifurushi kama kilivyo. + - mtiririko wa `stats` na `export`, na uchimbe tu `.lift` badala ya kifurushi kizima — ili viwe nafuu kwenye mfumo wenye media nyingi, na kikomo cha uchimbaji kitumike kwa `.lift` pekee badala ya kila kitu kingine. + - Utoaji umepunguzwa hadi 10 GiB na wanachama 100,000; kifurushi kinachovuka mojawapo ya mipaka hiyo kinakataliwa kwa `LiftParseError`, vivyo hivyo kifurushi ambacho njia za wanachama zake zinatoka nje ya saraka ya uondoaji. +- **Andika:** `Lexicon.save_zip("out.zip", wrap_folder="MyDict")` hufunga `.lift`, `.lift-ranges` zake, na kila faili nyingine katika folda ya chanzo (media, `WritingSystems/`, `consent/`, ...) katika zipu + - `wrap_folder` kwa chaguo-msingi huunda folda ya ngazi ya juu inayopewa jina la faili la zip (utaratibu wa kuingiza wa FieldWorks/Combine); toa `False` ili kupata hifadhi tambarare. `.lift` na `.lift-ranges` huhifadhi uaminifu wa baiti ndani ya kifurushi; chombo cha zip chenyewe hakiruhusu kurejesha baiti kikamilifu.