Repository navigation
Expand file tree
/
Copy pathcheck.html
More file actions
993 lines (977 loc) · 97.6 KB
/
Copy pathcheck.html
File metadata and controls
993 lines (977 loc) · 97.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="theme-color" content="#f6f8f7">
<meta name="description" content="Check installed Sileo packages against stable roothide repository versions.">
<title>Stable Package Consistency Check · roothide</title>
<style>
:root {
color-scheme: light;
--ink: #192821;
--muted: #617068;
--line: #dce3df;
--green: #176345;
--red: #a92333;
--yellow: #865800;
font-family: "Avenir Next", "PingFang SC", "Microsoft YaHei", sans-serif;
color: var(--ink);
background: #f6f8f7;
letter-spacing: 0;
}
* { box-sizing: border-box; }
body { margin: 0; background: linear-gradient(180deg, #edf3ef 0, #f6f8f7 320px); }
button, textarea, input, select { font: inherit; }
button { min-height: 44px; }
button, summary, input[type="checkbox"] { cursor: pointer; }
button:disabled, textarea:disabled, select:disabled { cursor: wait; opacity: .65; }
:focus-visible { outline: 3px solid #268c68; outline-offset: 3px; }
[hidden] { display: none !important; }
a { color: var(--green); text-underline-offset: 3px; }
.wrap { max-width: 880px; margin: 0 auto; padding: 20px 16px 32px; }
.header-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tools { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 8px; margin-top: 6px; font-size: 13px; }
.language-picker { display: flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; font-size: inherit; font-weight: 400; color: var(--muted); }
.language-picker select { width: 124px; max-width: 100%; min-width: 0; min-height: 44px; padding: 0 6px; border: 0; color: var(--muted); background: transparent; font: inherit; cursor: pointer; }
.language-picker span { overflow-wrap: anywhere; }
.brand { display: flex; gap: 8px; align-items: center; min-width: 0; font-size: 15px; font-weight: 600; }
.brand img { width: 28px; height: 28px; border-radius: 6px; }
.brand-copy { min-width: 0; }
h1 { margin: 0; font-size: 15px; line-height: 1.5; font-weight: 600; overflow-wrap: anywhere; }
.intro { margin: 16px 0; color: var(--muted); font-size: 13px; line-height: 1.7; }
#bookmark { display: inline-flex; align-items: center; justify-content: center; gap: 4px; flex: 0 1 auto; min-height: 44px; font: inherit; }
#bookmark img { width: 16px; height: 16px; }
.environment { margin-bottom: 16px; }
#system-version { display: block; width: 100%; min-height: 44px; margin-top: 6px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 6px; background: #fff; color: var(--ink); font-size: 16px; }
.label-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
label, h2, .system-label { font-size: 15px; font-weight: 600; }
.text-button { border: 0; padding: 0 5px; min-height: 32px; background: transparent; color: var(--muted); font-size: 13px; }
.input-actions { display: flex; align-items: center; gap: 20px; flex-shrink: 0; }
.input-actions button { min-height: 44px; }
.input-shell { position: relative; }
textarea { display: block; width: 100%; height: 110px; min-height: 110px; resize: vertical; padding: 10px; border: 1px solid #bac9c0; border-radius: 6px; background: #fff; color: var(--ink); font-size: 13px; line-height: 1.45; }
textarea:focus { font-size: 16px; }
.input-hint { position: absolute; inset: 11px; margin: 0; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; color: #829087; font-size: 13px; font-weight: 400; line-height: 1.45; cursor: text; }
textarea:focus + .input-hint { visibility: hidden; }
.privacy { margin: 8px 0 12px; color: var(--muted); font-size: 12px; line-height: 1.6; }
.primary { width: 100%; padding: 10px 16px; border: 1px solid var(--green); border-radius: 6px; background: var(--green); color: #fff; font-size: 16px; font-weight: 600; }
.primary:not(:disabled):hover { background: #104e35; }
.message { margin: 12px 0; padding: 10px; border-inline-start: 3px solid var(--green); background: #e8f1ec; font-size: 13px; line-height: 1.7; overflow-wrap: anywhere; scroll-margin-top: 16px; }
.message.error { color: var(--red); background: #fceef0; border-color: var(--red); }
#results { margin-top: 26px; scroll-margin-top: 16px; }
h2 { margin: 0; }
.result-meta { margin: 6px 0 12px; color: var(--muted); font-size: 12px; line-height: 1.7; }
.counts { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr) minmax(0, .75fr); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 11px 0; margin-bottom: 12px; }
.count { padding: 0 10px; border-inline-end: 1px solid var(--line); overflow-wrap: anywhere; }
.count:first-child { padding-inline-start: 0; }
.count:last-child { border-inline-end: 0; }
.count strong { display: block; font-size: 25px; line-height: 1.3; font-weight: 650; }
.count span { font-size: 12px; }
.higher { color: var(--red); }
.lower { color: var(--yellow); }
.equal { color: var(--green); }
.filter { display: inline-flex; align-items: center; gap: 7px; min-height: 36px; font-size: 13px; font-weight: 400; margin-bottom: 8px; }
.filter input { width: 18px; height: 18px; margin: 0; accent-color: var(--green); }
table { width: 100%; border-collapse: collapse; table-layout: fixed; text-align: start; }
col:first-child { width: 58%; }
col:last-child { width: 42%; }
th, td { text-align: start; }
thead th { color: var(--muted); background: #eef2ef; font-size: 12px; font-weight: 500; padding: 8px; }
thead th:first-child { border-radius: 4px 0 0 4px; }
thead th:last-child { border-radius: 0 4px 4px 0; }
tbody th, tbody td { padding: 11px 8px; border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; line-height: 1.6; }
tbody th { font-size: 13px; font-weight: 600; }
.package-name { display: block; unicode-bidi: plaintext; }
.package-id { display: block; margin-top: 4px; color: var(--muted); font-size: 10px; font-weight: 400; line-height: 1.5; direction: ltr; unicode-bidi: isolate; }
.status { display: flex; align-items: flex-start; gap: 6px; font-size: 13px; font-weight: 500; line-height: 1.6; }
.status span { min-width: 0; }
.status::before { content: ""; flex: 0 0 6px; width: 6px; height: 6px; margin-top: 7px; border-radius: 50%; background: currentColor; }
tr[data-status="higher"] { background: #fff1f2; }
tr[data-status="lower"] { background: #fff8df; }
.empty { margin: 0; padding: 16px 8px; text-align: center; color: var(--muted); font-size: 13px; }
.caution { margin: 14px 0; color: var(--muted); font-size: 12px; line-height: 1.8; }
details { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 10px; font-size: 12px; line-height: 1.8; }
summary { min-height: 32px; color: var(--muted); }
details ul { padding-inline-start: 20px; margin: 8px 0; overflow-wrap: anywhere; }
footer { margin-top: 26px; padding-top: 12px; border-top: 1px solid var(--line); color: var(--muted); font-size: 11px; line-height: 1.8; }
footer a { white-space: nowrap; }
@media (min-width: 640px) {
.wrap { padding: 29px 32px 38px; }
textarea { height: 130px; min-height: 130px; }
tbody th { font-size: 14px; }
.package-id { font-size: 11px; }
tbody th, tbody td, thead th { padding-left: 12px; padding-right: 12px; }
}
@supports (padding-bottom: env(safe-area-inset-bottom)) {
.wrap { padding-bottom: max(32px, env(safe-area-inset-bottom)); }
}
</style>
</head>
<body>
<main class="wrap">
<header>
<div class="header-row">
<div class="brand"><img src="https://github.com/roothide.png?size=64" alt="" width="28" height="28"><div class="brand-copy"><h1 data-i18n="title">Stable Package Consistency Check</h1></div></div>
</div>
<div class="tools">
<label class="language-picker"><span data-i18n="language">Language</span><select id="language" dir="ltr" aria-label="Language">
<option value="en" lang="en">English</option>
<option value="ja" lang="ja">日本語</option>
<option value="ko" lang="ko">한국어</option>
<option value="hi" lang="hi">हिन्दी</option>
<option value="id" lang="id">Bahasa Indonesia</option>
<option value="th" lang="th">ไทย</option>
<option value="vi" lang="vi">Tiếng Việt</option>
<option value="ar" lang="ar">العربية</option>
<option value="fa" lang="fa">فارسی</option>
<option value="he" lang="he">עברית</option>
<option value="tr" lang="tr">Türkçe</option>
<option value="ur" lang="ur">اردو</option>
<option value="zh-TW" lang="zh-TW">繁體中文</option>
<option value="zh-CN" lang="zh-CN">简体中文</option>
</select></label>
<button id="bookmark" class="text-button" type="button" aria-haspopup="dialog"><img src="https://cdn.jsdelivr.net/npm/lucide-static@0.468.0/icons/bookmark-plus.svg" alt="" width="16" height="16"><span data-i18n="bookmark">Bookmark</span></button>
</div>
<p class="intro" data-i18n="intro">Some private builds may modify stable package versions and prevent update notifications from the roothide repository. Use this page to investigate potential jailbreak faults or instability.</p>
</header>
<p id="message" class="message" role="status" aria-live="polite" tabindex="-1" hidden></p>
<form id="check-form" novalidate>
<div class="environment">
<label for="system-version" data-i18n="system">System</label>
<select id="system-version" required>
<option value="" data-i18n="unknownSystem" selected>Select your system version</option>
<option value="15">iOS 15 / iPadOS 15</option>
<option value="16">iOS 16 / iPadOS 16</option>
<option value="17">iOS 17 / iPadOS 17</option>
<option value="18">iOS 18 / iPadOS 18</option>
<option value="26">iOS 26 / iPadOS 26</option>
<option value="27">iOS 27 / iPadOS 27</option>
</select>
</div>
<div class="label-row"><label for="installed" data-i18n="installedList">Installed Sileo packages</label><div class="input-actions"><button id="paste" class="text-button" type="button" data-i18n="paste">Paste</button><button id="clear" class="text-button" type="button" data-i18n="clear">Clear</button></div></div>
<div class="input-shell">
<textarea id="installed" required dir="auto" spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off" aria-describedby="installed-hint privacy"></textarea>
<label id="installed-hint" class="input-hint" for="installed" data-i18n="placeholder">Export from Sileo: 1. Open Sileo and go to Installed. 2. Tap the export/share button at the top right. 3. Choose Copy in the share sheet. 4. Return here and paste the full list.</label>
</div>
<p id="privacy" class="privacy" data-i18n="privacy">Your list is processed in this browser only. It is not uploaded or saved.</p>
<button id="check" class="primary" type="submit" data-i18n="check">Start check</button>
</form>
<section id="results" aria-labelledby="results-title" tabindex="-1" hidden>
<h2 id="results-title" data-i18n="results">Results</h2>
<p id="result-meta" class="result-meta"></p>
<div class="counts">
<div class="count higher"><strong id="higher-count">0</strong><span data-i18n="higher">Mismatch</span></div>
<div class="count lower"><strong id="lower-count">0</strong><span data-i18n="lower">Outdated</span></div>
<div class="count equal"><strong id="equal-count">0</strong><span data-i18n="equal">Matching</span></div>
</div>
<label class="filter"><input id="different-only" type="checkbox"><span data-i18n="differentOnly">Only show version differences</span></label>
<table>
<colgroup><col><col></colgroup>
<thead><tr><th scope="col" data-i18n="package">Package</th><th scope="col" data-i18n="status">Status</th></tr></thead>
<tbody id="result-rows"></tbody>
</table>
<p id="empty-results" class="empty" data-i18n="emptyResults" hidden>No packages to display.</p>
<p id="higher-note" class="caution" data-i18n="caution" hidden>A higher installed version may suppress this repo's update notifications, but does not prove modification. Verify the source and select this repo's version in Sileo. Do not bulk-downgrade system dependencies.</p>
<details id="skipped-details" hidden><summary id="skipped-summary"></summary><ul id="skipped-list"></ul></details>
<details id="invalid-details" hidden><summary id="invalid-summary"></summary><ul id="invalid-list"></ul></details>
</section>
<footer><span data-i18n="versionOrder">Version order follows</span> <a href="https://www.debian.org/doc/debian-policy/ch-controlfields.html#version" target="_blank" rel="noopener noreferrer">Debian Policy</a> · <a href="https://github.com/roothide/roothide.github.io" data-i18n="mainIndex">Main index</a> · <a id="dist-link" href="https://github.com/roothide/roothide.github.io/tree/main/procursus" data-i18n="distIndex">Procursus index</a></footer>
<noscript><p class="message error">JavaScript is required to check versions.</p></noscript>
</main>
<script>
const ENGLISH = {
title: "Stable Package Consistency Check", language: "Language", bookmark: "Bookmark",
intro: "Some private builds may modify stable package versions and prevent update notifications from the roothide repository. Use this page to investigate potential jailbreak faults or instability.",
system: "System", installedList: "Installed Sileo packages", clear: "Clear",
paste: "Paste", pasteFallback: "Clipboard access is unavailable. Touch and hold inside the input box, then choose Paste.", clipboardEmpty: "The clipboard contains no text. Copy the package list from Sileo first.",
placeholder: "Export from Sileo:\n1. Open Sileo and go to Installed.\n2. Tap the export/share button at the top right.\n3. Choose Copy in the share sheet.\n4. Return here and paste the full list.",
privacy: "Your list is processed in this browser only. It is not uploaded or saved.", check: "Start check", results: "Results",
higher: "Mismatch", lower: "Outdated", equal: "Matching", differentOnly: "Only show version differences",
package: "Package", status: "Status", emptyResults: "No packages to display.",
caution: "A higher installed version may suppress this repo's update notifications, but does not prove modification. Verify the source and select this repo's version in Sileo. Do not bulk-downgrade system dependencies.",
versionOrder: "Version order follows", mainIndex: "Main index", distIndex: "Procursus index", main: "Main repo",
unsupported: "Not supported", unknownSystem: "Select your system version",
systemError: "Select your device's iOS / iPadOS version before starting the check.",
bookmarkMobile: "In Safari, tap Share, then Add to Favorites or Add Bookmark. In other browsers, open the menu and choose bookmarks or favorites.",
bookmarkDesktop: "Use your browser's Add Bookmark / Favorites menu, or press {shortcut}+D.",
badVersion: "Invalid Debian version", badFormat: "Unrecognized line format", missingFields: "{source}: index is missing Package or Version fields.",
badIndex: "{source}: invalid Packages index.", emptyIndex: "{source}: no packages available for checking.",
downloadError: "Index download failed: {path} ({reason}). Check your network connection and select Start check to retry.", timeout: "Request timed out", network: "Network error",
emptyInput: "Paste the installed package list exported from Sileo.", conflicts: "Multiple installed versions found for the same package. Correct the list and retry: {ids}",
noValid: "No valid packages found; {count} lines could not be read. Expected format: Name:(package.id) version.",
localFile: "Your browser cannot read repository indices from a local file. Open this page over HTTP / HTTPS.",
checking: "Checking…", downloading: "Downloading indices…", waiting: "Downloading the main and dist {dist} indices. Please wait; checking will continue automatically…",
report: "dist {dist} · {installed} installed · {compared} checked · {date}", skippedSummary: "Not checked: {count} packages", invalidSummary: "Incomplete: {count} unreadable lines",
skippedItem: "{name} ({id}) {version}: not in the main allowlist or selected dist index.", invalidItem: "Line {line} · {reason}: {text}",
noMatch: "No packages matched the check scope. Verify the list and system version; this does not mean everything is up to date.",
partial: "Valid entries checked, but {count} lines could not be read. See the details below.", complete: "Check complete: {count} packages compared; {skipped} outside the check scope.",
unexpected: "The check could not be completed. Please retry."
};
const TRANSLATIONS = { en: ENGLISH };
let language = "en";
function resolveLanguage(preferences = []) {
for (const preference of preferences) {
const locale = String(preference).replace(/_/g, "-").toLowerCase();
const exact = Object.keys(TRANSLATIONS).find(key => key.toLowerCase() === locale);
if (exact) return exact;
const base = locale.split("-")[0];
if (base === "zh") {
const traditional = /(?:^|-)(?:hant|tw|hk|mo)(?:-|$)/.test(locale);
const chinese = traditional ? "zh-TW" : "zh-CN";
if (TRANSLATIONS[chinese]) return chinese;
}
if (TRANSLATIONS[base]) return base;
}
return "en";
}
function distForVersion(value) {
const major = Number(value);
if (![15, 16, 17, 18, 26, 27].includes(major)) return "";
return major === 15 ? "1800" : "1900";
}
function t(key, values = {}) {
return (TRANSLATIONS[language]?.[key] ?? ENGLISH[key] ?? key).replace(/\{(\w+)\}/g, (_, name) => {
if (name === "source") return sourceLabel(values.source);
if (name === "reason" && values.reasonKey && !values.reason) return t(values.reasonKey);
return String(values[name] ?? "");
});
}
function sourceLabel(source) { return source === "main" ? t("main") : `dist ${source}`; }
function localizedError(key, values = {}) {
const error = new Error(key);
error.key = key;
error.values = values;
return error;
}
const BUILTIN_PACKAGES = new Set([
"com.opa334.choicy",
"com.opa334.libsandy",
"com.opa334.libundirect",
"roothide.patches.filza",
"com.tigisoftware.filza64bit",
"rootless-compat",
"com.roothide.manager",
"com.roothide.patcher",
"com.roothide.patchloader",
"ellekit",
"oldabi",
"oldabi-stub",
"preferenceloader",
"ws.hbang.common",
"org.coolstar.sileo",
].map(id => id.toLowerCase()));
function compareDigits(left, right) {
left = left.replace(/^0+/, "") || "0";
right = right.replace(/^0+/, "") || "0";
if (left.length !== right.length) return left.length < right.length ? -1 : 1;
return left === right ? 0 : left < right ? -1 : 1;
}
function splitVersion(version) {
let epoch = "0";
let upstream = version;
const colon = upstream.indexOf(":");
if (colon !== -1) {
epoch = upstream.slice(0, colon);
upstream = upstream.slice(colon + 1);
if (!/^\d+$/.test(epoch)) throw localizedError("badVersion");
}
let revision = "0";
const dash = upstream.lastIndexOf("-");
if (dash !== -1) {
revision = upstream.slice(dash + 1);
upstream = upstream.slice(0, dash);
if (!/^[A-Za-z0-9+.~]+$/.test(revision)) throw localizedError("badVersion");
}
if (!/^[0-9][A-Za-z0-9.+:~\-]*$/.test(upstream)) throw localizedError("badVersion");
return { epoch, upstream, revision };
}
function compareVersionPart(left, right) {
let leftIndex = 0;
let rightIndex = 0;
const isDigit = character => character >= "0" && character <= "9";
const order = character => {
if (character === "~") return -1;
if (!character || isDigit(character)) return 0;
const code = character.charCodeAt(0);
return /[A-Za-z]/.test(character) ? code : code + 256;
};
while (leftIndex < left.length || rightIndex < right.length) {
while ((left[leftIndex] && !isDigit(left[leftIndex])) || (right[rightIndex] && !isDigit(right[rightIndex]))) {
const difference = order(left[leftIndex]) - order(right[rightIndex]);
if (difference) return difference < 0 ? -1 : 1;
leftIndex++;
rightIndex++;
}
while (left[leftIndex] === "0") leftIndex++;
while (right[rightIndex] === "0") rightIndex++;
let firstDifference = 0;
while (isDigit(left[leftIndex]) && isDigit(right[rightIndex])) {
if (!firstDifference) firstDifference = left.charCodeAt(leftIndex) - right.charCodeAt(rightIndex);
leftIndex++;
rightIndex++;
}
if (isDigit(left[leftIndex])) return 1;
if (isDigit(right[rightIndex])) return -1;
if (firstDifference) return firstDifference < 0 ? -1 : 1;
}
return 0;
}
function compareVersions(left, right) {
const first = splitVersion(left);
const second = splitVersion(right);
return compareDigits(first.epoch, second.epoch)
|| compareVersionPart(first.upstream, second.upstream)
|| compareVersionPart(first.revision, second.revision);
}
// Automatic detection is disabled because browser version strings may be modified.
// function detectSystem(userAgent, maxTouchPoints = 0, supports = null) {
// const isIPad = /iPad/i.test(userAgent);
// const isDesktopIOS = /Macintosh/i.test(userAgent) && maxTouchPoints > 1;
// const match = userAgent.match(/(?:CPU(?: iPhone)? OS|iPhone OS)\s+(\d+)(?:[_.](\d+))?(?:[_.](\d+))?/i);
// if (match) {
// const major = Number(match[1]);
// const version = match.slice(1).filter(Boolean).join(".");
// const dist = major === 15 ? "1800" : major >= 16 ? "1900" : "";
// return { dist, system: isIPad ? "iPadOS" : "iOS", version };
// }
// const safari = userAgent.match(/Version\/(\d+)(?:\.\d+)*/i);
// if ((isIPad || isDesktopIOS) && safari && /Safari\//i.test(userAgent) && !/(?:CriOS|FxiOS|EdgiOS|OPiOS|Chrome|Chromium|Edg)\//i.test(userAgent)) {
// const major = Number(safari[1]);
// const dist = major === 15 ? "1800" : major >= 16 ? "1900" : "";
// return { dist, system: isIPad ? "iPadOS" : "iOS/iPadOS", method: "safariInferred", major };
// }
// if ((isIPad || isDesktopIOS) && /AppleWebKit\//i.test(userAgent) && /(?:CriOS|Chrome|Chromium)\//i.test(userAgent) && !/Android/i.test(userAgent) && supports) {
// const dist = supports("container-type", "inline-size") ? "1900" : supports("aspect-ratio", "1 / 1") ? "1800" : "";
// if (dist) return { dist, system: isIPad ? "iPadOS" : "iOS/iPadOS", method: "webkitInferred" };
// }
// return { dist: "" };
// }
function parseExport(text) {
const installed = new Map();
const invalid = [];
const conflicts = new Set();
text.replace(/^\uFEFF/, "").split(/\r\n|\n|\r/).forEach((raw, index) => {
const line = raw.trim();
if (!line) return;
const match = line.match(/^(.+):\s*\(([a-z0-9][a-z0-9+.\-]*)\)\s+(\S+)$/i);
if (!match) { invalid.push({ line: index + 1, text: line, reasonKey: "badFormat" }); return; }
const [, name, identifier, version] = match;
try { splitVersion(version); }
catch { invalid.push({ line: index + 1, text: line, reasonKey: "badVersion" }); return; }
const id = identifier.toLowerCase();
if (installed.has(id) && installed.get(id).version !== version) conflicts.add(id);
installed.set(id, { id, name: name.trim(), version });
});
return { installed, invalid, conflicts: [...conflicts] };
}
function parseIndex(text, source, allowlist) {
const packages = new Map();
let fields = {};
let lastKey = "";
const flush = () => {
if (!Object.keys(fields).length) return;
if (!fields.package || !fields.version) throw localizedError("missingFields", { source });
const id = fields.package.toLowerCase();
const version = fields.version;
splitVersion(version);
if ((!allowlist || allowlist.has(id)) && (!packages.has(id) || compareVersions(version, packages.get(id).version) > 0)) {
packages.set(id, { id, version, name: fields.name || fields.package, source });
}
fields = {};
lastKey = "";
};
for (const line of text.replace(/^\uFEFF/, "").split(/\r\n|\n|\r/)) {
if (!line.trim()) { flush(); continue; }
if (/^[ \t]/.test(line) && lastKey) { fields[lastKey] += ` ${line.trim()}`; continue; }
const match = line.match(/^([A-Za-z0-9-]+):\s*(.*)$/);
if (!match) throw localizedError("badIndex", { source });
lastKey = match[1].toLowerCase();
fields[lastKey] = match[2].trim();
}
flush();
if (!packages.size) throw localizedError("emptyIndex", { source });
return packages;
}
function compareInstalled(installed, catalog) {
const rows = [];
const skipped = [];
for (const entry of installed.values()) {
const latest = catalog.get(entry.id);
if (!latest) { skipped.push(entry); continue; }
const comparison = compareVersions(entry.version, latest.version);
rows.push({ ...entry, latest: latest.version, source: latest.source, status: comparison > 0 ? "higher" : comparison < 0 ? "lower" : "equal" });
}
const priority = { higher: 0, lower: 1, equal: 2 };
rows.sort((left, right) => priority[left.status] - priority[right.status] || left.id.localeCompare(right.id));
return { rows, skipped };
}
async function fetchIndex(path) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 20000);
try {
const response = await fetch(path, { cache: "no-store", signal: controller.signal });
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.text();
} catch (error) {
throw localizedError("downloadError", { path, reasonKey: error.name === "AbortError" ? "timeout" : "network", reason: error.message.startsWith("HTTP ") ? error.message : undefined });
} finally { clearTimeout(timer); }
}
document.addEventListener("DOMContentLoaded", () => {
Object.assign(TRANSLATIONS, typeof CHECK_LOCALES === "undefined" ? {} : CHECK_LOCALES);
const byId = id => document.getElementById(id);
const form = byId("check-form");
const input = byId("installed");
const inputHint = byId("installed-hint");
const pasteButton = byId("paste");
const button = byId("check");
const message = byId("message");
const results = byId("results");
const systemVersion = byId("system-version");
systemVersion.value = "";
let currentRows = [];
let currentMessage = null;
let lastReport = null;
const indexCache = new Map();
const catalogCache = new Map();
const catalogTasks = new Map();
const loadIndex = (indexPath, source, allowlist) => {
if (!indexCache.has(indexPath)) {
const task = fetchIndex(indexPath)
.then(text => parseIndex(text, source, allowlist))
.catch(error => { indexCache.delete(indexPath); throw error; });
indexCache.set(indexPath, task);
}
return indexCache.get(indexPath);
};
const loadCatalog = selectedDist => {
if (catalogCache.has(selectedDist)) return Promise.resolve(catalogCache.get(selectedDist));
if (!catalogTasks.has(selectedDist)) {
const path = `./procursus/dists/iphoneos-arm64e/${selectedDist}/main/binary-iphoneos-arm64e/Packages`;
const task = Promise.all([
loadIndex("./Packages", "main", BUILTIN_PACKAGES),
loadIndex(path, selectedDist)
]).then(([mainCatalog, distCatalog]) => {
const catalog = new Map(distCatalog);
for (const [id, entry] of mainCatalog) catalog.set(id, entry);
catalogCache.set(selectedDist, catalog);
return catalog;
}).finally(() => { catalogTasks.delete(selectedDist); });
catalogTasks.set(selectedDist, task);
}
return catalogTasks.get(selectedDist);
};
byId("bookmark").addEventListener("click", () => {
input.blur();
const isAppleMobile = /iPhone|iPad|iPod/i.test(navigator.userAgent) || (/Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints > 1);
alert(t(isAppleMobile ? "bookmarkMobile" : "bookmarkDesktop", { shortcut: /Macintosh/i.test(navigator.userAgent) ? "Command" : "Ctrl" }));
});
const showMessage = (key, error = false, values = {}) => {
currentMessage = { key, error, values };
message.textContent = t(key, values);
message.classList.toggle("error", error);
message.hidden = false;
if (error) {
input.blur();
message.focus({ preventScroll: true });
message.scrollIntoView({ block: "center" });
}
};
const invalidate = () => {
results.hidden = true;
message.hidden = true;
currentMessage = null;
};
const syncInput = () => { inputHint.hidden = Boolean(input.value); };
systemVersion.addEventListener("change", () => {
invalidate();
currentRows = [];
lastReport = null;
const selectedDist = distForVersion(systemVersion.value);
if (selectedDist && location.protocol !== "file:") loadCatalog(selectedDist).catch(() => {});
});
input.addEventListener("input", () => { syncInput(); invalidate(); });
byId("clear").addEventListener("click", () => { input.value = ""; syncInput(); invalidate(); input.focus(); });
pasteButton.addEventListener("click", async () => {
if (pasteButton.disabled || input.disabled) return;
pasteButton.disabled = true;
try {
if (!navigator.clipboard?.readText) throw new Error("Clipboard unavailable");
const text = await navigator.clipboard.readText();
if (input.disabled) return;
if (!text) { showMessage("clipboardEmpty", true); return; }
input.value = text;
syncInput();
invalidate();
input.focus();
} catch {
showMessage("pasteFallback", true);
} finally {
pasteButton.disabled = input.disabled;
}
});
const renderRows = () => {
const fragment = document.createDocumentFragment();
for (const row of currentRows) {
if (byId("different-only").checked && row.status === "equal") continue;
const tr = document.createElement("tr");
tr.dataset.status = row.status;
const nameCell = document.createElement("th");
nameCell.scope = "row";
const name = document.createElement("span");
name.className = "package-name";
name.dir = "auto";
name.textContent = row.name;
const identifier = document.createElement("span");
identifier.className = "package-id";
identifier.textContent = row.id;
const status = document.createElement("span");
status.className = `status ${row.status}`;
const statusText = document.createElement("span");
statusText.textContent = t(row.status);
status.append(statusText);
nameCell.append(name, identifier);
const statusCell = document.createElement("td");
statusCell.append(status);
tr.append(nameCell, statusCell);
fragment.append(tr);
}
byId("empty-results").hidden = Boolean(fragment.childNodes.length);
byId("result-rows").replaceChildren(fragment);
};
byId("different-only").addEventListener("change", renderRows);
const renderDetails = (prefix, items, title, format) => {
byId(`${prefix}-details`).hidden = !items.length;
byId(`${prefix}-details`).open = prefix === "invalid" && Boolean(items.length);
byId(`${prefix}-summary`).textContent = title;
byId(`${prefix}-list`).replaceChildren(...items.map(item => {
const element = document.createElement("li");
element.textContent = format(item);
return element;
}));
};
const renderReport = () => {
if (!lastReport) return;
const { parsed, skipped, date, selectedDist } = lastReport;
byId("result-meta").textContent = t("report", { dist: selectedDist, installed: parsed.installed.size, compared: currentRows.length, date: date.toLocaleString(language) });
renderRows();
renderDetails("skipped", skipped, t("skippedSummary", { count: skipped.length }), item => t("skippedItem", item));
renderDetails("invalid", parsed.invalid, t("invalidSummary", { count: parsed.invalid.length }), item => t("invalidItem", item));
};
const applyLanguage = value => {
language = Object.prototype.hasOwnProperty.call(TRANSLATIONS, value) ? value : "en";
document.documentElement.lang = language;
document.documentElement.dir = ["ar", "fa", "he", "ur"].includes(language) ? "rtl" : "ltr";
document.title = `${t("title")} · roothide`;
document.querySelector('meta[name="description"]').content = t("intro");
document.querySelectorAll("[data-i18n]").forEach(element => { element.textContent = t(element.dataset.i18n); });
byId("language").value = language;
byId("language").setAttribute("aria-label", t("language"));
syncInput();
if (button.disabled) button.textContent = t(catalogCache.has(distForVersion(systemVersion.value)) ? "checking" : "downloading");
if (currentMessage) message.textContent = t(currentMessage.key, currentMessage.values);
renderReport();
};
byId("language").addEventListener("change", event => applyLanguage(event.target.value));
applyLanguage(resolveLanguage(navigator.languages?.length ? navigator.languages : [navigator.language || "en"]));
form.addEventListener("submit", async event => {
event.preventDefault();
if (button.disabled) return;
invalidate();
input.blur();
const selectedDist = distForVersion(systemVersion.value);
if (!selectedDist) { showMessage("systemError", true); return; }
if (!input.value.trim()) { showMessage("emptyInput", true); return; }
const parsed = parseExport(input.value);
if (parsed.conflicts.length) { showMessage("conflicts", true, { ids: parsed.conflicts.join(", ") }); return; }
if (!parsed.installed.size) { showMessage("noValid", true, { count: parsed.invalid.length }); return; }
if (location.protocol === "file:") { showMessage("localFile", true); return; }
button.disabled = true;
input.disabled = true;
systemVersion.disabled = true;
byId("clear").disabled = true;
pasteButton.disabled = true;
button.textContent = t(catalogCache.has(selectedDist) ? "checking" : "downloading");
results.setAttribute("aria-busy", "true");
if (!catalogCache.has(selectedDist)) {
showMessage("waiting", false, { dist: selectedDist });
message.scrollIntoView({ block: "center" });
}
try {
const catalog = await loadCatalog(selectedDist);
const { rows, skipped } = compareInstalled(parsed.installed, catalog);
currentRows = rows;
const counts = { higher: 0, lower: 0, equal: 0 };
rows.forEach(row => counts[row.status]++);
Object.entries(counts).forEach(([status, count]) => { byId(`${status}-count`).textContent = count; });
byId("higher-note").hidden = !counts.higher;
byId("different-only").checked = false;
lastReport = { parsed, skipped, date: new Date(), selectedDist };
renderReport();
results.hidden = false;
if (!rows.length) showMessage("noMatch", true);
else if (parsed.invalid.length) showMessage("partial", true, { count: parsed.invalid.length });
else showMessage("complete", false, { count: rows.length, skipped: skipped.length });
if (rows.length) {
results.focus({ preventScroll: true });
results.scrollIntoView({ block: "start" });
}
} catch (error) {
showMessage(error.key || "unexpected", true, error.values);
} finally {
button.disabled = false;
input.disabled = false;
systemVersion.disabled = false;
byId("clear").disabled = false;
pasteButton.disabled = false;
button.textContent = t("check");
results.removeAttribute("aria-busy");
}
});
if (location.protocol !== "file:") loadIndex("./Packages", "main", BUILTIN_PACKAGES).catch(() => {});
});
</script>
<script>
const CHECK_LOCALES = {
"zh-TW": {
title: "穩定套件版本一致性檢查", language: "語言", bookmark: "加入收藏",
intro: "部分私人建置可能會修改穩定套件的版本號,使你無法收到來自roothide套件庫的更新通知。若越獄出現潛在故障或不穩定,請使用本頁排查。",
system: "目前系統", installedList: "Sileo 已安裝套件清單", clear: "清除",
paste: "貼上", pasteFallback: "瀏覽器無法讀取剪貼簿。請在輸入框內長按,再選擇「貼上」。", clipboardEmpty: "剪貼簿中沒有文字,請先從 Sileo 複製套件清單。",
placeholder: "從 Sileo 匯出已安裝套件清單:\n1. 開啟 Sileo,進入「已安裝」。\n2. 點選右上角的匯出/分享按鈕。\n3. 在分享選單中選擇「拷貝」。\n4. 回到本頁,在此貼上完整清單。",
privacy: "清單僅在此瀏覽器中處理,不會上傳或儲存。", check: "開始檢查", results: "檢查結果",
higher: "不一致", lower: "版本過舊", equal: "版本一致", differentOnly: "僅顯示版本不一致的套件",
package: "套件", status: "狀態", emptyResults: "沒有要顯示的套件。",
caution: "高於本源的版本可能使 Sileo 無法提示更新,但不能僅憑版本號斷定套件遭修改。請核對來源,並在 Sileo 選擇本源版本;請勿批次降級系統相依套件。",
versionOrder: "版本順序遵循", mainIndex: "主套件庫索引", distIndex: "Procursus 索引", main: "主套件庫",
unsupported: "不支援", unknownSystem: "請選擇系統版本",
systemError: "請先選擇裝置的 iOS / iPadOS 版本,再開始檢查。",
bookmarkMobile: "在 Safari 點選分享按鈕,再選擇「加入喜好項目」或「加入書籤」。其他瀏覽器請開啟選單,選擇收藏或書籤。",
bookmarkDesktop: "請使用瀏覽器選單中的「加入書籤 / 收藏」,也可按 {shortcut}+D。",
badVersion: "無效的 Debian 版本號", badFormat: "無法識別格式", missingFields: "{source} 索引缺少 Package 或 Version 欄位。",
badIndex: "{source} 不是有效的 Packages 索引。", emptyIndex: "{source} 索引中沒有可檢查的套件。",
downloadError: "索引下載失敗:{path}({reason})。請檢查網路連線,再次點選「開始檢查」重試。", timeout: "請求逾時", network: "網路錯誤",
emptyInput: "請貼上 Sileo 匯出的已安裝套件清單。", conflicts: "同一套件出現多個已安裝版本,請核對後重試:{ids}",
noValid: "找不到有效套件;{count} 行無法解析。預期格式:名稱:(套件ID) 版本號。", localFile: "瀏覽器無法從本機檔案讀取索引,請透過 HTTP / HTTPS 開啟本頁。",
checking: "檢查中…", downloading: "正在下載索引…", waiting: "正在下載主套件庫與 dist {dist} 的索引,請稍候,完成後將自動繼續檢查…",
report: "dist {dist} · 已安裝 {installed} 個 · 已比對 {compared} 個 · {date}", skippedSummary: "未納入檢查:{count} 個套件", invalidSummary: "未完成:{count} 行無法解析",
skippedItem: "{name} ({id}) {version}:不在主套件庫內建清單或所選 dist 索引中。", invalidItem: "第 {line} 行 · {reason}:{text}",
noMatch: "找不到符合範圍的套件。請核對清單與系統版本;這不表示所有套件都是最新版本。", partial: "已比對有效項目,但 {count} 行無法解析,請查看下方詳細資訊。",
complete: "檢查完成:已比對 {count} 個套件,{skipped} 個不在檢查範圍內。", unexpected: "無法完成檢查,請重試。"
},
"zh-CN": {
title: "稳定包版本一致性检查", language: "语言", bookmark: "添加到收藏夹",
intro: "一些私有构建可能会修改稳定包的版本号,并且你可能无法获得来自roothide仓库的包更新通知,如果越狱出现潜在故障/不稳定请使用本页面进行排查。",
system: "当前系统", installedList: "Sileo 已安装包列表", clear: "清空",
paste: "粘贴", pasteFallback: "浏览器无法读取剪贴板。请在输入框内长按,再选择「粘贴」。", clipboardEmpty: "剪贴板中没有文本,请先从 Sileo 复制包列表。",
placeholder: "从 Sileo 导出已安装包列表:\n1. 打开 Sileo,进入「已安装」。\n2. 点击右上角的导出/分享按钮。\n3. 在分享菜单中选择「拷贝」。\n4. 回到此页面,在这里粘贴完整列表。",
privacy: "列表仅在此浏览器中处理,不会上传或保存。", check: "开始检测", results: "检测结果",
higher: "不一致", lower: "版本过低", equal: "版本一致", differentOnly: "仅显示版本不一致的包",
package: "软件包", status: "状态", emptyResults: "没有需要显示的软件包。",
caution: "高于本源的版本可能使 Sileo 无法提示本源更新,但不能仅凭版本号断定包已被魔改。请核对来源,并在 Sileo 中选择本源版本;不要批量降级系统依赖。",
versionOrder: "版本顺序遵循", mainIndex: "主仓库索引", distIndex: "Procursus 索引", main: "主仓库",
unsupported: "不支持", unknownSystem: "请选择系统版本",
systemError: "请先选择设备的 iOS / iPadOS 版本,再开始检测。",
bookmarkMobile: "在 Safari 中点击分享按钮,再选择「添加到个人收藏」或「添加书签」。其他浏览器请打开菜单,选择收藏或书签。",
bookmarkDesktop: "请使用浏览器菜单中的「添加书签 / 收藏此页」,也可按 {shortcut}+D。",
badVersion: "无效的 Debian 版本号", badFormat: "格式无法识别", missingFields: "{source} 索引缺少 Package 或 Version 字段。",
badIndex: "{source} 不是有效的 Packages 索引。", emptyIndex: "{source} 索引中没有可检测的软件包。",
downloadError: "索引下载失败:{path}({reason})。请检查网络连接,再次点击「开始检测」重试。", timeout: "请求超时", network: "网络错误",
emptyInput: "请粘贴 Sileo 导出的已安装包列表。", conflicts: "同一包出现多个已安装版本,请核对后重试:{ids}",
noValid: "未识别到有效软件包,{count} 行无法解析。预期格式:名称:(包ID) 版本号。", localFile: "浏览器无法从本地文件读取索引,请通过 HTTP / HTTPS 地址打开此页。",
checking: "正在检测…", downloading: "正在下载索引…", waiting: "正在下载主仓库与 dist {dist} 的索引,请稍候,完成后将自动继续检测…",
report: "dist {dist} · 已识别 {installed} 个已安装包 · 已比对 {compared} 个 · {date}", skippedSummary: "未纳入检测:{count} 个包", invalidSummary: "未完成检测:{count} 行无法解析",
skippedItem: "{name} ({id}) {version}:不在主仓库内置名单或所选 dist 索引中。", invalidItem: "第 {line} 行 · {reason}:{text}",
noMatch: "没有匹配到待检包,请核对列表和系统版本;这不表示所有包都已是最新版本。", partial: "已比对有效条目,但 {count} 行无法解析,请查看下方详情。",
complete: "检测完成:已比对 {count} 个包,{skipped} 个包不在检测范围内。", unexpected: "无法完成检测,请重试。"
},
ja: {
title: "安定版パッケージの整合性チェック", language: "言語", bookmark: "ブックマーク",
intro: "一部の非公開ビルドは安定版パッケージのバージョン番号を変更し、roothide リポジトリからの更新通知を妨げることがあります。脱獄環境の不具合や不安定さの調査にこのページをご利用ください。",
system: "システム", installedList: "Sileo のインストール済みパッケージ", clear: "消去",
paste: "貼り付け", pasteFallback: "クリップボードを読み取れません。入力欄を長押しして「ペースト」を選んでください。", clipboardEmpty: "クリップボードにテキストがありません。先に Sileo の一覧をコピーしてください。",
placeholder: "Sileo から一覧をエクスポート:\n1. Sileo の「インストール済み」を開きます。\n2. 右上のエクスポート/共有ボタンをタップします。\n3. 共有メニューで「コピー」を選びます。\n4. このページに戻り、一覧全体を貼り付けます。",
privacy: "一覧はこのブラウザ内でのみ処理され、送信・保存されません。", check: "チェック開始", results: "チェック結果",
higher: "不一致", lower: "古いバージョン", equal: "一致", differentOnly: "バージョンが異なるものだけ表示",
package: "パッケージ", status: "状態", emptyResults: "表示するパッケージはありません。",
caution: "インストール済みのバージョンが高いと更新通知が届かない場合がありますが、改変の証拠ではありません。配布元を確認し、Sileo で本リポジトリのバージョンを選んでください。システム依存パッケージを一括でダウングレードしないでください。",
versionOrder: "バージョン順序の規則:", mainIndex: "メイン索引", distIndex: "Procursus 索引", main: "メインリポジトリ",
unsupported: "未対応", unknownSystem: "システムのバージョンを選択",
systemError: "チェックを始める前に、端末の iOS / iPadOS バージョンを選択してください。",
bookmarkMobile: "Safari の共有ボタンから「お気に入りに追加」または「ブックマークを追加」を選んでください。他のブラウザではメニューのブックマーク機能をご利用ください。",
bookmarkDesktop: "ブラウザのブックマーク追加メニュー、または {shortcut}+D をご利用ください。",
badVersion: "無効な Debian バージョン", badFormat: "認識できない形式", missingFields: "{source}:索引に Package または Version がありません。",
badIndex: "{source}:無効な Packages 索引です。", emptyIndex: "{source}:チェック可能なパッケージがありません。",
downloadError: "索引のダウンロードに失敗:{path}({reason})。ネットワークを確認し、「チェック開始」で再試行してください。", timeout: "タイムアウト", network: "ネットワークエラー",
emptyInput: "Sileo からエクスポートした一覧を貼り付けてください。", conflicts: "同じパッケージに複数のバージョンがあります。修正してください:{ids}",
noValid: "有効なパッケージがありません。{count} 行を読み取れませんでした。形式:名前:(package.id) バージョン。", localFile: "ローカルファイルから索引を読めません。HTTP / HTTPS でこのページを開いてください。",
checking: "チェック中…", downloading: "索引をダウンロード中…", waiting: "メインと dist {dist} の索引をダウンロード中です。完了後、自動的にチェックを続行します…",
report: "dist {dist} · インストール済み {installed} · 比較済み {compared} · {date}", skippedSummary: "対象外:{count} パッケージ", invalidSummary: "未完了:{count} 行を読めません",
skippedItem: "{name} ({id}) {version}:メインの対象リストまたは選択した dist 索引にありません。", invalidItem: "{line} 行目 · {reason}:{text}",
noMatch: "対象パッケージが見つかりません。一覧とシステムを確認してください。すべて最新版という意味ではありません。", partial: "有効な項目を比較しましたが、{count} 行を読めませんでした。詳細をご確認ください。",
complete: "完了:{count} パッケージを比較、{skipped} は対象外です。", unexpected: "チェックを完了できませんでした。再試行してください。"
},
ko: {
title: "안정 패키지 버전 일치 검사", language: "언어", bookmark: "즐겨찾기",
intro: "일부 비공개 빌드는 안정 패키지의 버전 번호를 변경하여 roothide 저장소의 업데이트 알림을 막을 수 있습니다. 탈옥 환경에 오류나 불안정 문제가 있다면 이 페이지로 확인하세요.",
system: "시스템", installedList: "Sileo 설치된 패키지 목록", clear: "지우기",
paste: "붙여넣기", pasteFallback: "클립보드를 읽을 수 없습니다. 입력란을 길게 누르고 붙여넣기를 선택하세요.", clipboardEmpty: "클립보드에 텍스트가 없습니다. 먼저 Sileo에서 패키지 목록을 복사하세요.",
placeholder: "Sileo에서 목록 내보내기:\n1. Sileo의 설치됨 탭을 엽니다.\n2. 오른쪽 위 내보내기/공유 버튼을 누릅니다.\n3. 공유 메뉴에서 복사를 선택합니다.\n4. 이 페이지로 돌아와 전체 목록을 붙여넣습니다.",
privacy: "목록은 이 브라우저에서만 처리되며 업로드하거나 저장하지 않습니다.", check: "검사 시작", results: "검사 결과",
higher: "불일치", lower: "오래된 버전", equal: "일치", differentOnly: "버전이 다른 패키지만 표시",
package: "패키지", status: "상태", emptyResults: "표시할 패키지가 없습니다.",
caution: "설치 버전이 높으면 업데이트 알림이 표시되지 않을 수 있지만, 변조의 증거는 아닙니다. 출처를 확인하고 Sileo에서 이 저장소의 버전을 선택하세요. 시스템 의존성을 일괄 다운그레이드하지 마세요.",
versionOrder: "버전 정렬 기준:", mainIndex: "기본 색인", distIndex: "Procursus 색인", main: "기본 저장소",
unsupported: "지원하지 않음", unknownSystem: "시스템 버전 선택",
systemError: "검사를 시작하기 전에 기기의 iOS / iPadOS 버전을 선택하세요.",
bookmarkMobile: "Safari의 공유 버튼을 누른 후 즐겨찾기에 추가 또는 책갈피 추가를 선택하세요. 다른 브라우저는 메뉴에서 즐겨찾기나 북마크를 선택하세요.",
bookmarkDesktop: "브라우저의 북마크/즐겨찾기 추가 메뉴 또는 {shortcut}+D를 사용하세요.",
badVersion: "잘못된 Debian 버전", badFormat: "인식할 수 없는 형식", missingFields: "{source}: 색인에 Package 또는 Version 필드가 없습니다.",
badIndex: "{source}: 잘못된 Packages 색인입니다.", emptyIndex: "{source}: 검사할 패키지가 없습니다.",
downloadError: "색인 다운로드 실패: {path} ({reason}). 네트워크를 확인하고 검사 시작을 눌러 다시 시도하세요.", timeout: "요청 시간 초과", network: "네트워크 오류",
emptyInput: "Sileo에서 내보낸 설치된 패키지 목록을 붙여넣으세요.", conflicts: "같은 패키지에 여러 버전이 있습니다. 목록을 수정하세요: {ids}",
noValid: "유효한 패키지가 없습니다. {count}줄을 읽지 못했습니다. 형식: 이름:(package.id) 버전.", localFile: "로컬 파일에서 색인을 읽을 수 없습니다. HTTP / HTTPS로 페이지를 여세요.",
checking: "검사 중…", downloading: "색인 다운로드 중…", waiting: "기본 및 dist {dist} 색인 다운로드 중입니다. 완료되면 자동으로 검사를 계속합니다…",
report: "dist {dist} · 설치 {installed}개 · 비교 {compared}개 · {date}", skippedSummary: "검사 제외: {count}개", invalidSummary: "미완료: {count}줄 읽기 실패",
skippedItem: "{name} ({id}) {version}: 기본 검사 목록 또는 선택한 dist 색인에 없습니다.", invalidItem: "{line}줄 · {reason}: {text}",
noMatch: "검사 대상 패키지가 없습니다. 목록과 시스템 버전을 확인하세요. 모두 최신이라는 의미는 아닙니다.", partial: "유효한 항목은 비교했지만 {count}줄을 읽지 못했습니다. 아래 세부 정보를 확인하세요.",
complete: "검사 완료: {count}개 비교, {skipped}개는 검사 범위 밖입니다.", unexpected: "검사를 완료하지 못했습니다. 다시 시도하세요."
},
hi: {
title: "स्थिर पैकेज संस्करण की संगति जाँच", language: "भाषा", bookmark: "बुकमार्क",
intro: "कुछ निजी बिल्ड स्थिर पैकेजों के संस्करण बदलकर roothide रिपॉज़िटरी की अपडेट सूचनाएँ रोक सकते हैं। जेलब्रेक में संभावित खराबी या अस्थिरता की जाँच के लिए इस पृष्ठ का उपयोग करें।",
system: "सिस्टम", installedList: "Sileo के इंस्टॉल किए गए पैकेज", clear: "साफ़ करें",
paste: "पेस्ट करें", pasteFallback: "क्लिपबोर्ड पढ़ा नहीं जा सकता। इनपुट बॉक्स को दबाकर रखें, फिर पेस्ट चुनें।", clipboardEmpty: "क्लिपबोर्ड में कोई टेक्स्ट नहीं है। पहले Sileo से पैकेज सूची कॉपी करें।",
placeholder: "Sileo से सूची निर्यात करें:\n1. Sileo में Installed खोलें।\n2. ऊपर दाईं ओर निर्यात/शेयर बटन दबाएँ।\n3. शेयर मेनू में Copy चुनें।\n4. यहाँ लौटकर पूरी सूची पेस्ट करें।",
privacy: "सूची केवल इस ब्राउज़र में संसाधित होती है। इसे अपलोड या सहेजा नहीं जाता।", check: "जाँच शुरू करें", results: "परिणाम",
higher: "असंगत", lower: "पुराना", equal: "समान", differentOnly: "केवल अलग संस्करण दिखाएँ",
package: "पैकेज", status: "स्थिति", emptyResults: "दिखाने के लिए कोई पैकेज नहीं है।",
caution: "अधिक इंस्टॉल संस्करण अपडेट सूचनाएँ रोक सकता है, पर यह संशोधन का प्रमाण नहीं है। स्रोत सत्यापित करें और Sileo में इस स्रोत का संस्करण चुनें। सिस्टम निर्भरताओं को एक साथ डाउनग्रेड न करें।",
versionOrder: "संस्करण क्रम का आधार:", mainIndex: "मुख्य सूचकांक", distIndex: "Procursus सूचकांक", main: "मुख्य स्रोत",
unsupported: "समर्थित नहीं", unknownSystem: "अपना सिस्टम संस्करण चुनें",
systemError: "जाँच शुरू करने से पहले अपने डिवाइस का iOS / iPadOS संस्करण चुनें।",
bookmarkMobile: "Safari में Share दबाएँ, फिर Add to Favorites या Add Bookmark चुनें। दूसरे ब्राउज़र में मेनू से बुकमार्क या पसंदीदा चुनें।",
bookmarkDesktop: "ब्राउज़र के बुकमार्क/पसंदीदा मेनू का उपयोग करें या {shortcut}+D दबाएँ।",
badVersion: "अमान्य Debian संस्करण", badFormat: "अपरिचित पंक्ति प्रारूप", missingFields: "{source}: सूचकांक में Package या Version फ़ील्ड नहीं है।",
badIndex: "{source}: अमान्य Packages सूचकांक।", emptyIndex: "{source}: जाँचने के लिए पैकेज नहीं हैं।",
downloadError: "सूचकांक डाउनलोड विफल: {path} ({reason})। नेटवर्क जाँचें और फिर जाँच शुरू करें दबाएँ।", timeout: "अनुरोध का समय समाप्त", network: "नेटवर्क त्रुटि",
emptyInput: "Sileo से निर्यात की गई इंस्टॉल पैकेज सूची पेस्ट करें।", conflicts: "एक ही पैकेज के कई संस्करण मिले। सूची ठीक करें: {ids}",
noValid: "मान्य पैकेज नहीं मिला; {count} पंक्तियाँ पढ़ी नहीं जा सकीं। प्रारूप: नाम:(package.id) संस्करण।", localFile: "स्थानीय फ़ाइल से सूचकांक नहीं पढ़ सकते। पृष्ठ को HTTP / HTTPS से खोलें।",
checking: "जाँच जारी है…", downloading: "सूचकांक डाउनलोड हो रहे हैं…", waiting: "मुख्य और dist {dist} सूचकांक डाउनलोड हो रहे हैं। कृपया रुकें; जाँच अपने आप आगे बढ़ेगी…",
report: "dist {dist} · {installed} इंस्टॉल · {compared} जाँचे गए · {date}", skippedSummary: "नहीं जाँचे गए: {count} पैकेज", invalidSummary: "अधूरा: {count} अपठनीय पंक्तियाँ",
skippedItem: "{name} ({id}) {version}: मुख्य सूची या चुने गए dist सूचकांक में नहीं है।", invalidItem: "पंक्ति {line} · {reason}: {text}",
noMatch: "जाँच के दायरे में पैकेज नहीं मिले। सूची और सिस्टम जाँचें; इसका अर्थ यह नहीं कि सब नवीनतम हैं।", partial: "मान्य प्रविष्टियाँ जाँची गईं, पर {count} पंक्तियाँ पढ़ी नहीं जा सकीं। नीचे विवरण देखें।",
complete: "जाँच पूरी: {count} पैकेजों की तुलना हुई; {skipped} दायरे से बाहर हैं।", unexpected: "जाँच पूरी नहीं हो सकी। फिर प्रयास करें।"
},
id: {
title: "Pemeriksaan Konsistensi Paket Stabil", language: "Bahasa", bookmark: "Bookmark",
intro: "Beberapa build privat dapat mengubah versi paket stabil dan menghalangi notifikasi pembaruan dari repositori roothide. Gunakan halaman ini untuk memeriksa gangguan atau ketidakstabilan jailbreak.",
system: "Sistem", installedList: "Paket Sileo terpasang", clear: "Hapus",
paste: "Tempel", pasteFallback: "Clipboard tidak dapat dibaca. Sentuh dan tahan kotak masukan, lalu pilih Tempel.", clipboardEmpty: "Clipboard tidak berisi teks. Salin daftar paket dari Sileo terlebih dahulu.",
placeholder: "Ekspor daftar dari Sileo:\n1. Buka Sileo, lalu tab Terpasang.\n2. Ketuk tombol ekspor/bagikan di kanan atas.\n3. Pilih Salin pada menu berbagi.\n4. Kembali ke sini dan tempel daftar lengkap.",
privacy: "Daftar hanya diproses di browser ini, tidak diunggah atau disimpan.", check: "Mulai periksa", results: "Hasil",
higher: "Tidak cocok", lower: "Usang", equal: "Sesuai", differentOnly: "Hanya tampilkan versi berbeda",
package: "Paket", status: "Status", emptyResults: "Tidak ada paket untuk ditampilkan.",
caution: "Versi terpasang yang lebih tinggi dapat menahan notifikasi pembaruan, tetapi bukan bukti modifikasi. Periksa sumber dan pilih versi repo ini di Sileo. Jangan turunkan versi dependensi sistem sekaligus.",
versionOrder: "Urutan versi mengikuti", mainIndex: "Indeks utama", distIndex: "Indeks Procursus", main: "Repo utama",
unsupported: "Tidak didukung", unknownSystem: "Pilih versi sistem Anda",
systemError: "Pilih versi iOS / iPadOS perangkat Anda sebelum memulai pemeriksaan.",
bookmarkMobile: "Di Safari, ketuk Bagikan, lalu Tambahkan ke Favorit atau Tambahkan Penanda. Di browser lain, buka menu bookmark atau favorit.",
bookmarkDesktop: "Gunakan menu Tambahkan Bookmark / Favorit, atau tekan {shortcut}+D.",
badVersion: "Versi Debian tidak valid", badFormat: "Format baris tidak dikenali", missingFields: "{source}: indeks tidak memiliki kolom Package atau Version.",
badIndex: "{source}: indeks Packages tidak valid.", emptyIndex: "{source}: tidak ada paket yang dapat diperiksa.",
downloadError: "Unduhan indeks gagal: {path} ({reason}). Periksa jaringan dan pilih Mulai periksa untuk mencoba lagi.", timeout: "Permintaan habis waktu", network: "Kesalahan jaringan",
emptyInput: "Tempel daftar paket terpasang yang diekspor dari Sileo.", conflicts: "Beberapa versi ditemukan untuk paket yang sama. Perbaiki daftar: {ids}",
noValid: "Tidak ada paket valid; {count} baris tidak dapat dibaca. Format: Nama:(package.id) versi.", localFile: "Indeks tidak dapat dibaca dari berkas lokal. Buka halaman melalui HTTP / HTTPS.",
checking: "Memeriksa…", downloading: "Mengunduh indeks…", waiting: "Mengunduh indeks utama dan dist {dist}. Tunggu; pemeriksaan akan dilanjutkan otomatis…",
report: "dist {dist} · {installed} terpasang · {compared} diperiksa · {date}", skippedSummary: "Tidak diperiksa: {count} paket", invalidSummary: "Belum lengkap: {count} baris tidak terbaca",
skippedItem: "{name} ({id}) {version}: tidak ada di daftar utama atau indeks dist terpilih.", invalidItem: "Baris {line} · {reason}: {text}",
noMatch: "Tidak ada paket dalam cakupan pemeriksaan. Periksa daftar dan sistem; ini bukan berarti semua sudah terbaru.", partial: "Entri valid telah diperiksa, tetapi {count} baris tidak terbaca. Lihat rincian di bawah.",
complete: "Selesai: {count} paket dibandingkan; {skipped} di luar cakupan.", unexpected: "Pemeriksaan tidak dapat diselesaikan. Coba lagi."
},
th: {
title: "ตรวจสอบเวอร์ชันแพ็กเกจเสถียร", language: "ภาษา", bookmark: "เพิ่มที่คั่นหน้า",
intro: "บิลด์ส่วนตัวบางตัวอาจแก้ไขเลขเวอร์ชันแพ็กเกจเสถียรและทำให้ไม่ได้รับแจ้งอัปเดตจากคลังแพ็กเกจ roothide ใช้หน้านี้ตรวจสอบข้อผิดพลาดหรือความไม่เสถียรของการเจลเบรก",
system: "ระบบ", installedList: "แพ็กเกจที่ติดตั้งใน Sileo", clear: "ล้าง",
paste: "วาง", pasteFallback: "อ่านคลิปบอร์ดไม่ได้ โปรดแตะช่องป้อนข้อมูลค้างไว้แล้วเลือกวาง", clipboardEmpty: "คลิปบอร์ดไม่มีข้อความ โปรดคัดลอกรายการแพ็กเกจจาก Sileo ก่อน",
placeholder: "ส่งออกรายการจาก Sileo:\n1. เปิด Sileo แล้วไปที่ติดตั้งแล้ว\n2. แตะปุ่มส่งออก/แชร์ที่มุมขวาบน\n3. เลือกคัดลอกในเมนูแชร์\n4. กลับมาที่นี่แล้ววางรายการทั้งหมด",
privacy: "รายการประมวลผลในเบราว์เซอร์นี้เท่านั้น ไม่อัปโหลดหรือบันทึก", check: "เริ่มตรวจสอบ", results: "ผลการตรวจสอบ",
higher: "ไม่ตรงกัน", lower: "เวอร์ชันเก่า", equal: "ตรงกัน", differentOnly: "แสดงเฉพาะเวอร์ชันที่ต่างกัน",
package: "แพ็กเกจ", status: "สถานะ", emptyResults: "ไม่มีแพ็กเกจที่จะแสดง",
caution: "เวอร์ชันที่ติดตั้งสูงกว่าอาจทำให้ไม่แจ้งอัปเดต แต่ไม่ได้ยืนยันว่าถูกดัดแปลง โปรดตรวจสอบแหล่งและเลือกเวอร์ชันจากแหล่งนี้ใน Sileo อย่าดาวน์เกรดส่วนพึ่งพาของระบบพร้อมกันทั้งหมด",
versionOrder: "ลำดับเวอร์ชันตาม", mainIndex: "ดัชนีหลัก", distIndex: "ดัชนี Procursus", main: "แหล่งหลัก",
unsupported: "ไม่รองรับ", unknownSystem: "เลือกเวอร์ชันระบบของคุณ",
systemError: "โปรดเลือกเวอร์ชัน iOS / iPadOS ของอุปกรณ์ก่อนเริ่มตรวจสอบ",
bookmarkMobile: "ใน Safari แตะแชร์ แล้วเลือกเพิ่มไปยังรายการโปรดหรือเพิ่มที่คั่นหน้า เบราว์เซอร์อื่นให้เปิดเมนูที่คั่นหน้าหรือรายการโปรด",
bookmarkDesktop: "ใช้เมนูเพิ่มที่คั่นหน้า/รายการโปรด หรือกด {shortcut}+D",
badVersion: "เวอร์ชัน Debian ไม่ถูกต้อง", badFormat: "ไม่รู้จักรูปแบบบรรทัด", missingFields: "{source}: ดัชนีไม่มีฟิลด์ Package หรือ Version",
badIndex: "{source}: ดัชนี Packages ไม่ถูกต้อง", emptyIndex: "{source}: ไม่มีแพ็กเกจสำหรับตรวจสอบ",
downloadError: "ดาวน์โหลดดัชนีไม่สำเร็จ: {path} ({reason}) โปรดตรวจสอบเครือข่ายแล้วกดเริ่มตรวจสอบเพื่อลองใหม่", timeout: "คำขอหมดเวลา", network: "ข้อผิดพลาดเครือข่าย",
emptyInput: "โปรดวางรายการแพ็กเกจที่ส่งออกจาก Sileo", conflicts: "พบหลายเวอร์ชันของแพ็กเกจเดียวกัน โปรดแก้รายการ: {ids}",
noValid: "ไม่พบแพ็กเกจที่ถูกต้อง อ่านไม่ได้ {count} บรรทัด รูปแบบ: ชื่อ:(package.id) เวอร์ชัน", localFile: "อ่านดัชนีจากไฟล์ในเครื่องไม่ได้ โปรดเปิดผ่าน HTTP / HTTPS",
checking: "กำลังตรวจสอบ…", downloading: "กำลังดาวน์โหลดดัชนี…", waiting: "กำลังดาวน์โหลดดัชนีหลักและ dist {dist} โปรดรอ ระบบจะตรวจสอบต่อโดยอัตโนมัติ…",
report: "dist {dist} · ติดตั้ง {installed} · ตรวจสอบ {compared} · {date}", skippedSummary: "ไม่ได้ตรวจสอบ: {count} แพ็กเกจ", invalidSummary: "ไม่สมบูรณ์: อ่านไม่ได้ {count} บรรทัด",
skippedItem: "{name} ({id}) {version}: ไม่อยู่ในรายการหลักหรือดัชนี dist ที่เลือก", invalidItem: "บรรทัด {line} · {reason}: {text}",
noMatch: "ไม่พบแพ็กเกจในขอบเขต โปรดตรวจสอบรายการและระบบ ไม่ได้หมายความว่าทั้งหมดเป็นเวอร์ชันล่าสุด", partial: "ตรวจสอบรายการที่ถูกต้องแล้ว แต่อ่านไม่ได้ {count} บรรทัด ดูรายละเอียดด้านล่าง",
complete: "เสร็จสิ้น: เปรียบเทียบ {count} แพ็กเกจ และ {skipped} แพ็กเกจอยู่นอกขอบเขต", unexpected: "ตรวจสอบไม่สำเร็จ โปรดลองใหม่"
},
vi: {
title: "Kiểm tra tính nhất quán gói ổn định", language: "Ngôn ngữ", bookmark: "Đánh dấu",
intro: "Một số bản dựng riêng có thể sửa đổi số phiên bản gói ổn định và chặn thông báo cập nhật từ kho roothide. Dùng trang này để kiểm tra lỗi hoặc tình trạng jailbreak không ổn định.",
system: "Hệ thống", installedList: "Gói Sileo đã cài", clear: "Xóa",
paste: "Dán", pasteFallback: "Không thể đọc bảng nhớ tạm. Nhấn giữ trong ô nhập rồi chọn Dán.", clipboardEmpty: "Bảng nhớ tạm không có văn bản. Hãy sao chép danh sách gói từ Sileo trước.",
placeholder: "Xuất danh sách từ Sileo:\n1. Mở Sileo và vào Đã cài đặt.\n2. Nhấn nút xuất/chia sẻ ở góc trên bên phải.\n3. Chọn Sao chép trong bảng chia sẻ.\n4. Quay lại đây và dán toàn bộ danh sách.",
privacy: "Danh sách chỉ được xử lý trong trình duyệt này, không tải lên hay lưu lại.", check: "Bắt đầu kiểm tra", results: "Kết quả",
higher: "Không khớp", lower: "Bản cũ", equal: "Khớp", differentOnly: "Chỉ hiện phiên bản khác nhau",
package: "Gói", status: "Trạng thái", emptyResults: "Không có gói để hiển thị.",
caution: "Phiên bản đã cài cao hơn có thể chặn thông báo cập nhật, nhưng không chứng minh gói bị sửa đổi. Xác minh nguồn và chọn phiên bản kho này trong Sileo. Không hạ cấp hàng loạt phụ thuộc hệ thống.",
versionOrder: "Thứ tự phiên bản tuân theo", mainIndex: "Chỉ mục chính", distIndex: "Chỉ mục Procursus", main: "Kho chính",
unsupported: "Không hỗ trợ", unknownSystem: "Chọn phiên bản hệ thống",
systemError: "Chọn phiên bản iOS / iPadOS của thiết bị trước khi bắt đầu kiểm tra.",
bookmarkMobile: "Trong Safari, nhấn Chia sẻ rồi chọn Thêm vào mục ưa thích hoặc Thêm dấu trang. Trình duyệt khác: mở menu dấu trang hoặc mục ưa thích.",
bookmarkDesktop: "Dùng menu Thêm dấu trang / Mục ưa thích hoặc nhấn {shortcut}+D.",
badVersion: "Phiên bản Debian không hợp lệ", badFormat: "Không nhận dạng được định dạng", missingFields: "{source}: chỉ mục thiếu trường Package hoặc Version.",
badIndex: "{source}: chỉ mục Packages không hợp lệ.", emptyIndex: "{source}: không có gói để kiểm tra.",
downloadError: "Tải chỉ mục thất bại: {path} ({reason}). Kiểm tra mạng rồi nhấn Bắt đầu kiểm tra để thử lại.", timeout: "Yêu cầu hết thời gian", network: "Lỗi mạng",
emptyInput: "Dán danh sách gói đã cài được xuất từ Sileo.", conflicts: "Có nhiều phiên bản cho cùng một gói. Sửa danh sách: {ids}",
noValid: "Không có gói hợp lệ; không đọc được {count} dòng. Định dạng: Tên:(package.id) phiên bản.", localFile: "Không đọc được chỉ mục từ tệp cục bộ. Mở trang qua HTTP / HTTPS.",
checking: "Đang kiểm tra…", downloading: "Đang tải chỉ mục…", waiting: "Đang tải chỉ mục chính và dist {dist}. Vui lòng đợi; kiểm tra sẽ tự động tiếp tục…",
report: "dist {dist} · {installed} đã cài · {compared} đã kiểm tra · {date}", skippedSummary: "Chưa kiểm tra: {count} gói", invalidSummary: "Chưa hoàn tất: {count} dòng không đọc được",
skippedItem: "{name} ({id}) {version}: không thuộc danh sách chính hoặc chỉ mục dist đã chọn.", invalidItem: "Dòng {line} · {reason}: {text}",
noMatch: "Không có gói trong phạm vi kiểm tra. Kiểm tra danh sách và hệ thống; điều này không có nghĩa mọi gói đều mới nhất.", partial: "Đã kiểm tra các mục hợp lệ nhưng không đọc được {count} dòng. Xem chi tiết bên dưới.",
complete: "Hoàn tất: đã so sánh {count} gói; {skipped} gói ngoài phạm vi.", unexpected: "Không thể hoàn tất kiểm tra. Vui lòng thử lại."
},
ar: {
title: "فحص توافق إصدارات الحزم المستقرة", language: "اللغة", bookmark: "إضافة للمفضلة",
intro: "قد تعدّل بعض الإصدارات الخاصة أرقام إصدارات الحزم المستقرة وتمنع إشعارات التحديث من مستودع roothide. استخدم هذه الصفحة لفحص أعطال الجيلبريك المحتملة أو عدم استقراره.",
system: "النظام", installedList: "حزم Sileo المثبتة", clear: "مسح",
paste: "لصق", pasteFallback: "لا يمكن قراءة الحافظة. اضغط مطولًا داخل مربع الإدخال ثم اختر لصق.", clipboardEmpty: "لا يوجد نص في الحافظة. انسخ قائمة الحزم من Sileo أولًا.",
placeholder: "تصدير القائمة من Sileo:\n1. افتح Sileo وانتقل إلى الحزم المثبتة.\n2. اضغط زر التصدير/المشاركة أعلى اليمين.\n3. اختر نسخ من قائمة المشاركة.\n4. عد إلى هنا والصق القائمة كاملة.",
privacy: "تتم معالجة القائمة داخل هذا المتصفح فقط، ولا يتم رفعها أو حفظها.", check: "بدء الفحص", results: "النتائج",
higher: "غير متطابق", lower: "قديم", equal: "متطابق", differentOnly: "عرض الإصدارات المختلفة فقط",
package: "الحزمة", status: "الحالة", emptyResults: "لا توجد حزم لعرضها.",
caution: "قد يمنع الإصدار المثبت الأعلى إشعارات التحديث، لكنه لا يثبت تعديل الحزمة. تحقّق من المصدر واختر إصدار هذا المصدر في Sileo. لا تخفّض إصدارات اعتماديات النظام دفعة واحدة.",
versionOrder: "ترتيب الإصدارات يتبع", mainIndex: "الفهرس الرئيسي", distIndex: "فهرس Procursus", main: "المصدر الرئيسي",
unsupported: "غير مدعوم", unknownSystem: "اختر إصدار نظامك",
systemError: "اختر إصدار iOS / iPadOS الخاص بجهازك قبل بدء الفحص.",
bookmarkMobile: "في Safari، اضغط مشاركة ثم إضافة إلى المفضلة أو إضافة إشارة مرجعية. في المتصفحات الأخرى، افتح قائمة الإشارات المرجعية أو المفضلة.",
bookmarkDesktop: "استخدم قائمة إضافة إشارة مرجعية / المفضلة، أو اضغط {shortcut}+D.",
badVersion: "إصدار Debian غير صالح", badFormat: "تنسيق السطر غير معروف", missingFields: "{source}: يفتقد الفهرس حقل Package أو Version.",
badIndex: "{source}: فهرس Packages غير صالح.", emptyIndex: "{source}: لا توجد حزم متاحة للفحص.",
downloadError: "فشل تنزيل الفهرس: {path} ({reason}). تحقّق من اتصال الشبكة واضغط بدء الفحص للمحاولة مجددًا.", timeout: "انتهت مهلة الطلب", network: "خطأ في الشبكة",
emptyInput: "الصق قائمة الحزم المثبتة المصدّرة من Sileo.", conflicts: "وُجدت إصدارات متعددة للحزمة نفسها. صحّح القائمة: {ids}",
noValid: "لا توجد حزم صالحة؛ تعذّرت قراءة {count} من الأسطر. التنسيق: الاسم:(package.id) الإصدار.", localFile: "لا يمكن قراءة الفهارس من ملف محلي. افتح الصفحة عبر HTTP / HTTPS.",
checking: "جارٍ الفحص…", downloading: "جارٍ تنزيل الفهارس…", waiting: "جارٍ تنزيل فهرس المصدر الرئيسي وdist {dist}. يُرجى الانتظار؛ سيستمر الفحص تلقائيًا…",
report: "dist {dist} · المثبتة: {installed} · المفحوصة: {compared} · {date}", skippedSummary: "حزم غير مفحوصة: {count}", invalidSummary: "غير مكتمل؛ أسطر غير مقروءة: {count}",
skippedItem: "{name} ({id}) {version}: ليست ضمن القائمة الرئيسية أو فهرس dist المحدد.", invalidItem: "السطر {line} · {reason}: {text}",
noMatch: "لا توجد حزم ضمن نطاق الفحص. تحقّق من القائمة والنظام؛ هذا لا يعني أن كل الحزم محدثة.", partial: "فُحصت الإدخالات الصالحة، لكن تعذّرت قراءة {count} من الأسطر. راجع التفاصيل أدناه.",
complete: "اكتمل الفحص؛ الحزم المقارنة: {count}، وخارج النطاق: {skipped}.", unexpected: "تعذّر إكمال الفحص. يُرجى المحاولة مجددًا."
},
fa: {
title: "بررسی سازگاری نسخه بستههای پایدار", language: "زبان", bookmark: "افزودن نشانک",
intro: "برخی ساختهای خصوصی ممکن است شماره نسخه بستههای پایدار را تغییر دهند و مانع اعلان بهروزرسانی از مخزن roothide شوند. برای بررسی خرابی یا ناپایداری احتمالی جیلبریک از این صفحه استفاده کنید.",
system: "سیستم", installedList: "بستههای نصبشده Sileo", clear: "پاک کردن",
paste: "جایگذاری", pasteFallback: "خواندن کلیپبورد ممکن نیست. داخل کادر ورودی لمس طولانی کنید و جایگذاری را انتخاب کنید.", clipboardEmpty: "کلیپبورد خالی است. ابتدا فهرست بستهها را از Sileo کپی کنید.",
placeholder: "خروجی گرفتن از Sileo:\n1. Sileo را باز کنید و به نصبشدهها بروید.\n2. دکمه خروجی/اشتراکگذاری بالا سمت راست را بزنید.\n3. در منوی اشتراکگذاری، کپی را انتخاب کنید.\n4. اینجا برگردید و فهرست کامل را جایگذاری کنید.",
privacy: "فهرست فقط در همین مرورگر پردازش میشود و بارگذاری یا ذخیره نمیشود.", check: "شروع بررسی", results: "نتایج",
higher: "ناسازگار", lower: "قدیمی", equal: "یکسان", differentOnly: "فقط نسخههای متفاوت را نمایش بده",
package: "بسته", status: "وضعیت", emptyResults: "بستهای برای نمایش وجود ندارد.",
caution: "نسخه نصبشده بالاتر ممکن است مانع اعلان بهروزرسانی شود، اما نشانه قطعی دستکاری نیست. منبع را بررسی و نسخه این مخزن را در Sileo انتخاب کنید. وابستگیهای سیستم را یکجا به نسخه پایینتر برنگردانید.",
versionOrder: "ترتیب نسخهها بر اساس", mainIndex: "نمایه اصلی", distIndex: "نمایه Procursus", main: "مخزن اصلی",
unsupported: "پشتیبانی نمیشود", unknownSystem: "نسخه سیستم خود را انتخاب کنید",
systemError: "پیش از شروع بررسی، نسخه iOS / iPadOS دستگاه خود را انتخاب کنید.",
bookmarkMobile: "در Safari دکمه اشتراکگذاری را بزنید و افزودن به علاقهمندیها یا افزودن نشانک را انتخاب کنید. در مرورگرهای دیگر از منوی نشانکها استفاده کنید.",
bookmarkDesktop: "از منوی افزودن نشانک / علاقهمندیها استفاده کنید یا {shortcut}+D را بزنید.",
badVersion: "نسخه Debian نامعتبر", badFormat: "قالب خط ناشناخته", missingFields: "{source}: نمایه فاقد فیلد Package یا Version است.",
badIndex: "{source}: نمایه Packages نامعتبر است.", emptyIndex: "{source}: بستهای برای بررسی وجود ندارد.",
downloadError: "دریافت نمایه ناموفق بود: {path} ({reason}). اتصال شبکه را بررسی و دوباره شروع بررسی را بزنید.", timeout: "مهلت درخواست تمام شد", network: "خطای شبکه",
emptyInput: "فهرست بستههای نصبشده خروجی Sileo را جایگذاری کنید.", conflicts: "برای یک بسته چند نسخه پیدا شد. فهرست را اصلاح کنید: {ids}",
noValid: "بسته معتبری یافت نشد؛ {count} خط خوانده نشد. قالب: نام:(package.id) نسخه.", localFile: "نمایهها از فایل محلی خوانده نمیشوند. صفحه را از طریق HTTP / HTTPS باز کنید.",
checking: "در حال بررسی…", downloading: "در حال دریافت نمایهها…", waiting: "در حال دریافت نمایه اصلی و dist {dist}. لطفاً صبر کنید؛ بررسی خودکار ادامه مییابد…",
report: "dist {dist} · نصبشده: {installed} · بررسیشده: {compared} · {date}", skippedSummary: "بستههای بررسینشده: {count}", invalidSummary: "ناقص؛ خطوط ناخوانا: {count}",
skippedItem: "{name} ({id}) {version}: در فهرست اصلی یا نمایه dist انتخابشده نیست.", invalidItem: "خط {line} · {reason}: {text}",
noMatch: "بستهای در محدوده بررسی یافت نشد. فهرست و سیستم را بررسی کنید؛ این به معنی بهروز بودن همه بستهها نیست.", partial: "موارد معتبر بررسی شد، اما {count} خط خوانده نشد. جزئیات زیر را ببینید.",
complete: "بررسی تمام شد؛ بستههای مقایسهشده: {count}، خارج از محدوده: {skipped}.", unexpected: "بررسی کامل نشد. دوباره تلاش کنید."
},
he: {
title: "בדיקת תאימות גרסאות חבילות יציבות", language: "שפה", bookmark: "הוספה למועדפים",
intro: "בניות פרטיות מסוימות עשויות לשנות את מספרי הגרסאות של חבילות יציבות ולמנוע התראות עדכון ממאגר roothide. השתמשו בעמוד לבדיקת תקלות או חוסר יציבות בפריצת המכשיר.",
system: "מערכת", installedList: "חבילות Sileo מותקנות", clear: "ניקוי",
paste: "הדבקה", pasteFallback: "לא ניתן לקרוא את הלוח. לחצו לחיצה ארוכה בתוך תיבת הקלט ובחרו הדבקה.", clipboardEmpty: "אין טקסט בלוח. העתיקו תחילה את רשימת החבילות מ־Sileo.",
placeholder: "ייצוא רשימה מ־Sileo:\n1. פתחו את Sileo ועברו לחבילות המותקנות.\n2. לחצו על ייצוא/שיתוף בפינה העליונה.\n3. בחרו העתקה בתפריט השיתוף.\n4. חזרו לכאן והדביקו את הרשימה המלאה.",
privacy: "הרשימה מעובדת רק בדפדפן זה, ואינה נשלחת או נשמרת.", check: "התחלת בדיקה", results: "תוצאות",
higher: "אי־התאמה", lower: "מיושן", equal: "תואם", differentOnly: "הצגת גרסאות שונות בלבד",
package: "חבילה", status: "מצב", emptyResults: "אין חבילות להצגה.",
caution: "גרסה מותקנת גבוהה יותר עלולה למנוע התראות עדכון, אך אינה הוכחה לשינוי החבילה. בדקו את המקור ובחרו את גרסת המאגר ב־Sileo. אין לשנמך את כל תלויות המערכת יחד.",
versionOrder: "סדר הגרסאות לפי", mainIndex: "אינדקס ראשי", distIndex: "אינדקס Procursus", main: "מאגר ראשי",
unsupported: "לא נתמך", unknownSystem: "בחרו את גרסת המערכת",
systemError: "בחרו את גרסת iOS / iPadOS של המכשיר לפני תחילת הבדיקה.",
bookmarkMobile: "ב־Safari לחצו על שיתוף ובחרו הוספה למועדפים או הוספת סימנייה. בדפדפנים אחרים פתחו את תפריט הסימניות או המועדפים.",
bookmarkDesktop: "השתמשו בתפריט הוספת סימנייה / מועדפים, או לחצו {shortcut}+D.",
badVersion: "גרסת Debian אינה תקינה", badFormat: "מבנה שורה לא מזוהה", missingFields: "{source}: חסר שדה Package או Version באינדקס.",
badIndex: "{source}: אינדקס Packages אינו תקין.", emptyIndex: "{source}: אין חבילות לבדיקה.",
downloadError: "הורדת האינדקס נכשלה: {path} ({reason}). בדקו את הרשת ולחצו התחלת בדיקה כדי לנסות שוב.", timeout: "זמן הבקשה הסתיים", network: "שגיאת רשת",
emptyInput: "הדביקו את רשימת החבילות שיוצאה מ־Sileo.", conflicts: "נמצאו כמה גרסאות לאותה חבילה. תקנו את הרשימה: {ids}",
noValid: "לא נמצאו חבילות תקינות; לא ניתן לקרוא {count} שורות. מבנה: שם:(package.id) גרסה.", localFile: "לא ניתן לקרוא אינדקסים מקובץ מקומי. פתחו דרך HTTP / HTTPS.",
checking: "מתבצעת בדיקה…", downloading: "מוריד אינדקסים…", waiting: "מוריד את האינדקס הראשי ואת dist {dist}. נא להמתין; הבדיקה תימשך אוטומטית…",
report: "dist {dist} · מותקנות: {installed} · נבדקו: {compared} · {date}", skippedSummary: "חבילות שלא נבדקו: {count}", invalidSummary: "לא הושלם; שורות שלא נקראו: {count}",
skippedItem: "{name} ({id}) {version}: לא ברשימה הראשית או באינדקס dist שנבחר.", invalidItem: "שורה {line} · {reason}: {text}",
noMatch: "לא נמצאו חבילות בטווח הבדיקה. בדקו את הרשימה והמערכת; אין פירוש הדבר שהכול מעודכן.", partial: "הרשומות התקינות נבדקו, אך לא ניתן לקרוא {count} שורות. ראו פרטים בהמשך.",
complete: "הבדיקה הושלמה; הושוו {count} חבילות, {skipped} מחוץ לטווח.", unexpected: "לא ניתן להשלים את הבדיקה. נסו שוב."
},
tr: {
title: "Kararlı Paket Sürümü Tutarlılık Kontrolü", language: "Dil", bookmark: "Yer imi ekle",
intro: "Bazı özel derlemeler kararlı paketlerin sürüm numaralarını değiştirip roothide deposundan gelen güncelleme bildirimlerini engelleyebilir. Olası jailbreak hatalarını veya kararsızlığını araştırmak için bu sayfayı kullanın.",
system: "Sistem", installedList: "Yüklü Sileo paketleri", clear: "Temizle",
paste: "Yapıştır", pasteFallback: "Pano okunamıyor. Giriş kutusuna basılı tutup Yapıştır'ı seçin.", clipboardEmpty: "Panoda metin yok. Önce Sileo'dan paket listesini kopyalayın.",
placeholder: "Sileo'dan listeyi dışa aktarın:\n1. Sileo'da Yüklü bölümünü açın.\n2. Sağ üstteki dışa aktarma/paylaşma düğmesine dokunun.\n3. Paylaşım menüsünde Kopyala'yı seçin.\n4. Buraya dönüp tam listeyi yapıştırın.",
privacy: "Liste yalnızca bu tarayıcıda işlenir; yüklenmez veya kaydedilmez.", check: "Kontrolü başlat", results: "Sonuçlar",
higher: "Uyumsuz", lower: "Eski", equal: "Eşleşiyor", differentOnly: "Yalnızca farklı sürümleri göster",
package: "Paket", status: "Durum", emptyResults: "Gösterilecek paket yok.",
caution: "Daha yüksek yüklü sürüm bildirimleri engelleyebilir, ancak değişiklik yapıldığını kanıtlamaz. Kaynağı doğrulayın ve Sileo'da bu deponun sürümünü seçin. Sistem bağımlılıklarını topluca eski sürüme düşürmeyin.",
versionOrder: "Sürüm sıralama kuralı:", mainIndex: "Ana dizin", distIndex: "Procursus dizini", main: "Ana depo",
unsupported: "Desteklenmiyor", unknownSystem: "Sistem sürümünüzü seçin",
systemError: "Kontrole başlamadan önce cihazınızın iOS / iPadOS sürümünü seçin.",
bookmarkMobile: "Safari'de Paylaş'a dokunup Favorilere Ekle veya Yer İmi Ekle'yi seçin. Diğer tarayıcılarda yer imleri veya favoriler menüsünü açın.",
bookmarkDesktop: "Yer İmi / Favorilere Ekle menüsünü kullanın veya {shortcut}+D tuşlarına basın.",
badVersion: "Geçersiz Debian sürümü", badFormat: "Tanınmayan satır biçimi", missingFields: "{source}: dizinde Package veya Version alanı eksik.",
badIndex: "{source}: geçersiz Packages dizini.", emptyIndex: "{source}: kontrol edilecek paket yok.",
downloadError: "Dizin indirilemedi: {path} ({reason}). Ağı kontrol edip Kontrolü başlat ile yeniden deneyin.", timeout: "İstek zaman aşımına uğradı", network: "Ağ hatası",
emptyInput: "Sileo'dan dışa aktarılan yüklü paket listesini yapıştırın.", conflicts: "Aynı paket için birden çok sürüm bulundu. Listeyi düzeltin: {ids}",
noValid: "Geçerli paket yok; {count} satır okunamadı. Biçim: Ad:(package.id) sürüm.", localFile: "Dizinler yerel dosyadan okunamaz. Sayfayı HTTP / HTTPS üzerinden açın.",
checking: "Kontrol ediliyor…", downloading: "Dizinler indiriliyor…", waiting: "Ana ve dist {dist} dizinleri indiriliyor. Bekleyin; kontrol otomatik sürecek…",
report: "dist {dist} · {installed} yüklü · {compared} kontrol edildi · {date}", skippedSummary: "Kontrol edilmedi: {count} paket", invalidSummary: "Eksik: {count} okunamayan satır",
skippedItem: "{name} ({id}) {version}: ana listede veya seçili dist dizininde yok.", invalidItem: "Satır {line} · {reason}: {text}",
noMatch: "Kapsamdaki paket bulunamadı. Listeyi ve sistemi doğrulayın; bu, her şeyin güncel olduğu anlamına gelmez.", partial: "Geçerli girdiler kontrol edildi, ancak {count} satır okunamadı. Aşağıdaki ayrıntılara bakın.",
complete: "Tamamlandı: {count} paket karşılaştırıldı; {skipped} kapsam dışında.", unexpected: "Kontrol tamamlanamadı. Yeniden deneyin."
},
ur: {
title: "مستحکم پیکیج ورژن کی مطابقت کی جانچ", language: "زبان", bookmark: "بک مارک کریں",
intro: "کچھ نجی بلڈ مستحکم پیکیج کے ورژن نمبر تبدیل کر کے roothide ذخیرے سے اپ ڈیٹ اطلاعات روک سکتے ہیں۔ جیل بریک کی ممکنہ خرابی یا عدم استحکام جانچنے کے لیے یہ صفحہ استعمال کریں۔",
system: "سسٹم", installedList: "Sileo کے نصب شدہ پیکیج", clear: "صاف کریں",
paste: "پیسٹ کریں", pasteFallback: "کلپ بورڈ نہیں پڑھا جا سکتا۔ ان پٹ باکس میں دبا کر رکھیں، پھر پیسٹ منتخب کریں۔", clipboardEmpty: "کلپ بورڈ میں متن نہیں ہے۔ پہلے Sileo سے پیکیج فہرست کاپی کریں۔",
placeholder: "Sileo سے فہرست برآمد کریں:\n1. Sileo کھولیں اور نصب شدہ پیکیج پر جائیں۔\n2. اوپر دائیں جانب برآمد/شیئر بٹن دبائیں۔\n3. شیئر مینو میں کاپی منتخب کریں۔\n4. یہاں واپس آ کر مکمل فہرست پیسٹ کریں۔",
privacy: "فہرست صرف اسی براؤزر میں پراسیس ہوتی ہے، اپ لوڈ یا محفوظ نہیں کی جاتی۔", check: "جانچ شروع کریں", results: "نتائج",
higher: "غیر مطابق", lower: "پرانا", equal: "مطابق", differentOnly: "صرف مختلف ورژن دکھائیں",
package: "پیکیج", status: "حالت", emptyResults: "دکھانے کے لیے کوئی پیکیج نہیں۔",
caution: "زیادہ نصب شدہ ورژن اپ ڈیٹ اطلاعات روک سکتا ہے، مگر یہ ترمیم کا ثبوت نہیں۔ ماخذ کی تصدیق کریں اور Sileo میں اس ذخیرے کا ورژن چنیں۔ سسٹم کی انحصاری پیکیجز کو ایک ساتھ ڈاؤن گریڈ نہ کریں۔",
versionOrder: "ورژن کی ترتیب کا معیار:", mainIndex: "مرکزی اشاریہ", distIndex: "Procursus اشاریہ", main: "مرکزی ذخیرہ",
unsupported: "تعاون یافتہ نہیں", unknownSystem: "اپنے سسٹم کا ورژن منتخب کریں",
systemError: "جانچ شروع کرنے سے پہلے اپنے آلے کا iOS / iPadOS ورژن منتخب کریں۔",
bookmarkMobile: "Safari میں شیئر دبائیں، پھر پسندیدہ میں شامل کریں یا بک مارک شامل کریں چنیں۔ دوسرے براؤزر میں بک مارکس یا پسندیدہ کا مینو کھولیں۔",
bookmarkDesktop: "براؤزر کا بک مارک / پسندیدہ شامل کرنے کا مینو استعمال کریں یا {shortcut}+D دبائیں۔",
badVersion: "غلط Debian ورژن", badFormat: "نامعلوم سطری فارمیٹ", missingFields: "{source}: اشاریے میں Package یا Version فیلڈ موجود نہیں۔",
badIndex: "{source}: غلط Packages اشاریہ۔", emptyIndex: "{source}: جانچنے کے لیے پیکیج موجود نہیں۔",
downloadError: "اشاریہ ڈاؤن لوڈ ناکام: {path} ({reason})۔ نیٹ ورک چیک کریں اور دوبارہ جانچ شروع کریں دبائیں۔", timeout: "درخواست کا وقت ختم", network: "نیٹ ورک کی خرابی",
emptyInput: "Sileo سے برآمد کردہ نصب شدہ پیکیج فہرست پیسٹ کریں۔", conflicts: "ایک ہی پیکیج کے کئی ورژن ملے۔ فہرست درست کریں: {ids}",
noValid: "درست پیکیج نہیں ملے؛ {count} سطریں پڑھی نہیں جا سکیں۔ فارمیٹ: نام:(package.id) ورژن۔", localFile: "مقامی فائل سے اشاریہ نہیں پڑھ سکتے۔ صفحہ HTTP / HTTPS سے کھولیں۔",
checking: "جانچ جاری ہے…", downloading: "اشاریے ڈاؤن لوڈ ہو رہے ہیں…", waiting: "مرکزی اور dist {dist} اشاریے ڈاؤن لوڈ ہو رہے ہیں۔ انتظار کریں؛ جانچ خود جاری ہو جائے گی…",
report: "dist {dist} · نصب شدہ: {installed} · جانچے گئے: {compared} · {date}", skippedSummary: "نہیں جانچے گئے پیکیج: {count}", invalidSummary: "نامکمل؛ ناقابلِ مطالعہ سطریں: {count}",
skippedItem: "{name} ({id}) {version}: مرکزی فہرست یا منتخب dist اشاریے میں نہیں۔", invalidItem: "سطر {line} · {reason}: {text}",
noMatch: "جانچ کے دائرے میں کوئی پیکیج نہیں ملا۔ فہرست اور سسٹم چیک کریں؛ اس کا مطلب یہ نہیں کہ سب تازہ ترین ہیں۔", partial: "درست اندراجات جانچے گئے مگر {count} سطریں پڑھی نہیں جا سکیں۔ نیچے تفصیل دیکھیں۔",
complete: "جانچ مکمل؛ موازنہ شدہ پیکیج: {count}، دائرے سے باہر: {skipped}۔", unexpected: "جانچ مکمل نہیں ہو سکی۔ دوبارہ کوشش کریں۔"
}
};
</script>
</body>
</html>