feat: add Spanish (es_MX) translation for Career Portal#810
Conversation
- 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)
There was a problem hiding this comment.
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.phpto 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.
| */ | ||
|
|
||
| $rssPage = true; | ||
| if (!defined("LEGACY_ROOT")) { define("LEGACY_ROOT", dirname(__FILE__) . "/.."); } |
| @session_name(CATS_SESSION_NAME); | ||
| session_start(); | ||
| if (session_status() === PHP_SESSION_NONE) { session_start(); } |
| <?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; ?> |
| <?php if (is_array($this->parsingStatus) && $this->parsingStatus['parseLimit'] >= 0 && $this->parsingStatus['parseUsed'] >= $this->parsingStatus['parseLimit']): ?> | ||
| | ||
| <?php else: ?> | ||
| <?php if ($this->isModal): ?> <?php else: ?> <?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): ?> |
| // 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); |
| $sUrl = 'https://maps.googleapis.com/maps/api/geocode/xml?sensor=false&address='; | ||
| $oXml = simplexml_load_file($sUrl . rawurlencode($zip)); |
| $allowedColumns = array('candidate.zip', 'zipcode', 'zip'); | ||
| if (!in_array($zipcodeColumn, $allowedColumns, true)) { | ||
| return array("select" => "0 as distance_km", "join" => ""); | ||
| } |
| } catch (Exception $e) { | ||
| // Mail not configured or failed - log error for debugging | ||
| $mailerStatus = false; | ||
|
|
||
| error_log('OpenCATS Mailer error (site=' . $this->_siteID . '): ' . $e->getMessage()); | ||
| } |
| </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" /> * |
|
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. |
|
Hello! I recently submitted PR #810 with a working Spanish (es_MX) The implementation uses template-based language detection (a "CATS 2.0 ES" I completely agree with the suggestion to wait for a proper i18n
Looking forward to contributing to the Laravel migration and a proper i18n |
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
containing "ES" activates Spanish strings)
Position Title → Puesto, Location → Ubicación
Continue to Application → Continuar a la solicitud,
Submit Application → Enviar solicitud, Login → Iniciar sesión
Bienvenido de nuevo / Cerrar sesión / Actualizar perfil
install/es_MX_career_portal_template.sql
Career Portal sections:
install/es_MX_README.md
How to activate
Backward compatibility
Tested on