write_contract.rs

Die Rust-Datei des Beispiels „Ein zweiseitiger Dienstleistungsvertrag“. Ein Dienstleistungsvertrag über zwei Seiten, in dem keine Klausel je durch einen Seitenwechsel halbiert wird, mit Feldern für Unterschrift, Name und Datum am Ende, die am Bildschirm ausgefüllt werden.

Rust 1258 Zeilen

Wofür dieses Beispiel da ist

Ein Vertrag wird einmal gelesen und später darüber gestritten, und der Streit geht immer um eine bestimmte Klausel. Eine durch einen Seitenwechsel halbierte Klausel — ihre Überschrift allein am Fuß einer Seite, ihr Text oben auf der nächsten — ist daher schlimmer als eine hässliche Seite: Es ist eine Klausel, von der jemand behaupten kann, er habe sie nie gesehen. Hier wartet eine Klausel, die nicht in den restlichen Platz einer Seite passt, und beginnt vollständig auf der nächsten, wie lang sie auch ist.

Was dieses Beispiel zeigt

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
//! Writes a services agreement two parties sign in reading software: a
//! letterhead, the parties, numbered clauses set as flowing paragraphs, and a
//! signature block with a signature field, a printed name and a date for each
//! side.
//!
//! The clauses are prose, so the page is laid out by measuring: each clause is
//! broken to the column, and a clause that would not fit under what is already
//! on the page starts the next one instead, heading and body together. The
//! number of pages is whatever that comes to, and the footer of every page says
//! which of them it is.
//!
//! The fields at the foot are what makes the page an agreement rather than a
//! picture of one: a reader signs the signature field, types the name and the
//! date into the two boxes under it, and every field carries a border so the
//! boxes to click are plain to see.
//!
//! The two signature fields are not written with the document. They are added
//! to the finished file afterwards, one section appended to it per party, the
//! way a place to sign is put into a contract received from somebody else:
//! every byte the file already held stays where it was, and the form the file
//! carries gathers the new fields beside its own. An evaluation copy carries no
//! form at all, and has nothing added to it.
//!
//! Every word the page draws is held in `Words`, once per language, and
//! `HQF_PDF_LANG` picks which one is drawn. The parties' names and addresses,
//! their registration numbers, the agreement's number, the day rate and the
//! names the form fields answer to are the same in both, and the French runs to
//! its own number of pages.
//!
//! The agreement opens on its pages alone, one column of them, and asks to be
//! printed on one side of the paper.
//!
//! Once written, the file is read back: the terminal says which signature
//! fields it carries, how many fields it asks, and what a copy weighs with the
//! two dates answered as a section of its own.
//!
//! Usage: `cargo run --example write_contract -- tmp/contract.pdf [font.ttf]`
//!        `HQF_PDF_LANG=fr cargo run --example write_contract -- tmp/contrat.pdf`

use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use hqf_pdf::content::Content;
use hqf_pdf::cos::Name;
use hqf_pdf::layout::{Align, RichText, Style, TextFlow};
use hqf_pdf::viewer::{Duplex, OpenMode, PageLayout, SidePanel, ViewerPreferences};
use hqf_pdf::{
    Document, Field, FieldBorder, Font, FontHandle, Image, ImageHandle, IncrementalUpdate, Page,
    Rgb, SignatureField, TextField,
};

#[path = "shared/out.rs"]
mod out;

#[path = "shared/licence.rs"]
mod licence;

#[path = "shared/language.rs"]
mod language;

#[path = "shared/failure.rs"]
mod failure;

use language::Language;

/// The font the example draws with when none is given on the command line.
fn default_font() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("fonts")
        .join("DejaVuSans.ttf")
}

/// The logo the letterhead carries: the committed fixture, so the example runs
/// on any machine. It stands in for the provider's mark.
fn logo_path() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("images")
        .join("hqf_development.png")
}

/// A4, in points.
const PAGE_WIDTH: f64 = 595.276;
const PAGE_HEIGHT: f64 = 841.89;
/// The page's left edge and, mirrored, its right.
const LEFT: f64 = 56.0;
const RIGHT: f64 = PAGE_WIDTH - LEFT;
/// The width every paragraph is broken to.
const BODY_WIDTH: f64 = PAGE_WIDTH - 2.0 * LEFT;

/// The ink the headings and rules are drawn in, and the grey of the small
/// print.
const ACCENT: Rgb = Rgb {
    r: 0.11,
    g: 0.33,
    b: 0.55,
};
const MUTED: Rgb = Rgb {
    r: 0.42,
    g: 0.42,
    b: 0.45,
};
const INK: Rgb = Rgb {
    r: 0.1,
    g: 0.1,
    b: 0.12,
};

/// The size the clause bodies are set at, and the distance from one of their
/// baselines to the next.
const BODY_SIZE: f64 = 9.5;
const LEADING: f64 = 13.5;
/// The drop from a clause heading's baseline to the top of its body, and the
/// gap left under a clause before the next one starts.
const HEADING_DROP: f64 = 5.0;
const CLAUSE_GAP: f64 = 19.0;

/// Where the clauses start on the pages after the first. On the first they
/// start under the preamble, wherever the preamble ends.
const NEXT_TOP: f64 = 782.0;
/// The lowest a clause or a block may reach before it moves to the next page.
const BOTTOM: f64 = 100.0;
/// The room the signature block needs under the last clause.
const SIGNATURE_HEIGHT: f64 = 250.0;

/// The colour and width every field's border is stroked in.
const BORDER: Rgb = Rgb::gray(0.55);
const BORDER_WIDTH: f64 = 0.75;

/// The width of a signature column, and the left edge of the second one.
const COLUMN_WIDTH: f64 = 224.0;
const COLUMN_TWO: f64 = 315.276;

/// What the agreement is called.
const NUMBER: &str = "HQF-2026-0087";

/// How many clauses the agreement is made of.
const CLAUSE_COUNT: usize = 9;

/// The party that supplies the services and the party that buys them: the name,
/// the two lines under it, and the tax number the third line carries.
const PROVIDER_NAME: &str = "HQF Development";
const PROVIDER_LINES: [&str; 2] = [
    "42 lot les Genêts, 13480 Calas, France",
    "SIRET 752 492 777 00012 · APE 6202A",
];
const PROVIDER_VAT: &str = "FR59 752 492 777";
const CLIENT_NAME: &str = "Northwind Trading SARL";
const CLIENT_LINES: [&str; 2] = [
    "18 quai du Port, 13002 Marseille, France",
    "RCS Marseille 812 665 431",
];
const CLIENT_VAT: &str = "FR41 812 665 431";

/// Who signs, in the order their columns are drawn, and the name the column's
/// fields answer to. A field name is what a form-filling program reads, not
/// something the page draws, so it is the same in every language.
const SIGNATORIES: [(&str, &str, f64); 2] = [
    ("Olivier Pons", "Provider", LEFT),
    ("Claire Lemoine", "Client", COLUMN_TWO),
];

