Skip to content

feat: Localization in NUI#545

Open
Cocodrulo wants to merge 82 commits into
Project-Sloth:mainfrom
Cocodrulo:localization
Open

feat: Localization in NUI#545
Cocodrulo wants to merge 82 commits into
Project-Sloth:mainfrom
Cocodrulo:localization

Conversation

@Cocodrulo
Copy link
Copy Markdown

This pull request implements a localization system across NUI, enabling support for multiple languages and making all user-facing text translatable. The changes include adding locale configuration, sending locale information from the client to the NUI, updating NUI components to use localized strings, and refactoring constants imports for better maintainability.

Localization system implementation:

  • Added a Config.Locale setting in config.lua and updated OpenMDT() in client/keys.lua to send the selected locale to the UI (setLocale message). [1] [2]
  • Introduced the setLocale function and message handler in web/src/App.svelte to dynamically update the UI language based on messages from the client. [1] [2]
  • Updated UI components (ChargeType.svelte, ContentArea.svelte, EvidenceManager.svelte, InvolvedPersons.svelte) to use the _L localization function for all user-facing strings, including button labels, section titles, placeholders, and descriptions. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23]

Refactoring and maintainability:

  • Refactored imports of constants and utility functions in several components to use index files for better structure and maintainability. [1] [2] [3] [4]
  • Updated tab button components to use localized tab labels and improved tab lookup logic. [1] [2] [3]

These changes lay the groundwork for full multi-language support and ensure that adding new languages in the future will be straightforward.

* PR Description made with copilot

Introduce ITranslations and IConfig interfaces and add a localization utility module. localization.ts dynamically imports locale JSON (defaulting to "en") and exposes helpers: getLocalizedDate, getLocalizedTime (using DATE_FORMAT_OPTIONS / TIME_FORMAT_OPTIONS), and _L for nested translation lookups with simple placeholder replacement. This centralizes translation typing and formatting logic for the app.
Replace direct toLocaleTimeString/toLocaleDateString calls with getLocalizedTime and getLocalizedDate from utils/localization for consistent, centralized formatting. Remove unused imports (fetchNui, NUI_EVENTS, TIME_FORMAT_OPTIONS, DATE_FORMAT_OPTIONS) and update the onMount time update logic to use the new helpers.
Import the localization helper and replace hardcoded UI text in TagManager.svelte with localized keys to prepare the component for i18n. Updated static strings for title, input label, placeholder, add button text, instructions, empty state, suggested tags heading, and the suggested-tag aria-label (now uses a parameterized localization key).

