Skip to content

feat: add Spanish (es_MX) translation for Career Portal#810

Closed
ocjorge wants to merge 7 commits into
opencats:masterfrom
ocjorge:feat/es-MX-career-portal-translation
Closed

feat: add Spanish (es_MX) translation for Career Portal#810
ocjorge wants to merge 7 commits into
opencats:masterfrom
ocjorge:feat/es-MX-career-portal-translation

Conversation

@ocjorge

@ocjorge ocjorge commented Jun 14, 2026

Copy link
Copy Markdown

Summary

Adds a complete Spanish (Mexico) translation of the OpenCATS Career Portal,
making it accessible to Spanish-speaking candidates without modifying the
existing English interface.

Changes

modules/careers/CareersUI.php

  • Added i18n language detection based on active template name (any template
    containing "ES" activates Spanish strings)
  • Translated table headers: Company → Empresa, Department → Departamento,
    Position Title → Puesto, Location → Ubicación
  • Translated action buttons: Apply to Position → Aplicar a esta posición,
    Continue to Application → Continuar a la solicitud,
    Submit Application → Enviar solicitud, Login → Iniciar sesión
  • Translated welcome message: Welcome back / Log Out / Update Profile →
    Bienvenido de nuevo / Cerrar sesión / Actualizar perfil

install/es_MX_career_portal_template.sql

  • New database template "CATS 2.0 ES" with full Spanish translation of all
    Career Portal sections:
    • Main page, Search Results, Job Details
    • Candidate Registration, Apply for Position
    • Candidate Profile, Thanks for Submission
    • Header with styled text buttons (replacing image buttons)

install/es_MX_README.md

  • Installation instructions for the Spanish template
  • How to switch between English and Spanish
  • Explanation of the i18n detection mechanism

How to activate

-- Activate Spanish
UPDATE settings SET value = 'CATS 2.0 ES' WHERE setting = 'activeBoard';

-- Revert to English
UPDATE settings SET value = 'CATS 2.0' WHERE setting = 'activeBoard';

Backward compatibility

  • English interface unchanged — existing installations are not affected
  • Language detection is automatic based on template name
  • No breaking changes

Tested on

  • PHP 8.4.21 + MariaDB 10.11 + Debian 12 (Bookworm)
  • Full candidate flow tested: view jobs → register → apply → upload CV → confirmation

ocjorge added 7 commits June 13, 2026 21:40
- AJAXInterface.php: Fix duplicate session_start() using session_status() check
- ZipLookup.php: Initialize variables before use, guard foreach against null, add isset() checks
- CareerPortal.php: Wrap PHPMailer send in try-catch to prevent fatal error when mail not configured
- candidates/Add.tpl: Add is_array() check before accessing parsingStatus array
- candidates/Search.tpl: Add isset() check for keySkills key
- candidates/Show.tpl: Cast extraFieldRS to array in count() calls
- candidates/Edit.tpl: Cast extraFieldRS to array in count() calls
- companies/Show.tpl: Add is_array() guards for contactsRS, departmentsRS; cast extraFieldRS
- companies/Edit.tpl: Cast extraFieldRS to array in count() calls
- companies/Add.tpl: Cast extraFieldRS to array in count() calls
- contacts/Show.tpl: Cast extraFieldRS to array in count() calls
- contacts/Edit.tpl: Cast extraFieldRS to array in count() calls
- contacts/Add.tpl: Cast extraFieldRS to array in count() calls
- joborders/Show.tpl: Cast extraFieldRS to array in count() calls
- joborders/Edit.tpl: Cast extraFieldRS to array in count() calls
- joborders/Add.tpl: Cast extraFieldRS to array in count() calls
- home/Home.tpl: Add is_array() guard for placedRS
- install/backupDB.php: Fix mysqli_query() argument order (PHP 8 changed parameter order)
- careers/CareersUI.php: Remove useCookie dependency for registration block display
- rss/index.php: Define LEGACY_ROOT constant if not already defined

