| 1 |
/** |
| 2 |
* Internationalization (i18n) utility |
| 3 |
* Handles translations for UI text |
| 4 |
*/ |
| 5 |
|
| 6 |
declare global { |
| 7 |
interface Window { |
| 8 |
yatraAdmin?: { |
| 9 |
apiUrl?: string; |
| 10 |
restUrl?: string; |
| 11 |
nonce?: string; |
| 12 |
brandLogoUrl?: string; |
| 13 |
/** |
| 14 |
* Operator-facing brand name. When the White Label module is |
| 15 |
* active (Agency-tier only) and the operator has filled in |
| 16 |
* "Plugin name" in WL settings, this is THAT value — otherwise |
| 17 |
* it's "Yatra". Use this everywhere instead of hardcoding |
| 18 |
* "Yatra" so the UI reflects the operator's brand for resellers. |
| 19 |
* |
| 20 |
* Injected by AdminAssetsProvider via `yatra_get_brand_name()`. |
| 21 |
*/ |
| 22 |
brandName?: string; |
| 23 |
pluginUrl?: string; |
| 24 |
currentUserAvatar?: string; |
| 25 |
currentUser?: number; |
| 26 |
siteUrl?: string; |
| 27 |
permissions?: string[]; |
| 28 |
roles?: string[]; |
| 29 |
capabilities?: Record<string, boolean>; |
| 30 |
isPro?: boolean; |
| 31 |
/** Yatra → Modules → Custom Landing Pages enabled (Pro). */ |
| 32 |
customLandingPagesModuleEnabled?: boolean; |
| 33 |
isProActive?: boolean; |
| 34 |
version?: string; |
| 35 |
proVersion?: string | null; |
| 36 |
translations?: Record<string, string>; |
| 37 |
locale?: string; |
| 38 |
emailAutomationEnabled?: boolean; |
| 39 |
tripConsentEnabled?: boolean; |
| 40 |
additionalServicesEnabled?: boolean; |
| 41 |
abandonedBookingRecoveryEnabled?: boolean; |
| 42 |
dynamicPricingEnabled?: boolean; |
| 43 |
dynamicFormFieldEnabled?: boolean; |
| 44 |
advancedDiscountEnabled?: boolean; |
| 45 |
showGoogleCalendarSettingsUI?: boolean; |
| 46 |
showMailchimpSettingsUI?: boolean; |
| 47 |
showFacebookPixelSettingsUI?: boolean; |
| 48 |
showGoogleAnalyticsSettingsUI?: boolean; |
| 49 |
flexiblePaymentsEnabled?: boolean; |
| 50 |
// Growth + Agency tier modules — set by their respective Pro |
| 51 |
// modules via yatra_admin_localized_data filter, OR by the |
| 52 |
// free plugin's AdminAssetsProvider (canonical source via |
| 53 |
// ModuleManager::isModuleEnabled). useModules() also writes |
| 54 |
// these at runtime once /modules resolves. |
| 55 |
aiAssistantEnabled?: boolean; |
| 56 |
whiteLabelEnabled?: boolean; |
| 57 |
whatsappEnabled?: boolean; |
| 58 |
channelManagerEnabled?: boolean; |
| 59 |
webhooksEnabled?: boolean; |
| 60 |
currency?: string; |
| 61 |
date_format?: string; |
| 62 |
time_format?: string; |
| 63 |
calendar_name?: string; |
| 64 |
connected?: boolean; |
| 65 |
redirect_uri?: string; |
| 66 |
last_sync?: string | null; |
| 67 |
googleCalendarRedirectUri?: string; |
| 68 |
mailchimp?: { |
| 69 |
connected?: boolean; |
| 70 |
listId?: string; |
| 71 |
listName?: string; |
| 72 |
syncOnBooking?: boolean; |
| 73 |
syncOnPayment?: boolean; |
| 74 |
addTags?: boolean; |
| 75 |
defaultTags?: string[]; |
| 76 |
doubleOptin?: boolean; |
| 77 |
fieldMapping?: Record<string, string>; |
| 78 |
}; |
| 79 |
facebookPixel?: { |
| 80 |
connected?: boolean; |
| 81 |
pixelId?: string; |
| 82 |
trackViewContent?: boolean; |
| 83 |
trackInitiateCheckout?: boolean; |
| 84 |
trackPurchase?: boolean; |
| 85 |
useConversionsApi?: boolean; |
| 86 |
testEventCode?: string; |
| 87 |
eventConfig?: Record< |
| 88 |
string, |
| 89 |
{ enabled: boolean; custom_params?: string[] } |
| 90 |
>; |
| 91 |
parameterMapping?: Record<string, string>; |
| 92 |
}; |
| 93 |
googleAnalytics?: { |
| 94 |
connected?: boolean; |
| 95 |
measurementId?: string; |
| 96 |
trackViewItem?: boolean; |
| 97 |
trackBeginCheckout?: boolean; |
| 98 |
trackPurchase?: boolean; |
| 99 |
useMeasurementProtocol?: boolean; |
| 100 |
debugMode?: boolean; |
| 101 |
customDimensions?: Array<{ |
| 102 |
name: string; |
| 103 |
yatra_field: string; |
| 104 |
scope?: string; |
| 105 |
}>; |
| 106 |
eventConfig?: Record< |
| 107 |
string, |
| 108 |
{ enabled: boolean; custom_params?: string[] } |
| 109 |
>; |
| 110 |
}; |
| 111 |
googleCalendar?: { |
| 112 |
client_id?: string; |
| 113 |
client_secret?: string; |
| 114 |
calendar_id?: string; |
| 115 |
calendar_name?: string; |
| 116 |
connected?: boolean; |
| 117 |
redirect_uri?: string; |
| 118 |
last_sync?: string | null; |
| 119 |
}; |
| 120 |
// Team & Access (Agency-tier) — injected by Team module's |
| 121 |
// LocalizedData service. Absent when module isn't installed. |
| 122 |
teamEnabled?: boolean; |
| 123 |
/** |
| 124 |
* Forward-looking "keep access on module disable" setting. |
| 125 |
* Only consulted when the Team & Access module is DISABLED: |
| 126 |
* - `false` (default): yatra_* caps are stripped for non-admin |
| 127 |
* users until the module is re-enabled. |
| 128 |
* - `true`: WP-native role machinery keeps resolving caps from |
| 129 |
* the stored role records — team members keep their access |
| 130 |
* even after disabling the module. |
| 131 |
* |
| 132 |
* When the module is enabled, this setting is irrelevant — |
| 133 |
* caps resolve normally through the full layered chain (admin |
| 134 |
* fallback, expiry, revoke, role, grant). |
| 135 |
*/ |
| 136 |
teamKeepAccessOnModuleDisable?: boolean; |
| 137 |
isWpAdmin?: boolean; |
| 138 |
userCaps?: string[]; |
| 139 |
userScopes?: { |
| 140 |
destinations: number[]; |
| 141 |
activities: number[]; |
| 142 |
trips: number[]; |
| 143 |
categories: number[]; |
| 144 |
}; |
| 145 |
}; |
| 146 |
} |
| 147 |
} |
| 148 |
|
| 149 |
/** |
| 150 |
* Internationalization (i18n) utility |
| 151 |
* Handles translations for UI text |
| 152 |
*/ |
| 153 |
|
| 154 |
import { |
| 155 |
__ as wpI18n__, |
| 156 |
_x as wpI18n_x, |
| 157 |
sprintf as wpSprintf, |
| 158 |
} from "@wordpress/i18n"; |
| 159 |
|
| 160 |
function __(key: string): string; |
| 161 |
function __(key: string, textDomain: string): string; |
| 162 |
function __(key: string, textDomain?: string): string { |
| 163 |
// If the frontend bootstrapped a translations map (e.g., account page), |
| 164 |
// use it as the highest priority source. This allows Loco Translate / PHP |
| 165 |
// string catalogs to power React UIs without requiring JS translation JSON files. |
| 166 |
if (typeof window !== "undefined") { |
| 167 |
const w = window as unknown as { |
| 168 |
yatraAccountPage?: { translations?: Record<string, string> }; |
| 169 |
yatraAdmin?: { translations?: Record<string, string> }; |
| 170 |
}; |
| 171 |
const fromAccount = w.yatraAccountPage?.translations?.[key]; |
| 172 |
if (typeof fromAccount === "string" && fromAccount !== "") { |
| 173 |
return fromAccount; |
| 174 |
} |
| 175 |
const fromAdmin = w.yatraAdmin?.translations?.[key]; |
| 176 |
if (typeof fromAdmin === "string" && fromAdmin !== "") { |
| 177 |
return fromAdmin; |
| 178 |
} |
| 179 |
} |
| 180 |
|
| 181 |
// Use direct WordPress i18n function which is working correctly |
| 182 |
if (typeof window !== "undefined" && (window as any).wp?.i18n?.__) { |
| 183 |
return (window as any).wp.i18n.__(key, textDomain || "yatra"); |
| 184 |
} |
| 185 |
// Fallback to @wordpress/i18n |
| 186 |
return wpI18n__(key, textDomain || "yatra"); |
| 187 |
} |
| 188 |
|
| 189 |
function _x(key: string, context: string): string; |
| 190 |
function _x(key: string, context: string, textDomain: string): string; |
| 191 |
function _x(key: string, context: string, textDomain?: string): string { |
| 192 |
// Use direct WordPress i18n function which is working correctly |
| 193 |
if (typeof window !== "undefined" && (window as any).wp?.i18n?._x) { |
| 194 |
return (window as any).wp.i18n._x(key, context, textDomain || "yatra"); |
| 195 |
} |
| 196 |
// Fallback to @wordpress/i18n |
| 197 |
return wpI18n_x(key, context, textDomain || "yatra"); |
| 198 |
} |
| 199 |
|
| 200 |
function sprintf(format: string, ...args: (string | number)[]): string { |
| 201 |
if (typeof window !== "undefined" && (window as any).wp?.i18n?.sprintf) { |
| 202 |
return (window as any).wp.i18n.sprintf(format, ...args); |
| 203 |
} |
| 204 |
return (wpSprintf as (fmt: string, ...a: (string | number)[]) => string)( |
| 205 |
format, |
| 206 |
...args, |
| 207 |
); |
| 208 |
} |
| 209 |
|
| 210 |
/** |
| 211 |
* Operator brand name — "Yatra" by default, or whatever the operator |
| 212 |
* has set in the White Label module (Agency tier). |
| 213 |
* |
| 214 |
* Use this in user-visible strings instead of hardcoding "Yatra": |
| 215 |
* |
| 216 |
* const brand = brandName(); |
| 217 |
* sprintf(__("%s role", "yatra"), brand) // "Acme role" if rebranded |
| 218 |
* |
| 219 |
* Always pass the brand as an interpolated argument so the translatable |
| 220 |
* string stays generic — that keeps `make-pot` extraction working AND |
| 221 |
* means a translator only has to translate "%s role" once, regardless |
| 222 |
* of brand. |
| 223 |
*/ |
| 224 |
function brandName(): string { |
| 225 |
if (typeof window === "undefined") return "Yatra"; |
| 226 |
return (window.yatraAdmin?.brandName as string | undefined) || "Yatra"; |
| 227 |
} |
| 228 |
|
| 229 |
export { __, _x, sprintf, brandName }; |
| 230 |
|
| 231 |
/** |
| 232 |
* Get translated string with number |
| 233 |
* @param single - Single form |
| 234 |
* @param plural - Plural form |
| 235 |
* @param number - Number to determine form |
| 236 |
* @param textDomain - Optional text domain; accepted for API parity with |
| 237 |
* WordPress's own `_n()` so call sites that already pass |
| 238 |
* `"yatra"` as a fourth arg type-check. Currently |
| 239 |
* unused — `__()` does its own domain resolution via |
| 240 |
* the translations map injected on `window.yatraAdmin`. |
| 241 |
* @returns Translated string |
| 242 |
*/ |
| 243 |
export const _n = ( |
| 244 |
single: string, |
| 245 |
plural: string, |
| 246 |
number: number, |
| 247 |
_textDomain?: string, |
| 248 |
): string => { |
| 249 |
return number === 1 ? __(single) : __(plural); |
| 250 |
}; |
| 251 |
|