Affected localization keys: tags.title, tags.addTag, tags.addTagPlaceholder, tags.addTagButton, tags.tagInstructions, tags.noTags, tags.suggestedTags, tags.addSuggestedTag.
Import the localization helper and replace hard-coded UI strings in web/src/components/SOPAgreementOverlay.svelte with _L(...) calls to enable translations. Replaced title, subtitle, mission statement, terms labels, intro paragraph, agree checkbox text, processing text, and the acknowledge button label. Keys used: sopa.agreement.title, sopa.agreement.subtitle, sopa.agreement.missionStatement, sopa.agreement.termsOfAccess, sopa.agreement.introSectionDefault, sopa.agreement.agreeToTerms, sopa.agreement.processing, sopa.agreement.acknowledgeAndContinue.
Replace hard-coded label text in web/src/components/ReportMetadata.svelte with localized strings via _L. Imports _L from @/utils/localization and updates labels for Report ID, Officer, Type, Created and Last Updated to use keys under reports.metadata, enabling i18n without changing component behavior.
Replace hardcoded English labels with the localization helper _L to enable i18n. Added import for _L and swapped UI text (edit/create title, live editing/connected badge, You, delete confirmation text and Yes/No, Delete, Cancel, Save/Saving) to use keys like reports.editorHeader.editReport, createReport, liveEditing, connected, you, delete, yes, no, cancel, saving, and save. No behavior changes.
Import localization helper and replace hard-coded UI text in Pagination.svelte with localized strings. Replaces "0 entries", per-page labels, and pagination button titles with _L(...) calls (including parameterized per-page text), preserving existing behavior while enabling translations.
Import localization helper and replace hardcoded UI text with localized keys in MugshotCamera.svelte. Defaults and labels (subject placeholder, REC indicator, MUGSHOT label, zoom display and scroll hint) are now resolved via _L(...) including a parameterized zoom string; no other behavior changes.
Import localization helper and replace hardcoded UI text in LoginOverlay.svelte with localized keys. Adds _L import and updates strings such as loginOverlay.authenticating, loginOverlay.verifyingCredentials, loginOverlay.accessDenied, loginOverlay.restrictedAccess, loginOverlay.closeTerminal, loginOverlay.offDuty, loginOverlay.mustBeOnDuty, loginOverlay.goOnDuty, and loginOverlay.authenticationError. No behavioral changes—purely prepares the component for localization.
Replace hardcoded English text in web/src/components/InvolvedPersons.svelte with the _L localization helper (imported from '@/utils/localization'). Section titles, counts, button labels, search placeholders, person detail labels (notes, type, badgeId), remove labels and empty-state messages now use localized keys and parameter substitution. Removed the now-unused VICTIM_TYPES/OFFICER_TYPES import. This is an i18n refactor with no functional behavior changes.
Import localization helper and replace hard-coded UI strings in EvidenceManager.svelte with _L(...) calls. Labels, help text, buttons, image count text and empty-state message were updated to use localization keys (e.g. evidence.title, evidence.addEvidence, evidence.images with count). No functional changes; this prepares the component for translation/internationalization.
Update _L to accept string or number replacement values and convert replacements to strings before applying them. This lets callers pass numeric values (e.g., counts) into translation templates without type errors by changing the replacements tuple type and calling toString() during replacement.
Replace hard-coded UI text in ContentArea.svelte with localized strings. Import the _L localization helper and use keys for permission title, permission description (passing the page label as a parameter), back-to-dashboard button, and the component-not-found message to enable i18n.
Import localization helpers (_L, getLocalizedCurrency) and apply them across ChargeType.svelte. Replace hard-coded table header labels and button text with localized keys (charges.code, charges.charge, charges.description, charges.fine, charges.time, charges.save, charges.cancel) and use getLocalizedCurrency for formatting fines, enabling localized strings and currency formatting.
Introduce getLocalizedCurrency(value: number) which formats numeric values as USD currency using Intl.NumberFormat with config.locale. Adds a reusable utility for producing localized currency strings for display.
Replace the hardcoded "Victims" default prop with a localized string. Import _L from @/utils/localization and set title = _L("victimsManager.title") so the VictimsManager uses i18n for its default heading.
Replace hardcoded English UI text in VehiclesManager.svelte with localized strings via the _L helper. Adds an import for _L and updates section label, add/close button text, search placeholder/status messages, 'Added' badge, owner label (parameterized), and 'Issue BOLO' button text to use localization keys under vehiclesManager.*. No functional behavior changed — this prepares the component for multi-language support.
Replace hardcoded labels in web/src/components/report-editor/TagsManager.svelte with the localization helper _L. Adds import of _L and swaps 'TAGS', 'Add', 'Available Tags', and 'No more tags available' for keys tagsManager.title, tagsManager.add, tagsManager.availableTags, and tagsManager.noTagsAvailable. No behavioral changes.
Import the _L localization helper and replace hardcoded UI text in SuspectsManager.svelte with localized calls. Strings updated include no-mugshot and no-fingerprint warnings (passing suspect.fullName as a parameter), action labels for Take Mugshot, Add Fingerprint, Issue Warrant, Issue Bench Warrant, and Issue BOLO to prepare the component for i18n.
Add multiple English i18n entries to web/src/translations/en.json for new UI components: evidence (labels, help text, image/serial handling), contentArea (permission messages), charges, victimsManager, vehiclesManager (search/placeholders/actions), tagsManager, and suspectsManager. These are purely localization additions to support new/updated UI text.
Replace hardcoded UI text in ReportHeader.svelte with localization calls. Import _L from utils/localization and use reportHeader.* keys for the title, cancel button, save button and saving state.
Replace hardcoded toolbar button titles with localized strings using _L from @/utils/localization. Adds the _L import and updates title attributes for Bold, Italic, Underline (with shortcut hints), Highlight, text alignment (left/center/right), Bullet/Numbered lists, and Heading 1–3 to enable internationalization.
Replace hardcoded English strings in web/src/components/report-editor/PersonSearchModal.svelte with calls to the localization helper (_L). The input placeholder now uses personSearchModal.searchPlaceholder, and the badge/ID result lines use _L with parameters (badgeId, rank) and (citizenid) respectively to enable internationalization.
Import the _L localization helper and replace hardcoded 'Add {title}' and '+ Add' strings with localized values. The button title and aria-label now use _L("personnelSection.addTitle", ["title", title]) and the visible label uses _L("personnelSection.add"). This enables i18n for the add button and improves accessibility.
Replace hardcoded UI strings in ImageUploadModal.svelte with localization calls. Adds import of _L and swaps static text for localization keys (imageUploadModal.title, imageUploadModal.uploading with fileName param, imageUploadModal.uploadingHint, imageUploadModal.clickToSelect, imageUploadModal.supports) to enable translations; no functional change.
Replace hardcoded UI text in EvidenceManager.svelte with localized strings. Added import of _L from @/utils/localization and swapped labels, button text, and placeholders (section label, add button, title/serial/notes/caseId placeholders, Create Case and Add Image buttons) to use localization keys under evidenceManager. No functional changes intended; this enables translation of the evidence manager UI.
Replace hardcoded "Live Editing" text with a localized string. Imports _L from '@/utils/localization' and uses _L('collabPresenceBar.liveEditing') in CollabPresenceBar.svelte to enable translations for the live editing indicator.
Replace hardcoded UI strings with localization calls and format currency values.