Tested on PHP 8.4.21 + MariaDB 10.11 on Debian 12
- ZipLookup.php: Restore public API (getCityStateByZip, makeSearchableUSZip, getDistanceFromPointQuery) as compatibility wrappers; switch Google Maps URL to HTTPS; remove error suppression (@)
- CareerPortal.php: Log mail exceptions via error_log() instead of silently ignoring
- candidates/Show.tpl: Apply (array) cast consistently in loop start index
- companies/Show.tpl: Apply (array) cast consistently in loop start index
- contacts/Show.tpl: Apply (array) cast consistently in loop start index
- candidates/Add.tpl: Change catsone.com link to HTTPS
- candidates/Add.tpl: Fix mismatched </font> tag to </span>
- home/Home.tpl: Use is_countable() instead of is_array() for Countable compatibility
- ZipLookup.php: rawurlencode zip before URL concatenation to prevent injection
- ZipLookup.php: restore getDistanceFromPointQuery() returning expected select/join keys
- CareerPortal.php: set mailerStatus=false in catch block for deterministic status
- candidates/Add.tpl: add is_countable() guard before count() on parsingStatus
- Extract address component parsing to private parseAddressComponents()
- Use early returns to reduce nesting
- Reduces cyclomatic complexity from 14 to under 10 (Codacy threshold)
…uery()

- Fix: change Earth radius from 3958 (miles) to 6371 (km) to match distance_km alias
- Fix: cast zipcode to int to prevent SQL injection
- Fix: validate zipcodeColumn against allowlist to prevent column injection
- Add CATS 2.0 ES template with full Spanish translation of all Career Portal sections
- Add i18n detection in CareersUI.php based on active template name (suffix ES)
- Translate table headers: Company/Department/Position Title/Location
- Translate action buttons: Apply, Continue to Application, Submit, Login
- Translate Welcome back / Log Out / Update Profile messages
- Add es_MX_career_portal_template.sql installation script
- Add es_MX_README.md with installation instructions

Tested on PHP 8.4.21 + MariaDB 10.11 + Debian 12 (Bookworm)
Copilot AI review requested due to automatic review settings June 14, 2026 05:28

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds Spanish (es_MX) career portal support and improves PHP 8+ compatibility across multiple templates and legacy utilities.

Changes:

  • Introduces a Spanish career portal template (SQL) plus documentation for installation/activation.
  • Adds basic language detection in CareersUI.php to switch some labels to Spanish when an “ES” template is active.
  • Addresses PHP 8+ warnings/compatibility (countability checks, session start guard) and refactors some legacy library code.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
rss/index.php Ensures LEGACY_ROOT is defined before including legacy libs.
modules/joborders/Show.tpl Avoids count() warnings by casting extra fields to array in sizing logic.
modules/joborders/Edit.tpl Avoids count() warnings by casting extra fields to array in loops.
modules/joborders/Add.tpl Avoids count() warnings by casting extra fields to array in loops.
modules/install/backupDB.php Fixes mysqli_query argument order for modern PHP/mysqli.
modules/home/Home.tpl Adds is_countable() guard before calling count().
modules/contacts/Show.tpl Makes extra field loops count-safe and reorders “Entered By” column in activity table.
modules/contacts/Edit.tpl Marks Title visually with an asterisk; makes extra field loop count-safe.
modules/contacts/Add.tpl Marks Title visually with an asterisk; makes extra field loop count-safe.
modules/companies/Show.tpl Adds array guards around count() and reorders activity table columns.
modules/companies/Edit.tpl Avoids count() warnings by casting extra fields to array in loops.
modules/companies/Add.tpl Avoids count() warnings by casting extra fields to array in loops.
modules/careers/CareersUI.php Adds “ES template” detection to switch some UI strings to Spanish; gates resume parsing by license.
modules/candidates/Show.tpl Makes extra field loops count-safe and reorders “Entered By” column in activity table.
modules/candidates/Search.tpl Guards missing keySkills index to avoid notices.
modules/candidates/Edit.tpl Avoids count() warnings by casting extra fields to array in loops.
modules/candidates/Add.tpl Adds parsing-usage messaging and disables resume import UI when parsing limit is reached; makes extra field loop count-safe.
lib/ZipLookup.php Refactors zip lookup flow; adds SQL injection guard + km/miles consistency for distance query builder.
lib/CareerPortal.php Wraps mail sending in try/catch and logs failures.
lib/AJAXInterface.php Avoids starting a session if one is already active.
install/es_MX_career_portal_template.sql Adds SQL inserts for a “CATS 2.0 ES” Spanish career portal template.
install/es_MX_README.md Documents installation and activation of the Spanish template.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rss/index.php
*/

