# Config Files

{% tabs %}
{% tab title="config.lua" %}

```lua
--============================================================--
-- iZaap Scripts — Garage 

Config = Config or {}

Config.Framework = Config.Framework or "auto" 
Config.CustomCore = Config.CustomCore or {
  Resource = "my_core",
  Export = "GetCoreObject"
}

Config.Locale = "es" -- "es" | "en"

Config.FuelDependency = "legacyfuel" -- Options: "none", "qb-fuel", "legacyfuel"
Config.KeysDependency = "qb-vehiclekeys" -- Options: "qb-vehiclekeys", "qbx_vehiclekeys", "brutal_keys"

Config.EnableVehicleImages = true

--============================================================--
-- RECOVER (Tow / Recover fee)
--============================================================--
Config.Recover = Config.Recover or {}
if Config.Recover.Enabled == nil then Config.Recover.Enabled = true end

Config.Recover.TowFee        = 200
Config.Recover.TowFeeAccount = "bank" -- "cash" | "bank"

--============================================================--
-- TRANSFER (Vehicle transfer fee)
--============================================================--
Config.Transfer = Config.Transfer or {
  Enabled = true,
  Fee     = 100,
  Account = "bank", -- "cash" | "bank"
}

--============================================================--
-- PEDS (Garage / Impound)
--============================================================--

Config.GaragePed = {
  DefaultModel    = "s_m_m_security_01",
  InteractRadius  = 2.2, -- distance to interact
}

Config.ImpoundPedModel = "ig_floyd"

--============================================================--
-- INTERACTION MODE
--============================================================--
Config.Interaction = {
  Mode = "textui", -- "textui" | "qb-target" | "ox-target" | "auto"

  Target = {
    Enabled       = true,
    Label         = "Open Garage",
    ImpoundsLabel = "Open Impound",
    Icon          = "fas fa-warehouse",
    Distance      = 4.0,
  }
}

Config.TextUI = {
  Enabled = true,

  Open = function(message)
    exports["jg-textui"]:DrawText("[E] Open Garage", message)
  end,

  Close = function()
    exports["jg-textui"]:HideText()
  end
}

--============================================================--
-- MARKERS (Visual marker at garages)
--============================================================--
Config.GarageMarker = {
  Enabled = true,
  Rotate  = true,
  ZOffset = 0.95,

  -- Type = 36,
  -- Scale = { x = 0.8, y = 0.8, z = 0.8 },
  -- Color = { r = 255, g = 214, b = 0, a = 180 },
  -- BobUpAndDown = false,
  -- FaceCamera = false,
}

--============================================================--
-- BLIPS 
--============================================================--
Config.Blips = {
  Enabled    = true,
  ShortRange = true,
  Display    = 4,
  Scale      = 0.65,

  -- If you use per-type sprites in the admin panel client:
  -- DefaultSprite = 50,
  -- Color = 3,
  -- SpritesByType = { public = 50, job = 357, gang = 84, private = 50, impound = 67 },

  -- Simple impound fallback
  impound = { blipId = 67, blipColor = 1},
}

--============================================================--
-- GARAGE INTERACT LOOP
--============================================================--
Config.GarageInteract = {
  UseGarageRadius = true, -- respects per-garage radius if stored
  Extra           = 0.0,  -- extra distance buffer
  Key             = 38,   -- 38 = E

  SleepFar        = 800,  -- ms when far away (performance)
  SleepNear       = 0,    -- ms when near (responsive)
}

--============================================================--
-- VEHICLE STATE VALUES (DB compatibility)
--============================================================--
-- "stored" and "out" values used by your database/resource.
Config.StoredStateValue = 1
Config.OutStateValue    = 0
--============================================================--
-- IMPOUND (Advanced pricing / time)
--============================================================--
Config.Impound = Config.Impound or {}
Config.Impound.Advanced = {
  -- Caps (to prevent insane fees)
  maxPriceAfterImpoundDate  = 6500,
  maxPriceBeforeImpoundDate = 14500,

  -- Defaults if the vehicle/impound row has no custom values
  defaultFeeAfter  = 2500,
  defaultFeeBefore = 0,

  -- Default selected time option (hours as string)
  -- "0" = available instantly
  defaultTimeValue = "72", -- 3 days

  -- Dropdown options (label shown in UI, value used internally)
  timeOptions = {
    { label = "Available Instantly", value = "0"   },
    { label = "1 Day",              value = "24"  },
    { label = "5 Days",             value = "120" },
    { label = "7 Days",             value = "168" },

    -- Use a very large value to represent "Only faction members"
    -- (Your UI can display it as "Restricted")
    { label = "Only By faction.",   value = "99999999" },
  }
}

--============================================================--
-- COMMANDS
--============================================================--
Config.Commands = Config.Commands or {
  AdminPanel       = "garageadmin",

  GiveCar          = "givecar",
  DeleteCar        = "dvcar",
  ChangePlate      = "changeplate",


  Impound          = "impound",
  JobImpoundsPanel = "panelimpounds",
}

-- Only these 3 are toggleable as you requested:
Config.CommandsEnabled = Config.CommandsEnabled or {
  GiveCar     = true,
  DeleteCar   = true,
  ChangePlate = true,
}

--============================================================--
-- SPAWN QUALITY
--============================================================--
Config.FixHealthOnSpawn = true

```

{% endtab %}

{% tab title="locales.lua" %}

