Compare commits

..
Author SHA1 Message Date
Anthony Stirling 1595a1799d url and close button 2026-01-27 21:53:18 +00:00
Anthony Stirling 7d621a9966 fix 2026-01-25 01:04:47 +00:00
269 changed files with 3752 additions and 14384 deletions
+2 -19
View File
@@ -59,8 +59,8 @@ def find_duplicate_keys(file_path, keys=None, prefix=""):
return duplicates
# Maximum size for TOML files (e.g., 1 MB)
MAX_FILE_SIZE = 1000 * 1024
# Maximum size for TOML files (e.g., 570 KB)
MAX_FILE_SIZE = 570 * 1024
def parse_toml_file(file_path):
@@ -259,27 +259,10 @@ def check_for_differences(reference_file, file_list, branch, actor):
report.append(
f" - **_Extra keys in `{locale_dir}/{basename_current_file}`_**: `{missing_keys_str}` that are not present in **_`{basename_reference_file}`_**."
)
report.append("")
report.append(" Use the following command to remove them:")
report.append(
f" `python scripts/translations/translation_merger.py {locale_dir} remove-unused`"
)
report.append("")
if extra_keys_list:
report.append(
f" - **_Missing keys in `{locale_dir}/{basename_current_file}`_**: `{extra_keys_str}` that are not present in **_`{basename_reference_file}`_**."
)
report.append("")
report.append(" Use the following command to add them:")
report.append(
f" `python scripts/translations/translation_merger.py {locale_dir} add-missing`"
)
report.append("")
if missing_keys_list or extra_keys_list:
report.append(
" See: https://github.com/Stirling-Tools/Stirling-PDF/tree/main/scripts/translations#2-translation_mergerpy"
)
else:
report.append("2. **Test Status:** ✅ **_Passed_**")
+329 -280
View File
@@ -97,9 +97,9 @@ cffi==2.0.0 \
--hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \
--hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf
# via weasyprint
cfgv==3.5.0 \
--hash=sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0 \
--hash=sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132
cfgv==3.4.0 \
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
# via pre-commit
cssselect2==0.8.0 \
--hash=sha256:46fc70ebc41ced7a32cd42d58b1884d72ade23d21e5a4eaaf022401c13f0e76e \
@@ -109,269 +109,259 @@ distlib==0.4.0 \
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
# via virtualenv
filelock==3.20.3 \
--hash=sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1 \
--hash=sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1
filelock==3.20.0 \
--hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \
--hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4
# via virtualenv
fonttools==4.61.1 \
--hash=sha256:0de30bfe7745c0d1ffa2b0b7048fb7123ad0d71107e10ee090fa0b16b9452e87 \
--hash=sha256:10d88e55330e092940584774ee5e8a6971b01fc2f4d3466a1d6c158230880796 \
--hash=sha256:11f35ad7805edba3aac1a3710d104592df59f4b957e30108ae0ba6c10b11dd75 \
--hash=sha256:15acc09befd16a0fb8a8f62bc147e1a82817542d72184acca9ce6e0aeda9fa6d \
--hash=sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371 \
--hash=sha256:2180f14c141d2f0f3da43f3a81bc8aa4684860f6b0e6f9e165a4831f24e6a23b \
--hash=sha256:21e7c8d76f62ab13c9472ccf74515ca5b9a761d1bde3265152a6dc58700d895b \
--hash=sha256:41a7170d042e8c0024703ed13b71893519a1a6d6e18e933e3ec7507a2c26a4b2 \
--hash=sha256:41ed4b5ec103bd306bb68f81dc166e77409e5209443e5773cb4ed837bcc9b0d3 \
--hash=sha256:497c31ce314219888c0e2fce5ad9178ca83fe5230b01a5006726cdf3ac9f24d9 \
--hash=sha256:4c1b526c8d3f615a7b1867f38a9410849c8f4aef078535742198e942fba0e9bd \
--hash=sha256:4d7092bb38c53bbc78e9255a59158b150bcdc115a1e3b3ce0b5f267dc35dd63c \
--hash=sha256:4f5686e1fe5fce75d82d93c47a438a25bf0d1319d2843a926f741140b2b16e0c \
--hash=sha256:58b0ee0ab5b1fc9921eccfe11d1435added19d6494dde14e323f25ad2bc30c56 \
--hash=sha256:5ce02f38a754f207f2f06557523cd39a06438ba3aafc0639c477ac409fc64e37 \
--hash=sha256:5fade934607a523614726119164ff621e8c30e8fa1ffffbbd358662056ba69f0 \
--hash=sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958 \
--hash=sha256:64102ca87e84261419c3747a0d20f396eb024bdbeb04c2bfb37e2891f5fadcb5 \
--hash=sha256:664c5a68ec406f6b1547946683008576ef8b38275608e1cee6c061828171c118 \
--hash=sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69 \
--hash=sha256:75c1a6dfac6abd407634420c93864a1e274ebc1c7531346d9254c0d8f6ca00f9 \
--hash=sha256:75da8f28eff26defba42c52986de97b22106cb8f26515b7c22443ebc9c2d3261 \
--hash=sha256:77efb033d8d7ff233385f30c62c7c79271c8885d5c9657d967ede124671bbdfb \
--hash=sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47 \
--hash=sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24 \
--hash=sha256:8c56c488ab471628ff3bfa80964372fc13504ece601e0d97a78ee74126b2045c \
--hash=sha256:91669ccac46bbc1d09e9273546181919064e8df73488ea087dcac3e2968df9ba \
--hash=sha256:9b666a475a65f4e839d3d10473fad6d47e0a9db14a2f4a224029c5bfde58ad2c \
--hash=sha256:9cfef3ab326780c04d6646f68d4b4742aae222e8b8ea1d627c74e38afcbc9d91 \
--hash=sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1 \
--hash=sha256:a75c301f96db737e1c5ed5fd7d77d9c34466de16095a266509e13da09751bd19 \
--hash=sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6 \
--hash=sha256:aed04cabe26f30c1647ef0e8fbb207516fd40fe9472e9439695f5c6998e60ac5 \
--hash=sha256:b148b56f5de675ee16d45e769e69f87623a4944f7443850bf9a9376e628a89d2 \
--hash=sha256:b501c862d4901792adaec7c25b1ecc749e2662543f68bb194c42ba18d6eec98d \
--hash=sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881 \
--hash=sha256:b931ae8f62db78861b0ff1ac017851764602288575d65b8e8ff1963fed419063 \
--hash=sha256:c33ab3ca9d3ccd581d58e989d67554e42d8d4ded94ab3ade3508455fe70e65f7 \
--hash=sha256:c6604b735bb12fef8e0efd5578c9fb5d3d8532d5001ea13a19cddf295673ee09 \
--hash=sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da \
--hash=sha256:d9203500f7c63545b4ce3799319fe4d9feb1a1b89b28d3cb5abd11b9dd64147e \
--hash=sha256:dc492779501fa723b04d0ab1f5be046797fee17d27700476edc7ee9ae535a61e \
--hash=sha256:e6bcdf33aec38d16508ce61fd81838f24c83c90a1d1b8c68982857038673d6b8 \
--hash=sha256:e76ce097e3c57c4bcb67c5aa24a0ecdbd9f74ea9219997a707a4061fbe2707aa \
--hash=sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6 \
--hash=sha256:f3cb4a569029b9f291f88aafc927dd53683757e640081ca8c412781ea144565e \
--hash=sha256:f79b168428351d11e10c5aeb61a74e1851ec221081299f4cf56036a95431c43a \
--hash=sha256:fa646ecec9528bef693415c79a86e733c70a4965dd938e9a226b0fc64c9d2e6c \
--hash=sha256:fe2efccb324948a11dd09d22136fe2ac8a97d6c1347cf0b58a911dcd529f66b7 \
--hash=sha256:fff4f534200a04b4a36e7ae3cb74493afe807b517a09e99cb4faa89a34ed6ecd
fonttools==4.60.1 \
--hash=sha256:022beaea4b73a70295b688f817ddc24ed3e3418b5036ffcd5658141184ef0d0c \
--hash=sha256:026290e4ec76583881763fac284aca67365e0be9f13a7fb137257096114cb3bc \
--hash=sha256:0b0835ed15dd5b40d726bb61c846a688f5b4ce2208ec68779bc81860adb5851a \
--hash=sha256:0eae96373e4b7c9e45d099d7a523444e3554360927225c1cdae221a58a45b856 \
--hash=sha256:122e1a8ada290423c493491d002f622b1992b1ab0b488c68e31c413390dc7eb2 \
--hash=sha256:1410155d0e764a4615774e5c2c6fc516259fe3eca5882f034eb9bfdbee056259 \
--hash=sha256:145daa14bf24824b677b9357c5e44fd8895c2a8f53596e1b9ea3496081dc692c \
--hash=sha256:1525796c3ffe27bb6268ed2a1bb0dcf214d561dfaf04728abf01489eb5339dce \
--hash=sha256:154cb6ee417e417bf5f7c42fe25858c9140c26f647c7347c06f0cc2d47eff003 \
--hash=sha256:2299df884c11162617a66b7c316957d74a18e3758c0274762d2cc87df7bc0272 \
--hash=sha256:2409d5fb7b55fd70f715e6d34e7a6e4f7511b8ad29a49d6df225ee76da76dd77 \
--hash=sha256:268ecda8ca6cb5c4f044b1fb9b3b376e8cd1b361cef275082429dc4174907038 \
--hash=sha256:282dafa55f9659e8999110bd8ed422ebe1c8aecd0dc396550b038e6c9a08b8ea \
--hash=sha256:2ee06fc57512144d8b0445194c2da9f190f61ad51e230f14836286470c99f854 \
--hash=sha256:3630e86c484263eaac71d117085d509cbcf7b18f677906824e4bace598fb70d2 \
--hash=sha256:398447f3d8c0c786cbf1209711e79080a40761eb44b27cdafffb48f52bcec258 \
--hash=sha256:4ba4bd646e86de16160f0fb72e31c3b9b7d0721c3e5b26b9fa2fc931dfdb2652 \
--hash=sha256:5664fd1a9ea7f244487ac8f10340c4e37664675e8667d6fee420766e0fb3cf08 \
--hash=sha256:583b7f8e3c49486e4d489ad1deacfb8d5be54a8ef34d6df824f6a171f8511d99 \
--hash=sha256:596ecaca36367027d525b3b426d8a8208169d09edcf8c7506aceb3a38bfb55c7 \
--hash=sha256:5c1015318e4fec75dd4943ad5f6a206d9727adf97410d58b7e32ab644a807914 \
--hash=sha256:66929e2ea2810c6533a5184f938502cfdaea4bc3efb7130d8cc02e1c1b4108d6 \
--hash=sha256:6ec722ee589e89a89f5b7574f5c45604030aa6ae24cb2c751e2707193b466fed \
--hash=sha256:6f68576bb4bbf6060c7ab047b1574a1ebe5c50a17de62830079967b211059ebb \
--hash=sha256:7473a8ed9ed09aeaa191301244a5a9dbe46fe0bf54f9d6cd21d83044c3321217 \
--hash=sha256:7b0c6d57ab00dae9529f3faf187f2254ea0aa1e04215cf2f1a8ec277c96661bc \
--hash=sha256:7b4c32e232a71f63a5d00259ca3d88345ce2a43295bb049d21061f338124246f \
--hash=sha256:8177ec9676ea6e1793c8a084a90b65a9f778771998eb919d05db6d4b1c0b114c \
--hash=sha256:839565cbf14645952d933853e8ade66a463684ed6ed6c9345d0faf1f0e868877 \
--hash=sha256:875cb7764708b3132637f6c5fb385b16eeba0f7ac9fa45a69d35e09b47045801 \
--hash=sha256:8a44788d9d91df72d1a5eac49b31aeb887a5f4aab761b4cffc4196c74907ea85 \
--hash=sha256:8b4eb332f9501cb1cd3d4d099374a1e1306783ff95489a1026bde9eb02ccc34a \
--hash=sha256:906306ac7afe2156fcf0042173d6ebbb05416af70f6b370967b47f8f00103bbb \
--hash=sha256:992775c9fbe2cf794786fa0ffca7f09f564ba3499b8fe9f2f80bd7197db60383 \
--hash=sha256:996a4d1834524adbb423385d5a629b868ef9d774670856c63c9a0408a3063401 \
--hash=sha256:9a52f254ce051e196b8fe2af4634c2d2f02c981756c6464dc192f1b6050b4e28 \
--hash=sha256:9d0ced62b59e0430b3690dbc5373df1c2aa7585e9a8ce38eff87f0fd993c5b01 \
--hash=sha256:a140761c4ff63d0cb9256ac752f230460ee225ccef4ad8f68affc723c88e2036 \
--hash=sha256:a184b2ea57b13680ab6d5fbde99ccef152c95c06746cb7718c583abd8f945ccc \
--hash=sha256:a3db56f153bd4c5c2b619ab02c5db5192e222150ce5a1bc10f16164714bc39ac \
--hash=sha256:a46b2f450bc79e06ef3b6394f0c68660529ed51692606ad7f953fc2e448bc903 \
--hash=sha256:a884aef09d45ba1206712c7dbda5829562d3fea7726935d3289d343232ecb0d3 \
--hash=sha256:b2cf105cee600d2de04ca3cfa1f74f1127f8455b71dbad02b9da6ec266e116d6 \
--hash=sha256:b33a7884fabd72bdf5f910d0cf46be50dce86a0362a65cfc746a4168c67eb96c \
--hash=sha256:b42d86938e8dda1cd9a1a87a6d82f1818eaf933348429653559a458d027446da \
--hash=sha256:b6379e7546ba4ae4b18f8ae2b9bc5960936007a1c0e30b342f662577e8bc3299 \
--hash=sha256:c7420a2696a44650120cdd269a5d2e56a477e2bfa9d95e86229059beb1c19e15 \
--hash=sha256:c8651e0d4b3bdeda6602b85fdc2abbefc1b41e573ecb37b6779c4ca50753a199 \
--hash=sha256:d066ea419f719ed87bc2c99a4a4bfd77c2e5949cb724588b9dd58f3fd90b92bf \
--hash=sha256:e6c58beb17380f7c2ea181ea11e7db8c0ceb474c9dd45f48e71e2cb577d146a1 \
--hash=sha256:e852d9dda9f93ad3651ae1e3bb770eac544ec93c3807888798eccddf84596537 \
--hash=sha256:ec3681a0cb34c255d76dd9d865a55f260164adb9fa02628415cdc2d43ee2c05d \
--hash=sha256:ee0c0b3b35b34f782afc673d503167157094a16f442ace7c6c5e0ca80b08f50c \
--hash=sha256:eedacb5c5d22b7097482fa834bda0dafa3d914a4e829ec83cdea2a01f8c813c4 \
--hash=sha256:ef00af0439ebfee806b25f24c8f92109157ff3fac5731dc7867957812e87b8d9 \
--hash=sha256:f0e8817c7d1a0c2eedebf57ef9a9896f3ea23324769a9a2061a80fe8852705ed \
--hash=sha256:f3d5be054c461d6a2268831f04091dc82753176f6ea06dc6047a5e168265a987 \
--hash=sha256:f4b5c37a5f40e4d733d3bbaaef082149bee5a5ea3156a785ff64d949bd1353fa
# via weasyprint
identify==2.6.16 \
--hash=sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0 \
--hash=sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980
identify==2.6.15 \
--hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \
--hash=sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf
# via pre-commit
nodeenv==1.10.0 \
--hash=sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827 \
--hash=sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb
nodeenv==1.9.1 \
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
--hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
# via pre-commit
numpy==2.4.1 \
--hash=sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c \
--hash=sha256:09aa8a87e45b55a1c2c205d42e2808849ece5c484b2aab11fecabec3841cafba \
--hash=sha256:0cce2a669e3c8ba02ee563c7835f92c153cf02edff1ae05e1823f1dde21b16a5 \
--hash=sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8 \
--hash=sha256:0f118ce6b972080ba0758c6087c3617b5ba243d806268623dc34216d69099ba0 \
--hash=sha256:178de8f87948163d98a4c9ab5bee4ce6519ca918926ec8df195af582de28544d \
--hash=sha256:18e14c4d09d55eef39a6ab5b08406e84bc6869c1e34eef45564804f90b7e0574 \
--hash=sha256:2023ef86243690c2791fd6353e5b4848eedaa88ca8a2d129f462049f6d484696 \
--hash=sha256:20d4649c773f66cc2fc36f663e091f57c3b7655f936a4c681b4250855d1da8f5 \
--hash=sha256:2302dc0224c1cbc49bb94f7064f3f923a971bfae45c33870dcbff63a2a550505 \
--hash=sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0 \
--hash=sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162 \
--hash=sha256:2f44de05659b67d20499cbc96d49f2650769afcb398b79b324bb6e297bfe3844 \
--hash=sha256:2ffd257026eb1b34352e749d7cc1678b5eeec3e329ad8c9965a797e08ccba205 \
--hash=sha256:382ad67d99ef49024f11d1ce5dcb5ad8432446e4246a4b014418ba3a1175a1f4 \
--hash=sha256:3869ea1ee1a1edc16c29bbe3a2f2a4e515cc3a44d43903ad41e0cacdbaf733dc \
--hash=sha256:3d1a100e48cb266090a031397863ff8a30050ceefd798f686ff92c67a486753d \
--hash=sha256:423797bdab2eeefbe608d7c1ec7b2b4fd3c58d51460f1ee26c7500a1d9c9ee93 \
--hash=sha256:42d7dd5fa36d16d52a84f821eb96031836fd405ee6955dd732f2023724d0aa01 \
--hash=sha256:49e792ec351315e16da54b543db06ca8a86985ab682602d90c60ef4ff4db2a9c \
--hash=sha256:4e53170557d37ae404bf8d542ca5b7c629d6efa1117dac6a83e394142ea0a43f \
--hash=sha256:4f1b68ff47680c2925f8063402a693ede215f0257f02596b1318ecdfb1d79e33 \
--hash=sha256:4f9c360ecef085e5841c539a9a12b883dff005fbd7ce46722f5e9cef52634d82 \
--hash=sha256:529050522e983e00a6c1c6b67411083630de8b57f65e853d7b03d9281b8694d2 \
--hash=sha256:52b5f61bdb323b566b528899cc7db2ba5d1015bda7ea811a8bcf3c89c331fa42 \
--hash=sha256:538bf4ec353709c765ff75ae616c34d3c3dca1a68312727e8f2676ea644f8509 \
--hash=sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a \
--hash=sha256:5b55aa56165b17aaf15520beb9cbd33c9039810e0d9643dd4379e44294c7303e \
--hash=sha256:5d558123217a83b2d1ba316b986e9248a1ed1971ad495963d555ccd75dcb1556 \
--hash=sha256:5de60946f14ebe15e713a6f22850c2372fa72f4ff9a432ab44aa90edcadaa65a \
--hash=sha256:62fea415f83ad8fdb6c20840578e5fbaf5ddd65e0ec6c3c47eda0f69da172510 \
--hash=sha256:6436cffb4f2bf26c974344439439c95e152c9a527013f26b3577be6c2ca64295 \
--hash=sha256:6461de5113088b399d655d45c3897fa188766415d0f568f175ab071c8873bd73 \
--hash=sha256:69e7419c9012c4aaf695109564e3387f1259f001b4326dfa55907b098af082d3 \
--hash=sha256:71abbea030f2cfc3092a0ff9f8c8fdefdc5e0bf7d9d9c99663538bb0ecdac0b9 \
--hash=sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8 \
--hash=sha256:727c6c3275ddefa0dc078524a85e064c057b4f4e71ca5ca29a19163c607be745 \
--hash=sha256:79e9e06c4c2379db47f3f6fc7a8652e7498251789bf8ff5bd43bf478ef314ca2 \
--hash=sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02 \
--hash=sha256:7d5d7999df434a038d75a748275cd6c0094b0ecdb0837342b332a82defc4dc4d \
--hash=sha256:8097529164c0f3e32bb89412a0905d9100bf434d9692d9fc275e18dcf53c9344 \
--hash=sha256:82c55962006156aeef1629b953fd359064aa47e4d82cfc8e67f0918f7da3344f \
--hash=sha256:8361ea4220d763e54cff2fbe7d8c93526b744f7cd9ddab47afeff7e14e8503be \
--hash=sha256:899d2c18024984814ac7e83f8f49d8e8180e2fbe1b2e252f2e7f1d06bea92425 \
--hash=sha256:8ad35f20be147a204e28b6a0575fbf3540c5e5f802634d4258d55b1ff5facce1 \
--hash=sha256:8f085da926c0d491ffff3096f91078cc97ea67e7e6b65e490bc8dcda65663be2 \
--hash=sha256:9171a42fcad32dcf3fa86f0a4faa5e9f8facefdb276f54b8b390d90447cff4e2 \
--hash=sha256:92a0e65272fd60bfa0d9278e0484c2f52fe03b97aedc02b357f33fe752c52ffb \
--hash=sha256:941c2a93313d030f219f3a71fd3d91a728b82979a5e8034eb2e60d394a2b83f9 \
--hash=sha256:98b35775e03ab7f868908b524fc0a84d38932d8daf7b7e1c3c3a1b6c7a2c9f15 \
--hash=sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690 \
--hash=sha256:a73044b752f5d34d4232f25f18160a1cc418ea4507f5f11e299d8ac36875f8a0 \
--hash=sha256:a7870e8c5fc11aef57d6fea4b4085e537a3a60ad2cdd14322ed531fdca68d261 \
--hash=sha256:a92f227dbcdc9e4c3e193add1a189a9909947d4f8504c576f4a732fd0b54240a \
--hash=sha256:ac08c63cb7779b85e9d5318e6c3518b424bc1f364ac4cb2c6136f12e5ff2dccc \
--hash=sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f \
--hash=sha256:c0faba4a331195bfa96f93dd9dfaa10b2c7aa8cda3a02b7fd635e588fe821bf5 \
--hash=sha256:ce9ce141a505053b3c7bce3216071f3bf5c182b8b28930f14cd24d43932cd2df \
--hash=sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9 \
--hash=sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2 \
--hash=sha256:d3e3087f53e2b4428766b54932644d148613c5a595150533ae7f00dab2f319a8 \
--hash=sha256:d3f8f0df9f4b8be57b3bf74a1d087fec68f927a2fab68231fdb442bf2c12e426 \
--hash=sha256:d797454e37570cfd61143b73b8debd623c3c0952959adb817dd310a483d58a1b \
--hash=sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87 \
--hash=sha256:e3bd2cb07841166420d2fa7146c96ce00cb3410664cbc1a6be028e456c4ee220 \
--hash=sha256:e7b6b5e28bbd47b7532698e5db2fe1db693d84b58c254e4389d99a27bb9b8f6b \
--hash=sha256:e867df947d427cdd7a60e3e271729090b0f0df80f5f10ab7dd436f40811699c3 \
--hash=sha256:ea66d2b41ca4a1630aae5507ee0a71647d3124d1741980138aa8f28f44dac36e \
--hash=sha256:edee228f76ee2dab4579fad6f51f6a305de09d444280109e0f75df247ff21501 \
--hash=sha256:f0a90aba7d521e6954670550e561a4cb925713bd944445dbe9e729b71f6cabee \
--hash=sha256:f93bc6892fe7b0663e5ffa83b61aab510aacffd58c16e012bb9352d489d90cb7 \
--hash=sha256:fb1461c99de4d040666ca0444057b06541e5642f800b71c56e6ea92d6a853a0c
numpy==2.2.6 \
--hash=sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff \
--hash=sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47 \
--hash=sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84 \
--hash=sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d \
--hash=sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6 \
--hash=sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f \
--hash=sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b \
--hash=sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49 \
--hash=sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163 \
--hash=sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571 \
--hash=sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42 \
--hash=sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff \
--hash=sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491 \
--hash=sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4 \
--hash=sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566 \
--hash=sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf \
--hash=sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40 \
--hash=sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd \
--hash=sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06 \
--hash=sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282 \
--hash=sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680 \
--hash=sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db \
--hash=sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3 \
--hash=sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90 \
--hash=sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1 \
--hash=sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289 \
--hash=sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab \
--hash=sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c \
--hash=sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d \
--hash=sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb \
--hash=sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d \
--hash=sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a \
--hash=sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf \
--hash=sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1 \
--hash=sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2 \
--hash=sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a \
--hash=sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543 \
--hash=sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00 \
--hash=sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c \
--hash=sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f \
--hash=sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd \
--hash=sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868 \
--hash=sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303 \
--hash=sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83 \
--hash=sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3 \
--hash=sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d \
--hash=sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87 \
--hash=sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa \
--hash=sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f \
--hash=sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae \
--hash=sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda \
--hash=sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915 \
--hash=sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249 \
--hash=sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de \
--hash=sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8
# via opencv-python-headless
opencv-python-headless==4.13.0.90 \
--hash=sha256:0e0c8c9f620802fddc4fa7f471a1d263c7b0dca16cd9e7e2f996bb8bd2128c0c \
--hash=sha256:12a28674f215542c9bf93338de1b5bffd76996d32da9acb9e739fdb9c8bbd738 \
--hash=sha256:32255203040dc98803be96362e13f9e4bce20146898222d2e5c242f80de50da5 \
--hash=sha256:96060fc57a1abb1144b0b8129e2ff3bfcdd0ccd8e8bd05bd85256ff4ed587d3b \
--hash=sha256:dbc1f4625e5af3a80ebdbd84380227c0f445228588f2521b11af47710caca1ba \
--hash=sha256:e13790342591557050157713af17a7435ac1b50c65282715093c9297fa045d8f \
--hash=sha256:eba38bc255d0b7d1969c5bcc90a060ca2b61a3403b613872c750bfa5dfe9e03b \
--hash=sha256:f46b17ea0aa7e4124ca6ad71143f89233ae9557f61d2326bcdb34329a1ddf9bd
opencv-python-headless==4.12.0.88 \
--hash=sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e \
--hash=sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9 \
--hash=sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154 \
--hash=sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528 \
--hash=sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0 \
--hash=sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09 \
--hash=sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd
# via -r .github/scripts/requirements_dev.in
pdf2image==1.17.0 \
--hash=sha256:eaa959bc116b420dd7ec415fcae49b98100dda3dd18cd2fdfa86d09f112f6d57 \
--hash=sha256:ecdd58d7afb810dffe21ef2b1bbc057ef434dabbac6c33778a38a3f7744a27e2
# via -r .github/scripts/requirements_dev.in
pillow==12.1.0 \
--hash=sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d \
--hash=sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc \
--hash=sha256:0b022eaaf709541b391ee069f0022ee5b36c709df71986e3f7be312e46f42c84 \
--hash=sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de \
--hash=sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0 \
--hash=sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef \
--hash=sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4 \
--hash=sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82 \
--hash=sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9 \
--hash=sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030 \
--hash=sha256:1f345e7bc9d7f368887c712aa5054558bad44d2a301ddf9248599f4161abc7c0 \
--hash=sha256:1fcc52d86ce7a34fd17cb04e87cfdb164648a3662a6f20565910a99653d66c18 \
--hash=sha256:21e686a21078b0f9cb8c8a961d99e6a4ddb88e0fc5ea6e130172ddddc2e5221a \
--hash=sha256:2415373395a831f53933c23ce051021e79c8cd7979822d8cc478547a3f4da8ef \
--hash=sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b \
--hash=sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6 \
--hash=sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179 \
--hash=sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e \
--hash=sha256:351889afef0f485b84078ea40fe33727a0492b9af3904661b0abbafee0355b72 \
--hash=sha256:3ffaa2f0659e2f740473bcf03c702c39a8d4b2b7ffc629052028764324842c64 \
--hash=sha256:40a8e3b9e8773876d6e30daed22f016509e3987bab61b3b7fe309d7019a87451 \
--hash=sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd \
--hash=sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924 \
--hash=sha256:43b4899cfd091a9693a1278c4982f3e50f7fb7cff5153b05174b4afc9593b616 \
--hash=sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a \
--hash=sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94 \
--hash=sha256:53d8b764726d3af1a138dd353116f774e3862ec7e3794e0c8781e30db0f35dfc \
--hash=sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8 \
--hash=sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9 \
--hash=sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91 \
--hash=sha256:5da841d81b1a05ef940a8567da92decaa15bc4d7dedb540a8c219ad83d91808a \
--hash=sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c \
--hash=sha256:609e89d9f90b581c8d16358c9087df76024cf058fa693dd3e1e1620823f39670 \
--hash=sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea \
--hash=sha256:64efdf00c09e31efd754448a383ea241f55a994fd079866b92d2bbff598aad91 \
--hash=sha256:65b80c1ee7e14a87d6a068dd3b0aea268ffcabfe0498d38661b00c5b4b22e74c \
--hash=sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc \
--hash=sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0 \
--hash=sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b \
--hash=sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65 \
--hash=sha256:742aea052cf5ab5034a53c3846165bc3ce88d7c38e954120db0ab867ca242661 \
--hash=sha256:75af0b4c229ac519b155028fa1be632d812a519abba9b46b20e50c6caa184f19 \
--hash=sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1 \
--hash=sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0 \
--hash=sha256:800429ac32c9b72909c671aaf17ecd13110f823ddb7db4dfef412a5587c2c24e \
--hash=sha256:806f3987ffe10e867bab0ddad45df1148a2b98221798457fa097ad85d6e8bc75 \
--hash=sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4 \
--hash=sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8 \
--hash=sha256:84cabc7095dd535ca934d57e9ce2a72ffd216e435a84acb06b2277b1de2689bd \
--hash=sha256:8637e29d13f478bc4f153d8daa9ffb16455f0a6cb287da1b432fdad2bfbd66c7 \
--hash=sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61 \
--hash=sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51 \
--hash=sha256:907bfa8a9cb790748a9aa4513e37c88c59660da3bcfffbd24a7d9e6abf224551 \
--hash=sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45 \
--hash=sha256:92a7fe4225365c5e3a8e598982269c6d6698d3e783b3b1ae979e7819f9cd55c1 \
--hash=sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644 \
--hash=sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796 \
--hash=sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587 \
--hash=sha256:9f5fefaca968e700ad1a4a9de98bf0869a94e397fe3524c4c9450c1445252304 \
--hash=sha256:a332ac4ccb84b6dde65dbace8431f3af08874bf9770719d32a635c4ef411b18b \
--hash=sha256:a40905599d8079e09f25027423aed94f2823adaf2868940de991e53a449e14a8 \
--hash=sha256:a6dfc2af5b082b635af6e08e0d1f9f1c4e04d17d4e2ca0ef96131e85eda6eb17 \
--hash=sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171 \
--hash=sha256:a83e0850cb8f5ac975291ebfc4170ba481f41a28065277f7f735c202cd8e0af3 \
--hash=sha256:aa0c9cc0b82b14766a99fbe6084409972266e82f459821cd26997a488a7261a7 \
--hash=sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988 \
--hash=sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a \
--hash=sha256:b6e53e82ec2db0717eabb276aa56cf4e500c9a7cec2c2e189b55c24f65a3e8c0 \
--hash=sha256:bb0984b30e973f7e2884362b7d23d0a348c7143ee559f38ef3eaab640144204c \
--hash=sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2 \
--hash=sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14 \
--hash=sha256:bef9768cab184e7ae6e559c032e95ba8d07b3023c289f79a2bd36e8bf85605a5 \
--hash=sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a \
--hash=sha256:ca94b6aac0d7af2a10ba08c0f888b3d5114439b6b3ef39968378723622fed377 \
--hash=sha256:cad302dc10fac357d3467a74a9561c90609768a6f73a1923b0fd851b6486f8b0 \
--hash=sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5 \
--hash=sha256:d70347c8a5b7ccd803ec0c85c8709f036e6348f1e6a5bf048ecd9c64d3550b8b \
--hash=sha256:d70534cea9e7966169ad29a903b99fc507e932069a881d0965a1a84bb57f6c6d \
--hash=sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac \
--hash=sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c \
--hash=sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554 \
--hash=sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643 \
--hash=sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13 \
--hash=sha256:e75d3dba8fc1ddfec0cd752108f93b83b4f8d6ab40e524a95d35f016b9683b09 \
--hash=sha256:efdc140e7b63b8f739d09a99033aa430accce485ff78e6d311973a67b6bf3208 \
--hash=sha256:f10c98f49227ed8383d28174ee95155a675c4ed7f85e2e573b04414f7e371bda \
--hash=sha256:f188028b5af6b8fb2e9a76ac0f841a575bd1bd396e46ef0840d9b88a48fdbcea \
--hash=sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e \
--hash=sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0 \
--hash=sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831 \
--hash=sha256:fb125d860738a09d363a88daa0f59c4533529a90e564785e20fe875b200b6dbd
pillow==12.0.0 \
--hash=sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643 \
--hash=sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e \
--hash=sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e \
--hash=sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc \
--hash=sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642 \
--hash=sha256:1979f4566bb96c1e50a62d9831e2ea2d1211761e5662afc545fa766f996632f6 \
--hash=sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1 \
--hash=sha256:1b1b133e6e16105f524a8dec491e0586d072948ce15c9b914e41cdadd209052b \
--hash=sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399 \
--hash=sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba \
--hash=sha256:266cd5f2b63ff316d5a1bba46268e603c9caf5606d44f38c2873c380950576ad \
--hash=sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47 \
--hash=sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739 \
--hash=sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b \
--hash=sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f \
--hash=sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10 \
--hash=sha256:3830c769decf88f1289680a59d4f4c46c72573446352e2befec9a8512104fa52 \
--hash=sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d \
--hash=sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b \
--hash=sha256:3e42edad50b6909089750e65c91aa09aaf1e0a71310d383f11321b27c224ed8a \
--hash=sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9 \
--hash=sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d \
--hash=sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098 \
--hash=sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905 \
--hash=sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b \
--hash=sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3 \
--hash=sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371 \
--hash=sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953 \
--hash=sha256:58eea5ebe51504057dd95c5b77d21700b77615ab0243d8152793dc00eb4faf01 \
--hash=sha256:5d5c411a8eaa2299322b647cd932586b1427367fd3184ffbb8f7a219ea2041ca \
--hash=sha256:6846bd2d116ff42cba6b646edf5bf61d37e5cbd256425fa089fee4ff5c07a99e \
--hash=sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7 \
--hash=sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27 \
--hash=sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082 \
--hash=sha256:7438839e9e053ef79f7112c881cef684013855016f928b168b81ed5835f3e75e \
--hash=sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d \
--hash=sha256:792a2c0be4dcc18af9d4a2dfd8a11a17d5e25274a1062b0ec1c2d79c76f3e7f8 \
--hash=sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a \
--hash=sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad \
--hash=sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3 \
--hash=sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a \
--hash=sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d \
--hash=sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353 \
--hash=sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee \
--hash=sha256:8dc232e39d409036af549c86f24aed8273a40ffa459981146829a324e0848b4b \
--hash=sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b \
--hash=sha256:905b0365b210c73afb0ebe9101a32572152dfd1c144c7e28968a331b9217b94a \
--hash=sha256:99353a06902c2e43b43e8ff74ee65a7d90307d82370604746738a1e0661ccca7 \
--hash=sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef \
--hash=sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a \
--hash=sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a \
--hash=sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257 \
--hash=sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07 \
--hash=sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4 \
--hash=sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c \
--hash=sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c \
--hash=sha256:afbefa430092f71a9593a99ab6a4e7538bc9eabbf7bf94f91510d3503943edc4 \
--hash=sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe \
--hash=sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8 \
--hash=sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5 \
--hash=sha256:b2e4b27a6e15b04832fe9bf292b94b5ca156016bbc1ea9c2c20098a0320d6cf6 \
--hash=sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e \
--hash=sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8 \
--hash=sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e \
--hash=sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275 \
--hash=sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3 \
--hash=sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76 \
--hash=sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227 \
--hash=sha256:beeae3f27f62308f1ddbcfb0690bf44b10732f2ef43758f169d5e9303165d3f9 \
--hash=sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5 \
--hash=sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79 \
--hash=sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca \
--hash=sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa \
--hash=sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b \
--hash=sha256:c98fa880d695de164b4135a52fd2e9cd7b7c90a9d8ac5e9e443a24a95ef9248e \
--hash=sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197 \
--hash=sha256:d034140032870024e6b9892c692fe2968493790dd57208b2c37e3fb35f6df3ab \
--hash=sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79 \
--hash=sha256:d4827615da15cd59784ce39d3388275ec093ae3ee8d7f0c089b76fa87af756c2 \
--hash=sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363 \
--hash=sha256:d52610d51e265a51518692045e372a4c363056130d922a7351429ac9f27e70b0 \
--hash=sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e \
--hash=sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782 \
--hash=sha256:d7e091d464ac59d2c7ad8e7e08105eaf9dafbc3883fd7265ffccc2baad6ac925 \
--hash=sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0 \
--hash=sha256:e5d8efac84c9afcb40914ab49ba063d94f5dbdf5066db4482c66a992f47a3a3b \
--hash=sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced \
--hash=sha256:f13711b1a5ba512d647a0e4ba79280d3a9a045aaf7e0cc6fbe96b91d4cdf6b0c \
--hash=sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344 \
--hash=sha256:fa3ed2a29a9e9d2d488b4da81dcb54720ac3104a20bf0bd273f1e4648aff5af9 \
--hash=sha256:fb3096c30df99fd01c7bf8e544f392103d0795b9f98ba71a8054bcbf56b255f1
# via
# -r .github/scripts/requirements_dev.in
# pdf2image
# weasyprint
platformdirs==4.5.1 \
--hash=sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda \
--hash=sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31
platformdirs==4.5.0 \
--hash=sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312 \
--hash=sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3
# via virtualenv
pre-commit==4.5.1 \
--hash=sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77 \
--hash=sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61
pre-commit==4.3.0 \
--hash=sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8 \
--hash=sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16
# via -r .github/scripts/requirements_dev.in
pycparser==3.0 \
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
--hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992
pycparser==2.23 \
--hash=sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2 \
--hash=sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934
# via cffi
pydyf==0.12.1 \
--hash=sha256:ea25b4e1fe7911195cb57067560daaa266639184e8335365cc3ee5214e7eaadc \
--hash=sha256:fbd7e759541ac725c29c506612003de393249b94310ea78ae44cb1d04b220095
pydyf==0.11.0 \
--hash=sha256:0aaf9e2ebbe786ec7a78ec3fbffa4cdcecde53fd6f563221d53c6bc1328848a3 \
--hash=sha256:394dddf619cca9d0c55715e3c55ea121a9bf9cbc780cdc1201a2427917b86b64
# via weasyprint
pyphen==0.17.2 \
--hash=sha256:3a07fb017cb2341e1d9ff31b8634efb1ae4dc4b130468c7c39dd3d32e7c3affd \
@@ -452,9 +442,9 @@ pyyaml==6.0.3 \
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
# via pre-commit
tinycss2==1.5.1 \
--hash=sha256:3415ba0f5839c062696996998176c4a3751d18b7edaaeeb658c9ce21ec150661 \
--hash=sha256:d339d2b616ba90ccce58da8495a78f46e55d4d25f9fd71dfd526f07e7d53f957
tinycss2==1.4.0 \
--hash=sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7 \
--hash=sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289
# via
# cssselect2
# weasyprint
@@ -462,17 +452,17 @@ tinyhtml5==2.0.0 \
--hash=sha256:086f998833da24c300c414d9fe81d9b368fd04cb9d2596a008421cbc705fcfcc \
--hash=sha256:13683277c5b176d070f82d099d977194b7a1e26815b016114f581a74bbfbf47e
# via weasyprint
unoserver==3.6 \
--hash=sha256:25c360fa194396a89cb79b4edd2735f8e4f0fd8531e59db3952114585bd7df05 \
--hash=sha256:e446bcb3638c51880f002aaeecab1cf74dfa9df81035f027f7ff2e081b6d7015
unoserver==3.4 \
--hash=sha256:3dcf2204013def1d1ddd3671f38b11346bdf349fef9728277462666a8a634419 \
--hash=sha256:64c24d33d4f65d680a2d9f676518cb28e7fd6c1f9d9a745c33e4a4cb59afdfcd
# via -r .github/scripts/requirements_dev.in
virtualenv==20.36.1 \
--hash=sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f \
--hash=sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba
virtualenv==20.35.4 \
--hash=sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c \
--hash=sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b
# via pre-commit
weasyprint==68.0 \
--hash=sha256:447f40898b747cb44ac31a5d493d512e7441fd56e13f63744c099383bbf9cda9 \
--hash=sha256:c2cb40c71b50837c5971f00171c9e4078e8c9912dd7c217f3e90e068f11e8aa1
weasyprint==66.0 \
--hash=sha256:82b0783b726fcd318e2c977dcdddca76515b30044bc7a830cc4fbe717582a6d0 \
--hash=sha256:da71dc87dc129ac9cffdc65e5477e90365ab9dbae45c744014ec1d06303dde40
# via -r .github/scripts/requirements_dev.in
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
@@ -481,27 +471,86 @@ webencodings==0.5.1 \
# cssselect2
# tinycss2
# tinyhtml5
zopfli==0.4.0 \
--hash=sha256:03181d48e719fcb6cf8340189c61e8f9883d8bbbdf76bf5212a74457f7d083c1 \
--hash=sha256:18b5f1570f64d4988482e4466f10ef5f2a30f687c19ad62a64560f2152dc89eb \
--hash=sha256:25e4863b8dc30e5d5309f87c106b0b7d3da4ed0e340b8a52b36d4471e797589f \
--hash=sha256:7d66337be6d5613dec55213e9ac28f378c41e2cc04fbad4a10748e4df774ca85 \
--hash=sha256:9097e8e1dfdb7f5aea5464e469946857e80502b6d29ba1b232450916bd4a74d1 \
--hash=sha256:a8ee992b2549e090cd3f0178bf606dd41a29e0613a04cdf5054224662c72dce6 \
--hash=sha256:b72a010d205d00b2855acc2302772067362f9ab5a012e3550662aec60d28e6b3 \
--hash=sha256:b8bdb41fbfdc4738b7bdc09ed7c1e951579fae192391a5e694d59bb186cdbec7 \
--hash=sha256:c3ba02a9a6ca90481d2b2f68bab038b310d63a1e3b5ae305e95a6599787ed941 \
--hash=sha256:d1b98ad47c434ef213444a03ef2f826eeec100144d64f6a57504b9893d3931ce \
--hash=sha256:f67d04280065e24cb9a4174cb6b3d1f763687f8cb2963aa135ad8f57c6995f5a \
--hash=sha256:f94e4dd7d76b4fe9f5d9229372be20d7f786164eea5152d1af1c34298c3d5975
zopfli==0.2.3.post1 \
--hash=sha256:0aa5f90d6298bda02a95bc8dc8c3c19004d5a4e44bda00b67ca7431d857b4b54 \
--hash=sha256:0cc20b02a9531559945324c38302fd4ba763311632d0ec8a1a0aa9c10ea363e6 \
--hash=sha256:1d8cc06605519e82b16df090e17cb3990d1158861b2872c3117f1168777b81e4 \
--hash=sha256:1f990634fd5c5c8ced8edddd8bd45fab565123b4194d6841e01811292650acae \
--hash=sha256:2345e713260a350bea0b01a816a469ea356bc2d63d009a0d777691ecbbcf7493 \
--hash=sha256:2768c877f76c8a0e7519b1c86c93757f3c01492ddde55751e9988afb7eff64e1 \
--hash=sha256:29ea74e72ffa6e291b8c6f2504ce6c146b4fe990c724c1450eb8e4c27fd31431 \
--hash=sha256:34a99592f3d9eb6f737616b5bd74b48a589fdb3cb59a01a50d636ea81d6af272 \
--hash=sha256:3654bfc927bc478b1c3f3ff5056ed7b20a1a37fa108ca503256d0a699c03bbb1 \
--hash=sha256:3657e416ffb8f31d9d3424af12122bb251befae109f2e271d87d825c92fc5b7b \
--hash=sha256:37d011e92f7b9622742c905fdbed9920a1d0361df84142807ea2a528419dea7f \
--hash=sha256:3827170de28faf144992d3d4dcf8f3998fe3c8a6a6f4a08f1d42c2ec6119d2bb \
--hash=sha256:39e576f93576c5c223b41d9c780bbb91fd6db4babf3223d2a4fe7bf568e2b5a8 \
--hash=sha256:3a89277ed5f8c0fb2d0b46d669aa0633123aa7381f1f6118c12f15e0fb48f8ca \
--hash=sha256:3c163911f8bad94b3e1db0a572e7c28ba681a0c91d0002ea1e4fa9264c21ef17 \
--hash=sha256:3f0197b6aa6eb3086ae9e66d6dd86c4d502b6c68b0ec490496348ae8c05ecaef \
--hash=sha256:48dba9251060289101343110ab47c0756f66f809bb4d1ddbb6d5c7e7752115c5 \
--hash=sha256:4915a41375bdee4db749ecd07d985a0486eb688a6619f713b7bf6fbfd145e960 \
--hash=sha256:4c1226a7e2c7105ac31503a9bb97454743f55d88164d6d46bc138051b77f609b \
--hash=sha256:4e50ffac74842c1c1018b9b73875a0d0a877c066ab06bf7cccbaa84af97e754f \
--hash=sha256:518f1f4ed35dd69ce06b552f84e6d081f07c552b4c661c5312d950a0b764a58a \
--hash=sha256:5aad740b4d4fcbaaae4887823925166ffd062db3b248b3f432198fc287381d1a \
--hash=sha256:5f272186e03ad55e7af09ab78055535c201b1a0bcc2944edb1768298d9c483a4 \
--hash=sha256:5fcfc0dc2761e4fcc15ad5d273b4d58c2e8e059d3214a7390d4d3c8e2aee644e \
--hash=sha256:60db20f06c3d4c5934b16cfa62a2cc5c3f0686bffe0071ed7804d3c31ab1a04e \
--hash=sha256:615a8ac9dda265e9cc38b2a76c3142e4a9f30fea4a79c85f670850783bc6feb4 \
--hash=sha256:6482db9876c68faac2d20a96b566ffbf65ddaadd97b222e4e73641f4f8722fc4 \
--hash=sha256:6617fb10f9e4393b331941861d73afb119cd847e88e4974bdbe8068ceef3f73f \
--hash=sha256:676919fba7311125244eb0c4393679ac5fe856e5864a15d122bd815205369fa0 \
--hash=sha256:6c2d2bc8129707e34c51f9352c4636ca313b52350bbb7e04637c46c1818a2a70 \
--hash=sha256:71390dbd3fbf6ebea9a5d85ffed8c26ee1453ee09248e9b88486e30e0397b775 \
--hash=sha256:716cdbfc57bfd3d3e31a58e6246e8190e6849b7dbb7c4ce39ef8bbf0edb8f6d5 \
--hash=sha256:75a26a2307b10745a83b660c404416e984ee6fca515ec7f0765f69af3ce08072 \
--hash=sha256:7be5cc6732eb7b4df17305d8a7b293223f934a31783a874a01164703bc1be6cd \
--hash=sha256:7cce242b5df12b2b172489daf19c32e5577dd2fac659eb4b17f6a6efb446fd5c \
--hash=sha256:81c341d9bb87a6dbbb0d45d6e272aca80c7c97b4b210f9b6e233bf8b87242f29 \
--hash=sha256:89899641d4de97dbad8e0cde690040d078b6aea04066dacaab98e0b5a23573f2 \
--hash=sha256:8d5ab297d660b75c159190ce6d73035502310e40fd35170aed7d1a1aea7ddd65 \
--hash=sha256:8fbe5bcf10d01aab3513550f284c09fef32f342b36f56bfae2120a9c4d12c130 \
--hash=sha256:91a2327a4d7e77471fa4fbb26991c6de4a738c6fc6a33e09bb25f56a870a4b7b \
--hash=sha256:95a260cafd56b8fffa679918937401c80bb38e1681c448b988022e4c3610965d \
--hash=sha256:96484dc0f48be1c5d7ae9f38ed1ce41e3675fd506b27c11a6607f14b49101e99 \
--hash=sha256:9a6aec38a989bad7ddd1ef53f1265699e49e294d08231b5313d61293f3cd6237 \
--hash=sha256:9ba214f4f45bec195ee8559651154d3ac2932470b9d91c5715fc29c013349f8c \
--hash=sha256:9f4a7ec2770e6af05f5a02733fd3900f30a9cd58e5d6d3727e14c5bcd6e7d587 \
--hash=sha256:a1cf720896d2ce998bc8e051d4b4ce0d8bec007aab6243102e8e1d22a0b2fb3f \
--hash=sha256:a241a68581d34d67b40c425cce3d1fd211c092f99d9250947824ccba9f491949 \
--hash=sha256:a53b18797cdef27e019db595d66c4b077325afe2fd62145953275f53d84ce40c \
--hash=sha256:a82fc2dbebe6eb908b9c665e71496f8525c1bc4d2e3a7a7722ef2b128b6227c8 \
--hash=sha256:a86eb88e06bd87e1fff31dac878965c26b0c26db59ddcf78bb0379a954b120de \
--hash=sha256:aa588b21044f8a74e423d8c8a4c7fc9988501878aacced793467010039c50734 \
--hash=sha256:b05296e8bc88c92e2b21e0a9bae4740c1551ee613c1d93a51fd28a7a0b2b6fbb \
--hash=sha256:b0ec13f352ea5ae0fc91f98a48540512eed0767d0ec4f7f3cb92d92797983d18 \
--hash=sha256:b3df42f52502438ee973042cc551877d24619fa1cd38ef7b7e9ac74200daca8b \
--hash=sha256:b78008a69300d929ca2efeffec951b64a312e9a811e265ea4a907ab546d79fa6 \
--hash=sha256:b9026a21b6d41eb0e2e63f5bc1242c3fcc43ecb770963cda99a4307863dac12e \
--hash=sha256:bbe429fc50686bb2a2608a30843e36fbaa123462a5284f136c7d9e0145220bfd \
--hash=sha256:bfa1eb759e07d8b7aa7a310a2bc535e127ee70addf90dc8d4b946b593c3e51a8 \
--hash=sha256:c1e0ed5d84ffa2d677cc9582fc01e61dab2e7ef8b8996e055f0a76167b1b94df \
--hash=sha256:c4278d1873ce6e803e5d4f8d702fd3026bd67fca744aa98881324d1157ddf748 \
--hash=sha256:cac2b37ab21c2b36a10b685b1893ebd6b0f83ae26004838ac817680881576567 \
--hash=sha256:cbe6df25807227519debd1a57ab236f5f6bad441500e85b13903e51f93a43214 \
--hash=sha256:cd2c002f160502608dcc822ed2441a0f4509c52e86fcfd1a09e937278ed1ca14 \
--hash=sha256:e0137dd64a493ba6a4be37405cfd6febe650a98cc1e9dca8f6b8c63b1db11b41 \
--hash=sha256:e63d558847166543c2c9789e6f985400a520b7eacc4b99181668b2c3aeadd352 \
--hash=sha256:eb45a34f23da4f8bc712b6376ca5396914b0b7c09adbb001dad964eb7f3132f8 \
--hash=sha256:ecb7572df5372abce8073df078207d9d1749f20b8b136089916a4a0868d56051 \
--hash=sha256:f12000a6accdd4bf0a3fa6eaa1b1c7a7bc80af0a2edf3f89d770d3dcce1d0e22 \
--hash=sha256:f7d69c1a7168ad0e9cb864e8663acb232986a0c9c9cb9801f56bf6214f53a54d \
--hash=sha256:f815fcc2b2a457977724bad97fb4854022980f51ce7b136925e336b530545ae1 \
--hash=sha256:fc39f5c27f962ec8660d8d20c24762431131b5d8c672b44b0a54cf2b5bcde9b9
# via fonttools
# The following packages are considered to be unsafe in a requirements file:
pip==26.0 \
--hash=sha256:3ce220a0a17915972fbf1ab451baae1521c4539e778b28127efa79b974aff0fa \
--hash=sha256:98436feffb9e31bc9339cf369fd55d3331b1580b6a6f1173bacacddcf9c34754
pip==25.3 \
--hash=sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343 \
--hash=sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd
# via -r .github/scripts/requirements_dev.in
setuptools==80.10.2 \
--hash=sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70 \
--hash=sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173
setuptools==80.9.0 \
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
# via -r .github/scripts/requirements_dev.in
+18 -18
View File
@@ -12,25 +12,25 @@ distlib==0.4.0 \
--hash=sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 \
--hash=sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d
# via virtualenv
filelock==3.20.3 \
--hash=sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1 \
--hash=sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1
filelock==3.20.0 \
--hash=sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2 \
--hash=sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4
# via virtualenv
identify==2.6.16 \
--hash=sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0 \
--hash=sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980
identify==2.6.15 \
--hash=sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757 \
--hash=sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf
# via pre-commit
nodeenv==1.10.0 \
--hash=sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827 \
--hash=sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb
nodeenv==1.9.1 \
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
--hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
# via pre-commit
platformdirs==4.5.1 \
--hash=sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda \
--hash=sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31
platformdirs==4.5.0 \
--hash=sha256:70ddccdd7c99fc5942e9fc25636a8b34d04c24b335100223152c2803e4063312 \
--hash=sha256:e578a81bb873cbb89a41fcc904c7ef523cc18284b7e3b3ccf06aca1403b7ebd3
# via virtualenv
pre-commit==4.5.1 \
--hash=sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77 \
--hash=sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61
pre-commit==4.5.0 \
--hash=sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1 \
--hash=sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b
# via -r .github/scripts/requirements_pre_commit.in
pyyaml==6.0.3 \
--hash=sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c \
@@ -107,7 +107,7 @@ pyyaml==6.0.3 \
--hash=sha256:fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926 \
--hash=sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0
# via pre-commit
virtualenv==20.36.1 \
--hash=sha256:575a8d6b124ef88f6f51d56d656132389f961062a9177016a50e4f507bbcc19f \
--hash=sha256:8befb5c81842c641f8ee658481e42641c68b5eab3521d8e092d18320902466ba
virtualenv==20.35.4 \
--hash=sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c \
--hash=sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b
# via pre-commit
+3 -3
View File
@@ -8,7 +8,7 @@ tomli-w==1.2.0 \
--hash=sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90 \
--hash=sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021
# via -r .github/scripts/requirements_sync_readme.in
tomlkit==0.14.0 \
--hash=sha256:592064ed85b40fa213469f81ac584f67a4f2992509a7c3ea2d632208623a3680 \
--hash=sha256:cf00efca415dbd57575befb1f6634c4f42d2d87dbba376128adb42c121b87064
tomlkit==0.13.3 \
--hash=sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1 \
--hash=sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0
# via -r .github/scripts/requirements_sync_readme.in
+4 -4
View File
@@ -116,7 +116,7 @@ jobs:
egress-policy: audit
- name: Checkout main repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: ${{ github.repository }}
ref: main
@@ -172,7 +172,7 @@ jobs:
return newComment.id;
- name: Checkout PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: ${{ needs.check-pr.outputs.pr_repository }}
ref: ${{ needs.check-pr.outputs.pr_ref }}
@@ -189,7 +189,7 @@ jobs:
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
@@ -362,7 +362,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
@@ -45,7 +45,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
@@ -133,7 +133,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
@@ -145,19 +145,19 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Checkout PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: refs/pull/${{ needs.check-comment.outputs.pr_number }}/merge
token: ${{ steps.setup-bot.outputs.token }}
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -179,7 +179,7 @@ jobs:
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
@@ -375,7 +375,7 @@ jobs:
egress-policy: audit
- name: Check out the repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
id: setup-bot
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
egress-policy: audit
- name: Checkout PR
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
if: github.actor != 'dependabot[bot]'
+2 -2
View File
@@ -23,7 +23,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
@@ -87,7 +87,7 @@ jobs:
- name: AI PR Title Analysis
if: steps.actor.outputs.is_repo_dev == 'true'
id: ai-title-analysis
uses: actions/ai-inference@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5
uses: actions/ai-inference@334892bb203895caaed82ec52d23c1ed9385151e # v2.0.4
with:
model: openai/gpt-4o
system-prompt-file: ".github/config/system-prompt.txt"
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
id: setup-bot
+23 -23
View File
@@ -36,7 +36,7 @@ jobs:
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@@ -60,16 +60,16 @@ jobs:
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK ${{ matrix.jdk-version }}
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: ${{ matrix.jdk-version }}
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -101,7 +101,7 @@ jobs:
- name: Upload Test Reports
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: test-reports-jdk-${{ matrix.jdk-version }}-spring-security-${{ matrix.spring-security }}
path: |
@@ -135,16 +135,16 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -157,7 +157,7 @@ jobs:
DISABLE_ADDITIONAL_FEATURES: true
- name: Upload OpenAPI Documentation
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: openapi-docs
path: ./SwaggerDoc.json
@@ -172,9 +172,9 @@ jobs:
with:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: "22"
cache: "npm"
@@ -190,7 +190,7 @@ jobs:
- name: Run frontend tests
run: cd frontend && npm run test -- --run
- name: Upload frontend build artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: frontend-build
path: frontend/dist/
@@ -207,16 +207,16 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -229,7 +229,7 @@ jobs:
- name: FAILED - check the licenses for compatibility
if: failure()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: dependencies-without-allowed-license.json
path: build/reports/dependency-license/dependencies-without-allowed-license.json
@@ -261,16 +261,16 @@ jobs:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -325,7 +325,7 @@ jobs:
egress-policy: audit
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Free disk space on runner
run: |
@@ -335,13 +335,13 @@ jobs:
echo "Disk space after cleanup:" && df -h
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -376,7 +376,7 @@ jobs:
- name: Upload Reports
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: reports-docker-${{ matrix.artifact-suffix }}
path: |
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
egress-policy: audit
- name: Checkout main branch first
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
id: setup-bot
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
egress-policy: audit
- name: "Checkout Repository"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: "Dependency Review"
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
with:
+2 -2
View File
@@ -23,7 +23,7 @@ jobs:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
@@ -85,7 +85,7 @@ jobs:
fi
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
@@ -30,7 +30,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@@ -54,7 +54,7 @@ jobs:
egress-policy: audit
- name: Checkout PR head (default)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
@@ -69,7 +69,7 @@ jobs:
- name: Checkout BASE branch (safe script)
if: github.event_name == 'pull_request'
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.base.sha }}
path: base
@@ -77,7 +77,7 @@ jobs:
persist-credentials: false
- name: Set up Node.js
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
with:
node-version: "22"
cache: "npm"
@@ -273,7 +273,7 @@ jobs:
- name: Create Pull Request (Push only)
id: cpr
if: github.event_name == 'push' && env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
with:
token: ${{ steps.setup-bot.outputs.token }}
commit-message: "Update Frontend 3rd Party Licenses"
@@ -317,7 +317,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
@@ -331,13 +331,13 @@ jobs:
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -364,7 +364,7 @@ jobs:
- name: Upload artifact on license issues
if: env.LICENSE_WARNINGS_EXIST == 'true'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: backend-dependencies-without-allowed-license.json
path: build/reports/dependency-license/dependencies-without-allowed-license.json
@@ -490,7 +490,7 @@ jobs:
- name: Create Pull Request (push only)
if: github.event_name == 'push' && env.CHANGES_DETECTED == 'true'
id: cpr
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
with:
token: ${{ steps.setup-bot.outputs.token }}
commit-message: "Update Backend 3rd Party Licenses"
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
egress-policy: audit
- name: Check out the repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Run Labeler
uses: crazy-max/ghaction-github-labeler@24d110aa46a59976b8a7f35518cb7f14f434c916 # v5.3.0
+16 -16
View File
@@ -42,16 +42,16 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -115,22 +115,22 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
- name: Setup Node.js
if: matrix.variant.build_frontend == true
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
@@ -154,7 +154,7 @@ jobs:
cp app/core/build/libs/stirling-pdf-${{ needs.determine-matrix.outputs.version }}.jar ./jar-dist/Stirling-PDF${{ matrix.variant.file_suffix }}.jar
- name: Upload JAR artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: jar${{ matrix.variant.file_suffix }}
path: ./jar-dist/*.jar
@@ -176,7 +176,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04'
@@ -185,26 +185,26 @@ jobs:
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libjavascriptcoregtk-4.0-dev libsoup2.4-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Setup Rust
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ (matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -291,7 +291,7 @@ jobs:
- name: Setup DigiCert KeyLocker
id: digicert-setup
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY != '' && (github.event_name == 'release' || github.ref == 'refs/heads/V2-master') }}
uses: digicert/ssm-code-signing@af7f4b07694120e514fe5b19f0598af3c20256e3 # v1.2.0
uses: digicert/ssm-code-signing@v1.1.0
env:
SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_CLIENT_CERT_FILE_B64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }}
@@ -399,7 +399,7 @@ jobs:
echo "Certificate imported successfully."
- name: Build Tauri app
uses: tauri-apps/tauri-action@51a9f1156b33df106d827c3a78f8f894946c5faa # v0.5.25
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -533,7 +533,7 @@ jobs:
fi
- name: Upload build artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: Stirling-PDF-${{ matrix.name }}
path: ./dist/*
+5 -13
View File
@@ -26,10 +26,9 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
fetch-depth: 0
persist-credentials: false
- name: Setup GitHub App Bot
id: setup-bot
@@ -49,24 +48,17 @@ jobs:
run: |
pip install --require-hashes --only-binary=:all: -r ./.github/scripts/requirements_pre_commit.txt
- name: Run Pre-Commit
run: |
pre-commit run ruff --all-files -c .pre-commit-config.yaml
pre-commit run ruff-format --all-files -c .pre-commit-config.yaml
pre-commit run codespell --all-files -c .pre-commit-config.yaml
pre-commit run gitleaks --all-files -c .pre-commit-config.yaml
pre-commit run end-of-file-fixer --all-files -c .pre-commit-config.yaml
pre-commit run trailing-whitespace --all-files -c .pre-commit-config.yaml
- run: pre-commit run --all-files -c .pre-commit-config.yaml
continue-on-error: true
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: 21
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -84,7 +76,7 @@ jobs:
- name: Create Pull Request
if: env.CHANGES_DETECTED == 'true'
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
with:
token: ${{ steps.setup-bot.outputs.token }}
commit-message: ":file_folder: pre-commit"
+5 -5
View File
@@ -37,16 +37,16 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -75,13 +75,13 @@ jobs:
cosign-release: "v2.4.1"
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
- name: Login to GitHub Container Registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
+2 -2
View File
@@ -40,7 +40,7 @@ jobs:
egress-policy: audit
- name: "Checkout code"
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
@@ -67,7 +67,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: SARIF file
path: results.sarif
+3 -3
View File
@@ -31,16 +31,16 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
+3 -9
View File
@@ -39,9 +39,7 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup GitHub App Bot
id: setup-bot
@@ -57,16 +55,12 @@ jobs:
cache: "pip" # caching pip dependencies
- name: Install Python dependencies
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt -r ./.github/scripts/requirements_pre_commit.txt
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
- name: Sync translation TOML files
run: |
python .github/scripts/check_language_toml.py --reference-file "frontend/public/locales/en-GB/translation.toml" --branch main
- name: pre-commit run
run: |
pre-commit run toml-sort-fix --all-files
- name: Commit translation files
run: |
git add frontend/public/locales/*/translation.toml
@@ -83,7 +77,7 @@ jobs:
- name: Create Pull Request
if: always()
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
with:
token: ${{ steps.setup-bot.outputs.token }}
commit-message: Update files
+8 -113
View File
@@ -25,7 +25,6 @@ on:
permissions:
contents: read
pull-requests: write
jobs:
determine-matrix:
@@ -34,11 +33,6 @@ jobs:
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Determine build matrix
id: set-matrix
run: |
@@ -78,7 +72,7 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Install dependencies (ubuntu only)
if: matrix.platform == 'ubuntu-22.04'
@@ -87,26 +81,26 @@ jobs:
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libjavascriptcoregtk-4.0-dev libsoup2.4-dev libjavascriptcoregtk-4.1-dev libsoup-3.0-dev
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
uses: actions/setup-node@v4
with:
node-version: 22
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Setup Rust
uses: dtolnay/rust-toolchain@4be9e76fd7c4901c61fb841f559994984270fce7 # stable
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ (matrix.platform == 'macos-15' || matrix.platform == 'macos-15-intel') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -194,7 +188,7 @@ jobs:
- name: Setup DigiCert KeyLocker
id: digicert-setup
if: ${{ matrix.platform == 'windows-latest' && env.SM_API_KEY != '' && github.ref == 'refs/heads/main' }}
uses: digicert/ssm-code-signing@af7f4b07694120e514fe5b19f0598af3c20256e3 # v1.2.0
uses: digicert/ssm-code-signing@v1.1.0
env:
SM_API_KEY: ${{ secrets.SM_API_KEY }}
SM_CLIENT_CERT_FILE_B64: ${{ secrets.SM_CLIENT_CERT_FILE_B64 }}
@@ -313,7 +307,7 @@ jobs:
ls -la /usr/bin/hd* || echo "No hd* tools found"
- name: Build Tauri app
uses: tauri-apps/tauri-action@51a9f1156b33df106d827c3a78f8f894946c5faa # v0.5.25
uses: tauri-apps/tauri-action@v0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
@@ -587,7 +581,7 @@ jobs:
}
- name: Upload artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: Stirling-PDF-${{ matrix.name }}
path: ./dist/*
@@ -640,110 +634,11 @@ jobs:
fi
done
pr-comment:
needs: build
runs-on: ubuntu-latest
if: github.event_name == 'pull_request' && needs.build.result == 'success'
permissions:
pull-requests: write
steps:
- name: Harden the runner
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Post/Update PR Comment with Download Links
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const prNumber = context.issue.number;
const runId = context.runId;
// Fetch artifacts for this workflow run
const { data: artifactsList } = await github.rest.actions.listWorkflowRunArtifacts({
owner,
repo,
run_id: runId
});
// Map of expected artifact names to display info
const artifactMap = {
'Stirling-PDF-windows-x86_64': { icon: '🪟', platform: 'Windows x64', files: '.exe, .msi' },
'Stirling-PDF-macos-aarch64': { icon: '🍎', platform: 'macOS ARM64', files: '.dmg' },
'Stirling-PDF-macos-x86_64': { icon: '🍎', platform: 'macOS Intel', files: '.dmg' },
'Stirling-PDF-linux-x86_64': { icon: '🐧', platform: 'Linux x64', files: '.deb, .AppImage' }
};
let commentBody = `## 📦 Tauri Desktop Builds Ready!\n\n`;
commentBody += `The desktop applications have been built and are ready for testing.\n\n`;
commentBody += `### Download Artifacts:\n\n`;
// Add links for each found artifact
let foundArtifacts = 0;
for (const artifact of artifactsList.artifacts) {
const info = artifactMap[artifact.name];
if (info) {
foundArtifacts++;
// GitHub doesn't provide direct download URLs via API, but we can link to the artifact on the Actions page
const artifactUrl = `https://github.com/${owner}/${repo}/actions/runs/${runId}/artifacts/${artifact.id}`;
commentBody += `${info.icon} **${info.platform}**: [Download ${artifact.name}](${artifactUrl}) `;
commentBody += `(${info.files}) - ${(artifact.size_in_bytes / 1024 / 1024).toFixed(1)} MB\n`;
}
}
if (foundArtifacts === 0) {
commentBody += `⚠️ **Warning**: No artifacts found in workflow run.\n`;
commentBody += `[View workflow run](https://github.com/${owner}/${repo}/actions/runs/${runId})\n`;
}
commentBody += `\n---\n`;
commentBody += `_Built from commit ${context.sha.substring(0, 7)}_\n`;
commentBody += `_Artifacts expire in 7 days_`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber
});
const botComment = comments.find(comment =>
comment.user.type === 'Bot' &&
comment.body.includes('📦 Tauri Desktop Builds Ready!')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner,
repo,
comment_id: botComment.id,
body: commentBody
});
console.log('Updated existing comment');
} else {
// Create new comment
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: commentBody
});
console.log('Created new comment');
}
report:
needs: build
runs-on: ubuntu-latest
if: always()
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- name: Report build results
run: |
if [ "${{ needs.build.result }}" = "success" ]; then
+7 -12
View File
@@ -30,16 +30,16 @@ jobs:
egress-policy: audit
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up JDK 21
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
java-version: "21"
distribution: "temurin"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@f29f5a9d7b09a7c6b29859002d29d24e1674c884 # v5.0.1
uses: gradle/actions/setup-gradle@4d9f0ba0025fe599b4ebab900eb7f3a1d93ef4c2 # v5.0.0
with:
gradle-version: 8.14
@@ -61,7 +61,7 @@ jobs:
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
- name: Login to Docker Hub
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_API }}
@@ -128,12 +128,7 @@ jobs:
outputs:
frontend: ${{ steps.changes.outputs.frontend }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Check for file changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
@@ -152,10 +147,10 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Node
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
cache: "npm"
cache-dependency-path: frontend/package-lock.json
+1 -1
View File
@@ -149,7 +149,6 @@ app/proprietary/build
common/build
proprietary/build
stirling-pdf/build
frontend/src-tauri/provisioner/target
# Byte-compiled / optimized / DLL files
__pycache__/
@@ -244,3 +243,4 @@ docs/type3/signatures/
# Type3 sample PDFs (development only)
**/type3/samples/
+3 -9
View File
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.14.14
rev: v0.14.8
hooks:
- id: ruff
args:
@@ -16,11 +16,11 @@ repos:
hooks:
- id: codespell
args:
- --ignore-words-list=thirdParty,tabEl,tabEls,Sie,ist
- --ignore-words-list=thirdParty,tabEl,tabEls
- --skip="./.*,*.csv,*.json,*.ambr"
- --quiet-level=2
files: \.(html|css|js|py|md)$
exclude: (.vscode|.devcontainer|app/core/src/main/resources|app/proprietary/src/main/resources|frontend/public/vendor|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
exclude: (.vscode|.devcontainer|app/core/src/main/resources|app/proprietary/src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.0
hooks:
@@ -34,12 +34,6 @@ repos:
- id: trailing-whitespace
files: ^.*(\.js|\.java|\.py|\.yml)$
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$)
- repo: https://github.com/pappasam/toml-sort
rev: v0.24.3
hooks:
- id: toml-sort-fix
files: frontend/public/locales/.*\.toml$
args: ['--in-place', '--all', '--ignore-case']
# - repo: https://github.com/thibaudcolas/pre-commit-stylelint
# rev: v16.21.1
# hooks:
+1 -1
View File
@@ -13,7 +13,7 @@
"vscjava.vscode-spring-boot-dashboard", // Spring Boot dashboard for managing and visualizing Spring Boot applications
"EditorConfig.EditorConfig", // EditorConfig support for maintaining consistent coding styles
"ms-azuretools.vscode-docker", // Docker extension for Visual Studio Code
"GitHub.copilot-chat", // GitHub Copilot AI pair programmer for Visual Studio Code
"GitHub.copilot", // GitHub Copilot AI pair programmer for Visual Studio Code
"GitHub.vscode-pull-request-github", // GitHub Pull Requests extension for Visual Studio Code
"charliermarsh.ruff", // Ruff code formatter for Python to follow the Ruff Style Guide
"yzhang.markdown-all-in-one", // Markdown All-in-One extension for enhanced Markdown editing
+3 -115
View File
@@ -30,91 +30,6 @@ Set `DOCKER_ENABLE_SECURITY=true` environment variable to enable security featur
- **Web Server**: `npm run build` then serve dist/ folder
- **Development**: `npm run tauri-dev` for desktop dev mode
#### Import Paths - CRITICAL
**ALWAYS use `@app/*` for imports.** Do not use `@core/*` or `@proprietary/*` unless explicitly wrapping/extending a lower layer implementation.
```typescript
// ✅ CORRECT - Use @app/* for all imports
import { AppLayout } from "@app/components/AppLayout";
import { useFileContext } from "@app/contexts/FileContext";
import { FileContext } from "@app/contexts/FileContext";
// ❌ WRONG - Do not use @core/* or @proprietary/* in normal code
import { AppLayout } from "@core/components/AppLayout";
import { useFileContext } from "@proprietary/contexts/FileContext";
```
**Only use explicit aliases when:**
- Building layer-specific override that wraps a lower layer's component
- Example: `import { AppProviders as CoreAppProviders } from "@core/components/AppProviders"` when creating proprietary/AppProviders.tsx that extends the core version
The `@app/*` alias automatically resolves to the correct layer based on build target (core/proprietary/desktop) and handles the fallback cascade.
#### Component Override Pattern (Stub/Shadow)
Use this pattern for desktop-specific or proprietary-specific features WITHOUT runtime checks or conditionals.
**How it works:**
1. Core defines stub component (returns null or no-op)
2. Desktop/proprietary overrides with same path/name
3. Core imports via `@app/*` - higher layer "shadows" core in those builds
4. No `@ts-ignore`, no `isTauri()` checks, no runtime conditionals!
**Example - Desktop-specific footer:**
```typescript
// core/components/rightRail/RightRailFooterExtensions.tsx (stub)
interface RightRailFooterExtensionsProps {
className?: string;
}
export function RightRailFooterExtensions(_props: RightRailFooterExtensionsProps) {
return null; // Stub - does nothing in web builds
}
```
```typescript
// desktop/components/rightRail/RightRailFooterExtensions.tsx (real implementation)
import { Box } from '@mantine/core';
import { BackendHealthIndicator } from '@app/components/BackendHealthIndicator';
interface RightRailFooterExtensionsProps {
className?: string;
}
export function RightRailFooterExtensions({ className }: RightRailFooterExtensionsProps) {
return (
<Box className={className}>
<BackendHealthIndicator />
</Box>
);
}
```
```typescript
// core/components/shared/RightRail.tsx (usage - works in ALL builds)
import { RightRailFooterExtensions } from '@app/components/rightRail/RightRailFooterExtensions';
export function RightRail() {
return (
<div>
{/* In web builds: renders nothing (stub returns null) */}
{/* In desktop builds: renders BackendHealthIndicator */}
<RightRailFooterExtensions className="right-rail-footer" />
</div>
);
}
```
**Build resolution:**
- **Core build**: `@app/*``core/*` → Gets stub (returns null)
- **Desktop build**: `@app/*``desktop/*` → Gets real implementation (shadows core)
**Benefits:**
- No runtime checks or feature flags
- Type-safe across all builds
- Clean, readable code
- Build-time optimization (dead code elimination)
#### Multi-Tool Workflow Architecture
Frontend designed for **stateful document processing**:
- Users upload PDFs once, then chain tools (split → merge → compress → view)
@@ -122,7 +37,7 @@ Frontend designed for **stateful document processing**:
- No file reloading between tools - performance critical for large PDFs (up to 100GB+)
#### FileContext - Central State Management
**Location**: `frontend/src/core/contexts/FileContext.tsx`
**Location**: `src/contexts/FileContext.tsx`
- **Active files**: Currently loaded PDFs and their variants
- **Tool navigation**: Current mode (viewer/pageEditor/fileEditor/toolName)
- **Memory management**: PDF document cleanup, blob URL lifecycle, Web Worker management
@@ -147,7 +62,7 @@ Without cleanup: browser crashes with memory leaks.
**Architecture**: Modular hook-based system with clear separation of concerns:
- **useToolOperation** (`frontend/src/core/hooks/tools/shared/useToolOperation.ts`): Main orchestrator hook
- **useToolOperation** (`frontend/src/hooks/tools/shared/useToolOperation.ts`): Main orchestrator hook
- Coordinates all tool operations with consistent interface
- Integrates with FileContext for operation tracking
- Handles validation, error handling, and UI state management
@@ -232,34 +147,8 @@ return useToolOperation({
- **Pipeline System**: Automated PDF processing workflows via `PipelineController`
- **Security Layer**: Authentication, authorization, and user management (when enabled)
### Frontend Directory Structure
The frontend is organized with a clear separation of concerns:
- **`frontend/src/core/`**: Main application code (shared, production-ready components)
- **`core/components/`**: React components organized by feature
- `core/components/tools/`: Individual PDF tool implementations
- `core/components/viewer/`: PDF viewer components
- `core/components/pageEditor/`: Page manipulation UI
- `core/components/tooltips/`: Help tooltips for tools
- `core/components/shared/`: Reusable UI components
- **`core/contexts/`**: React Context providers
- `FileContext.tsx`: Central file state management
- `file/`: File reducer and selectors
- `toolWorkflow/`: Tool workflow state
- **`core/hooks/`**: Custom React hooks
- `hooks/tools/`: Tool-specific operation hooks (one directory per tool)
- `hooks/tools/shared/`: Shared hook utilities (useToolOperation, etc.)
- **`core/constants/`**: Application constants and configuration
- **`core/data/`**: Static data (tool taxonomy, etc.)
- **`core/services/`**: Business logic services (PDF processing, storage, etc.)
- **`frontend/src/desktop/`**: Desktop-specific (Tauri) code
- **`frontend/src/proprietary/`**: Proprietary/licensed features
- **`frontend/src-tauri/`**: Tauri (Rust) native desktop application code
- **`frontend/public/`**: Static assets served directly
- `public/locales/`: Translation JSON files
### Component Architecture
- **React Components**: Located in `frontend/src/components/` and `frontend/src/tools/`
- **Static Assets**: CSS, JS, and resources in `src/main/resources/static/` (legacy) + `frontend/public/` (modern)
- **Internationalization**:
- Backend: `messages_*.properties` files
@@ -314,7 +203,6 @@ The frontend is organized with a clear separation of concerns:
- **Backend**: Designed to be stateless - files are processed in memory/temp locations only
- **Frontend**: Uses IndexedDB for client-side file storage and caching (with thumbnails)
- **Security**: When `DOCKER_ENABLE_SECURITY=false`, security-related classes are excluded from compilation
- **Import Paths**: ALWAYS use `@app/*` for imports - never use `@core/*` or `@proprietary/*` unless explicitly wrapping/extending a lower layer
- **FileContext**: All file operations MUST go through FileContext - never bypass with direct File handling
- **Memory Management**: Manual cleanup required for PDF.js documents and blob URLs - don't remove cleanup code
- **Tool Development**: New tools should follow `useToolOperation` hook pattern (see `useCompressOperation.ts`)
@@ -303,23 +303,22 @@ public class EndpointConfiguration {
// Adding endpoints to "PageOps" group
addEndpointToGroup("PageOps", "remove-pages");
addEndpointToGroup("PageOps", "merge-pdfs");
addEndpointToGroup("PageOps", "split-pages");
addEndpointToGroup("PageOps", "rearrange-pages");
addEndpointToGroup("PageOps", "split-pdfs");
addEndpointToGroup("PageOps", "pdf-organizer");
addEndpointToGroup("PageOps", "rotate-pdf");
addEndpointToGroup("PageOps", "multi-page-layout");
addEndpointToGroup("PageOps", "booklet-imposition");
addEndpointToGroup("PageOps", "scale-pages");
addEndpointToGroup("PageOps", "crop");
addEndpointToGroup("PageOps", "extract-page");
addEndpointToGroup("PageOps", "pdf-to-single-page");
addEndpointToGroup("PageOps", "auto-split-pdf");
addEndpointToGroup("PageOps", "split-by-size-or-count");
addEndpointToGroup("PageOps", "overlay-pdf");
addEndpointToGroup("PageOps", "split-pdf-by-sections");
addEndpointToGroup("PageOps", "split-pdf-by-chapters");
addEndpointToGroup("PageOps", "add-page-numbers");
addEndpointToGroup("PageOps", "extract-pages");
// Adding endpoints to "Convert" group (Frontend has 15 convert endpoints)
// Adding endpoints to "Convert" group
addEndpointToGroup("Convert", "pdf-to-img");
addEndpointToGroup("Convert", "img-to-pdf");
addEndpointToGroup("Convert", "pdf-to-pdfa");
@@ -335,8 +334,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Convert", "pdf-to-csv");
addEndpointToGroup("Convert", "pdf-to-markdown");
addEndpointToGroup("Convert", "eml-to-pdf");
addEndpointToGroup("Convert", "pdf-to-epub");
// Backend-only endpoints (not in frontend tool registry)
addEndpointToGroup("Convert", "pdf-to-vector");
addEndpointToGroup("Convert", "vector-to-pdf");
addEndpointToGroup("Convert", "pdf-to-video");
@@ -344,7 +341,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Convert", "pdf-to-cbz");
addEndpointToGroup("Convert", "pdf-to-json");
addEndpointToGroup("Convert", "json-to-pdf");
addEndpointToGroup("Convert", "pdf-to-rtf");
// Adding endpoints to "Security" group
addEndpointToGroup("Security", "add-password");
@@ -355,49 +351,51 @@ public class EndpointConfiguration {
addEndpointToGroup("Security", "remove-cert-sign");
addEndpointToGroup("Security", "sanitize-pdf");
addEndpointToGroup("Security", "auto-redact");
addEndpointToGroup("Security", "validate-signature");
addEndpointToGroup("Security", "add-stamp");
addEndpointToGroup("Security", "unlock-pdf-forms");
// Backend-only endpoints (not in frontend tool registry endpoints)
addEndpointToGroup("Security", "redact");
addEndpointToGroup("Security", "validate-signature");
addEndpointToGroup("Security", "verify-pdf");
addEndpointToGroup("Security", "stamp");
addEndpointToGroup("Security", "sign");
// Adding endpoints to "Other" group
addEndpointToGroup("Other", "ocr-pdf");
addEndpointToGroup("Other", "add-image");
addEndpointToGroup("Other", "extract-images");
addEndpointToGroup("Other", "update-metadata");
addEndpointToGroup("Other", "change-metadata");
addEndpointToGroup("Other", "flatten");
addEndpointToGroup("Other", "unlock-pdf-forms");
addEndpointToGroup("Other", REMOVE_BLANKS);
addEndpointToGroup("Other", "remove-annotations");
addEndpointToGroup("Other", "compare");
addEndpointToGroup("Other", "add-page-numbers");
addEndpointToGroup("Other", "get-info-on-pdf");
addEndpointToGroup("Other", "remove-image-pdf");
addEndpointToGroup("Other", "add-attachments");
addEndpointToGroup("Other", "replace-invert-pdf");
addEndpointToGroup("Other", "edit-table-of-contents");
addEndpointToGroup("Other", "text-editor-pdf");
// Backend-only endpoints (not in frontend tool registry endpoints)
addEndpointToGroup("Other", "add-image");
addEndpointToGroup("Other", "compare");
addEndpointToGroup("Other", "view-pdf");
addEndpointToGroup("Other", "replace-and-invert-color-pdf");
addEndpointToGroup("Other", "multi-tool");
// Adding form-related endpoints to "Other" group
addEndpointToGroup("Other", "fields");
addEndpointToGroup("Other", "modify-fields");
addEndpointToGroup("Other", "delete-fields");
addEndpointToGroup("Other", "fill");
// Adding endpoints to "Advance" group
addEndpointToGroup("Advance", "adjust-contrast");
addEndpointToGroup("Advance", "compress-pdf");
addEndpointToGroup("Advance", "extract-image-scans");
addEndpointToGroup("Advance", "repair");
addEndpointToGroup("Advance", "auto-rename");
addEndpointToGroup("Advance", "handleData");
addEndpointToGroup("Advance", "scanner-effect");
addEndpointToGroup("Advance", "show-javascript");
addEndpointToGroup("Advance", "overlay-pdf");
// Backend-only endpoints
addEndpointToGroup("Advance", "adjust-contrast");
addEndpointToGroup("Advance", "pipeline");
addEndpointToGroup("Advance", "scanner-effect");
addEndpointToGroup("Advance", "auto-split-pdf");
addEndpointToGroup("Advance", "show-javascript");
addEndpointToGroup("Advance", "split-by-size-or-count");
addEndpointToGroup("Advance", "overlay-pdf");
addEndpointToGroup("Advance", "split-pdf-by-sections");
addEndpointToGroup("Advance", "edit-table-of-contents");
addEndpointToGroup("Advance", "split-pdf-by-chapters");
// CLI
addEndpointToGroup("CLI", "compress-pdf");
@@ -438,8 +436,8 @@ public class EndpointConfiguration {
// Java
addEndpointToGroup("Java", "merge-pdfs");
addEndpointToGroup("Java", "remove-pages");
addEndpointToGroup("Java", "split-pages");
addEndpointToGroup("Java", "rearrange-pages");
addEndpointToGroup("Java", "split-pdfs");
addEndpointToGroup("Java", "pdf-organizer");
addEndpointToGroup("Java", "rotate-pdf");
addEndpointToGroup("Java", "pdf-to-img");
addEndpointToGroup("Java", "img-to-pdf");
@@ -447,10 +445,9 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "remove-password");
addEndpointToGroup("Java", "change-permissions");
addEndpointToGroup("Java", "add-watermark");
addEndpointToGroup("Java", "add-stamp");
addEndpointToGroup("Java", "add-image");
addEndpointToGroup("Java", "extract-images");
addEndpointToGroup("Java", "update-metadata");
addEndpointToGroup("Java", "change-metadata");
addEndpointToGroup("Java", "cert-sign");
addEndpointToGroup("Java", "remove-cert-sign");
addEndpointToGroup("Java", "multi-page-layout");
@@ -462,6 +459,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "sanitize-pdf");
addEndpointToGroup("Java", "crop");
addEndpointToGroup("Java", "get-info-on-pdf");
addEndpointToGroup("Java", "extract-page");
addEndpointToGroup("Java", "pdf-to-single-page");
addEndpointToGroup("Java", "markdown-to-pdf");
addEndpointToGroup("Java", "show-javascript");
@@ -471,9 +469,7 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "split-by-size-or-count");
addEndpointToGroup("Java", "overlay-pdf");
addEndpointToGroup("Java", "split-pdf-by-sections");
addEndpointToGroup("Java", "split-pdf-by-chapters");
addEndpointToGroup("Java", REMOVE_BLANKS);
addEndpointToGroup("Java", "remove-annotations");
addEndpointToGroup("Java", "pdf-to-text");
addEndpointToGroup("Java", "remove-image-pdf");
addEndpointToGroup("Java", "pdf-to-markdown");
@@ -483,24 +479,15 @@ public class EndpointConfiguration {
addEndpointToGroup("Java", "pdf-to-cbz");
addEndpointToGroup("Java", "pdf-to-json");
addEndpointToGroup("Java", "json-to-pdf");
addEndpointToGroup("rar", "pdf-to-cbr");
addEndpointToGroup("Java", "pdf-to-video");
addEndpointToGroup("Java", "verify-pdf");
addEndpointToGroup("Java", "flatten");
addEndpointToGroup("Java", "unlock-pdf-forms");
addEndpointToGroup("Java", "validate-signature");
addEndpointToGroup("Java", "text-editor-pdf");
addEndpointToGroup("Java", "edit-table-of-contents");
addEndpointToGroup("Java", "pdf-to-epub");
addEndpointToGroup("Java", "eml-to-pdf");
addEndpointToGroup("Java", "handleData");
addEndpointToGroup("rar", "pdf-to-cbr");
// Javascript
addEndpointToGroup("Javascript", "rearrange-pages");
addEndpointToGroup("Javascript", "pdf-organizer");
addEndpointToGroup("Javascript", "sign");
addEndpointToGroup("Javascript", "compare");
addEndpointToGroup("Javascript", "adjust-contrast");
addEndpointToGroup("Javascript", "text-editor-pdf");
/* qpdf */
addEndpointToGroup("qpdf", "repair");
@@ -511,7 +498,6 @@ public class EndpointConfiguration {
addEndpointToGroup("Ghostscript", "compress-pdf");
addEndpointToGroup("Ghostscript", "crop");
addEndpointToGroup("Ghostscript", "replace-invert-pdf");
addEndpointToGroup("Ghostscript", "scanner-effect");
addEndpointToGroup("Ghostscript", "pdf-to-vector");
addEndpointToGroup("Ghostscript", "vector-to-pdf");
@@ -530,8 +516,6 @@ public class EndpointConfiguration {
addEndpointAlternative("compress-pdf", "qpdf");
addEndpointAlternative("compress-pdf", "Ghostscript");
addEndpointAlternative("compress-pdf", "Java");
addEndpointAlternative("crop", "Ghostscript");
addEndpointAlternative("crop", "Java");
addEndpointAlternative("ocr-pdf", "tesseract");
addEndpointAlternative("ocr-pdf", "OCRmyPDF");
@@ -560,9 +544,6 @@ public class EndpointConfiguration {
// Pdftohtml dependent endpoints
addEndpointToGroup("Pdftohtml", "pdf-to-html");
addEndpointToGroup("Pdftohtml", "pdf-to-markdown");
// Calibre dependent endpoints
addEndpointToGroup("Calibre", "pdf-to-epub");
}
private void processEnvironmentConfigs() {
@@ -1,14 +1,10 @@
package stirling.software.common.configuration;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
@@ -45,7 +41,6 @@ public class RuntimePathConfig {
// Pipeline paths
private final String pipelineWatchedFoldersPath;
private final List<String> pipelineWatchedFoldersPaths;
private final String pipelineFinishedFoldersPath;
private final String pipelineDefaultWebUiConfigs;
private final String pipelinePath;
@@ -54,27 +49,20 @@ public class RuntimePathConfig {
this.properties = properties;
this.basePath = InstallationPathConfig.getPath();
this.pipelinePath = Path.of(basePath, "pipeline").toString();
String defaultWatchedFolders = Path.of(this.pipelinePath, "watchedFolders").toString();
String defaultFinishedFolders = Path.of(this.pipelinePath, "finishedFolders").toString();
String defaultWebUIConfigs = Path.of(this.pipelinePath, "defaultWebUIConfigs").toString();
System system = properties.getSystem();
CustomPaths customPaths = system.getCustomPaths();
Pipeline pipeline = customPaths.getPipeline();
this.pipelinePath =
this.pipelineWatchedFoldersPath =
resolvePath(
Path.of(basePath, "pipeline").toString(),
pipeline != null ? pipeline.getPipelineDir() : null);
String defaultWatchedFolders = Path.of(this.pipelinePath, "watchedFolders").toString();
String defaultFinishedFolders = Path.of(this.pipelinePath, "finishedFolders").toString();
String defaultWebUIConfigs = Path.of(this.pipelinePath, "defaultWebUIConfigs").toString();
List<String> watchedFoldersDirs =
sanitizePathList(pipeline != null ? pipeline.getWatchedFoldersDirs() : null);
this.pipelineWatchedFoldersPaths =
resolveWatchedFolderPaths(
defaultWatchedFolders,
watchedFoldersDirs,
pipeline != null ? pipeline.getWatchedFoldersDir() : null);
this.pipelineWatchedFoldersPath = this.pipelineWatchedFoldersPaths.get(0);
this.pipelineFinishedFoldersPath =
resolvePath(
defaultFinishedFolders,
@@ -84,9 +72,6 @@ public class RuntimePathConfig {
defaultWebUIConfigs,
pipeline != null ? pipeline.getWebUIConfigsDir() : null);
// Validate path conflicts after all paths are resolved
validatePipelinePaths();
boolean isDocker = isRunningInDocker();
// Initialize Operation paths
@@ -144,140 +129,6 @@ public class RuntimePathConfig {
return StringUtils.isNotBlank(customPath) ? customPath : defaultPath;
}
private List<String> resolveWatchedFolderPaths(
String defaultPath, List<String> watchedFoldersDirs, String legacyWatchedFolder) {
List<String> rawPaths = new ArrayList<>();
// Collect paths from new config
if (watchedFoldersDirs != null && !watchedFoldersDirs.isEmpty()) {
rawPaths.addAll(watchedFoldersDirs);
}
// Fall back to legacy config
else if (StringUtils.isNotBlank(legacyWatchedFolder)) {
rawPaths.add(legacyWatchedFolder);
}
// Fall back to default
else {
rawPaths.add(defaultPath);
}
// Validate, normalize, and deduplicate paths
List<String> validatedPaths = validateAndNormalizePaths(rawPaths);
// Ensure we have at least one valid path (critical for system to function)
if (validatedPaths.isEmpty()) {
log.warn(
"No valid watched folder paths configured, falling back to default: {}",
defaultPath);
validatedPaths.add(defaultPath);
}
// Detect overlapping paths (warning only, not blocking)
detectOverlappingPaths(validatedPaths);
return validatedPaths;
}
private List<String> sanitizePathList(List<String> paths) {
if (paths == null || paths.isEmpty()) {
return Collections.emptyList();
}
List<String> sanitized = new ArrayList<>();
for (String path : paths) {
if (StringUtils.isNotBlank(path)) {
sanitized.add(path.trim());
}
}
return sanitized;
}
private List<String> validateAndNormalizePaths(List<String> paths) {
Set<String> normalizedPaths = new LinkedHashSet<>(); // Preserves order, prevents duplicates
for (String pathStr : paths) {
if (StringUtils.isBlank(pathStr)) {
continue;
}
try {
// Normalize to absolute path
Path path = Paths.get(pathStr.trim()).toAbsolutePath().normalize();
String normalizedPath = path.toString();
// Check for duplicates
if (normalizedPaths.contains(normalizedPath)) {
log.debug("Skipping duplicate watched folder path: {}", pathStr);
continue;
}
normalizedPaths.add(normalizedPath);
log.info("Registered watched folder path: {}", normalizedPath);
} catch (InvalidPathException e) {
log.error(
"Invalid watched folder path '{}' - skipping: {}", pathStr, e.getMessage());
}
}
return new ArrayList<>(normalizedPaths);
}
private void detectOverlappingPaths(List<String> paths) {
for (int i = 0; i < paths.size(); i++) {
Path path1 = Paths.get(paths.get(i));
for (int j = i + 1; j < paths.size(); j++) {
Path path2 = Paths.get(paths.get(j));
// Check if one path is a parent of the other
if (path1.startsWith(path2)) {
log.warn(
"Watched folder path '{}' is nested inside '{}' - this may cause duplicate processing",
path1,
path2);
} else if (path2.startsWith(path1)) {
log.warn(
"Watched folder path '{}' is nested inside '{}' - this may cause duplicate processing",
path2,
path1);
}
}
}
}
private void validatePipelinePaths() {
try {
Path finishedPath = Paths.get(pipelineFinishedFoldersPath).toAbsolutePath().normalize();
for (String watchedPathStr : pipelineWatchedFoldersPaths) {
Path watchedPath = Paths.get(watchedPathStr).toAbsolutePath().normalize();
// Check if watched folder is same as finished folder
if (watchedPath.equals(finishedPath)) {
log.error(
"CRITICAL: Watched folder '{}' is the same as finished folder '{}' - this will cause processing loops!",
watchedPath,
finishedPath);
}
// Check if watched folder contains finished folder
else if (finishedPath.startsWith(watchedPath)) {
log.warn(
"Finished folder '{}' is nested inside watched folder '{}' - this may cause issues",
finishedPath,
watchedPath);
}
// Check if finished folder contains watched folder
else if (watchedPath.startsWith(finishedPath)) {
log.error(
"CRITICAL: Watched folder '{}' is nested inside finished folder '{}' - this will cause processing loops!",
watchedPath,
finishedPath);
}
}
} catch (Exception e) {
log.error("Error validating pipeline paths: {}", e.getMessage());
}
}
private boolean isRunningInDocker() {
return Files.exists(Path.of("/.dockerenv"));
}
@@ -35,8 +35,6 @@ import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import jakarta.annotation.PostConstruct;
import stirling.software.common.configuration.InstallationPathConfig;
import stirling.software.common.configuration.YamlPropertySourceFactory;
import stirling.software.common.model.exception.UnsupportedProviderException;
@@ -100,46 +98,6 @@ public class ApplicationProperties {
return propertySource;
}
/**
* Initialize fileUploadLimit from environment variables if not set in settings.yml.
* Supports SYSTEMFILEUPLOADLIMIT (format: "100MB") and SYSTEM_MAXFILESIZE (format: "100" in MB).
*/
@PostConstruct
public void initializeFileUploadLimitFromEnv() {
// Only override if fileUploadLimit is not already set in settings.yml
if (system.getFileUploadLimit() == null || system.getFileUploadLimit().isEmpty()) {
String fileUploadLimit = null;
// Check SYSTEMFILEUPLOADLIMIT first (format: "100MB", "1GB", etc.)
String systemFileUploadLimit = java.lang.System.getenv("SYSTEMFILEUPLOADLIMIT");
if (systemFileUploadLimit != null && !systemFileUploadLimit.trim().isEmpty()) {
fileUploadLimit = systemFileUploadLimit.trim();
log.info("Setting fileUploadLimit from SYSTEMFILEUPLOADLIMIT: {}", fileUploadLimit);
} else {
// Check SYSTEM_MAXFILESIZE (format: number in MB, e.g., "100")
String systemMaxFileSize = java.lang.System.getenv("SYSTEM_MAXFILESIZE");
if (systemMaxFileSize != null && !systemMaxFileSize.trim().isEmpty()) {
try {
// Validate it's a number
long sizeInMB = Long.parseLong(systemMaxFileSize.trim());
if (sizeInMB > 0 && sizeInMB <= 999) {
fileUploadLimit = sizeInMB + "MB";
log.info("Setting fileUploadLimit from SYSTEM_MAXFILESIZE: {}MB", sizeInMB);
} else {
log.warn("SYSTEM_MAXFILESIZE value {} is out of valid range (1-999), ignoring", sizeInMB);
}
} catch (NumberFormatException e) {
log.warn("SYSTEM_MAXFILESIZE value '{}' is not a valid number, ignoring", systemMaxFileSize);
}
}
}
if (fileUploadLimit != null) {
system.setFileUploadLimit(fileUploadLimit);
}
}
}
@Data
public static class AutoPipeline {
private String outputFolder;
@@ -206,7 +164,6 @@ public class ApplicationProperties {
private String customGlobalAPIKey;
private Jwt jwt = new Jwt();
private Validation validation = new Validation();
private String xFrameOptions = "DENY";
public Boolean isAltLogin() {
return saml2.getEnabled() || oauth2.getEnabled();
@@ -501,9 +458,7 @@ public class ApplicationProperties {
@Data
public static class Pipeline {
private String pipelineDir;
private String watchedFoldersDir;
private List<String> watchedFoldersDirs = new ArrayList<>();
private String finishedFoldersDir;
private String webUIConfigsDir;
}
@@ -29,7 +29,7 @@ public class FileMonitor {
private final ConcurrentHashMap.KeySetView<Path, Boolean> readyForProcessingFiles;
private final WatchService watchService;
private final Predicate<Path> pathFilter;
private final List<Path> rootDirs;
private final Path rootDir;
private Set<Path> stagingFiles;
/**
@@ -47,28 +47,8 @@ public class FileMonitor {
this.pathFilter = pathFilter;
this.readyForProcessingFiles = ConcurrentHashMap.newKeySet();
this.watchService = FileSystems.getDefault().newWatchService();
List<String> watchedFoldersDirs = runtimePathConfig.getPipelineWatchedFoldersPaths();
List<Path> validRootDirs = new ArrayList<>();
for (String pathStr : watchedFoldersDirs) {
try {
Path path = Path.of(pathStr);
validRootDirs.add(path);
log.info("Monitoring directory: {}", path);
} catch (Exception e) {
log.error(
"Failed to initialize monitoring for path '{}': {}",
pathStr,
e.getMessage());
}
}
this.rootDirs = Collections.unmodifiableList(validRootDirs);
if (this.rootDirs.isEmpty()) {
log.error("No valid directories to monitor - FileMonitor will not function");
}
log.info("Monitoring directory: {}", runtimePathConfig.getPipelineWatchedFoldersPath());
this.rootDir = Path.of(runtimePathConfig.getPipelineWatchedFoldersPath());
}
private boolean shouldNotProcess(Path path) {
@@ -105,15 +85,13 @@ public class FileMonitor {
readyForProcessingFiles.clear();
if (path2KeyMapping.isEmpty()) {
log.warn("Not monitoring any directories; attempting to re-register root paths.");
for (Path rootDir : rootDirs) {
if (Files.exists(
rootDir)) { // if the root directory exists, re-register the root directory
try {
recursivelyRegisterEntry(rootDir);
} catch (IOException e) {
log.error("unable to register monitoring for {}", rootDir, e);
}
log.warn("not monitoring any directory, even the root directory itself: {}", rootDir);
if (Files.exists(
rootDir)) { // if the root directory exists, re-register the root directory
try {
recursivelyRegisterEntry(rootDir);
} catch (IOException e) {
log.error("unable to register monitoring", e);
}
}
}
@@ -9,7 +9,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.List;
import java.util.function.Predicate;
import org.junit.jupiter.api.BeforeEach;
@@ -35,8 +34,7 @@ class FileMonitorTest {
@BeforeEach
void setUp() throws IOException {
when(runtimePathConfig.getPipelineWatchedFoldersPaths())
.thenReturn(List.of(tempDir.toString()));
when(runtimePathConfig.getPipelineWatchedFoldersPath()).thenReturn(tempDir.toString());
// This mock is used in all tests except testPathFilter
// We use lenient to avoid UnnecessaryStubbingException in that test
-1
View File
@@ -221,7 +221,6 @@ tasks.register('npmBuild', Exec) {
commandLine = Os.isFamily(Os.FAMILY_WINDOWS) ? ['cmd', '/c', 'npm', 'run', 'build'] : ['npm', 'run', 'build']
dependsOn npmInstall
inputs.dir(new File(frontendDir, 'src'))
inputs.dir(new File(frontendDir, 'public'))
inputs.file(new File(frontendDir, 'package.json'))
outputs.dir(frontendDistDir)
@@ -118,8 +118,7 @@ public class ExternalAppDepConfig {
for (String group : affectedGroups) {
List<String> affectedFeatures = getAffectedFeatures(group);
endpointConfiguration.disableGroup(
group, EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup(group);
log.warn(
"Missing dependency: {} - Disabling group: {} (Affected features: {})",
command,
@@ -144,8 +143,7 @@ public class ExternalAppDepConfig {
commandToGroupMapping.getOrDefault(
command, List.of("Weasyprint"));
for (String group : affectedGroups) {
endpointConfiguration.disableGroup(
group, EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup(group);
}
log.warn(
"WeasyPrint version {} is below required {} - disabling"
@@ -174,8 +172,7 @@ public class ExternalAppDepConfig {
List<String> affectedGroups =
commandToGroupMapping.getOrDefault(command, List.of("qpdf"));
for (String group : affectedGroups) {
endpointConfiguration.disableGroup(
group, EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup(group);
}
log.warn(
"qpdf version {} is below required {} - disabling group(s): {}",
@@ -229,8 +226,7 @@ public class ExternalAppDepConfig {
int ec = runAndWait(List.of(python, "-c", "import cv2"), DEFAULT_TIMEOUT).exitCode();
if (ec != 0) {
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup(
"OpenCV", EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup("OpenCV");
log.warn(
"OpenCV not available in Python - Disabling OpenCV features: {}",
String.join(", ", openCVFeatures));
@@ -240,10 +236,8 @@ public class ExternalAppDepConfig {
private void disablePythonAndOpenCV(String reason) {
List<String> pythonFeatures = getAffectedFeatures("Python");
List<String> openCVFeatures = getAffectedFeatures("OpenCV");
endpointConfiguration.disableGroup(
"Python", EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup(
"OpenCV", EndpointConfiguration.DisableReason.DEPENDENCY);
endpointConfiguration.disableGroup("Python");
endpointConfiguration.disableGroup("OpenCV");
log.warn(
"Missing dependency: Python (reason: {}) - Disabling Python features: {} and OpenCV"
+ " features: {}",
@@ -1,76 +0,0 @@
package stirling.software.SPDF.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.util.unit.DataSize;
import jakarta.servlet.MultipartConfigElement;
import lombok.extern.slf4j.Slf4j;
import stirling.software.SPDF.controller.web.UploadLimitService;
/**
* Configuration for Spring multipart file upload settings.
* Synchronizes multipart limits with fileUploadLimit from settings.yml or environment variables
* (SYSTEMFILEUPLOADLIMIT or SYSTEM_MAXFILESIZE).
*/
@Configuration
@Slf4j
public class MultipartConfiguration {
@Autowired private UploadLimitService uploadLimitService;
/**
* Creates MultipartConfigElement that respects fileUploadLimit from settings.yml
* or environment variables (SYSTEMFILEUPLOADLIMIT or SYSTEM_MAXFILESIZE).
* Depends on ApplicationProperties being initialized so @PostConstruct has run.
*/
@Bean
@DependsOn("applicationProperties")
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// First check if SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE is explicitly set
String springMaxFileSize = java.lang.System.getenv("SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE");
long uploadLimitBytes = 0;
if (springMaxFileSize != null && !springMaxFileSize.trim().isEmpty()) {
// Parse the Spring property format (e.g., "2000MB")
try {
DataSize dataSize = DataSize.parse(springMaxFileSize.trim());
uploadLimitBytes = dataSize.toBytes();
log.info("Using SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {}", springMaxFileSize);
} catch (Exception e) {
log.warn("Failed to parse SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {}", springMaxFileSize, e);
}
}
// If not set via Spring property, use UploadLimitService which reads from
// fileUploadLimit (set from SYSTEMFILEUPLOADLIMIT/SYSTEM_MAXFILESIZE or settings.yml)
if (uploadLimitBytes == 0) {
uploadLimitBytes = uploadLimitService.getUploadLimit();
if (uploadLimitBytes > 0) {
log.info(
"Using fileUploadLimit setting: {}",
uploadLimitService.getReadableUploadLimit());
}
}
// If still no limit, use default of 2000MB
if (uploadLimitBytes == 0) {
uploadLimitBytes = 2000L * 1024 * 1024; // 2000MB default
log.info("Using default multipart file upload limit: 2000MB");
}
// Set max file size and max request size to the same value
factory.setMaxFileSize(DataSize.ofBytes(uploadLimitBytes));
factory.setMaxRequestSize(DataSize.ofBytes(uploadLimitBytes));
return factory.createMultipartConfig();
}
}
@@ -106,29 +106,16 @@ public class WebMvcConfig implements WebMvcConfigurer {
.allowCredentials(true)
.maxAge(3600);
} else if (hasConfiguredOrigins) {
// Use user-configured origins + always include Tauri origins for desktop app support
// Use user-configured origins
logger.info(
"Configuring CORS with allowed origins: {}",
applicationProperties.getSystem().getCorsAllowedOrigins());
// Combine user-configured origins with Tauri origins
java.util.List<String> allOrigins =
new java.util.ArrayList<>(
applicationProperties.getSystem().getCorsAllowedOrigins());
// Always include Tauri origins for desktop app compatibility
// Tauri v1 uses tauri://localhost, v2 uses http(s)://tauri.localhost
if (!allOrigins.contains("tauri://localhost")) {
allOrigins.add("tauri://localhost");
}
if (!allOrigins.contains("http://tauri.localhost")) {
allOrigins.add("http://tauri.localhost");
}
if (!allOrigins.contains("https://tauri.localhost")) {
allOrigins.add("https://tauri.localhost");
}
String[] allowedOrigins = allOrigins.toArray(new String[0]);
String[] allowedOrigins =
applicationProperties
.getSystem()
.getCorsAllowedOrigins()
.toArray(new String[0]);
registry.addMapping("/**")
.allowedOriginPatterns(allowedOrigins)
@@ -46,18 +46,18 @@ public class EditTableOfContentsController {
@Operation(
summary = "Extract PDF Bookmarks",
description = "Extracts bookmarks/table of contents from a PDF document as JSON.")
public ResponseEntity<List<Map<String, Object>>> extractBookmarks(
@RequestParam("file") MultipartFile file) throws Exception {
@ResponseBody
public List<Map<String, Object>> extractBookmarks(@RequestParam("file") MultipartFile file)
throws Exception {
try (PDDocument document = pdfDocumentFactory.load(file)) {
PDDocumentOutline outline = document.getDocumentCatalog().getDocumentOutline();
if (outline == null) {
log.info("No outline/bookmarks found in PDF");
return ResponseEntity.ok(new ArrayList<>());
return new ArrayList<>();
}
List<Map<String, Object>> bookmarks = extractBookmarkItems(document, outline);
return ResponseEntity.ok(bookmarks);
return extractBookmarkItems(document, outline);
}
}
@@ -71,12 +71,10 @@ import org.apache.xmpbox.schema.PDFAIdentificationSchema;
import org.apache.xmpbox.schema.XMPBasicSchema;
import org.apache.xmpbox.xml.DomXmpParser;
import org.apache.xmpbox.xml.XmpSerializer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;
import io.github.pixee.security.Filenames;
import io.swagger.v3.oas.annotations.Operation;
@@ -101,7 +99,6 @@ public class ConvertPDFToPDFA {
private static final Pattern NON_PRINTABLE_ASCII = Pattern.compile("[^\\x20-\\x7E]");
private final RuntimePathConfig runtimePathConfig;
private final stirling.software.SPDF.service.VeraPDFService veraPDFService;
private static final String ICC_RESOURCE_PATH = "/icc/sRGB2014.icc";
private static final int PDFA_COMPATIBILITY_POLICY = 1;
@@ -590,8 +587,7 @@ public class ConvertPDFToPDFA {
if (isPdfX) {
return handlePdfXConversion(inputFile, outputFormat);
} else {
return handlePdfAConversion(
inputFile, outputFormat, request.getStrict() != null && request.getStrict());
return handlePdfAConversion(inputFile, outputFormat);
}
}
@@ -1797,7 +1793,7 @@ public class ConvertPDFToPDFA {
}
private ResponseEntity<byte[]> handlePdfAConversion(
MultipartFile inputFile, String outputFormat, boolean strict) throws Exception {
MultipartFile inputFile, String outputFormat) throws Exception {
PdfaProfile profile = PdfaProfile.fromRequest(outputFormat);
// Get the original filename without extension
@@ -1826,10 +1822,6 @@ public class ConvertPDFToPDFA {
validateAndWarnPdfA(converted, profile, "Ghostscript");
if (strict) {
verifyStrictCompliance(converted);
}
return WebResponseUtils.bytesToWebResponse(
converted, outputFilename, MediaType.APPLICATION_PDF);
} catch (IOException | InterruptedException e) {
@@ -1847,42 +1839,14 @@ public class ConvertPDFToPDFA {
// Validate with PDFBox preflight and warn if issues found
validateAndWarnPdfA(converted, profile, "PDFBox/LibreOffice");
if (strict) {
verifyStrictCompliance(converted);
}
return WebResponseUtils.bytesToWebResponse(
converted, outputFilename, MediaType.APPLICATION_PDF);
} finally {
deleteQuietly(workingDir);
}
}
private void verifyStrictCompliance(byte[] pdfBytes) throws IOException {
try (InputStream is = new ByteArrayInputStream(pdfBytes)) {
List<stirling.software.SPDF.model.api.security.PDFVerificationResult> results =
veraPDFService.validatePDF(is);
boolean isCompliant = results.stream().anyMatch(result -> result.isCompliant());
if (!isCompliant) {
String details =
results.stream()
.map(r -> r.getStandard() + ": " + r.getComplianceSummary())
.collect(Collectors.joining("; "));
throw new ResponseStatusException(
HttpStatus.BAD_REQUEST,
"Strict PDF/A mode enabled: Conversion is not perfectly compliant. Details: "
+ details);
}
} catch (Exception e) {
if (e instanceof ResponseStatusException) {
throw (ResponseStatusException) e;
}
log.error("Error during strict PDF/A verification", e);
throw new ResponseStatusException(
HttpStatus.INTERNAL_SERVER_ERROR, "Error during strict PDF/A verification");
}
}
private Path sanitizePdfWithPdfBox(Path inputPdf, boolean addWhiteBackground) {
try {
Path sanitizedPath =
@@ -2,7 +2,6 @@ package stirling.software.SPDF.controller.api.converters;
import java.util.Optional;
import java.util.UUID;
import java.nio.charset.StandardCharsets;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
@@ -57,7 +56,6 @@ public class ConvertPdfJsonController {
}
byte[] jsonBytes = pdfJsonConversionService.convertPdfToJson(inputFile, lightweight);
logJsonResponse("pdf/text-editor", jsonBytes);
String originalName = inputFile.getOriginalFilename();
String baseName =
(originalName != null && !originalName.isBlank())
@@ -114,7 +112,6 @@ public class ConvertPdfJsonController {
byte[] jsonBytes =
pdfJsonConversionService.extractDocumentMetadata(inputFile, scopedJobKey);
logJsonResponse("pdf/text-editor/metadata", jsonBytes);
String originalName = inputFile.getOriginalFilename();
String baseName =
(originalName != null && !originalName.isBlank())
@@ -178,7 +175,6 @@ public class ConvertPdfJsonController {
validateJobAccess(jobId);
byte[] jsonBytes = pdfJsonConversionService.extractSinglePage(jobId, pageNumber);
logJsonResponse("pdf/text-editor/page", jsonBytes);
String docName = "page_" + pageNumber + ".json";
return WebResponseUtils.bytesToWebResponse(jsonBytes, docName, MediaType.APPLICATION_JSON);
}
@@ -213,182 +209,6 @@ public class ConvertPdfJsonController {
return baseJobId;
}
private void logJsonResponse(String label, byte[] jsonBytes) {
if (jsonBytes == null) {
log.warn("Returning {} JSON response: null bytes", label);
return;
}
int length = jsonBytes.length;
boolean endsWithJson =
length > 0 && (jsonBytes[length - 1] == '}' || jsonBytes[length - 1] == ']');
String tail = "";
if (length > 0) {
int start = Math.max(0, length - 64);
tail = new String(jsonBytes, start, length - start, StandardCharsets.UTF_8);
tail = tail.replaceAll("[\\r\\n\\t]+", " ").replaceAll("[^\\x20-\\x7E]", "?");
}
log.info(
"Returning {} JSON response ({} bytes, endsWithJson={}, tail='{}')",
label,
length,
endsWithJson,
tail);
if (isPdfJsonDebugDumpEnabled()) {
try {
String tmpDir = System.getProperty("java.io.tmpdir");
String customDir = System.getenv("SPDF_PDFJSON_DUMP_DIR");
java.nio.file.Path dumpDir =
customDir != null && !customDir.isBlank()
? java.nio.file.Path.of(customDir)
: java.nio.file.Path.of(tmpDir);
java.nio.file.Path dumpPath =
java.nio.file.Files.createTempFile(dumpDir, "pdfjson_", ".json");
java.nio.file.Files.write(dumpPath, jsonBytes);
log.info("PDF JSON debug dump ({}): {}", label, dumpPath);
} catch (Exception ex) {
log.warn("Failed to write PDF JSON debug dump ({}): {}", label, ex.getMessage());
}
}
if (isPdfJsonRepeatScanEnabled()) {
logRepeatedJsonStrings(label, jsonBytes);
}
}
private boolean isPdfJsonDebugDumpEnabled() {
String env = System.getenv("SPDF_PDFJSON_DUMP");
if (env != null && env.equalsIgnoreCase("true")) {
return true;
}
return Boolean.getBoolean("spdf.pdfjson.dump");
}
private boolean isPdfJsonRepeatScanEnabled() {
String env = System.getenv("SPDF_PDFJSON_REPEAT_SCAN");
if (env != null && env.equalsIgnoreCase("true")) {
return true;
}
return Boolean.getBoolean("spdf.pdfjson.repeatScan");
}
private void logRepeatedJsonStrings(String label, byte[] jsonBytes) {
final int minLen = 12;
final int maxLen = 200;
final int maxUnique = 50000;
java.util.Map<String, Integer> counts = new java.util.HashMap<>();
boolean inString = false;
boolean escape = false;
boolean tooLong = false;
StringBuilder current = new StringBuilder(64);
boolean capped = false;
for (byte b : jsonBytes) {
char ch = (char) (b & 0xFF);
if (!inString) {
if (ch == '"') {
inString = true;
escape = false;
tooLong = false;
current.setLength(0);
}
continue;
}
if (escape) {
escape = false;
if (!tooLong && current.length() < maxLen) {
current.append(ch);
}
continue;
}
if (ch == '\\') {
escape = true;
continue;
}
if (ch == '"') {
inString = false;
if (!tooLong) {
int len = current.length();
if (len >= minLen && len <= maxLen) {
String value = current.toString();
if (!looksLikeBase64(value)) {
if (!capped || counts.containsKey(value)) {
counts.merge(value, 1, Integer::sum);
if (!capped && counts.size() >= maxUnique) {
capped = true;
}
}
}
}
}
continue;
}
if (!tooLong) {
if (current.length() < maxLen) {
current.append(ch);
} else {
tooLong = true;
}
}
}
java.util.List<java.util.Map.Entry<String, Integer>> top =
counts.entrySet().stream()
.filter(e -> e.getValue() > 1)
.sorted((a, b) -> Integer.compare(b.getValue(), a.getValue()))
.limit(20)
.toList();
if (!top.isEmpty()) {
String summary =
top.stream()
.map(
e ->
String.format(
"\"%s\"(len=%d,count=%d)",
truncateForLog(e.getKey()),
e.getKey().length(),
e.getValue()))
.collect(java.util.stream.Collectors.joining("; "));
log.info(
"PDF JSON repeat scan ({}): top strings -> {}{}",
label,
summary,
capped ? " (capped)" : "");
} else {
log.info(
"PDF JSON repeat scan ({}): no repeated strings found{}", label, capped ? " (capped)" : "");
}
}
private boolean looksLikeBase64(String value) {
if (value.length() < 32) {
return false;
}
int base64Chars = 0;
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if ((c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| c == '+'
|| c == '/'
|| c == '=') {
base64Chars++;
}
}
return base64Chars >= value.length() * 0.9;
}
private String truncateForLog(String value) {
int max = 64;
if (value.length() <= max) {
return value.replaceAll("[\\r\\n\\t]+", " ");
}
return value.substring(0, max).replaceAll("[\\r\\n\\t]+", " ") + "...";
}
/**
* Validate that the current user has access to the given job.
*
@@ -52,17 +52,9 @@ public class PageNumbersController {
int pageNumber = request.getStartingNumber();
String pagesToNumber = request.getPagesToNumber();
String customText = request.getCustomText();
int zeroPad = request.getZeroPad();
float fontSize = request.getFontSize();
String fontType = request.getFontType();
String fontColor = request.getFontColor();
// compute padded number string where requested
String formatN;
if (zeroPad > 0) {
formatN = String.format("%%0%dd", Math.max(0, zeroPad));
} else {
formatN = "%d";
}
Color color = Color.BLACK;
if (fontColor != null && !fontColor.trim().isEmpty()) {
@@ -101,10 +93,9 @@ public class PageNumbersController {
PDPage page = document.getPage(i);
PDRectangle pageSize = page.getMediaBox();
String nFormatted = String.format(formatN, pageNumber);
String text =
customText
.replace("{n}", nFormatted)
.replace("{n}", String.valueOf(pageNumber))
.replace("{total}", String.valueOf(document.getNumberOfPages()))
.replace(
"{filename}",
@@ -7,13 +7,11 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
@@ -60,13 +58,6 @@ public class StampController {
private final CustomPDFDocumentFactory pdfDocumentFactory;
private final TempFileManager tempFileManager;
private static final int MAX_DATE_FORMAT_LENGTH = 50;
private static final Pattern SAFE_DATE_FORMAT_PATTERN =
Pattern.compile("^[yMdHhmsS/\\-:\\s.,'+EGuwWDFzZXa]+$");
private static final Pattern CUSTOM_DATE_PATTERN = Pattern.compile("@date\\{([^}]{1,50})\\}");
// Placeholder for escaped @ symbol (using Unicode private use area)
private static final String ESCAPED_AT_PLACEHOLDER = "\uE000ESCAPED_AT\uE000";
/**
* Initialize data binder for multipart file uploads. This method registers a custom editor for
* MultipartFile to handle file uploads. It sets the MultipartFile to null if the uploaded file
@@ -175,9 +166,7 @@ public class StampController {
overrideX,
overrideY,
margin,
customColor,
pageIndex,
pdfFileName);
customColor);
} else if ("image".equalsIgnoreCase(stampType)) {
addImageStamp(
contentStream,
@@ -212,11 +201,9 @@ public class StampController {
float fontSize,
String alphabet,
float overrideX, // X override
float overrideY, // Y override
float overrideY,
float margin,
String colorString,
int currentPageNumber,
String filename)
String colorString) // Y override
throws IOException {
String resourceDir;
PDFont font = new PDType1Font(Standard14Fonts.FontName.HELVETICA);
@@ -244,6 +231,8 @@ public class StampController {
}
}
contentStream.setFont(font, fontSize);
Color redactColor;
try {
if (!colorString.startsWith("#")) {
@@ -251,54 +240,47 @@ public class StampController {
}
redactColor = Color.decode(colorString);
} catch (NumberFormatException e) {
redactColor = Color.LIGHT_GRAY;
}
contentStream.setNonStrokingColor(redactColor);
PDRectangle pageSize = page.getMediaBox();
float x, y;
if (overrideX >= 0 && overrideY >= 0) {
// Use override values if provided
x = overrideX;
y = overrideY;
} else {
x = calculatePositionX(pageSize, position, fontSize, font, fontSize, stampText, margin);
y =
calculatePositionY(
pageSize, position, calculateTextCapHeight(font, fontSize), margin);
}
String currentDate = LocalDate.now().toString();
String currentTime = LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
int pageCount = document.getNumberOfPages();
String processedStampText =
processStampText(stampText, currentPageNumber, pageCount, filename, document);
stampText
.replace("@date", currentDate)
.replace("@time", currentTime)
.replace("@page_count", String.valueOf(pageCount));
String normalizedText =
// Split the stampText into multiple lines
String[] lines =
RegexPatternUtils.getInstance()
.getEscapedNewlinePattern()
.matcher(processedStampText)
.replaceAll("\n");
String[] lines = normalizedText.split("\\r?\\n");
PDRectangle pageSize = page.getMediaBox();
// Use fontSize directly (default 40 if not specified)
float effectiveFontSize = fontSize > 0 ? fontSize : 40f;
contentStream.setFont(font, effectiveFontSize);
.split(processedStampText);
// Calculate dynamic line height based on font ascent and descent
float ascent = font.getFontDescriptor().getAscent();
float descent = font.getFontDescriptor().getDescent();
float lineHeight = ((ascent - descent) / 1000) * effectiveFontSize;
float maxLineWidth = 0;
for (String line : lines) {
float lineWidth = calculateTextWidth(line, font, effectiveFontSize);
if (lineWidth > maxLineWidth) {
maxLineWidth = lineWidth;
}
}
float totalTextHeight = lines.length * lineHeight;
float x, y;
if (overrideX >= 0 && overrideY >= 0) {
x = overrideX;
y = overrideY;
} else {
x = calculatePositionX(pageSize, position, maxLineWidth, margin);
y = calculatePositionY(pageSize, position, totalTextHeight, margin);
}
float lineHeight = ((ascent - descent) / 1000) * fontSize;
contentStream.beginText();
for (int i = 0; i < lines.length; i++) {
@@ -311,140 +293,6 @@ public class StampController {
contentStream.endText();
}
/**
* Process stamp text by replacing all @commands with their actual values. Supported commands:
*
* <p>Date & Time:
*
* <ul>
* <li>@date - Current date (YYYY-MM-DD)
* <li>@time - Current time (HH:mm:ss)
* <li>@datetime - Current date and time (YYYY-MM-DD HH:mm:ss)
* <li>@date{format} - Custom date/time format (e.g., @date{dd/MM/yyyy})
* <li>@year - Current year (4 digits)
* <li>@month - Current month (01-12)
* <li>@day - Current day of month (01-31)
* </ul>
*
* <p>Page Information:
*
* <ul>
* <li>@page_number or @page - Current page number
* <li>@total_pages or @page_count - Total number of pages
* </ul>
*
* <p>File Information:
*
* <ul>
* <li>@filename - Original filename (without extension)
* <li>@filename_full - Original filename (with extension)
* </ul>
*
* <p>Document Metadata:
*
* <ul>
* <li>@author - Document author (from PDF metadata)
* <li>@title - Document title (from PDF metadata)
* <li>@subject - Document subject (from PDF metadata)
* </ul>
*
* <p>Other:
*
* <ul>
* <li>@uuid - Short unique identifier (8 characters)
* </ul>
*/
private String processStampText(
String stampText,
int currentPageNumber,
int totalPages,
String filename,
PDDocument document) {
if (stampText == null || stampText.isEmpty()) {
return "";
}
// Handle escaped @@ sequences first - replace with placeholder to preserve literal @
String result = stampText.replace("@@", ESCAPED_AT_PLACEHOLDER);
LocalDateTime now = LocalDateTime.now();
String currentDate = now.toLocalDate().toString();
String currentTime = now.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
String currentDateTime = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
String filenameWithoutExt = filename != null ? filename : "";
if (filename != null && filename.contains(".")) {
int lastDot = filename.lastIndexOf('.');
if (lastDot > 0) { // Ensure there's actually a name before the dot
filenameWithoutExt = filename.substring(0, lastDot);
}
}
String author = "";
String title = "";
String subject = "";
if (document != null && document.getDocumentInformation() != null) {
var info = document.getDocumentInformation();
author = info.getAuthor() != null ? info.getAuthor() : "";
title = info.getTitle() != null ? info.getTitle() : "";
subject = info.getSubject() != null ? info.getSubject() : "";
}
String uuid = UUID.randomUUID().toString().substring(0, 8);
// Process @date{format} with custom format first (must be before simple @date)
Matcher matcher = CUSTOM_DATE_PATTERN.matcher(result);
StringBuilder sb = new StringBuilder();
while (matcher.find()) {
String format = matcher.group(1);
String replacement = processCustomDateFormat(format, now);
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(sb);
result = sb.toString();
result =
result.replace("@datetime", currentDateTime)
.replace("@date", currentDate)
.replace("@time", currentTime)
.replace("@year", String.valueOf(now.getYear()))
.replace("@month", String.format("%02d", now.getMonthValue()))
.replace("@day", String.format("%02d", now.getDayOfMonth()))
.replace("@page_number", String.valueOf(currentPageNumber))
.replace(
"@page_count", String.valueOf(totalPages)) // Must come before @page
.replace("@total_pages", String.valueOf(totalPages))
.replace(
"@page",
String.valueOf(currentPageNumber)) // Must come after @page_count
.replace("@filename_full", filename != null ? filename : "")
.replace("@filename", filenameWithoutExt)
.replace("@author", author)
.replace("@title", title)
.replace("@subject", subject)
.replace("@uuid", uuid);
result = result.replace(ESCAPED_AT_PLACEHOLDER, "@");
return result;
}
private String processCustomDateFormat(String format, LocalDateTime now) {
if (format == null || format.length() > MAX_DATE_FORMAT_LENGTH) {
return "[invalid format: too long]";
}
if (!SAFE_DATE_FORMAT_PATTERN.matcher(format).matches()) {
return "[invalid format]";
}
try {
return now.format(DateTimeFormatter.ofPattern(format));
} catch (IllegalArgumentException e) {
return "[invalid format: " + format + "]";
}
}
private void addImageStamp(
PDPageContentStream contentStream,
MultipartFile stampImage,
@@ -481,8 +329,8 @@ public class StampController {
x = overrideX;
y = overrideY;
} else {
x = calculatePositionX(pageSize, position, desiredPhysicalWidth, margin);
y = calculatePositionY(pageSize, position, desiredPhysicalHeight, margin);
x = calculatePositionX(pageSize, position, desiredPhysicalWidth, null, 0, null, margin);
y = calculatePositionY(pageSize, position, fontSize, margin);
}
contentStream.saveGraphicsState();
@@ -493,14 +341,23 @@ public class StampController {
}
private float calculatePositionX(
PDRectangle pageSize, int position, float contentWidth, float margin) {
PDRectangle pageSize,
int position,
float contentWidth,
PDFont font,
float fontSize,
String text,
float margin)
throws IOException {
float actualWidth =
(text != null) ? calculateTextWidth(text, font, fontSize) : contentWidth;
return switch (position % 3) {
case 1: // Left
yield pageSize.getLowerLeftX() + margin;
case 2: // Center
yield (pageSize.getWidth() - contentWidth) / 2;
yield (pageSize.getWidth() - actualWidth) / 2;
case 0: // Right
yield pageSize.getUpperRightX() - contentWidth - margin;
yield pageSize.getUpperRightX() - actualWidth - margin;
default:
yield 0;
};
@@ -509,12 +366,12 @@ public class StampController {
private float calculatePositionY(
PDRectangle pageSize, int position, float height, float margin) {
return switch ((position - 1) / 3) {
case 0: // Top - first line near the top
yield pageSize.getUpperRightY() - margin;
case 1: // Middle - center of text block at page center
yield (pageSize.getHeight() + height) / 2;
case 2: // Bottom - first line positioned so last line is at bottom margin
yield pageSize.getLowerLeftY() + margin + height;
case 0: // Top
yield pageSize.getUpperRightY() - height - margin;
case 1: // Middle
yield (pageSize.getHeight() - height) / 2;
case 2: // Bottom
yield pageSize.getLowerLeftY() + margin;
default:
yield 0;
};
@@ -523,4 +380,8 @@ public class StampController {
private float calculateTextWidth(String text, PDFont font, float fontSize) throws IOException {
return font.getStringWidth(text) / 1000 * fontSize;
}
private float calculateTextCapHeight(PDFont font, float fontSize) {
return font.getFontDescriptor().getCapHeight() / 1000 * fontSize;
}
}
@@ -3,7 +3,6 @@ package stirling.software.SPDF.controller.api.pipeline;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystemException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -15,7 +14,6 @@ import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -43,20 +41,14 @@ import stirling.software.common.util.FileMonitor;
@Slf4j
public class PipelineDirectoryProcessor {
private static final int MAX_DIRECTORY_DEPTH = 50; // Prevent excessive recursion
private final ObjectMapper objectMapper;
private final ApiDocService apiDocService;
private final PipelineProcessor processor;
private final FileMonitor fileMonitor;
private final PostHogService postHogService;
private final List<String> watchedFoldersDirs;
private final String watchedFoldersDir;
private final String finishedFoldersDir;
// Track processed directories in current scan to prevent duplicates
private final ThreadLocal<java.util.Set<Path>> processedDirsInScan =
ThreadLocal.withInitial(java.util.HashSet::new);
public PipelineDirectoryProcessor(
ObjectMapper objectMapper,
ApiDocService apiDocService,
@@ -69,26 +61,13 @@ public class PipelineDirectoryProcessor {
this.processor = processor;
this.fileMonitor = fileMonitor;
this.postHogService = postHogService;
this.watchedFoldersDirs = runtimePathConfig.getPipelineWatchedFoldersPaths();
this.watchedFoldersDir = runtimePathConfig.getPipelineWatchedFoldersPath();
this.finishedFoldersDir = runtimePathConfig.getPipelineFinishedFoldersPath();
}
@Scheduled(fixedRate = 60000)
public void scanFolders() {
// Clear the processed directories set for this scan cycle
processedDirsInScan.get().clear();
try {
for (String watchedFoldersDir : watchedFoldersDirs) {
scanWatchedFolder(Paths.get(watchedFoldersDir).toAbsolutePath());
}
} finally {
// Clean up ThreadLocal to prevent memory leaks
processedDirsInScan.remove();
}
}
private void scanWatchedFolder(Path watchedFolderPath) {
Path watchedFolderPath = Paths.get(watchedFoldersDir).toAbsolutePath();
if (!Files.exists(watchedFolderPath)) {
try {
Files.createDirectories(watchedFolderPath);
@@ -99,34 +78,16 @@ public class PipelineDirectoryProcessor {
}
}
// Validate the path is a directory and readable
if (!Files.isDirectory(watchedFolderPath)) {
log.error("Path is not a directory: {}", watchedFolderPath);
return;
}
if (!Files.isReadable(watchedFolderPath)) {
log.error("Directory is not readable: {}", watchedFolderPath);
return;
}
try {
// Use FOLLOW_LINKS to follow symlinks, with max depth to prevent infinite loops
Files.walkFileTree(
watchedFolderPath,
EnumSet.of(FileVisitOption.FOLLOW_LINKS),
MAX_DIRECTORY_DEPTH,
new SimpleFileVisitor<>() {
@Override
public FileVisitResult preVisitDirectory(
Path dir, BasicFileAttributes attrs) {
try {
String dirName =
dir.getFileName() != null
? dir.getFileName().toString()
: "";
// Skip root directory and "processing" subdirectories
if (!dir.equals(watchedFolderPath)
&& !"processing".equals(dirName)) {
if (!dir.equals(watchedFolderPath) && !dir.endsWith("processing")) {
handleDirectory(dir);
}
} catch (Exception e) {
@@ -137,11 +98,8 @@ public class PipelineDirectoryProcessor {
@Override
public FileVisitResult visitFileFailed(Path path, IOException exc) {
// Handle broken symlinks, permission issues, or inaccessible
// directories
if (exc != null) {
log.debug("Cannot access path '{}': {}", path, exc.getMessage());
}
// Handle broken symlinks or inaccessible directories
log.error("Error accessing path: {}", path, exc);
return FileVisitResult.CONTINUE;
}
});
@@ -151,17 +109,6 @@ public class PipelineDirectoryProcessor {
}
public void handleDirectory(Path dir) throws IOException {
// Normalize path to absolute to prevent duplicate processing from different path
// representations
Path normalizedDir = dir.toAbsolutePath().normalize();
// Check if we've already processed this directory in this scan cycle
java.util.Set<Path> processedDirs = processedDirsInScan.get();
if (!processedDirs.add(normalizedDir)) {
log.debug("Directory already processed in this scan cycle: {}", normalizedDir);
return;
}
log.info("Handling directory: {}", dir);
Path processingDir = createProcessingDirectory(dir);
Optional<Path> jsonFileOptional = findJsonFile(dir);
@@ -16,9 +16,4 @@ public class PdfToPdfARequest extends PDFFile {
requiredMode = Schema.RequiredMode.REQUIRED,
allowableValues = {"pdfa", "pdfa-1", "pdfa-2", "pdfa-2b", "pdfa-3", "pdfa-3b", "pdfx"})
private String outputFormat;
@Schema(
description =
"If true, the conversion will fail if the output is not perfectly compliant")
private Boolean strict = false;
}
@@ -39,14 +39,6 @@ public class AddPageNumbersRequest extends PDFWithPageNums {
requiredMode = RequiredMode.NOT_REQUIRED)
private String fontColor;
@Schema(
description =
"Zero-padding width for page numbers (Bates Stamping). Set to 0 to disable padding",
minimum = "0",
defaultValue = "0",
requiredMode = RequiredMode.NOT_REQUIRED)
private int zeroPad = 0;
@Schema(
description =
"Position: 1-9 representing positions on the page (1=top-left, 2=top-center,"
@@ -32,8 +32,8 @@ public class AddStampRequest extends PDFWithPageNums {
private String alphabet = "roman";
@Schema(
description = "The font size of the stamp text and image in points.",
defaultValue = "40",
description = "The font size of the stamp text and image",
defaultValue = "30",
requiredMode = Schema.RequiredMode.REQUIRED)
private float fontSize;
@@ -427,9 +427,8 @@ public class PdfJsonConversionService {
progress.accept(
PdfJsonConversionProgress.of(
80, "annotations", "Collecting annotations and form fields"));
boolean includeAnnotationRawData = !(lightweight && isRealJobId);
Map<Integer, List<PdfJsonAnnotation>> annotationsByPage =
collectAnnotations(document, totalPages, progress, includeAnnotationRawData);
collectAnnotations(document, totalPages, progress);
progress.accept(
PdfJsonConversionProgress.of(90, "metadata", "Extracting metadata"));
@@ -442,15 +441,9 @@ public class PdfJsonConversionService {
Comparator.comparing(
PdfJsonFont::getUid,
Comparator.nullsLast(Comparator.naturalOrder())));
dedupeFontPayloads(serializedFonts);
pdfJson.setFonts(serializedFonts);
pdfJson.setPages(
extractPages(
document,
textByPage,
imagesByPage,
annotationsByPage,
lightweight && isRealJobId));
extractPages(document, textByPage, imagesByPage, annotationsByPage));
pdfJson.setFormFields(collectFormFields(document));
// Only cache for real async jobIds, not synthetic synchronous ones
@@ -514,12 +507,6 @@ public class PdfJsonConversionService {
if (lightweight) {
applyLightweightTransformations(pdfJson);
}
if (lightweight && isRealJobId) {
stripFontCosStreamData(serializedFonts);
}
logFontPayloadStats(serializedFonts, "pdf/text-editor");
analyzePdfJson(pdfJson, "pdf/text-editor");
progress.accept(
PdfJsonConversionProgress.of(95, "serializing", "Generating JSON output"));
@@ -530,9 +517,8 @@ public class PdfJsonConversionService {
.filter(
f ->
Boolean.TRUE.equals(f.getEmbedded())
&& !(hasPayload(f.getProgram())
|| hasPayload(f.getPdfProgram())
|| hasPayload(f.getWebProgram())))
&& (f.getProgram() == null
|| f.getProgram().isEmpty()))
.map(
f -> {
String name =
@@ -1053,376 +1039,6 @@ public class PdfJsonConversionService {
return toPdfJsonFont(cacheEntry, fontId, pageNumber, jobId);
}
private void logFontPayloadStats(List<PdfJsonFont> fonts, String label) {
if (fonts == null || fonts.isEmpty()) {
return;
}
long programBytes = 0;
long webProgramBytes = 0;
long pdfProgramBytes = 0;
long toUnicodeBytes = 0;
long maxFontPayload = 0;
String maxFontId = null;
for (PdfJsonFont font : fonts) {
if (font == null) {
continue;
}
long fontBytes = 0;
if (font.getProgram() != null) {
long len = font.getProgram().length();
programBytes += len;
fontBytes += len;
}
if (font.getWebProgram() != null) {
long len = font.getWebProgram().length();
webProgramBytes += len;
fontBytes += len;
}
if (font.getPdfProgram() != null) {
long len = font.getPdfProgram().length();
pdfProgramBytes += len;
fontBytes += len;
}
if (font.getToUnicode() != null) {
long len = font.getToUnicode().length();
toUnicodeBytes += len;
fontBytes += len;
}
if (fontBytes > maxFontPayload) {
maxFontPayload = fontBytes;
maxFontId = font.getUid() != null ? font.getUid() : font.getId();
}
}
log.info(
"Font payload stats ({}): fonts={}, programBytes={}, webProgramBytes={}, pdfProgramBytes={}, toUnicodeBytes={}, maxFontPayloadBytes={} (fontId={})",
label,
fonts.size(),
programBytes,
webProgramBytes,
pdfProgramBytes,
toUnicodeBytes,
maxFontPayload,
maxFontId);
}
private void analyzePdfJson(PdfJsonDocument pdfJson, String label) {
if (!isPdfJsonDebugAnalyzeEnabled() || pdfJson == null) {
return;
}
try {
Map<String, DuplicateStats> resourceStats = new HashMap<>();
Map<String, DuplicateStats> fontDictStats = new HashMap<>();
Map<String, DuplicateStats> annotationStats = new HashMap<>();
long imageDataBytes = 0;
long imageCount = 0;
long textElementCount = 0;
long textCharCount = 0;
List<PdfJsonPage> pages = pdfJson.getPages();
if (pages != null) {
for (PdfJsonPage page : pages) {
if (page == null) {
continue;
}
recordDuplicate(resourceStats, page.getResources());
List<PdfJsonAnnotation> annotations = page.getAnnotations();
if (annotations != null) {
for (PdfJsonAnnotation annotation : annotations) {
recordDuplicate(annotationStats, annotation.getRawData());
}
}
List<PdfJsonImageElement> images = page.getImageElements();
if (images != null) {
for (PdfJsonImageElement image : images) {
if (image == null) {
continue;
}
String data = image.getImageData();
if (data != null) {
imageDataBytes += data.length();
}
imageCount++;
}
}
List<PdfJsonTextElement> textElements = page.getTextElements();
if (textElements != null) {
for (PdfJsonTextElement element : textElements) {
if (element == null) {
continue;
}
textElementCount++;
String text = element.getText();
if (text != null) {
textCharCount += text.length();
}
}
}
}
}
List<PdfJsonFont> fonts = pdfJson.getFonts();
if (fonts != null) {
for (PdfJsonFont font : fonts) {
recordDuplicate(fontDictStats, font.getCosDictionary());
}
}
logDuplicateSummary("resources", label, resourceStats);
logDuplicateSummary("fontCosDictionary", label, fontDictStats);
logDuplicateSummary("annotationRawData", label, annotationStats);
log.info(
"PDF JSON analysis ({}): images={} imageDataBytes={} textElements={} textChars={}",
label,
imageCount,
imageDataBytes,
textElementCount,
textCharCount);
long fontsBytes = sizeOfObject(pdfJson.getFonts());
long pagesBytes = sizeOfObject(pdfJson.getPages());
long metadataBytes = sizeOfObject(pdfJson.getMetadata());
long xmpBytes = sizeOfObject(pdfJson.getXmpMetadata());
long formFieldsBytes = sizeOfObject(pdfJson.getFormFields());
log.info(
"PDF JSON analysis ({}): sectionSizes fonts={} pages={} metadata={} xmp={} formFields={}",
label,
fontsBytes,
pagesBytes,
metadataBytes,
xmpBytes,
formFieldsBytes);
if (pages != null && !pages.isEmpty()) {
List<PageSizeStat> topPages = new ArrayList<>();
int pageIndex = 0;
for (PdfJsonPage page : pages) {
if (page == null) {
pageIndex++;
continue;
}
long size = sizeOfObject(page);
int pageNumber =
page.getPageNumber() != null ? page.getPageNumber() : pageIndex + 1;
topPages.add(new PageSizeStat(pageNumber, size, page));
pageIndex++;
}
topPages.sort((a, b) -> Long.compare(b.sizeBytes, a.sizeBytes));
String top =
topPages.stream()
.limit(5)
.map(
s ->
String.format(
"page=%d size=%d", s.pageNumber, s.sizeBytes))
.collect(java.util.stream.Collectors.joining("; "));
log.info("PDF JSON analysis ({}): topPageSizes -> {}", label, top);
topPages.stream()
.limit(3)
.forEach(
s -> {
PdfJsonPage page = s.page;
long resources = sizeOfObject(page.getResources());
long contentStreams = sizeOfObject(page.getContentStreams());
long annotations = sizeOfObject(page.getAnnotations());
long textElements = sizeOfObject(page.getTextElements());
long imageElements = sizeOfObject(page.getImageElements());
log.info(
"PDF JSON analysis ({}): pageBreakdown page={} total={} resources={} contentStreams={} annotations={} textElements={} imageElements={}",
label,
s.pageNumber,
s.sizeBytes,
resources,
contentStreams,
annotations,
textElements,
imageElements);
});
}
} catch (Exception ex) {
log.warn("PDF JSON analysis failed ({}): {}", label, ex.getMessage());
}
}
private void recordDuplicate(Map<String, DuplicateStats> stats, PdfJsonCosValue value)
throws IOException, java.security.NoSuchAlgorithmException {
if (value == null) {
return;
}
byte[] bytes = objectMapper.writeValueAsBytes(value);
if (bytes.length == 0) {
return;
}
String hash = Base64.getEncoder().encodeToString(
java.security.MessageDigest.getInstance("SHA-256").digest(bytes));
DuplicateStats entry = stats.computeIfAbsent(hash, k -> new DuplicateStats());
entry.count++;
if (entry.sizeBytes == 0) {
entry.sizeBytes = bytes.length;
}
}
private void logDuplicateSummary(
String category, String label, Map<String, DuplicateStats> stats) {
if (stats.isEmpty()) {
return;
}
List<DuplicateStats> duplicates =
stats.values().stream()
.filter(s -> s.count > 1)
.sorted(
(a, b) ->
Long.compare(
b.totalBytesSaved(), a.totalBytesSaved()))
.limit(5)
.toList();
if (duplicates.isEmpty()) {
return;
}
String summary =
duplicates.stream()
.map(
s ->
String.format(
"count=%d size=%d potentialSavings=%d",
s.count, s.sizeBytes, s.totalBytesSaved()))
.collect(java.util.stream.Collectors.joining("; "));
log.info(
"PDF JSON analysis ({}): top duplicates for {} -> {}",
label,
category,
summary);
}
private boolean isPdfJsonDebugAnalyzeEnabled() {
String env = System.getenv("SPDF_PDFJSON_ANALYZE");
if (env != null && env.equalsIgnoreCase("true")) {
return true;
}
return Boolean.getBoolean("spdf.pdfjson.analyze");
}
private long sizeOfObject(Object value) {
if (value == null) {
return 0;
}
try {
return objectMapper.writeValueAsBytes(value).length;
} catch (Exception ex) {
log.warn("Failed to serialize object for size analysis: {}", ex.getMessage());
return -1;
}
}
private static final class DuplicateStats {
private int count;
private long sizeBytes;
private long totalBytesSaved() {
return sizeBytes * (long) (count - 1);
}
}
private static final class PageSizeStat {
private final int pageNumber;
private final long sizeBytes;
private final PdfJsonPage page;
private PageSizeStat(int pageNumber, long sizeBytes, PdfJsonPage page) {
this.pageNumber = pageNumber;
this.sizeBytes = sizeBytes;
this.page = page;
}
}
private void dedupeFontPayloads(List<PdfJsonFont> fonts) {
if (fonts == null || fonts.isEmpty()) {
return;
}
for (PdfJsonFont font : fonts) {
if (font == null) {
continue;
}
String program = font.getProgram();
String pdfProgram = font.getPdfProgram();
String webProgram = font.getWebProgram();
if (pdfProgram != null && !pdfProgram.isBlank()) {
if (program != null && program.equals(pdfProgram)) {
font.setProgram(null);
font.setProgramFormat(null);
}
if (webProgram != null && webProgram.equals(pdfProgram)) {
font.setWebProgram(null);
font.setWebProgramFormat(null);
}
continue;
}
if (program != null && webProgram != null && program.equals(webProgram)) {
font.setWebProgram(null);
font.setWebProgramFormat(null);
}
}
}
private void stripFontCosStreamData(List<PdfJsonFont> fonts) {
if (fonts == null || fonts.isEmpty()) {
return;
}
Set<PdfJsonCosValue> visited =
Collections.newSetFromMap(new IdentityHashMap<>());
for (PdfJsonFont font : fonts) {
if (font == null) {
continue;
}
PdfJsonCosValue cosDictionary = font.getCosDictionary();
if (cosDictionary != null) {
stripStreamRawData(cosDictionary, visited);
}
}
}
private void stripStreamRawData(PdfJsonCosValue value, Set<PdfJsonCosValue> visited) {
if (value == null || value.getType() == null) {
return;
}
if (!visited.add(value)) {
return;
}
switch (value.getType()) {
case STREAM:
if (value.getStream() != null) {
value.getStream().setRawData(null);
}
break;
case ARRAY:
if (value.getItems() != null) {
for (PdfJsonCosValue item : value.getItems()) {
stripStreamRawData(item, visited);
}
}
break;
case DICTIONARY:
if (value.getEntries() != null) {
for (PdfJsonCosValue entry : value.getEntries().values()) {
stripStreamRawData(entry, visited);
}
}
break;
default:
break;
}
}
private FontModelCacheEntry createFontCacheEntry(
PDDocument document, PDFont font, String fontId, int pageNumber, String jobId)
throws IOException {
@@ -2359,8 +1975,7 @@ public class PdfJsonConversionService {
PDDocument document,
Map<Integer, List<PdfJsonTextElement>> textByPage,
Map<Integer, List<PdfJsonImageElement>> imagesByPage,
Map<Integer, List<PdfJsonAnnotation>> annotationsByPage,
boolean omitResourceStreamData)
Map<Integer, List<PdfJsonAnnotation>> annotationsByPage)
throws IOException {
List<PdfJsonPage> pages = new ArrayList<>();
int pageIndex = 0;
@@ -2383,14 +1998,8 @@ public class PdfJsonConversionService {
// imageElements
COSBase resourcesBase = page.getCOSObject().getDictionaryObject(COSName.RESOURCES);
COSBase filteredResources = filterImageXObjectsFromResources(resourcesBase);
PdfJsonCosValue resourcesModel =
omitResourceStreamData
? cosMapper.serializeCosValue(
filteredResources,
PdfJsonCosMapper.SerializationContext.RESOURCES_LIGHTWEIGHT)
: cosMapper.serializeCosValue(filteredResources);
pageModel.setResources(resourcesModel);
pageModel.setContentStreams(extractContentStreams(page, true));
pageModel.setResources(cosMapper.serializeCosValue(filteredResources));
pageModel.setContentStreams(extractContentStreams(page));
pages.add(pageModel);
pageIndex++;
}
@@ -2421,10 +2030,7 @@ public class PdfJsonConversionService {
}
private Map<Integer, List<PdfJsonAnnotation>> collectAnnotations(
PDDocument document,
int totalPages,
Consumer<PdfJsonConversionProgress> progress,
boolean includeRawData)
PDDocument document, int totalPages, Consumer<PdfJsonConversionProgress> progress)
throws IOException {
Map<Integer, List<PdfJsonAnnotation>> annotationsByPage = new LinkedHashMap<>();
int pageNumber = 1;
@@ -2496,13 +2102,8 @@ public class PdfJsonConversionService {
}
}
if (includeRawData) {
// Store raw dictionary for lossless round-trip
ann.setRawData(
cosMapper.serializeCosValue(
annotDict,
PdfJsonCosMapper.SerializationContext.ANNOTATION_RAW_DATA));
}
// Store raw dictionary for lossless round-trip
ann.setRawData(cosMapper.serializeCosValue(annotDict));
annotations.add(ann);
} catch (Exception e) {
@@ -2582,10 +2183,7 @@ public class PdfJsonConversionService {
}
// Store raw dictionary for lossless round-trip
formField.setRawData(
cosMapper.serializeCosValue(
field.getCOSObject(),
PdfJsonCosMapper.SerializationContext.FORM_FIELD_RAW_DATA));
formField.setRawData(cosMapper.serializeCosValue(field.getCOSObject()));
formFields.add(formField);
} catch (Exception e) {
@@ -2919,8 +2517,7 @@ public class PdfJsonConversionService {
return streams;
}
private List<PdfJsonStream> extractContentStreams(PDPage page, boolean omitRawData)
throws IOException {
private List<PdfJsonStream> extractContentStreams(PDPage page) throws IOException {
List<PdfJsonStream> streams = new ArrayList<>();
Iterator<PDStream> iterator = page.getContentStreams();
if (iterator == null) {
@@ -2928,13 +2525,7 @@ public class PdfJsonConversionService {
}
while (iterator.hasNext()) {
PDStream stream = iterator.next();
PdfJsonStream model =
omitRawData
? cosMapper.serializeStream(
stream,
PdfJsonCosMapper.SerializationContext
.CONTENT_STREAMS_LIGHTWEIGHT)
: cosMapper.serializeStream(stream);
PdfJsonStream model = cosMapper.serializeStream(stream);
if (model != null) {
streams.add(model);
}
@@ -2942,10 +2533,6 @@ public class PdfJsonConversionService {
return streams;
}
private List<PdfJsonStream> extractContentStreams(PDPage page) throws IOException {
return extractContentStreams(page, false);
}
private PDStream extractVectorGraphics(
PDDocument document,
List<PDStream> preservedStreams,
@@ -6064,8 +5651,6 @@ public class PdfJsonConversionService {
serializedFonts.sort(
Comparator.comparing(
PdfJsonFont::getUid, Comparator.nullsLast(Comparator.naturalOrder())));
dedupeFontPayloads(serializedFonts);
stripFontCosStreamData(serializedFonts);
docMetadata.setFonts(serializedFonts);
// Extract page dimensions
@@ -6231,7 +5816,7 @@ public class PdfJsonConversionService {
}
}
// For cached page extraction, skip rawData to avoid huge payloads
ann.setRawData(cosMapper.serializeCosValue(annotDict));
annotations.add(ann);
} catch (Exception e) {
log.warn(
@@ -6254,11 +5839,8 @@ public class PdfJsonConversionService {
// Extract resources and content streams
COSBase resourcesBase = page.getCOSObject().getDictionaryObject(COSName.RESOURCES);
COSBase filteredResources = filterImageXObjectsFromResources(resourcesBase);
pageModel.setResources(
cosMapper.serializeCosValue(
filteredResources,
PdfJsonCosMapper.SerializationContext.RESOURCES_LIGHTWEIGHT));
pageModel.setContentStreams(extractContentStreams(page, true));
pageModel.setResources(cosMapper.serializeCosValue(filteredResources));
pageModel.setContentStreams(extractContentStreams(page));
log.debug(
"Extracted page {} (text: {}, images: {}, annotations: {}) for jobId: {}",
@@ -6463,12 +6045,6 @@ public class PdfJsonConversionService {
List<PdfJsonFont> fontModels,
int pageNumberValue)
throws IOException {
boolean preserveExistingAnnotations =
shouldPreserveExistingAnnotations(pageModel.getAnnotations());
boolean preserveExistingContentStreams =
shouldPreserveExistingContentStreams(pageModel.getContentStreams());
boolean preserveExistingResources = shouldPreserveExistingResources(pageModel.getResources());
PDRectangle currentBox = page.getMediaBox();
float fallbackWidth = currentBox != null ? currentBox.getWidth() : 612f;
float fallbackHeight = currentBox != null ? currentBox.getHeight() : 792f;
@@ -6483,20 +6059,14 @@ public class PdfJsonConversionService {
page.setRotation(pageModel.getRotation());
}
if (!preserveExistingResources) {
applyPageResources(document, page, pageModel.getResources());
}
applyPageResources(document, page, pageModel.getResources());
List<PDStream> preservedStreams;
if (preserveExistingContentStreams) {
preservedStreams = snapshotExistingContentStreams(page);
List<PDStream> preservedStreams =
buildContentStreams(document, pageModel.getContentStreams());
if (preservedStreams.isEmpty()) {
page.setContents(new ArrayList<>());
} else {
preservedStreams = buildContentStreams(document, pageModel.getContentStreams());
if (preservedStreams.isEmpty()) {
page.setContents(new ArrayList<>());
} else {
page.setContents(preservedStreams);
}
page.setContents(preservedStreams);
}
List<PdfJsonImageElement> imageElements =
@@ -6536,14 +6106,12 @@ public class PdfJsonConversionService {
pageNumberValue);
if (regenerateMode == RegenerateMode.REUSE_EXISTING) {
if (!preserveExistingAnnotations) {
page.getAnnotations().clear();
List<PdfJsonAnnotation> annotations =
pageModel.getAnnotations() != null
? new ArrayList<>(pageModel.getAnnotations())
: new ArrayList<>();
restoreAnnotations(document, page, annotations);
}
page.getAnnotations().clear();
List<PdfJsonAnnotation> annotations =
pageModel.getAnnotations() != null
? new ArrayList<>(pageModel.getAnnotations())
: new ArrayList<>();
restoreAnnotations(document, page, annotations);
return;
}
@@ -6572,14 +6140,12 @@ public class PdfJsonConversionService {
pageNumberValue,
appendMode);
if (!preserveExistingAnnotations) {
page.getAnnotations().clear();
List<PdfJsonAnnotation> annotations =
pageModel.getAnnotations() != null
? new ArrayList<>(pageModel.getAnnotations())
: new ArrayList<>();
restoreAnnotations(document, page, annotations);
}
page.getAnnotations().clear();
List<PdfJsonAnnotation> annotations =
pageModel.getAnnotations() != null
? new ArrayList<>(pageModel.getAnnotations())
: new ArrayList<>();
restoreAnnotations(document, page, annotations);
}
private RegenerateMode determineRegenerateMode(
@@ -6626,83 +6192,6 @@ public class PdfJsonConversionService {
REGENERATE_CLEAR
}
private boolean shouldPreserveExistingAnnotations(List<PdfJsonAnnotation> annotations) {
if (annotations == null || annotations.isEmpty()) {
return true;
}
for (PdfJsonAnnotation annotation : annotations) {
if (annotation == null || annotation.getRawData() == null) {
return true;
}
if (hasMissingStreamData(annotation.getRawData())) {
return true;
}
}
return false;
}
private boolean shouldPreserveExistingContentStreams(List<PdfJsonStream> streams) {
if (streams == null || streams.isEmpty()) {
return false;
}
for (PdfJsonStream stream : streams) {
if (stream == null || stream.getRawData() == null) {
return true;
}
}
return false;
}
private boolean shouldPreserveExistingResources(PdfJsonCosValue resources) {
return hasMissingStreamData(resources);
}
private List<PDStream> snapshotExistingContentStreams(PDPage page) throws IOException {
List<PDStream> streams = new ArrayList<>();
Iterator<PDStream> iterator = page.getContentStreams();
if (iterator == null) {
return streams;
}
while (iterator.hasNext()) {
PDStream stream = iterator.next();
if (stream != null) {
streams.add(stream);
}
}
return streams;
}
private boolean hasMissingStreamData(PdfJsonCosValue value) {
if (value == null || value.getType() == null) {
return false;
}
switch (value.getType()) {
case STREAM:
PdfJsonStream stream = value.getStream();
return stream == null || stream.getRawData() == null;
case ARRAY:
if (value.getItems() != null) {
for (PdfJsonCosValue item : value.getItems()) {
if (hasMissingStreamData(item)) {
return true;
}
}
}
return false;
case DICTIONARY:
if (value.getEntries() != null) {
for (PdfJsonCosValue entry : value.getEntries().values()) {
if (hasMissingStreamData(entry)) {
return true;
}
}
}
return false;
default:
return false;
}
}
/** Schedules automatic cleanup of cached documents after 30 minutes. */
private void scheduleDocumentCleanup(String jobId) {
new Thread(
@@ -37,70 +37,23 @@ import stirling.software.SPDF.model.json.PdfJsonStream;
@Component
public class PdfJsonCosMapper {
public enum SerializationContext {
DEFAULT,
ANNOTATION_RAW_DATA,
FORM_FIELD_RAW_DATA,
CONTENT_STREAMS_LIGHTWEIGHT,
RESOURCES_LIGHTWEIGHT;
public boolean omitStreamData() {
return this != DEFAULT;
}
}
public PdfJsonStream serializeStream(PDStream stream) throws IOException {
if (stream == null) {
return null;
}
return serializeStream(
stream.getCOSObject(),
Collections.newSetFromMap(new IdentityHashMap<>()),
SerializationContext.DEFAULT);
stream.getCOSObject(), Collections.newSetFromMap(new IdentityHashMap<>()));
}
public PdfJsonStream serializeStream(COSStream cosStream) throws IOException {
if (cosStream == null) {
return null;
}
return serializeStream(
cosStream,
Collections.newSetFromMap(new IdentityHashMap<>()),
SerializationContext.DEFAULT);
}
public PdfJsonStream serializeStream(COSStream cosStream, SerializationContext context)
throws IOException {
if (cosStream == null) {
return null;
}
SerializationContext effective =
context != null ? context : SerializationContext.DEFAULT;
return serializeStream(
cosStream, Collections.newSetFromMap(new IdentityHashMap<>()), effective);
}
public PdfJsonStream serializeStream(PDStream stream, SerializationContext context)
throws IOException {
if (stream == null) {
return null;
}
return serializeStream(stream.getCOSObject(), context);
return serializeStream(cosStream, Collections.newSetFromMap(new IdentityHashMap<>()));
}
public PdfJsonCosValue serializeCosValue(COSBase base) throws IOException {
return serializeCosValue(
base,
Collections.newSetFromMap(new IdentityHashMap<>()),
SerializationContext.DEFAULT);
}
public PdfJsonCosValue serializeCosValue(COSBase base, SerializationContext context)
throws IOException {
SerializationContext effective =
context != null ? context : SerializationContext.DEFAULT;
return serializeCosValue(
base, Collections.newSetFromMap(new IdentityHashMap<>()), effective);
return serializeCosValue(base, Collections.newSetFromMap(new IdentityHashMap<>()));
}
public COSBase deserializeCosValue(PdfJsonCosValue value, PDDocument document)
@@ -212,8 +165,8 @@ public class PdfJsonCosMapper {
return cosStream;
}
private PdfJsonCosValue serializeCosValue(
COSBase base, Set<COSBase> visited, SerializationContext context) throws IOException {
private PdfJsonCosValue serializeCosValue(COSBase base, Set<COSBase> visited)
throws IOException {
if (base == null) {
return null;
}
@@ -267,22 +220,21 @@ public class PdfJsonCosMapper {
if (base instanceof COSArray array) {
List<PdfJsonCosValue> items = new ArrayList<>(array.size());
for (COSBase item : array) {
PdfJsonCosValue serialized = serializeCosValue(item, visited, context);
PdfJsonCosValue serialized = serializeCosValue(item, visited);
items.add(serialized);
}
builder.type(PdfJsonCosValue.Type.ARRAY).items(items);
return builder.build();
}
if (base instanceof COSStream stream) {
builder.type(PdfJsonCosValue.Type.STREAM)
.stream(serializeStream(stream, visited, context));
builder.type(PdfJsonCosValue.Type.STREAM).stream(serializeStream(stream, visited));
return builder.build();
}
if (base instanceof COSDictionary dictionary) {
Map<String, PdfJsonCosValue> entries = new LinkedHashMap<>();
for (COSName key : dictionary.keySet()) {
PdfJsonCosValue serialized =
serializeCosValue(dictionary.getDictionaryObject(key), visited, context);
serializeCosValue(dictionary.getDictionaryObject(key), visited);
entries.put(key.getName(), serialized);
}
builder.type(PdfJsonCosValue.Type.DICTIONARY).entries(entries);
@@ -296,23 +248,16 @@ public class PdfJsonCosMapper {
}
}
private PdfJsonStream serializeStream(
COSStream cosStream, Set<COSBase> visited, SerializationContext context)
private PdfJsonStream serializeStream(COSStream cosStream, Set<COSBase> visited)
throws IOException {
Map<String, PdfJsonCosValue> dictionary = new LinkedHashMap<>();
for (COSName key : cosStream.keySet()) {
COSBase value = cosStream.getDictionaryObject(key);
PdfJsonCosValue serialized = serializeCosValue(value, visited, context);
PdfJsonCosValue serialized = serializeCosValue(value, visited);
if (serialized != null) {
dictionary.put(key.getName(), serialized);
}
}
if (context != null && context.omitStreamData()) {
log.debug("Omitting stream rawData during {} serialization", context);
return PdfJsonStream.builder().dictionary(dictionary).rawData(null).build();
}
String rawData = null;
try (InputStream inputStream = cosStream.createRawInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
@@ -26,11 +26,8 @@ spring.mvc.problemdetails.enabled=true
#logging.level.org.springframework=DEBUG
#logging.level.org.springframework.security=DEBUG
# Multipart file size limits
# Can be set via environment variables: SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE and SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE
# Or via SYSTEMFILEUPLOADLIMIT/SYSTEM_MAXFILESIZE which will also set fileUploadLimit in settings.yml
spring.servlet.multipart.max-file-size=${SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE:2000MB}
spring.servlet.multipart.max-request-size=${SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE:2000MB}
spring.servlet.multipart.max-file-size=2000MB
spring.servlet.multipart.max-request-size=2000MB
server.servlet.session.tracking-modes=cookie
server.servlet.context-path=${SYSTEM_ROOTURIPATH:/}
spring.devtools.restart.enabled=true
@@ -81,7 +81,6 @@ security:
revocation:
mode: none # Revocation checking mode: 'none' (disabled), 'ocsp' (OCSP only), 'crl' (CRL only), 'ocsp+crl' (OCSP with CRL fallback)
hardFail: false # Fail validation if revocation status cannot be determined (true=strict, false=soft-fail)
xFrameOptions: DENY # X-Frame-Options header value. Options: 'DENY' (default, prevents all framing), 'SAMEORIGIN' (allows framing from same domain), 'DISABLED' (no X-Frame-Options header sent). Note: automatically set to DISABLED when login is disabled
premium:
key: 00000000-0000-0000-0000-000000000000
@@ -203,9 +202,7 @@ system:
name: postgres # set the name of your database. Should match the name of the database you create
customPaths:
pipeline:
pipelineDir: "" # Defaults to /pipeline
watchedFoldersDir: "" # Defaults to /pipeline/watchedFolders
watchedFoldersDirs: [] # List of watched folder directories. Defaults to watchedFoldersDir or /pipeline/watchedFolders.
finishedFoldersDir: "" # Defaults to /pipeline/finishedFolders
operations:
weasyprint: "" # Defaults to /opt/venv/bin/weasyprint
@@ -1,12 +1,5 @@
{
"dependencies": [
{
"moduleName": "ch.qos.logback:logback-classic",
"moduleUrl": "http://www.qos.ch",
"moduleVersion": "1.5.22",
"moduleLicense": "GNU Lesser General Public License",
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
},
{
"moduleName": "ch.qos.logback:logback-classic",
"moduleUrl": "http://www.qos.ch",
@@ -14,13 +7,6 @@
"moduleLicense": "GNU Lesser General Public License",
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
},
{
"moduleName": "ch.qos.logback:logback-core",
"moduleUrl": "http://www.qos.ch",
"moduleVersion": "1.5.22",
"moduleLicense": "GNU Lesser General Public License",
"moduleLicenseUrl": "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html"
},
{
"moduleName": "ch.qos.logback:logback-core",
"moduleUrl": "http://www.qos.ch",
@@ -372,13 +358,6 @@
"moduleLicense": "CDDL+GPL License",
"moduleLicenseUrl": "http://glassfish.java.net/public/CDDL+GPL_1_1.html"
},
{
"moduleName": "com.sun.xml.bind:jaxb-core",
"moduleUrl": "https://www.eclipse.org",
"moduleVersion": "4.0.6",
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
},
{
"moduleName": "com.sun.xml.bind:jaxb-impl",
"moduleUrl": "https://www.eclipse.org",
@@ -386,13 +365,6 @@
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
},
{
"moduleName": "com.sun.xml.bind:jaxb-impl",
"moduleUrl": "https://www.eclipse.org",
"moduleVersion": "4.0.6",
"moduleLicense": "GNU General Public License, version 2 with the GNU Classpath Exception",
"moduleLicenseUrl": "https://www.gnu.org/software/classpath/license.html"
},
{
"moduleName": "com.twelvemonkeys.common:common-image",
"moduleVersion": "3.13.0",
@@ -786,13 +758,6 @@
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "io.swagger.core.v3:swagger-annotations-jakarta",
"moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-annotations",
"moduleVersion": "2.2.42",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "io.swagger.core.v3:swagger-core-jakarta",
"moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-core",
@@ -800,13 +765,6 @@
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "io.swagger.core.v3:swagger-core-jakarta",
"moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-core",
"moduleVersion": "2.2.42",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "io.swagger.core.v3:swagger-models-jakarta",
"moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-models",
@@ -814,13 +772,6 @@
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "io.swagger.core.v3:swagger-models-jakarta",
"moduleUrl": "https://github.com/swagger-api/swagger-core/modules/swagger-models",
"moduleVersion": "2.2.42",
"moduleLicense": "Apache License, Version 2.0",
"moduleLicenseUrl": "https://www.apache.org/licenses/LICENSE-2.0"
},
{
"moduleName": "jakarta.activation:jakarta.activation-api",
"moduleUrl": "https://www.eclipse.org",
@@ -947,13 +898,6 @@
"moduleLicense": "GPL2 w/ CPE",
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
},
{
"moduleName": "javax.xml.bind:jaxb-api",
"moduleUrl": "http://www.oracle.com/",
"moduleVersion": "2.4.0-b180830.0359",
"moduleLicense": "GPL2 w/ CPE",
"moduleLicenseUrl": "https://oss.oracle.com/licenses/CDDL+GPL-1.1"
},
{
"moduleName": "net.bytebuddy:byte-buddy",
"moduleVersion": "1.17.8",
@@ -1221,13 +1165,6 @@
"moduleLicense": "The MIT License",
"moduleLicenseUrl": "http://opensource.org/licenses/MIT"
},
{
"moduleName": "org.checkerframework:checker-qual",
"moduleUrl": "https://checkerframework.org/",
"moduleVersion": "3.52.0",
"moduleLicense": "The MIT License",
"moduleLicenseUrl": "http://opensource.org/licenses/MIT"
},
{
"moduleName": "org.commonmark:commonmark",
"moduleVersion": "0.27.0",
@@ -1759,13 +1696,6 @@
"moduleLicense": "BSD-2-Clause",
"moduleLicenseUrl": "https://jdbc.postgresql.org/about/license.html"
},
{
"moduleName": "org.postgresql:postgresql",
"moduleUrl": "https://jdbc.postgresql.org/",
"moduleVersion": "42.7.9",
"moduleLicense": "BSD-2-Clause",
"moduleLicenseUrl": "https://jdbc.postgresql.org/about/license.html"
},
{
"moduleName": "org.simplejavamail:core-module",
"moduleVersion": "8.12.6",
@@ -85,13 +85,10 @@ class EditTableOfContentsControllerTest {
when(mockOutlineItem.getNextSibling()).thenReturn(null);
// When
ResponseEntity<List<Map<String, Object>>> response =
editTableOfContentsController.extractBookmarks(mockFile);
List<Map<String, Object>> result = editTableOfContentsController.extractBookmarks(mockFile);
// Then
assertNotNull(response);
assertNotNull(response.getBody());
List<Map<String, Object>> result = response.getBody();
assertNotNull(result);
assertEquals(1, result.size());
Map<String, Object> bookmark = result.get(0);
@@ -110,13 +107,10 @@ class EditTableOfContentsControllerTest {
when(mockCatalog.getDocumentOutline()).thenReturn(null);
// When
ResponseEntity<List<Map<String, Object>>> response =
editTableOfContentsController.extractBookmarks(mockFile);
List<Map<String, Object>> result = editTableOfContentsController.extractBookmarks(mockFile);
// Then
assertNotNull(response);
assertNotNull(response.getBody());
List<Map<String, Object>> result = response.getBody();
assertNotNull(result);
assertTrue(result.isEmpty());
verify(mockDocument).close();
}
@@ -147,13 +141,10 @@ class EditTableOfContentsControllerTest {
when(childItem.getNextSibling()).thenReturn(null);
// When
ResponseEntity<List<Map<String, Object>>> response =
editTableOfContentsController.extractBookmarks(mockFile);
List<Map<String, Object>> result = editTableOfContentsController.extractBookmarks(mockFile);
// Then
assertNotNull(response);
assertNotNull(response.getBody());
List<Map<String, Object>> result = response.getBody();
assertNotNull(result);
assertEquals(1, result.size());
Map<String, Object> parentBookmark = result.get(0);
@@ -186,13 +177,10 @@ class EditTableOfContentsControllerTest {
when(mockOutlineItem.getNextSibling()).thenReturn(null);
// When
ResponseEntity<List<Map<String, Object>>> response =
editTableOfContentsController.extractBookmarks(mockFile);
List<Map<String, Object>> result = editTableOfContentsController.extractBookmarks(mockFile);
// Then
assertNotNull(response);
assertNotNull(response.getBody());
List<Map<String, Object>> result = response.getBody();
assertNotNull(result);
assertEquals(1, result.size());
Map<String, Object> bookmark = result.get(0);
@@ -1,567 +0,0 @@
package stirling.software.SPDF.controller.api.misc;
import static org.junit.jupiter.api.Assertions.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.service.CustomPDFDocumentFactory;
import stirling.software.common.util.TempFileManager;
@ExtendWith(MockitoExtension.class)
class StampControllerTest {
@Mock private CustomPDFDocumentFactory pdfDocumentFactory;
@Mock private TempFileManager tempFileManager;
@InjectMocks private StampController stampController;
private Method processStampTextMethod;
private Method processCustomDateFormatMethod;
@BeforeEach
void setUp() throws NoSuchMethodException {
processStampTextMethod =
StampController.class.getDeclaredMethod(
"processStampText",
String.class,
int.class,
int.class,
String.class,
PDDocument.class);
processStampTextMethod.setAccessible(true);
processCustomDateFormatMethod =
StampController.class.getDeclaredMethod(
"processCustomDateFormat", String.class, LocalDateTime.class);
processCustomDateFormatMethod.setAccessible(true);
}
private String invokeProcessStampText(
String stampText, int pageNumber, int totalPages, String filename, PDDocument document)
throws Exception {
try {
return (String)
processStampTextMethod.invoke(
stampController, stampText, pageNumber, totalPages, filename, document);
} catch (InvocationTargetException e) {
throw (Exception) e.getCause();
}
}
private String invokeProcessCustomDateFormat(String format, LocalDateTime now)
throws Exception {
try {
return (String) processCustomDateFormatMethod.invoke(stampController, format, now);
} catch (InvocationTargetException e) {
throw (Exception) e.getCause();
}
}
@Nested
@DisplayName("Basic Variable Substitution Tests")
class BasicVariableTests {
@Test
@DisplayName("Should replace @page_number with current page")
void testPageNumberReplacement() throws Exception {
String result = invokeProcessStampText("Page @page_number", 5, 20, "test.pdf", null);
assertEquals("Page 5", result);
}
@Test
@DisplayName("Should replace @total_pages with total page count")
void testTotalPagesReplacement() throws Exception {
String result =
invokeProcessStampText("of @total_pages pages", 1, 100, "test.pdf", null);
assertEquals("of 100 pages", result);
}
@Test
@DisplayName("Should replace combined page variables")
void testCombinedPageVariables() throws Exception {
String result =
invokeProcessStampText(
"Page @page_number of @total_pages", 5, 20, "test.pdf", null);
assertEquals("Page 5 of 20", result);
}
@Test
@DisplayName("Should replace @page alias")
void testPageAlias() throws Exception {
String result = invokeProcessStampText("Page @page", 7, 10, "test.pdf", null);
assertEquals("Page 7", result);
}
@Test
@DisplayName("Should replace @page_count alias for total pages")
void testPageCountAlias() throws Exception {
String result = invokeProcessStampText("Total: @page_count", 1, 50, "test.pdf", null);
assertEquals("Total: 50", result);
}
}
@Nested
@DisplayName("Filename Variable Tests")
class FilenameTests {
@Test
@DisplayName("Should replace @filename with filename without extension")
void testFilenameWithoutExtension() throws Exception {
String result = invokeProcessStampText("File: @filename", 1, 1, "document.pdf", null);
assertEquals("File: document", result);
}
@Test
@DisplayName("Should replace @filename_full with full filename")
void testFilenameWithExtension() throws Exception {
String result =
invokeProcessStampText("File: @filename_full", 1, 1, "document.pdf", null);
assertEquals("File: document.pdf", result);
}
@Test
@DisplayName("Should handle filename without extension")
void testFilenameWithoutDot() throws Exception {
String result = invokeProcessStampText("@filename", 1, 1, "document", null);
assertEquals("document", result);
}
@Test
@DisplayName("Should handle null filename")
void testNullFilename() throws Exception {
String result = invokeProcessStampText("File: @filename", 1, 1, null, null);
assertEquals("File: ", result);
}
@Test
@DisplayName("Should handle filename with multiple dots")
void testFilenameMultipleDots() throws Exception {
String result = invokeProcessStampText("@filename", 1, 1, "my.document.v2.pdf", null);
assertEquals("my.document.v2", result);
}
@Test
@DisplayName("Should handle hidden file (starts with dot)")
void testHiddenFile() throws Exception {
String result = invokeProcessStampText("@filename", 1, 1, ".hidden.pdf", null);
assertEquals(".hidden", result);
}
}
@Nested
@DisplayName("Date/Time Variable Tests")
class DateTimeTests {
@Test
@DisplayName("Should replace @date with current date")
void testDateReplacement() throws Exception {
String result = invokeProcessStampText("Date: @date", 1, 1, "test.pdf", null);
assertTrue(
result.matches("Date: \\d{4}-\\d{2}-\\d{2}"),
"Date should match YYYY-MM-DD format");
}
@Test
@DisplayName("Should replace @time with current time")
void testTimeReplacement() throws Exception {
String result = invokeProcessStampText("Time: @time", 1, 1, "test.pdf", null);
assertTrue(
result.matches("Time: \\d{2}:\\d{2}:\\d{2}"),
"Time should match HH:mm:ss format");
}
@Test
@DisplayName("Should replace @datetime with combined date and time")
void testDateTimeReplacement() throws Exception {
String result = invokeProcessStampText("@datetime", 1, 1, "test.pdf", null);
// DateTime format: YYYY-MM-DD HH:mm:ss
assertTrue(
result.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"),
"DateTime should match YYYY-MM-DD HH:mm:ss format");
}
@Test
@DisplayName("Should replace @year with current year")
void testYearReplacement() throws Exception {
String result = invokeProcessStampText("© @year", 1, 1, "test.pdf", null);
int currentYear = LocalDateTime.now().getYear();
assertEquals("© " + currentYear, result);
}
@Test
@DisplayName("Should replace @month with zero-padded month")
void testMonthReplacement() throws Exception {
String result = invokeProcessStampText("Month: @month", 1, 1, "test.pdf", null);
assertTrue(result.matches("Month: \\d{2}"), "Month should be zero-padded");
}
@Test
@DisplayName("Should replace @day with zero-padded day")
void testDayReplacement() throws Exception {
String result = invokeProcessStampText("Day: @day", 1, 1, "test.pdf", null);
assertTrue(result.matches("Day: \\d{2}"), "Day should be zero-padded");
}
}
@Nested
@DisplayName("Custom Date Format Tests")
class CustomDateFormatTests {
@Test
@DisplayName("Should handle custom date format dd/MM/yyyy")
void testCustomDateFormatSlash() throws Exception {
String result = invokeProcessStampText("@date{dd/MM/yyyy}", 1, 1, "test.pdf", null);
assertTrue(
result.matches("\\d{2}/\\d{2}/\\d{4}"),
"Should match dd/MM/yyyy format: " + result);
}
@Test
@DisplayName("Should handle custom date format with time")
void testCustomDateFormatWithTime() throws Exception {
String result =
invokeProcessStampText("@date{yyyy-MM-dd HH:mm}", 1, 1, "test.pdf", null);
assertTrue(
result.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}"),
"Should match yyyy-MM-dd HH:mm format: " + result);
}
@Test
@DisplayName("Should handle multiple custom date formats in same text")
void testMultipleCustomDateFormats() throws Exception {
String result =
invokeProcessStampText(
"Start: @date{dd/MM/yyyy} End: @date{yyyy}", 1, 1, "test.pdf", null);
assertTrue(result.contains("/"), "Should contain slash from first format");
// Should have year twice (once with slashes, once alone)
}
}
@Nested
@DisplayName("Custom Date Format Security Tests")
class CustomDateFormatSecurityTests {
@Test
@DisplayName("Should not match format that is too long - regex won't capture it")
void testFormatTooLong() throws Exception {
String longFormat = "y".repeat(51); // 51 chars, over the 50 char regex limit
String result =
invokeProcessStampText("@date{" + longFormat + "}", 1, 1, "test.pdf", null);
// The CUSTOM_DATE_PATTERN only captures up to 50 chars, so this won't match
// The @date part will be replaced by simple replacement, leaving {yyy...}
assertTrue(
result.contains("{"), "Should contain { because regex didn't match: " + result);
}
@Test
@DisplayName("Should reject format with unsafe characters - shell injection attempt")
void testShellInjectionAttempt() throws Exception {
String result =
invokeProcessStampText("@date{yyyy-MM-dd$(rm -rf /)}", 1, 1, "test.pdf", null);
assertEquals("[invalid format]", result);
}
@Test
@DisplayName("Should reject format with unsafe characters - semicolon")
void testSemicolonInjection() throws Exception {
String result = invokeProcessStampText("@date{yyyy;rm}", 1, 1, "test.pdf", null);
assertEquals("[invalid format]", result);
}
@Test
@DisplayName("Should reject format with unsafe characters - backticks")
void testBacktickInjection() throws Exception {
String result = invokeProcessStampText("@date{`whoami`}", 1, 1, "test.pdf", null);
assertEquals("[invalid format]", result);
}
@ParameterizedTest
@ValueSource(strings = {"$(cmd)", "`cmd`", ";cmd", "|cmd", "&cmd", "<cmd", ">cmd"})
@DisplayName("Should reject various injection attempts")
void testVariousInjectionAttempts(String injection) throws Exception {
String result =
invokeProcessStampText("@date{yyyy" + injection + "}", 1, 1, "test.pdf", null);
assertEquals("[invalid format]", result);
}
@Test
@DisplayName("Should accept valid format characters")
void testValidFormatCharacters() throws Exception {
// All these should be valid based on SAFE_DATE_FORMAT_PATTERN: yMdHhmsS/-:.,
// '+EGuwWDFzZXa and space
String result =
invokeProcessStampText("@date{yyyy-MM-dd HH:mm:ss}", 1, 1, "test.pdf", null);
assertFalse(
result.startsWith("[invalid"), "Valid format should be accepted: " + result);
}
@Test
@DisplayName("Should handle invalid DateTimeFormatter pattern gracefully")
void testInvalidFormatterPattern() throws Exception {
LocalDateTime now = LocalDateTime.now();
// Use 'sssss' - too many seconds digits will throw IllegalArgumentException from
// DateTimeFormatter
// Note: The pattern 'sssss' passes the SAFE_DATE_FORMAT_PATTERN but fails
// DateTimeFormatter.ofPattern()
String result = invokeProcessCustomDateFormat("sssss", now);
assertTrue(
result.startsWith("[invalid format:"),
"Invalid pattern should return error message: " + result);
}
}
@Nested
@DisplayName("Escape Sequence Tests")
class EscapeSequenceTests {
@Test
@DisplayName("Should convert @@ to literal @")
void testDoubleAtEscape() throws Exception {
String result =
invokeProcessStampText("Email: test@@example.com", 1, 1, "test.pdf", null);
assertEquals("Email: test@example.com", result);
}
@Test
@DisplayName("Should preserve @@ before variable")
void testEscapeBeforeVariable() throws Exception {
String result = invokeProcessStampText("@@date is @date", 1, 1, "test.pdf", null);
// @@date should become @date, and @date should be replaced with actual date
assertTrue(result.startsWith("@date is "), "Should start with literal @date");
assertTrue(
result.matches("@date is \\d{4}-\\d{2}-\\d{2}"),
"Should have date after: " + result);
}
@Test
@DisplayName("Should handle multiple escape sequences")
void testMultipleEscapes() throws Exception {
String result = invokeProcessStampText("@@one @@two @@three", 1, 1, "test.pdf", null);
assertEquals("@one @two @three", result);
}
@Test
@DisplayName("Should handle escape at end of string")
void testEscapeAtEnd() throws Exception {
String result = invokeProcessStampText("Contact: user@@", 1, 1, "test.pdf", null);
assertEquals("Contact: user@", result);
}
}
@Nested
@DisplayName("Document Metadata Tests")
class DocumentMetadataTests {
@Test
@DisplayName("Should replace @author with document author")
void testAuthorReplacement() throws Exception {
PDDocument doc = new PDDocument();
PDDocumentInformation info = new PDDocumentInformation();
info.setAuthor("John Doe");
doc.setDocumentInformation(info);
try {
String result = invokeProcessStampText("Author: @author", 1, 1, "test.pdf", doc);
assertEquals("Author: John Doe", result);
} finally {
doc.close();
}
}
@Test
@DisplayName("Should replace @title with document title")
void testTitleReplacement() throws Exception {
PDDocument doc = new PDDocument();
PDDocumentInformation info = new PDDocumentInformation();
info.setTitle("My Document Title");
doc.setDocumentInformation(info);
try {
String result = invokeProcessStampText("Title: @title", 1, 1, "test.pdf", doc);
assertEquals("Title: My Document Title", result);
} finally {
doc.close();
}
}
@Test
@DisplayName("Should replace @subject with document subject")
void testSubjectReplacement() throws Exception {
PDDocument doc = new PDDocument();
PDDocumentInformation info = new PDDocumentInformation();
info.setSubject("Important Subject");
doc.setDocumentInformation(info);
try {
String result = invokeProcessStampText("Subject: @subject", 1, 1, "test.pdf", doc);
assertEquals("Subject: Important Subject", result);
} finally {
doc.close();
}
}
@Test
@DisplayName("Should handle null metadata gracefully")
void testNullMetadata() throws Exception {
PDDocument doc = new PDDocument();
// Don't set any document information
try {
String result =
invokeProcessStampText("@author @title @subject", 1, 1, "test.pdf", doc);
assertEquals(" ", result); // All should be empty strings
} finally {
doc.close();
}
}
@Test
@DisplayName("Should handle null document gracefully")
void testNullDocument() throws Exception {
String result = invokeProcessStampText("Author: @author", 1, 1, "test.pdf", null);
assertEquals("Author: ", result);
}
}
@Nested
@DisplayName("UUID Variable Tests")
class UuidTests {
@Test
@DisplayName("Should generate 8-character UUID")
void testUuidLength() throws Exception {
String result = invokeProcessStampText("ID: @uuid", 1, 1, "test.pdf", null);
// UUID format: "ID: " + 8 chars
assertEquals(12, result.length(), "Should be 'ID: ' + 8 char UUID");
}
@Test
@DisplayName("Should generate different UUIDs for each call")
void testUuidUniqueness() throws Exception {
String result1 = invokeProcessStampText("@uuid", 1, 1, "test.pdf", null);
String result2 = invokeProcessStampText("@uuid", 1, 1, "test.pdf", null);
assertNotEquals(result1, result2, "UUIDs should be unique");
}
@Test
@DisplayName("UUID should contain only hex characters")
void testUuidFormat() throws Exception {
String result = invokeProcessStampText("@uuid", 1, 1, "test.pdf", null);
assertTrue(result.matches("[0-9a-f]{8}"), "UUID should be 8 hex characters: " + result);
}
}
@Nested
@DisplayName("Edge Cases and Error Handling")
class EdgeCaseTests {
@Test
@DisplayName("Should handle null stamp text")
void testNullStampText() throws Exception {
String result = invokeProcessStampText(null, 1, 1, "test.pdf", null);
assertEquals("", result);
}
@Test
@DisplayName("Should handle empty stamp text")
void testEmptyStampText() throws Exception {
String result = invokeProcessStampText("", 1, 1, "test.pdf", null);
assertEquals("", result);
}
@Test
@DisplayName("Should handle text with no variables")
void testNoVariables() throws Exception {
String result = invokeProcessStampText("Just plain text", 1, 1, "test.pdf", null);
assertEquals("Just plain text", result);
}
@Test
@DisplayName("Should handle unknown variables")
void testUnknownVariable() throws Exception {
String result = invokeProcessStampText("@unknown_var", 1, 1, "test.pdf", null);
assertEquals("@unknown_var", result);
}
@Test
@DisplayName("Should preserve text around variables")
void testPreservesSurroundingText() throws Exception {
String result =
invokeProcessStampText("Before @page_number After", 5, 10, "test.pdf", null);
assertEquals("Before 5 After", result);
}
@Test
@DisplayName("Should handle multiple same variables")
void testMultipleSameVariables() throws Exception {
String result =
invokeProcessStampText("@page_number / @page_number", 3, 10, "test.pdf", null);
assertEquals("3 / 3", result);
}
@Test
@DisplayName("Should handle variables adjacent to each other")
void testAdjacentVariables() throws Exception {
String result = invokeProcessStampText("@page@page_number", 5, 10, "test.pdf", null);
// @page should be replaced first (it's in the order), then @page_number
// Since @page_number is longer and comes first in replace chain, should work
assertEquals("55", result);
}
}
@Nested
@DisplayName("Complex Scenario Tests")
class ComplexScenarioTests {
@Test
@DisplayName("Should handle legal footer template")
void testLegalFooterTemplate() throws Exception {
String template = "© @year - All Rights Reserved\\n@filename - Page @page_number";
String result = invokeProcessStampText(template, 3, 15, "contract.pdf", null);
int year = LocalDateTime.now().getYear();
String expected = "© " + year + " - All Rights Reserved\\ncontract - Page 3";
assertEquals(expected, result);
}
@Test
@DisplayName("Should handle Brazilian date format template")
void testBrazilianDateFormat() throws Exception {
String template = "Documento criado em @date{dd/MM/yyyy} às @time";
String result = invokeProcessStampText(template, 1, 1, "doc.pdf", null);
assertTrue(result.startsWith("Documento criado em "));
assertTrue(result.contains("/"));
assertTrue(result.contains(":"));
}
@ParameterizedTest
@CsvSource({
"'Page @page_number of @total_pages', 1, 10, 'Page 1 of 10'",
"'Page @page_number of @total_pages', 5, 20, 'Page 5 of 20'",
"'Page @page_number of @total_pages', 100, 1000, 'Page 100 of 1000'"
})
@DisplayName("Should handle page number template with various values")
void testPageNumberTemplates(String template, int page, int total, String expected)
throws Exception {
String result = invokeProcessStampText(template, page, total, "test.pdf", null);
assertEquals(expected, result);
}
}
}
+2 -2
View File
@@ -49,7 +49,7 @@ dependencies {
api 'org.springframework.boot:spring-boot-starter-mail'
api 'org.springframework.boot:spring-boot-starter-cache'
api 'com.github.ben-manes.caffeine:caffeine'
api 'io.swagger.core.v3:swagger-core-jakarta:2.2.42'
api 'io.swagger.core.v3:swagger-core-jakarta:2.2.41'
implementation 'com.bucket4j:bucket4j_jdk17-core:8.15.0'
// https://mvnrepository.com/artifact/com.bucket4j/bucket4j_jdk17
@@ -62,7 +62,7 @@ dependencies {
runtimeOnly "io.jsonwebtoken:jjwt-impl:$jwtVersion"
runtimeOnly "io.jsonwebtoken:jjwt-jackson:$jwtVersion"
runtimeOnly 'com.h2database:h2:2.3.232' // Don't upgrade h2database
runtimeOnly 'org.postgresql:postgresql:42.7.9'
runtimeOnly 'org.postgresql:postgresql:42.7.8'
constraints {
implementation "org.opensaml:opensaml-core:$openSamlVersion"
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
@@ -139,7 +139,6 @@ public class ProprietaryUIDataController {
// Add enableLogin flag so frontend doesn't need to call /app-config
data.setEnableLogin(securityProps.isEnableLogin());
data.setSsoAutoLogin(applicationProperties.getPremium().getProFeatures().isSsoAutoLogin());
// Check if this is first-time setup with default credentials
// The isFirstLogin flag captures: default username/password usage and unchanged state
@@ -219,7 +218,9 @@ public class ProprietaryUIDataController {
String backendUrl = getBackendBaseUrl();
String fullSamlPath = backendUrl + saml2AuthenticationPath;
providerList.put(fullSamlPath, samlIdp + " (SAML 2)");
if (!applicationProperties.getPremium().getProFeatures().isSsoAutoLogin()) {
providerList.put(fullSamlPath, samlIdp + " (SAML 2)");
}
}
// Remove null entries
@@ -532,7 +533,6 @@ public class ProprietaryUIDataController {
@Data
public static class LoginData {
private Boolean enableLogin;
private boolean ssoAutoLogin;
private Map<String, String> providerList;
private String loginMethod;
private boolean altLogin;
@@ -33,8 +33,7 @@ public class PersistentAuditEvent {
private String principal;
private String type;
@Column(columnDefinition = "text")
private String data; // JSON blob
@Lob private String data; // JSON blob
private Instant timestamp;
}
@@ -8,7 +8,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
@@ -186,39 +185,11 @@ public class SecurityConfiguration {
}
@Bean
@Order(1)
public SecurityFilterChain samlFilterChain(
HttpSecurity http,
@Lazy IPRateLimitingFilter rateLimitingFilter,
@Lazy JwtAuthenticationFilter jwtAuthenticationFilter)
throws Exception {
http.securityMatcher("/saml2/**", "/login/saml2/**");
SessionCreationPolicy sessionPolicy =
(securityProperties.isSaml2Active() && runningProOrHigher)
? SessionCreationPolicy.IF_REQUIRED
: SessionCreationPolicy.STATELESS;
return configureSecurity(http, rateLimitingFilter, jwtAuthenticationFilter, sessionPolicy);
}
@Bean
@Order(2)
public SecurityFilterChain filterChain(
HttpSecurity http,
@Lazy IPRateLimitingFilter rateLimitingFilter,
@Lazy JwtAuthenticationFilter jwtAuthenticationFilter)
throws Exception {
SessionCreationPolicy sessionPolicy = SessionCreationPolicy.STATELESS;
return configureSecurity(http, rateLimitingFilter, jwtAuthenticationFilter, sessionPolicy);
}
private SecurityFilterChain configureSecurity(
HttpSecurity http,
@Lazy IPRateLimitingFilter rateLimitingFilter,
@Lazy JwtAuthenticationFilter jwtAuthenticationFilter,
SessionCreationPolicy sessionPolicy)
throws Exception {
// Enable CORS only if we have configured origins
CorsConfigurationSource corsSource = corsConfigurationSource();
if (corsSource != null) {
@@ -230,30 +201,6 @@ public class SecurityConfiguration {
http.csrf(CsrfConfigurer::disable);
// Configure X-Frame-Options based on settings.yml configuration
// When login is disabled, automatically disable X-Frame-Options to allow embedding
if (!loginEnabledValue) {
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable()));
} else {
String xFrameOption = securityProperties.getXFrameOptions();
if (xFrameOption != null) {
http.headers(
headers -> {
if ("DISABLED".equalsIgnoreCase(xFrameOption)) {
headers.frameOptions(frameOptions -> frameOptions.disable());
} else if ("SAMEORIGIN".equalsIgnoreCase(xFrameOption)) {
headers.frameOptions(frameOptions -> frameOptions.sameOrigin());
} else {
// Default to DENY
headers.frameOptions(frameOptions -> frameOptions.deny());
}
});
} else {
// If not configured, use default DENY
http.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.deny()));
}
}
if (loginEnabledValue) {
http.addFilterBefore(
@@ -262,7 +209,9 @@ public class SecurityConfiguration {
.addFilterBefore(jwtAuthenticationFilter, UserAuthenticationFilter.class);
http.sessionManagement(
sessionManagement -> sessionManagement.sessionCreationPolicy(sessionPolicy));
sessionManagement ->
sessionManagement.sessionCreationPolicy(
SessionCreationPolicy.STATELESS));
http.authenticationProvider(daoAuthenticationProvider());
http.requestCache(requestCache -> requestCache.requestCache(new NullRequestCache()));
@@ -309,16 +309,10 @@ public class AdminLicenseController {
}
try {
log.info(
"License upload: original filename='{}', size={} bytes, contentType='{}'",
file.getOriginalFilename(),
file.getSize(),
file.getContentType());
// Validate certificate format by reading content
byte[] fileBytes = file.getBytes();
String content = new String(fileBytes, StandardCharsets.UTF_8);
if (!content.trim().startsWith("-----BEGIN LICENSE FILE-----")) {
log.warn("License upload rejected: invalid certificate header");
return ResponseEntity.badRequest()
.body(
Map.of(
@@ -330,15 +324,9 @@ public class AdminLicenseController {
// Get config directory and target path
Path configPath = Paths.get(InstallationPathConfig.getConfigPath());
Path configPathAbs = configPath.toAbsolutePath().normalize();
Path targetPath = configPathAbs.resolve(filename).normalize();
log.info(
"License upload paths: configPath='{}', targetPath='{}'",
configPathAbs,
targetPath.toAbsolutePath());
Path targetPath = configPath.resolve(filename).normalize();
// Prevent directory traversal: ensure targetPath is inside configPath
if (!targetPath.startsWith(configPathAbs)) {
log.warn("License upload rejected: target path outside config path");
if (!targetPath.startsWith(configPath.normalize().toAbsolutePath())) {
return ResponseEntity.badRequest()
.body(Map.of("success", false, "error", "Invalid file path"));
}
@@ -186,13 +186,6 @@ public class AdminSettingsController {
+ HtmlUtils.htmlEscape(key)));
}
// Validate pipeline path settings
String validationError = validatePipelinePathSetting(key, value);
if (validationError != null) {
return ResponseEntity.badRequest()
.body(Map.of("error", HtmlUtils.htmlEscape(validationError)));
}
log.info("Admin updating setting: {} = {}", key, value);
GeneralUtils.saveKeyToSettings(key, value);
@@ -649,54 +642,6 @@ public class AdminSettingsController {
return true;
}
private String validatePipelinePathSetting(String key, Object value) {
// Validate pipeline path settings
if (key.startsWith("system.customPaths.pipeline.watchedFoldersDirs")
&& value instanceof java.util.List) {
@SuppressWarnings("unchecked")
java.util.List<String> paths = (java.util.List<String>) value;
// Check for empty or all-blank paths
if (paths.isEmpty()) {
return null; // Empty is OK, will use default
}
// Validate each path
java.util.Set<String> normalizedPaths = new java.util.HashSet<>();
for (String path : paths) {
if (path != null && !path.trim().isEmpty()) {
try {
java.nio.file.Path normalized =
java.nio.file.Paths.get(path.trim()).toAbsolutePath().normalize();
String normalizedStr = normalized.toString();
// Check for duplicates
if (normalizedPaths.contains(normalizedStr)) {
return "Duplicate path detected: " + path;
}
normalizedPaths.add(normalizedStr);
} catch (java.nio.file.InvalidPathException e) {
return "Invalid path: " + path + " - " + e.getMessage();
}
}
}
// Check for overlapping paths
java.util.List<String> pathList = new java.util.ArrayList<>(normalizedPaths);
for (int i = 0; i < pathList.size(); i++) {
java.nio.file.Path path1 = java.nio.file.Paths.get(pathList.get(i));
for (int j = i + 1; j < pathList.size(); j++) {
java.nio.file.Path path2 = java.nio.file.Paths.get(pathList.get(j));
if (path1.startsWith(path2) || path2.startsWith(path1)) {
return "Overlapping paths detected: " + path1 + " and " + path2;
}
}
}
}
return null; // Valid
}
private Object getSettingByKey(String key) {
if (key == null || key.trim().isEmpty()) {
return null;
@@ -286,10 +286,7 @@ public class AuthController {
log.debug("Token refreshed for user: {}", username);
return ResponseEntity.ok(
Map.of(
"user", buildUserResponse(user),
"session", Map.of("access_token", newToken, "expires_in", 3600)));
return ResponseEntity.ok(Map.of("access_token", newToken, "expires_in", 3600));
} catch (Exception e) {
log.error("Token refresh error", e);
@@ -87,6 +87,7 @@ public class User implements UserDetails, Serializable {
@ElementCollection
@MapKeyColumn(name = "setting_key")
@Lob
@Column(name = "setting_value", columnDefinition = "text")
@CollectionTable(name = "user_settings", joinColumns = @JoinColumn(name = "user_id"))
@JsonIgnore
@@ -0,0 +1,135 @@
package stirling.software.proprietary.security.saml2;
import java.util.HashMap;
import java.util.Map;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import stirling.software.proprietary.security.service.JwtServiceInterface;
@Slf4j
public class JwtSaml2AuthenticationRequestRepository
implements Saml2AuthenticationRequestRepository<Saml2PostAuthenticationRequest> {
private final Map<String, String> tokenStore;
private final JwtServiceInterface jwtService;
private final RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
private static final String SAML_REQUEST_TOKEN = "stirling_saml_request_token";
public JwtSaml2AuthenticationRequestRepository(
Map<String, String> tokenStore,
JwtServiceInterface jwtService,
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
this.tokenStore = tokenStore;
this.jwtService = jwtService;
this.relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
}
@Override
public void saveAuthenticationRequest(
Saml2PostAuthenticationRequest authRequest,
HttpServletRequest request,
HttpServletResponse response) {
if (!jwtService.isJwtEnabled()) {
log.debug("V2 is not enabled, skipping SAMLRequest token storage");
return;
}
if (authRequest == null) {
removeAuthenticationRequest(request, response);
return;
}
Map<String, Object> claims = serializeSamlRequest(authRequest);
String token = jwtService.generateToken("", claims);
String relayState = authRequest.getRelayState();
tokenStore.put(relayState, token);
request.setAttribute(SAML_REQUEST_TOKEN, relayState);
response.addHeader(SAML_REQUEST_TOKEN, relayState);
log.debug("Saved SAMLRequest token with RelayState: {}", relayState);
}
@Override
public Saml2PostAuthenticationRequest loadAuthenticationRequest(HttpServletRequest request) {
String token = extractTokenFromStore(request);
if (token == null) {
log.debug("No SAMLResponse token found in RelayState");
return null;
}
Map<String, Object> claims = jwtService.extractClaims(token);
return deserializeSamlRequest(claims);
}
@Override
public Saml2PostAuthenticationRequest removeAuthenticationRequest(
HttpServletRequest request, HttpServletResponse response) {
Saml2PostAuthenticationRequest authRequest = loadAuthenticationRequest(request);
String relayStateId = request.getParameter("RelayState");
if (relayStateId != null) {
tokenStore.remove(relayStateId);
log.debug("Removed SAMLRequest token for RelayState ID: {}", relayStateId);
}
return authRequest;
}
private String extractTokenFromStore(HttpServletRequest request) {
String authnRequestId = request.getParameter("RelayState");
if (authnRequestId != null && !authnRequestId.isEmpty()) {
String token = tokenStore.get(authnRequestId);
if (token != null) {
tokenStore.remove(authnRequestId);
log.debug("Retrieved SAMLRequest token for RelayState ID: {}", authnRequestId);
return token;
} else {
log.warn("No SAMLRequest token found for RelayState ID: {}", authnRequestId);
}
}
return null;
}
private Map<String, Object> serializeSamlRequest(Saml2PostAuthenticationRequest authRequest) {
Map<String, Object> claims = new HashMap<>();
claims.put("id", authRequest.getId());
claims.put("relyingPartyRegistrationId", authRequest.getRelyingPartyRegistrationId());
claims.put("authenticationRequestUri", authRequest.getAuthenticationRequestUri());
claims.put("samlRequest", authRequest.getSamlRequest());
claims.put("relayState", authRequest.getRelayState());
return claims;
}
private Saml2PostAuthenticationRequest deserializeSamlRequest(Map<String, Object> claims) {
String relyingPartyRegistrationId = (String) claims.get("relyingPartyRegistrationId");
RelyingPartyRegistration relyingPartyRegistration =
relyingPartyRegistrationRepository.findByRegistrationId(relyingPartyRegistrationId);
if (relyingPartyRegistration == null) {
return null;
}
return Saml2PostAuthenticationRequest.withRelyingPartyRegistration(relyingPartyRegistration)
.id((String) claims.get("id"))
.authenticationRequestUri((String) claims.get("authenticationRequestUri"))
.samlRequest((String) claims.get("samlRequest"))
.relayState((String) claims.get("relayState"))
.build();
}
}
@@ -3,6 +3,7 @@ package stirling.software.proprietary.security.saml2;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -11,10 +12,12 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import jakarta.servlet.http.HttpServletRequest;
@@ -24,6 +27,7 @@ import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.ApplicationProperties;
import stirling.software.common.model.ApplicationProperties.Security.SAML2;
import stirling.software.proprietary.security.service.JwtServiceInterface;
@Configuration
@Slf4j
@@ -149,10 +153,22 @@ public class Saml2Configuration {
return new InMemoryRelyingPartyRegistrationRepository(rp);
}
@Bean
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
public Saml2AuthenticationRequestRepository<Saml2PostAuthenticationRequest>
saml2AuthenticationRequestRepository(
JwtServiceInterface jwtService,
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
return new JwtSaml2AuthenticationRequestRepository(
new ConcurrentHashMap<>(), jwtService, relyingPartyRegistrationRepository);
}
@Bean
@ConditionalOnProperty(name = "security.saml2.enabled", havingValue = "true")
public OpenSaml4AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository,
Saml2AuthenticationRequestRepository<Saml2PostAuthenticationRequest>
saml2AuthenticationRequestRepository) {
OpenSaml4AuthenticationRequestResolver resolver =
new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationRepository);
@@ -160,10 +176,30 @@ public class Saml2Configuration {
customizer -> {
HttpServletRequest request = customizer.getRequest();
AuthnRequest authnRequest = customizer.getAuthnRequest();
Saml2PostAuthenticationRequest saml2AuthenticationRequest =
saml2AuthenticationRequestRepository.loadAuthenticationRequest(request);
// Generate a unique AuthnRequest ID for each SAML request
authnRequest.setID("ARQ" + UUID.randomUUID().toString().substring(1));
if (saml2AuthenticationRequest != null) {
String sessionId = request.getSession(false).getId();
log.debug(
"Retrieving SAML 2 authentication request ID from the current HTTP session {}",
sessionId);
String authenticationRequestId = saml2AuthenticationRequest.getId();
if (!authenticationRequestId.isBlank()) {
authnRequest.setID(authenticationRequestId);
} else {
log.warn(
"No authentication request found for HTTP session {}. Generating new ID",
sessionId);
authnRequest.setID("ARQ" + UUID.randomUUID().toString().substring(1));
}
} else {
log.debug("Generating new authentication request ID");
authnRequest.setID("ARQ" + UUID.randomUUID().toString().substring(1));
}
logAuthnRequestDetails(authnRequest);
logHttpRequestDetails(request);
});
@@ -67,7 +67,6 @@ public class UserService implements UserServiceInterface {
private final ApplicationProperties.Security.OAUTH2 oAuth2;
@Transactional
public void processSSOPostLogin(
String username,
String ssoProviderId,
@@ -182,9 +182,8 @@ class AuthControllerLoginTest {
mockMvc.perform(post("/api/v1/auth/refresh"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.user").exists())
.andExpect(jsonPath("$.session.access_token").value("new-token"))
.andExpect(jsonPath("$.session.expires_in").value(3600));
.andExpect(jsonPath("$.access_token").value("new-token"))
.andExpect(jsonPath("$.expires_in").value(3600));
}
@Test
@@ -0,0 +1,243 @@
package stirling.software.proprietary.security.saml2;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import stirling.software.proprietary.security.service.JwtServiceInterface;
@ExtendWith(MockitoExtension.class)
class JwtSaml2AuthenticationRequestRepositoryTest {
private static final String SAML_REQUEST_TOKEN = "stirling_saml_request_token";
private Map<String, String> tokenStore;
@Mock private JwtServiceInterface jwtService;
@Mock private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
private JwtSaml2AuthenticationRequestRepository jwtSaml2AuthenticationRequestRepository;
@BeforeEach
void setUp() {
tokenStore = new ConcurrentHashMap<>();
jwtSaml2AuthenticationRequestRepository =
new JwtSaml2AuthenticationRequestRepository(
tokenStore, jwtService, relyingPartyRegistrationRepository);
}
@Test
void saveAuthenticationRequest() {
var authRequest = mock(Saml2PostAuthenticationRequest.class);
var request = mock(MockHttpServletRequest.class);
var response = mock(MockHttpServletResponse.class);
String token = "testToken";
String id = "testId";
String relayState = "testRelayState";
String authnRequestUri = "example.com/authnRequest";
String samlRequest = "testSamlRequest";
String relyingPartyRegistrationId = "stirling-pdf";
when(jwtService.isJwtEnabled()).thenReturn(true);
when(authRequest.getRelayState()).thenReturn(relayState);
when(authRequest.getId()).thenReturn(id);
when(authRequest.getAuthenticationRequestUri()).thenReturn(authnRequestUri);
when(authRequest.getSamlRequest()).thenReturn(samlRequest);
when(authRequest.getRelyingPartyRegistrationId()).thenReturn(relyingPartyRegistrationId);
when(jwtService.generateToken(eq(""), anyMap())).thenReturn(token);
jwtSaml2AuthenticationRequestRepository.saveAuthenticationRequest(
authRequest, request, response);
verify(request).setAttribute(SAML_REQUEST_TOKEN, relayState);
verify(response).addHeader(SAML_REQUEST_TOKEN, relayState);
}
@Test
void saveAuthenticationRequestWithNullRequest() {
var request = mock(MockHttpServletRequest.class);
var response = mock(MockHttpServletResponse.class);
jwtSaml2AuthenticationRequestRepository.saveAuthenticationRequest(null, request, response);
assertTrue(tokenStore.isEmpty());
}
@Test
void loadAuthenticationRequest() {
var request = mock(MockHttpServletRequest.class);
var relyingPartyRegistration = mock(RelyingPartyRegistration.class);
var assertingPartyMetadata = mock(AssertingPartyMetadata.class);
String relayState = "testRelayState";
String token = "testToken";
Map<String, Object> claims =
Map.of(
"id", "testId",
"relyingPartyRegistrationId", "stirling-pdf",
"authenticationRequestUri", "example.com/authnRequest",
"samlRequest", "testSamlRequest",
"relayState", relayState);
when(request.getParameter("RelayState")).thenReturn(relayState);
when(jwtService.extractClaims(token)).thenReturn(claims);
when(relyingPartyRegistrationRepository.findByRegistrationId("stirling-pdf"))
.thenReturn(relyingPartyRegistration);
when(relyingPartyRegistration.getRegistrationId()).thenReturn("stirling-pdf");
when(relyingPartyRegistration.getAssertingPartyMetadata())
.thenReturn(assertingPartyMetadata);
when(assertingPartyMetadata.getSingleSignOnServiceLocation())
.thenReturn("https://example.com/sso");
tokenStore.put(relayState, token);
var result = jwtSaml2AuthenticationRequestRepository.loadAuthenticationRequest(request);
assertNotNull(result);
assertFalse(tokenStore.containsKey(relayState));
}
@ParameterizedTest
@NullAndEmptySource
void loadAuthenticationRequestWithInvalidRelayState(String relayState) {
var request = mock(MockHttpServletRequest.class);
when(request.getParameter("RelayState")).thenReturn(relayState);
var result = jwtSaml2AuthenticationRequestRepository.loadAuthenticationRequest(request);
assertNull(result);
}
@Test
void loadAuthenticationRequestWithNonExistentToken() {
var request = mock(MockHttpServletRequest.class);
when(request.getParameter("RelayState")).thenReturn("nonExistentRelayState");
var result = jwtSaml2AuthenticationRequestRepository.loadAuthenticationRequest(request);
assertNull(result);
}
@Test
void loadAuthenticationRequestWithNullRelyingPartyRegistration() {
var request = mock(MockHttpServletRequest.class);
String relayState = "testRelayState";
String token = "testToken";
Map<String, Object> claims =
Map.of(
"id", "testId",
"relyingPartyRegistrationId", "stirling-pdf",
"authenticationRequestUri", "example.com/authnRequest",
"samlRequest", "testSamlRequest",
"relayState", relayState);
when(request.getParameter("RelayState")).thenReturn(relayState);
when(jwtService.extractClaims(token)).thenReturn(claims);
when(relyingPartyRegistrationRepository.findByRegistrationId("stirling-pdf"))
.thenReturn(null);
tokenStore.put(relayState, token);
var result = jwtSaml2AuthenticationRequestRepository.loadAuthenticationRequest(request);
assertNull(result);
}
@Test
void removeAuthenticationRequest() {
var request = mock(HttpServletRequest.class);
var response = mock(HttpServletResponse.class);
var relyingPartyRegistration = mock(RelyingPartyRegistration.class);
var assertingPartyMetadata = mock(AssertingPartyMetadata.class);
String relayState = "testRelayState";
String token = "testToken";
Map<String, Object> claims =
Map.of(
"id", "testId",
"relyingPartyRegistrationId", "stirling-pdf",
"authenticationRequestUri", "example.com/authnRequest",
"samlRequest", "testSamlRequest",
"relayState", relayState);
when(request.getParameter("RelayState")).thenReturn(relayState);
when(jwtService.extractClaims(token)).thenReturn(claims);
when(relyingPartyRegistrationRepository.findByRegistrationId("stirling-pdf"))
.thenReturn(relyingPartyRegistration);
when(relyingPartyRegistration.getRegistrationId()).thenReturn("stirling-pdf");
when(relyingPartyRegistration.getAssertingPartyMetadata())
.thenReturn(assertingPartyMetadata);
when(assertingPartyMetadata.getSingleSignOnServiceLocation())
.thenReturn("https://example.com/sso");
tokenStore.put(relayState, token);
var result =
jwtSaml2AuthenticationRequestRepository.removeAuthenticationRequest(
request, response);
assertNotNull(result);
assertFalse(tokenStore.containsKey(relayState));
}
@Test
void removeAuthenticationRequestWithNullRelayState() {
var request = mock(HttpServletRequest.class);
var response = mock(HttpServletResponse.class);
when(request.getParameter("RelayState")).thenReturn(null);
var result =
jwtSaml2AuthenticationRequestRepository.removeAuthenticationRequest(
request, response);
assertNull(result);
}
@Test
void removeAuthenticationRequestWithNonExistentToken() {
var request = mock(HttpServletRequest.class);
var response = mock(HttpServletResponse.class);
when(request.getParameter("RelayState")).thenReturn("nonExistentRelayState");
var result =
jwtSaml2AuthenticationRequestRepository.removeAuthenticationRequest(
request, response);
assertNull(result);
}
@Test
void removeAuthenticationRequestWithOnlyRelayState() {
var request = mock(HttpServletRequest.class);
var response = mock(HttpServletResponse.class);
String relayState = "testRelayState";
when(request.getParameter("RelayState")).thenReturn(relayState);
var result =
jwtSaml2AuthenticationRequestRepository.removeAuthenticationRequest(
request, response);
assertNull(result);
assertFalse(tokenStore.containsKey(relayState));
}
}
+2 -20
View File
@@ -67,7 +67,7 @@ springBoot {
allprojects {
group = 'stirling.software'
version = '2.4.5'
version = '2.4.0'
configurations.configureEach {
exclude group: 'commons-logging', module: 'commons-logging'
@@ -461,24 +461,6 @@ swaggerhubUpload {
oas = "3.0.0" // The version of the OpenAPI Specification you"re using
}
repositories {
if (!rootProject.ext.mavenUrl.isEmpty()) {
maven {
url = rootProject.ext.mavenUrl + '/releases'
credentials(PasswordCredentials) {
username = rootProject.ext.username
password = rootProject.ext.password
}
authentication {
basic(BasicAuthentication)
}
allowInsecureProtocol = true
}
}
maven { url = "https://build.shibboleth.net/maven/releases" }
mavenCentral()
}
dependencies {
implementation project(':stirling-pdf')
implementation project(':common')
@@ -555,4 +537,4 @@ tasks.register('buildRestartHelper', Jar) {
doLast {
println "restart-helper.jar created at: ${destinationDirectory.get()}/restart-helper.jar"
}
}
}
+1 -2
View File
@@ -35,7 +35,7 @@ RUN DISABLE_ADDITIONAL_FEATURES=true \
./gradlew clean build -PbuildWithFrontend=true -x spotlessApply -x spotlessCheck -x test -x sonarqube
# Stage 2: Runtime image
FROM alpine:3.23.3@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659
FROM alpine:3.23.2@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8
@@ -58,7 +58,6 @@ LABEL org.opencontainers.image.keywords="PDF, manipulation, ultra-lite, API, Spr
# Copy scripts
COPY scripts/init-without-ocr.sh /scripts/init-without-ocr.sh
COPY scripts/installFonts.sh /scripts/installFonts.sh
COPY scripts/stirling-diagnostics.sh /scripts/stirling-diagnostics.sh
# Copy built JAR from build stage
COPY --from=build /app/app/core/build/libs/*.jar /app.jar
@@ -32,7 +32,4 @@ services:
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
SHOW_SURVEY: "true"
SPDF_PDFJSON_DUMP: "true"
SPDF_PDFJSON_ANALYZE: "true"
SPDF_PDFJSON_REPEAT_SCAN: "true"
restart: on-failure:5
+217 -271
View File
@@ -11,28 +11,27 @@
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
"@dnd-kit/core": "^6.3.1",
"@embedpdf/core": "^2.5.0",
"@embedpdf/engines": "^2.5.0",
"@embedpdf/models": "^2.5.0",
"@embedpdf/plugin-annotation": "^2.5.0",
"@embedpdf/plugin-bookmark": "^2.5.0",
"@embedpdf/plugin-document-manager": "^2.5.0",
"@embedpdf/plugin-export": "^2.5.0",
"@embedpdf/plugin-history": "^2.5.0",
"@embedpdf/plugin-interaction-manager": "^2.5.0",
"@embedpdf/plugin-pan": "^2.5.0",
"@embedpdf/plugin-print": "^2.5.0",
"@embedpdf/plugin-redaction": "^2.5.0",
"@embedpdf/plugin-render": "^2.5.0",
"@embedpdf/plugin-rotate": "^2.5.0",
"@embedpdf/plugin-scroll": "^2.5.0",
"@embedpdf/plugin-search": "^2.5.0",
"@embedpdf/plugin-selection": "^2.5.0",
"@embedpdf/plugin-spread": "^2.5.0",
"@embedpdf/plugin-thumbnail": "^2.5.0",
"@embedpdf/plugin-tiling": "^2.5.0",
"@embedpdf/plugin-viewport": "^2.5.0",
"@embedpdf/plugin-zoom": "^2.5.0",
"@embedpdf/core": "^1.5.0",
"@embedpdf/engines": "^1.5.0",
"@embedpdf/plugin-annotation": "^1.5.0",
"@embedpdf/plugin-bookmark": "^1.5.0",
"@embedpdf/plugin-export": "^1.5.0",
"@embedpdf/plugin-history": "^1.5.0",
"@embedpdf/plugin-interaction-manager": "^1.5.0",
"@embedpdf/plugin-loader": "^1.5.0",
"@embedpdf/plugin-pan": "^1.5.0",
"@embedpdf/plugin-print": "^1.5.0",
"@embedpdf/plugin-redaction": "^1.5.0",
"@embedpdf/plugin-render": "^1.5.0",
"@embedpdf/plugin-rotate": "^1.5.0",
"@embedpdf/plugin-scroll": "^1.5.0",
"@embedpdf/plugin-search": "^1.5.0",
"@embedpdf/plugin-selection": "^1.5.0",
"@embedpdf/plugin-spread": "^1.5.0",
"@embedpdf/plugin-thumbnail": "^1.5.0",
"@embedpdf/plugin-tiling": "^1.5.0",
"@embedpdf/plugin-viewport": "^1.5.0",
"@embedpdf/plugin-zoom": "^1.5.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@iconify/react": "^6.0.2",
@@ -48,14 +47,13 @@
"@supabase/supabase-js": "^2.47.13",
"@tailwindcss/postcss": "^4.1.13",
"@tanstack/react-virtual": "^3.13.12",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-dialog": "^2.6.0",
"@tauri-apps/plugin-fs": "^2.4.5",
"@tauri-apps/plugin-http": "^2.5.6",
"@tauri-apps/plugin-shell": "^2.3.4",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-fs": "^2.4.0",
"@tauri-apps/plugin-http": "^2.5.4",
"@tauri-apps/plugin-shell": "^2.3.3",
"autoprefixer": "^10.4.21",
"axios": "^1.13.2",
"globals": "^17.1.0",
"axios": "^1.12.2",
"globals": "^17.0.0",
"i18next": "^25.5.2",
"i18next-browser-languagedetector": "^8.2.0",
"jszip": "^3.10.1",
@@ -64,7 +62,7 @@
"pdfjs-dist": "^5.4.149",
"peerjs": "^1.5.5",
"posthog-js": "^1.268.0",
"qrcode.react": "^4.2.0",
"qrcode.react": "^4.1.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-i18next": "^15.7.3",
@@ -77,10 +75,10 @@
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@iconify-json/material-symbols": "^1.2.53",
"@iconify/utils": "^3.1.0",
"@iconify-json/material-symbols": "^1.2.48",
"@iconify/utils": "^3.0.2",
"@playwright/test": "^1.55.0",
"@tauri-apps/cli": "^2.9.6",
"@tauri-apps/cli": "^2.5.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",
@@ -554,13 +552,13 @@
}
},
"node_modules/@embedpdf/core": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-2.5.0.tgz",
"integrity": "sha512-nI7GnA5xCNtJHAdKBLPKJVvi4+yAKjy1sysaDf+qp+z3D81Hy8oAcl///QTaZ9ob0SL2jyqi3x//hKl0Rwmgrw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/core/-/core-1.5.0.tgz",
"integrity": "sha512-Yrh9XoVaT8cUgzgqpJ7hx5wg6BqQrCFirqqlSwVb+Ly9oNn4fZbR9GycIWmzJOU5XBnaOJjXfQSaDyoNP0woNA==",
"license": "MIT",
"dependencies": {
"@embedpdf/engines": "2.5.0",
"@embedpdf/models": "2.5.0"
"@embedpdf/engines": "1.5.0",
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"preact": "^10.26.4",
@@ -571,20 +569,13 @@
}
},
"node_modules/@embedpdf/engines": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-2.5.0.tgz",
"integrity": "sha512-SEknNmQrYvkAZgJllRKXuvXSrHSndDQsr7b3mrIVa9bzV6TeZua0a/YUlvI3/jf74Sdajru3XKPe22iHEOH4Zg==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/engines/-/engines-1.5.0.tgz",
"integrity": "sha512-/GzhjHFHWfOaX7vjgFJX/pyq668wYjoda1bZ9MpwF/EF000Wwy2Q0AOhprjldPFz8ASKjwKwqsXmaqrK99yOAQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/fonts-arabic": "1.0.0",
"@embedpdf/fonts-hebrew": "1.0.0",
"@embedpdf/fonts-jp": "1.0.0",
"@embedpdf/fonts-kr": "1.0.0",
"@embedpdf/fonts-latin": "1.0.0",
"@embedpdf/fonts-sc": "1.0.0",
"@embedpdf/fonts-tc": "1.0.0",
"@embedpdf/models": "2.5.0",
"@embedpdf/pdfium": "2.5.0"
"@embedpdf/models": "1.5.0",
"@embedpdf/pdfium": "1.5.0"
},
"peerDependencies": {
"preact": "^10.26.4",
@@ -594,125 +585,64 @@
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/fonts-arabic": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-arabic/-/fonts-arabic-1.0.0.tgz",
"integrity": "sha512-SnGvQb+LwPZQO2WjjvlmXrJZolJUfLYbLZQSaYUw1vrQyMyJKT4LewvJGG+hZ+Yz2fz7OMIQ+4Gc98mGODZtOg==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-hebrew": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-hebrew/-/fonts-hebrew-1.0.0.tgz",
"integrity": "sha512-5HVAKGL7VqPeTxxADDrSqAFBxfmAXdP8fIqrPwJIKkqdK2643bOer8CqnnpO3/nPoFhkzxhttWMB9BGiqSW62w==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-jp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-jp/-/fonts-jp-1.0.0.tgz",
"integrity": "sha512-BY2tv/mcICUUKf+M/bizf3RU65PMqKClJ/e5o9mgMibxyML0OQvEDwYMRPODQkKgJKXCO3ScHmVvcmXp6kt+fA==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-kr": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-kr/-/fonts-kr-1.0.0.tgz",
"integrity": "sha512-bh88HXSvOBS581kgmihWY7Ijp9hBsvlmXogFG5LSNx9UBAobRcakZiFMGieRBc06hUSkpo7WhjaFM/z/SfQ8dQ==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-latin": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-latin/-/fonts-latin-1.0.0.tgz",
"integrity": "sha512-LLYysdr8O6sRNzhmW3PbF3AeA8xnqvOi4XLFfIfNlW5uEZ+qsJdcfd78Q78sFJMhlaOAYFMziMMsnOzmx463rA==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-sc": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-sc/-/fonts-sc-1.0.0.tgz",
"integrity": "sha512-ETXl7XCwaQLSSvMO3EUDwMNqtL64kX2LlFxarTRi/NsIGGOIxUurGfKtrkmtnKHrWy1jAJSt6oxK2uJhvdvQIw==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/fonts-tc": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@embedpdf/fonts-tc/-/fonts-tc-1.0.0.tgz",
"integrity": "sha512-rGZJbVD6DYS5BbXdpEMnWkpVF0Knar+bsiyb2o3+YRx7O8eyFubEBQUSUInirQk69HA6fc3GhYCg7TyC/oD76Q==",
"license": "OFL-1.1"
},
"node_modules/@embedpdf/models": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-2.5.0.tgz",
"integrity": "sha512-wu7XgargYBQEh46hVnfsmkTF6TvuoP9nAkTASR60s5ourjlT12qL9RiFLpwGkOBfs8E58h8V5hkgKsra5t03Lw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/models/-/models-1.5.0.tgz",
"integrity": "sha512-x/1li3jdag+IzfZkcfRLKLqASLep4v6dgVi3z0JArwaicFra8k1IY2xaVTrwcZyx7pRb/rxvoO9yLHW0Y34NFw==",
"license": "MIT"
},
"node_modules/@embedpdf/pdfium": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-2.5.0.tgz",
"integrity": "sha512-2VEO4cNZsV8ig9upS+C+x3Tb58aqNxiAdaUMlD2ZZT8FgszhsV9xMyEuM2maFRdjeT7EO37FtzYBdXc/K67ivA==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/pdfium/-/pdfium-1.5.0.tgz",
"integrity": "sha512-PI32t2U4ThZC907n2Iwr8E5WqmC574G83u3V9ysNFl29N9kasrY9RiLSzU4W/yQvXPjIbpQHBsbMKXLjCFBI9w==",
"license": "MIT"
},
"node_modules/@embedpdf/plugin-annotation": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-2.5.0.tgz",
"integrity": "sha512-S5zCeWU3hM9jrnaGuW5RAXt+AzXXvQbFtAdCtxHW1hFADiZ97FKr8KS9MGCkkj6C9madtZP6iUJikvnhoLCABQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-annotation/-/plugin-annotation-1.5.0.tgz",
"integrity": "sha512-mxEPI6xYwOGaf9fYfoywuj6nwA10eHFPBuN066MzwphDk6DOHJGZ3Vq8zNQBXh20c/Lb25PL718D7MZWxZLUHg==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0",
"@embedpdf/utils": "2.5.0"
"@embedpdf/models": "1.5.0",
"@embedpdf/utils": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-history": "2.5.0",
"@embedpdf/plugin-interaction-manager": "2.5.0",
"@embedpdf/plugin-selection": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-history": "1.5.0",
"@embedpdf/plugin-interaction-manager": "1.5.0",
"@embedpdf/plugin-selection": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"svelte": ">=5 <6",
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-bookmark": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-bookmark/-/plugin-bookmark-2.5.0.tgz",
"integrity": "sha512-2N5kGoamUrQqWZC5SMWIhdyBHqZN/CdcGf8GVH71FFw3AU6rmZ1AD/AkLzgqoYGIuZFE8ACckdrhtbpsZMmSDQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-bookmark/-/plugin-bookmark-1.5.0.tgz",
"integrity": "sha512-s3C9PtVesy5X8Ds/C9TEElFiqfKGRklG/uNPTROpNoolfpi0h7qX2xqqh/9+FzKH2nHjVcPB7Pp432v16h7eRA==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"svelte": ">=5 <6",
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-document-manager": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-document-manager/-/plugin-document-manager-2.5.0.tgz",
"integrity": "sha512-I8Z/0B7R/YhtVaJFruwFO+QBLIDmQfHx9WVlrDXWZs68YiGwEbjSyizEIEqtulUJxcXfPs2Tf7oIBbdSuPG2NQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"svelte": ">=5 <6",
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-export": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-2.5.0.tgz",
"integrity": "sha512-KC9jXqwcxe76QqfxLx0tnrSdFoApTFOpT+dwrvox186uxYKSmSt1JHFWe4THB/A63hCNr8uMwyswYdFO8fWNHw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-export/-/plugin-export-1.5.0.tgz",
"integrity": "sha512-luk68mNW9l2X31qk4b02phKaqDl9aDXUAgHVz1EWrgwXQ3Oz9WEdu60utYARYDiepDo3Caadll8RwctYSf/anA==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -721,15 +651,31 @@
}
},
"node_modules/@embedpdf/plugin-history": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-2.5.0.tgz",
"integrity": "sha512-Av9NBSE9Or1Y6cXcNWpx0bBZN3yI4vywa6kSNjhaqOrgpQDWMaTO57eApJpyHzBodqEztY+klE9YJ7MH88zm6w==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-history/-/plugin-history-1.5.0.tgz",
"integrity": "sha512-p7PTNNaIr4gH3jLwX+eLJe1DeUXgi21kVGN6SRx/pocH8esg4jqoOeD/YiRRZoZnPOiy0jBXVhkPkwSmY7a2hQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-interaction-manager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-1.5.0.tgz",
"integrity": "sha512-ckHgTfvkW6c5Ta7Mc+Dl9C2foVnvEpqEJ84wyBnqrU0OWbe/jsiPhyKBVeartMGqNI/kVfaQTXupyrKhekAVmg==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -737,16 +683,16 @@
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-interaction-manager": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-interaction-manager/-/plugin-interaction-manager-2.5.0.tgz",
"integrity": "sha512-QrmowLVvC5FNZdvVr2kczSDdnHHOuhf+So0VG5Ythts/OL1bIR/0OOpuyJsScTyo5boYnRkXv8yPf8htL57YKQ==",
"node_modules/@embedpdf/plugin-loader": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-loader/-/plugin-loader-1.5.0.tgz",
"integrity": "sha512-P4YpIZfaW69etYIjphyaL4cGl2pB14h3OdTE0tRQ2pZYZHFLTvlt4q9B3PVSdhlSrHK5nob7jfLGon2U7xCslg==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -755,17 +701,17 @@
}
},
"node_modules/@embedpdf/plugin-pan": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-2.5.0.tgz",
"integrity": "sha512-DfdA+hBm9kGYYy7OuJym6azk2h2U/Geirud+tmVzFSL7+OZ3tZ3K9fqj07w66zx0msyUVlYrXzkYSU9NEmwpLA==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-pan/-/plugin-pan-1.5.0.tgz",
"integrity": "sha512-EMQ08dHqLkZmFVuLOO6h3AAinFPQoA1r6OlL9z+p0sswq31JAgd4X7+xjYIpI01z/V3+cTzPHzp7qwob5E4tbA==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-interaction-manager": "2.5.0",
"@embedpdf/plugin-viewport": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-interaction-manager": "1.5.0",
"@embedpdf/plugin-viewport": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -774,15 +720,15 @@
}
},
"node_modules/@embedpdf/plugin-print": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-print/-/plugin-print-2.5.0.tgz",
"integrity": "sha512-qejq7/0K9hh3hzop+u+Qmn7ijTqGcDhxaiXoPkyl91CZVOyAD8qMBzWnhC7vRNOB7hcYgBP81uegE3se+EIlcA==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-print/-/plugin-print-1.5.0.tgz",
"integrity": "sha512-rjorvNxAZfO9X4cFZVU9fHnldMWqMceJGmr3mH+yj7KdHePvNDDP+omyZyZKtxlUZENaeDI2h6k5z0GbhBz6sQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=18.0.0",
"react-dom": ">=18.0.0",
@@ -791,37 +737,34 @@
}
},
"node_modules/@embedpdf/plugin-redaction": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-redaction/-/plugin-redaction-2.5.0.tgz",
"integrity": "sha512-G0cm1hLWi09gU8WV+IShq2XHkmLtEbk+EvD3dIiyJV2kbOjgwGSC2Ezt8br3DzH6R/0bF6RAbDIpFyS2Q0oMfg==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-redaction/-/plugin-redaction-1.5.0.tgz",
"integrity": "sha512-txiukr5UKAGvJzl6dVBmmIT1v3r/t4e2qYm1hqU2faGgNCa2dwk79x9mDBlvWwxlJXCDFuFE+7Ps9/nU6qmU2w==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0",
"@embedpdf/utils": "2.5.0"
"@embedpdf/models": "1.5.0",
"@embedpdf/utils": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-annotation": "2.5.0",
"@embedpdf/plugin-history": "2.5.0",
"@embedpdf/plugin-interaction-manager": "2.5.0",
"@embedpdf/plugin-selection": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-interaction-manager": "1.5.0",
"@embedpdf/plugin-selection": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"svelte": ">=5 <6",
"vue": ">=3.2.0"
}
},
"node_modules/@embedpdf/plugin-render": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-2.5.0.tgz",
"integrity": "sha512-nrTmg8cVMohcKYiQ/7erErsaWlyaq20OtXbVjmnPNnqz4amJLAjlPyudTJRlWWPyIiri9SF4A0ue5ICDY2sypg==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-render/-/plugin-render-1.5.0.tgz",
"integrity": "sha512-ywwSj0ByrlkvrJIHKRzqxARkOZriki8VJUC+T4MV8fGyF4CzvCRJyKlPktahFz+VxhoodqTh7lBCib68dH+GvA==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -830,15 +773,15 @@
}
},
"node_modules/@embedpdf/plugin-rotate": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-2.5.0.tgz",
"integrity": "sha512-crFsXduaxNZJmVRfgklBpO4x4i9cRxPmfFBvdIoyJ1ea6AGOCL0rQKQcfqHTFdgtPzlVUiIg6Hi2v+033jdLUg==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-rotate/-/plugin-rotate-1.5.0.tgz",
"integrity": "sha512-5EmBCsq0VfrE3xWY6ofuVm8S6aK95EbAycRIk1wczcmTdvpsuXZ6P2ZaECUgYMcpZ6uAg4/kGf8X8VVZuCihSQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -847,16 +790,16 @@
}
},
"node_modules/@embedpdf/plugin-scroll": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-2.5.0.tgz",
"integrity": "sha512-AdLuSgvAaukLl1uQ0FbswcAIPFaR3Jk2ZbEJpWLd9E6iQ+66Cta0Sz8d5J6ndx7VBlRYAZwoqiXF85utJxpQ5g==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-scroll/-/plugin-scroll-1.5.0.tgz",
"integrity": "sha512-RNmTZCZ8X1mA8cw9M7TMDuhO9GtkOalGha2bBL3En3D1IlDRS7PzNNMSMV7eqT7OQICSTltlpJ8p8Qi5esvL/Q==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-viewport": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-viewport": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -865,15 +808,16 @@
}
},
"node_modules/@embedpdf/plugin-search": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-2.5.0.tgz",
"integrity": "sha512-ycHJh05vBZ1PTSdEMgdx6K1py0oklwbwY2eXO4nD54EN9EVZgWlYC4Q+u8nyGOiNL6VmJYcqJ0HmjSWBdmGWBw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-search/-/plugin-search-1.5.0.tgz",
"integrity": "sha512-TB5b0H8Iobx/azVUBIlG2ClaKtf0y3/Xi3E/iB8BwvkIE2+g6EGfp8IMXIn8WDXST6bbvJEP31Ab0Ilp6SVkiw==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-loader": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -882,17 +826,17 @@
}
},
"node_modules/@embedpdf/plugin-selection": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-2.5.0.tgz",
"integrity": "sha512-M3WDjahig/6KE83SZGvTaJWhqEOIzH002k2fpJVuks926UBnfgYCH8uqV7SOUQTneQDmIa0PlyFiuEXDw1Ocrw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-selection/-/plugin-selection-1.5.0.tgz",
"integrity": "sha512-zrxLBAZQoPswDuf9q9DrYaQc6B0Ysc2U1hueTjNH/4+ydfl0BFXZkKR63C2e3YmWtXvKjkoIj0GyPzsiBORLUw==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0",
"@embedpdf/utils": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-interaction-manager": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-interaction-manager": "1.5.0",
"@embedpdf/plugin-viewport": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -901,15 +845,16 @@
}
},
"node_modules/@embedpdf/plugin-spread": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-2.5.0.tgz",
"integrity": "sha512-kG8HZMZmbpUVDxCOEyQzIiMPW+VjjebOl93V+quAH+GAI5Tkg6exPyyQ2+/DOJPCtYX4Kh2z2aeoyK2b7NRgIQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-spread/-/plugin-spread-1.5.0.tgz",
"integrity": "sha512-3EU5Cp+fPQSiMjvMR/P2kXxXry/RlnxHLs4JeskAaH95QcqWW3VD+DrHkWSiLFkdhI18rNNGNlMc5RvDGvbXGQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-loader": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -918,16 +863,16 @@
}
},
"node_modules/@embedpdf/plugin-thumbnail": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-2.5.0.tgz",
"integrity": "sha512-iWofJSXKbWrgvS2fe8v3U1+e2wjBRXD2i1DUcJKnTrqyfjZ8YzUomc5EzdG2RT7uUjtqrcu7463TZ9JHXUkASQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-thumbnail/-/plugin-thumbnail-1.5.0.tgz",
"integrity": "sha512-Z2qpyyr5s2M6460KDGu1Vk6rdbQFIoCpnyFAT6e7UaTIKkqJSNpmjqMsBU5PosYCFu/cClpHPvS7tg9/IKAk6g==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-render": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-render": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -936,18 +881,18 @@
}
},
"node_modules/@embedpdf/plugin-tiling": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-2.5.0.tgz",
"integrity": "sha512-oih0GyGOJvfaXPLSEY+qfC05UUU1ZkADEbr6uCwRMmdHIXu/0ZTJnAToegfWXtfE+Sw0J5wscVkipXXIX5azlw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-tiling/-/plugin-tiling-1.5.0.tgz",
"integrity": "sha512-0Vx9elHNpMM+zv8hEoZXBEm8Q0+4kU52LxOlTYRr1A5FskF836sUct6g1ngwK1bmfbAfpz+62PnYI2EeilDZig==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-render": "2.5.0",
"@embedpdf/plugin-scroll": "2.5.0",
"@embedpdf/plugin-viewport": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-render": "1.5.0",
"@embedpdf/plugin-scroll": "1.5.0",
"@embedpdf/plugin-viewport": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -956,15 +901,15 @@
}
},
"node_modules/@embedpdf/plugin-viewport": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-2.5.0.tgz",
"integrity": "sha512-z0AXHA9Z3rZdCLje7P2NsQbxKLJ4b/l8lgzXOVn5Ow/pIPE0D2P3fn9WzImHTNI1RNrZMdkW9OH3lfkEXFTqHw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-viewport/-/plugin-viewport-1.5.0.tgz",
"integrity": "sha512-G8GDyYRhfehw72+r4qKkydnA5+AU8qH67g01Y12b0DzI0VIzymh/05Z4dK8DsY3jyWPXJfw2hlg5+KDHaMBHgQ==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/core": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -973,17 +918,19 @@
}
},
"node_modules/@embedpdf/plugin-zoom": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-2.5.0.tgz",
"integrity": "sha512-HWJlqXOXdv/kttV+XWCCStUZAeLl66AuaO8BsnPlAPwEADLLCH4tR4XqJQoWr7/r5watKP7UeQ00FsWu0oGclw==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/plugin-zoom/-/plugin-zoom-1.5.0.tgz",
"integrity": "sha512-LiDkCd5/IXg2CRORl1Yikan2op+AYXSxhHzCFatyBdwzVj+n4y9I74OwCI62Mar8WDAIMyXZDCQxGPToSm+zDw==",
"license": "MIT",
"dependencies": {
"@embedpdf/models": "2.5.0"
"@embedpdf/models": "1.5.0",
"hammerjs": "^2.0.8"
},
"peerDependencies": {
"@embedpdf/core": "2.5.0",
"@embedpdf/plugin-scroll": "2.5.0",
"@embedpdf/plugin-viewport": "2.5.0",
"@embedpdf/core": "1.5.0",
"@embedpdf/plugin-interaction-manager": "1.5.0",
"@embedpdf/plugin-scroll": "1.5.0",
"@embedpdf/plugin-viewport": "1.5.0",
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
@@ -992,15 +939,14 @@
}
},
"node_modules/@embedpdf/utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/utils/-/utils-2.5.0.tgz",
"integrity": "sha512-JjYj6BRzu9oesA1JOqKPFMEWKinjvJIjziWu1j6lDXxLsE59bkShjUKbaEG+lkXRspuZRWNP++rzE2p2Ht4veg==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@embedpdf/utils/-/utils-1.5.0.tgz",
"integrity": "sha512-L6jsAPQPGM8ne+MMFAd5gqXb1RNEgNyh16VvVUVKcVnJlBhwil59nVeEQ0cwPhjF5qVeY6MQDIOjBzJqkgXOYg==",
"license": "MIT",
"peerDependencies": {
"preact": "^10.26.4",
"react": ">=16.8.0",
"react-dom": ">=16.8.0",
"svelte": ">=5 <6",
"vue": ">=3.2.0"
}
},
@@ -1952,9 +1898,9 @@
}
},
"node_modules/@iconify-json/material-symbols": {
"version": "1.2.53",
"resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.53.tgz",
"integrity": "sha512-2jXBKFdNzL9zy6chnJqubykL9WZno7rEP6/isSzpp6fKJJMXXhRtVkaGw1Clle0RlXGWzVkd/eiYUH8f9/ILrQ==",
"version": "1.2.50",
"resolved": "https://registry.npmjs.org/@iconify-json/material-symbols/-/material-symbols-1.2.50.tgz",
"integrity": "sha512-71tjHR70h46LHtBFab3fAd2V/wPTO7JMV5lKnRn3IcF303LaFgAlO0BZeTJDcmCv9d0snRZmnoLZAJVD7/eisw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -4181,37 +4127,28 @@
"node": ">= 10"
}
},
"node_modules/@tauri-apps/plugin-dialog": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.6.0.tgz",
"integrity": "sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.8.0"
}
},
"node_modules/@tauri-apps/plugin-fs": {
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.4.5.tgz",
"integrity": "sha512-dVxWWGE6VrOxC7/jlhyE+ON/Cc2REJlM35R3PJX3UvFw2XwYhLGQVAIyrehenDdKjotipjYEVc4YjOl3qq90fA==",
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-fs/-/plugin-fs-2.4.4.tgz",
"integrity": "sha512-MTorXxIRmOnOPT1jZ3w96vjSuScER38ryXY88vl5F0uiKdnvTKKTtaEjTEo8uPbl4e3gnUtfsDVwC7h77GQLvQ==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.8.0"
}
},
"node_modules/@tauri-apps/plugin-http": {
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.5.6.tgz",
"integrity": "sha512-KhCK3TDNDF4vdz75/j+KNQipYKf+295Visa8r32QcXScg0+D3JwShcCM6D+FN8WuDF24X3KSiAB8QtRxW6jKRA==",
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-http/-/plugin-http-2.5.4.tgz",
"integrity": "sha512-/i4U/9za3mrytTgfRn5RHneKubZE/dwRmshYwyMvNRlkWjvu1m4Ma72kcbVJMZFGXpkbl+qLyWMGrihtWB76Zg==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.8.0"
}
},
"node_modules/@tauri-apps/plugin-shell": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.3.4.tgz",
"integrity": "sha512-ktsRWf8wHLD17aZEyqE8c5x98eNAuTizR1FSX475zQ4TxaiJnhwksLygQz+AGwckJL5bfEP13nWrlTNQJUpKpA==",
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.3.3.tgz",
"integrity": "sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.8.0"
@@ -7096,9 +7033,9 @@
}
},
"node_modules/devalue": {
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz",
"integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.1.tgz",
"integrity": "sha512-jDwizj+IlEZBunHcOuuFVBnIMPAEHvTsJj0BcIp94xYguLRVBcXO853px/MyIJvbVzWdsGvrRweIUWJw8hBP7A==",
"license": "MIT",
"peer": true
},
@@ -8619,9 +8556,9 @@
}
},
"node_modules/globals": {
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.1.0.tgz",
"integrity": "sha512-8HoIcWI5fCvG5NADj4bDav+er9B9JMj2vyL2pI8D0eismKyUvPLTSs+Ln3wqhwcp306i73iyVnEKx3F6T47TGw==",
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.0.0.tgz",
"integrity": "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==",
"license": "MIT",
"engines": {
"node": ">=18"
@@ -8723,6 +8660,15 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/hammerjs": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
"integrity": "sha512-tSQXBXS/MWQOn/RKckawJ61vvsDpCom87JgxiYdGwHdOa0ht0vzUWDlfioofFCRU0L+6NGDt6XzbgoJvZkMeRQ==",
"license": "MIT",
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/has-bigints": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz",
@@ -12230,9 +12176,9 @@
"license": "0BSD"
},
"node_modules/react-router": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.0.tgz",
"integrity": "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw==",
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.11.0.tgz",
"integrity": "sha512-uI4JkMmjbWCZc01WVP2cH7ZfSzH91JAZUDd7/nIprDgWxBV1TkkmLToFh7EbMTcMak8URFRa2YoBL/W8GWnCTQ==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
@@ -12252,12 +12198,12 @@
}
},
"node_modules/react-router-dom": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.0.tgz",
"integrity": "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g==",
"version": "7.11.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.11.0.tgz",
"integrity": "sha512-e49Ir/kMGRzFOOrYQBdoitq3ULigw4lKbAyKusnvtDu2t4dBX4AGYPrzNvorXmVuOyeakai6FUPW5MmibvVG8g==",
"license": "MIT",
"dependencies": {
"react-router": "7.13.0"
"react-router": "7.11.0"
},
"engines": {
"node": ">=20.0.0"
@@ -13502,9 +13448,9 @@
}
},
"node_modules/svelte": {
"version": "5.48.2",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.2.tgz",
"integrity": "sha512-VPWD+UyoSFZ7Nxix5K/F8yWiKWOiROkLlWYXOZReE0TUycw+58YWB3D6lAKT+57xmN99wRX4H3oZmw0NPy7y3Q==",
"version": "5.46.1",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.46.1.tgz",
"integrity": "sha512-ynjfCHD3nP2el70kN5Pmg37sSi0EjOm9FgHYQdC4giWG/hzO3AatzXXJJgP305uIhGQxSufJLuYWtkY8uK/8RA==",
"license": "MIT",
"peer": true,
"dependencies": {
@@ -13516,7 +13462,7 @@
"aria-query": "^5.3.1",
"axobject-query": "^4.1.0",
"clsx": "^2.1.1",
"devalue": "^5.6.2",
"devalue": "^5.5.0",
"esm-env": "^1.2.1",
"esrap": "^2.2.1",
"is-reference": "^3.0.3",
+31 -34
View File
@@ -7,28 +7,27 @@
"dependencies": {
"@atlaskit/pragmatic-drag-and-drop": "^1.7.7",
"@dnd-kit/core": "^6.3.1",
"@embedpdf/core": "^2.5.0",
"@embedpdf/engines": "^2.5.0",
"@embedpdf/models": "^2.5.0",
"@embedpdf/plugin-annotation": "^2.5.0",
"@embedpdf/plugin-bookmark": "^2.5.0",
"@embedpdf/plugin-export": "^2.5.0",
"@embedpdf/plugin-history": "^2.5.0",
"@embedpdf/plugin-document-manager": "^2.5.0",
"@embedpdf/plugin-interaction-manager": "^2.5.0",
"@embedpdf/plugin-pan": "^2.5.0",
"@embedpdf/plugin-print": "^2.5.0",
"@embedpdf/plugin-redaction": "^2.5.0",
"@embedpdf/plugin-render": "^2.5.0",
"@embedpdf/plugin-rotate": "^2.5.0",
"@embedpdf/plugin-scroll": "^2.5.0",
"@embedpdf/plugin-search": "^2.5.0",
"@embedpdf/plugin-selection": "^2.5.0",
"@embedpdf/plugin-spread": "^2.5.0",
"@embedpdf/plugin-thumbnail": "^2.5.0",
"@embedpdf/plugin-tiling": "^2.5.0",
"@embedpdf/plugin-viewport": "^2.5.0",
"@embedpdf/plugin-zoom": "^2.5.0",
"@embedpdf/core": "^1.5.0",
"@embedpdf/engines": "^1.5.0",
"@embedpdf/plugin-annotation": "^1.5.0",
"@embedpdf/plugin-bookmark": "^1.5.0",
"@embedpdf/plugin-export": "^1.5.0",
"@embedpdf/plugin-history": "^1.5.0",
"@embedpdf/plugin-interaction-manager": "^1.5.0",
"@embedpdf/plugin-loader": "^1.5.0",
"@embedpdf/plugin-pan": "^1.5.0",
"@embedpdf/plugin-print": "^1.5.0",
"@embedpdf/plugin-redaction": "^1.5.0",
"@embedpdf/plugin-render": "^1.5.0",
"@embedpdf/plugin-rotate": "^1.5.0",
"@embedpdf/plugin-scroll": "^1.5.0",
"@embedpdf/plugin-search": "^1.5.0",
"@embedpdf/plugin-selection": "^1.5.0",
"@embedpdf/plugin-spread": "^1.5.0",
"@embedpdf/plugin-thumbnail": "^1.5.0",
"@embedpdf/plugin-tiling": "^1.5.0",
"@embedpdf/plugin-viewport": "^1.5.0",
"@embedpdf/plugin-zoom": "^1.5.0",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@iconify/react": "^6.0.2",
@@ -44,14 +43,13 @@
"@supabase/supabase-js": "^2.47.13",
"@tailwindcss/postcss": "^4.1.13",
"@tanstack/react-virtual": "^3.13.12",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-dialog": "^2.6.0",
"@tauri-apps/plugin-fs": "^2.4.5",
"@tauri-apps/plugin-http": "^2.5.6",
"@tauri-apps/plugin-shell": "^2.3.4",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-fs": "^2.4.0",
"@tauri-apps/plugin-http": "^2.5.4",
"@tauri-apps/plugin-shell": "^2.3.3",
"autoprefixer": "^10.4.21",
"axios": "^1.13.2",
"globals": "^17.1.0",
"axios": "^1.12.2",
"globals": "^17.0.0",
"i18next": "^25.5.2",
"i18next-browser-languagedetector": "^8.2.0",
"jszip": "^3.10.1",
@@ -60,7 +58,7 @@
"pdfjs-dist": "^5.4.149",
"peerjs": "^1.5.5",
"posthog-js": "^1.268.0",
"qrcode.react": "^4.2.0",
"qrcode.react": "^4.1.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-i18next": "^15.7.3",
@@ -72,7 +70,6 @@
"web-vitals": "^5.1.0"
},
"scripts": {
"pretauri-build": "node scripts/build-provisioner.mjs",
"predev": "npm run generate-icons",
"dev": "vite",
"prebuild": "npm run generate-icons",
@@ -129,10 +126,10 @@
},
"devDependencies": {
"@eslint/js": "^9.36.0",
"@iconify-json/material-symbols": "^1.2.53",
"@iconify/utils": "^3.1.0",
"@iconify-json/material-symbols": "^1.2.48",
"@iconify/utils": "^3.0.2",
"@playwright/test": "^1.55.0",
"@tauri-apps/cli": "^2.9.6",
"@tauri-apps/cli": "^2.5.0",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.8.0",
"@testing-library/react": "^16.3.0",
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "الصفحات والرقم الابتدائي"
positionAndPages = "الموضع والصفحات"
preview = "اختيار الموضع"
previewDisclaimer = "المعاينة تقديرية. قد يختلف الناتج النهائي بسبب مقاييس خطوط PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "حدد ملف PDF:"
@@ -441,9 +439,7 @@ fullscreen = "ملء الشاشة"
[settings.general.updates]
title = "تحديثات البرنامج"
description = "التحقق من التحديثات وعرض معلومات الإصدار"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "الإصدار الحالي"
latestVersion = "أحدث إصدار"
checkForUpdates = "التحقق من التحديثات"
viewDetails = "عرض التفاصيل"
@@ -954,7 +950,6 @@ title = "تقسيم تلقائي بالحجم/العدد"
desc = "تقسيم ملف PDF واحد إلى مستندات متعددة بناءً على الحجم أو عدد الصفحات أو عدد المستندات"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "استبدال وعكس الألوان"
desc = "استبدال الألوان أو عكسها في مستندات PDF"
@@ -969,22 +964,18 @@ title = "المسح الآلي للمجلدات"
desc = "رابط إلى دليل المسح الآلي للمجلدات"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "دليل SSO"
desc = "رابط إلى دليل SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "إعداد معزول"
desc = "رابط إلى دليل الإعداد المعزول"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "إضافة كلمة مرور"
desc = "تشفير مستند PDF الخاص بك بكلمة مرور."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "تغيير الأذونات"
desc = "تغيير قيود المستند وأذوناته"
@@ -994,12 +985,10 @@ title = "أتمتة"
desc = "ابنِ تدفّقات عمل متعددة الخطوات بسلسلة إجراءات PDF. مثالي للمهام المتكررة."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "تراكب ملف PDF فوق آخر"
title = "تراكب ملفات PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "محرر نصوص PDF"
desc = "مراجعة وتحرير صادرات Stirling PDF بصيغة JSON مع تحرير نصوص مجمّعة وإعادة إنشاء PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "صيغة الناتج"
pdfaNote = "PDF/A-1b أكثر توافقًا، وPDF/A-2b يدعم مزيدًا من الميزات."
pdfaFormat = "تنسيق PDF/A"
pdfaDigitalSignatureWarning = "يحتوي PDF على توقيع رقمي. سيتم إزالة هذا في الخطوة التالية."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "يحتوي ملف PDF على توقيع رقمي. سيتم إزالة ذلك في الخطوة التالية."
pdfxDescription = "PDF/X هو مجموعة فرعية قياسية من PDF وفق ISO يوفّر طباعة موثوقة وتبادُل الرسومات."
fileFormat = "صيغة الملف"
@@ -2646,7 +2633,6 @@ label = "ملف PDF الأصلي"
[compare.edited]
label = "ملف PDF المعدل"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "إعادة تشغيل المقارنة؟"
@@ -3567,44 +3553,6 @@ imageSize = "حجم الصورة"
margin = "الهامش"
positionAndFormatting = "الموضع والتنسيق"
quickPosition = "اختر موضعًا على الصفحة لوضع الختم."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "حدث خطأ أثناء إضافة الختم إلى ملف PDF."
@@ -4523,18 +4471,10 @@ description = "تهيئة مسارات مخصصة لنظام الملفات لم
[admin.settings.general.customPaths.pipeline]
label = "دلائل خط الأنابيب"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "دليل المجلدات المراقَبة"
description = "الدليل الذي يراقب فيه خط الأنابيب ملفات PDF الواردة (اتركه فارغًا للإعداد الافتراضي: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "دليل المجلدات المنتهية"
description = "الدليل الذي تُخرَج فيه ملفات PDF المعالجة (اتركه فارغًا للإعداد الافتراضي: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "الحد الأقصى لعدد محاولات تسجيل الدخ
label = "وقت إعادة التعيين لتسجيل الدخول (بالدقائق)"
description = "المدة قبل إعادة تعيين عدد المحاولات الفاشلة"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "تعطيل حماية CSRF"
description = "تعطيل حماية تزوير طلبات المواقع (غير مستحسن)"
@@ -6573,7 +6506,6 @@ link = "أو الاتصال بحساب مُستضاف ذاتيًا"
title = "الاتصال بالخادم"
subtitle = "أدخل عنوان URL لخادمك المستضاف ذاتياً"
testing = "جارٍ اختبار الاتصال..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Səhifələr və başlanğıc nömrəsi"
positionAndPages = "Mövqe və səhifələr"
preview = "Mövqe seçimi"
previewDisclaimer = "Önizləmə təxmindir. Son çıxış PDF şrift metriklərinə görə dəyişə bilər."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF faylını seçin:"
@@ -441,9 +439,7 @@ fullscreen = "Tam ekran"
[settings.general.updates]
title = "Proqram yeniləmələri"
description = "Yeniləmələri yoxlayın və versiya məlumatlarını görün"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Cari versiya"
latestVersion = "Ən son versiya"
checkForUpdates = "Yeniləmələri yoxla"
viewDetails = "Ətraflı bax"
@@ -954,7 +950,6 @@ title = "Say/Ölçüyə Əsasən Avtomatik Ayır"
desc = "PDF-i ölçüyə, səhifə sayına və ya sənəd sayına əsasən bir neçə PDF-ə ayır."
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Rəngi əvəz et və invert et"
desc = "PDF sənədlərində rəngləri əvəz edin və ya invert edin"
@@ -969,22 +964,18 @@ title = "Avtomatik qovluq skanı"
desc = "Avtomatlaşdırılmış qovluq skan təlimatına keçid"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO təlimatı"
desc = "SSO təlimatına keçid"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Şəbəkəsiz quraşdırma"
desc = "Təcrid edilmiş quraşdırma təlimatına keçid"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Şifr Əlavə Et"
desc = "Sənədini şifr ilə kilidlə."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "İcazələri Dəyişdir"
desc = "Sənəd məhdudiyyətlərini və icazələrini dəyişin"
@@ -994,12 +985,10 @@ title = "Avtomatlaşdır"
desc = "PDF əməliyyatlarını zəncirləyərək çoxaddımlı iş axınları qurun. Təkrarlanan tapşırıqlar üçün idealdır."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Bir PDF-i digərinin üstünə qoyur"
title = "Üst-Üstə Qoy"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF Mətn Redaktoru"
desc = "Qruplaşdırılmış mətn redaktəsi və PDF yenidən yaradılması ilə Stirling PDF JSON ixraclarını nəzərdən keçirin və redaktə edin"
@@ -1302,8 +1291,6 @@ outputFormat = "Çıxış formatı"
pdfaNote = "PDF/A-1b daha uyğundur, PDF/A-2b daha çox funksiyanı dəstəkləyir."
pdfaFormat = "PDF/A formatı"
pdfaDigitalSignatureWarning = "PDF Rəqəmsal İmza Ehtiva Edir.Bu, növbəti addımda silinəcək."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF rəqəmsal imza ehtiva edir. Bu imza növbəti addımda silinəcək."
pdfxDescription = "PDF/X etibarlı çap və qrafika mübadiləsi üçün ISO standartlı PDF alt dəstidir."
fileFormat = "Fayl formatı"
@@ -2646,7 +2633,6 @@ label = "Orijinal PDF"
[compare.edited]
label = "Redaktə edilmiş PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Müqayisə yenidən işlənsin?"
@@ -3567,44 +3553,6 @@ imageSize = "Şəkil ölçüsü"
margin = "Kənar boşluğu"
positionAndFormatting = "Mövqe və formatlama"
quickPosition = "Möhürü yerləşdirmək üçün səhifədə bir mövqe seçin."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF-ə möhür əlavə edilərkən xəta baş verdi."
@@ -4523,18 +4471,10 @@ description = "Pipeline emalı və xarici alətlər üçün fərdi fayl sistemi
[admin.settings.general.customPaths.pipeline]
label = "Pipeline Qovluqları"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "İzlənən Qovluqlar Qovluğu"
description = "Pipeline daxil olan PDF-ləri izlədiyi qovluq (defolt üçün boş saxlayın: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Tamamlanmış Qovluqlar Qovluğu"
description = "Emal olunmuş PDF-lərin çıxarıldığı qovluq (defolt üçün boş saxlayın: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Hesabın bloklanmasından əvvəl maksimal uğursuz giriş cəhdl
label = "Girişi sıfırlama vaxtı (dəqiqə)"
description = "Uğursuz giriş cəhdlərinin sıfırlanmasına qədər olan vaxt"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF mühafizəsini söndür"
description = "Cross-Site Request Forgery mühafizəsini söndür (tövsiyə olunmur)"
@@ -6573,7 +6506,6 @@ link = "və ya self-hosted hesaba qoşulun"
title = "Serverə qoşulun"
subtitle = "Öz serverinizin URL ünvanını daxil edin"
testing = "Bağlantı yoxlanılır..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Страници и начално число"
positionAndPages = "Позиция и страници"
preview = "Избор на позиция"
previewDisclaimer = "Прегледът е ориентировъчен. Крайният резултат може да се различава заради метриките на PDF шрифтовете."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Изберете PDF файл:"
@@ -441,9 +439,7 @@ fullscreen = "Цял екран"
[settings.general.updates]
title = "Актуализации на софтуера"
description = "Проверете за актуализации и вижте информация за версията"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Текуща версия"
latestVersion = "Последна версия"
checkForUpdates = "Провери за актуализации"
viewDetails = "Виж подробности"
@@ -954,7 +950,6 @@ title = "Авто делене по размер/брой"
desc = "Разделете един PDF на множество документи въз основа на размер, брой страници или брой документи"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Смени/обърни цветове"
desc = "Заместване или инвертиране на цветове в PDF документи"
@@ -969,22 +964,18 @@ title = "Авто сканиране на папки"
desc = "Връзка към ръководство за автоматизирано сканиране на папки"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Ръководство за SSO"
desc = "Връзка към SSO ръководство"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Настройка за airgapped среда"
desc = "Връзка към ръководство за air‑gapped настройка"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Добавете парола"
desc = "Шифровайте вашия PDF документ с парола."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Промяна на правата"
desc = "Промяна на ограниченията и разрешенията на документа"
@@ -994,12 +985,10 @@ title = "Автоматизация"
desc = "Създавайте многостъпкови работни процеси чрез свързване на PDF действия. Идеално за повтарящи се задачи."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Наслагва PDF файлове върху друг PDF"
title = "Наслагване PDF-и"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF текстов редактор"
desc = "Преглеждайте и редактирайте JSON експорти на Stirling PDF с групово редактиране на текст и повторно генериране на PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Изходен формат"
pdfaNote = "PDF/A-1b е по-съвместим, PDF/A-2b поддържа повече функции."
pdfaFormat = "Формат PDF/A"
pdfaDigitalSignatureWarning = "PDF файлът съдържа цифров подпис. Това ще бъде премахнато в следващата стъпка."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF файлът съдържа цифров подпис. Той ще бъде премахнат на следващата стъпка."
pdfxDescription = "PDF/X е подмножество на PDF по стандарта ISO за надежден печат и обмен на графики."
fileFormat = "Файлов формат"
@@ -2646,7 +2633,6 @@ label = "Оригинален PDF"
[compare.edited]
label = "Редактиран PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Да се изпълни сравнение отново?"
@@ -3567,44 +3553,6 @@ imageSize = "Размер на изображението"
margin = "Отстъп"
positionAndFormatting = "Позиция и форматиране"
quickPosition = "Изберете позиция на страницата, където да поставите печата."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Възникна грешка при добавяне на печат към PDF."
@@ -4523,18 +4471,10 @@ description = "Конфигурирайте персонализирани пъ
[admin.settings.general.customPaths.pipeline]
label = "Директории за Pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Директория за наблюдавани папки"
description = "Директория, където pipeline наблюдава за входящи PDF (оставете празно за подразбиране: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Директория за завършени папки"
description = "Директория, където се извеждат обработените PDF (оставете празно за подразбиране: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Максимален брой неуспешни опити за
label = "Време за нулиране на входа (минути)"
description = "Време, преди неуспешните опити за вход да се нулират"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Деактивирай CSRF защита"
description = "Деактивира защита срещу Cross-Site Request Forgery (не се препоръчва)"
@@ -6573,7 +6506,6 @@ link = "или се свържете със самостоятелно хост
title = "Свързване към сървър"
subtitle = "Въведете URL на самостоятелно хоствания си сървър"
testing = "Тестване на връзката..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "ཤོག་ངོས་དང་འགོ་འཛུགས
positionAndPages = "གནས་བབ་དང་ཤོག་ངོས།"
preview = "ལས་གནས་འདེམས་པ།"
previewDisclaimer = "སྔོན་ལྟ་ནི་ཚོད་དཔག་ཡིན། མཐའ་མའི་ཐོན་འབྲས་དེ་PDFཡིག་གཟུགས་ཚད་གཞིའི་རྐྱེན་གྱིས་མི་འདྲ་བ་ཆགས་སྲིད།"
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDFཡིག་ཆ་འདེམས།"
@@ -441,9 +439,7 @@ fullscreen = "བརྙན་ཤེལ་ཆ་ཚང་།"
[settings.general.updates]
title = "མཉེན་ཆས་གསར་བརྗེ།"
description = "གསར་བརྗེའི་གནས་ཚུལ་ལ་ཞིབ་བཤེར་དང་ཐོན་རིམ་གྱི་ཆ་འཕྲིན་ལ་ལྟོས།"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "ད་ལྟའི་ཐོན་རིམ།"
latestVersion = "ཐོན་རིམ་གསར་ཤོས།"
checkForUpdates = "གསར་བརྗེ་ལ་ཞིབ་བཤེར།"
viewDetails = "ཞིབ་ཕྲའི་གནས་ཚུལ་ལ་ལྟོས།"
@@ -954,7 +950,6 @@ title = "ཆེ་ཆུང་/གྲངས་ཚད་ཀྱིས་རང་
desc = "རང་འགུལ་གྱིས་ཡིག་ཆའི་ཆེ་ཆུང་དང་ཡང་ན་ཤོག་ངོས་གྲངས་ལ་གཞིགས་ནས་PDFsབགོད་དགོས།"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "ཁ་དོག་བརྗེ་ལེན་དང་བསྒྱུར་བ།"
desc = "PDFཡིག་ཆའི་ནང་ཁ་དོག་བརྗེ་ལེན་བྱེད་པའམ་ཡང་ན་བསྒྱུར་བ།"
@@ -969,22 +964,18 @@ title = "རང་འགུལ་ཅན་གྱི་སྣོད་བཅུ
desc = "རང་འགུལ་སྣོད་ཀྱི་པར་བཤེར་ལམ་སྟོན་ལ་འབྲེལ་མཐུད་བྱེད།"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO ལམ་སྟོན།"
desc = "SSO ལམ་སྟོན་ལ་འབྲེལ་མཐུད་བྱེད།"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "མཁའ་དབྱིངས་ཀྱི་ཆ་སྒྲིག་སྒྲིག་བཀོད།"
desc = "མཁའ་རླུང་གི་བར་ཐག་གིས་སྒྲིག་པའི་སྒྲིག་ལམ་ལ་འབྲེལ་མཐུད་བྱེད་པ།"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "གསང་གྲངས་ཁ་སྣོན་བྱེད།"
desc = "གསང་གྲངས་སྲུང་སྐྱོབ་དང་ཚད་བཀག་PDFཡིག་ཆ་ལ་ཁ་སྣོན་བྱེད་པ།"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "འཕོ་འགྱུར།"
desc = "ཡིག་ཆའི་ཚད་བཀག་དང་ཆོག་མཆན་བསྒྱུར་བ།"
@@ -994,12 +985,10 @@ title = "རང་འགུལ་ཅན།"
desc = "གོམ་པ་མང་པོའི་ལས་ཀའི་འགྲོ་ལུགས་དེ་PDFབྱ་སྤྱོད་མཉམ་དུ་སྒྲིག་ནས་བཟོས། ལས་འགན་ཡང་བསྐྱར་འཚོག་པར་འཚམ་པོ་ཡོད།"
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "གཞན་ཞིག་གི་སྟེང་དུ་PDFགཅིག་བཀབ་དགོས།"
title = "བཀབ་པའི་PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDFཡིག་འབྲིའི་རྩོམ་སྒྲིག་པ།"
desc = "ད་ཡོད་ཀྱི་ཡིག་ཆ་དང་པར་རིས་PDFནང་དུ་རྩོམ་སྒྲིག་བྱས།"
@@ -1302,8 +1291,6 @@ outputFormat = "ཐོན་འབྲས་རྣམ་གྲངས།"
pdfaNote = "PDF/A-1b མཐུན་སྒྲིལ་ཆེ་བ་དང་། PDF/A-2b ཡིས་ཁྱད་ཆོས་མང་བ་ལ་རྒྱབ་སྐྱོར་བྱེད་ཀྱི་ཡོད། PDF/A-3b ཡིས་བཙུགས་པའི་ཡིག་ཆ་ལ་རྒྱབ་སྐྱོར་བྱེད་ཀྱི་ཡོད།"
pdfaFormat = "PDF/A རྣམ་གཞག"
pdfaDigitalSignatureWarning = "PDF ནང་ཨང་གྲངས་ཀྱི་མཚན་རྟགས་ཡོད། འདི་གོམ་པ་རྗེས་མར་མེད་པར་བཟོ་རྒྱུ་རེད།"
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "དེབ PDF ནང་ གློག་སྒྲིག་མིང་རྟགས་ཡོད། རྗེས་སྟབས་ནས་འདི་བསུབ་བྱེད།"
pdfxDescription = "PDF/X ནི ISO ཚད་ལྡན་PDF གྲངས་ཆ་ཞིག་ཡིན་པས་ ཡིད་ཆེན་པོར་པར་འདེབས་དང་ རི་མོ་བརྗེ་སོར་བྱེད་ཐུབ།"
fileFormat = "ཡིག་ཆ།"
@@ -2646,7 +2633,6 @@ label = "ཐོག་མའི་PDF"
[compare.edited]
label = "རྩོམ་སྒྲིག་བྱས་པའི་PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "བསྐྱར་དུ་འགྲན་བསྡུར།"
@@ -3567,44 +3553,6 @@ imageSize = "པར་རིས་ཚད་གཞི།"
margin = "མཐའ་ཤོག"
positionAndFormatting = "ལས་གནས་དང་རྩ་སྒྲིག།"
quickPosition = "ཤོག་ངོས་སྟེང་དུ་གནས་ཡུལ་ཞིག་འདེམས་ནས་མཚོན་རྟགས་འཇོག་དགོས།"
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF ལ་མཚོན་རྟགས་ཁ་སྣོན་བྱེད་སྐབས་ནོར་འཁྲུལ་བྱུང་ཡོད།"
@@ -4523,18 +4471,10 @@ description = "མདོང་ལམ་ལས་སྣོན་དང་ཕྱ
[admin.settings.general.customPaths.pipeline]
label = "མདོང་ལམ་ངོས་འཛིན།"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "བལྟ་བའི་སྣོད་ཆས་སྣོད་ཐོ།"
description = "སྣོད་ཐོ་དེ་PDFནང་དུ་འོང་བའི་མདོང་ལམ་གྱི་ལྟ་རྟོག་བྱེད་ཆས་(སྔོན་སྒྲིག་ལ་སྟོང་པར་བཞག་པ་: /pipeline/whatedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "མཇུག་སྒྲིལ། སྣོད་ཐོ་ཐོ་གཞུང་།"
description = "ལས་སྣོན་བྱས་པའི་PDFs ཐོན་ཚད་ཡོད་པའི་སྣོད་ཐོ། (སྔོན་སྒྲིག་ལ་སྟོང་པ་སྟོང་པ་: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "རྩིས་ཁྲའི་བཀག་སྡོམ་མ་
label = "ནང་འཇུག་བསྐྱར་སྒྲིག་དུས་ཚོད།"
description = "ནང་འཇུག་ཚོད་ལྟ་འཐུས་ཤོར་མ་བྱུང་གོང་གི་དུས་ཚོད།"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF སྲུང་སྐྱོབ།"
description = "ས་ཁོངས་བརྒལ་བའི་རེ་འདུན་རྫུན་བཟོ་སྲུང་སྐྱོབ།"
@@ -6573,7 +6506,6 @@ link = "ཡང་ན་རང་གིས་བདག་གཉེར་བྱེ
title = "སར་བར་མཐུད་པ།"
subtitle = "ཁྱེད་རང་གི་རང་གིས་གཉེར་བའི་སར་བར་གྱི་URLནང་འཇུག་བྱེད།"
testing = "ཚོད་ལྟ། འབྲེལ་བ། ..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "སིཊི་རི་ལིང་PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Pàgines i número inicial"
positionAndPages = "Posició i pàgines"
preview = "Selecció de posició"
previewDisclaimer = "La previsualització és aproximada. El resultat final pot variar a causa de les mètriques del tipus de lletra del PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Selecciona PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Pantalla completa"
[settings.general.updates]
title = "Actualitzacions de programari"
description = "Comprova actualitzacions i informació de la versió"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versió actual"
latestVersion = "Última versió"
checkForUpdates = "Comprova actualitzacions"
viewDetails = "Veure detalls"
@@ -954,7 +950,6 @@ title = "Divideix auto per mida/pàg."
desc = "Divideix un únic PDF en múltiples documents basant-se en la mida, el nombre de pàgines o el nombre de documents"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Substitueix i inverteix el color"
desc = "Substitueix o inverteix colors en documents PDF"
@@ -969,22 +964,18 @@ title = "Escaneig automàtic de carpeta"
desc = "Enllaç a la guia d'escaneig automàtic de carpetes"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guia d'SSO"
desc = "Enllaç a la guia d'SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Configuració air-gapped"
desc = "Enllaç a la guia de configuració en entorn air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Afegir Contrasenya"
desc = "Xifra el document PDF amb contrasenya."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Canviar Permissos"
desc = "Canvia les restriccions i els permisos del document"
@@ -994,12 +985,10 @@ title = "Automatitza"
desc = "Construeix fluxos de treball multietapa enllaçant accions PDF. Ideal per a tasques recurrents."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Superposa PDFs sobre un altre PDF"
title = "Superposar PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor de text PDF"
desc = "Revisa i edita exportacions JSON de Stirling PDF amb edició de text agrupada i regeneració del PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Format de sortida"
pdfaNote = "PDF/A-1b és més compatible; PDF/A-2b admet més funcions."
pdfaFormat = "Format PDF/A"
pdfaDigitalSignatureWarning = "El PDF conté una signatura digital. Aquesta serà eliminada en el següent pas."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "El PDF conté una signatura digital. Aquesta se suprimirà en el pas següent."
pdfxDescription = "PDF/X és un subconjunt de PDF estàndard ISO per a una impressió fiable i un intercanvi de gràfics fiable."
fileFormat = "Format de fitxer"
@@ -2646,7 +2633,6 @@ label = "PDF original"
[compare.edited]
label = "PDF editat"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Tornar a executar la comparació?"
@@ -3567,44 +3553,6 @@ imageSize = "Mida de la imatge"
margin = "Marge"
positionAndFormatting = "Posició i format"
quickPosition = "Seleccioneu una posició a la pàgina per col·locar el segell."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "S'ha produït un error en afegir el segell al PDF."
@@ -4523,18 +4471,10 @@ description = "Configureu camins personalitzats del sistema de fitxers per al pr
[admin.settings.general.customPaths.pipeline]
label = "Directoris de pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Directori de carpetes monitoritzades"
description = "Directori on la pipeline monitoritza l'arribada de PDFs (deixeu-ho buit per al valor per defecte: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Directori de carpetes finalitzades"
description = "Directori on es generen els PDFs processats (deixeu-ho buit per al valor per defecte: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Nombre màxim d'intents d'inici de sessió fallits abans de bloqu
label = "Temps de reinicialització d'inici de sessió (minuts)"
description = "Temps abans que es restableixin els intents d'inici de sessió fallits"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Desactiva la protecció CSRF"
description = "Desactiva la protecció contra Cross-Site Request Forgery (no recomanat)"
@@ -6573,7 +6506,6 @@ link = "o connecteu-vos a un compte autoallotjat"
title = "Connecta't al servidor"
subtitle = "Introdueix la URL del servidor autoallotjat"
testing = "Provant la connexió..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Strany a počáteční číslo"
positionAndPages = "Pozice a stránky"
preview = "Výběr pozice"
previewDisclaimer = "Náhled je orientační. Konečný výstup se může lišit kvůli metrikám písem PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Vyberte PDF soubor:"
@@ -441,9 +439,7 @@ fullscreen = "Celá obrazovka"
[settings.general.updates]
title = "Aktualizace softwaru"
description = "Zkontrolujte aktualizace a zobrazte informace o verzi"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Aktuální verze"
latestVersion = "Nejnovější verze"
checkForUpdates = "Zkontrolovat aktualizace"
viewDetails = "Zobrazit podrobnosti"
@@ -954,7 +950,6 @@ title = "Automaticky rozdělit podle velikosti/počtu"
desc = "Rozdělí jeden PDF na více dokumentů podle velikosti, počtu stránek nebo počtu dokumentů"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Nahradit a invertovat barvy"
desc = "Nahradit nebo invertovat barvy v dokumentech PDF"
@@ -969,22 +964,18 @@ title = "Autom. skenování složek"
desc = "Odkaz na průvodce automatizovaným skenováním složek"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Průvodce SSO"
desc = "Odkaz na průvodce SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Offline nastavení"
desc = "Odkaz na průvodce nastavením v odpojeném prostředí"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Přidat heslo"
desc = "Zašifrovat váš PDF dokument heslem."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Změnit oprávnění"
desc = "Změnit omezení a oprávnění dokumentu"
@@ -994,12 +985,10 @@ title = "Automatizace"
desc = "Vytvářejte vícekrokové workflow řetězením akcí PDF. Ideální pro opakující se úlohy."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Překryje PDF nad jiným PDF"
title = "Překrýt PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor textu PDF"
desc = "Prohlížejte a upravujte exporty JSON ze Stirling PDF se skupinovými úpravami textu a regenerací PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Výstupní formát"
pdfaNote = "PDF/A-1b je kompatibilnější, PDF/A-2b podporuje více funkcí."
pdfaFormat = "Formát PDF/A"
pdfaDigitalSignatureWarning = "PDF obsahuje digitální podpis, který bude v dalším kroku odstraněn."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF obsahuje digitální podpis. Ten bude v dalším kroku odstraněn."
pdfxDescription = "PDF/X je podmnožina PDF dle standardu ISO pro spolehlivý tisk a výměnu grafiky."
fileFormat = "Formát souboru"
@@ -2646,7 +2633,6 @@ label = "Původní PDF"
[compare.edited]
label = "Upravené PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Spustit porovnání znovu?"
@@ -3567,44 +3553,6 @@ imageSize = "Velikost obrázku"
margin = "Okraj"
positionAndFormatting = "Umístění a formátování"
quickPosition = "Vyberte na stránce pozici pro umístění razítka."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Při přidávání razítka do PDF došlo k chybě."
@@ -4523,18 +4471,10 @@ description = "Nakonfigurujte vlastní cesty systému souborů pro zpracovatelsk
[admin.settings.general.customPaths.pipeline]
label = "Adresáře pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Adresář sledovaných složek"
description = "Adresář, kde pipeline sleduje příchozí PDF (ponechte prázdné pro výchozí: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Adresář dokončených složek"
description = "Adresář, do kterého se ukládají zpracovaná PDF (ponechte prázdné pro výchozí: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maximální počet neúspěšných pokusů o přihlášení před
label = "Čas pro reset přihlášení (minuty)"
description = "Doba, po které se neúspěšné pokusy o přihlášení resetují"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Zakázat ochranu CSRF"
description = "Zakázat ochranu proti Cross-Site Request Forgery (nedoporučuje se)"
@@ -6573,7 +6506,6 @@ link = "nebo se připojte k účtu s vlastním hostováním"
title = "Připojit k serveru"
subtitle = "Zadejte URL vašeho samohostovaného serveru"
testing = "Testuji připojení..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Sider og startnummer"
positionAndPages = "Position og sider"
preview = "Positionsvalg"
previewDisclaimer = "Forhåndsvisning er vejledende. Det endelige output kan variere pga. PDF-skrifttypemetrik."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Vælg PDF-fil:"
@@ -441,9 +439,7 @@ fullscreen = "Fuldskærm"
[settings.general.updates]
title = "Softwareopdateringer"
description = "Søg efter opdateringer og se versionsinfo"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Nuværende version"
latestVersion = "Seneste version"
checkForUpdates = "Søg efter opdateringer"
viewDetails = "Vis detaljer"
@@ -954,7 +950,6 @@ title = "Auto-opdel størrelse/antal"
desc = "Opdel en enkelt PDF i flere dokumenter baseret på størrelse, sideantal eller dokumentantal"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Erstat og inverter farver"
desc = "Erstat eller inverter farver i PDF-dokumenter"
@@ -969,22 +964,18 @@ title = "Automatiseret mappescanning"
desc = "Link til guide for automatiseret mappescanning"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO-vejledning"
desc = "Link til SSO-vejledning"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped opsætning"
desc = "Link til guide for air-gapped opsætning"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Tilføj Adgangskode"
desc = "Kryptér dit PDF-dokument med en adgangskode."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Ændre Tilladelser"
desc = "Ændr dokumentbegrænsninger og tilladelser"
@@ -994,12 +985,10 @@ title = "Automatiser"
desc = "Byg flertrins-workflows ved at kæde PDF-handlinger sammen. Ideelt til tilbagevendende opgaver."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Overlejrer PDF'er oven på en anden PDF"
title = "Overlejr PDF'er"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF-teksteditor"
desc = "Gennemse og rediger Stirling PDF JSON-eksporter med grupperet tekstredigering og regenerering af PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Outputformat"
pdfaNote = "PDF/A-1b er mere kompatibel, PDF/A-2b understøtter flere funktioner."
pdfaFormat = "PDF/A-format"
pdfaDigitalSignatureWarning = "PDF'en indeholder en digital signatur. Dette vil blive fjernet i næste trin."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF'en indeholder en digital signatur. Denne fjernes i næste trin."
pdfxDescription = "PDF/X er en ISO-standard PDF-undersæt til pålidelig udskrivning og grafikudveksling."
fileFormat = "Filformat"
@@ -2646,7 +2633,6 @@ label = "Original-PDF"
[compare.edited]
label = "Redigeret PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Kør sammenligningen igen?"
@@ -3567,44 +3553,6 @@ imageSize = "Billedstørrelse"
margin = "Margen"
positionAndFormatting = "Placering og formatering"
quickPosition = "Vælg en placering på siden til stemplet."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Der opstod en fejl under tilføjelse af stempel til PDF'en."
@@ -4523,18 +4471,10 @@ description = "Konfigurer brugerdefinerede filsystemstier til pipeline-behandlin
[admin.settings.general.customPaths.pipeline]
label = "Pipelinemapper"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Mappe for overvågede mapper"
description = "Mappe hvor pipelinen overvåger indkommende PDF'er (lad tom for standard: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Mappe for færdige mapper"
description = "Mappe hvor behandlede PDF'er gemmes (lad tom for standard: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maksimalt antal mislykkede loginforsøg før kontolock"
label = "Nulstil login (minutter)"
description = "Tid før mislykkede loginforsøg nulstilles"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Deaktivér CSRF-beskyttelse"
description = "Deaktivér Cross-Site Request Forgery-beskyttelse (anbefales ikke)"
@@ -6573,7 +6506,6 @@ link = "eller opret forbindelse til en selvhostet konto"
title = "Forbind til server"
subtitle = "Indtast URL til din selvhostede server"
testing = "Tester forbindelse..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Seiten & Startnummer"
positionAndPages = "Position & Seiten"
preview = "Positionsauswahl"
previewDisclaimer = "Vorschau ist ungefähr. Das Endergebnis kann aufgrund der PDF-Schriftmetriken variieren."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF-Datei auswählen:"
@@ -441,9 +439,7 @@ fullscreen = "Vollbild"
[settings.general.updates]
title = "Software-Updates"
description = "Nach Updates suchen und Versionsinformationen anzeigen"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Aktuelle Version"
latestVersion = "Neueste Version"
checkForUpdates = "Nach Updates suchen"
viewDetails = "Details anzeigen"
@@ -954,7 +950,6 @@ title = "Teilen nach Größe/Anzahl"
desc = "Teilen Sie ein einzelnes PDF basierend auf Größe, Seitenanzahl oder Dokumentanzahl in mehrere Dokumente auf"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Farbe ersetzen & invertieren"
desc = "Farben in PDF-Dokumenten ersetzen oder invertieren"
@@ -969,22 +964,18 @@ title = "Autom. Ordner-Scan"
desc = "Link zum Leitfaden für automatisches Ordner-Scannen"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO-Anleitung"
desc = "Link zum SSO-Leitfaden"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Offline-Setup"
desc = "Link zum Air-Gap-Einrichtungsleitfaden"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Passwort hinzufügen"
desc = "Das PDF mit einem Passwort verschlüsseln"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Berechtigungen ändern"
desc = "Dokumentbeschränkungen und -berechtigungen ändern"
@@ -994,12 +985,10 @@ title = "Automatisieren"
desc = "Mehrstufige Arbeitsabläufe durch Verkettung von PDF-Aktionen erstellen. Ideal für wiederkehrende Aufgaben."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Ein PDF über ein anderes legen"
title = "PDFs überlagern"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF-Texteditor"
desc = "Vorhandenen Text und Bilder in PDFs bearbeiten"
@@ -1302,8 +1291,6 @@ outputFormat = "Ausgabeformat"
pdfaNote = "PDF/A-1b ist kompatibler, PDF/A-2b unterstützt mehr Funktionen."
pdfaFormat = "PDF/A-Format"
pdfaDigitalSignatureWarning = "Das PDF enthält eine digitale Signatur. Sie wird im nächsten Schritt entfernt."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Das PDF enthält eine digitale Signatur. Diese wird im nächsten Schritt entfernt."
pdfxDescription = "PDF/X ist eine ISO-Standard-PDF-Teilmenge für zuverlässigen Druck und Grafikaustausch."
fileFormat = "Dateiformat"
@@ -2646,7 +2633,6 @@ label = "Original-PDF"
[compare.edited]
label = "Bearbeitetes PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Vergleich erneut ausführen?"
@@ -3567,44 +3553,6 @@ imageSize = "Bildgröße"
margin = "Rand"
positionAndFormatting = "Position & Formatierung"
quickPosition = "Wählen Sie eine Position auf der Seite, um den Stempel zu platzieren."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Beim Hinzufügen des Stempels zum PDF ist ein Fehler aufgetreten."
@@ -4523,18 +4471,10 @@ description = "Benutzerdefinierte Dateisystempfade für Pipeline-Verarbeitung un
[admin.settings.general.customPaths.pipeline]
label = "Pipeline-Verzeichnisse"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Verzeichnis für überwachte Ordner"
description = "Verzeichnis, in dem die Pipeline nach eingehenden PDFs überwacht (leer lassen für Standard: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Verzeichnis für fertiggestellte Ordner"
description = "Verzeichnis, in das verarbeitete PDFs ausgegeben werden (leer lassen für Standard: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maximale Anzahl fehlgeschlagener Anmeldeversuche vor Kontosperre"
label = "Zurücksetzungszeit für Anmeldungen (Minuten)"
description = "Zeit, nach der fehlgeschlagene Anmeldeversuche zurückgesetzt werden"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF-Schutz deaktivieren"
description = "Cross-Site Request Forgery-Schutz deaktivieren (nicht empfohlen)"
@@ -6573,7 +6506,6 @@ link = "oder mit einem selbstgehosteten Konto verbinden"
title = "Mit Server verbinden"
subtitle = "Geben Sie die URL Ihres Self-Hosted-Servers ein"
testing = "Verbindung wird getestet..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Σελίδες & Αρχικός αριθμός"
positionAndPages = "Θέση & Σελίδες"
preview = "Επιλογή θέσης"
previewDisclaimer = "Η προεπισκόπηση είναι κατά προσέγγιση. Το τελικό αποτέλεσμα μπορεί να διαφέρει λόγω των μετρικών γραμματοσειράς του PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Επιλέξτε αρχείο PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Πλήρης οθόνη"
[settings.general.updates]
title = "Ενημερώσεις λογισμικού"
description = "Έλεγχος ενημερώσεων και προβολή πληροφοριών έκδοσης"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Τρέχουσα έκδοση"
latestVersion = "Νεότερη έκδοση"
checkForUpdates = "Έλεγχος για ενημερώσεις"
viewDetails = "Προβολή λεπτομερειών"
@@ -954,7 +950,6 @@ title = "Αυτόματο σπάσιμο με μέγεθος/σελ."
desc = "Διαχωρισμός ενός PDF σε πολλαπλά έγγραφα βάσει μεγέθους, αριθμού σελίδων ή αριθμού εγγράφων"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Αλλαγή & αντιστροφή χρώματος"
desc = "Αντικαταστήστε ή αντιστρέψτε χρώματα σε έγγραφα PDF"
@@ -969,22 +964,18 @@ title = "Αυτόματη σάρωση φακέλων"
desc = "Σύνδεσμος προς τον οδηγό αυτοματοποιημένης σάρωσης φακέλων"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Οδηγός SSO"
desc = "Σύνδεσμος προς τον οδηγό SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Ρύθμιση Air-gapped"
desc = "Σύνδεσμος προς τον οδηγό ρύθμισης Air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Προσθήκη κωδικού"
desc = "Κρυπτογράφηση του εγγράφου PDF με κωδικό."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Αλλαγή δικαιωμάτων"
desc = "Αλλαγή περιορισμών και δικαιωμάτων εγγράφου"
@@ -994,12 +985,10 @@ title = "Αυτοματοποίηση"
desc = "Δημιουργήστε ροές πολλών βημάτων συνδέοντας ενέργειες PDF. Ιδανικό για επαναλαμβανόμενες εργασίες."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Επικάλυψη PDF πάνω σε άλλο PDF"
title = "Επικάλυψη PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Επεξεργαστής κειμένου PDF"
desc = "Επιθεωρήστε και επεξεργαστείτε εξαγωγές JSON του Stirling PDF με ομαδοποιημένη επεξεργασία κειμένου και αναδημιουργία PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Μορφή εξόδου"
pdfaNote = "Το PDF/A-1b είναι πιο συμβατό, το PDF/A-2b υποστηρίζει περισσότερες δυνατότητες."
pdfaFormat = "Μορφή PDF/A"
pdfaDigitalSignatureWarning = "Το PDF περιέχει ψηφιακή υπογραφή. Αυτή θα αφαιρεθεί στο επόμενο βήμα."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Το PDF περιέχει ψηφιακή υπογραφή. Αυτή θα αφαιρεθεί στο επόμενο βήμα."
pdfxDescription = "Το PDF/X είναι ένα υποσύνολο PDF προτύπου ISO για αξιόπιστη εκτύπωση και ανταλλαγή γραφικών."
fileFormat = "Μορφή αρχείου"
@@ -2646,7 +2633,6 @@ label = "Αρχικό PDF"
[compare.edited]
label = "Τροποποιημένο PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Επανεκτέλεση σύγκρισης;"
@@ -3567,44 +3553,6 @@ imageSize = "Μέγεθος εικόνας"
margin = "Περιθώριο"
positionAndFormatting = "Θέση & μορφοποίηση"
quickPosition = "Επιλέξτε μια θέση στη σελίδα για τοποθέτηση της σφραγίδας."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Παρουσιάστηκε σφάλμα κατά την προσθήκη σφραγίδας στο PDF."
@@ -4523,18 +4471,10 @@ description = "Ρυθμίστε προσαρμοσμένες διαδρομές
[admin.settings.general.customPaths.pipeline]
label = "Κατάλογοι pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Κατάλογος παρακολουθούμενων φακέλων"
description = "Κατάλογος όπου το pipeline παρακολουθεί για εισερχόμενα PDF (αφήστε κενό για προεπιλογή: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Κατάλογος ολοκληρωμένων φακέλων"
description = "Κατάλογος όπου εξάγονται τα επεξεργασμένα PDF (αφήστε κενό για προεπιλογή: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Μέγιστος αριθμός αποτυχημένων προσ
label = "Χρόνος επαναφοράς σύνδεσης (λεπτά)"
description = "Χρόνος πριν μηδενιστούν οι αποτυχημένες προσπάθειες σύνδεσης"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Απενεργοποίηση προστασίας CSRF"
description = "Απενεργοποίηση προστασίας Cross-Site Request Forgery (δεν συνιστάται)"
@@ -6573,7 +6506,6 @@ link = "ή συνδεθείτε σε έναν self-hosted λογαριασμό"
title = "Σύνδεση σε διακομιστή"
subtitle = "Εισαγάγετε το URL του self-hosted διακομιστή σας"
testing = "Έλεγχος σύνδεσης..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+56 -126
View File
@@ -219,9 +219,6 @@ pagesAndStarting = "Pages & Starting Number"
positionAndPages = "Position & Pages"
preview = "Position Selection"
previewDisclaimer = "Preview is approximate. Final output may vary due to PDF font metrics."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Select PDF file:"
@@ -442,9 +439,7 @@ fullscreen = "Fullscreen"
[settings.general.updates]
title = "Software Updates"
description = "Check for updates and view version information"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Current Version"
latestVersion = "Latest Version"
checkForUpdates = "Check for Updates"
viewDetails = "View Details"
@@ -695,257 +690,257 @@ workbenchSlide = "Workspace panel"
workspace = "Workspace"
[home.multiTool]
tags = "multiple,tools,multi-tool,all-in-one,swiss army,page organizer,page editor,edit pages,manage pages,organize,reorganize"
tags = "multiple,tools"
title = "PDF Multi Tool"
desc = "Merge, Rotate, Rearrange, Split, and Remove pages"
[home.merge]
tags = "combine,join,unite,merge,merge PDFs,combine PDFs,join PDFs,concatenate,append,stitch,combine files,join files,merge documents"
tags = "combine,join,unite"
title = "Merge"
desc = "Easily merge multiple PDFs into one."
[home.split]
tags = "divide,separate,break,split,extract pages,separate pages,divide document,break apart,separate files,unbind,split by page,divide by chapter"
tags = "divide,separate,break"
title = "Split"
desc = "Split PDFs into multiple documents"
[home.rotate]
tags = "turn,flip,orient,rotate,orientation,landscape,portrait,90 degrees,180 degrees,clockwise,anticlockwise,counter-clockwise,fix orientation"
tags = "turn,flip,orient"
title = "Rotate"
desc = "Easily rotate your PDFs."
[home.convert]
tags = "transform,change,convert,PDF to Word,PDF to Excel,PDF to image,Word to PDF,Excel to PDF,PowerPoint to PDF,HTML to PDF,export,import,file conversion,format change,save as"
tags = "transform,change"
title = "Convert"
desc = "Convert files between different formats"
[home.pdfOrganiser]
tags = "organize,rearrange,reorder,organise,arrange pages,sort,move pages,delete pages,remove pages,page management,page organizer,page organiser,resequence"
tags = "organize,rearrange,reorder"
title = "Organise"
desc = "Remove/Rearrange pages in any order"
[home.addImage]
tags = "insert,embed,place,add image,insert image,place image,embed image,add photo,add picture,add logo,graphics,insert picture,place photo,PNG,JPG,JPEG"
tags = "insert,embed,place"
title = "Add image"
desc = "Adds a image onto a set location on the PDF"
[home.addAttachments]
tags = "embed,attach,include,attachments,attach files,embed files,include files,add files,file attachment,associated files,supplementary files"
tags = "embed,attach,include"
title = "Add Attachments"
desc = "Add or remove embedded files (attachments) to/from a PDF"
[home.watermark]
tags = "stamp,mark,overlay,watermark,branding,logo,confidential,draft,copyright,trademark,text overlay,image overlay,background text"
tags = "stamp,mark,overlay"
title = "Add Watermark"
desc = "Add a custom watermark to your PDF document."
[home.removePassword]
tags = "unlock,remove password,unlock PDF,decrypt,remove encryption,unprotect,open protected PDF,password removal,unlock protected,disable password,remove security,remove owner password"
tags = "unlock"
title = "Remove Password"
desc = "Remove password protection from your PDF document."
[home.compress]
tags = "shrink,reduce,optimize,compress,smaller,downsize,file size,reduce size,minimize,make smaller,decrease size,optimize size"
tags = "shrink,reduce,optimize"
title = "Compress"
desc = "Compress PDFs to reduce their file size."
[home.unlockPDFForms]
tags = "unlock,enable,edit,unlock forms,enable forms,editable forms,remove read only,make editable,unlock fields,enable editing,form fields,fillable,unprotect forms"
tags = "unlock,enable,edit"
title = "Unlock PDF Forms"
desc = "Remove read-only property of form fields in a PDF document."
[home.changeMetadata]
tags = "edit,modify,update,metadata,properties,document properties,author,title,subject,keywords,creator,producer,info,document info,file properties"
tags = "edit,modify,update"
title = "Change Metadata"
desc = "Change/Remove/Add metadata from a PDF document"
[home.ocr]
tags = "extract,scan,OCR,optical character recognition,text recognition,scan to text,image to text,scanned document,searchable PDF,make searchable,extract text,recognize text,read scanned"
tags = "extract,scan"
title = "OCR / Cleanup scans"
desc = "Cleanup scans and detects text from images within a PDF and re-adds it as text."
[home.extractImages]
tags = "pull,save,export,extract images,get images,save images,export images,extract photos,extract pictures,pull images,download images,rip images,extract graphics,save photos"
tags = "pull,save,export"
title = "Extract Images"
desc = "Extracts all images from a PDF and saves them to zip"
[home.scannerImageSplit]
tags = "detect,split,photos,auto detect,detect photos,split photos,separate photos,split scanned images,multiple photos,auto split,photo detection,image detection,scan separation"
tags = "detect,split,photos"
title = "Detect & Split Scanned Photos"
desc = "Detect and split scanned photos into separate pages"
[home.sign]
tags = "signature,autograph,e-sign,electronic signature,digital signature,sign document,approval,signoff,authorize,endorse,ink signature,handwriting"
tags = "signature,autograph"
title = "Sign"
desc = "Adds signature to PDF by drawing, text or image"
[home.annotate]
tags = "annotate,highlight,draw,markup,comment,notes,review,redline,feedback,markup tools,sticky notes,shapes,arrows,text box,freehand"
tags = "annotate,highlight,draw"
title = "Annotate"
desc = "Highlight, draw, add notes and shapes in the viewer"
[home.flatten]
tags = "simplify,remove,interactive,flatten,flatten form,remove form fields,make static,finalize form,lock form,disable editing,convert to image,non-editable"
tags = "simplify,remove,interactive"
title = "Flatten"
desc = "Remove all interactive elements and forms from a PDF"
[home.certSign]
tags = "authenticate,PEM,P12,official,encrypt,sign,certificate,PKCS12,JKS,server,manual,auto,digital certificate,certificate signature,PKI,cryptographic signature,trusted signature"
tags = "authenticate,PEM,P12,official,encrypt,sign,certificate,PKCS12,JKS,server,manual,auto"
title = "Sign with Certificate"
desc = "Signs a PDF with a Certificate/Key (PEM/P12)"
[home.repair]
tags = "fix,restore,repair,fix PDF,fix broken,fix corrupt,repair PDF,repair corrupt,broken PDF,corrupt PDF,damaged PDF,recover,fix errors,PDF won't open,can't open PDF,PDF errors,troubleshoot,restore PDF,rebuild,corrupted"
tags = "fix,restore"
title = "Repair"
desc = "Tries to repair a corrupt/broken PDF"
[home.removeBlanks]
tags = "delete,clean,empty,remove blank,delete blank pages,empty pages,white pages,remove empty,clean up,cleanup blank"
tags = "delete,clean,empty"
title = "Remove Blank pages"
desc = "Detects and removes blank pages from a document"
[home.removeAnnotations]
tags = "delete,clean,strip,remove annotations,remove comments,delete comments,remove markup,remove highlights,clean annotations,strip comments,remove notes,delete markup,clear comments"
tags = "delete,clean,strip"
title = "Remove Annotations"
desc = "Removes all comments/annotations from a PDF"
[home.compare]
tags = "difference,compare,diff,compare PDFs,compare documents,find differences,show differences,changes,what changed,track changes,revisions,version compare,side by side,contrast,delta"
tags = "difference"
title = "Compare"
desc = "Compares and shows the differences between 2 PDF Documents"
[home.removeCertSign]
tags = "remove,delete,unlock,remove certificate,remove signature,delete signature,unsigned,remove digital signature,strip signature,remove cert,unsign"
tags = "remove,delete,unlock"
title = "Remove Certificate Sign"
desc = "Remove certificate signature from PDF"
[home.pageLayout]
tags = "layout,arrange,combine,N-up,2-up,4-up,multiple per page,pages per sheet,layout pages,tile,grid layout,multi-page layout,combine on page,handout"
tags = "layout,arrange,combine"
title = "Multi-Page Layout"
desc = "Merge multiple pages of a PDF document into a single page"
[home.bookletImposition]
tags = "booklet,print,binding,imposition,booklet printing,saddle stitch,fold,pamphlet,brochure,print booklet,duplex,two-sided,signature,book layout,page imposition,print layout"
tags = "booklet,print,binding"
title = "Booklet Imposition"
desc = "Create booklets with proper page ordering and multi-page layout for printing and binding"
[home.scalePages]
tags = "resize,adjust,scale,page size,resize page,scale page,change size,adjust size,enlarge,shrink page,fit to page,A4,letter size"
tags = "resize,adjust,scale"
title = "Adjust page size/scale"
desc = "Change the size/scale of a page and/or its contents."
[home.addPageNumbers]
tags = "number,pagination,count,add page numbers,page numbering,page numbers,footer,header,number pages,sequential,pagination tool"
tags = "number,pagination,count"
title = "Add Page Numbers"
desc = "Add Page numbers throughout a document in a set location"
[home.autoRename]
tags = "auto-detect,header-based,organize,relabel,auto rename,automatic rename,smart rename,rename by content,filename,file naming,detect title"
tags = "auto-detect,header-based,organize,relabel"
title = "Auto Rename PDF File"
desc = "Auto renames a PDF file based on its detected header"
[home.adjustContrast]
tags = "contrast,brightness,saturation,adjust colors,color correction,enhance,lighten,darken,improve quality,color balance,hue,vibrance"
tags = "contrast,brightness,saturation"
title = "Adjust Colours/Contrast"
desc = "Adjust Colors/Contrast, Saturation and Brightness of a PDF"
[home.crop]
tags = "trim,cut,resize,crop,crop PDF,trim PDF,trim margins,remove margins,cut edges,trim borders,remove white space,crop pages,trim pages,reduce margins,set margins"
tags = "trim,cut,resize"
title = "Crop PDF"
desc = "Crop a PDF to reduce its size (maintains text!)"
[home.autoSplitPDF]
tags = "auto,split,QR,auto split,QR code,QR split,barcode,automatic split,divider page,separator page,scan divider,batch scanning"
tags = "auto,split,QR"
title = "Auto Split Pages"
desc = "Auto Split Scanned PDF with physical scanned page splitter QR Code"
[home.sanitize]
tags = "clean,purge,remove,sanitize,sanitise,remove scripts,remove javascript,remove metadata,strip metadata,security,clean document,remove hidden data,privacy"
tags = "clean,purge,remove"
title = "Sanitise"
desc = "Remove potentially harmful elements from PDF files"
[home.getPdfInfo]
tags = "info,metadata,details,PDF info,document info,properties,file info,get info,show info,view properties,document properties,statistics,page count,file details,inspect"
tags = "info,metadata,details"
title = "Get ALL Info on PDF"
desc = "Grabs any and all information possible on PDFs"
[home.pdfToSinglePage]
tags = "combine,merge,single,single page,one page,merge to single,combine all,stitch pages,concatenate vertical,long page,poster"
tags = "combine,merge,single"
title = "PDF to Single Large Page"
desc = "Merges all PDF pages into one large single page"
[home.showJS]
tags = "javascript,code,script,show javascript,show JS,find javascript,detect javascript,view javascript,embedded scripts,malware,security,inspect,debug"
tags = "javascript,code,script"
title = "Show Javascript"
desc = "Searches and displays any JS injected into a PDF"
[home.redact]
tags = "censor,blackout,hide,redact,redaction,black out,block out,remove sensitive,hide text,privacy,confidential,GDPR,PII,sensitive data,permanently remove,cover up,legal redaction"
tags = "censor,blackout,hide"
title = "Redact"
desc = "Redacts (blacks out) a PDF based on selected text, drawn shapes and/or selected page(s)"
[home.splitBySections]
tags = "split,sections,divide,split by sections,grid split,divide pages,split into sections,cut pages,divide grid,section split,horizontal split,vertical split"
tags = "split,sections,divide"
title = "Split PDF by Sections"
desc = "Divide each page of a PDF into smaller horizontal and vertical sections"
[home.addStamp]
tags = "stamp,mark,seal,approved,rejected,confidential,stamp tool,rubber stamp,date stamp,approval stamp,received,void,copy,original"
tags = "stamp,mark,seal"
title = "Add Stamp to PDF"
desc = "Add text or add image stamps at set locations"
[home.removeImage]
tags = "remove,delete,clean,remove image,delete image,strip images,remove pictures,delete photos,clean images,reduce size,remove graphics"
tags = "remove,delete,clean"
title = "Remove image"
desc = "Remove image from PDF to reduce file size"
[home.splitByChapters]
tags = "split,chapters,structure,split by chapters,split by bookmarks,bookmarks,outline,table of contents,TOC split,chapter split,divide by sections"
tags = "split,chapters,structure"
title = "Split PDF by Chapters"
desc = "Split a PDF into multiple files based on its chapter structure."
[home.validateSignature]
tags = "validate,verify,certificate,validate signature,verify signature,check signature,digital signature,certificate verification,signature validation,authentic,trust,signed,verify certificate"
tags = "validate,verify,certificate"
title = "Validate PDF Signature"
desc = "Verify digital signatures and certificates in PDF documents"
[home.swagger]
tags = "API,documentation,test,swagger,API docs,REST API,endpoints,developer,API reference,API testing,OpenAPI,integration,developer docs"
tags = "API,documentation,test"
title = "API Documentation"
desc = "View API documentation and test endpoints"
[home.scannerEffect]
tags = "scan,simulate,create,fake scan,look scanned,scanner effect,make look scanned,photocopy effect,simulate scanner,realistic scan"
tags = "scan,simulate,create"
title = "Scanner Effect"
desc = "Create a PDF that looks like it was scanned"
[home.editTableOfContents]
tags = "bookmarks,contents,edit,table of contents,TOC,outline,navigation,chapters,sections,add bookmarks,edit bookmarks,PDF outline"
tags = "bookmarks,contents,edit"
title = "Edit Table of Contents"
desc = "Add or edit bookmarks and table of contents in PDF documents"
[home.manageCertificates]
tags = "certificates,import,export,manage certificates,digital certificates,certificate management,PFX,P12,keystore,import certificate,export certificate,certificate store,PKI"
tags = "certificates,import,export"
title = "Manage Certificates"
desc = "Import, export, or delete digital certificate files used for signing PDFs."
[home.read]
tags = "view,open,display,read,viewer,PDF viewer,PDF reader,open PDF,view PDF,display PDF,preview,browse"
tags = "view,open,display"
title = "Read"
desc = "View and annotate PDFs. Highlight text, draw, or insert comments for review and collaboration."
[home.reorganizePages]
tags = "rearrange,reorder,organize,reorganize,move pages,page order,sort pages,arrange pages,shuffle,resequence"
tags = "rearrange,reorder,organize"
title = "Reorganize Pages"
desc = "Rearrange, duplicate, or delete PDF pages with visual drag-and-drop control."
[home.extractPages]
tags = "pull,select,copy,extract,extract pages,get pages,pull out,save pages,export pages,copy pages,select pages,specific pages"
tags = "pull,select,copy"
title = "Extract Pages"
desc = "Extract specific pages from a PDF document"
[home.removePages]
tags = "delete,extract,exclude,remove pages,delete pages,remove page,delete page,exclude pages,take out pages,discard pages,drop pages"
tags = "delete,extract,exclude"
title = "Remove Pages"
desc = "Remove specific pages from a PDF document"
@@ -955,57 +950,50 @@ title = "Auto Split by Size/Count"
desc = "Automatically split PDFs by file size or page count"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Replace & Invert Colour"
desc = "Replace or invert colours in PDF documents"
[home.devApi]
tags = "API,development,documentation,developer,REST,integration,endpoints,programmatic,automation,scripting"
tags = "API,development,documentation"
title = "API"
desc = "Link to API documentation"
[home.devFolderScanning]
tags = "automation,folder,scanning,watch folder,hot folder,automatic processing,batch,monitor folder,auto process,folder monitoring"
tags = "automation,folder,scanning"
title = "Automated Folder Scanning"
desc = "Link to automated folder scanning guide"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO Guide"
desc = "Link to SSO guide"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped Setup"
desc = "Link to air-gapped setup guide"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Add Password"
desc = "Add password protection and restrictions to PDF files"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Change Permissions"
desc = "Change document restrictions and permissions"
[home.automate]
tags = "workflow,sequence,automation,automate,batch,batch processing,pipeline,chain,multi-step,recurring,scheduled,automatic,process multiple,bulk operations"
tags = "workflow,sequence,automation"
title = "Automate"
desc = "Build multi-step workflows by chaining together PDF actions. Ideal for recurring tasks."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Overlay one PDF on top of another"
title = "Overlay PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF Text Editor"
desc = "Edit existing text and images inside PDFs"
[home.addText]
tags = "text,annotation,label,add text,insert text,place text,text box,add label,add caption,type on PDF,write on PDF,add words,add note,text overlay,typewriter"
tags = "text,annotation,label"
title = "Add Text"
desc = "Add custom text anywhere in your PDF"
@@ -1303,8 +1291,6 @@ outputFormat = "Output Format"
pdfaNote = "PDF/A-1b is more compatible, PDF/A-2b supports more features, PDF/A-3b supports embedded files."
pdfaFormat = "PDF/A Format"
pdfaDigitalSignatureWarning = "The PDF contains a digital signature. This will be removed in the next step."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "The PDF contains a digital signature. This will be removed in the next step."
pdfxDescription = "PDF/X is an ISO standard PDF subset for reliable printing and graphics exchange."
fileFormat = "File Format"
@@ -2647,7 +2633,6 @@ label = "Original PDF"
[compare.edited]
label = "Edited PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Re-run comparison?"
@@ -3411,7 +3396,6 @@ instructions = "Select text or draw areas on the PDF to mark content for redacti
markText = "Mark Text"
markArea = "Mark Area"
pendingLabel = "Pending:"
applyRedactions = "Apply Redactions"
applyWarning = "⚠️ Permanent application, cannot be undone and the data underneath will be deleted"
apply = "Apply"
noMarks = "No redaction marks. Use the tools above to mark content for redaction."
@@ -3569,44 +3553,6 @@ imageSize = "Image Size"
margin = "Margin"
positionAndFormatting = "Position & Formatting"
quickPosition = "Select a position on the page to place the stamp."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "An error occurred while adding stamp to the PDF."
@@ -4526,18 +4472,10 @@ description = "Configure custom file system paths for pipeline processing and ex
[admin.settings.general.customPaths.pipeline]
label = "Pipeline Directories"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Watched Folders Directory"
description = "Directory where pipeline monitors for incoming PDFs (leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Finished Folders Directory"
description = "Directory where processed PDFs are outputted (leave empty for default: /pipeline/finishedFolders)"
@@ -4589,13 +4527,6 @@ description = "Maximum number of failed login attempts before account lockout"
label = "Login Reset Time (minutes)"
description = "Time before failed login attempts are reset"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Disable CSRF Protection"
description = "Disable Cross-Site Request Forgery protection (not recommended)"
@@ -6565,7 +6496,6 @@ link = "or connect to a self-hosted account"
title = "Connect to Server"
subtitle = "Enter your self-hosted server URL"
testing = "Testing connection..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Páginas y número inicial"
positionAndPages = "Posición y páginas"
preview = "Selección de posición"
previewDisclaimer = "La vista previa es aproximada. El resultado final puede variar debido a las métricas de fuentes del PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Seleccionar archivo PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Pantalla completa"
[settings.general.updates]
title = "Actualizaciones de software"
description = "Compruebe actualizaciones y vea la información de versión"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versión actual"
latestVersion = "Última versión"
checkForUpdates = "Buscar actualizaciones"
viewDetails = "Ver detalles"
@@ -954,7 +950,6 @@ title = "Auto dividir por tamaño/conteo"
desc = "Divide un solo PDF en múltiples documentos según su tamaño, número de páginas, o número de documento"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Reemplazar e Invertir Color"
desc = "Reemplace o invierta colores en documentos PDF"
@@ -969,22 +964,18 @@ title = "Escaneo Automatizado de Carpetas"
desc = "Enlace a la guía de escaneo automatizado de carpetas"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guía de SSO"
desc = "Enlace a la guía de SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Configuración Aislada"
desc = "Enlace a la guía de configuración aislada"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Proteger con contraseña"
desc = "Cifrar documento PDF con contraseña"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Cambiar permisos"
desc = "Modificar restricciones y permisos del documento"
@@ -994,12 +985,10 @@ title = "Automatizar"
desc = "Crear flujos de trabajo de múltiples pasos encadenando acciones de PDF. Ideal para tareas recurrentes."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Superponer PDFs encima de otro PDF"
title = "Superponer PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor de texto PDF"
desc = "Revise y edite exportaciones JSON de Stirling PDF con edición de texto agrupada y regeneración de PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Formato de Salida"
pdfaNote = "PDF/A-1b es más compatible, PDF/A-2b soporta más funciones."
pdfaFormat = "Formato PDF/A"
pdfaDigitalSignatureWarning = "El PDF contiene una firma digital. Ésta se eliminará en el siguiente paso."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "El PDF contiene una firma digital. Se eliminará en el siguiente paso."
pdfxDescription = "PDF/X es un subconjunto estándar ISO de PDF para impresión fiable e intercambio de gráficos."
fileFormat = "Formato de Archivo"
@@ -2646,7 +2633,6 @@ label = "PDF original"
[compare.edited]
label = "PDF editado"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "¿Volver a ejecutar la comparación?"
@@ -3567,44 +3553,6 @@ imageSize = "Tamaño de la imagen"
margin = "Margen"
positionAndFormatting = "Posición y formato"
quickPosition = "Selecciona una posición en la página para colocar el sello."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Se produjo un error al añadir el sello al PDF."
@@ -4523,18 +4471,10 @@ description = "Configura rutas de sistema de archivos personalizadas para el pro
[admin.settings.general.customPaths.pipeline]
label = "Directorios del pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Directorio de carpetas vigiladas"
description = "Directorio donde el pipeline supervisa la llegada de PDFs (dejar vacío para el valor predeterminado: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Directorio de carpetas finalizadas"
description = "Directorio donde se generan los PDFs procesados (dejar vacío para el valor predeterminado: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Número máximo de intentos fallidos antes de bloquear la cuenta"
label = "Tiempo de restablecimiento del inicio de sesión (minutos)"
description = "Tiempo antes de que se restablezcan los intentos fallidos de inicio de sesión"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Desactivar la protección CSRF"
description = "Desactivar la protección contra Cross-Site Request Forgery (no recomendado)"
@@ -6573,7 +6506,6 @@ link = "o conectarse a una cuenta autoalojada"
title = "Conectar con el servidor"
subtitle = "Introduzca la URL de su servidor autoalojado"
testing = "Probando la conexión..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Orrialdeak eta hasierako zenbakia"
positionAndPages = "Kokalekua eta orrialdeak"
preview = "Kokalekuaren hautaketa"
previewDisclaimer = "Aurrebista orientagarria da. Azken emaitza aldatu daiteke PDFaren letra-metriken arabera."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Aukeratu PDF fitxategia:"
@@ -441,9 +439,7 @@ fullscreen = "Pantaila osoa"
[settings.general.updates]
title = "Software eguneratzeak"
description = "Egiaztatu eguneratzeak eta ikusi bertsio-informazioa"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Uneko bertsioa"
latestVersion = "Azken bertsioa"
checkForUpdates = "Egiaztatu eguneratzeak"
viewDetails = "Xehetasunak ikusi"
@@ -954,7 +950,6 @@ title = "Autom. zatitu tamaina/kop."
desc = "Split a single PDF into multiple documents based on size, page count, or document count"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Ordeztu eta inbertitu kolorea"
desc = "Ordeztu edo alderantzikatu koloreak PDF dokumentuetan"
@@ -969,22 +964,18 @@ title = "Karpeta eskaneatze autom."
desc = "Esteka karpeta eskaneatze automatizatuaren gidara"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO gida"
desc = "Esteka SSO gidara"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Sare isolatuko konfigurazioa"
desc = "Esteka sare isolatutako konfigurazio gidara"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Gehitu pasahitza"
desc = "Enkriptatu PDF dokumentua pasahitz batekin"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Aldatu baimenak"
desc = "Aldatu dokumentuaren murrizketak eta baimenak"
@@ -994,12 +985,10 @@ title = "Automatizatu"
desc = "Eraiki hainbat pausotako workflowak PDF ekintzak kateatuz. Egokia zeregin errepikakorretarako."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Overlays PDFs on-top of another PDF"
title = "Gainjarri PDFak"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF testu-editorea"
desc = "Berrikusi eta editatu Stirling PDF JSON esportazioak taldekatutako testu-edizioarekin eta PDF birsorkuntzarekin"
@@ -1302,8 +1291,6 @@ outputFormat = "Irteerako formatua"
pdfaNote = "PDF/A-1b bateragarriagoa da; PDF/A-2b-k ezaugarri gehiago onartzen ditu."
pdfaFormat = "PDF/A formatua"
pdfaDigitalSignatureWarning = "PDFak sinadura digitala dauka. Hurrengo urratsean kenduko da."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDFak sinadura digital bat dauka. Hurrengo urratsean kenduko da."
pdfxDescription = "PDF/X inprimaketa eta grafikoen truke fidagarrirako ISO estandarreko PDF azpimultzoa da."
fileFormat = "Fitxategi formatua"
@@ -2646,7 +2633,6 @@ label = "Jatorrizko PDFa"
[compare.edited]
label = "Editatutako PDFa"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Berriro exekutatu konparazioa?"
@@ -3567,44 +3553,6 @@ imageSize = "Irudiaren tamaina"
margin = "Marjina"
positionAndFormatting = "Kokapena eta formatua"
quickPosition = "Hautatu orrian zigiloa kokatzeko posizio bat."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Errore bat gertatu da zigilua PDFari gehitzean."
@@ -4523,18 +4471,10 @@ description = "Konfiguratu fitxategi-sistemako bide pertsonalizatuak pipeline pr
[admin.settings.general.customPaths.pipeline]
label = "Pipeline direktorioak"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Gainbegiratutako karpeten direktorioa"
description = "Pipelineak sarrerako PDFak gainbegiratzen dituen direktorioa (utzi hutsik lehenetsia erabiltzeko: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Amaitutako karpeten direktorioa"
description = "Prozesatutako PDFak ateratzen diren direktorioa (utzi hutsik lehenetsia erabiltzeko: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Kontua blokeatu aurretik huts egindako saio-saiakeren gehienezko
label = "Saio-hasieraren berrezartze denbora (minutuak)"
description = "Huts egindako saio-saiakerak berrezarri aurreko denbora"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF babesa desgaitu"
description = "Desgaitu Cross-Site Request Forgery babesa (ez da gomendatzen)"
@@ -6573,7 +6506,6 @@ link = "edo konektatu autoostatutako kontu batera"
title = "Konektatu zerbitzarira"
subtitle = "Sartu zure auto-ostatuko zerbitzariaren URLa"
testing = "Konexioa probatzen..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "صفحات و شماره آغازین"
positionAndPages = "موقعیت و صفحات"
preview = "انتخاب موقعیت"
previewDisclaimer = "پیش‌نمایش تقریبی است. خروجی نهایی ممکن است به دلیل معیارهای فونت PDF متفاوت باشد."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "انتخاب فایل PDF:"
@@ -441,9 +439,7 @@ fullscreen = "تمام‌صفحه"
[settings.general.updates]
title = "به‌روزرسانی نرم‌افزار"
description = "بررسی به‌روزرسانی و مشاهده اطلاعات نسخه"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "نسخه فعلی"
latestVersion = "آخرین نسخه"
checkForUpdates = "بررسی به‌روزرسانی"
viewDetails = "مشاهده جزئیات"
@@ -954,7 +950,6 @@ title = "تقسیم خودکار بر اساس اندازه/تعداد"
desc = "تقسیم یک PDF به چند سند بر اساس اندازه، تعداد صفحات، یا تعداد اسناد"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "جایگزینی و معکوس کردن رنگ"
desc = "جایگزینی یا معکوس کردن رنگ‌ها در اسناد PDF"
@@ -969,22 +964,18 @@ title = "اسکن خودکار پوشه"
desc = "پیوند به راهنمای اسکن خودکار پوشه"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "راهنمای SSO"
desc = "پیوند به راهنمای SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "راه‌اندازی Air-gapped"
desc = "پیوند به راهنمای راه‌اندازی Air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "افزودن رمز عبور"
desc = "رمزگذاری سند PDF شما با رمز عبور."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "تغییر مجوزها"
desc = "تغییر محدودیت‌ها و مجوزهای سند"
@@ -994,12 +985,10 @@ title = "اتوماسیون"
desc = "ساخت گردش‌کارهای چندمرحله‌ای با زنجیره کردن اقدامات PDF. مناسب برای کارهای تکرارشونده."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "PDF‌ها را بر روی PDF دیگری هم‌پوشانی می‌کند"
title = "هم‌پوشانی PDF‌ها"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "ویرایشگر متن PDF"
desc = "بازبینی و ویرایش خروجی‌های JSON Stirling PDF با ویرایش گروهی متن و بازتولید PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "قالب خروجی"
pdfaNote = "PDF/A-1b سازگارتر است، PDF/A-2b از قابلیت‌های بیشتری پشتیبانی می‌کند."
pdfaFormat = "فرمت PDF/A"
pdfaDigitalSignatureWarning = "PDF حاوی یک امضای دیجیتال است. این در مرحله بعد حذف خواهد شد."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "این PDF شامل امضای دیجیتال است. این مورد در مرحله بعد حذف خواهد شد."
pdfxDescription = "PDF/X زیرمجموعه استاندارد ISO از PDF برای چاپ قابل‌اعتماد و تبادل گرافیک است."
fileFormat = "قالب فایل"
@@ -2646,7 +2633,6 @@ label = "PDF اصلی"
[compare.edited]
label = "PDF ویرایش‌شده"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "مقایسه دوباره انجام شود؟"
@@ -3567,44 +3553,6 @@ imageSize = "اندازه تصویر"
margin = "حاشیه"
positionAndFormatting = "موقعیت و قالب‌بندی"
quickPosition = "یک موقعیت روی صفحه برای قرار دادن مهر انتخاب کنید."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "هنگام افزودن مهر به PDF خطایی رخ داد."
@@ -4523,18 +4471,10 @@ description = "پیکربندی مسیرهای فایل سیستم سفارشی
[admin.settings.general.customPaths.pipeline]
label = "دایرکتوری‌های پایپلاین"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "دایرکتوری پوشه‌های پایش‌شده"
description = "مسیر پوشه‌ای که پایپلاین برای PDFهای ورودی پایش می‌کند (خالی بگذارید برای پیش‌فرض: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "دایرکتوری پوشه‌های پایان‌یافته"
description = "مسیر پوشه‌ای که PDFهای پردازش‌شده در آن خروجی داده می‌شوند (خالی بگذارید برای پیش‌فرض: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "حداکثر تعداد تلاش ناموفق ورود قبل ا
label = "زمان بازنشانی ورود (دقیقه)"
description = "مدتی که پس از آن تلاش‌های ناموفق ورود بازنشانی می‌شوند"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "غیرفعال کردن محافظت CSRF"
description = "غیرفعال کردن محافظت Cross-Site Request Forgery (توصیه نمی‌شود)"
@@ -6573,7 +6506,6 @@ link = "یا به یک حساب خودمیزبان متصل شوید"
title = "اتصال به سرور"
subtitle = "URL سرور خودمیزبان خود را وارد کنید"
testing = "در حال آزمون اتصال..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Pages et numéro de départ"
positionAndPages = "Position et pages"
preview = "Sélection de la position"
previewDisclaimer = "Laperçu est approximatif. Le résultat final peut varier en raison des métriques de police du PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Sélectionnez le fichier PDF"
@@ -441,9 +439,7 @@ fullscreen = "Plein écran"
[settings.general.updates]
title = "Mises à jour logicielles"
description = "Rechercher des mises à jour et voir les informations de version"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Version actuelle"
latestVersion = "Dernière version"
checkForUpdates = "Rechercher des mises à jour"
viewDetails = "Voir les détails"
@@ -954,7 +950,6 @@ title = "Scinder auto taille/pages"
desc = "Séparer un PDF unique en plusieurs documents en fonction de la taille, du nombre de pages ou du nombre de documents."
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Remplacer & inverser couleurs"
desc = "Remplacer ou inverser les couleurs dans les documents PDF"
@@ -969,22 +964,18 @@ title = "Scan auto de dossiers"
desc = "Lien vers le guide danalyse de dossier automatisée"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guide SSO"
desc = "Lien vers le guide SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Installation isolée"
desc = "Lien vers le guide dinstallation isolée (air-gapped)"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Ajouter un mot de passe"
desc = "Chiffrez votre PDF avec un mot de passe."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Modifier les permissions"
desc = "Modifier les restrictions et permissions du document"
@@ -994,12 +985,10 @@ title = "Automatiser"
desc = "Créez des workflows multi-étapes en enchaînant des actions PDF. Idéal pour les tâches récurrentes."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Superposer un PDF sur un autre"
title = "Superposer des PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Éditeur de texte PDF"
desc = "Afficher et modifier les exports JSON de Stirling PDF avec édition de texte groupée et régénération du PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Format de sortie"
pdfaNote = "PDF/A-1b est plus compatible, PDF/A-2b prend en charge davantage de fonctionnalités."
pdfaFormat = "Format PDF/A"
pdfaDigitalSignatureWarning = "Le PDF contient une signature numérique. Elle sera supprimée dans l'étape suivante."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Le PDF contient une signature numérique. Elle sera supprimée à l'étape suivante."
pdfxDescription = "PDF/X est un sous-ensemble PDF conforme à l'ISO pour une impression fiable et un échange graphique."
fileFormat = "Format de fichier"
@@ -2646,7 +2633,6 @@ label = "PDF original"
[compare.edited]
label = "PDF modifié"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Relancer la comparaison ?"
@@ -3567,44 +3553,6 @@ imageSize = "Taille de limage"
margin = "Marge"
positionAndFormatting = "Position et mise en forme"
quickPosition = "Sélectionnez une position sur la page pour placer le tampon."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Une erreur sest produite lors de lajout du tampon au PDF."
@@ -4523,18 +4471,10 @@ description = "Configurer des chemins de système de fichiers personnalisés pou
[admin.settings.general.customPaths.pipeline]
label = "Répertoires du pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Répertoire des dossiers surveillés"
description = "Répertoire où le pipeline surveille les PDF entrants (laisser vide pour la valeur par défaut : /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Répertoire des dossiers terminés"
description = "Répertoire où les PDF traités sont produits (laisser vide pour la valeur par défaut : /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Nombre maximal de tentatives de connexion échouées avant le ver
label = "Délai de réinitialisation (minutes)"
description = "Délai avant la réinitialisation du compteur de tentatives de connexion échouées"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Désactiver la protection CSRF"
description = "Désactiver la protection contre la falsification de requête intersites (non recommandé)"
@@ -6573,7 +6506,6 @@ link = "ou connectez-vous à un compte auto-hébergé"
title = "Connexion au serveur"
subtitle = "Saisissez lURL de votre serveur autohébergé"
testing = "Test de connexion…"
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Leathanaigh & Uimhir Tosaigh"
positionAndPages = "Suíomh & Leathanaigh"
preview = "Roghnú Suímh"
previewDisclaimer = "Is garbh an réamhamharc. D'fhéadfadh an toradh deiridh a bheith éagsúil de bharr méadrachtaí cló PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Roghnaigh comhad PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Lánscáileán"
[settings.general.updates]
title = "Nuashonruithe Bogearraí"
description = "Seiceáil le haghaidh nuashonruithe agus féach faisnéis leagain"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Leagan Reatha"
latestVersion = "Leagan is Déanaí"
checkForUpdates = "Seiceáil le haghaidh Nuashonruithe"
viewDetails = "Féach Sonraí"
@@ -954,7 +950,6 @@ title = "Scoilt auto: méid/líon"
desc = "Scoilt PDF amháin i ndoiciméid iolracha bunaithe ar mhéid, líon na leathanach, nó comhaireamh doiciméad"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Ionadaigh & Inbhéartaigh Dath"
desc = "Ionadaigh nó inbhéartaigh dathanna i gcáipéisí PDF"
@@ -969,22 +964,18 @@ title = "Scanadh Fillteán Uathoibríoch"
desc = "Nasc le treoir scantha fillteán uathoibrithe"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Treoir SSO"
desc = "Nasc le treoir SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Socrú Air-gapped"
desc = "Nasc le treoir socraithe Air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Cuir Pasfhocal leis"
desc = "Criptigh do dhoiciméad PDF le focal faire."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Athrú Ceadanna"
desc = "Athraigh srianta agus ceadanna cáipéise"
@@ -994,12 +985,10 @@ title = "Uathoibrigh"
desc = "Tóg sreafaí oibre ilchéime trí ghníomhartha PDF a nascadh le chéile. Foirfe do thascanna athfhillteacha."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Forleagain PDF ar bharr PDF eile"
title = "Forleagan PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Eagarthóir Téacs PDF"
desc = "Cuir téacs agus íomhánna atá ann cheana in eagar laistigh de PDFanna"
@@ -1302,8 +1291,6 @@ outputFormat = "Formáid Aschuir"
pdfaNote = "Tá PDF/A-1b níos comhoiriúnaí, tacaíonn PDF/A-2b le níos mó gnéithe."
pdfaFormat = "Formáid PDF/A"
pdfaDigitalSignatureWarning = "Tá síniú digiteach ar an PDF. Bainfear é seo sa chéad chéim eile."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Tá síniú digiteach sa PDF. Bainfear é sa chéad chéim eile."
pdfxDescription = "Is fo-thacar PDF de chaighdeán ISO é PDF/X le haghaidh priontála agus malartaithe grafaice iontaofa."
fileFormat = "Formáid Comhaid"
@@ -2646,7 +2633,6 @@ label = "PDF Bunaidh"
[compare.edited]
label = "PDF Eagarthaithe"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Rith an chomparáid arís?"
@@ -3567,44 +3553,6 @@ imageSize = "Méid Íomhá"
margin = "Imeall"
positionAndFormatting = "Suíomh & Formáidiú"
quickPosition = "Roghnaigh suíomh ar an leathanach le stampa a chur."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Tharla earráid agus stampa á chur leis an PDF."
@@ -4523,18 +4471,10 @@ description = "Cumraigh conairí comhadchórais saincheaptha le haghaidh próise
[admin.settings.general.customPaths.pipeline]
label = "Eolairí Píblíne"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Comhadlann na bhFillteán Faire"
description = "Comhadlann ina ndéanann an píblíne monatóireacht ar PDFs isteach (fág folamh don réamhshocrú: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Comhadlann na bhFillteán Críochnaithe"
description = "Comhadlann ina naschuirtear PDFs próiseáilte (fág folamh don réamhshocrú: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Uasmhéid iarrachtaí logála isteach teipthe sula gcuirtear an c
label = "Am Athshocraithe Logála Isteach (nóiméid)"
description = "Am sula nathshocraítear iarrachtaí logála isteach teipthe"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Díchumasaigh Cosaint CSRF"
description = "Díchumasaigh cosaint Cross-Site Request Forgery (ní mholtar)"
@@ -6573,7 +6506,6 @@ link = "nó ceangail le cuntas féinóstáilte"
title = "Ceangail leis an bhFreastalaí"
subtitle = "Cuir isteach URL do fhreastalaí féin-óstáilte"
testing = "Ceangal á thástáil..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "पृष्ठ और आरंभिक संख्या
positionAndPages = "स्थिति और पृष्ठ"
preview = "स्थिति चयन"
previewDisclaimer = "पूर्वावलोकन अनुमानित है। अंतिम आउटपुट PDF फ़ॉन्ट मेट्रिक्स के कारण भिन्न हो सकता है।"
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF फ़ाइल चुनें:"
@@ -441,9 +439,7 @@ fullscreen = "फुलस्क्रीन"
[settings.general.updates]
title = "सॉफ़्टवेयर अपडेट्स"
description = "अपडेट्स जाँचें और वर्ज़न जानकारी देखें"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "वर्तमान संस्करण"
latestVersion = "नवीनतम संस्करण"
checkForUpdates = "अपडेट्स जाँचें"
viewDetails = "विवरण देखें"
@@ -954,7 +950,6 @@ title = "आकार/गिनती से ऑटो बाँटें"
desc = "एक PDF को आकार, पृष्ठ संख्या, या दस्तावेज़ संख्या के आधार पर कई दस्तावेज़ों में विभाजित करें"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "रंग बदलें/उलटें"
desc = "PDF दस्तावेज़ों में रंगों को प्रतिस्थापित या उलटें"
@@ -969,22 +964,18 @@ title = "स्वचालित फ़ोल्डर स्कैनिंग
desc = "स्वचालित फ़ोल्डर स्कैनिंग गाइड के लिए लिंक"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO गाइड"
desc = "SSO गाइड के लिए लिंक"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "एयर-गैप्ड सेटअप"
desc = "एयर-गैप्ड सेटअप गाइड के लिए लिंक"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "पासवर्ड जोड़ें"
desc = "पासवर्ड के साथ अपने PDF दस्तावेज को एन्क्रिप्ट करें।"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "अनुमतियां बदलें"
desc = "दस्तावेज़ प्रतिबंध और अनुमतियाँ बदलें"
@@ -994,12 +985,10 @@ title = "स्वचालित करें"
desc = "PDF क्रियाओं को जोड़कर बहु-चरणीय वर्कफ़्लो बनाएँ। बार-बार होने वाले कार्यों के लिए उपयुक्त।"
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "PDF को दूसरी PDF के ऊपर ओवरले करें"
title = "PDF ओवरले करें"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF टेक्स्ट एडिटर"
desc = "ग्रुप्ड टेक्स्ट एडिटिंग और PDF पुनर्जनन के साथ Stirling PDF JSON एक्सपोर्ट की समीक्षा व संपादन करें"
@@ -1302,8 +1291,6 @@ outputFormat = "आउटपुट फ़ॉर्मेट"
pdfaNote = "PDF/A-1b अधिक संगत है, PDF/A-2b अधिक सुविधाएँ समर्थित करता है।"
pdfaFormat = "PDF/A फ़ॉर्मेट"
pdfaDigitalSignatureWarning = "PDF में एक डिजिटल हस्ताक्षर है। यह अगले चरण में हटा दिया जाएगा।"
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF में एक डिजिटल हस्ताक्षर है। यह अगले चरण में हटा दिया जाएगा।"
pdfxDescription = "PDF/X विश्वसनीय प्रिंटिंग और ग्राफ़िक्स विनिमय के लिए एक ISO मानक PDF उपसमुच्चय है।"
fileFormat = "फ़ाइल फ़ॉर्मेट"
@@ -2646,7 +2633,6 @@ label = "मूल PDF"
[compare.edited]
label = "संपादित PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "तुलना पुनः चलाएं?"
@@ -3567,44 +3553,6 @@ imageSize = "छवि आकार"
margin = "हाशिया"
positionAndFormatting = "स्थिति और फ़ॉर्मैटिंग"
quickPosition = "मुहर रखने के लिए पृष्ठ पर एक स्थान चुनें।"
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF में मुहर जोड़ते समय त्रुटि हुई।"
@@ -4523,18 +4471,10 @@ description = "पाइपलाइन प्रोसेसिंग और
[admin.settings.general.customPaths.pipeline]
label = "पाइपलाइन डायरेक्टरीज़"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "वॉच्ड फ़ोल्डर्स डायरेक्टरी"
description = "वह डायरेक्टरी जहाँ पाइपलाइन आने वाले PDF मॉनिटर करती है (डिफ़ॉल्ट हेतु खाली छोड़ें: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "फिनिश्ड फ़ोल्डर्स डायरेक्टरी"
description = "वह डायरेक्टरी जहाँ प्रोसेस किए गए PDF आउटपुट होते हैं (डिफ़ॉल्ट हेतु खाली छोड़ें: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "खाते को लॉक करने से पहले
label = "लॉगिन रीसेट समय (मिनट)"
description = "वह समय जिसके बाद असफल लॉगिन प्रयास रीसेट हो जाते हैं"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF सुरक्षा निष्क्रिय करें"
description = "Cross-Site Request Forgery सुरक्षा निष्क्रिय करें (अनुशंसित नहीं)"
@@ -6573,7 +6506,6 @@ link = "या किसी स्व-होस्टेड खाते से
title = "सर्वर से कनेक्ट करें"
subtitle = "अपना सेल्फ-होस्टेड सर्वर URL दर्ज करें"
testing = "कनेक्शन परीक्षण हो रहा है..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Stranice i početni broj"
positionAndPages = "Položaj i stranice"
preview = "Odabir položaja"
previewDisclaimer = "Pregled je približan. Konačni izlaz može varirati zbog metrika fonta u PDF-u."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Odaberi PDF datoteku:"
@@ -441,9 +439,7 @@ fullscreen = "Cijeli zaslon"
[settings.general.updates]
title = "Ažuriranja softvera"
description = "Provjerite ažuriranja i pogledajte informacije o verziji"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Trenutačna verzija"
latestVersion = "Najnovija verzija"
checkForUpdates = "Provjeri ažuriranja"
viewDetails = "Prikaži detalje"
@@ -954,7 +950,6 @@ title = "Auto dijeli po veličini/broju"
desc = "Podijelite jedan PDF na više dokumenata na temelju veličine, broja stranica ili broja dokumenata"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Zamijeni i invertiraj boju"
desc = "Zamijenite ili invertirajte boje u PDF dokumentima"
@@ -969,22 +964,18 @@ title = "Auto skeniranje mapa"
desc = "Poveznica na vodič za automatizirano skeniranje mapa"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO vodič"
desc = "Poveznica na SSO vodič"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped postavljanje"
desc = "Poveznica na vodič za air-gapped postavljanje"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Dodaj lozinku"
desc = "Šifrirajte svoj PDF dokument lozinkom.."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Promjena dopuštenja"
desc = "Promijenite ograničenja dokumenta i dopuštenja"
@@ -994,12 +985,10 @@ title = "Automatiziraj"
desc = "Izgradite višekoračne tijekove rada povezivanjem PDF radnji. Idealno za ponavljajuće zadatke."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Preklapa PDF-ove na drugi PDF"
title = "Preklapanje PDF-ova"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF uređivač teksta"
desc = "Pregledajte i uredite Stirling PDF JSON izvoze s grupnim uređivanjem teksta i ponovnim generiranjem PDF-a"
@@ -1302,8 +1291,6 @@ outputFormat = "Izlazni format"
pdfaNote = "PDF/A-1b je kompatibilniji, PDF/A-2b podržava više značajki."
pdfaFormat = "PDF/A format"
pdfaDigitalSignatureWarning = "PDF sadrži digitalni potpis. U sledećem koraku će biti uklonjen."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF sadrži digitalni potpis. Bit će uklonjen u sljedećem koraku."
pdfxDescription = "PDF/X je ISO standardni podskup PDF-a za pouzdani tisak i razmjenu grafike."
fileFormat = "Format datoteke"
@@ -2646,7 +2633,6 @@ label = "Izvorni PDF"
[compare.edited]
label = "Uređeni PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Ponovno pokrenuti usporedbu?"
@@ -3567,44 +3553,6 @@ imageSize = "Veličina slike"
margin = "Margina"
positionAndFormatting = "Položaj i oblikovanje"
quickPosition = "Odaberite položaj na stranici za postavljanje pečata."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Došlo je do pogreške pri dodavanju pečata u PDF."
@@ -4523,18 +4471,10 @@ description = "Konfigurirajte prilagođene putanje datotečnog sustava za obradu
[admin.settings.general.customPaths.pipeline]
label = "Direktoriji cjevovoda"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Direktorij nadziranih mapa"
description = "Direktorij u kojem cjevovod nadzire dolazne PDF-ove (ostavite prazno za zadano: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Direktorij dovršenih mapa"
description = "Direktorij u koji se ispisuju obrađeni PDF-ovi (ostavite prazno za zadano: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maksimalan broj neuspjelih pokušaja prijave prije zaključavanja
label = "Vrijeme resetiranja prijave (minute)"
description = "Vrijeme prije resetiranja neuspjelih pokušaja prijave"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Onemogući zaštitu od CSRF-a"
description = "Onemogući zaštitu od Cross-Site Request Forgery (ne preporučuje se)"
@@ -6573,7 +6506,6 @@ link = "ili se povežite sa samohostiranim računom"
title = "Povežite se s poslužiteljem"
subtitle = "Unesite URL svog self-hosted Stirling PDF poslužitelja"
testing = "Testiranje veze..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Oldalak és kezdő sorszám"
positionAndPages = "Pozíció és oldalak"
preview = "Pozíció kiválasztása"
previewDisclaimer = "Az előnézet hozzávetőleges. A végső kimenet eltérhet a PDF betűkészlet-metrikái miatt."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF fájl kiválasztása:"
@@ -441,9 +439,7 @@ fullscreen = "Teljes képernyő"
[settings.general.updates]
title = "Szoftverfrissítések"
description = "Frissítések keresése és verzióinformációk megtekintése"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Jelenlegi verzió"
latestVersion = "Legújabb verzió"
checkForUpdates = "Frissítések keresése"
viewDetails = "Részletek megtekintése"
@@ -954,7 +950,6 @@ title = "Auto felosztás méret/darab"
desc = "Egyetlen PDF felosztása több dokumentumra méret, oldalszám vagy dokumentumszám alapján"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Színek cseréje és invertálása"
desc = "Színek cseréje vagy invertálása PDF dokumentumokban"
@@ -969,22 +964,18 @@ title = "Automatikus mappaszkennelés"
desc = "Hivatkozás az automatikus mappaszkennelés útmutatójára"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO útmutató"
desc = "Hivatkozás az SSO útmutatóra"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped beállítás"
desc = "Hivatkozás az elszigetelt környezet beállítási útmutatójára"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Jelszó hozzáadása"
desc = "PDF dokumentum jelszavas védelme"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Jogosultságok módosítása"
desc = "Dokumentumkorlátozások és jogosultságok módosítása"
@@ -994,12 +985,10 @@ title = "Automatizálás"
desc = "Többlépéses munkafolyamatok összeállítása PDF műveletek összefűzésével. Ideális ismétlődő feladatokhoz."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "PDF-ek egymásra helyezése egy másik PDF-en"
title = "PDF-ek egymásra helyezése"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF szövegszerkesztő"
desc = "Nézze át és szerkessze a Stirling PDF JSON exportokat csoportosított szövegszerkesztéssel és PDF-újragenerálással"
@@ -1302,8 +1291,6 @@ outputFormat = "Kimeneti formátum"
pdfaNote = "A PDF/A-1b kompatibilisebb, a PDF/A-2b több funkciót támogat."
pdfaFormat = "PDF/A formátum"
pdfaDigitalSignatureWarning = "A PDF digitális aláírást tartalmaz. Ez a következő lépésben eltávolításra kerül."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "A PDF digitális aláírást tartalmaz. Ez a következő lépésben eltávolításra kerül."
pdfxDescription = "A PDF/X egy ISO szabványos PDF-részhalmaz megbízható nyomtatáshoz és grafikai cseréhez."
fileFormat = "Fájlformátum"
@@ -2646,7 +2633,6 @@ label = "Eredeti PDF"
[compare.edited]
label = "Szerkesztett PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Újrafuttatja az összehasonlítást?"
@@ -3567,44 +3553,6 @@ imageSize = "Képméret"
margin = "Margó"
positionAndFormatting = "Pozíció és formázás"
quickPosition = "Válasszon pozíciót az oldalon a bélyeg elhelyezéséhez."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Hiba történt a bélyeg hozzáadása közben a PDF-hez."
@@ -4523,18 +4471,10 @@ description = "Egyéni fájlrendszer-útvonalak konfigurálása a pipeline feldo
[admin.settings.general.customPaths.pipeline]
label = "Pipeline könyvtárak"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Megfigyelt mappák könyvtára"
description = "Könyvtár, ahol a pipeline a beérkező PDF-eket figyeli (hagyja üresen az alapértelmezett útvonalhoz: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Befejezett mappák könyvtára"
description = "Könyvtár, ahova a feldolgozott PDF-ek kimenete kerül (hagyja üresen az alapértelmezett útvonalhoz: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Sikertelen bejelentkezési kísérletek maximális száma fiókz
label = "Visszaállítás ideje (perc)"
description = "Idő, ami után a sikertelen bejelentkezési kísérletek számlálója lenullázódik"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF védelem letiltása"
description = "Cross-Site Request Forgery védelem letiltása (nem ajánlott)"
@@ -6573,7 +6506,6 @@ link = "vagy csatlakozzon egy saját üzemeltetésű fiókhoz"
title = "Csatlakozás a szerverhez"
subtitle = "Adja meg az önhostolt szerver URL-jét"
testing = "Kapcsolat tesztelése..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Halaman & Nomor Awal"
positionAndPages = "Posisi & Halaman"
preview = "Pemilihan Posisi"
previewDisclaimer = "Pratinjau bersifat perkiraan. Hasil akhir dapat berbeda karena metrik font PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Pilih berkas PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Layar penuh"
[settings.general.updates]
title = "Pembaruan Software"
description = "Periksa pembaruan dan lihat informasi versi"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versi Saat Ini"
latestVersion = "Versi Terbaru"
checkForUpdates = "Periksa Pembaruan"
viewDetails = "Lihat Detail"
@@ -954,7 +950,6 @@ title = "Pisah otomatis ukuran/jumlah"
desc = "Membagi satu PDF menjadi beberapa dokumen berdasarkan ukuran, jumlah halaman, atau jumlah dokumen"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Ganti & Balik Warna"
desc = "Ganti atau balik warna dalam dokumen PDF"
@@ -969,22 +964,18 @@ title = "Pemindaian Folder Otomatis"
desc = "Tautan ke panduan pemindaian folder otomatis"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Panduan SSO"
desc = "Tautan ke panduan SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Penyiapan Air-gapped"
desc = "Tautan ke panduan penyiapan air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Tambahkan Kata Sandi"
desc = "Enkripsi dokumen PDF Anda dengan kata sandi."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Ganti Perizinan"
desc = "Ubah pembatasan dan izin dokumen"
@@ -994,12 +985,10 @@ title = "Otomasi"
desc = "Bangun alur kerja multi-langkah dengan merangkai tindakan PDF. Ideal untuk tugas berulang."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Menumpuk PDF di atas PDF lain"
title = "Tumpuk PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor Teks PDF"
desc = "Tinjau dan edit ekspor Stirling PDF JSON dengan pengeditan teks terkelompok dan pembuatan ulang PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Format Keluaran"
pdfaNote = "PDF/A-1b lebih kompatibel, PDF/A-2b mendukung lebih banyak fitur."
pdfaFormat = "Format PDF/A"
pdfaDigitalSignatureWarning = "PDF ini mengandung tanda tangan digital. Ini akan dihapus pada langkah berikutnya."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF berisi tanda tangan digital. Ini akan dihapus pada langkah berikutnya."
pdfxDescription = "PDF/X adalah subset standar ISO dari PDF untuk pencetakan yang andal dan pertukaran grafis."
fileFormat = "Format File"
@@ -2646,7 +2633,6 @@ label = "PDF Asli"
[compare.edited]
label = "PDF yang Diedit"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Jalankan ulang perbandingan?"
@@ -3567,44 +3553,6 @@ imageSize = "Ukuran Gambar"
margin = "Margin"
positionAndFormatting = "Posisi & Pemformatan"
quickPosition = "Pilih posisi pada halaman untuk menempatkan stempel."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Terjadi kesalahan saat menambahkan stempel ke PDF."
@@ -4523,18 +4471,10 @@ description = "Konfigurasikan jalur sistem file kustom untuk pemrosesan pipeline
[admin.settings.general.customPaths.pipeline]
label = "Direktori Pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Direktori Folder yang Dipantau"
description = "Direktori tempat pipeline memantau PDF yang masuk (biarkan kosong untuk default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Direktori Folder Selesai"
description = "Direktori tempat PDF yang diproses dikeluarkan (biarkan kosong untuk default: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Jumlah maksimum kegagalan login sebelum akun terkunci"
label = "Waktu Reset Login (menit)"
description = "Waktu sebelum upaya login yang gagal direset"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Nonaktifkan Perlindungan CSRF"
description = "Nonaktifkan perlindungan Cross-Site Request Forgery (tidak disarankan)"
@@ -6573,7 +6506,6 @@ link = "atau hubungkan ke akun self-hosted"
title = "Sambungkan ke Server"
subtitle = "Masukkan URL server self-hosted Anda"
testing = "Menguji koneksi..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Pagine e numero iniziale"
positionAndPages = "Posizione e pagine"
preview = "Selezione posizione"
previewDisclaimer = "L'anteprima è approssimativa. Il risultato finale può variare a causa delle metriche dei font PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Seleziona il file PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Schermo intero"
[settings.general.updates]
title = "Aggiornamenti software"
description = "Controlla aggiornamenti e visualizza informazioni sulla versione"
currentBackendVersion = "Versione attuale del Backend"
currentFrontendVersion = "Versione attuale del Frontend"
versionMismatch = "Attenzione: è stata rilevata una discrepanza tra la versione del client e la versione di AppConfig. L'utilizzo di versioni diverse può causare problemi di compatibilità, errori e rischi per la sicurezza. Assicurarsi che server e client utilizzino la stessa versione."
currentVersion = "Versione attuale"
latestVersion = "Ultima versione"
checkForUpdates = "Controlla aggiornamenti"
viewDetails = "Vedi dettagli"
@@ -954,7 +950,6 @@ title = "Dividi auto per peso/pagine"
desc = "Dividi un singolo PDF in più documenti in base alle dimensioni, al numero di pagine o al numero di documenti"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Sostituisci e inverti colore"
desc = "Sostituisci o inverti i colori nei documenti PDF"
@@ -969,22 +964,18 @@ title = "Scansione automatica cartelle"
desc = "Link alla guida per scansione cartelle automatizzata"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guida SSO"
desc = "Link alla guida SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Setup isolato (airgapped)"
desc = "Link alla guida per setup airgapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Aggiungi Password"
desc = "Crittografa il tuo PDF con una password."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Cambia Permessi"
desc = "Modifica restrizioni e permessi del documento"
@@ -994,12 +985,10 @@ title = "Automatizza"
desc = "Crea flussi multistep concatenando azioni PDF. Ideale per attività ricorrenti."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Sovrapponi un PDF sopra un altro"
title = "Sovrapponi PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor di testo PDF"
desc = "Modifica testo e immagini esistenti nei PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Formato di output"
pdfaNote = "PDF/A-1b è più compatibile, PDF/A-2b supporta più funzionalità."
pdfaFormat = "Formato PDF/A"
pdfaDigitalSignatureWarning = "Il PDF contiene una firma digitale. Questo verrà rimosso nel passaggio successivo."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Il PDF contiene una firma digitale. Questa verrà rimossa nel passaggio successivo."
pdfxDescription = "PDF/X è un sottoinsieme PDF standard ISO per una stampa affidabile e lo scambio di grafica."
fileFormat = "Formato file"
@@ -2646,7 +2633,6 @@ label = "PDF originale"
[compare.edited]
label = "PDF modificato"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Eseguire di nuovo il confronto?"
@@ -3567,44 +3553,6 @@ imageSize = "Dimensione immagine"
margin = "Margine"
positionAndFormatting = "Posizione e formattazione"
quickPosition = "Seleziona una posizione sulla pagina in cui posizionare il timbro."
preview = "Anteprima:"
useTemplate = "Usa modello"
selectTemplate = "Seleziona un modello..."
stampTextDescription = "Utilizzare le variabili dinamiche di seguito. Utilizzare @@ per il carattere letterale @. Utilizzare \\n per le nuove righe."
dynamicVariables = "Variabili dinamiche"
clickToExpand = "Clicca per espandere"
variablesHelp = "Fai clic su una variabile qualsiasi per inserirla nel testo del timbro. Utilizzare @@ per letterale @."
dateTimeVars = "Data & Ora"
dateDesc = "Data corrente"
timeDesc = "Ora corrente"
datetimeDesc = "Data e ora combinate"
customDateDesc = "Formato personalizzato"
yearMonthDayDesc = "Parti di data individuali"
pageVars = "Informazioni sulla pagina"
pageNumberDesc = "Numero di pagina corrente"
totalPagesDesc = "Numero totale di pagine"
fileVars = "Informazioni sul file"
filenameDesc = "Nome file senza estensione"
filenameFullDesc = "Nome file con estensione"
metadataVars = "Metadati del documento"
metadataDesc = "Dalle proprietà del documento PDF"
otherVars = "Altro"
uuidDesc = "Identificatore univoco breve (8 caratteri)"
examples = "Esempi"
multiLine = "multilinea"
[AddStampRequest.template]
pageNumberFooter = "Piè di pagina con numero di pagina"
dateHeader = "Data intestazione"
europeanDate = "Data europea"
timestamp = "Timestamp"
draftWatermark = "Bozza Filigrana"
custom = "Personalizzato"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Si è verificato un errore durante l'aggiunta del timbro al PDF."
@@ -4523,18 +4471,10 @@ description = "Configura percorsi personalizzati del file system per l'elaborazi
[admin.settings.general.customPaths.pipeline]
label = "Directory pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Directory cartelle monitorate"
description = "Directory in cui la pipeline monitora i PDF in arrivo (lascia vuoto per predefinito: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Directory cartelle completate"
description = "Directory di output dei PDF elaborati (lascia vuoto per default: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Numero massimo di tentativi di accesso falliti prima del blocco d
label = "Tempo di reset accessi (minuti)"
description = "Tempo prima che i tentativi di accesso falliti vengano azzerati"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Disabilita protezione CSRF"
description = "Disabilita la protezione Cross-Site Request Forgery (non raccomandato)"
@@ -6573,7 +6506,6 @@ link = "oppure connettiti a un account self-hosted"
title = "Connetti al server"
subtitle = "Inserisci l'URL del tuo server self-hosted"
testing = "Verifica connessione..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "ページと開始番号"
positionAndPages = "位置とページ"
preview = "位置の選択"
previewDisclaimer = "プレビューは概算です。最終出力は PDF のフォントメトリクスにより異なる場合があります。"
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDFファイルを選択:"
@@ -441,9 +439,7 @@ fullscreen = "フルスクリーン"
[settings.general.updates]
title = "ソフトウェア更新"
description = "更新の確認とバージョン情報の表示"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "現在のバージョン"
latestVersion = "最新バージョン"
checkForUpdates = "更新を確認"
viewDetails = "詳細を表示"
@@ -954,7 +950,6 @@ title = "サイズ・数による自動分割"
desc = "サイズ・ページ数またはドキュメント数に基づいて、1つのPDFを複数のドキュメントに分割します。"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "色の置換と反転"
desc = "PDF 文書の色を置換または反転"
@@ -969,22 +964,18 @@ title = "自動フォルダスキャン"
desc = "自動フォルダスキャン ガイドへのリンク"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO ガイド"
desc = "SSO ガイドへのリンク"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "エアギャップ設定"
desc = "エアギャップ環境のセットアップガイドへのリンク"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "パスワードの追加"
desc = "PDFをパスワードで暗号化します。"
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "権限の変更"
desc = "文書の制限と権限を変更"
@@ -994,12 +985,10 @@ title = "自動化"
desc = "PDF アクションを連結して複数ステップのワークフローを構築。繰り返し作業に最適です。"
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "1つのPDFを別のPDFの上に重ねます"
title = "PDFを重ね合わせ"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDFテキストエディター"
desc = "グループ化されたテキスト編集とPDF再生成で、Stirling PDF の JSON エクスポートをレビュー・編集します。"
@@ -1302,8 +1291,6 @@ outputFormat = "出力形式"
pdfaNote = "PDF/A-1b は互換性が高く、PDF/A-2b はより多くの機能をサポートします。"
pdfaFormat = "PDF/A 形式"
pdfaDigitalSignatureWarning = "PDFにはデジタル署名が含まれています。これは次の手順で削除されます。"
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF にはデジタル署名が含まれています。これは次のステップで削除されます。"
pdfxDescription = "PDF/X は、信頼性の高い印刷とグラフィック交換のための ISO 規格の PDF サブセットです。"
fileFormat = "ファイル形式"
@@ -2646,7 +2633,6 @@ label = "元の PDF"
[compare.edited]
label = "編集済み PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "比較を再実行しますか?"
@@ -3567,44 +3553,6 @@ imageSize = "画像サイズ"
margin = "余白"
positionAndFormatting = "位置と書式"
quickPosition = "ページ上の配置位置を選択してください。"
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF にスタンプを追加中にエラーが発生しました。"
@@ -4523,18 +4471,10 @@ description = "パイプライン処理や外部ツール用のカスタムフ
[admin.settings.general.customPaths.pipeline]
label = "パイプラインディレクトリ"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "監視フォルダーのディレクトリ"
description = "パイプラインが受信 PDF を監視するディレクトリ(空欄で既定: /pipeline/watchedFolders"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "完了フォルダーのディレクトリ"
description = "処理済み PDF の出力先ディレクトリ(空欄で既定: /pipeline/finishedFolders"
@@ -4586,13 +4526,6 @@ description = "アカウントロックまでの最大失敗回数"
label = "ログインリセット時間(分)"
description = "失敗回数がリセットされるまでの時間"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF 保護を無効化"
description = "クロスサイトリクエストフォージェリ保護を無効化(非推奨)"
@@ -6573,7 +6506,6 @@ link = "またはセルフホスト型アカウントに接続"
title = "サーバーに接続"
subtitle = "セルフホスト サーバーの URL を入力"
testing = "接続をテスト中..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "페이지 및 시작 번호"
positionAndPages = "위치 및 페이지"
preview = "위치 선택"
previewDisclaimer = "미리보기는 대략적인 표시입니다. 최종 출력은 PDF 글꼴 메트릭에 따라 달라질 수 있습니다."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF 파일 선택:"
@@ -441,9 +439,7 @@ fullscreen = "전체 화면"
[settings.general.updates]
title = "소프트웨어 업데이트"
description = "업데이트 확인 및 버전 정보 보기"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "현재 버전"
latestVersion = "최신 버전"
checkForUpdates = "업데이트 확인"
viewDetails = "자세히 보기"
@@ -954,7 +950,6 @@ title = "크기/개수별 자동 분할"
desc = "단일 PDF를 크기, 페이지 수 또는 문서 수를 기준으로 여러 문서로 분할"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "색상 교체 및 반전"
desc = "PDF 문서의 색상을 교체하거나 반전합니다."
@@ -969,22 +964,18 @@ title = "자동 폴더 스캔"
desc = "자동 폴더 스캔 가이드로 이동"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO 가이드"
desc = "SSO 가이드로 이동"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "격리 환경 설정"
desc = "격리 환경 설정 가이드로 이동"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "비밀번호 추가"
desc = "PDF 문서를 비밀번호로 암호화합니다."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "권한 변경"
desc = "문서 제한 및 권한 변경"
@@ -994,12 +985,10 @@ title = "자동화"
desc = "PDF 작업을 연결하여 다단계 워크플로를 구성하세요. 반복 작업에 이상적입니다."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "PDF를 다른 PDF 위에 오버레이"
title = "PDF 오버레이"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF 텍스트 편집기"
desc = "그룹화된 텍스트 편집과 PDF 재생성으로 Stirling PDF의 JSON 내보내기를 검토하고 편집하세요"
@@ -1302,8 +1291,6 @@ outputFormat = "출력 형식"
pdfaNote = "PDF/A-1b는 호환성이 더 높고, PDF/A-2b는 더 많은 기능을 지원합니다."
pdfaFormat = "PDF/A 형식"
pdfaDigitalSignatureWarning = "PDF에 디지털 서명이 포함되어 있습니다. 다음 단계에서 제거됩니다."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "해당 PDF에는 디지털 서명이 포함되어 있습니다. 다음 단계에서 제거됩니다."
pdfxDescription = "PDF/X는 신뢰할 수 있는 인쇄와 그래픽 교환을 위한 ISO 표준 PDF 하위 집합입니다."
fileFormat = "파일 형식"
@@ -2646,7 +2633,6 @@ label = "원본 PDF"
[compare.edited]
label = "수정된 PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "비교를 다시 실행할까요?"
@@ -3567,44 +3553,6 @@ imageSize = "이미지 크기"
margin = "여백"
positionAndFormatting = "위치 및 서식"
quickPosition = "페이지에서 스탬프 위치를 선택하세요."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF에 스탬프를 추가하는 중 오류가 발생했습니다."
@@ -4523,18 +4471,10 @@ description = "파이프라인 처리 및 외부 도구용 사용자 지정 파
[admin.settings.general.customPaths.pipeline]
label = "파이프라인 디렉터리"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "감시 폴더 디렉터리"
description = "파이프라인이 들어오는 PDF를 감시하는 디렉터리(기본값 사용 시 비워두세요: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "처리 완료 폴더 디렉터리"
description = "처리된 PDF가 출력되는 디렉터리(기본값 사용 시 비워두세요: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "계정 잠금 전 허용되는 최대 로그인 실패 횟수"
label = "로그인 재설정 시간(분)"
description = "로그인 실패 횟수가 재설정되기까지의 시간"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF 보호 비활성화"
description = "교차 사이트 요청 위조 보호를 비활성화합니다(권장하지 않음)"
@@ -6573,7 +6506,6 @@ link = "또는 셀프 호스팅 계정에 연결"
title = "서버에 연결"
subtitle = "자가 호스팅 서버 URL을 입력하세요"
testing = "연결 테스트 중..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "പേജുകളും ആരംഭ നമ്പറും"
positionAndPages = "സ്ഥാനം & പേജുകൾ"
preview = "സ്ഥാനം തിരഞ്ഞെടുപ്പ്"
previewDisclaimer = "പ്രിവ്യൂ ഏകദേശമാണ്. PDF ഫോണ്ട് മീട്രിക്‌സിന്റെ കാരണമായി അന്തിമ ഔട്ട്പുട്ട് വ്യത്യാസപ്പെട്ടേക്കാം."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "PDF ഫയൽ തിരഞ്ഞെടുക്കുക:"
@@ -441,9 +439,7 @@ fullscreen = "ഫുൾസ്ക്രീൻ"
[settings.general.updates]
title = "സോഫ്റ്റ്‌വെയർ അപ്‌ഡേറ്റുകൾ"
description = "അപ്‌ഡേറ്റുകൾ പരിശോധിക്കുകയും പതിപ്പിന്റെ വിവരങ്ങൾ കാണുകയും ചെയ്യുക"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "ഇപ്പോഴത്തെ പതിപ്പ്"
latestVersion = "പുതിയ പതിപ്പ്"
checkForUpdates = "അപ്‌ഡേറ്റുകൾ പരിശോധിക്കുക"
viewDetails = "വിശദാംശങ്ങൾ കാണുക"
@@ -954,7 +950,6 @@ title = "സൈസ്/കൗണ്ട് ഓട്ടോ സ്പ്ലിറ
desc = "ഫയൽ വലുപ്പം അല്ലെങ്കിൽ പേജ് എണ്ണം പ്രകാരം PDF-കൾ സ്വയം വിഭജിക്കുക"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "നിറം മാറ്റുക / ഇൻവേർട്ട്"
desc = "PDF ഡോക്യുമെന്റുകളിൽ നിറങ്ങൾ പകരംവെക്കുകയോ ഇൻവേർട്ട് ചെയ്യുകയോ ചെയ്യുക"
@@ -969,22 +964,18 @@ title = "ഓട്ടോമേറ്റഡ് ഫോൾഡർ സ്കാനി
desc = "ഓട്ടോമേറ്റഡ് ഫോൾഡർ സ്കാനിംഗ് ഗൈഡിലേക്കുള്ള ലിങ്ക്"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO ഗൈഡ്"
desc = "SSO ഗൈഡിലേക്കുള്ള ലിങ്ക്"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped സെറ്റപ്പ്"
desc = "എയർ-ഗ്യാപ്ഡ് സെറ്റപ്പ് ഗൈഡിലേക്കുള്ള ലിങ്ക്"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "പാസ്‌വേഡ് ചേർക്കുക"
desc = "നിങ്ങളുടെ PDF പ്രമാണം ഒരു പാസ്‌വേഡ് ഉപയോഗിച്ച് എൻക്രിപ്റ്റ് ചെയ്യുക."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "അനുമതികൾ മാറ്റുക"
desc = "ഡോക്യുമെന്റ് നിയന്ത്രണങ്ങളും അനുമതികളും മാറ്റുക"
@@ -994,12 +985,10 @@ title = "ഓട്ടോമേറ്റ്"
desc = "PDF പ്രവർത്തനങ്ങൾ ബന്ധിപ്പിച്ച് മൾട്ടി-സ്റ്റെപ്പ് വർക്‌ഫ്ലോകൾ നിർമ്മിക്കുക. ആവർത്തിക്കുന്ന ജോലികൾക്ക് അനുയോജ്യം."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "മറ്റൊരു PDF-ന് മുകളിൽ PDF-കൾ ഓവർലേ ചെയ്യുന്നു"
title = "PDF-കൾ ഓവർലേ ചെയ്യുക"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF ടെക്സ്റ്റ് എഡിറ്റർ"
desc = "ഗ്രൂപ്പുചെയ്ത ടെക്സ്റ്റ് എഡിറ്റിംഗിനോടും PDF വീണ്ടും സൃഷ്ടിക്കുന്നതോടും കൂടി Stirling PDF JSON എക്സ്പോർട്ടുകൾ റിവ്യൂ ചെയ്ത് എഡിറ്റ് ചെയ്യുക"
@@ -1302,8 +1291,6 @@ outputFormat = "ഔട്ട്പുട്ട് ഫോർമാറ്റ്"
pdfaNote = "PDF/A-1b കൂടുതൽ അനുയോജ്യതയുള്ളത്, PDF/A-2b കൂടുതൽ ഫീച്ചറുകൾ പിന്തുണയ്ക്കുന്നു."
pdfaFormat = "PDF/A ഫോർമാറ്റ്"
pdfaDigitalSignatureWarning = "ഈ PDF-ൽ ഡിജിറ്റൽ ഒപ്പ് ഉണ്ട്. ഇത് അടുത്ത ഘട്ടത്തിൽ നീക്കം ചെയ്യപ്പെടും."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF-യിൽ ഡിജിറ്റൽ ഒപ്പ് ഉണ്ട്. ഇത് അടുത്ത ഘട്ടത്തിൽ നീക്കം ചെയ്യും."
pdfxDescription = "വിശ്വാസ്യതയുള്ള പ്രിന്റിംഗിനും ഗ്രാഫിക്സ് കൈമാറ്റത്തിനുമായി PDF/X ഒരു ISO സ്റ്റാൻഡേർഡ് PDF ഉപസമുച്ചയമാണ്."
fileFormat = "ഫയൽ ഫോർമാറ്റ്"
@@ -2646,7 +2633,6 @@ label = "ഓറിജിനൽ PDF"
[compare.edited]
label = "എഡിറ്റുചെയ്ത PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "താരതമ്യം വീണ്ടും നടത്തണോ?"
@@ -3567,44 +3553,6 @@ imageSize = "ഇമേജ് വലിപ്പം"
margin = "മാർജിൻ"
positionAndFormatting = "സ്ഥാനം & ഫോർമാറ്റിംഗ്"
quickPosition = "സ്റ്റാമ്പ് വയ്ക്കാൻ പേജിലെ ഒരു സ്ഥാനം തിരഞ്ഞെടുക്കുക."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "PDF-ലേക്ക് സ്റ്റാമ്പ് ചേർക്കുന്നതിനിടെ പിശക് സംഭവിച്ചു."
@@ -4523,18 +4471,10 @@ description = "പൈപ്പ്‌ലൈൻ പ്രോസസിംഗിന
[admin.settings.general.customPaths.pipeline]
label = "പൈപ്പ്‌ലൈൻ ഡയറക്ടറികൾ"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "വാച്ച് ചെയ്യുന്ന ഫോൾഡറുകളുടെ ഡയറക്ടറി"
description = "പൈപ്പ്‌ലൈൻ ഇൻകമിംഗ് PDFകൾക്കായി നിരീക്ഷിക്കുന്ന ഡയറക്ടറി (ഡീഫാൾട്ട് ഉപയോഗിക്കാൻ ശൂന്യം വിടുക: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "ഫിനിഷ്ഡ് ഫോൾഡറുകളുടെ ഡയറക്ടറി"
description = "പ്രോസസ്സ് ചെയ്ത PDFകൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്ന ഡയറക്ടറി (ഡീഫാൾട്ട് ഉപയോഗിക്കാൻ ശൂന്യം വിടുക: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "അക്കൗണ്ട് ലോക്കാകുന്നത
label = "ലോഗിൻ റീസെറ്റ് സമയം (മിനിറ്റ്)"
description = "പരാജയപ്പെട്ട ലോഗിൻ ശ്രമങ്ങൾ റീസെറ്റ് ചെയ്യുന്നതിന് മുമ്പുള്ള സമയം"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF സംരക്ഷണം അപ്രാപ്തമാക്കുക"
description = "Cross-Site Request Forgery സംരക്ഷണം അപ്രാപ്തമാക്കുക (ശുപാർശ ചെയ്യുന്നതല്ല)"
@@ -6573,7 +6506,6 @@ link = "അല്ലെങ്കിൽ സ്വയം-ഹോസ്റ്റു
title = "സെർവറിലേക്ക് കണക്റ്റുചെയ്യുക"
subtitle = "നിങ്ങളുടെ സെൽഫ്-ഹോസ്റ്റഡ് സെർവർ URL നൽകുക"
testing = "കണക്ഷൻ പരിശോധിക്കുന്നു..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Pagina's en startnummer"
positionAndPages = "Positie en pagina's"
preview = "Positie selecteren"
previewDisclaimer = "Voorbeeld is indicatief. Het uiteindelijke resultaat kan afwijken door PDF-lettertype­metriek."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Selecteer PDF-bestand:"
@@ -441,9 +439,7 @@ fullscreen = "Volledig scherm"
[settings.general.updates]
title = "Software-updates"
description = "Controleer op updates en bekijk versie-informatie"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Huidige versie"
latestVersion = "Laatste versie"
checkForUpdates = "Op updates controleren"
viewDetails = "Details bekijken"
@@ -954,7 +950,6 @@ title = "Automatisch splitsen op grootte/aantal"
desc = "Splits een enkele PDF in meerdere documenten op basis van grootte, aantal pagina's of aantal documenten"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Kleur vervangen en inverteren"
desc = "Kleuren in PDF-documenten vervangen of inverteren"
@@ -969,22 +964,18 @@ title = "Geautomatiseerd mappenscannen"
desc = "Link naar handleiding voor geautomatiseerd mappenscannen"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO-gids"
desc = "Link naar SSO-gids"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Air-gapped-installatie"
desc = "Link naar handleiding voor air-gapped-installatie"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Wachtwoord toevoegen"
desc = "Versleutel uw PDF-document met een wachtwoord."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Rechten wijzigen"
desc = "Documentbeperkingen en machtigingen wijzigen"
@@ -994,12 +985,10 @@ title = "Automatiseren"
desc = "Bouw workflows met meerdere stappen door PDF-acties te koppelen. Ideaal voor terugkerende taken."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Plaatst PDF's over een andere PDF heen"
title = "PDF's overlappen"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF-teksteditor"
desc = "Bewerk bestaande tekst en afbeeldingen in PDF's"
@@ -1302,8 +1291,6 @@ outputFormat = "Uitvoerformaat"
pdfaNote = "PDF/A-1b is compatibeler, PDF/A-2b ondersteunt meer functies."
pdfaFormat = "PDF/A-formaat"
pdfaDigitalSignatureWarning = "Dit PDF bestand bevat een digitale handtekening. Deze wordt in de volgende stap verwijderd."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "Het PDF-bestand bevat een digitale handtekening. Deze wordt in de volgende stap verwijderd."
pdfxDescription = "PDF/X is een ISO-standaard PDF-subset voor betrouwbaar afdrukken en grafische uitwisseling."
fileFormat = "Bestandsformaat"
@@ -2646,7 +2633,6 @@ label = "Originele PDF"
[compare.edited]
label = "Bewerkte PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Vergelijking opnieuw uitvoeren?"
@@ -3567,44 +3553,6 @@ imageSize = "Afbeeldingsgrootte"
margin = "Marge"
positionAndFormatting = "Positie & opmaak"
quickPosition = "Selecteer een positie op de pagina om de stempel te plaatsen."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Er is een fout opgetreden bij het toevoegen van een stempel aan de PDF."
@@ -4523,18 +4471,10 @@ description = "Configureer aangepaste bestandssysteempaden voor pijplijnverwerki
[admin.settings.general.customPaths.pipeline]
label = "Pipelinemappen"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Map met bewaakte mappen"
description = "Map waarin de pipeline inkomende PDF's bewaakt (laat leeg voor standaard: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Map met voltooide mappen"
description = "Map waar verwerkte PDF's worden weggeschreven (laat leeg voor standaard: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maximaal aantal mislukte inlogpogingen voordat het account wordt
label = "Resetperiode voor inloggen (minuten)"
description = "Tijd voordat mislukte inlogpogingen worden gereset"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "CSRF-bescherming uitschakelen"
description = "Cross-Site Request Forgery-bescherming uitschakelen (niet aanbevolen)"
@@ -6573,7 +6506,6 @@ link = "of maak verbinding met een zelfgehost account"
title = "Verbinden met server"
subtitle = "Vul de URL van uw self-hosted server in"
testing = "Verbinding testen..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Sider og startnummer"
positionAndPages = "Plassering og sider"
preview = "Valg av plassering"
previewDisclaimer = "Forhåndsvisningen er omtrentlig. Endelig resultat kan variere på grunn av PDF-skriftmetrikker."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Velg PDF-fil:"
@@ -441,9 +439,7 @@ fullscreen = "Fullskjerm"
[settings.general.updates]
title = "Programvareoppdateringer"
description = "Se etter oppdateringer og vis versjonsinformasjon"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Nåværende versjon"
latestVersion = "Siste versjon"
checkForUpdates = "Søk etter oppdateringer"
viewDetails = "Vis detaljer"
@@ -954,7 +950,6 @@ title = "Auto-del størrelse/antall"
desc = "Del en enkelt PDF i flere dokumenter basert på størrelse, antall sider eller dokumenter"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Erstatt og inverter farger"
desc = "Erstatt eller inverter farger i PDF-dokumenter"
@@ -969,22 +964,18 @@ title = "Automatisert mappeskanning"
desc = "Lenke til veiledning for automatisert mappeskanning"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "SSO-veiledning"
desc = "Lenke til SSO-veiledning"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Luftgap-oppsett"
desc = "Lenke til veiledning for luftgap-oppsett"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Legg til Passord"
desc = "Krypter din PDF-dokument med et passord."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Endre tillatelser"
desc = "Endre dokumentbegrensninger og tillatelser"
@@ -994,12 +985,10 @@ title = "Automatiser"
desc = "Bygg flertrinns arbeidsflyter ved å lenke sammen PDF-handlinger. Ideelt for gjentakende oppgaver."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Legger PDF-er over hverandre"
title = "Overlay PDF-er"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "PDF-tekstredigerer"
desc = "Gå gjennom og rediger Stirling PDF JSON-eksporter med gruppert tekstredigering og regenerering av PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Utdataformat"
pdfaNote = "PDF/A-1b er mer kompatibel, PDF/A-2b støtter flere funksjoner."
pdfaFormat = "PDF/A-format"
pdfaDigitalSignatureWarning = "PDFen inneholder en digital signatur. Denne vil bli fjernet i neste steg."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF-en inneholder en digital signatur. Denne vil bli fjernet i neste trinn."
pdfxDescription = "PDF/X er en ISO-standardisert PDF-undermengde for pålitelig utskrift og grafikkutveksling."
fileFormat = "Filformat"
@@ -2646,7 +2633,6 @@ label = "Original-PDF"
[compare.edited]
label = "Redigert PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Kjøre sammenligning på nytt?"
@@ -3567,44 +3553,6 @@ imageSize = "Bildestørrelse"
margin = "Marg"
positionAndFormatting = "Plassering og formatering"
quickPosition = "Velg en posisjon på siden for å plassere stempelet."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Det oppstod en feil under tillegg av stempel til PDF-en."
@@ -4523,18 +4471,10 @@ description = "Konfigurer egendefinerte filsystemstier for pipeline-prosessering
[admin.settings.general.customPaths.pipeline]
label = "Pipeline-kataloger"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Katalog for overvåkede mapper"
description = "Katalog der pipeline overvåker innkommende PDF-er (la stå tomt for standard: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Katalog for ferdige mapper"
description = "Katalog der behandlede PDF-er plasseres (la stå tomt for standard: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maksimalt antall mislykkede innloggingsforsøk før kontolåsing"
label = "Tilbakestillingstid for innlogging (minutter)"
description = "Tid før mislykkede innloggingsforsøk nullstilles"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Deaktiver CSRF-beskyttelse"
description = "Deaktiver Cross-Site Request Forgery-beskyttelse (anbefales ikke)"
@@ -6573,7 +6506,6 @@ link = "eller koble til en selvhostet konto"
title = "Koble til server"
subtitle = "Skriv inn URL-en til din selvhostede server"
testing = "Tester tilkobling..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Strony i numer początkowy"
positionAndPages = "Pozycja i strony"
preview = "Wybór położenia"
previewDisclaimer = "Podgląd jest przybliżony. Finalny wynik może się różnić z powodu metryk czcionek PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Wskaż plik PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Pełny ekran"
[settings.general.updates]
title = "Aktualizacje oprogramowania"
description = "Sprawdź aktualizacje i informacje o wersji"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Bieżąca wersja"
latestVersion = "Najnowsza wersja"
checkForUpdates = "Sprawdź aktualizacje"
viewDetails = "Pokaż szczegóły"
@@ -954,7 +950,6 @@ title = "Podziel (Rozmiar/Ilość stron)"
desc = "Rozdziela dokument PDF na wiele dokumentów bazując na podanym rozmiarze, ilości stron bądź ilości dokumentów"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Zastąp i odwróć kolor"
desc = "Zastępuj lub odwracaj kolory w dokumentach PDF"
@@ -969,22 +964,18 @@ title = "Auto skan folderów"
desc = "Link do przewodnika automatycznego skanowania folderów"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Przewodnik SSO"
desc = "Link do przewodnika SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Konfiguracja odizolowana"
desc = "Link do przewodnika konfiguracji odizolowanej"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Dodaj hasło"
desc = "Zaszyfruj dokument PDF za pomocą hasła."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Zmień uprawnienia"
desc = "Zmień ograniczenia i uprawnienia dokumentu"
@@ -994,12 +985,10 @@ title = "Automatyzuj"
desc = "Buduj wieloetapowe przepływy, łącząc akcje PDF. Idealne do powtarzających się zadań."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Nakłada dokumenty PDF na siebie"
title = "Nałóż PDFa"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Edytor tekstu PDF"
desc = "Przeglądaj i edytuj eksporty JSON z Stirling PDF z grupową edycją tekstu i ponowną generacją PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Format wyjściowy"
pdfaNote = "PDF/A-1b jest bardziej kompatybilny, PDF/A-2b obsługuje więcej funkcji."
pdfaFormat = "Format PDF/A"
pdfaDigitalSignatureWarning = "Dokument zawiera podpis cyfrowy, nie zostanie on wczytany."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF zawiera podpis cyfrowy. Zostanie on usunięty w następnym kroku."
pdfxDescription = "PDF/X to podzbiór PDF zgodny z normą ISO, przeznaczony do niezawodnego druku i wymiany grafiki."
fileFormat = "Format pliku"
@@ -2646,7 +2633,6 @@ label = "Oryginalny PDF"
[compare.edited]
label = "Edytowany PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Uruchomić porównanie ponownie?"
@@ -3567,44 +3553,6 @@ imageSize = "Rozmiar obrazu"
margin = "Margines"
positionAndFormatting = "Pozycja i formatowanie"
quickPosition = "Wybierz pozycję na stronie, aby umieścić stempel."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Wystąpił błąd podczas dodawania stempla do PDF."
@@ -4523,18 +4471,10 @@ description = "Skonfiguruj niestandardowe ścieżki systemu plików dla przetwar
[admin.settings.general.customPaths.pipeline]
label = "Katalogi potoku"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Katalog obserwowanych folderów"
description = "Katalog, w którym potok monitoruje przychodzące pliki PDF (pozostaw puste, aby użyć domyślnego: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Katalog ukończonych folderów"
description = "Katalog, do którego trafiają przetworzone pliki PDF (pozostaw puste, aby użyć domyślnego: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Maksymalna liczba nieudanych prób logowania przed zablokowaniem
label = "Czas resetu prób logowania (minuty)"
description = "Czas, po którym licznik nieudanych prób logowania jest resetowany"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Wyłącz ochronę CSRF"
description = "Wyłącz ochronę przed Cross-Site Request Forgery (niezalecane)"
@@ -6573,7 +6506,6 @@ link = "lub połącz się z kontem hostowanym samodzielnie"
title = "Połącz z serwerem"
subtitle = "Wpisz URL własnego serwera"
testing = "Testowanie połączenia..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Páginas e número inicial"
positionAndPages = "Posição e páginas"
preview = "Seleção de posição"
previewDisclaimer = "A prévia é aproximada. A saída final pode variar devido às métricas de fonte do PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Selecionar arquivo PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Tela cheia"
[settings.general.updates]
title = "Atualizações de software"
description = "Verifique atualizações e veja informações da versão"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versão atual"
latestVersion = "Última versão"
checkForUpdates = "Verificar atualizações"
viewDetails = "Ver detalhes"
@@ -954,7 +950,6 @@ title = "Divisão Manual do PDF"
desc = "Divida um PDF em vários, com base no tamanho, contagem de páginas ou contagem de documentos."
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Substituir e inverter cor"
desc = "Substituir ou inverter cores em documentos PDF"
@@ -969,22 +964,18 @@ title = "Varredura automática de pasta"
desc = "Link para o guia de varredura automática de pastas"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guia de SSO"
desc = "Link para o guia de SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Configuração Air-gapped"
desc = "Link para o guia de configuração isolada (air-gapped)"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Proteger PDF"
desc = "Criptografar seu PDF com uma senha podendo realizar alterações de permissões."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Alterar Permissões"
desc = "Alterar restrições e permissões do documento"
@@ -994,12 +985,10 @@ title = "Automatizar"
desc = "Crie fluxos de trabalho de várias etapas encadeando ações de PDF. Ideal para tarefas recorrentes."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Sobrepor um PDF sobre outro"
title = "Sobrepor PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor de texto de PDF"
desc = "Revise e edite exportações JSON do Stirling PDF com edição de texto agrupada e regeneração do PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Formato de saída"
pdfaNote = "PDF/A-1b é mais compatível; PDF/A-2b oferece mais recursos."
pdfaFormat = "Formato PDF/A"
pdfaDigitalSignatureWarning = "O PDF contém uma assinatura digital. Isso será removido na próxima etapa."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "O PDF contém uma assinatura digital. Ela será removida na próxima etapa."
pdfxDescription = "PDF/X é um subconjunto de PDF padrão ISO para impressão confiável e troca de gráficos."
fileFormat = "Formato de arquivo"
@@ -2646,7 +2633,6 @@ label = "PDF original"
[compare.edited]
label = "PDF editado"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Executar a comparação novamente?"
@@ -3567,44 +3553,6 @@ imageSize = "Tamanho da imagem"
margin = "Margem"
positionAndFormatting = "Posição e formatação"
quickPosition = "Selecione uma posição na página para colocar o carimbo."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Ocorreu um erro ao adicionar o carimbo ao PDF."
@@ -4523,18 +4471,10 @@ description = "Configurar caminhos personalizados do sistema de arquivos para pr
[admin.settings.general.customPaths.pipeline]
label = "Diretórios do pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Diretório de pastas monitoradas"
description = "Diretório onde o pipeline monitora PDFs recebidos (deixe em branco para padrão: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Diretório de pastas finalizadas"
description = "Diretório onde os PDFs processados são gerados (deixe em branco para padrão: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Número máximo de tentativas de login com falha antes do bloquei
label = "Tempo para redefinir tentativas (minutos)"
description = "Tempo antes que as tentativas de login com falha sejam redefinidas"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Desativar proteção CSRF"
description = "Desativar a proteção contra Cross-Site Request Forgery (não recomendado)"
@@ -6573,7 +6506,6 @@ link = "ou conecte-se a uma conta auto-hospedada"
title = "Conectar ao servidor"
subtitle = "Informe a URL do seu servidor self-hosted"
testing = "Testando conexão..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Páginas e número inicial"
positionAndPages = "Posição e páginas"
preview = "Seleção de posição"
previewDisclaimer = "A pré-visualização é aproximada. O resultado final pode variar devido às métricas de fontes do PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Selecionar ficheiro PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Ecrã inteiro"
[settings.general.updates]
title = "Atualizações de software"
description = "Procurar atualizações e ver informações da versão"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versão atual"
latestVersion = "Última versão"
checkForUpdates = "Procurar atualizações"
viewDetails = "Ver detalhes"
@@ -954,7 +950,6 @@ title = "Auto-dividir por tamanho/n.º"
desc = "Dividir um único PDF em múltiplos documentos baseado em tamanho, contagem de páginas, ou contagem de documentos"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Substituir e inverter cor"
desc = "Substituir ou inverter cores em documentos PDF"
@@ -969,22 +964,18 @@ title = "Varrimento auto de pastas"
desc = "Ligação para o guia de varrimento automático de pastas"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Guia de SSO"
desc = "Ligação para o guia de SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Configuração Air-gapped"
desc = "Ligação para o guia de configuração Air-gapped"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Adicionar Palavra-passe"
desc = "Encriptar o seu documento PDF com uma palavra-passe."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Alterar Permissões"
desc = "Alterar restrições e permissões do documento"
@@ -994,12 +985,10 @@ title = "Automatizar"
desc = "Crie fluxos de trabalho de vários passos encadeando ações de PDF. Ideal para tarefas recorrentes."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Sobrepõe PDFs em cima de outro PDF"
title = "Sobrepor PDFs"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor de texto PDF"
desc = "Revise e edite exportações JSON do Stirling PDF com edição de texto agrupado e regeneração de PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Formato de saída"
pdfaNote = "PDF/A-1b é mais compatível, PDF/A-2b suporta mais funcionalidades."
pdfaFormat = "Formato PDF/A"
pdfaDigitalSignatureWarning = "O PDF contém uma assinatura digital. Esta será removida no próximo passo."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "O PDF contém uma assinatura digital. Esta será removida no passo seguinte."
pdfxDescription = "PDF/X é um subconjunto de PDF normalizado pela ISO para impressão fiável e troca de gráficos."
fileFormat = "Formato de ficheiro"
@@ -2646,7 +2633,6 @@ label = "PDF Original"
[compare.edited]
label = "PDF Editado"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Executar comparação novamente?"
@@ -3567,44 +3553,6 @@ imageSize = "Tamanho da imagem"
margin = "Margem"
positionAndFormatting = "Posição e formatação"
quickPosition = "Selecione uma posição na página para colocar o carimbo."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Ocorreu um erro ao adicionar o carimbo ao PDF."
@@ -4523,18 +4471,10 @@ description = "Configurar caminhos de sistema de ficheiros personalizados para o
[admin.settings.general.customPaths.pipeline]
label = "Diretórios do pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Diretório de pastas monitorizadas"
description = "Diretório onde o pipeline monitoriza PDFs de entrada (deixe vazio para predefinição: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Diretório de pastas concluídas"
description = "Diretório onde são gravados os PDFs processados (deixe vazio para predefinição: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Número máximo de tentativas falhadas de início de sessão ante
label = "Tempo de reposição do início de sessão (minutos)"
description = "Tempo até que as tentativas falhadas de início de sessão sejam repostas"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Desativar proteção CSRF"
description = "Desativar proteção Cross-Site Request Forgery (não recomendado)"
@@ -6573,7 +6506,6 @@ link = "ou ligue-se a uma conta autoalojada"
title = "Ligar ao servidor"
subtitle = "Introduza o URL do seu servidor autoalojado"
testing = "A testar ligação..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Pagini și număr de start"
positionAndPages = "Poziție și pagini"
preview = "Selecție poziție"
previewDisclaimer = "Previzualizarea este aproximativă. Rezultatul final poate varia din cauza metricilor de font ale PDF-ului."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Selectează fișierul PDF:"
@@ -441,9 +439,7 @@ fullscreen = "Ecran complet"
[settings.general.updates]
title = "Actualizări software"
description = "Caută actualizări și vezi informații despre versiune"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Versiune curentă"
latestVersion = "Ultima versiune"
checkForUpdates = "Caută actualizări"
viewDetails = "Vezi detalii"
@@ -954,7 +950,6 @@ title = "Auto-împărțire mărime/pagini"
desc = "Împarte un singur PDF în mai multe documente bazat pe dimensiune, număr de pagini sau număr de documente"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Schimbă și inversează culori"
desc = "Înlocuiți sau inversați culorile în documente PDF"
@@ -969,22 +964,18 @@ title = "Scanare automată foldere"
desc = "Link către ghidul de scanare automată a folderelor"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Ghid SSO"
desc = "Link către ghidul SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Configurare air-gapped"
desc = "Link către ghidul de configurare izolată de rețea"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Adaugă Parolă"
desc = "Criptează documentul PDF cu o parolă."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Schimbă Permisiunile"
desc = "Schimbați restricțiile și permisiunile documentului"
@@ -994,12 +985,10 @@ title = "Automatizare"
desc = "Construiți fluxuri cu mai mulți pași legând acțiuni PDF. Ideal pentru sarcini recurente."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Suprapune PDF-uri peste alt PDF"
title = "Suprapune PDF-uri"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Editor text PDF"
desc = "Revizuiește și editează exporturile JSON Stirling PDF cu editare de text grupată și regenerare PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Format de ieșire"
pdfaNote = "PDF/A-1b este mai compatibil, PDF/A-2b acceptă mai multe funcții."
pdfaFormat = "Format PDF/A"
pdfaDigitalSignatureWarning = "PDF-ul conține o semnătură digitală. Aceasta va fi eliminată în pasul următor."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF-ul conține o semnătură digitală. Aceasta va fi eliminată în pasul următor."
pdfxDescription = "PDF/X este un subset PDF standardizat ISO pentru tipărire fiabilă și schimb de grafică."
fileFormat = "Format fișier"
@@ -2646,7 +2633,6 @@ label = "PDF original"
[compare.edited]
label = "PDF editat"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Rulați din nou comparația?"
@@ -3567,44 +3553,6 @@ imageSize = "Dimensiunea imaginii"
margin = "Margine"
positionAndFormatting = "Poziție și formatare"
quickPosition = "Selectați o poziție pe pagină pentru a plasa ștampila."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "A apărut o eroare la adăugarea ștampilei în PDF."
@@ -4523,18 +4471,10 @@ description = "Configurați căi personalizate ale sistemului de fișiere pentru
[admin.settings.general.customPaths.pipeline]
label = "Directoare pipeline"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Directorul dosarelor monitorizate"
description = "Directorul în care pipeline-ul monitorizează PDF-urile primite (lăsați gol pentru implicit: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Directorul dosarelor finalizate"
description = "Directorul în care sunt scrise PDF-urile procesate (lăsați gol pentru implicit: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Numărul maxim de încercări eșuate înainte de blocarea contul
label = "Timp resetare autentificare (minute)"
description = "Timpul înainte de resetarea încercărilor eșuate"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Dezactivează protecția CSRF"
description = "Dezactivează protecția Cross-Site Request Forgery (nerecomandat)"
@@ -6573,7 +6506,6 @@ link = "sau conectați-vă la un cont self-hosted"
title = "Conectează-te la server"
subtitle = "Introdu URL-ul serverului tău self-hosted"
testing = "Se testează conexiunea..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"
+1 -69
View File
@@ -219,8 +219,6 @@ pagesAndStarting = "Страницы и начальный номер"
positionAndPages = "Положение и страницы"
preview = "Выбор положения"
previewDisclaimer = "Предпросмотр приблизительный. Итог может отличаться из‑за метрик шрифтов PDF."
zeroPad = "Zeropad Width (Bates Stamping)"
zeroPadTooltip = "Zeropad (Bates Stamp) page numbers to this width (e.g., 3 ⇒ 001). Set 0 to disable."
[addPageNumbers.selectText]
1 = "Выберите PDF-файл:"
@@ -441,9 +439,7 @@ fullscreen = "Полноэкранный"
[settings.general.updates]
title = "Обновления ПО"
description = "Проверка обновлений и сведения о версии"
currentBackendVersion = "Current Backend Version"
currentFrontendVersion = "Current Frontend Version"
versionMismatch = "Warning: A mismatch has been detected between the client version and the AppConfig version. Using different versions can lead to compatibility issues, errors, and security risks. Please ensure that server and client are using the same version."
currentVersion = "Текущая версия"
latestVersion = "Последняя версия"
checkForUpdates = "Проверить обновления"
viewDetails = "Подробнее"
@@ -954,7 +950,6 @@ title = "Авторазбить по размеру/стр."
desc = "Разделяет один PDF на несколько документов на основе размера, количества страниц или количества документов"
[home.replaceColor]
tags = "replace color,invert color,color replacement,swap colors,change color,invert,negative,color swap,find and replace color,convert color,color change"
title = "Заменить и инвертировать цвет"
desc = "Заменяйте или инвертируйте цвета в PDF-документах"
@@ -969,22 +964,18 @@ title = "Автосканирование папок"
desc = "Ссылка на руководство по автоматическому сканированию папок"
[home.devSsoGuide]
tags = "SSO,single sign-on,authentication,SAML,OAuth,OIDC,login,enterprise,identity provider,IdP"
title = "Руководство по SSO"
desc = "Ссылка на руководство по SSO"
[home.devAirgapped]
tags = "air-gapped,offline,isolated,no internet,disconnected,secure,network isolation,standalone"
title = "Изолированная установка"
desc = "Ссылка на руководство по изолированной установке"
[home.addPassword]
tags = "encrypt,password,lock,secure,protect,security,encryption,safeguard,confidential,private,restrict access"
title = "Добавить пароль"
desc = "Зашифруйте ваш PDF-документ паролем."
[home.changePermissions]
tags = "permissions,restrictions,rights,access control,allow,deny,printing,copying,editing,modify permissions,security settings,user rights"
title = "Изменить разрешения"
desc = "Изменение ограничений и разрешений документа"
@@ -994,12 +985,10 @@ title = "Автоматизация"
desc = "Создавайте многошаговые процессы, связывая PDF-действия. Идеально для повторяющихся задач."
[home.overlay-pdfs]
tags = "overlay,combine,merge,layer,superimpose,overlay PDF,layer PDFs,combine PDFs,stack,overlay pages,background,foreground,composite"
desc = "Наложить один PDF поверх другого"
title = "Наложение PDF"
[home.pdfTextEditor]
tags = "edit text,modify text,change text,edit content,update text,rewrite,correct,amend,redline,revise,text editor,content editor"
title = "Редактор текста в PDF"
desc = "Просмотр и редактирование экспортов Stirling PDF в JSON с групповым редактированием текста и регенерацией PDF"
@@ -1302,8 +1291,6 @@ outputFormat = "Выходной формат"
pdfaNote = "PDF/A-1b более совместим, PDF/A-2b поддерживает больше функций."
pdfaFormat = "Формат PDF/A"
pdfaDigitalSignatureWarning = "PDF содержит цифровую подпись. Она будет удалена на следующем шаге."
strictMode = "Strict Mode"
strictModeDesc = "Error if conversion is not perfect (uses VeraPDF verification)"
pdfxDigitalSignatureWarning = "PDF содержит цифровую подпись. Она будет удалена на следующем шаге."
pdfxDescription = "PDF/X — это стандарт ISO, подмножество PDF для надежной печати и обмена графикой."
fileFormat = "Формат файла"
@@ -2646,7 +2633,6 @@ label = "Исходный PDF"
[compare.edited]
label = "Измененный PDF"
placeholder = "Select the edited PDF"
[compare.swap]
confirmTitle = "Выполнить сравнение заново?"
@@ -3567,44 +3553,6 @@ imageSize = "Размер изображения"
margin = "Отступ"
positionAndFormatting = "Положение и форматирование"
quickPosition = "Выберите положение на странице для размещения штампа."
preview = "Preview:"
useTemplate = "Use Template"
selectTemplate = "Select a template..."
stampTextDescription = "Use dynamic variables below. Use @@ for literal @. Use \\n for new lines."
dynamicVariables = "Dynamic Variables"
clickToExpand = "Click to expand"
variablesHelp = "Click on any variable to insert it into your stamp text. Use @@ for literal @."
dateTimeVars = "Date & Time"
dateDesc = "Current date"
timeDesc = "Current time"
datetimeDesc = "Date and time combined"
customDateDesc = "Custom format"
yearMonthDayDesc = "Individual date parts"
pageVars = "Page Information"
pageNumberDesc = "Current page number"
totalPagesDesc = "Total number of pages"
fileVars = "File Information"
filenameDesc = "Filename without extension"
filenameFullDesc = "Filename with extension"
metadataVars = "Document Metadata"
metadataDesc = "From PDF document properties"
otherVars = "Other"
uuidDesc = "Short unique identifier (8 chars)"
examples = "Examples"
multiLine = "multi-line"
[AddStampRequest.template]
pageNumberFooter = "Page Number Footer"
dateHeader = "Date Header"
europeanDate = "European Date"
timestamp = "Timestamp"
draftWatermark = "Draft Watermark"
custom = "Custom"
page-numbers = "Page Numbers"
draft = "Draft Watermark"
doc-info = "Document Info"
legal-footer = "Legal Footer"
european-date = "European Date (DD/MM/YYYY)"
[AddStampRequest.error]
failed = "Произошла ошибка при добавлении штампа в PDF."
@@ -4523,18 +4471,10 @@ description = "Настройте пользовательские пути фа
[admin.settings.general.customPaths.pipeline]
label = "Каталоги конвейера"
[admin.settings.general.customPaths.pipeline.pipelineDir]
label = "Pipeline Directory"
description = "Base directory for pipeline resources (leave empty for default: /pipeline)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDir]
label = "Каталог отслеживаемых папок"
description = "Каталог, где конвейер отслеживает входящие PDF (оставьте пустым по умолчанию: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.watchedFoldersDirs]
label = "Watched Folders Directories"
description = "Directories where pipeline monitors for incoming PDFs (one per line or comma-separated; leave empty for default: /pipeline/watchedFolders)"
[admin.settings.general.customPaths.pipeline.finishedFoldersDir]
label = "Каталог завершенных папок"
description = "Каталог, куда выводятся обработанные PDF (оставьте пустым по умолчанию: /pipeline/finishedFolders)"
@@ -4586,13 +4526,6 @@ description = "Максимальное число неудачных попыт
label = "Время сброса попыток (минуты)"
description = "Время до сброса счетчика неудачных попыток входа"
[admin.settings.security.xFrameOptions]
label = "X-Frame-Options"
description = "Controls whether the application can be embedded in iframes"
deny = "Deny (Prevents all framing)"
sameorigin = "Same Origin (Allow framing from same domain)"
disabled = "Disabled (No X-Frame-Options header)"
[admin.settings.security.csrfDisabled]
label = "Отключить защиту CSRF"
description = "Отключить защиту от межсайтовой подделки запросов (не рекомендуется)"
@@ -6573,7 +6506,6 @@ link = "или подключитесь к самохостируемой учё
title = "Подключение к серверу"
subtitle = "Введите URL своего self-hosted сервера"
testing = "Проверка подключения..."
useLast = "Last used server: {{serverUrl}}"
[setup.server.type]
saas = "Stirling PDF SaaS"

Some files were not shown because too many files have changed in this diff Show More