/// Every word the page draws, in one language.
///
/// What is not language stays out of it: the parties' names and addresses,
/// their registration numbers, the agreement's number, the day rate and the
/// names the form fields answer to are drawn from constants of their own and
/// read the same in every language.
#[derive(Debug)]
struct Words {
    /// The words the document's title is built from, and the word set large at
    /// the head of the first page.
    title: &'static str,
    heading: &'static str,
    /// What stands before the agreement's number.
    number_label: &'static str,
    /// What stands before the day it was signed, and that day.
    signed_label: &'static str,
    agreement_date: &'static str,
    /// What stands before the day it runs from, and that day.
    effective_label: &'static str,
    effective_date: &'static str,
    /// The heading over each party.
    provider_heading: &'static str,
    client_heading: &'static str,
    /// The word before a tax number, wherever one is set.
    vat: &'static str,
    /// The sentence that binds the parties, cut where the two dates go into it.
    preamble_first: &'static str,
    preamble_second: &'static str,
    preamble_after: &'static str,
    /// The clauses the agreement is made of: a heading, and the paragraph under
    /// it.
    clauses: [(&'static str, &'static str); CLAUSE_COUNT],
    /// The heading over the signature block, and the sentence under it, cut
    /// where the three things a reader fills in are named.
    signatures: &'static str,
    note_before: &'static str,
    note_marked: &'static str,
    note_after: &'static str,
    /// The heading over each signature column, and what each signatory does.
    signatory_headings: [&'static str; 2],
    signatory_roles: [&'static str; 2],
    /// What stands under each of a column's three boxes.
    signature_label: &'static str,
    printed_name_label: &'static str,
    date_label: &'static str,
    /// The words the page number is built from, at the foot of every page.
    page_before: &'static str,
    page_word: &'static str,
    page_of: &'static str,
}

impl Words {
    /// The words the agreement is written in, in `language`.
    fn of(language: Language) -> &'static Self {
        language::pick(&WORDS, language)
    }
}

/// The agreement in English.
const ENGLISH: Words = Words {
    title: "Services agreement",
    heading: "AGREEMENT",
    number_label: "Agreement No.",
    signed_label: "Signed",
    agreement_date: "20 July 2026",
    effective_label: "Effective",
    effective_date: "1 September 2026",
    provider_heading: "SERVICE PROVIDER",
    client_heading: "CLIENT",
    vat: "VAT",
    preamble_first: "This agreement is made on",
    preamble_second: "between the parties named above, and takes effect on",
    preamble_after: ". It sets out the terms on which the Provider supplies \
         software development and support services to the Client. Each clause \
         below binds both parties from the date the last of them signs.",
    clauses: [
        (
            "Scope of services",
            "The Provider designs, builds and maintains the software described in \
             the statement of work annexed to this agreement, together with any \
             further work the parties agree to in writing. A change of scope is \
             agreed in writing before it is carried out, and the Provider may \
             decline a change that cannot be delivered within the agreed term.",
        ),
        (
            "Term and commencement",
            "This agreement begins on the effective date shown above and runs for \
             twelve months. It renews for successive periods of twelve months \
             unless either party gives written notice of at least sixty days \
             before the end of the period then running.",
        ),
        (
            "Fees and payment",
            "The Client pays the Provider 620.00 EUR for each day of work, before \
             value added tax. The Provider invoices monthly in arrears and each \
             invoice falls due thirty days after its issue date. A sum still \
             unpaid on the due date carries interest at the statutory rate, and no \
             reminder has to be sent for that interest to run.",
        ),
        (
            "Intellectual property",
            "Once an invoice has been paid in full, the Client owns the source \
             code and the documents written for it under this agreement. The \
             Provider keeps the tools, libraries and generic components it brought \
             to the work or wrote for general use, and grants the Client a \
             perpetual non-exclusive licence to use them as part of the delivered \
             software.",
        ),
        (
            "Confidentiality",
            "Each party keeps in confidence what it learns of the other's \
             business, customers and technology, and uses it only to perform this \
             agreement. That duty outlives the agreement by five years. It does \
             not cover what is already public through no fault of the party that \
             received it, nor what a court or a regulator requires be disclosed.",
        ),
        (
            "Warranties and liability",
            "The Provider warrants that the work is performed with the skill and \
             care of a competent professional, and corrects at its own cost any \
             defect reported within ninety days of delivery. Neither party is \
             liable for loss of profit, loss of data or any indirect loss, and the \
             liability of each party under this agreement is capped at the fees \
             paid over the twelve months before the claim arose.",
        ),
        (
            "Termination",
            "Either party may end this agreement on sixty days' written notice, \
             and either may end it at once if the other commits a material breach \
             that is not put right within thirty days of being asked in writing to \
             put it right. On termination the Client pays for the work done up to \
             that date and the Provider hands over the deliverables in the state \
             they are then in.",
        ),
        (
            "Notices",
            "Notice under this agreement is given in writing to the address shown \
             for the party at the head of this document, and takes effect on the \
             day it is delivered. A party that moves tells the other within \
             fifteen days.",
        ),
        (
            "Entire agreement and governing law",
            "This document, with the statement of work annexed to it, is the whole \
             of what the parties have agreed on this subject and replaces every \
             earlier understanding of it. The agreement is governed by French law, \
             and any dispute the parties cannot settle between them goes to the \
             courts of Aix-en-Provence, France.",
        ),
    ],
    signatures: "SIGNATURES",
    note_before: "Each party signs in the boxes below: a ",
    note_marked: "signature, a printed name and a date",
    note_after: ", filled in from reading software. The agreement takes effect on the \
         later of the two dates written here, and a copy of the signed \
         document goes to each party.",
    signatory_headings: ["FOR THE PROVIDER", "FOR THE CLIENT"],
    signatory_roles: ["Director", "Managing Director"],
    signature_label: "Signature",
    printed_name_label: "Printed name",
    date_label: "Date (DD/MM/YYYY)",
    page_before: "Agreement",
    page_word: "page",
    page_of: "of",
};

/// The agreement in French.
const FRENCH: Words = Words {
    title: "Contrat de prestation de services",
    heading: "CONTRAT",
    number_label: "Contrat n°",
    signed_label: "Signé le",
    agreement_date: "20 juillet 2026",
    effective_label: "Prise d’effet",
    effective_date: "1er septembre 2026",
    provider_heading: "PRESTATAIRE",
    client_heading: "CLIENT",
    vat: "TVA",
    preamble_first: "Le présent contrat est conclu le",
    preamble_second: "entre les parties désignées ci-dessus et prend effet le",
    preamble_after: ". Il fixe les conditions dans lesquelles le Prestataire \
         fournit au Client des prestations de développement et de maintenance \
         logicielle. Chaque article ci-dessous engage les deux parties à \
         compter de la date de la dernière signature.",
    clauses: [
        (
            "Objet du contrat",
            "Le Prestataire conçoit, développe et maintient le logiciel décrit dans le \
cahier des charges annexé au présent contrat, ainsi que toute prestation \
complémentaire convenue par écrit entre les parties. Toute modification de \
l’objet est convenue par écrit avant son exécution, et le Prestataire peut \
refuser une modification qui ne peut être livrée dans le délai convenu.",
        ),
        (
            "Durée et prise d’effet",
            "Le présent contrat prend effet à la date indiquée ci-dessus pour une durée de \
douze mois. Il se renouvelle par périodes successives de douze mois, sauf \
dénonciation écrite de l’une des parties adressée au moins soixante jours \
avant le terme de la période en cours.",
        ),
        (
            "Prix et modalités de paiement",
            "Le Client verse au Prestataire 620.00 EUR par journée de travail, hors taxes. \
Le Prestataire facture chaque mois à terme échu et chaque facture est payable \
trente jours après sa date d’émission. Toute somme impayée à l’échéance \
produit des intérêts au taux légal, sans qu’une mise en demeure soit \
nécessaire.",
        ),
        (
            "Propriété intellectuelle",
            "Dès le paiement intégral de la facture correspondante, le Client devient \
propriétaire du code source et des documents rédigés pour lui au titre du \
présent contrat. Le Prestataire conserve les outils, bibliothèques et \
composants génériques qu’il a apportés ou écrits pour un usage général, et \
concède au Client une licence perpétuelle et non exclusive de les utiliser au \
sein du logiciel livré.",
        ),
        (
            "Confidentialité",
            "Chaque partie tient confidentiel ce qu’elle apprend de l’activité, de la \
clientèle et de la technologie de l’autre, et ne l’utilise que pour \
l’exécution du présent contrat. Cette obligation survit cinq ans au contrat. \
Elle ne couvre ni ce qui est déjà public sans faute de la partie qui l’a reçu, \
ni ce dont un tribunal ou une autorité exige la communication.",
        ),
        (
            "Garanties et responsabilité",
            "Le Prestataire garantit que les travaux sont exécutés avec le soin et la \
compétence d’un professionnel avisé, et corrige à ses frais tout défaut \
signalé dans les quatre-vingt-dix jours suivant la livraison. Aucune des \
parties ne répond de la perte d’exploitation, de la perte de données ni \
d’aucun dommage indirect, et la responsabilité de chaque partie au titre du \
présent contrat est plafonnée aux sommes versées au cours des douze mois \
précédant le fait générateur.",
        ),
        (
            "Résiliation",
            "Chaque partie peut résilier le présent contrat moyennant un préavis écrit de \
soixante jours, et chacune peut y mettre fin immédiatement si l’autre commet \
un manquement grave auquel elle ne remédie pas dans les trente jours suivant \
une mise en demeure écrite. En cas de résiliation, le Client règle les travaux \
exécutés jusqu’à cette date et le Prestataire remet les livrables en l’état où \
ils se trouvent.",
        ),
        (
            "Notifications",
            "Toute notification au titre du présent contrat est faite par écrit à l’adresse \
indiquée pour la partie en tête du présent document, et prend effet le jour de \
sa remise. La partie qui change d’adresse en informe l’autre dans les quinze \
jours.",
        ),
        (
            "Intégralité du contrat et loi applicable",
            "Le présent document, avec le cahier des charges qui lui est annexé, constitue \
l’intégralité de l’accord des parties sur son objet et remplace tout accord \
antérieur portant sur celui-ci. Le contrat est régi par la loi française, et \
tout litige que les parties ne peuvent régler entre elles relève des tribunaux \
d’Aix-en-Provence, France.",
        ),
    ],
    signatures: "SIGNATURES",
    note_before: "Chaque partie signe dans les cases ci-dessous : une ",
    note_marked: "signature, un nom en clair et une date",
    note_after: ", saisis depuis un logiciel de lecture. Le contrat prend effet à la plus \
tardive des deux dates inscrites ici, et un exemplaire signé est remis à \
chaque partie.",
    signatory_headings: ["POUR LE PRESTATAIRE", "POUR LE CLIENT"],
    signatory_roles: ["Gérant", "Directrice générale"],
    signature_label: "Signature",
    printed_name_label: "Nom en clair",
    date_label: "Date (JJ/MM/AAAA)",
    page_before: "Contrat",
    page_word: "page",
    page_of: "sur",
};

/// The agreement in Dutch.
const DUTCH: Words = Words {
    title: "Dienstverleningsovereenkomst",
    heading: "OVEREENKOMST",
    number_label: "Overeenkomst nr.",
    signed_label: "Getekend",
    agreement_date: "20 juli 2026",
    effective_label: "Ingangsdatum",
    effective_date: "1 september 2026",
    provider_heading: "DIENSTVERLENER",
    client_heading: "OPDRACHTGEVER",
    vat: "Btw",
    preamble_first: "Deze overeenkomst wordt gesloten op",
    preamble_second: "tussen de hierboven genoemde partijen, en gaat in op",
    preamble_after: ". Ze legt de voorwaarden vast waarop de Dienstverlener softwareontwikkeling en ondersteuning levert aan de Opdrachtgever. Elk artikel hieronder bindt beide partijen vanaf de datum waarop de laatste van hen tekent.",
    clauses: [
        (
            "Omvang van de diensten",
            "De Dienstverlener ontwerpt, bouwt en onderhoudt de software die is beschreven in de werkomschrijving bij deze overeenkomst, samen met ander werk dat de partijen schriftelijk overeenkomen. Een wijziging van de omvang wordt schriftelijk overeengekomen voordat ze wordt uitgevoerd, en de Dienstverlener mag een wijziging weigeren die niet binnen de afgesproken termijn kan worden geleverd.",
        ),
        (
            "Looptijd en aanvang",
            "Deze overeenkomst begint op de hierboven vermelde ingangsdatum en loopt twaalf maanden. Ze wordt telkens met twaalf maanden verlengd, tenzij een van de partijen ten minste zestig dagen voor het einde van de lopende periode schriftelijk opzegt.",
        ),
        (
            "Vergoeding en betaling",
            "De Opdrachtgever betaalt de Dienstverlener EUR 620,00 per werkdag, exclusief btw. De Dienstverlener factureert maandelijks achteraf en elke factuur vervalt dertig dagen na de factuurdatum. Over een op de vervaldag onbetaald bedrag is wettelijke rente verschuldigd, zonder dat daarvoor een herinnering hoeft te worden gestuurd.",
        ),
        (
            "Intellectuele eigendom",
            "Zodra een factuur volledig is betaald, is de Opdrachtgever eigenaar van de broncode en de documenten die onder deze overeenkomst voor hem zijn geschreven. De Dienstverlener behoudt de hulpmiddelen, bibliotheken en generieke onderdelen die hij voor het werk meebracht of voor algemeen gebruik schreef, en verleent de Opdrachtgever een eeuwigdurende, niet-exclusieve licentie om ze te gebruiken als deel van de geleverde software.",
        ),
        (
            "Geheimhouding",
            "Elke partij houdt geheim wat zij te weten komt over het bedrijf, de klanten en de technologie van de ander, en gebruikt dat alleen om deze overeenkomst uit te voeren. Die plicht blijft vijf jaar na de overeenkomst bestaan. Ze geldt niet voor wat al openbaar is zonder schuld van de ontvangende partij, noch voor wat een rechter of toezichthouder verplicht openbaar te maken.",
        ),
        (
            "Garanties en aansprakelijkheid",
            "De Dienstverlener garandeert dat het werk wordt uitgevoerd met de kunde en zorg van een bekwame vakman, en herstelt op eigen kosten elk gebrek dat binnen negentig dagen na levering wordt gemeld. Geen van de partijen is aansprakelijk voor gederfde winst, gegevensverlies of indirecte schade, en de aansprakelijkheid van elke partij onder deze overeenkomst is beperkt tot de vergoedingen die in de twaalf maanden voor de claim zijn betaald.",
        ),
        (
            "Beëindiging",
            "Elke partij kan deze overeenkomst beëindigen met een schriftelijke opzegtermijn van zestig dagen, en elke partij kan haar direct beëindigen als de ander een wezenlijke tekortkoming begaat die niet binnen dertig dagen na een schriftelijke ingebrekestelling is hersteld. Bij beëindiging betaalt de Opdrachtgever het werk tot die datum en levert de Dienstverlener de resultaten in de staat waarin ze zich bevinden.",
        ),
        (
            "Kennisgevingen",
            "Een kennisgeving onder deze overeenkomst gebeurt schriftelijk aan het adres dat bovenaan dit document voor de partij staat, en gaat in op de dag van bezorging. Een partij die verhuist, laat dat de ander binnen vijftien dagen weten.",
        ),
        (
            "Volledige overeenkomst en toepasselijk recht",
            "Dit document, met de werkomschrijving erbij, is alles wat de partijen over dit onderwerp zijn overeengekomen en vervangt elke eerdere afspraak erover. Op de overeenkomst is Frans recht van toepassing, en een geschil dat de partijen niet onderling kunnen oplossen gaat naar de rechtbank van Aix-en-Provence, Frankrijk.",
        ),
    ],
    signatures: "HANDTEKENINGEN",
    note_before: "Elke partij vult de vakken hieronder in: een",
    note_marked: "handtekening, een naam in blokletters en een datum",
    note_after: ", rechtstreeks in de leessoftware. De overeenkomst gaat in op de laatste van de twee hier geschreven data, en elke partij krijgt een kopie van het getekende document.",
    signatory_headings: ["VOOR DE DIENSTVERLENER", "VOOR DE OPDRACHTGEVER"],
    signatory_roles: ["Directeur", "Algemeen directeur"],
    signature_label: "Handtekening",
    printed_name_label: "Naam in blokletters",
    date_label: "Datum (DD/MM/JJJJ)",
    page_before: "Overeenkomst",
    page_word: "pagina",
    page_of: "van",
};

/// The agreement in Portuguese.
const PORTUGUESE: Words = Words {
    title: "Contrato de prestação de serviços",
    heading: "CONTRATO",
    number_label: "Contrato n.º",
    signed_label: "Assinado",
    agreement_date: "20 de julho de 2026",
    effective_label: "Em vigor",
    effective_date: "1 de setembro de 2026",
    provider_heading: "PRESTADOR",
    client_heading: "CLIENTE",
    vat: "NIF",
    preamble_first: "O presente contrato é celebrado em",
    preamble_second: "entre as partes acima identificadas, e entra em vigor em",
    preamble_after: ". Fixa as condições em que o Prestador fornece ao Cliente serviços de desenvolvimento e suporte de software. Cada cláusula abaixo vincula ambas as partes a partir da data em que a última delas o assina.",
    clauses: [
        (
            "Objeto dos serviços",
            "O Prestador concebe, constrói e mantém o software descrito no caderno de encargos anexo a este contrato, bem como qualquer outro trabalho que as partes acordem por escrito. Uma alteração do objeto é acordada por escrito antes de ser executada, e o Prestador pode recusar uma alteração que não possa ser entregue no prazo acordado.",
        ),
        (
            "Duração e início",
            "Este contrato começa na data de entrada em vigor acima indicada e dura doze meses. Renova-se por períodos sucessivos de doze meses salvo denúncia escrita de uma das partes com pelo menos sessenta dias de antecedência sobre o fim do período em curso.",
        ),
        (
            "Honorários e pagamento",
            "O Cliente paga ao Prestador 620,00 EUR por cada dia de trabalho, sem imposto sobre o valor acrescentado. O Prestador fatura no fim de cada mês e cada fatura vence trinta dias após a data de emissão. Uma quantia por pagar na data de vencimento vence juros à taxa legal, sem necessidade de qualquer aviso para que corram.",
        ),
        (
            "Propriedade intelectual",
            "Uma vez paga integralmente a fatura correspondente, o Cliente é titular do código-fonte e dos documentos escritos para ele ao abrigo deste contrato. O Prestador conserva as ferramentas, bibliotecas e componentes genéricos que trouxe para o trabalho ou escreveu para uso geral, e concede ao Cliente uma licença perpétua e não exclusiva para os usar como parte do software entregue.",
        ),
        (
            "Confidencialidade",
            "Cada parte mantém em sigilo o que conhece do negócio, dos clientes e da tecnologia da outra, e só o usa para executar este contrato. Esse dever sobrevive ao contrato por cinco anos. Não abrange o que já é público sem culpa da parte que o recebeu, nem o que um tribunal ou um regulador exija que seja divulgado.",
        ),
        (
            "Garantias e responsabilidade",
            "O Prestador garante que o trabalho é executado com a competência e o cuidado de um profissional qualificado, e corrige à sua custa qualquer defeito comunicado nos noventa dias seguintes à entrega. Nenhuma das partes responde por lucros cessantes, perda de dados ou qualquer dano indireto, e a responsabilidade de cada parte ao abrigo deste contrato limita-se aos honorários pagos nos doze meses anteriores à reclamação.",
        ),
        (
            "Cessação",
            "Qualquer das partes pode pôr fim a este contrato com sessenta dias de pré-aviso escrito, e qualquer delas pode resolvê-lo de imediato se a outra cometer um incumprimento grave que não seja sanado nos trinta dias seguintes a uma interpelação escrita. Na cessação, o Cliente paga o trabalho feito até essa data e o Prestador entrega os resultados no estado em que se encontrem.",
        ),
        (
            "Notificações",
            "As notificações ao abrigo deste contrato fazem-se por escrito para a morada indicada para cada parte no cabeçalho deste documento, e produzem efeito no dia da entrega. Uma parte que mude de morada informa a outra no prazo de quinze dias.",
        ),
        (
            "Acordo integral e lei aplicável",
            "Este documento, com o caderno de encargos anexo, é tudo o que as partes acordaram sobre esta matéria e substitui qualquer entendimento anterior. O contrato rege-se pela lei francesa, e qualquer litígio que as partes não consigam resolver entre si é submetido aos tribunais de Aix-en-Provence, França.",
        ),
    ],
    signatures: "ASSINATURAS",
    note_before: "Cada parte assina nas caixas abaixo: uma",
    note_marked: "assinatura, um nome em maiúsculas e uma data",
    note_after: ", preenchidos a partir de um programa de leitura. O contrato entra em vigor na mais tardia das duas datas aqui escritas, e cada parte recebe uma cópia do documento assinado.",
    signatory_headings: ["PELO PRESTADOR", "PELO CLIENTE"],
    signatory_roles: ["Diretor", "Administrador-delegado"],
    signature_label: "Assinatura",
    printed_name_label: "Nome em maiúsculas",
    date_label: "Data (DD/MM/AAAA)",
    page_before: "Contrato",
    page_word: "página",
    page_of: "de",
};

/// The agreement in Italian.
const ITALIAN: Words = Words {
    title: "Contratto di servizi",
    heading: "CONTRATTO",
    number_label: "Contratto n.",
    signed_label: "Firmato",
    agreement_date: "20 luglio 2026",
    effective_label: "In vigore",
    effective_date: "1° settembre 2026",
    provider_heading: "FORNITORE",
    client_heading: "CLIENTE",
    vat: "P. IVA",
    preamble_first: "Il presente contratto è stipulato il",
    preamble_second: "tra le parti sopra indicate, ed entra in vigore il",
    preamble_after: ". Stabilisce le condizioni alle quali il Fornitore presta al Cliente servizi di sviluppo e assistenza software. Ogni clausola seguente vincola entrambe le parti dalla data in cui firma l’ultima di esse.",
    clauses: [
        (
            "Oggetto dei servizi",
            "Il Fornitore progetta, realizza e mantiene il software descritto nel capitolato allegato al presente contratto, insieme a ogni altro lavoro che le parti concordino per iscritto. Una modifica dell’oggetto si concorda per iscritto prima di essere eseguita, e il Fornitore può rifiutare una modifica che non si possa consegnare nel termine concordato.",
        ),
        (
            "Durata e decorrenza",
            "Il presente contratto decorre dalla data di entrata in vigore sopra indicata e dura dodici mesi. Si rinnova per periodi successivi di dodici mesi salvo disdetta scritta di una delle parti almeno sessanta giorni prima della fine del periodo in corso.",
        ),
        (
            "Compensi e pagamento",
            "Il Cliente paga al Fornitore 620,00 EUR per ogni giornata di lavoro, al netto dell’imposta sul valore aggiunto. Il Fornitore fattura mensilmente a posteriori e ogni fattura scade trenta giorni dopo la data di emissione. Una somma non pagata alla scadenza produce interessi al tasso legale, senza bisogno di alcun sollecito perché decorrano.",
        ),
        (
            "Proprietà intellettuale",
            "Una volta pagata integralmente una fattura, il Cliente è titolare del codice sorgente e dei documenti scritti per lui in base al presente contratto. Il Fornitore conserva gli strumenti, le librerie e i componenti generici che ha portato nel lavoro o scritto per uso generale, e concede al Cliente una licenza perpetua e non esclusiva per usarli come parte del software consegnato.",
        ),
        (
            "Riservatezza",
            "Ciascuna parte mantiene riservato ciò che apprende dell’attività, dei clienti e della tecnologia dell’altra, e lo usa solo per eseguire il presente contratto. Tale obbligo sopravvive al contratto per cinque anni. Non copre ciò che è già pubblico senza colpa della parte che lo ha ricevuto, né ciò che un tribunale o un’autorità impone di rivelare.",
        ),
        (
            "Garanzie e responsabilità",
            "Il Fornitore garantisce che il lavoro è eseguito con la perizia e la diligenza di un professionista competente, e corregge a proprie spese ogni difetto segnalato entro novanta giorni dalla consegna. Nessuna delle parti risponde di mancato guadagno, perdita di dati o danni indiretti, e la responsabilità di ciascuna parte in base al presente contratto è limitata ai compensi pagati nei dodici mesi precedenti la richiesta.",
        ),
        (
            "Risoluzione",
            "Ciascuna parte può porre fine al presente contratto con sessanta giorni di preavviso scritto, e ciascuna può risolverlo immediatamente se l’altra commette un inadempimento grave non sanato entro trenta giorni da una diffida scritta. Alla risoluzione il Cliente paga il lavoro svolto fino a quella data e il Fornitore consegna quanto prodotto nello stato in cui si trova.",
        ),
        (
            "Comunicazioni",
            "Le comunicazioni previste dal presente contratto si fanno per iscritto all’indirizzo indicato per ciascuna parte in testa a questo documento, e hanno effetto il giorno della consegna. Una parte che cambia sede lo comunica all’altra entro quindici giorni.",
        ),
        (
            "Intero accordo e legge applicabile",
            "Questo documento, con il capitolato allegato, è tutto ciò che le parti hanno convenuto in materia e sostituisce ogni intesa precedente. Il contratto è regolato dalla legge francese, e ogni controversia che le parti non riescano a comporre va al foro di Aix-en-Provence, Francia.",
        ),
    ],
    signatures: "FIRME",
    note_before: "Ciascuna parte firma nelle caselle qui sotto: una",
    note_marked: "firma, un nome in stampatello e una data",
    note_after: ", compilati da un programma di lettura. Il contratto entra in vigore alla più tarda delle due date qui scritte, e ciascuna parte riceve una copia del documento firmato.",
    signatory_headings: ["PER IL FORNITORE", "PER IL CLIENTE"],
    signatory_roles: ["Direttore", "Amministratore delegato"],
    signature_label: "Firma",
    printed_name_label: "Nome in stampatello",
    date_label: "Data (GG/MM/AAAA)",
    page_before: "Contratto",
    page_word: "pagina",
    page_of: "di",
};

/// The agreement in Spanish.
const SPANISH: Words = Words {
    title: "Contrato de servicios",
    heading: "CONTRATO",
    number_label: "Contrato n.º",
    signed_label: "Firmado",
    agreement_date: "20 de julio de 2026",
    effective_label: "En vigor",
    effective_date: "1 de septiembre de 2026",
    provider_heading: "PROVEEDOR",
    client_heading: "CLIENTE",
    vat: "IVA",
    preamble_first: "Este contrato se celebra el",
    preamble_second: "entre las partes indicadas arriba, y entra en vigor el",
    preamble_after: ". Fija las condiciones en que el Proveedor presta al Cliente servicios de desarrollo y soporte de software. Cada cláusula de abajo obliga a ambas partes desde la fecha en que firma la última de ellas.",
    clauses: [
        (
            "Alcance de los servicios",
            "El Proveedor diseña, construye y mantiene el software descrito en el pliego de trabajo anexo a este contrato, junto con cualquier otro trabajo que las partes acuerden por escrito. Un cambio de alcance se acuerda por escrito antes de realizarse, y el Proveedor puede rechazar un cambio que no pueda entregarse en el plazo acordado.",
        ),
        (
            "Duración e inicio",
            "Este contrato empieza en la fecha de entrada en vigor indicada arriba y dura doce meses. Se renueva por periodos sucesivos de doce meses salvo que una de las partes lo denuncie por escrito al menos sesenta días antes del final del periodo en curso.",
        ),
        (
            "Honorarios y pago",
            "El Cliente paga al Proveedor 620,00 EUR por cada día de trabajo, más el impuesto sobre el valor añadido. El Proveedor factura mensualmente a mes vencido y cada factura vence treinta días después de su fecha de emisión. Una suma impagada en la fecha de vencimiento devenga intereses al tipo legal, sin necesidad de enviar ningún recordatorio para que corran.",
        ),
        (
            "Propiedad intelectual",
            "Una vez pagada íntegramente una factura, el Cliente es propietario del código fuente y de los documentos escritos para él en virtud de este contrato. El Proveedor conserva las herramientas, bibliotecas y componentes genéricos que aportó al trabajo o escribió para uso general, y concede al Cliente una licencia perpetua y no exclusiva para usarlos como parte del software entregado.",
        ),
        (
            "Confidencialidad",
            "Cada parte guarda en secreto lo que conoce del negocio, los clientes y la tecnología de la otra, y solo lo usa para ejecutar este contrato. Esa obligación subsiste cinco años después de terminado el contrato. No cubre lo que ya es público sin culpa de la parte que lo recibió, ni lo que un tribunal o un regulador exija revelar.",
        ),
        (
            "Garantías y responsabilidad",
            "El Proveedor garantiza que el trabajo se realiza con la pericia y el cuidado de un profesional competente, y corrige a su costa cualquier defecto comunicado en los noventa días siguientes a la entrega. Ninguna de las partes responde del lucro cesante, la pérdida de datos ni ningún daño indirecto, y la responsabilidad de cada parte en virtud de este contrato se limita a los honorarios pagados en los doce meses anteriores a la reclamación.",
        ),
        (
            "Resolución",
            "Cualquiera de las partes puede poner fin a este contrato con sesenta días de preaviso por escrito, y cualquiera puede resolverlo de inmediato si la otra comete un incumplimiento grave que no subsana en los treinta días siguientes a un requerimiento por escrito. A la resolución, el Cliente paga el trabajo hecho hasta esa fecha y el Proveedor entrega el trabajo en el estado en que esté.",
        ),
        (
            "Notificaciones",
            "Las notificaciones en virtud de este contrato se hacen por escrito a la dirección indicada para cada parte en la cabecera de este documento, y surten efecto el día de su entrega. Una parte que cambia de domicilio lo comunica a la otra en un plazo de quince días.",
        ),
        (
            "Acuerdo íntegro y ley aplicable",
            "Este documento, con el pliego de trabajo anexo, es todo lo que las partes han acordado sobre esta materia y sustituye cualquier entendimiento anterior. El contrato se rige por la ley francesa, y cualquier litigio que las partes no puedan resolver entre ellas se somete a los tribunales de Aix-en-Provence, Francia.",
        ),
    ],
    signatures: "FIRMAS",
    note_before: "Cada parte firma en las casillas de abajo: una ",
    note_marked: "firma, un nombre en mayúsculas y una fecha",
    note_after: ", rellenados desde un programa de lectura. El contrato entra en vigor en la más tardía de las dos fechas escritas aquí, y cada parte recibe una copia del documento firmado.",
    signatory_headings: ["POR EL PROVEEDOR", "POR EL CLIENTE"],
    signatory_roles: ["Director", "Director general"],
    signature_label: "Firma",
    printed_name_label: "Nombre en mayúsculas",
    date_label: "Fecha (DD/MM/AAAA)",
    page_before: "Contrato",
    page_word: "página",
    page_of: "de",
};

/// The agreement in German.
const GERMAN: Words = Words {
    title: "Dienstleistungsvertrag",
    heading: "VERTRAG",
    number_label: "Vertrag Nr.",
    signed_label: "Unterzeichnet",
    agreement_date: "20. Juli 2026",
    effective_label: "Wirksam ab",
    effective_date: "1. September 2026",
    provider_heading: "AUFTRAGNEHMER",
    client_heading: "AUFTRAGGEBER",
    vat: "USt-IdNr.",
    preamble_first: "Dieser Vertrag wird geschlossen am",
    preamble_second: "zwischen den oben genannten Parteien und wird wirksam am",
    preamble_after: ". Er legt die Bedingungen fest, zu denen der Auftragnehmer dem Auftraggeber Leistungen der Softwareentwicklung und des Supports erbringt. Jede der folgenden Klauseln bindet beide Parteien ab dem Tag, an dem die letzte von ihnen unterschreibt.",
    clauses: [
        (
            "Leistungsumfang",
            "Der Auftragnehmer entwirft, erstellt und pflegt die Software, die in der diesem Vertrag beigefügten Leistungsbeschreibung beschrieben ist, sowie jede weitere Arbeit, auf die sich die Parteien schriftlich einigen. Eine Änderung des Umfangs wird schriftlich vereinbart, bevor sie ausgeführt wird, und der Auftragnehmer kann eine Änderung ablehnen, die nicht innerhalb der vereinbarten Frist geliefert werden kann.",
        ),
        (
            "Laufzeit und Beginn",
            "Dieser Vertrag beginnt am oben angegebenen Tag des Inkrafttretens und läuft zwölf Monate. Er verlängert sich um jeweils zwölf Monate, sofern nicht eine Partei mindestens sechzig Tage vor Ablauf des laufenden Zeitraums schriftlich kündigt.",
        ),
        (
            "Vergütung und Zahlung",
            "Der Auftraggeber zahlt dem Auftragnehmer 620,00 EUR je Arbeitstag, zuzüglich Mehrwertsteuer. Der Auftragnehmer rechnet monatlich nachträglich ab, und jede Rechnung ist dreißig Tage nach ihrem Ausstellungsdatum fällig. Ein am Fälligkeitstag noch offener Betrag wird zum gesetzlichen Zinssatz verzinst, ohne dass dafür eine Mahnung nötig ist.",
        ),
        (
            "Geistiges Eigentum",
            "Sobald eine Rechnung vollständig bezahlt ist, gehören dem Auftraggeber der Quellcode und die Dokumente, die im Rahmen dieses Vertrags für ihn geschrieben wurden. Der Auftragnehmer behält die Werkzeuge, Bibliotheken und allgemeinen Bausteine, die er mitgebracht oder für den allgemeinen Gebrauch geschrieben hat, und räumt dem Auftraggeber eine unbefristete, nicht ausschließliche Lizenz ein, sie als Teil der gelieferten Software zu nutzen.",
        ),
        (
            "Vertraulichkeit",
            "Jede Partei behandelt vertraulich, was sie über Geschäft, Kunden und Technik der anderen erfährt, und nutzt es nur zur Erfüllung dieses Vertrags. Diese Pflicht gilt fünf Jahre über das Vertragsende hinaus. Sie erfasst weder, was ohne Verschulden der empfangenden Partei bereits öffentlich ist, noch, was ein Gericht oder eine Behörde offenzulegen verlangt.",
        ),
        (
            "Gewährleistung und Haftung",
            "Der Auftragnehmer gewährleistet, dass die Arbeit mit fachmännischer Sorgfalt ausgeführt wird, und behebt auf eigene Kosten jeden Mangel, der binnen neunzig Tagen nach Lieferung gemeldet wird. Keine Partei haftet für entgangenen Gewinn, Datenverlust oder mittelbare Schäden, und die Haftung jeder Partei aus diesem Vertrag ist auf die in den zwölf Monaten vor Entstehen des Anspruchs gezahlten Vergütungen begrenzt.",
        ),
        (
            "Kündigung",
            "Jede Partei kann diesen Vertrag mit einer Frist von sechzig Tagen schriftlich kündigen, und jede kann ihn fristlos beenden, wenn die andere eine wesentliche Pflichtverletzung begeht, die nicht binnen dreißig Tagen nach schriftlicher Aufforderung behoben wird. Bei Beendigung zahlt der Auftraggeber die bis dahin geleistete Arbeit, und der Auftragnehmer übergibt die Arbeitsergebnisse in dem Zustand, in dem sie sich dann befinden.",
        ),
        (
            "Mitteilungen",
            "Mitteilungen im Rahmen dieses Vertrags erfolgen schriftlich an die im Kopf dieses Dokuments für die Partei angegebene Adresse und werden am Tag ihrer Zustellung wirksam. Eine Partei, die umzieht, teilt dies der anderen binnen fünfzehn Tagen mit.",
        ),
        (
            "Gesamter Vertrag und anwendbares Recht",
            "Dieses Dokument bildet zusammen mit der beigefügten Leistungsbeschreibung die gesamte Vereinbarung der Parteien zu diesem Gegenstand und ersetzt jede frühere Absprache darüber. Der Vertrag unterliegt französischem Recht, und jeder Streit, den die Parteien nicht untereinander beilegen können, geht vor die Gerichte von Aix-en-Provence, Frankreich.",
        ),
    ],
    signatures: "UNTERSCHRIFTEN",
    note_before: "Jede Partei unterschreibt in den Feldern unten: ",
    note_marked: "Unterschrift, Name in Druckschrift und Datum",
    note_after: ", in einer Lesesoftware ausgefüllt. Der Vertrag wird am späteren der beiden hier eingetragenen Daten wirksam, und jede Partei erhält eine Kopie des unterschriebenen Dokuments.",
    signatory_headings: ["FÜR DEN AUFTRAGNEHMER", "FÜR DEN AUFTRAGGEBER"],
    signatory_roles: ["Geschäftsführer", "Geschäftsführerin"],
    signature_label: "Unterschrift",
    printed_name_label: "Name in Druckschrift",
    date_label: "Datum (TT/MM/JJJJ)",
    page_before: "Vertrag",
    page_word: "Seite",
    page_of: "von",
};

/// Every language the example is written in. A language is added by writing its
/// own set of words and naming it here.
static WORDS: [(Language, &Words); 7] = [
    (Language::English, &ENGLISH),
    (Language::French, &FRENCH),
    (Language::German, &GERMAN),
    (Language::Spanish, &SPANISH),
    (Language::Italian, &ITALIAN),
    (Language::Portuguese, &PORTUGUESE),
    (Language::Dutch, &DUTCH),
];

/// Draws a line of text, left-aligned, in a colour of its own.
fn text(content: &mut Content, font: &FontHandle, size: f64, x: f64, y: f64, color: Rgb, s: &str) {
    let _ = content.set_fill(color);
    content.begin_text();
    let _ = content.set_font(font, size);
    let _ = content.text_origin(x, y);
    content.show_glyphs(&font.glyphs(s));
    content.end_text();
}

/// Draws a line of text whose right edge sits at `right`.
fn text_right(
    content: &mut Content,
    font: &FontHandle,
    size: f64,
    right: f64,
    y: f64,
    color: Rgb,
    s: &str,
) {
    text(
        content,
        font,
        size,
        right - font.measure(s, size),
        y,
        color,
        s,
    );
}

/// A horizontal rule from `LEFT` to `RIGHT` at height `y`.
fn rule(content: &mut Content, y: f64, width: f64, color: Rgb) -> Result<(), hqf_pdf::Error> {
    content.set_stroke(color)?;
    content.set_line_width(width)?;
    content.move_to(LEFT, y)?;
    content.line_to(RIGHT, y)?;
    content.stroke();
    Ok(())
}

/// Draws the letterhead: the mark, the provider's name, what the page is, and
/// the agreement's number and dates, closed off by a rule.
fn letterhead(
    content: &mut Content,
    font: &FontHandle,
    logo: &ImageHandle,
    words: &Words,
) -> Result<(), hqf_pdf::Error> {
    let (logo_w, logo_h) = logo.fit_within(84.0, 84.0)?;
    content.draw_image(logo, LEFT, 826.5 - logo_h, logo_w, logo_h)?;

    text(
        content,
        font,
        8.5,
        LEFT,
        768.0,
        MUTED,
        "42 lot les Genêts, 13480 Calas, France",
    );
    text(
        content,
        font,
        8.5,
        LEFT,
        756.0,
        MUTED,
        "contact@hqf-pdf.com",
    );

    text_right(content, font, 26.0, RIGHT, 796.0, ACCENT, words.heading);
    text_right(
        content,
        font,
        9.5,
        RIGHT,
        770.0,
        INK,
        &format!("{}  {NUMBER}", words.number_label),
    );
    text_right(
        content,
        font,
        9.5,
        RIGHT,
        757.0,
        MUTED,
        &format!("{}  {}", words.signed_label, words.agreement_date),
    );
    text_right(
        content,
        font,
        9.5,
        RIGHT,
        744.0,
        MUTED,
        &format!("{}  {}", words.effective_label, words.effective_date),
    );

    rule(content, 730.0, 1.2, ACCENT)
}

/// Draws the two parties, side by side, and the sentence that binds them.
/// Answers with the height the first clause may start at, which is under
/// however many lines the sentence came to.
fn parties(content: &mut Content, font: &FontHandle, words: &Words) -> Result<f64, hqf_pdf::Error> {
    let columns = [
        (
            words.provider_heading,
            PROVIDER_NAME,
            PROVIDER_LINES,
            PROVIDER_VAT,
            LEFT,
        ),
        (
            words.client_heading,
            CLIENT_NAME,
            CLIENT_LINES,
            CLIENT_VAT,
            COLUMN_TWO,
        ),
    ];

    for (heading, name, lines, vat, x) in columns {
        text(content, font, 8.0, x, 712.0, MUTED, heading);
        text(content, font, 11.5, x, 696.0, INK, name);
        let mut y = 681.0;
        for line in lines {
            text(content, font, 8.5, x, y, MUTED, line);
            y -= 11.5;
        }
        text(
            content,
            font,
            8.5,
            x,
            y,
            MUTED,
            &format!("{} {vat}", words.vat),
        );
    }

    // The date the agreement runs from is underlined mid-sentence, which is
    // what rich text is for.
    let body = Style::new(font, BODY_SIZE);
    let marked = Style::new(font, BODY_SIZE).underline();
    let preamble = RichText::new()
        .align(Align::Justify)
        .span(
            format!(
                "{} {} {} ",
                words.preamble_first, words.agreement_date, words.preamble_second
            ),
            &body,
        )
        .span(words.effective_date, &marked)
        .span(words.preamble_after, &body);

    let preamble_top = 632.0;
    let lines = preamble.break_lines(BODY_WIDTH);
    content.set_fill(INK)?;
    preamble.draw(content, &lines, LEFT, preamble_top, BODY_WIDTH)?;

    Ok(preamble_top - RichText::height(&lines) - 24.0)
}

/// Draws the signature block from `top` down: a heading, a sentence saying what
/// a reader does with it, and a column for each party carrying a signature
/// field, a box for the printed name and a box for the date. The two text
/// fields are pushed onto `fields`, for the page they land on, and the
/// signature fields onto `places`, for the file once it is written.
fn signatures(
    content: &mut Content,
    font: &FontHandle,
    words: &Words,
    top: f64,
    fields: &mut Vec<Field>,
    places: &mut Vec<SignatureField>,
) -> Result<(), hqf_pdf::Error> {
    text(content, font, 10.5, LEFT, top, ACCENT, words.signatures);

    let body = Style::new(font, 9.0);
    let marked = Style::new(font, 9.0).underline();
    let note = RichText::new()
        .align(Align::Justify)
        .span(words.note_before, &body)
        .span(words.note_marked, &marked)
        .span(words.note_after, &body);
    let note_top = top - HEADING_DROP;
    let lines = note.break_lines(BODY_WIDTH);
    content.set_fill(INK)?;
    note.draw(content, &lines, LEFT, note_top, BODY_WIDTH)?;

    let block_top = note_top - RichText::height(&lines) - 28.0;
    let columns = SIGNATORIES
        .iter()
        .zip(words.signatory_headings)
        .zip(words.signatory_roles);
    for (((name, field_name, x), heading), role) in columns {
        text(content, font, 8.0, *x, block_top, MUTED, heading);
        text(
            content,
            font,
            9.5,
            *x,
            block_top - 14.0,
            INK,
            &format!("{name} — {role}"),
        );

        let signature_bottom = block_top - 84.0;
        places.push(
            SignatureField::new(
                format!("{field_name} signature"),
                *x,
                signature_bottom,
                COLUMN_WIDTH,
                48.0,
            )
            .border(FieldBorder::solid(BORDER, BORDER_WIDTH)),
        );
        text(
            content,
            font,
            7.5,
            *x,
            signature_bottom - 10.0,
            MUTED,
            words.signature_label,
        );

        // The printed name and the date are text fields, so what a reader types
        // is read back as text and not as a picture of a hand.
        for (label, field_label, bottom) in [
            (
                words.printed_name_label,
                "printed name",
                signature_bottom - 42.0,
            ),
            (words.date_label, "date", signature_bottom - 84.0),
        ] {
            fields.push(
                TextField::new(
                    format!("{field_name} {field_label}"),
                    *x,
                    bottom,
                    COLUMN_WIDTH,
                    18.0,
                    font.name(),
                    10.0,
                )
                .border(FieldBorder::solid(BORDER, BORDER_WIDTH))
                .into(),
            );
            text(content, font, 7.5, *x, bottom - 10.0, MUTED, label);
        }
    }

    Ok(())
}

/// Draws the foot of one page: a rule, what the law asks the provider to carry,
/// and which page of how many this is.
fn footer(
    content: &mut Content,
    font: &FontHandle,
    words: &Words,
    number: usize,
    total: usize,
) -> Result<(), hqf_pdf::Error> {
    rule(content, 78.0, 0.5, Rgb::gray(0.8))?;

    let mentions = format!(
        "HQF Development · 42 lot les Genêts, 13480 Calas, France · \
        SIRET 752 492 777 00012 · APE 6202A · {} {PROVIDER_VAT}",
        words.vat
    );
    let mentions_x = LEFT + (BODY_WIDTH - font.measure(&mentions, 7.0)) / 2.0;
    text(content, font, 7.0, mentions_x, 66.0, MUTED, &mentions);

    let label = format!(
        "{} {NUMBER} — {} {number} {} {total}",
        words.page_before, words.page_word, words.page_of
    );
    let label_x = LEFT + (BODY_WIDTH - font.measure(&label, 7.0)) / 2.0;
    text(content, font, 7.0, label_x, 55.0, MUTED, &label);
    Ok(())
}

/// What the copy of the written file answers each date field with.
const DATED: &str = "2026-09-17";

fn main() -> std::process::ExitCode {
    failure::reported(run())
}

fn run() -> Result<(), Box<dyn std::error::Error>> {
    let language = Language::from_environment()?;
    let words = Words::of(language);

    let mut args = env::args().skip(1);
    // A named file is written as named; the default one carries the language,
    // so the two languages do not overwrite each other in `tmp/`.
    let path = args
        .next()
        .unwrap_or_else(|| language.file_name(&out::default_path("contract")));
    let font_path = args.next().map_or_else(default_font, PathBuf::from);

    let licence = licence::licensed();
    let mut doc = Document::new();
    doc.set_license(licence.clone());
    doc.set_info(Name::new("Title"), &format!("{} {NUMBER}", words.title));

    let font = doc.add_font(Font::parse(fs::read(&font_path)?)?);
    let logo = doc.add_image(Image::parse(fs::read(logo_path())?)?);

    let mut content = Content::new();
    letterhead(&mut content, &font, &logo, words)?;
    let mut top = parties(&mut content, &font, words)?;

    // Every clause is measured before it is drawn, and one that would run past
    // the foot of the page starts the next one whole: a heading is never left
    // behind on a page away from the paragraph it introduces.
    let mut finished: Vec<Content> = Vec::new();
    let flow = TextFlow::new(&font, BODY_SIZE)
        .align(Align::Justify)
        .leading(LEADING);

    for (index, (heading, clause)) in words.clauses.iter().enumerate() {
        let lines = flow.break_lines(clause, BODY_WIDTH);
        let height = flow.height(&lines);
        if top - (HEADING_DROP + height + CLAUSE_GAP) < BOTTOM {
            finished.push(std::mem::replace(&mut content, Content::new()));
            top = NEXT_TOP;
        }

        let numbered = format!("{}. {heading}", index + 1);
        text(&mut content, &font, 10.5, LEFT, top, ACCENT, &numbered);

        let body_top = top - HEADING_DROP;
        content.set_fill(INK)?;
        content.begin_text();
        flow.draw(&mut content, &lines, LEFT, body_top, BODY_WIDTH)?;
        content.end_text();

        top = body_top - height - CLAUSE_GAP;
    }

    if top - SIGNATURE_HEIGHT < BOTTOM {
        finished.push(std::mem::replace(&mut content, Content::new()));
        top = NEXT_TOP;
    }
    let mut fields = Vec::new();
    let mut places = Vec::new();
    signatures(
        &mut content,
        &font,
        words,
        top - 10.0,
        &mut fields,
        &mut places,
    )?;
    finished.push(content);

    // The footer says which page of how many, so it is drawn once the count is
    // known, and the fields go on the page the signature block landed on.
    let total = finished.len();
    for (index, mut content) in finished.into_iter().enumerate() {
        footer(&mut content, &font, words, index + 1, total)?;

        let mut page = Page::new(PAGE_WIDTH, PAGE_HEIGHT);
        page.content = content.into_bytes();
        if index + 1 == total {
            page.fields = std::mem::take(&mut fields);
        }
        doc.add_page(page)?;
    }

    doc.set_open_mode(OpenMode::PageOnly);

    doc.set_page_layout(PageLayout::OneColumn);

    doc.set_viewer_preferences(
        ViewerPreferences::new()
            .after_full_screen(SidePanel::PageOnly)
            .duplex(Duplex::OneSided),
    );

    let mut bytes = doc.to_bytes()?;

    // Each signature field goes into the written file as a section of its own,
    // on the last page, where the signature block is drawn.
    if !licence.marks_documents() {
        for place in &places {
            let mut update = IncrementalUpdate::new(bytes)?;
            update.set_license(licence.clone());
            bytes = update.to_bytes_with_signature_field(total - 1, place)?;
        }

        // What the written file asks, read back from it, and a copy of it with
        // the dates answered as a section of its own; the copy is not kept.
        let mut read = IncrementalUpdate::new(bytes.clone())?;
        read.set_license(licence);
        let signed_in = read.signature_fields()?;
        let asked = read.form_fields()?;
        let dated: Vec<(&str, &str)> = asked
            .iter()
            .filter(|field| field.name.ends_with(" date"))
            .map(|field| (field.name.as_str(), DATED))
            .collect();
        let filled = read.to_filled_bytes(&dated)?;
        println!(
            "{} signature fields ({}), {} fields in all; {} dates answered in a copy of {} bytes",
            signed_in.len(),
            signed_in.join(", "),
            asked.len(),
            dated.len(),
            filled.len()
        );
    }

    if let Some(parent) = Path::new(&path).parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(&path, &bytes)?;

    println!("wrote {path}: {} bytes, {total} pages", bytes.len());
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{WORDS, language};

    /// The lines two languages are allowed to write the same way, each with
    /// what makes the two the same word.
    const SPARED: [&str; 13] = [
        // The party that buys the services is a client in both.
        r#"client_heading: "CLIENT""#,
        // A block of signatures is headed by the same word in both.
        r#"signatures: "SIGNATURES""#,
        // What a hand puts in the first box is a signature in both.
        r#"signature_label: "Signature""#,
        // A page is a page in both.
        r#"page_word: "page""#,
        // Written the same way in Spanish.
        r#""Director""#,
        // Written the same way in Italian.
        r#"client_heading: "CLIENTE""#,
        r#"signature_label: "Firma""#,
        // Written the same way in Portuguese.
        r#"heading: "CONTRATO""#,
        r#"number_label: "Contrato n.º""#,
        r#"page_before: "Contrato""#,
        r#"page_of: "de""#,
        r#"page_word: "página""#,
        // Written the same way in Dutch.
        r#"page_word: "pagina""#,
    ];

    #[test]
    fn every_language_draws_the_agreement_in_its_own_words() {
        let untranslated = language::untranslated_lines(&WORDS, &SPARED);

        assert!(
            untranslated.is_empty(),
            "the agreement says these in more than one language: {untranslated:?}"
        );
    }
}