```lua
-- locales.lua

local Locales = {}

-- =========================================================
-- ES (Español)
-- =========================================================
Locales.es = {
  -- =========================
  -- Global / Common
  -- =========================
  close = "Cerrar",
  cancel = "Cancelar",
  confirm = "Confirmar",
  save = "Guardar",
  edit = "Editar",
  delete = "Eliminar",
  on = "ON",
  off = "OFF",

  pg_prev = "Anterior",
  pg_next = "Siguiente",

  -- =========================
  -- Topbar / Nav
  -- =========================
  ui_title = "GARAGE ADMIN",
  ui_subtitle = "iZaap Studios • Garage Manager",
  nav_garages = "Garages",
  nav_impounds = "Impounds",
  nav_jobvehicles = "Vehículos de Trabajo",
  nav_gangvehicles = "Vehículos de Banda",

  -- =========================
  -- Toolbars
  -- =========================
  garages_search_ph = "Buscar garage por nombre o tipo...",
  add_garage = "Añadir Garage",
  map_view = "Ver mapa",
  list_view = "Ver lista",
  view_map_title = "Ver mapa",
  view_list_title = "Ver lista",

  impounds_search_ph = "Buscar Impound",
  impounds_create = "CREAR NUEVO",

  jobveh_search_ph = "Buscar Vehículo",
  jobveh_create = "Crear Nuevo",

  -- =========================
  -- Tables (Garages)
  -- =========================
  th_garage_label = "Nombre",
  th_garage_type = "Tipo",
  th_access = "Acceso",
  th_private = "Privado",
  th_garage_job = "Job del Garage",
  th_actions = "Acciones",

  garages_empty = "No hay garages aún. Pulsa “Añadir Garage”.",

  -- =========================
  -- Access labels
  -- =========================
  access_public = "PÚBLICO",
  access_job = "TRABAJO",
  access_gang = "BANDA",
  access_private = "PRIVADO",
  access_open_access = "Acceso abierto",
  access_players = "{count} jugador(es)",

  -- =========================
  -- Type labels
  -- =========================
  type_car = "Auto",
  type_boat = "Barco",
  type_air = "Aire",

  -- =========================
  -- Map Admin
  -- =========================
  map_title = "Mapa de Garages",
  map_sub = "Click en un icono para Editar/Eliminar",
  map_fit = "Centrar mapa",
  map_hint = "Arrastra para mover • Rueda para zoom",
  map_count = "{count} garages",
  map_pop_title = "Garage",

  -- =========================
  -- Section placeholders
  -- =========================
  vehicles_soon = "Vehículos (próximamente)",
  gang_soon = "Vehículos de banda (próximamente)",

  -- =========================
  -- Garage Modal (Admin)
  -- =========================
  modal_edit_garage = "EDITAR GARAGE",
  modal_sub_garage = "Configura label, radio, coords, ped coords, z-range y blip.",
  garage_label = "Nombre del Garage",
  garage_label_ph = "Ej: Bajeta Private",
  visible_name = "Nombre visible.",
  garage_radius = "Radio del Garage",
  garage_radius_help = "Radio de acceso (metros).",
  garage_type = "Tipo de Garage",
  garage_type_help = "Selecciona el tipo.",
  garage_location = "Coordenadas del Garage",
  use_current_coords = "Usar coords actuales",
  garage_location_note = "Define el punto base del garage.",
  ped_coords = "Coords del Ped del Garage (opcional)",
  ped_coords_note = "Opcional. Útil para un NPC/spawn puntual.",
  blip_enable = "Habilita/Deshabilita blip en el mapa.",
  access_toggle_title = "Expandir/Contraer",

  -- Access block
  access_options = "Opciones de Acceso",
  job_restricted = "Restringido por Job",
  job_restricted_ph = "mechanic",
  job_restricted_help = "Job que tendrá acceso exclusivo a este garage.",
  job_grade_restricted = "Rango mínimo del Job",
  job_grade_restricted_help = "Rango desde el cual se permite usar el garage.",
  gang_restricted = "Restringido por Banda",
  gang_restricted_ph = "ballas",
  gang_restricted_help = "Banda con acceso exclusivo a este garage.",
  gang_grade_restricted = "Rango mínimo de Banda",
  gang_grade_restricted_help = "Rango desde el cual se permite usar el garage.",
  search_player = "Buscar jugador",
  private_search_ph = "Click para buscar... (citizenid / license)",
  private_add = "Agregar jugador",
  private_help = "Escribe un identificador y Enter / + para agregar (citizenid, license, etc.).",
  garage_mode = "Modo del Garage",
  owned_vehicles = "Vehículos Propios",
  job_vehicles = "Vehículos de Trabajo",
  garage_mode_help = "Selecciona el modo (owned/job).",
  public_garage = "GARAGE PÚBLICO",
  job_only = "SOLO JOB",
  private_garage = "GARAGE PRIVADO",
  gang_only = "SOLO BANDA",
  access_notice = "Aviso: Solo puedes elegir un tipo de acceso — Job, Banda o Privado. No se pueden combinar. Deja todo vacío si quieres desactivar restricciones.",

  -- Garage Admin (app.js extras)
  ga_private_empty = "No hay jugadores añadidos todavía.",
  ga_private_duplicate = "Ese jugador ya está en la lista.",
  ga_blip_applied = "Blip settings aplicados.",



  -- =========================================================
  -- PLAYER GARAGE UI (garage.js)
  -- =========================================================
  garage_search_sub = "Busca por nombre o placa",
  sort_fav_title = "Ordenar: Favoritos primero",
  go_showroom = "IR A SHOWROOM",
  garage_player_search_ph = "Buscar por nombre o placa",
  vehicles_count = "{count} vehículo(s)",
  veh_count = "{count} vehículo(s)",

  stat_fuel = "Gasolina",
  stat_engine = "Motor",
  stat_body = "Carrocería",

  note_still_out = "Tu vehículo sigue afuera (en la calle).",
  note_gps_marked = "GPS marcado al vehículo.",
  note_tow_fee = "La grúa se llevó tu vehículo. Sácalo de nuevo por {fee}.",

  checking_vehicle = "Verificando estado del vehículo...",
  not_in_this_garage = "Este vehículo no está en este garage.",

  status_stored = "Guardado",
  status_outside = "Afuera",
  status_impounded = "Incautado",
  status_job = "Trabajo",
  status_towed = "Remolcado",

  btn_drive = "Sacar",
  btn_drive_fee = "Sacar {fee}",
  btn_mark = "Marcar Ubicación",
  btn_transfer = "Transferir",

  -- aliases usados por algunos JS
  btn_impounded = "Incautado",
  btn_checking = "Verificando...",
  takeout_failed = "No se pudo sacar el vehículo.",
  mark_failed = "No se pudo marcar el vehículo.",
  garage_initializing = "El garage todavía está inicializando. Intenta de nuevo en 1–2s.",
  garage_title_fallback = "Garage",
  vehicle_fallback_name = "Vehículo",
  vehicle_impounded_note = "Vehículo incautado.",

  fav_add = "Marcar favorito",
  fav_remove = "Quitar favorito",
  rename_title = "Renombrar",
  rename_save = "Guardar nombre",
  rename_cancel = "Cancelar",

  -- =========================================================
  -- TRANSFER UI
  -- =========================================================
  transfer_title = "Transferir Vehículo",
  plate_label = "Placa: {plate}",
  transfer_plate = "Placa: {plate}",
  select_dest_garage = "Selecciona el garage destino",
  transfer_select_ph = "Selecciona un garage",
  transfer_fee = "Se te cobrará {fee} por transferir",
  transfer = "Transferir",

  transfer_no_garages = "No hay garages disponibles para transferir (admin).",
  transfer_select_destination = "Selecciona un garage destino.",
  transfer_invalid_plate = "Placa inválida.",
  transfer_failed = "Falló la transferencia.",
  transfer_ui_error = "Error de Transfer UI (revisa consola F8).",
  transfer_select_missing = "No se encontró el selector de garages.",

  -- Transfer Player (tabs + list)
  tp_tab_garage = "Transferir a garage",
  tp_tab_player = "Transferir a jugador",
  tp_search_ph = "Buscar por ID o nombre...",
  tp_hint_notify = "El jugador recibirá una notificación al completar la transferencia.",
  tp_empty_players = "No hay jugadores.",
  tp_btn_transfer = "TRANSFERIR",
  tp_status_processing = "Procesando transferencia...",
  tp_status_done = "Transferencia completada.",
  tp_err_no_plate = "No se pudo leer la placa a transferir.",
  tp_err_failed = "No se pudo transferir.",

  -- =========================================================
  -- CHANGE PLATE UI
  -- =========================================================
  change_plate = "CAMBIAR PLACA",
  current_plate = "Placa actual",
  new_plate = "Nueva placa",
  new_plate_ph = "EJ: ABC1234",

  cp_err_write_plate = "Escribe una nueva placa.",
  cp_err_max_8 = "Máximo 8 caracteres (sin espacios).",
  cp_err_offline = "NUI offline",
  cp_err_failed = "No se pudo cambiar la placa.",

  -- =========================================================
  -- IMPOUNDS (Client world / textui / blips)
  -- =========================================================
  imp_open_label = "Abrir impound",
  imp_textui_open = "[E] Abrir impound",
  imp_blip_name = "Impound: {label}",

  -- client_impounds.lua (notify/errors)
  imp_spawn_failed = "No se pudo spawnear el vehículo.",
  imp_no_job_impounds = "Tu trabajo no tiene impounds para enviar.",
  imp_get_out_vehicle = "Bájate del vehículo y párate cerca de él para enviarlo al impound.",
  imp_no_vehicle_near = "No hay ningún vehículo cerca para enviar al impound.",
  imp_get_closer_vehicle = "Acércate más al vehículo para enviarlo al impound.",
  imp_invalid_plate = "Placa inválida.",
  imp_no_job_assigned = "No tienes trabajo asignado.",
  imp_no_permission = "No tienes el trabajo para hacer esto.",

  -- =========================================================
  -- IMPOUND UI (Player)
  -- =========================================================
  impound = "IMPOUND",
  impound_search_sub = "Buscar Vehículo",
  impound_search_ph = "Buscar Vehículo",

  -- Accordion list
  iu_count = "{count} vehículo(s)",
  iu_empty = "No hay vehículos incautados aquí.",
  iu_tag_impound = "IMPOUND",
  iu_tag_status_fallback = "FUERA DEL GARAGE",
  iu_expand_aria = "Expandir",

  iu_info_title = "¡Un vehículo fue incautado!",
  iu_impounded_by = "Incautado por:",
  iu_location = "Ubicación:",
  iu_reason = "Razón:",
  iu_available_at = "Disponible en:",
  iu_price_now = "Precio para liberar ahora:",

  iu_locked = "BLOQUEADO ({time})",
  iu_impound_for = "LIBERAR POR ${price}",

  iu_prev = "Anterior",
  iu_next = "Siguiente",
  iu_showing = "Mostrando {start}-{end} de {total}",
  iu_wait_time = "TIEMPO DE ESPERA",

  -- =========================================================
  -- IMPOUND INFO WIDGET
  -- =========================================================
  imp_info_title = "Información de Incautación",
  imp_info_hint = "Debes ir al impound para recuperar tu vehículo.",

  imp_k_impound = "Impound",
  imp_k_by = "Incautado por",
  imp_k_reason = "Razón",
  imp_k_fee_before = "Tarifa (antes)",
  imp_k_fee_after = "Tarifa (después)",
  imp_k_impounded_at = "Incautado en",
  imp_k_status = "Estado",

  imp_status_locked = "BLOQUEADO ({time})",
  imp_status_available = "Disponible",

  -- aliases para el JS (imp_info_k_* / imp_info_status_*)
  imp_info_k_impound = "Impound",
  imp_info_k_by = "Incautado por",
  imp_info_k_reason = "Razón",
  imp_info_k_fee_before = "Tarifa (antes)",
  imp_info_k_fee_after = "Tarifa (después)",
  imp_info_k_impounded_at = "Incautado en",
  imp_info_k_status = "Estado",

  imp_info_status_locked = "BLOQUEADO ({time})",
  imp_info_status_available = "Disponible",

  imp_info_k_release_at = "Liberación en",

  -- Time strings
  time_just_now = "justo ahora",
  time_min_ago = "hace {min} min",
  time_h_ago = "hace {h} h",
  time_yesterday = "ayer",
  tow_fee_note = "La grúa se llevó tu vehículo. Sácalo de nuevo por {fee}.",

  -- =========================================================
  -- IMPOUND SEND (Job)
  -- =========================================================
  impound_menu = "Menú de Impound",
  impound_menu_sub = "Impoundear vehículo cerca de ti (no dentro).",
  vehicle_plate = "Placa del Vehículo",
  must_be_near = "Debe estar cerca del vehículo.",
  reason_optional = "Razón (opcional)",
  reason_ph = "Parqueo ilegal / Violaciones de parqueo",
  max_255 = "Máx 255 caracteres.",
  impound_location = "Ubicación del Impound",
  select_where_goes = "Selecciona dónde quedará el vehículo.",
  impound_time = "Tiempo de Impound",
  price_before = "Precio ANTES de la fecha (Liberación temprana)",
  early_release_disabled = "Si es 0, la liberación temprana se desactiva (bloqueado hasta que termine el tiempo).",
  price_after = "Precio DESPUÉS de la fecha (Liberación normal)",
  fee_after_note = "Se cobra después de que termine el tiempo de bloqueo.",
  impound_btn = "IMPOUNDEAR",

  -- Fallback si no hay label real
  imp_default_label = "Incautación",

  -- =========================================================
  -- IMPOUNDS (server notifications)
  -- =========================================================
  imp_invalid = "Impound inválido.",
  imp_job_no_impounds = "Tu trabajo no tiene impounds para enviar.",
  imp_vehicle_not_registered = "Este vehículo no está registrado (no se puede impound).",
  imp_vehicle_sent = "Vehículo enviado al impound.",
  imp_locked_cannot_release = "Aún no puedes liberar este vehículo. Está bloqueado por tiempo.",
  imp_not_enough_money = "No tienes dinero suficiente.",
  imp_vehicle_released = "Vehículo liberado del impound.",
  imp_vehicle_not_in_impound = "Este vehículo no está en impound.",
  imp_admin_release_done = "Impound liberado (sin fee/tiempo). El jugador debe retirarlo en el impound.",

  -- =========================================================
  -- SHOWROOM HUD
  -- =========================================================
  showroom = "SALA DE EXPOSICIONES",
  plate = "PLACA: {plate}",
  engine = "Motor",
  body = "Carrocería",
  fuel = "Gasolina",
  exit_backspace = "BACKSPACE para salir",
  not_favorite = "No favorito",

  showroom_block_street = "BLOQUEADO",
  showroom_block_impound = "IMPOUND - BLOQUEADO",

  -- =========================================================
  -- IMPOUNDS ADMIN (panel)
  -- =========================================================
  imp_th_label = "Nombre",
  imp_th_type = "Tipo",
  imp_empty = "No hay impounds aún. Pulsa “CREAR NUEVO”.",

  imp_modal_create = "CREAR IMPOUND",
  imp_modal_sub = "Nombre, tipo, coords, blip y jobs permitidos.",
  imp_label = "Nombre del Impound",
  imp_label_ph = "Escribe el nombre...",
  imp_label_help = "Nombre que aparecerá en el mapa.",
  imp_type = "Tipo de Impound",
  imp_type_help = "Selecciona el tipo de impound.",
  imp_car = "Auto",
  imp_boat = "Barco",
  imp_air = "Aire",
  imp_location = "Coordenadas del Impound",
  use_current = "Usar actuales",
  coords_note = "Configura coords y heading del punto del impound.",
  blip_toggle = "Blip",
  blip_note = "Activar/Desactivar el blip en el mapa.",
  allowed_jobs = "Jobs permitidos",
  search_job = "Buscar job",
  imp_job_ph = "Click para buscar... (escribe el job y Enter)",
  imp_job_help = "Permite a estos jobs impoundear vehículos a esta ubicación.",

  -- Admin JS toasts/labels
  imp_modal_edit = "EDITAR IMPOUND",
  imp_jobs_empty = "No hay jobs agregados todavía.",
  imp_job_already_added = "Ese job ya está agregado.",
  imp_err_label_required = "El nombre del Impound es obligatorio.",
  imp_err_coords_invalid = "Coords inválidas.",
  imp_err_need_job = "Agrega al menos 1 job permitido.",
  imp_err_save_failed = "No se pudo guardar.",
  imp_saved_ok = "Guardado correctamente.",
  imp_err_delete_failed = "No se pudo eliminar.",
  imp_deleted_ok = "Eliminado.",
  imp_coords_copied = "Coords copiadas.",

  -- =========================================================
  -- JOB IMPOUNDS (Admin/Staff)
  -- =========================================================
  job_impounds = "IMPOUNDS DE JOB",
  th_plate = "Placa",
  th_vehicle = "Vehículo",
  th_impound = "Impound",
  th_owner = "Dueño",
  th_by = "Por",
  th_status = "Estado",
  th_action = "Acción",

  -- impounds_job.js
  ij_count = "{count} vehículo(s)",
  ij_empty = "No hay vehículos incautados.",
  ij_refresh = "Actualizar",
  ij_refresh_title = "Actualizar lista",

  ij_more_info = "Más info",
  ij_view_reason = "Ver razón",
  ij_unlock = "DESBLOQUEAR",
  ij_unlock_title = "Desbloquear vehículo",

  ij_released = "LIBERADO",
  ij_already_free = "Ya está libre",

  ij_free = "LIBRE",
  ij_locked = "BLOQUEADO",
  ij_locked_wait = "BLOQUEADO ({time})",

  ij_reason_aria = "Nota de impound",
  ij_reason_title = "NOTA DE IMPOUND",
  ij_reason_label = "Descripción de la razón",
  ij_reason_none = "No se especificó una razón.",

  ij_reason_plate = "Placa: {plate}",
  ij_reason_impound = "Impound: {impound}",
  ij_reason_vehicle = "Vehículo: {vehicle}",
  ij_reason_owner = "Dueño: {owner}",
  ij_reason_by = "Por: {by}",

  -- =========================================================
  -- JOB VEHICLES (Admin UI) + jobvehicles.js
  -- =========================================================
  jobveh_th_index = "Índice del Vehículo",
  jobveh_th_model = "Modelo del Vehículo",
  jobveh_th_job = "Para Job",
  jobveh_th_actions = "Acciones",

  jobveh_empty = "No hay vehículos de job aún. Pulsa “CREAR NUEVO”.",
  jobveh_modal_edit = "EDITAR VEHÍCULO DE JOB",
  jobveh_modal_sub = "Modelo, job, rangos permitidos y propiedades.",

  jobveh_lbl_model = "Modelo del Vehículo",
  jobveh_ph_model = "rebla",
  jobveh_help_model = "Escribe el modelo del vehículo.",

  jobveh_lbl_job = "Job del Vehículo",
  jobveh_ph_job = "mechanic",
  jobveh_help_job = "Si está vacío, el job que lo use podrá spawnear este vehículo.",

  jobveh_allowed_grades = "Rangos permitidos",
  jobveh_ph_grade = "Escribe el rango...",
  jobveh_btn_add_grade = "Agregar rango",
  jobveh_note_grades = "Los rangos permitidos podrán usar este vehículo.",

  jobveh_vehicle_props = "Propiedades del Vehículo",
  jobveh_note_props = "Debe ser JSON válido (vehicle props).",

  jobveh_btn_delete = "Eliminar",
  jobveh_btn_cancel = "Cancelar",
  jobveh_btn_save = "Guardar",
  jobveh_title_add_grade = "Agregar rango",

  -- jobvehicles.js hardcodes
  jv_modal_title_create = "CREAR VEHÍCULO DE JOB",
  jv_modal_title_edit = "EDITAR VEHÍCULO DE JOB",

  jv_grades_empty = "No hay rangos agregados.",
  jv_grade_label = "Rango: {grade}",
  jv_grade_remove_title = "Quitar",

  jv_toast_grade_invalid = "Rango inválido (0-100).",
  jv_toast_grade_dup = "Ese rango ya está agregado.",

  jv_err_props_json = "Las propiedades del vehículo deben ser un JSON válido.",
  jv_err_model_required = "El modelo del vehículo es obligatorio.",
  jv_err_job_required = "El job del vehículo es obligatorio.",
  jv_err_load_failed = "No se pudieron cargar los vehículos de job (¿permisos?).",

  jv_actions_title = "Acciones",
  jv_action_edit = "Editar",
  jv_action_delete = "Eliminar",

  jv_err_save_failed = "No se pudo guardar.",
  jv_saved_ok = "Guardado correctamente.",

  jv_err_delete_failed = "No se pudo eliminar.",
  jv_deleted_ok = "Eliminado.",

  jv_err_model_first = "Escribe primero un modelo de vehículo.",
  jv_props_loading = "Cargando propiedades del vehículo...",
  jv_props_fetch_failed = "No se pudieron obtener las propiedades del vehículo.",
  jv_props_pasted_cache = "Propiedades pegadas (caché).",
  jv_props_pasted = "Propiedades pegadas.",
}

-- =========================================================
-- EN (English)
-- =========================================================
Locales.en = {
  -- =========================
  -- Global / Common
  -- =========================
  close = "Close",
  cancel = "Cancel",
  confirm = "Confirm",
  save = "Save",
  edit = "Edit",
  delete = "Delete",
  on = "ON",
  off = "OFF",

  pg_prev = "Previous",
  pg_next = "Next",

  -- =========================
  -- Topbar / Nav
  -- =========================
  ui_title = "GARAGE ADMIN",
  ui_subtitle = "iZaap Studios • Garage Manager",
  nav_garages = "Garages",
  nav_impounds = "Impounds",
  nav_jobvehicles = "Job Vehicles",
  nav_gangvehicles = "Gang Vehicles",

  -- =========================
  -- Toolbars
  -- =========================
  garages_search_ph = "Search for a garage by name or type...",
  add_garage = "Add Garage",
  map_view = "Map View",
  list_view = "List View",
  view_map_title = "View map",
  view_list_title = "View list",

  impounds_search_ph = "Search for Impound",
  impounds_create = "CREATE NEW",

  jobveh_search_ph = "Search for Vehicle",
  jobveh_create = "Create New",

  -- =========================
  -- Tables (Garages)
  -- =========================
  th_garage_label = "Garage Label",
  th_garage_type = "Garage Type",
  th_access = "Access",
  th_private = "Private",
  th_garage_job = "Garage Job",
  th_actions = "Actions",

  garages_empty = "No garages yet. Press “Add Garage”.",

  -- =========================
  -- Access labels
  -- =========================
  access_public = "PUBLIC",
  access_job = "JOB",
  access_gang = "GANG",
  access_private = "PRIVATE",
  access_open_access = "Open access",
  access_players = "{count} player(s)",

  -- =========================
  -- Type labels
  -- =========================
  type_car = "Auto",
  type_boat = "Boat",
  type_air = "Air",

  -- =========================
  -- Map Admin
  -- =========================
  map_title = "Garage Map",
  map_sub = "Click an icon to Edit/Delete",
  map_fit = "Center map",
  map_hint = "Drag to move • Wheel to zoom",
  map_count = "{count} garages",
  map_pop_title = "Garage",

  -- =========================
  -- Section placeholders
  -- =========================
  vehicles_soon = "Vehicles (coming soon)",
  gang_soon = "Gang Vehicles (coming soon)",

  -- =========================
  -- Garage Modal (Admin)
  -- =========================
  modal_edit_garage = "EDIT GARAGE",
  modal_sub_garage = "Configure label, radius, coords, ped coords, z-range and blip.",
  garage_label = "Garage Label",
  garage_label_ph = "Ex: Bajeta Private",
  visible_name = "Visible name.",
  garage_radius = "Garage Radius",
  garage_radius_help = "Access radius (meters).",
  garage_type = "Garage Type",
  garage_type_help = "Select type.",
  garage_location = "Garage Location Coords",
  use_current_coords = "Use current coords",
  garage_location_note = "Define garage base point.",
  ped_coords = "Garage Ped Coords (optional)",
  ped_coords_note = "Optional. Useful for a fixed NPC/spawn.",
  blip_enable = "Enable/Disable blip on map.",
  access_toggle_title = "Collapse/Expand",

  -- Access block
  access_options = "Access Options",
  job_restricted = "Job Restricted",
  job_restricted_ph = "mechanic",
  job_restricted_help = "Enter job name that will only have access to this garage.",
  job_grade_restricted = "Job Grade Restricted",
  job_grade_restricted_help = "Enter job grade from which players will be allowed to use garage.",
  gang_restricted = "Gang Restricted",
  gang_restricted_ph = "ballas",
  gang_restricted_help = "Enter gang name that will only have access to this garage.",
  gang_grade_restricted = "Gang Grade Restricted",
  gang_grade_restricted_help = "Enter gang grade from which players will be allowed to use garage.",
  search_player = "Search for player",
  private_search_ph = "Click to search... (citizenid / license)",
  private_add = "Add player",
  private_help = "Write an identifier and press Enter / + to add (citizenid, license, etc.).",
  garage_mode = "Garage Mode",
  owned_vehicles = "Owned Vehicles",
  job_vehicles = "Job Vehicles",
  garage_mode_help = "Select garage mode (owned/job).",
  public_garage = "PUBLIC GARAGE",
  job_only = "JOB RESTRICTED",
  private_garage = "PRIVATE GARAGE",
  gang_only = "GANG RESTRICTED",
  access_notice = "Notice: You may select only one access type — Job, Gang, or Private. These options cannot be combined. Leave all fields empty if you want to disable access restrictions entirely.",

  -- Garage Admin (app.js extras)
  ga_private_empty = "No players added yet.",
  ga_private_duplicate = "That player is already in the list.",
  ga_blip_applied = "Blip settings applied.",


  -- =========================================================
  -- PLAYER GARAGE UI (garage.js)
  -- =========================================================
  garage_search_sub = "Search by name or plate",
  sort_fav_title = "Sort: Favorites first",
  go_showroom = "GO SHOWROOM",
  garage_player_search_ph = "Search by name or plate",
  vehicles_count = "{count} vehicle(s)",
  veh_count = "{count} vehicle(s)",

  stat_fuel = "Fuel",
  stat_engine = "Engine",
  stat_body = "Body",

  note_still_out = "Your vehicle is still outside (on the street).",
  note_gps_marked = "GPS marked to the vehicle.",
  note_tow_fee = "The tow truck took your car. Take it out again for {fee}.",

  checking_vehicle = "Checking vehicle status...",
  not_in_this_garage = "This vehicle is not in this garage.",

  status_stored = "Stored",
  status_outside = "Outside",
  status_impounded = "Impounded",
  status_job = "Job",
  status_towed = "Towed",

  btn_drive = "Drive",
  btn_drive_fee = "Drive {fee}",
  btn_mark = "Mark Location",
  btn_transfer = "Transfer",

  -- aliases usados por algunos JS
  btn_impounded = "Impounded",
  btn_checking = "Checking...",
  takeout_failed = "Failed to take out the vehicle.",
  mark_failed = "Failed to mark the vehicle.",
  garage_initializing = "Garage is still initializing. Try again in 1–2s.",
  garage_title_fallback = "Garage",
  vehicle_fallback_name = "Vehicle",
  vehicle_impounded_note = "Vehicle impounded.",

  fav_add = "Mark favorite",
  fav_remove = "Remove favorite",
  rename_title = "Rename",
  rename_save = "Save name",
  rename_cancel = "Cancel",

  -- =========================================================
  -- TRANSFER UI
  -- =========================================================
  transfer_title = "Transfer Vehicle",
  plate_label = "Plate: {plate}",
  transfer_plate = "Plate: {plate}",
  select_dest_garage = "Select destination garage",
  transfer_select_ph = "Select a garage",
  transfer_fee = "You will be charged {fee} to transfer",
  transfer = "Transfer",

  transfer_no_garages = "No garages available to transfer (admin).",
  transfer_select_destination = "Select a destination garage.",
  transfer_invalid_plate = "Invalid plate.",
  transfer_failed = "Transfer failed.",
  transfer_ui_error = "Transfer UI error (check F8 console).",
  transfer_select_missing = "Garage select element not found.",

  -- Transfer Player (tabs + list)
  tp_tab_garage = "Transfer to garage",
  tp_tab_player = "Transfer to player",
  tp_search_ph = "Search by ID or name...",
  tp_hint_notify = "The player will receive a notification when the transfer completes.",
  tp_empty_players = "No players.",
  tp_btn_transfer = "TRANSFER",
  tp_status_processing = "Processing transfer...",
  tp_status_done = "Transfer completed.",
  tp_err_no_plate = "Could not read the plate to transfer.",
  tp_err_failed = "Transfer failed.",

  -- =========================================================
  -- CHANGE PLATE UI
  -- =========================================================
  change_plate = "CHANGE PLATE",
  current_plate = "Current plate",
  new_plate = "New plate",
  new_plate_ph = "EX: ABC1234",

  cp_err_write_plate = "Write a new plate.",
  cp_err_max_8 = "Max 8 characters (no spaces).",
  cp_err_offline = "NUI offline",
  cp_err_failed = "Could not change the plate.",

  -- =========================================================
  -- IMPOUNDS (Client world / textui / blips)
  -- =========================================================
  imp_open_label = "Open impound",
  imp_textui_open = "[E] Open impound",
  imp_blip_name = "Impound: {label}",

  -- client_impounds.lua (notify/errors)
  imp_spawn_failed = "Could not spawn the vehicle.",
  imp_no_job_impounds = "Your job has no impounds available.",
  imp_get_out_vehicle = "Exit the vehicle and stand close to it to send it to impound.",
  imp_no_vehicle_near = "No vehicle nearby to send to impound.",
  imp_get_closer_vehicle = "Get closer to the vehicle to send to impound.",
  imp_invalid_plate = "Invalid plate.",
  imp_no_job_assigned = "You don't have a job assigned.",
  imp_no_permission = "You don't have permission to do this.",

  -- =========================================================
  -- IMPOUND UI (Player)
  -- =========================================================
  impound = "IMPOUND",
  impound_search_sub = "Search for Vehicle",
  impound_search_ph = "Search for Vehicle",

  -- Accordion list
  iu_count = "{count} vehicle(s)",
  iu_empty = "No vehicles impounded here.",

  iu_tag_impound = "IMPOUND",
  iu_tag_status_fallback = "OUT OF GARAGE",
  iu_expand_aria = "Expand",

  iu_info_title = "A Vehicle Has Been Impounded!",
  iu_impounded_by = "Impounded by:",
  iu_location = "Location:",
  iu_reason = "Reason:",
  iu_available_at = "Available at:",
  iu_price_now = "Impound now Price:",

  iu_locked = "LOCKED ({time})",
  iu_impound_for = "IMPOUND FOR ${price}",

  iu_prev = "Previous",
  iu_next = "Next",
  iu_showing = "Showing {start}-{end} of {total}",

  iu_wait_time = "WAIT TIME",

  -- =========================================================
  -- IMPOUND INFO WIDGET
  -- =========================================================
  imp_info_title = "Impound Information",
  imp_info_hint = "You must go to the impound to recover your vehicle.",

  imp_k_impound = "Impound",
  imp_k_by = "Impounded by",
  imp_k_reason = "Reason",
  imp_k_fee_before = "Fee (before)",
  imp_k_fee_after = "Fee (after)",
  imp_k_impounded_at = "Impounded at",
  imp_k_status = "Status",

  imp_status_locked = "LOCKED ({time})",
  imp_status_available = "Available",

  -- aliases para el JS (imp_info_k_* / imp_info_status_*)
  imp_info_k_impound = "Impound",
  imp_info_k_by = "Impounded by",
  imp_info_k_reason = "Reason",
  imp_info_k_fee_before = "Fee (before)",
  imp_info_k_fee_after = "Fee (after)",
  imp_info_k_impounded_at = "Impounded at",
  imp_info_k_status = "Status",

  imp_info_status_locked = "LOCKED ({time})",
  imp_info_status_available = "Available",

  imp_info_k_release_at = "Release at",

  -- Time strings
  time_just_now = "just now",
  time_min_ago = "{min} min ago",
  time_h_ago = "{h} h ago",
  time_yesterday = "yesterday",

  -- =========================================================
  -- IMPOUND SEND (Job)
  -- =========================================================
  impound_menu = "Impound Menu",
  impound_menu_sub = "Impound vehicle near you (not inside).",
  vehicle_plate = "Vehicle Plate",
  must_be_near = "Must be near the vehicle.",
  reason_optional = "Reason (optional)",
  reason_ph = "Illegal parking / Parking violations",
  max_255 = "Max 255 characters.",
  impound_location = "Impound Location",
  select_where_goes = "Select where the vehicle will be placed.",
  impound_time = "Impound Time",
  price_before = "Price BEFORE date (Early Release)",
  early_release_disabled = "If 0, early release is disabled (locked until time ends).",
  price_after = "Price AFTER date (Normal Release)",
  fee_after_note = "Fee charged after the lock time ends.",
  impound_btn = "IMPOUND",

  -- Fallback if no real label
  imp_default_label = "Impound",

  -- =========================================================
  -- IMPOUNDS (server notifications)
  -- =========================================================
  imp_invalid = "Invalid impound.",
  imp_job_no_impounds = "Your job has no impounds available to send to.",
  imp_vehicle_not_registered = "This vehicle is not registered (cannot impound).",
  imp_vehicle_sent = "Vehicle sent to impound.",
  imp_locked_cannot_release = "You cannot release this vehicle yet. It is time-locked.",
  imp_not_enough_money = "You don't have enough money.",
  imp_vehicle_released = "Vehicle released from impound.",
  imp_vehicle_not_in_impound = "This vehicle is not in impound.",
  imp_admin_release_done = "Impound released (no fee/time). The player must retrieve it at the impound.",

  -- =========================================================
  -- SHOWROOM HUD
  -- =========================================================
  showroom = "SHOWROOM",
  plate = "PLATE: {plate}",
  engine = "Engine",
  body = "Body",
  fuel = "Fuel",
  exit_backspace = "BACKSPACE to exit",
  not_favorite = "Not favorite",

  showroom_block_street = "LOCKED",
  showroom_block_impound = "IMPOUND - LOCKED",

  -- =========================================================
  -- IMPOUNDS ADMIN (panel)
  -- =========================================================
  imp_th_label = "Impound Label",
  imp_th_type = "Impound Type",
  imp_empty = "No impounds yet. Press “CREATE NEW”.",

  imp_modal_create = "CREATE IMPOUND",
  imp_modal_sub = "Label, type, coords, blip & allowed jobs.",
  imp_label = "Impound Label",
  imp_label_ph = "Enter Label...",
  imp_label_help = "Enter impound label which will be displayed on map.",
  imp_type = "Impound Type",
  imp_type_help = "Select impound type.",
  imp_car = "Car",
  imp_boat = "Boat",
  imp_air = "Air",
  imp_location = "Impound Location Coords",
  use_current = "Use current",
  coords_note = "Set coords and heading for impound location.",
  blip_toggle = "Blip Toggle",
  blip_note = "Enable/Disable blip display on map.",
  allowed_jobs = "Allowed Jobs",
  search_job = "Search for job",
  imp_job_ph = "Click to search... (type job name & press Enter)",
  imp_job_help = "Allow selected jobs to impound vehicles to this location.",

  -- Admin JS toasts/labels
  imp_modal_edit = "EDIT IMPOUND",
  imp_jobs_empty = "No jobs added yet.",
  imp_job_already_added = "That job is already added.",
  imp_err_label_required = "Impound label is required.",
  imp_err_coords_invalid = "Invalid coords.",
  imp_err_need_job = "Add at least 1 allowed job.",
  imp_err_save_failed = "Could not save.",
  imp_saved_ok = "Saved successfully.",
  imp_err_delete_failed = "Could not delete.",
  imp_deleted_ok = "Deleted.",
  imp_coords_copied = "Coords copied.",

  create_now = "Create",
  -- =========================================================
  -- JOB IMPOUNDS (Admin/Staff)
  -- =========================================================
  job_impounds = "JOB IMPOUNDS",
  th_plate = "Plate",
  th_vehicle = "Vehicle",
  th_impound = "Impound",
  th_owner = "Owner",
  th_by = "By",
  th_status = "Status",
  th_action = "Action",

  -- impounds_job.js
  ij_count = "{count} vehicle(s)",
  ij_empty = "No impounded vehicles.",
  ij_refresh = "Refresh",
  ij_refresh_title = "Refresh list",

  ij_more_info = "More info",
  ij_view_reason = "View reason",
  ij_unlock = "UNLOCK",
  ij_unlock_title = "Unlock vehicle",

  ij_released = "RELEASED",
  ij_already_free = "Already free",

  ij_free = "FREE",
  ij_locked = "LOCKED",
  ij_locked_wait = "LOCKED ({time})",

  ij_reason_aria = "Impound note",
  ij_reason_title = "IMPOUND NOTE",
  ij_reason_label = "Reason description",
  ij_reason_none = "No reason specified.",

  ij_reason_plate = "Plate: {plate}",
  ij_reason_impound = "Impound: {impound}",
  ij_reason_vehicle = "Vehicle: {vehicle}",
  ij_reason_owner = "Owner: {owner}",
  ij_reason_by = "By: {by}",

  -- =========================================================
  -- JOB VEHICLES (Admin UI) + jobvehicles.js
  -- =========================================================
  jobveh_th_index = "Vehicle Index",
  jobveh_th_model = "Vehicle Model",
  jobveh_th_job = "For Job",
  jobveh_th_actions = "Actions",

  jobveh_empty = "No job vehicles yet. Press “CREATE NEW”.",
  jobveh_modal_edit = "EDIT JOB VEHICLE",
  jobveh_modal_sub = "Model, job, allowed grades and properties.",

  jobveh_lbl_model = "Vehicle Model",
  jobveh_ph_model = "rebla",
  jobveh_help_model = "Enter vehicle model.",

  jobveh_lbl_job = "Vehicle Job",
  jobveh_ph_job = "mechanic",
  jobveh_help_job = "If empty, the job that uses it will be allowed to spawn this vehicle.",

  jobveh_allowed_grades = "Allowed Grades",
  jobveh_ph_grade = "Enter Grade...",
  jobveh_btn_add_grade = "Add grade",
  jobveh_note_grades = "Allowed grades can use this vehicle.",

  jobveh_vehicle_props = "Vehicle Properties",
  jobveh_note_props = "Must be valid JSON (vehicle props).",

  jobveh_btn_delete = "Delete",
  jobveh_btn_cancel = "Cancel",
  jobveh_btn_save = "Save",
  jobveh_title_add_grade = "Add grade",

  -- jobvehicles.js hardcodes
  jv_modal_title_create = "CREATE JOB VEHICLE",
  jv_modal_title_edit = "EDIT JOB VEHICLE",

  jv_grades_empty = "No grades added.",
  jv_grade_label = "Grade: {grade}",
  jv_grade_remove_title = "Remove",

  jv_toast_grade_invalid = "Invalid grade (0-100).",
  jv_toast_grade_dup = "That grade is already added.",

  jv_err_props_json = "Vehicle Properties must be valid JSON.",
  jv_err_model_required = "Vehicle Model is required.",
  jv_err_job_required = "Vehicle Job is required.",
  jv_err_load_failed = "Could not load job vehicles (permission?).",

  jv_actions_title = "Actions",
  jv_action_edit = "Edit",
  jv_action_delete = "Delete",

  jv_err_save_failed = "Could not save.",
  jv_saved_ok = "Saved successfully.",

  jv_err_delete_failed = "Could not delete.",
  jv_deleted_ok = "Deleted.",

  jv_err_model_first = "Write a vehicle model first.",
  jv_props_loading = "Loading vehicle properties...",
  jv_props_fetch_failed = "Could not fetch vehicle properties.",
  jv_props_pasted_cache = "Properties pasted (cache).",
  jv_props_pasted = "Properties pasted.",
}

local function interpolate(s, vars)
  if type(s) ~= "string" then return s end
  if type(vars) ~= "table" then return s end
  return (s:gsub("{(.-)}", function(k)
    local v = vars[k]
    if v == nil then return "{" .. k .. "}" end
    return tostring(v)
  end))
end

local M = {}

function M.get(locale)
  locale = tostring(locale or "en"):lower()
  return Locales[locale] or Locales.en
end

function M.t(locale, key, vars)
  local dict = M.get(locale)
  local s = dict[key] or (Locales.en and Locales.en[key]) or key
  return interpolate(s, vars)
end

_G.IZAAP_LOCALES = M

return M

```

{% endtab %}
{% endtabs %}