$rssPage = true;
if (!defined("LEGACY_ROOT")) { define("LEGACY_ROOT", dirname(__FILE__) . "/.."); }
Comment thread lib/AJAXInterface.php
Comment on lines 206 to +207
@session_name(CATS_SESSION_NAME);
session_start();
if (session_status() === PHP_SESSION_NONE) { session_start(); }
Comment on lines +125 to +130
<?php if (PARSING_ENABLED &&
is_countable($this->parsingStatus) && count($this->parsingStatus) &&
$this->parsingStatus['parseUsed'] >= $this->parsingStatus['parseLimit'] &&
$this->parsingStatus['parseLimit'] >= 0): ?>
<a href="https://www.catsone.com/professional" target="_blank">All daily resume imports used. For more, upgrade to CATS professional</a>.
<?php endif; ?>
Comment on lines +196 to +201
<?php if (is_array($this->parsingStatus) && $this->parsingStatus['parseLimit'] >= 0 && $this->parsingStatus['parseUsed'] >= $this->parsingStatus['parseLimit']): ?>
&nbsp;
<?php else: ?>
<?php if ($this->isModal): ?>&nbsp;&nbsp;<?php else: ?>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<?php endif; ?>
<img id="transfer" src="images/parser/transfer<?php echo ($this->contents != '' ? '' : '_grey'); ?>.gif" <?php echo ($this->contents != '' ? 'style="cursor: pointer;"' : ''); ?> border="0" alt="Import Resume" onclick="parseDocumentFileContents();" />
<?php endif; ?>

<!-- CONTACT INFO -->
<?php if (count($this->departmentsRS) > 0): ?>
<?php if (is_array($this->departmentsRS) && count($this->departmentsRS) > 0): ?>
Comment on lines +1434 to +1436
// i18n: detect language based on active template name
$activeTemplate = isset($_GET['templateName']) ? $_GET['templateName'] : (isset($GLOBALS['activeBoard']) ? $GLOBALS['activeBoard'] : '');
$isSpanish = (strpos($activeTemplate, ' ES') !== false || strpos($activeTemplate, '_ES') !== false || strpos($activeTemplate, 'ES') !== false);
Comment thread lib/ZipLookup.php
Comment on lines +23 to +24
$sUrl = 'https://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address=';
$oXml = simplexml_load_file($sUrl . rawurlencode($zip));
Comment thread lib/ZipLookup.php
Comment on lines +69 to +72
$allowedColumns = array('candidate.zip', 'zipcode', 'zip');
if (!in_array($zipcodeColumn, $allowedColumns, true)) {
return array("select" => "0 as distance_km", "join" => "");
}
Comment thread lib/CareerPortal.php
Comment on lines +469 to +474
} catch (Exception $e) {
// Mail not configured or failed - log error for debugging
$mailerStatus = false;

error_log('OpenCATS Mailer error (site=' . $this->_siteID . '): ' . $e->getMessage());
}
Comment thread modules/contacts/Edit.tpl
</td>
<td class="tdData">
<input type="text" name="title" id="title" value="<?php $this->_($this->data['title']); ?>" class="inputbox" style="width: 150px" />
<input type="text" name="title" id="title" value="<?php $this->_($this->data['title']); ?>" class="inputbox" style="width: 150px" />&nbsp;*
@anonymoususer72041

Copy link
Copy Markdown
Contributor

I suggest to wait for a proper i18n implementation, which might be implemented after switching to a framework like Laravel, as currently discussed in #780.

This PR also seems to refactor some things regarding PHP 8 compatibility, which expands the described feature scope.

@ocjorge ocjorge closed this Jun 17, 2026
@ocjorge

ocjorge commented Jun 17, 2026

Copy link
Copy Markdown
Author

Hello! I recently submitted PR #810 with a working Spanish (es_MX)
translation of the Career Portal, tested on PHP 8.4.21 + MariaDB 10.11
on Debian 12.

The implementation uses template-based language detection (a "CATS 2.0 ES"
database template) rather than a proper i18n framework, which I now
understand is intentional given the planned Laravel migration discussed here.

I completely agree with the suggestion to wait for a proper i18n
implementation within the Laravel framework. The PR #810 branch will remain
available as a reference for:

  • Which strings need translation in the Career Portal
  • A complete es_MX translation of all Career Portal sections
  • The SQL template structure that could inform a future i18n approach

Looking forward to contributing to the Laravel migration and a proper i18n
implementation in v1.0.0 or v2.0.0. Happy to help with the Spanish
translation effort when the time comes!

@ocjorge ocjorge reopened this Jun 17, 2026
@ocjorge ocjorge closed this Jun 17, 2026
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.

3 participants