- ManagementVisibility.svelte: import _L and replace static labels, loading/empty state texts, boss tags/notes, group actions and save button text with localized keys.
- ChargesManager.svelte: import _L and getLocalizedCurrency; replace section labels, placeholders, button texts, hints, no-results/empty texts, reduction modal labels and percentage/months strings with localized keys; format fines using getLocalizedCurrency and use localization for parameterized strings.

Purpose: enable i18n for these components and ensure currency is displayed using the app's localized formatter.
Import the localization helper and replace hardcoded UI text in web/src/pages/PPR.svelte with localized strings (_L("reportEditor.*")). Updated labels, button text, placeholders, select options, section titles, notes/messages, table headers, and status strings (e.g. backToPPRList, incidentDetails, save/cancel/edit/delete, title/category/description/officer/author/date, newPerformanceReview, submit/submitting, searchPPREntries, loading/no-results messages, etc.). No functional logic changes — this is strictly UI text internationalization.
Adds extensive English localization entries for new MDT functionality, including report editor/header/toolbar, evidence manager, person search, charges manager, numerous Management modules (visibility, tracking, templates, tags, SOP, permissions, licenses, jail & fines, FTO, colors, bulletins, awards, activity), dashboard, weapons, warrants, vehicles, SOP, settings, roster, reports page, report editor, and PPR pages. These strings provide UI labels, placeholders, status messages, and error text for the expanded feature set. Note: a trailing comment ("// Pages MDT") was appended at the EOF which could invalidate the JSON and should be removed or converted to a valid JSON entry if unintended.
Replace hard-coded English labels in web/src/pages/Map.svelte with localization calls. Adds import for _L from utils/localization and updates control header, toggle labels, style buttons, and legend items to use translation keys (map.tracking, map.officers, map.vehicles, map.bodycams, map.style, map.dots, map.badges, map.officer, map.vehicle, map.bodycam). This enables runtime localization of the map UI.
Import localization helpers and replace hard-coded UI text and date formatting with localized equivalents. Adds _L, getLocalizedDate and getLocalizedTime imports; updates formatDateValue/formatDateTimeValue to use localization helpers; replaces static labels, button text, placeholders and section titles with _L(...) calls; and localizes evidence link numbering. No behavior changes beyond presentation/localization.
Import localization helpers (_L, getLocalizedDate) and replace hardcoded UI text in web/src/pages/Evidence.svelte with localized keys (section titles, labels, placeholders, button text, empty states, option labels, etc.). Also replace new Date(...).toLocaleDateString() with getLocalizedDate for consistent localized date formatting. No functional logic changes — prepares the Evidence page for internationalization.
Import localization helpers and replace hardcoded UI text and date formatting in Dashboard.svelte. Uses _L(...) for label translations (panels, stats, buttons, empty states, pill labels, relative time units/phrases) and getLocalizedDate(...) instead of toLocaleDateString() for consistent localized date output.
Import the _L localization helper and replace hard-coded English strings in ComplaintForm.svelte with localized keys (complaintForm.*). This updates category labels, success messages, header/title, form field labels, evidence button text and cancel text to use _L(), preserving existing behavior while enabling translations.
Replace hardcoded submit button text with localization calls so the label uses _L("complaintForm.submitting") when submitting and _L("complaintForm.submitComplaint") otherwise. No functional change to button behavior.
Import localization helpers and replace hardcoded UI strings with _L(...) calls across CivilianView.svelte, and format monetary fines using getLocalizedCurrency. This updates tab labels, section headers, info labels, empty/loading states, warrants/BOLO/report text, license status, charge table headers, and charge fine formatting. No functional logic changes were made—this commit prepares the view for i18n and locale-aware currency display.
Replace hard-coded UI text in web/src/pages/Citizens.svelte with the _L localization helper and import it from utils/localization. Updated labels, buttons, placeholders, panel titles, empty-state messages, stats, badges, modal content, table headers, and other UI strings to use localization keys (including parameterized calls for "more warrants/BOLOs"). No functional changes beyond text localization.
Import the _L localization helper and replace hard-coded UI text in web/src/pages/Charges.svelte with localized keys. Updates include the search placeholder, result count wording, loading/refresh button text, edit/done label, and empty-state titles/subtext (uses chargesPage.* keys). No functional changes besides switching to localized strings; pluralization logic was replaced by a localized term for the result count.
Replace hard-coded UI text in web/src/pages/Cases.svelte with localization calls and localized date/time helpers. Imports _L, getLocalizedDate and getLocalizedTime; swap toLocaleDateString/toLocaleTimeString usage; convert ACTION_LABELS to localized keys; update placeholders, button labels, section titles, list text and pagination labels. No business logic changes — only string/date/time localization updates for i18n.
Import the localization helper (_L) and replace hardcoded UI text in web/src/pages/Cameras.svelte with localized keys (camerasPage.*). Changes include the search placeholder, refresh/loading button text, empty-state messages, table headers (ID, Camera, Status, Viewers), online/offline pill labels, and the View button label. No functional changes were made; this prepares the page for i18n.
Import the localization helper and replace hardcoded English UI strings in web/src/pages/Bolos.svelte with calls to _L("bolosPage.*"). This updates type labels, list/button text, modal field labels, form labels and options, and status/messages (e.g. loading/no results), enabling translations without changing component behavior.
Import the localization helper (_L) and replace hardcoded UI strings on Bodycams.svelte with localized keys. Updates include input placeholder, refresh/loading text, table headers (callsign, officer, rank, status, viewers), empty-state titles and messages, status pills (Online/Offline) and the View button label. No functional changes; this prepares the page for localization via bodycamsPage.* keys.
Import the localization helper and replace hard-coded UI text on the Awards page with localized keys. This updates tab labels, loading/empty states, stat labels, earned/in-progress section headers (with counts), leaderboard labels and sort options to use _L("awardsPage.*"), enabling translations for the awards UI.
Replace hard-coded strings and US-specific date/time formatting in WarrantReview.svelte with localization helpers. Adds import of _L, getLocalizedDate, and getLocalizedTime; updates formatDateValue and formatDateTimeValue to use getLocalizedDate/getLocalizedTime. Replaces labels, buttons, placeholders, table headers, modal text, and document type options with _L calls and localizes loading/empty states and topbar text.
Import _L from the localization utilities and replace hard-coded strings in the create-document modal of LegalDocuments.svelte with _L(...) calls. Updated modal title, field labels, select options, placeholders and action buttons to use localization keys (e.g. legalDocument.newLegalDocument, legalDocument.type, legalDocument.brief, legalDocument.title, legalDocument.documentTitle, legalDocument.linkToCourtCase, legalDocument.courtCaseId, legalDocument.content, legalDocument.documentContent, legalDocument.cancel, legalDocument.createDocument) to enable i18n support.
Replace hardcoded English labels and placeholders in CourtOrders.svelte with localization calls using _L and switch date formatting to getLocalizedDate. Imports _L and getLocalizedDate from @/utils/localization and updates type option labels, table/header labels, buttons, modal fields, status/messages, and loading/refresh text to use localized keys (e.g. courtOrders.* and common keys like cancel, refresh, loadingOrders). No functional behavior changes.
Import the _L localization helper and replace hard-coded UI text with localized keys across the CourtCases page. This updates topbar labels, section titles, field labels, buttons (Add/Remove/Save/Cancel/Create), placeholders, modal titles, case/document type options, search placeholder, loading/no-cases messages, and other visible strings to use _L("courtCases.*"). No functional behavior was changed — this prepares the component for i18n.
Rename/move en.json from web/src/translations to web/public/translations and add many new translation keys across UI pages. Switch translation loading from a build-time import to a runtime fetch so locales are loaded from /translations/<locale>.json. Improve localization util: safer _L lookup with dev warnings for missing keys or non-string values, robust placeholder replacement, and currency formatting that respects config.currency with USD as fallback. Also fix Vehicles.svelte status rendering precedence by properly parenthesizing the status expression.
Add a complete Spanish translations file at web/public/translations/es.json (~1539 entries) covering dashboard, reports, evidence, management, forms, settings and other UI strings. Update web/src/utils/localization.ts to register/use the new 'es' locale (es-ES date/time locales) so the app can load the Spanish translations and formatting.
Introduce i18n support across the UI: add many translation keys to en.json and es.json (evidence, IA, tabs, bolos, cases, reports, cameras, etc.). Update MDT_TABS to include localized label fields and use _L() in NAV_GROUPS labels. Replace hardcoded strings with _L() in multiple components and pages (InstanceTabButton, NavigationPills, ReportEditorHeader, ReportHeader, EvidenceManager, Bolos, Cases, Evidence, IA, PPR, Reports, Vehicles, Warrants) and add a helper getTabLabel. PPR now uses getLocalizedDate/getLocalizedTime for date formatting. Also update imports/types (IMDT) where needed. These changes centralize UI text for translation and ensure consistent localized tab labels.
Replace direct toLocaleDateString()/toLocaleTimeString() usage with getLocalizedDate/getLocalizedTime across multiple components and the report service for consistent localized formatting. Add and use new translation keys (en and es) for FTO, IA, roster, weapons, citizens, vehicles and other UI messages; update various notification messages to use _L. Files updated include many pages/components (ReportItem, ManagementActivity, ReportMetadata, Awards, Cases, Citizens, CivilianView, Evidence, FTO, IA, Roster, Weapons) and web/src/services/reportService.svelte.ts.
Expand and refine English translations and UI labels across the app. Major changes in web/public/translations/en.json include many new keys and placeholders (evidence fields, management tabs, permissions, FTO, PPR, IA/complaints, court/legal messages, report/evidence types, app titles, etc.), wording adjustments, and several key renames for clarity. Related UI components and pages were updated to follow the revised strings and constants (multiple files under web/src/components/management and web/src/pages, plus web/src/constants/index.ts). These updates improve localization coverage and standardize labels/placeholders used throughout the application.
Refactor localization into a Svelte-aware module and add runtime locale handling. Renamed utils/localization.ts -> utils/localization.svelte.ts and introduced a LocalizationConfig $state to hold config and translations, plus setLocale() to load translations at runtime (default locale changed to "en"). Created web/src/constants/date.ts for TIME_FORMAT_OPTIONS/DATE_FORMAT_OPTIONS and re-exported it from constants/index.ts. Updated imports across the app to point to the new localization.svelte module and date constants. Wire up client/server: added Config.Locale = "en" to config.lua and send locale from client/keys.lua; App.svelte now handles the 'setLocale' NUI message and calls setLocale. These changes centralize localization state, separate date format constants, and enable changing locale dynamically from the client.
Update message handling and translation loading:

- App.svelte: Read locale from event.data.data.locale (message payload nested under data) when handling setLocale messages.
- localization.svelte.ts: Use a relative path (./translations/...) for fetching translation JSON so files are resolved correctly in embedded or relative deployments.

These changes fix failures to set the locale from posted messages and to load translation files in non-root or packaged environments.
Major refactor of the app's constant/management layers and i18n keys. Moved and renamed web/src/constants/index.ts to index.svelte.ts and replaced many static constant exports with getter functions (getMDTTabs, getNavGroups, getAppInfo, getReportTypes, getOfficerTypes, getVictimTypes, getTabVisibilityKeys, etc.) to better support localization and non-reactive vs reactive usage. Management constants were moved from management.ts into a new management.svelte.ts module with getManagementTabs, getPermissionCategories and helpers. Updated imports across many components to use the new modules and getters, switched components to read labels from localized getters instead of hardcoded strings, and adjusted related types (ComponentId/TAB mapping changes). Updated en/es translation files to use camelCase reportTypes keys (e.g. incidentReport) and set default locale to Spanish (setLocale("es") in App.svelte). Lots of components and services were modified to accommodate the new constant APIs. This is a breaking structural change for any code importing the old constant names/files—run the app and tests to verify all runtime i18n and tab/permission behaviors.
Replace setLocale("es") with setLocale() in web/src/App.svelte so the app no longer forces Spanish as the default. This lets the locale resolution use its built-in/default behavior (e.g., auto-detection or configured default) instead of a hardcoded value.
Import the _L localization helper and replace hardcoded tab labels in Management.svelte with localized strings (keys like `management.tabs.bulletins`, `management.tabs.activity`, etc.). This enables i18n for the management page tabs without changing any tab permissions or behavior.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant