Files
claude 98979b58f8 refactor: Extract shared JavaScript utilities (Step 1 of 6)
Create reusable utility modules to eliminate duplication across main.js,
cv-matcher.js, and legal.js:

- js/utils/form-helpers.js: showFieldError, clearFieldErrors, isValidEmail,
  extractApiError — shared form validation and error handling
- js/utils/i18n.js: currentLang, t, applyLanguage, updateLegalLinks,
  browserLang — shared translation and language switching
- js/utils/api.js: checkApiLive, getRecaptchaWebKey, getGoogleTagManagerId,
  loadGoogleTagManager — shared API configuration loading
- js/modules/cookie-consent.js: getConsent, setConsent, initConsent,
  setupConsentHandlers — cookie banner and consent management

All utilities exposed on window.MyAi namespace for use by existing pages.
Full JSDoc headers and inline comments for maintainability.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-29 09:05:51 +03:00

92 lines
2.8 KiB
JavaScript

/**
* Internationalization (i18n) Utilities
*
* Shared helpers for language detection, translation lookup, and language switching.
* Expects window.MyAi.i18n dictionary to be populated by i18n.js.
*/
var LANG_KEY = "myai_lang";
/**
* Detect browser language preference from navigator.
* Returns 'ro' if browser language starts with 'ro', otherwise 'en'.
*
* @returns {string} - 'ro' or 'en'
*/
function browserLang() {
return ((navigator.language || navigator.userLanguage || 'en').toLowerCase().indexOf('ro') === 0) ? 'ro' : 'en';
}
/**
* Get the currently active language preference.
* Uses localStorage if set, otherwise detects from browser.
*
* @returns {string} - 'ro' or 'en'
*/
function currentLang() {
return localStorage.getItem(LANG_KEY) || browserLang();
}
/**
* Translate a key into the current language.
* Falls back to English if key not found in the current language.
* Requires window.MyAi.i18n to be populated with en/ro dictionaries.
*
* Usage: MyAi.t('form.name') → "Name" (or "Nume" if lang is 'ro')
*
* @param {string} key - Translation key (e.g., 'form.name')
* @returns {string} - Translated text or fallback key if not found
*/
function t(key) {
var lang = currentLang();
return (window.MyAi.i18n[lang] && window.MyAi.i18n[lang][key]) ||
window.MyAi.i18n.en[key] || key;
}
/**
* Apply a language across the entire page.
* Updates:
* - localStorage with new language preference
* - <html lang> attribute
* - All [data-i18n] elements with translated text
* - All [data-i18n-placeholder] elements with translated placeholders
* - Legal page links to point to correct language version
* - Language button states (aria-pressed)
*
* @param {string} lang - Language code ('en' or 'ro')
*/
function applyLanguage(lang) {
localStorage.setItem(LANG_KEY, lang);
document.documentElement.lang = lang;
updateLegalLinks(lang);
$('[data-i18n]').each(function () {
$(this).text(t($(this).data('i18n')));
});
$('[data-i18n-placeholder]').each(function () {
$(this).attr('placeholder', t($(this).data('i18n-placeholder')));
});
$('.lang-flag').attr('aria-pressed', 'false');
$('.lang-flag[data-lang="' + lang + '"]').attr('aria-pressed', 'true');
}
/**
* Update all legal page links to point to the active language version.
* Looks for [data-legal] attribute (e.g., data-legal="terms") and
* updates href to /legal/{page}-{lang}.html
*
* @param {string} lang - Language code ('en' or 'ro')
*/
function updateLegalLinks(lang) {
$('[data-legal]').each(function () {
var page = $(this).data('legal');
$(this).attr('href', '/legal/' + page + '-' + lang + '.html');
});
}
// Expose i18n utilities on window.MyAi for use by other scripts
window.MyAi = window.MyAi || {};
window.MyAi.currentLang = currentLang;
window.MyAi.t = t;
window.MyAi.applyLanguage = applyLanguage;
window.MyAi.browserLang = browserLang;