@kernhq/module-hr 0.13.1 → 0.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kernhq/module-hr",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "Kern HR module: people, offices, org chart, calendars",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
@@ -45,9 +45,12 @@ export const en: Record<string, Message> = {
45
45
  'hr.accr_col_policy': 'Policy',
46
46
  'hr.accr_col_when': 'When',
47
47
  'hr.accr_config_unreadable': "This policy's settings cannot be read",
48
+ 'hr.accr_config_unreadable_form':
49
+ "This policy's stored settings could not be read, so the fields below are defaults rather than what is saved. Saving replaces the stored settings with these.",
48
50
  'hr.accr_copy_of': '{name} (copy)',
49
51
  'hr.accr_create_title': 'New accrual policy',
50
52
  'hr.accr_created': '"{name}" created',
53
+ 'hr.accr_day_is': 'a day is {length}',
51
54
  'hr.accr_day_length': 'Length of a leave day',
52
55
  'hr.accr_day_length_hint':
53
56
  'In minutes — {length}. Balances are kept in minutes so half days and hourly leave stay exact.',
@@ -71,6 +74,8 @@ export const en: Record<string, Message> = {
71
74
  'hr.accr_error_name': 'Give the policy a name.',
72
75
  'hr.accr_error_pick_policy': 'Pick a policy.',
73
76
  'hr.accr_error_pick_subject': 'Pick who it applies to.',
77
+ 'hr.accr_error_round_cap':
78
+ 'A rounding step cannot be longer than {max}, so a whole day is not one on a day this long.',
74
79
  'hr.accr_error_tier_clash': 'Two tiers start at the same number of years.',
75
80
  'hr.accr_error_to_before_from': 'The end date is before the start date.',
76
81
  'hr.accr_freq_anniversary': 'On each work anniversary',
@@ -117,9 +122,9 @@ export const en: Record<string, Message> = {
117
122
  'A policy says how much a year earns, when it appears and how it rounds. Nobody accrues until a policy is assigned to them.',
118
123
  'hr.accr_preview_error': 'The preview could not be computed',
119
124
  'hr.accr_readonly': 'You can read this page, but changing anything needs permission to manage policies.',
120
- 'hr.accr_round_day': 'A whole day',
125
+ 'hr.accr_round_day': 'A whole day ({length})',
121
126
  'hr.accr_round_exact': 'No rounding',
122
- 'hr.accr_round_half_day': 'Half a day',
127
+ 'hr.accr_round_half_day': 'Half a day ({length})',
123
128
  'hr.accr_round_minutes': { one: '{count} minute', other: '{count} minutes' },
124
129
  'hr.accr_round_short': 'rounded to {step}',
125
130
  'hr.accr_rounding': 'Rounding',
@@ -148,6 +153,7 @@ export const en: Record<string, Message> = {
148
153
  'hr.accr_run_title': 'Accrual run',
149
154
  'hr.accr_run_to': 'Period to',
150
155
  'hr.accr_run_total': 'Total',
156
+ 'hr.accr_run_total_note': 'Time, not days: one run can cover policies with different day lengths.',
151
157
  'hr.accr_run_writes':
152
158
  'Crediting writes to the leave ledger. It cannot be undone here — a wrong credit is corrected with a leave adjustment.',
153
159
  'hr.accr_rung_empty': 'Nothing on this rung.',
@@ -652,6 +658,10 @@ export const en: Record<string, Message> = {
652
658
  'hr.employment_intern': 'Intern',
653
659
  'hr.employment_part_time': 'Part time',
654
660
  'hr.employment_temporary': 'Temporary',
661
+ 'hr.filter_clear': 'Show everyone',
662
+ 'hr.filter_department': '{name} and the departments under it',
663
+ 'hr.filter_department_unnamed': 'One department and the departments under it',
664
+ 'hr.filter_office_unnamed': 'One office',
655
665
  'hr.general_country_desc':
656
666
  'Used when the module is switched on: the first office is created in this country and its holiday calendar is seeded from the pack Kern ships for it.',
657
667
  'hr.general_country_hint': 'Offices that already exist keep their own country; change one under Offices.',
@@ -889,6 +899,10 @@ export const en: Record<string, Message> = {
889
899
  'hr.nav': 'People',
890
900
  'hr.no_people': 'Nobody here yet',
891
901
  'hr.no_people_desc': 'Add the first person to start the directory.',
902
+ 'hr.no_people_match': 'Nobody matches',
903
+ 'hr.no_people_match_filtered':
904
+ 'Nobody in this part of the company matches. Show everyone to search the whole directory.',
905
+ 'hr.no_people_match_search': 'No name matches what you typed.',
892
906
  'hr.not_clocked_in': 'Not clocked in',
893
907
  'hr.offboard': 'End employment',
894
908
  'hr.offboard_already': 'This person has already left',
@@ -1001,6 +1015,7 @@ export const en: Record<string, Message> = {
1001
1015
  'hr.offices_timezones': 'Timezones',
1002
1016
  'hr.offices_title': 'Offices',
1003
1017
  'hr.on_break_since': 'On break since {time}',
1018
+ 'hr.on_leave_note': 'Away right now',
1004
1019
  'hr.org_archive_blocked_children': {
1005
1020
  one: 'Its {count} sub-department would be left with no parent. Move or archive it first.',
1006
1021
  other: 'Its {count} sub-departments would be left with no parent. Move or archive them first.',
@@ -1072,7 +1087,7 @@ export const en: Record<string, Message> = {
1072
1087
  'hr.org_root': 'Top level',
1073
1088
  'hr.org_search_label': 'Search departments by name or code',
1074
1089
  'hr.org_search_placeholder': 'Search departments',
1075
- 'hr.org_see_people': { one: 'See the {count} person here', other: 'See the {count} people here' },
1090
+ 'hr.org_see_people': { one: 'See the {count} person', other: 'See the {count} people' },
1076
1091
  'hr.org_stat_levels': 'Levels deep',
1077
1092
  'hr.org_stat_people': 'People placed',
1078
1093
  'hr.org_stat_positions': 'Positions',
@@ -1242,13 +1257,8 @@ export const en: Record<string, Message> = {
1242
1257
  'hr.schedule_saved': 'Schedule saved',
1243
1258
  'hr.schedule_start': 'Start',
1244
1259
  'hr.schedule_time_missing': 'Every working day needs a start and an end.',
1245
- 'hr.schedule_tz_fixed': 'One fixed zone',
1246
- 'hr.schedule_tz_hint': '09:00 is a reading on a clock. This says whose clock.',
1247
- 'hr.schedule_tz_label': 'Zone',
1248
- 'hr.schedule_tz_mode': 'Time zone',
1249
- 'hr.schedule_tz_office': "The person's office",
1250
- 'hr.schedule_tz_person': "The person's own time zone",
1251
- 'hr.schedule_tz_required': 'Choose the zone this schedule is read in.',
1260
+ 'hr.schedule_tz_note':
1261
+ "09:00 means nine o'clock where the person is their primary office's time zone, unless their own profile sets one.",
1252
1262
  'hr.schedule_week': 'Working week',
1253
1263
  'hr.schedule_week_empty': 'Every day is off — there would be nothing to measure.',
1254
1264
  'hr.schedule_week_total': '{hours} a week',
@@ -1357,9 +1367,12 @@ export const ar: Record<string, Message> = {
1357
1367
  'hr.accr_col_policy': 'السياسة',
1358
1368
  'hr.accr_col_when': 'متى',
1359
1369
  'hr.accr_config_unreadable': 'تعذّرت قراءة إعدادات هذه السياسة',
1370
+ 'hr.accr_config_unreadable_form':
1371
+ 'تعذّرت قراءة الإعدادات المحفوظة لهذه السياسة، لذا فالحقول أدناه قيم افتراضية لا ما هو محفوظ. الحفظ سيستبدل المحفوظ بها.',
1360
1372
  'hr.accr_copy_of': '{name} (نسخة)',
1361
1373
  'hr.accr_create_title': 'سياسة استحقاق جديدة',
1362
1374
  'hr.accr_created': 'أُنشئت «{name}»',
1375
+ 'hr.accr_day_is': 'اليوم {length}',
1363
1376
  'hr.accr_day_length': 'طول يوم الإجازة',
1364
1377
  'hr.accr_day_length_hint':
1365
1378
  'بالدقائق — {length}. تُحفظ الأرصدة بالدقائق كي تبقى أنصاف الأيام والإجازة الساعية دقيقة.',
@@ -1390,6 +1403,8 @@ export const ar: Record<string, Message> = {
1390
1403
  'hr.accr_error_name': 'امنح السياسة اسمًا.',
1391
1404
  'hr.accr_error_pick_policy': 'اختر سياسة.',
1392
1405
  'hr.accr_error_pick_subject': 'اختر من تنطبق عليه.',
1406
+ 'hr.accr_error_round_cap':
1407
+ 'لا يمكن أن تتجاوز خطوة التقريب {max}، لذا لا يصلح اليوم الكامل خطوةً في يوم بهذا الطول.',
1393
1408
  'hr.accr_error_tier_clash': 'درجتان تبدآن عند العدد نفسه من السنوات.',
1394
1409
  'hr.accr_error_to_before_from': 'تاريخ الانتهاء قبل تاريخ البدء.',
1395
1410
  'hr.accr_freq_anniversary': 'في كل ذكرى سنوية للتعيين',
@@ -1436,9 +1451,9 @@ export const ar: Record<string, Message> = {
1436
1451
  'تحدّد السياسة كم يمنح العام من أيام، ومتى تظهر، وكيف تُقرَّب. ولا يستحق أحد شيئًا قبل أن تُسنَد إليه سياسة.',
1437
1452
  'hr.accr_preview_error': 'تعذّر حساب المعاينة',
1438
1453
  'hr.accr_readonly': 'يمكنك قراءة هذه الصفحة، لكن تغيير أي شيء يحتاج صلاحية إدارة السياسات.',
1439
- 'hr.accr_round_day': 'يوم كامل',
1454
+ 'hr.accr_round_day': 'يوم كامل ({length})',
1440
1455
  'hr.accr_round_exact': 'بلا تقريب',
1441
- 'hr.accr_round_half_day': 'نصف يوم',
1456
+ 'hr.accr_round_half_day': 'نصف يوم ({length})',
1442
1457
  'hr.accr_round_minutes': {
1443
1458
  zero: '{count} دقيقة',
1444
1459
  one: 'دقيقة واحدة',
@@ -1499,6 +1514,7 @@ export const ar: Record<string, Message> = {
1499
1514
  'hr.accr_run_title': 'تشغيل الاستحقاق',
1500
1515
  'hr.accr_run_to': 'الفترة إلى',
1501
1516
  'hr.accr_run_total': 'الإجمالي',
1517
+ 'hr.accr_run_total_note': 'وقت لا أيام: قد يشمل التشغيل الواحد سياسات بأطوال أيام مختلفة.',
1502
1518
  'hr.accr_run_writes':
1503
1519
  'الإضافة تُكتب في دفتر الإجازات. ولا يمكن التراجع عنها من هنا — تُصحَّح الإضافة الخاطئة بتسوية إجازة.',
1504
1520
  'hr.accr_rung_empty': 'لا شيء على هذه الدرجة.',
@@ -2040,6 +2056,10 @@ export const ar: Record<string, Message> = {
2040
2056
  'hr.employment_intern': 'متدرب',
2041
2057
  'hr.employment_part_time': 'دوام جزئي',
2042
2058
  'hr.employment_temporary': 'مؤقت',
2059
+ 'hr.filter_clear': 'عرض الجميع',
2060
+ 'hr.filter_department': '{name} والأقسام التابعة لها',
2061
+ 'hr.filter_department_unnamed': 'قسم واحد والأقسام التابعة له',
2062
+ 'hr.filter_office_unnamed': 'مكتب واحد',
2043
2063
  'hr.general_country_desc':
2044
2064
  'يُستخدم عند تشغيل الوحدة: يُنشأ المكتب الأول في هذه الدولة ويُملأ تقويم عطلاته من حزمة الدولة نفسها.',
2045
2065
  'hr.general_country_hint': 'المكاتب الموجودة تحتفظ بدولتها؛ لتغيير أحدها انتقل إلى المكاتب.',
@@ -2328,6 +2348,9 @@ export const ar: Record<string, Message> = {
2328
2348
  'hr.nav': 'الأشخاص',
2329
2349
  'hr.no_people': 'لا يوجد أحد هنا بعد',
2330
2350
  'hr.no_people_desc': 'أضف أول شخص لتبدأ القائمة.',
2351
+ 'hr.no_people_match': 'لا أحد مطابق',
2352
+ 'hr.no_people_match_filtered': 'لا أحد في هذا الجزء من الشركة مطابق. اعرض الجميع للبحث في الدليل كله.',
2353
+ 'hr.no_people_match_search': 'لا يوجد اسم مطابق لما كتبته.',
2331
2354
  'hr.not_clocked_in': 'لم يُسجَّل الحضور',
2332
2355
  'hr.offboard': 'إنهاء التوظيف',
2333
2356
  'hr.offboard_already': 'غادر هذا الشخص بالفعل',
@@ -2441,6 +2464,7 @@ export const ar: Record<string, Message> = {
2441
2464
  'hr.offices_timezones': 'المناطق الزمنية',
2442
2465
  'hr.offices_title': 'المكاتب',
2443
2466
  'hr.on_break_since': 'في استراحة منذ {time}',
2467
+ 'hr.on_leave_note': 'غائبون الآن',
2444
2468
  'hr.org_archive_blocked_children': {
2445
2469
  zero: 'سيبقى {count} أقسام فرعية بلا قسم أعلى. انقلها أو أرشفها أولًا.',
2446
2470
  one: 'سيبقى قسم فرعي واحد بلا قسم أعلى. انقله أو أرشفه أولًا.',
@@ -2534,12 +2558,12 @@ export const ar: Record<string, Message> = {
2534
2558
  'hr.org_search_label': 'ابحث في الأقسام بالاسم أو الرمز',
2535
2559
  'hr.org_search_placeholder': 'ابحث في الأقسام',
2536
2560
  'hr.org_see_people': {
2537
- zero: 'عرض {count} أشخاص هنا',
2538
- one: 'عرض شخص واحد هنا',
2539
- two: 'عرض شخصين هنا',
2540
- few: 'عرض {count} أشخاص هنا',
2541
- many: 'عرض {count} شخصًا هنا',
2542
- other: 'عرض {count} شخص هنا',
2561
+ zero: 'عرض {count} أشخاص',
2562
+ one: 'عرض شخص واحد',
2563
+ two: 'عرض شخصين',
2564
+ few: 'عرض {count} أشخاص',
2565
+ many: 'عرض {count} شخصًا',
2566
+ other: 'عرض {count} شخص',
2543
2567
  },
2544
2568
  'hr.org_stat_levels': 'المستويات',
2545
2569
  'hr.org_stat_people': 'الأشخاص المُسنَدون',
@@ -2714,13 +2738,8 @@ export const ar: Record<string, Message> = {
2714
2738
  'hr.schedule_saved': 'تم حفظ المناوبة',
2715
2739
  'hr.schedule_start': 'البداية',
2716
2740
  'hr.schedule_time_missing': 'كل يوم عمل يحتاج إلى بداية ونهاية.',
2717
- 'hr.schedule_tz_fixed': 'منطقة واحدة ثابتة',
2718
- 'hr.schedule_tz_hint': '٠٩:٠٠ قراءة على ساعة. وهذا يحدد ساعة مَن.',
2719
- 'hr.schedule_tz_label': 'المنطقة',
2720
- 'hr.schedule_tz_mode': 'المنطقة الزمنية',
2721
- 'hr.schedule_tz_office': 'مكتب الشخص',
2722
- 'hr.schedule_tz_person': 'المنطقة الزمنية الخاصة بالشخص',
2723
- 'hr.schedule_tz_required': 'اختر المنطقة التي تُقرأ بها هذه المناوبة.',
2741
+ 'hr.schedule_tz_note':
2742
+ '٠٩:٠٠ تعني التاسعة في المكان الذي يوجد فيه الشخص: المنطقة الزمنية لمكتبه الأساسي، ما لم يحدّد ملفه منطقة خاصة به.',
2724
2743
  'hr.schedule_week': 'أسبوع العمل',
2725
2744
  'hr.schedule_week_empty': 'كل الأيام متوقفة — لن يبقى شيء يُقاس.',
2726
2745
  'hr.schedule_week_total': '{hours} في الأسبوع',
@@ -2823,9 +2842,12 @@ export const de: Record<string, Message> = {
2823
2842
  'hr.accr_col_policy': 'Regel',
2824
2843
  'hr.accr_col_when': 'Wann',
2825
2844
  'hr.accr_config_unreadable': 'Die Einstellungen dieser Regel sind nicht lesbar',
2845
+ 'hr.accr_config_unreadable_form':
2846
+ 'Die gespeicherten Einstellungen dieser Regel konnten nicht gelesen werden. Die Felder unten zeigen Standardwerte, nicht das Gespeicherte — Speichern ersetzt es dadurch.',
2826
2847
  'hr.accr_copy_of': '{name} (Kopie)',
2827
2848
  'hr.accr_create_title': 'Neue Anspruchsregel',
2828
2849
  'hr.accr_created': '„{name}“ wurde angelegt',
2850
+ 'hr.accr_day_is': 'ein Tag sind {length}',
2829
2851
  'hr.accr_day_length': 'Länge eines Urlaubstags',
2830
2852
  'hr.accr_day_length_hint':
2831
2853
  'In Minuten — {length}. Guthaben werden in Minuten geführt, damit halbe Tage und stundenweiser Urlaub exakt bleiben.',
@@ -2849,6 +2871,8 @@ export const de: Record<string, Message> = {
2849
2871
  'hr.accr_error_name': 'Geben Sie der Regel einen Namen.',
2850
2872
  'hr.accr_error_pick_policy': 'Wählen Sie eine Regel.',
2851
2873
  'hr.accr_error_pick_subject': 'Wählen Sie, für wen sie gilt.',
2874
+ 'hr.accr_error_round_cap':
2875
+ 'Ein Rundungsschritt darf nicht länger als {max} sein — bei einem so langen Tag ist ein ganzer Tag daher keiner.',
2852
2876
  'hr.accr_error_tier_clash': 'Zwei Stufen beginnen bei derselben Anzahl Jahre.',
2853
2877
  'hr.accr_error_to_before_from': 'Das Enddatum liegt vor dem Startdatum.',
2854
2878
  'hr.accr_freq_anniversary': 'An jedem Eintrittsjahrestag',
@@ -2898,9 +2922,9 @@ export const de: Record<string, Message> = {
2898
2922
  'hr.accr_preview_error': 'Die Vorschau konnte nicht berechnet werden',
2899
2923
  'hr.accr_readonly':
2900
2924
  'Sie können diese Seite lesen; zum Ändern brauchen Sie die Berechtigung, Regeln zu verwalten.',
2901
- 'hr.accr_round_day': 'Ein ganzer Tag',
2925
+ 'hr.accr_round_day': 'Ein ganzer Tag ({length})',
2902
2926
  'hr.accr_round_exact': 'Keine Rundung',
2903
- 'hr.accr_round_half_day': 'Ein halber Tag',
2927
+ 'hr.accr_round_half_day': 'Ein halber Tag ({length})',
2904
2928
  'hr.accr_round_minutes': { one: '{count} Minute', other: '{count} Minuten' },
2905
2929
  'hr.accr_round_short': 'auf {step} gerundet',
2906
2930
  'hr.accr_rounding': 'Rundung',
@@ -2929,6 +2953,7 @@ export const de: Record<string, Message> = {
2929
2953
  'hr.accr_run_title': 'Anspruchslauf',
2930
2954
  'hr.accr_run_to': 'Zeitraum bis',
2931
2955
  'hr.accr_run_total': 'Gesamt',
2956
+ 'hr.accr_run_total_note': 'Zeit, keine Tage: ein Lauf kann Regeln mit verschiedenen Taglängen umfassen.',
2932
2957
  'hr.accr_run_writes':
2933
2958
  'Die Gutschrift wird in das Urlaubskonto geschrieben. Hier ist sie nicht rückgängig zu machen — eine falsche Gutschrift wird über eine Urlaubskorrektur berichtigt.',
2934
2959
  'hr.accr_rung_empty': 'Auf dieser Stufe liegt nichts.',
@@ -3457,6 +3482,10 @@ export const de: Record<string, Message> = {
3457
3482
  'hr.employment_intern': 'Praktikum',
3458
3483
  'hr.employment_part_time': 'Teilzeit',
3459
3484
  'hr.employment_temporary': 'Befristet',
3485
+ 'hr.filter_clear': 'Alle anzeigen',
3486
+ 'hr.filter_department': '{name} und die Abteilungen darunter',
3487
+ 'hr.filter_department_unnamed': 'Eine Abteilung und die Abteilungen darunter',
3488
+ 'hr.filter_office_unnamed': 'Ein Standort',
3460
3489
  'hr.general_country_desc':
3461
3490
  'Wird beim Einschalten des Moduls verwendet: Der erste Standort entsteht in diesem Land, und sein Feiertagskalender wird aus dem Paket für dieses Land befüllt.',
3462
3491
  'hr.general_country_hint':
@@ -3703,6 +3732,10 @@ export const de: Record<string, Message> = {
3703
3732
  'hr.nav': 'Personen',
3704
3733
  'hr.no_people': 'Noch keine Personen',
3705
3734
  'hr.no_people_desc': 'Fügen Sie die erste Person hinzu, um das Verzeichnis aufzubauen.',
3735
+ 'hr.no_people_match': 'Niemand passt',
3736
+ 'hr.no_people_match_filtered':
3737
+ 'In diesem Teil des Unternehmens passt niemand. Zeigen Sie alle an, um das ganze Verzeichnis zu durchsuchen.',
3738
+ 'hr.no_people_match_search': 'Kein Name passt zu Ihrer Eingabe.',
3706
3739
  'hr.not_clocked_in': 'Nicht eingestempelt',
3707
3740
  'hr.offboard': 'Beschäftigung beenden',
3708
3741
  'hr.offboard_already': 'Diese Person ist bereits ausgeschieden',
@@ -3818,6 +3851,7 @@ export const de: Record<string, Message> = {
3818
3851
  'hr.offices_timezones': 'Zeitzonen',
3819
3852
  'hr.offices_title': 'Standorte',
3820
3853
  'hr.on_break_since': 'Seit {time} in der Pause',
3854
+ 'hr.on_leave_note': 'Gerade abwesend',
3821
3855
  'hr.org_archive_blocked_children': {
3822
3856
  one: 'Ihre {count} Unterabteilung bliebe ohne übergeordnete Abteilung. Verschieben oder archivieren Sie sie zuerst.',
3823
3857
  other:
@@ -3897,7 +3931,7 @@ export const de: Record<string, Message> = {
3897
3931
  'hr.org_root': 'Oberste Ebene',
3898
3932
  'hr.org_search_label': 'Abteilungen nach Name oder Kürzel durchsuchen',
3899
3933
  'hr.org_search_placeholder': 'Abteilungen durchsuchen',
3900
- 'hr.org_see_people': { one: 'Die {count} Person hier ansehen', other: 'Die {count} Personen hier ansehen' },
3934
+ 'hr.org_see_people': { one: 'Die {count} Person ansehen', other: 'Die {count} Personen ansehen' },
3901
3935
  'hr.org_stat_levels': 'Ebenen',
3902
3936
  'hr.org_stat_people': 'Zugeordnete Personen',
3903
3937
  'hr.org_stat_positions': 'Stellen',
@@ -4070,13 +4104,8 @@ export const de: Record<string, Message> = {
4070
4104
  'hr.schedule_saved': 'Arbeitszeitmodell gespeichert',
4071
4105
  'hr.schedule_start': 'Beginn',
4072
4106
  'hr.schedule_time_missing': 'Jeder Arbeitstag braucht einen Beginn und ein Ende.',
4073
- 'hr.schedule_tz_fixed': 'Eine feste Zone',
4074
- 'hr.schedule_tz_hint': '09:00 ist eine Uhrzeit. Hier steht, wessen Uhr gemeint ist.',
4075
- 'hr.schedule_tz_label': 'Zone',
4076
- 'hr.schedule_tz_mode': 'Zeitzone',
4077
- 'hr.schedule_tz_office': 'Der Standort der Person',
4078
- 'hr.schedule_tz_person': 'Die eigene Zeitzone der Person',
4079
- 'hr.schedule_tz_required': 'Wählen Sie die Zone, in der dieses Modell gelesen wird.',
4107
+ 'hr.schedule_tz_note':
4108
+ '09:00 heißt neun Uhr dort, wo die Person ist die Zeitzone ihres primären Standorts, sofern ihr Profil keine eigene angibt.',
4080
4109
  'hr.schedule_week': 'Arbeitswoche',
4081
4110
  'hr.schedule_week_empty': 'Alle Tage sind frei — es gäbe nichts zu messen.',
4082
4111
  'hr.schedule_week_total': '{hours} pro Woche',
@@ -4182,9 +4211,12 @@ export const fa: Record<string, Message> = {
4182
4211
  'hr.accr_col_policy': 'قاعده',
4183
4212
  'hr.accr_col_when': 'کِی',
4184
4213
  'hr.accr_config_unreadable': 'تنظیمات این قاعده خوانده نمی‌شود',
4214
+ 'hr.accr_config_unreadable_form':
4215
+ 'تنظیمات ذخیره‌شدهٔ این سیاست خوانده نشد؛ بنابراین فیلدهای زیر مقدارهای پیش‌فرض‌اند، نه آنچه ذخیره شده. ذخیره‌کردن، تنظیمات ذخیره‌شده را با همین‌ها جایگزین می‌کند.',
4185
4216
  'hr.accr_copy_of': '{name} (رونوشت)',
4186
4217
  'hr.accr_create_title': 'قاعدهٔ انباشت تازه',
4187
4218
  'hr.accr_created': '«{name}» ساخته شد',
4219
+ 'hr.accr_day_is': 'هر روز {length}',
4188
4220
  'hr.accr_day_length': 'طول یک روز مرخصی',
4189
4221
  'hr.accr_day_length_hint':
4190
4222
  'به دقیقه — {length}. مانده‌ها به دقیقه نگه داشته می‌شوند تا نیم‌روز و مرخصی ساعتی دقیق بماند.',
@@ -4208,6 +4240,8 @@ export const fa: Record<string, Message> = {
4208
4240
  'hr.accr_error_name': 'به قاعده نامی بدهید.',
4209
4241
  'hr.accr_error_pick_policy': 'یک قاعده انتخاب کنید.',
4210
4242
  'hr.accr_error_pick_subject': 'انتخاب کنید برای چه کسی است.',
4243
+ 'hr.accr_error_round_cap':
4244
+ 'گام گِردکردن نمی‌تواند بیش از {max} باشد؛ پس در روزی به این بلندی، یک روز کامل گام معتبری نیست.',
4211
4245
  'hr.accr_error_tier_clash': 'دو پله از یک تعداد سال یکسان شروع می‌شوند.',
4212
4246
  'hr.accr_error_to_before_from': 'تاریخ پایان پیش از تاریخ شروع است.',
4213
4247
  'hr.accr_freq_anniversary': 'در هر سالگرد استخدام',
@@ -4254,9 +4288,9 @@ export const fa: Record<string, Message> = {
4254
4288
  'هر قاعده می‌گوید یک سال چقدر مرخصی می‌آورد، کِی اضافه می‌شود و چطور گرد می‌شود. تا قاعده‌ای به کسی داده نشود، چیزی برایش انباشته نمی‌شود.',
4255
4289
  'hr.accr_preview_error': 'پیش‌نمایش محاسبه نشد',
4256
4290
  'hr.accr_readonly': 'این صفحه را می‌بینید، اما تغییر هر چیزی به دسترسی مدیریت قاعده‌ها نیاز دارد.',
4257
- 'hr.accr_round_day': 'یک روز کامل',
4291
+ 'hr.accr_round_day': 'یک روز کامل ({length})',
4258
4292
  'hr.accr_round_exact': 'بدون گردکردن',
4259
- 'hr.accr_round_half_day': 'نیم‌روز',
4293
+ 'hr.accr_round_half_day': 'نیم‌روز ({length})',
4260
4294
  'hr.accr_round_minutes': { one: '{count} دقیقه', other: '{count} دقیقه' },
4261
4295
  'hr.accr_round_short': 'گرد شده به {step}',
4262
4296
  'hr.accr_rounding': 'گردکردن',
@@ -4285,6 +4319,7 @@ export const fa: Record<string, Message> = {
4285
4319
  'hr.accr_run_title': 'اجرای انباشت',
4286
4320
  'hr.accr_run_to': 'دوره تا',
4287
4321
  'hr.accr_run_total': 'جمع',
4322
+ 'hr.accr_run_total_note': 'زمان است، نه روز: یک اجرا می‌تواند سیاست‌هایی با طول روز متفاوت را دربر بگیرد.',
4288
4323
  'hr.accr_run_writes':
4289
4324
  'اضافه‌کردن در دفتر مرخصی نوشته می‌شود. از اینجا برگشت‌پذیر نیست — اضافهٔ اشتباه با یک اصلاح مرخصی جبران می‌شود.',
4290
4325
  'hr.accr_rung_empty': 'روی این پله چیزی نیست.',
@@ -4782,6 +4817,10 @@ export const fa: Record<string, Message> = {
4782
4817
  'hr.employment_intern': 'کارآموز',
4783
4818
  'hr.employment_part_time': 'پاره‌وقت',
4784
4819
  'hr.employment_temporary': 'موقت',
4820
+ 'hr.filter_clear': 'نمایش همه',
4821
+ 'hr.filter_department': '{name} و واحدهای زیرمجموعه',
4822
+ 'hr.filter_department_unnamed': 'یک واحد و واحدهای زیرمجموعه',
4823
+ 'hr.filter_office_unnamed': 'یک دفتر',
4785
4824
  'hr.general_country_desc':
4786
4825
  'وقتی ماژول روشن می‌شود از این مقدار استفاده می‌شود: نخستین دفتر در همین کشور ساخته و تقویم تعطیلاتش از بستهٔ همان کشور پر می‌شود.',
4787
4826
  'hr.general_country_hint':
@@ -5019,6 +5058,10 @@ export const fa: Record<string, Message> = {
5019
5058
  'hr.nav': 'افراد',
5020
5059
  'hr.no_people': 'هنوز کسی نیست',
5021
5060
  'hr.no_people_desc': 'اولین نفر را اضافه کنید تا فهرست شروع شود.',
5061
+ 'hr.no_people_match': 'کسی پیدا نشد',
5062
+ 'hr.no_people_match_filtered':
5063
+ 'در این بخش از شرکت کسی پیدا نشد. برای جست‌وجو در کل فهرست، همه را نمایش دهید.',
5064
+ 'hr.no_people_match_search': 'هیچ نامی با آنچه نوشتید مطابقت ندارد.',
5022
5065
  'hr.not_clocked_in': 'ورود نزده',
5023
5066
  'hr.offboard': 'پایان همکاری',
5024
5067
  'hr.offboard_already': 'این فرد قبلاً رفته است',
@@ -5130,6 +5173,7 @@ export const fa: Record<string, Message> = {
5130
5173
  'hr.offices_timezones': 'منطقه‌های زمانی',
5131
5174
  'hr.offices_title': 'دفاتر',
5132
5175
  'hr.on_break_since': 'از {time} در استراحت',
5176
+ 'hr.on_leave_note': 'همین حالا در مرخصی',
5133
5177
  'hr.org_archive_blocked_children': {
5134
5178
  one: '{count} زیرواحد بی‌سرپرست می‌ماند. اول آن‌ها را جابه‌جا یا بایگانی کنید.',
5135
5179
  other: '{count} زیرواحد بی‌سرپرست می‌ماند. اول آن‌ها را جابه‌جا یا بایگانی کنید.',
@@ -5203,7 +5247,7 @@ export const fa: Record<string, Message> = {
5203
5247
  'hr.org_root': 'بالاترین سطح',
5204
5248
  'hr.org_search_label': 'جست‌وجوی واحدها بر پایهٔ نام یا کد',
5205
5249
  'hr.org_search_placeholder': 'جست‌وجوی واحدها',
5206
- 'hr.org_see_people': { one: 'دیدن {count} نفر اینجا', other: 'دیدن {count} نفر اینجا' },
5250
+ 'hr.org_see_people': { one: 'دیدن {count} نفر', other: 'دیدن {count} نفر' },
5207
5251
  'hr.org_stat_levels': 'عمق چارت',
5208
5252
  'hr.org_stat_people': 'افراد جای‌گرفته',
5209
5253
  'hr.org_stat_positions': 'سمت‌ها',
@@ -5373,13 +5417,8 @@ export const fa: Record<string, Message> = {
5373
5417
  'hr.schedule_saved': 'شیفت ذخیره شد',
5374
5418
  'hr.schedule_start': 'شروع',
5375
5419
  'hr.schedule_time_missing': 'هر روز کاری باید شروع و پایان داشته باشد.',
5376
- 'hr.schedule_tz_fixed': 'یک منطقهٔ ثابت',
5377
- 'hr.schedule_tz_hint': '۰۹:۰۰ خواندن یک ساعت است. این می‌گوید ساعتِ چه کسی.',
5378
- 'hr.schedule_tz_label': 'منطقه',
5379
- 'hr.schedule_tz_mode': 'منطقهٔ زمانی',
5380
- 'hr.schedule_tz_office': 'دفتر فرد',
5381
- 'hr.schedule_tz_person': 'منطقهٔ زمانی خود فرد',
5382
- 'hr.schedule_tz_required': 'منطقه‌ای را که این شیفت با آن خوانده می‌شود انتخاب کنید.',
5420
+ 'hr.schedule_tz_note':
5421
+ '۰۹:۰۰ یعنی ساعت نُه در جایی که فرد هست: منطقهٔ زمانی دفتر اصلی او، مگر آنکه در نمایه‌اش منطقهٔ خودش تعیین شده باشد.',
5383
5422
  'hr.schedule_week': 'هفتهٔ کاری',
5384
5423
  'hr.schedule_week_empty': 'همهٔ روزها خاموش‌اند — چیزی برای سنجیدن نمی‌ماند.',
5385
5424
  'hr.schedule_week_total': 'هفته‌ای {hours}',
@@ -5481,9 +5520,12 @@ export const tr: Record<string, Message> = {
5481
5520
  'hr.accr_col_policy': 'Kural',
5482
5521
  'hr.accr_col_when': 'Ne zaman',
5483
5522
  'hr.accr_config_unreadable': 'Bu kuralın ayarları okunamıyor',
5523
+ 'hr.accr_config_unreadable_form':
5524
+ 'Bu politikanın kayıtlı ayarları okunamadı; aşağıdaki alanlar kayıtlı değerler değil, varsayılanlardır. Kaydetmek, kayıtlı ayarların yerine bunları yazar.',
5484
5525
  'hr.accr_copy_of': '{name} (kopya)',
5485
5526
  'hr.accr_create_title': 'Yeni hakediş kuralı',
5486
5527
  'hr.accr_created': '"{name}" oluşturuldu',
5528
+ 'hr.accr_day_is': 'bir gün {length}',
5487
5529
  'hr.accr_day_length': 'Bir izin gününün uzunluğu',
5488
5530
  'hr.accr_day_length_hint':
5489
5531
  'Dakika olarak — {length}. Bakiyeler dakika tutulur; böylece yarım günler ve saatlik izin tam kalır.',
@@ -5507,6 +5549,8 @@ export const tr: Record<string, Message> = {
5507
5549
  'hr.accr_error_name': 'Kurala bir ad verin.',
5508
5550
  'hr.accr_error_pick_policy': 'Bir kural seçin.',
5509
5551
  'hr.accr_error_pick_subject': 'Kime uygulanacağını seçin.',
5552
+ 'hr.accr_error_round_cap':
5553
+ 'Yuvarlama adımı {max} değerinden uzun olamaz; bu kadar uzun bir günde tam gün adım olamaz.',
5510
5554
  'hr.accr_error_tier_clash': 'İki kademe aynı yıl sayısında başlıyor.',
5511
5555
  'hr.accr_error_to_before_from': 'Bitiş tarihi başlangıç tarihinden önce.',
5512
5556
  'hr.accr_freq_anniversary': 'Her işe giriş yıl dönümünde',
@@ -5554,9 +5598,9 @@ export const tr: Record<string, Message> = {
5554
5598
  'hr.accr_preview_error': 'Önizleme hesaplanamadı',
5555
5599
  'hr.accr_readonly':
5556
5600
  'Bu sayfayı okuyabilirsiniz, ama bir şeyi değiştirmek için kuralları yönetme yetkisi gerekir.',
5557
- 'hr.accr_round_day': 'Tam gün',
5601
+ 'hr.accr_round_day': 'Tam bir gün ({length})',
5558
5602
  'hr.accr_round_exact': 'Yuvarlama yok',
5559
- 'hr.accr_round_half_day': 'Yarım gün',
5603
+ 'hr.accr_round_half_day': 'Yarım gün ({length})',
5560
5604
  'hr.accr_round_minutes': { one: '{count} dakika', other: '{count} dakika' },
5561
5605
  'hr.accr_round_short': '{step} adımına yuvarlanır',
5562
5606
  'hr.accr_rounding': 'Yuvarlama',
@@ -5585,6 +5629,8 @@ export const tr: Record<string, Message> = {
5585
5629
  'hr.accr_run_title': 'Hakediş çalıştırma',
5586
5630
  'hr.accr_run_to': 'Dönem sonu',
5587
5631
  'hr.accr_run_total': 'Toplam',
5632
+ 'hr.accr_run_total_note':
5633
+ 'Gün değil, süre: tek bir çalıştırma farklı gün uzunluklarına sahip politikaları kapsayabilir.',
5588
5634
  'hr.accr_run_writes':
5589
5635
  'Ekleme, izin defterine yazar. Buradan geri alınamaz; yanlış bir ekleme izin düzeltmesiyle giderilir.',
5590
5636
  'hr.accr_rung_empty': 'Bu basamakta bir şey yok.',
@@ -6084,6 +6130,10 @@ export const tr: Record<string, Message> = {
6084
6130
  'hr.employment_intern': 'Stajyer',
6085
6131
  'hr.employment_part_time': 'Yarı zamanlı',
6086
6132
  'hr.employment_temporary': 'Geçici',
6133
+ 'hr.filter_clear': 'Herkesi göster',
6134
+ 'hr.filter_department': '{name} ve altındaki departmanlar',
6135
+ 'hr.filter_department_unnamed': 'Bir departman ve altındaki departmanlar',
6136
+ 'hr.filter_office_unnamed': 'Bir ofis',
6087
6137
  'hr.general_country_desc':
6088
6138
  'Modül açıldığında kullanılır: ilk ofis bu ülkede oluşturulur ve tatil takvimi bu ülke için hazırlanan paketten doldurulur.',
6089
6139
  'hr.general_country_hint':
@@ -6326,6 +6376,10 @@ export const tr: Record<string, Message> = {
6326
6376
  'hr.nav': 'Kişiler',
6327
6377
  'hr.no_people': 'Henüz kimse yok',
6328
6378
  'hr.no_people_desc': 'Rehberi başlatmak için ilk kişiyi ekleyin.',
6379
+ 'hr.no_people_match': 'Eşleşen kimse yok',
6380
+ 'hr.no_people_match_filtered':
6381
+ 'Şirketin bu bölümünde eşleşen kimse yok. Tüm rehberde aramak için herkesi gösterin.',
6382
+ 'hr.no_people_match_search': 'Yazdığınızla eşleşen bir ad yok.',
6329
6383
  'hr.not_clocked_in': 'Giriş yapılmadı',
6330
6384
  'hr.offboard': 'İşi bitir',
6331
6385
  'hr.offboard_already': 'Bu kişi zaten ayrıldı',
@@ -6438,6 +6492,7 @@ export const tr: Record<string, Message> = {
6438
6492
  'hr.offices_timezones': 'Saat dilimi',
6439
6493
  'hr.offices_title': 'Ofisler',
6440
6494
  'hr.on_break_since': '{time} saatinden beri molada',
6495
+ 'hr.on_leave_note': 'Şu anda izinde',
6441
6496
  'hr.org_archive_blocked_children': {
6442
6497
  one: 'Altındaki {count} departman bağlısız kalır. Önce onu taşıyın veya arşivleyin.',
6443
6498
  other: 'Altındaki {count} departman bağlısız kalır. Önce onları taşıyın veya arşivleyin.',
@@ -6509,7 +6564,7 @@ export const tr: Record<string, Message> = {
6509
6564
  'hr.org_root': 'En üst kademe',
6510
6565
  'hr.org_search_label': 'Departmanları ada veya koda göre ara',
6511
6566
  'hr.org_search_placeholder': 'Departman ara',
6512
- 'hr.org_see_people': { one: 'Buradaki {count} kişiyi gör', other: 'Buradaki {count} kişiyi gör' },
6567
+ 'hr.org_see_people': { one: '{count} kişiyi gör', other: '{count} kişiyi gör' },
6513
6568
  'hr.org_stat_levels': 'Kademe',
6514
6569
  'hr.org_stat_people': 'Yerleştirilen kişi',
6515
6570
  'hr.org_stat_positions': 'Pozisyonlar',
@@ -6679,13 +6734,8 @@ export const tr: Record<string, Message> = {
6679
6734
  'hr.schedule_saved': 'Vardiya kaydedildi',
6680
6735
  'hr.schedule_start': 'Başlangıç',
6681
6736
  'hr.schedule_time_missing': 'Her çalışma gününün bir başlangıcı ve bitişi olmalı.',
6682
- 'hr.schedule_tz_fixed': 'Tek bir sabit dilim',
6683
- 'hr.schedule_tz_hint': '09:00 bir saat okumasıdır. Bu, kimin saati olduğunu söyler.',
6684
- 'hr.schedule_tz_label': 'Dilim',
6685
- 'hr.schedule_tz_mode': 'Saat dilimi',
6686
- 'hr.schedule_tz_office': 'Kişinin ofisi',
6687
- 'hr.schedule_tz_person': 'Kişinin kendi saat dilimi',
6688
- 'hr.schedule_tz_required': 'Bu vardiyanın okunacağı dilimi seçin.',
6737
+ 'hr.schedule_tz_note':
6738
+ '09:00, kişinin bulunduğu yerde saat dokuz demektir: profilinde kendi saat dilimi yazılı değilse birincil ofisinin dilimi geçerlidir.',
6689
6739
  'hr.schedule_week': 'Çalışma haftası',
6690
6740
  'hr.schedule_week_empty': 'Bütün günler kapalı — ölçülecek bir şey kalmaz.',
6691
6741
  'hr.schedule_week_total': 'Haftada {hours}',
@@ -18,6 +18,7 @@ import { getHrApi } from '../api-instance.js'
18
18
  import ClockControls from '../components/ClockControls.svelte'
19
19
  import DayDetail from '../components/DayDetail.svelte'
20
20
  import { t } from '../i18n.js'
21
+ import { canHr } from '../permissions.js'
21
22
  import { formatDuration, hrKeys, monthRange } from '../query.js'
22
23
 
23
24
  /**
@@ -47,6 +48,26 @@ const workspaceId = $derived(workspace?.id ?? '')
47
48
 
48
49
  const range = $derived(monthRange())
49
50
 
51
+ /**
52
+ * The clock is the punch permission, and nothing else on this page is.
53
+ *
54
+ * `hr.attendance.view` is what opens this route — reading your own month — while every one of the
55
+ * four transitions behind `ClockControls` is `requires('hr.attendance.punch')` on the server. A
56
+ * workspace revokes that from somebody whose punches arrive from a badge terminal or from their
57
+ * manager, and for them the clock row was a set of buttons that can only answer 403 — an offer the
58
+ * product cannot honour.
59
+ *
60
+ * Hidden rather than disabled-with-a-reason, because this is a permission and not a state: they may
61
+ * never do it, there is nothing to wait for, and "you cannot clock in" repeated on every visit
62
+ * teaches nothing. It is also the same answer the dashboard already gives — `module.ts` declares the
63
+ * clock widget with `permission: attendancePunch`, so the shell has always hidden this exact
64
+ * component for these people. The page was the one place it leaked.
65
+ *
66
+ * The status line goes with the buttons it captions; the month underneath is what a viewer keeps,
67
+ * and today is a row in it.
68
+ */
69
+ const canPunch = $derived(canHr('attendancePunch'))
70
+
50
71
  const daysQuery = createQuery(() => ({
51
72
  queryKey: hrKeys.attendanceDays(workspaceId, undefined, range.from, range.to),
52
73
  enabled: Boolean(workspaceId),
@@ -168,7 +189,9 @@ const dayLabel = (iso: string) =>
168
189
  {/snippet}
169
190
 
170
191
  <Page>
171
- <ClockControls {workspaceId} />
192
+ {#if canPunch}
193
+ <ClockControls {workspaceId} />
194
+ {/if}
172
195
 
173
196
  {#if totalsUnknown}
174
197
  {@render tilesUnknown()}