Check, format and test / build (push) Successful in 10m27s
Employee names are now cached locally (employees.toml, keyed by reader
index then employee id) instead of being re-fetched from the time
clock on every month: load_employees only asks the device for ids not
already in the cache. When a month has employees the cache doesn't
know yet, a new screen (NewEmployees.svelte) lets the user name them
before continuing to the review screen; the chosen names are local to
Oxibadge only, never written back to the device. The same cache can be
managed afterwards from a drawer reachable from the time clock card in
Settings ("Gestisci dipendenti"), reusing the rename-in-row pattern
from the original mockup.
Settings.readers is a list again (was flattened to a single `reader`
object) so multiple time clocks can be supported later; only the first
one is used today.
Also:
- buildEmployees() now derives the employee list from the month's
records instead of from every cached name ever seen, so the review
screen no longer shows employees unrelated to the selected month.
- Renaming an employee from the review screen's pencil button now
actually persists to the cache (the callback existed but was never
wired up).
- Translated to English a number of Rust/TS/Svelte comments that had
been written in Italian; only the i18n locale files should contain
Italian.
- Minor dedup: extracted PillButton.svelte (was duplicated inline in
ReaderCard), promoted the repeated .mono CSS rule to app.css, moved
initials() out of the review feature into $lib/text.ts.
Assisted-by: Claude Sonnet 5 <noreply@anthropic.com>
183 lines
7.7 KiB
JSON
183 lines
7.7 KiB
JSON
{
|
||
"loading": "Loading...",
|
||
"onboarding": {
|
||
"title": "Welcome!",
|
||
"subtitle": "Connect Oxibadge to your time clock by entering its IP address and port.",
|
||
"host_label": "IP address",
|
||
"port_label": "Port",
|
||
"hint": "You can find the address in the time clock's network settings.",
|
||
"button": {
|
||
"idle": "Test connection",
|
||
"testing": "Connecting...",
|
||
"retry": "Retry"
|
||
}
|
||
},
|
||
"confirm_month": {
|
||
"title": "Confirm the month",
|
||
"subtitle": "You're about to confirm this month's clock-ins. Tap the month or year to change them.",
|
||
"change_month_aria": "Month: {month}, change",
|
||
"change_year_aria": "Year: {year}, change",
|
||
"close_aria": "Close selection",
|
||
"choose_month_aria": "Choose the month",
|
||
"choose_year_aria": "Choose the year",
|
||
"month_option_aria": "{month} {year}",
|
||
"button": "Go to clock-ins"
|
||
},
|
||
"loading_records": {
|
||
"title": "Downloading clock-ins...",
|
||
"description": "Reading <strong>{period}</strong>'s clock-ins from the time clock. This can take a few seconds."
|
||
},
|
||
"loading_employees": {
|
||
"title": "Fetching employees...",
|
||
"description": "Reading the employee names registered on the time clock. Just a moment."
|
||
},
|
||
"errors": {
|
||
"title": "Could not reach the time clock"
|
||
},
|
||
"review": {
|
||
"title": "Clock-in review",
|
||
"day_word": "{n, plural, one {1 day} other {{n} days}}",
|
||
"to_check": "to check",
|
||
"to_round": "to round",
|
||
"to_check_cap": "To check",
|
||
"to_round_cap": "To round",
|
||
"shift_1": "1st shift",
|
||
"shift_2": "2nd shift",
|
||
"issue_stacked": "{total} punches all on the {shift}",
|
||
"issue_invalid_time": "Invalid time (use HH:MM)",
|
||
"issue_lunch_missing": "Lunch break not punched",
|
||
"issue_missing_out": "Missing clock-out for the {shift}",
|
||
"issue_missing_in": "Missing clock-in for the {shift}",
|
||
"issue_out_before_in": "Clock-out before clock-in ({shift})",
|
||
"info_unrounded": "Times not rounded to {step} min",
|
||
"note_empty": "No punches",
|
||
"note_lunch_added": "Lunch break added",
|
||
"note_shifts_fixed": "Shifts fixed",
|
||
"note_edited": "{n, plural, one {1 time edited} other {{n} times edited}}",
|
||
"note_rounded": "{n, plural, one {1 time rounded} other {{n} times rounded}}",
|
||
"export_done": "Export completed: {who}",
|
||
"everyone": "all employees",
|
||
"only_unrounded": "{days} with unrounded times",
|
||
"confirm_title_all": "There are {summary}",
|
||
"confirm_title_one": "{name} has {summary}",
|
||
"close_menu_aria": "Close menu",
|
||
"no_records": "No punches found for this month.",
|
||
"back_to_month": "Back to month selection",
|
||
"export": "Export",
|
||
"export_options_aria": "More export options",
|
||
"all_employees": "All employees",
|
||
"employee_count": "{n} employees",
|
||
"all_good": "all good",
|
||
"all_good_cap": "All good",
|
||
"only_name": "Only {name}",
|
||
"employees_nav_aria": "Employees",
|
||
"search_employee": "Search employee",
|
||
"days_to_check_aria": "{n} days to check",
|
||
"days_to_round_aria": "{n} days to round",
|
||
"no_problem_aria": "No problem",
|
||
"employee_name_aria": "Employee name",
|
||
"save_name": "Save name",
|
||
"save": "Save",
|
||
"cancel": "Cancel",
|
||
"edit_name": "Edit name",
|
||
"days_worked": "days worked",
|
||
"total_hours": "total hours",
|
||
"edited": "edited",
|
||
"fix_shifts_title": "Sorts and redistributes punches that all ended up on the same shift",
|
||
"fix_shifts": "Fix shifts ({days})",
|
||
"fix_shifts_short": "Fix shifts",
|
||
"add_lunch_title": "Adds the {start}–{end} break on days with only a morning clock-in and an evening clock-out",
|
||
"add_lunch": "Add lunch break ({days})",
|
||
"lunch_short": "Lunch",
|
||
"round_title": "Round to the nearest time",
|
||
"round_all": "Round to {step} min ({days})",
|
||
"round_short": "Round",
|
||
"day_filter_aria": "Day filter",
|
||
"all_days": "All days",
|
||
"col_day": "Day",
|
||
"col_in": "In",
|
||
"col_out": "Out",
|
||
"col_hours": "Hours",
|
||
"col_notes": "Notes",
|
||
"col_in_1": "1st shift clock-in",
|
||
"col_out_1": "1st shift clock-out",
|
||
"col_in_2": "2nd shift clock-in",
|
||
"col_out_2": "2nd shift clock-out",
|
||
"cell_aria": "{label}, {col}",
|
||
"cell_aria_stacked": "{label}, {col} ({index} of {total})",
|
||
"fix_shifts_day_aria": "Fix the shifts for {label}",
|
||
"add_lunch_day_aria": "Add the {start}–{end} lunch break to {label}",
|
||
"round_day_aria": "Round the times for {label}",
|
||
"no_rows": "No days to check for this employee.",
|
||
"cancel_export_aria": "Cancel export",
|
||
"export_warning_issues": "If you export now, these days will end up in the file with missing, unverified, or unrounded times. You can go back and fix them, or export anyway.",
|
||
"export_warning_unrounded": "The times are complete, but some aren't rounded to {step} minutes. You can round them automatically before exporting, or export them as they are.",
|
||
"back_to_review": "Back to review",
|
||
"round_and_export": "Round and export",
|
||
"export_anyway": "Export anyway"
|
||
},
|
||
"settings": {
|
||
"title": "Settings",
|
||
"device_title": "Time clock",
|
||
"device_desc": "The time clock Oxibadge downloads punches from.",
|
||
"device_label": "Address",
|
||
"status_testing": "Checking…",
|
||
"status_ok": "Reachable",
|
||
"status_idle": "Not verified",
|
||
"edit_address": "Edit address",
|
||
"test_connection": "Test connection",
|
||
"ip_label": "IP address",
|
||
"port_label": "Port",
|
||
"ip_invalid": "Invalid format, e.g. 192.168.1.100",
|
||
"cancel": "Cancel",
|
||
"confirm": "Confirm",
|
||
"shifts_title": "Expected shifts",
|
||
"shifts_desc": "The standard work schedule. The break between the two shifts is the one used by \"Add lunch break\" in the review.",
|
||
"shift_1": "1st shift",
|
||
"shift_2": "2nd shift",
|
||
"shift_in": "In",
|
||
"shift_out": "Out",
|
||
"shift_error_format": "Enter all times in HH:MM format.",
|
||
"shift_error_out1": "The 1st shift's clock-out must be after its clock-in.",
|
||
"shift_error_in2": "The 2nd shift must start after the 1st one ends.",
|
||
"shift_error_out2": "The 2nd shift's clock-out must be after its clock-in.",
|
||
"hours_per_day_label": "Expected hours",
|
||
"per_day": "per day",
|
||
"break_label": "Break",
|
||
"round_title": "Time rounding",
|
||
"round_desc": "Times are rounded to the nearest multiple.",
|
||
"round_example": "E.g. {from} → {to}.",
|
||
"round_label": "Minutes",
|
||
"minutes_short": "min",
|
||
"round_range": "From 1 to 60 minutes",
|
||
"language_title": "Language",
|
||
"language_desc": "Oxibadge's interface language.",
|
||
"save_idle": "Changes are saved automatically",
|
||
"save_saving": "Saving…",
|
||
"save_saved": "Changes saved",
|
||
"save_invalid": "Not saved: fix the error",
|
||
"save_failed": "Save failed",
|
||
"employees_title": "Employees",
|
||
"employees_count": "{n, plural, one {1 employee} other {{n} employees}}",
|
||
"manage_employees": "Manage employees",
|
||
"close_aria": "Close",
|
||
"employee_name_aria": "Name of employee #{id}",
|
||
"edit_name_aria": "Edit {name}'s name",
|
||
"remove_name_aria": "Remove {name} from the cache",
|
||
"employee_remove_confirm": "Remove {name}? You'll be asked for their name again next time.",
|
||
"remove": "Remove",
|
||
"no_employees_found": "No employees found.",
|
||
"employees_local_note": "Edited names only apply within Oxibadge: the time clock is never written to."
|
||
},
|
||
"new_employees": {
|
||
"title": "New employees",
|
||
"subtitle": "{n, plural, one {The time clock found 1 new employee.} other {The time clock found {n} new employees.}}",
|
||
"hint": "Fix the names if needed: they only apply within Oxibadge.",
|
||
"missing_placeholder": "missing name",
|
||
"name_aria": "Name of employee #{id}",
|
||
"renamed_count": "{n, plural, one {1 name edited} other {{n} names edited}}",
|
||
"missing_count": "{n, plural, one {1 name missing} other {{n} names missing}}",
|
||
"continue": "Continue"
|
||
}
|
||
}
|