Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-hooks', 'wp-i18n'), 'version' => '0491df37b6a1e537a25f');
<?php return array('dependencies' => array('react', 'wp-block-editor', 'wp-components', 'wp-hooks', 'wp-i18n'), 'version' => 'fdda3cb08621f4cb8256');
2 changes: 1 addition & 1 deletion modules/blocks-v2/phone-field/assets/build/editor/index.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array(), 'version' => '92ba0e044099359e44a2');
<?php return array('dependencies' => array(), 'version' => 'a72ffadd3ce1e0830d2a');

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions modules/blocks-v2/phone-field/assets/src/editor/block/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export default function IntlPhoneEdit( props ) {
/>

<BaseControl
id={ uniqKey( 'preferredCountries' ) }
label={ __( 'Preferred Countries', 'jet-form-builder' ) }
help={ __( 'Comma-separated country codes (e.g., "US, GB, UA").', 'jet-form-builder' ) }
>
Expand All @@ -77,6 +78,7 @@ export default function IntlPhoneEdit( props ) {
</BaseControl>

<BaseControl
id={ uniqKey( 'onlyCountries' ) }
label={ __( 'Only Countries', 'jet-form-builder' ) }
help={ __( 'Show only these countries (e.g., "US, CA, MX").', 'jet-form-builder' ) }
>
Expand All @@ -91,6 +93,7 @@ export default function IntlPhoneEdit( props ) {

{ attributes.only_countries.length <= 0 && (
<BaseControl
id={ uniqKey( 'excludeCountries' ) }
label={ __( 'Exclude Countries', 'jet-form-builder' ) }
help={ __( 'Exclude these countries (e.g., "US, BY")', 'jet-form-builder' ) }
>
Expand Down Expand Up @@ -128,6 +131,7 @@ export default function IntlPhoneEdit( props ) {
'jet-form-builder'
) }
/>

</PanelBody>

<PanelBody
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { loadCurrentLocaleTranslations } from './i18n-loader';
import {
loadCurrentLocaleTranslations,
} from './i18n-loader';

const {
InputData,
Expand All @@ -17,6 +19,7 @@ function PhoneFieldData() {

/**
* Check if this handler supports the field
* @param node
*/
this.isSupported = function ( node ) {
const supported = node.classList.contains( 'phone-field' );
Expand Down Expand Up @@ -54,7 +57,6 @@ function PhoneFieldData() {
const excludeCountries = this.parseCountryList( node.dataset.excludeCountries );
const separateDialCode = node.dataset.separateDialCode || false;
const ipinfoToken = node.dataset.ipinfoToken || '';

// Determine initial country
let initialCountry = defaultCountry;

Expand All @@ -69,8 +71,8 @@ function PhoneFieldData() {

// Build config object, only include arrays if they have items
const config = {
initialCountry: initialCountry,
separateDialCode: 1 == separateDialCode ? true : false,
initialCountry,
separateDialCode: separateDialCode === '1',
strictMode: true,
nationalMode: true,
formatAsYouType: true,
Expand Down Expand Up @@ -104,8 +106,8 @@ function PhoneFieldData() {
this.normalizeIfInternational = function( input ) {
const value = input.value.trim();

if ( !value ) return;
if ( value[0] === '+' ) {
if ( !value ) { return; }
if ( '+' === value[ 0 ] ) {
this.itiInstance.setNumber( value );

this.setValue();
Expand All @@ -114,6 +116,7 @@ function PhoneFieldData() {

/**
* Parse comma-separated country list
* @param str
*/
this.parseCountryList = function ( str ) {
if ( ! str ) {
Expand All @@ -124,6 +127,7 @@ function PhoneFieldData() {

/**
* Detect country by IP using ipinfo.io
* @param token
*/
this.detectCountryByIP = function ( token ) {
// Use cached value if available
Expand Down Expand Up @@ -151,7 +155,7 @@ function PhoneFieldData() {
}
}
} )
.catch( error => {
.catch( () => {
} );

return null;
Expand Down Expand Up @@ -214,7 +218,7 @@ function PhoneFieldData() {
let libraryTranslations = {};
try {
libraryTranslations = await loadCurrentLocaleTranslations();
} catch ( error ) {
} catch {
}

// Merge translations: WordPress overrides library translations
Expand Down Expand Up @@ -252,7 +256,7 @@ function PhoneFieldData() {
this.syncFromIntlInput( input, node );

// Validate and show error before submit
const isValid = this.validateAndShowError();
this.validateAndShowError();
}, true); // Use capture phase to run before JetFormBuilder
}

Expand Down Expand Up @@ -289,6 +293,8 @@ function PhoneFieldData() {

/**
* Sync value from intl-tel-input field to main field
* @param intlInput
* @param mainField
*/
// eslint-disable-next-line no-unused-vars
this.syncFromIntlInput = function ( intlInput, mainField ) {
Expand Down Expand Up @@ -322,6 +328,7 @@ function PhoneFieldData() {

/**
* Show error message under the phone field
* @param message
*/
this.showError = function ( message ) {
const wrapper = this.getWrapperNode();
Expand Down Expand Up @@ -388,6 +395,7 @@ function PhoneFieldData() {

/**
* Get validation message from data-attributes or fallback
* @param type
*/
this.getValidationMessage = function ( type ) {
const mainField = this.nodes[ 0 ];
Expand Down
191 changes: 119 additions & 72 deletions modules/blocks-v2/phone-field/assets/src/frontend/field/i18n-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,46 @@
*/

/**
* Map WordPress locale codes to intl-tel-input i18n folder names
* Map normalized locale codes to intl-tel-input i18n folder names.
*/
const localeMap = {
// WordPress locale => intl-tel-input i18n folder
'uk': 'uk', // Ukrainian
'ru_RU': 'ru', // Russian
'de_DE': 'de', // German
'fr_FR': 'fr', // French
'es_ES': 'es', // Spanish
'it_IT': 'it', // Italian
'pl_PL': 'pl', // Polish
'pt_PT': 'pt', // Portuguese
'pt_BR': 'pt', // Portuguese (Brazil)
'nl_NL': 'nl', // Dutch
'ja': 'ja', // Japanese
'zh_CN': 'zh', // Chinese
'ko_KR': 'ko', // Korean
'ar': 'ar', // Arabic
'tr_TR': 'tr', // Turkish
'sv_SE': 'sv', // Swedish
'da_DK': 'da', // Danish
'fi': 'fi', // Finnish
'no': 'no', // Norwegian
'cs_CZ': 'cs', // Czech
'hu_HU': 'hu', // Hungarian
'ro_RO': 'ro', // Romanian
'bg_BG': 'bg', // Bulgarian
'hr': 'hr', // Croatian
'sk_SK': 'sk', // Slovak
'el': 'el', // Greek
'th': 'th', // Thai
'vi': 'vi', // Vietnamese
'id_ID': 'id', // Indonesian
'hi_IN': 'hi', // Hindi
'bn_BD': 'bn', // Bengali
'ur': 'ur', // Urdu
'fa_IR': 'fa', // Persian
'mr': 'mr', // Marathi
'te': 'te', // Telugu
'bs_BA': 'bs', // Bosnian
'ca': 'ca', // Catalan
'en_US': 'en', // English (US)
'en': 'en', // English (generic)
ar: 'ar',
bg: 'bg',
bn: 'bn',
bs: 'bs',
ca: 'ca',
cs: 'cs',
da: 'da',
de: 'de',
el: 'el',
en: 'en',
es: 'es',
fa: 'fa',
fi: 'fi',
fr: 'fr',
hi: 'hi',
hr: 'hr',
hu: 'hu',
id: 'id',
it: 'it',
ja: 'ja',
ko: 'ko',
mr: 'mr',
nl: 'nl',
no: 'no',
pl: 'pl',
pt: 'pt',
ro: 'ro',
ru: 'ru',
sk: 'sk',
sv: 'sv',
te: 'te',
th: 'th',
tr: 'tr',
uk: 'uk',
ur: 'ur',
vi: 'vi',
zh: 'zh',
};

/**
Expand Down Expand Up @@ -100,15 +97,67 @@ const loaders = {
*/
const translationCache = {};

const getWindowLocaleContext = () => {
return typeof window.jfbPhoneFieldLocaleContext === 'object' &&
window.jfbPhoneFieldLocaleContext !== null
? window.jfbPhoneFieldLocaleContext
: {};
};

const getFirstNormalizedLocale = ( candidates = [] ) => {
for ( const locale of candidates ) {
const normalizedLocale = normalizeLocale( locale );

if ( normalizedLocale ) {
return normalizedLocale;
}
}

return '';
};

export function normalizeLocale( locale ) {
if ( ! locale || 'string' !== typeof locale ) {
return '';
}

const sanitized = locale.trim().replace( /-/g, '_' );

if ( ! sanitized ) {
return '';
}

const [ language = '', region = '' ] = sanitized.split( '_' );

if ( ! language ) {
return '';
}

return region
? `${ language.toLowerCase() }_${ region.toUpperCase() }`
: language.toLowerCase();
}

export function resolveIntlLocale( locale ) {
const normalizedLocale = normalizeLocale( locale );

if ( ! normalizedLocale ) {
return 'en';
}

const [ language ] = normalizedLocale.split( '_' );

return localeMap[ normalizedLocale ] || localeMap[ language ] || 'en';
}

/**
* Load translations for intl-tel-input (ESM import approach)
*
* @param {string} wpLocale - WordPress locale (e.g., 'uk', 'de_DE')
* @return {Promise<Object>} - Promise that resolves to translations object
*/
export async function loadIntlTelInputLocale( wpLocale ) {
// Get intl-tel-input locale code
const locale = localeMap[ wpLocale ] || 'en';
const locale = resolveIntlLocale( wpLocale );

// English is built-in to intl-tel-input, no need to load
if ( locale === 'en' ) {
Expand Down Expand Up @@ -140,8 +189,7 @@ export async function loadIntlTelInputLocale( wpLocale ) {
translationCache[ locale ] = translations;

return translations;
} catch ( error ) {
console.error( `[PhoneField] Failed to load locale "${ locale }":`, error );
} catch {
return {};
}
}
Expand All @@ -151,34 +199,29 @@ export async function loadIntlTelInputLocale( wpLocale ) {
*
* @return {string} WordPress locale code
*/
export function getWordPressLocale() {
let locale = '';

// Try to get from HTML lang attribute
const htmlLang = document.documentElement.lang;

if ( htmlLang ) {
// Convert 'uk-UA' to 'uk', 'en-US' to 'en_US'
// But keep simple codes like 'uk' as is
if ( htmlLang.includes( '-' ) ) {
locale = htmlLang.replace( '-', '_' );
} else {
locale = htmlLang;
}
}
export function getPageLocale() {
const localeContext = getWindowLocaleContext();

return getFirstNormalizedLocale( [
localeContext.pageLocale,
localeContext.pageLang,
document.documentElement?.lang,
localeContext.siteLocale,
localeContext.siteLang,
] );
}

// Try to get from WordPress global variables
if ( ! locale && typeof window.wp !== 'undefined' && window.wp.i18n ) {
// WordPress 5.0+ has locale info
locale = window.wp.i18n.getLocaleData?.()?.locale || '';
}
export function getSiteLocale() {
const localeContext = getWindowLocaleContext();

// Fallback to English
if ( ! locale ) {
locale = 'en';
}
return getFirstNormalizedLocale( [
localeContext.siteLocale,
localeContext.siteLang,
] );
}

return locale;
export function resolveCurrentLocale() {
return getPageLocale() || 'en';
}

/**
Expand All @@ -187,14 +230,18 @@ export function getWordPressLocale() {
* @return {Promise<Object>} Country translations
*/
export async function loadCurrentLocaleTranslations() {
const locale = getWordPressLocale();
const locale = resolveCurrentLocale();

return await loadIntlTelInputLocale( locale );
}

export default {
loadIntlTelInputLocale,
loadCurrentLocaleTranslations,
getWordPressLocale,
getPageLocale,
getSiteLocale,
resolveCurrentLocale,
resolveIntlLocale,
normalizeLocale,
localeMap,
};
Loading
Loading