PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
← All changes | resources/js/lib/i18n.ts +115 -3 3.0.2.6 → 3.0.16 View file →
@@ -6,10 +6,21 @@
6 6 declare global {
7 7 interface Window {
8 8 yatraAdmin?: {
9 9 apiUrl?: string;
10 + restUrl?: string;
10 11 nonce?: string;
11 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;
12 23 pluginUrl?: string;
13 24 currentUserAvatar?: string;
14 25 currentUser?: number;
15 26 siteUrl?: string;
@@ -16,8 +27,10 @@
16 27 permissions?: string[];
17 28 roles?: string[];
18 29 capabilities?: Record<string, boolean>;
19 30 isPro?: boolean;
31 + /** Yatra → Modules → Custom Landing Pages enabled (Pro). */
32 + customLandingPagesModuleEnabled?: boolean;
20 33 isProActive?: boolean;
21 34 version?: string;
22 35 proVersion?: string | null;
23 36 translations?: Record<string, string>;
@@ -22,13 +35,15 @@
22 35 proVersion?: string | null;
23 36 translations?: Record<string, string>;
24 37 locale?: string;
25 38 emailAutomationEnabled?: boolean;
39 + emailTemplateOverridesEnabled?: boolean;
26 40 tripConsentEnabled?: boolean;
27 41 additionalServicesEnabled?: boolean;
28 42 abandonedBookingRecoveryEnabled?: boolean;
29 43 dynamicPricingEnabled?: boolean;
30 44 dynamicFormFieldEnabled?: boolean;
45 + bookingFormConditionsEnabled?: boolean;
31 46 advancedDiscountEnabled?: boolean;
32 47 showGoogleCalendarSettingsUI?: boolean;
33 48 showMailchimpSettingsUI?: boolean;
34 49 showFacebookPixelSettingsUI?: boolean;
@@ -33,8 +48,19 @@
33 48 showMailchimpSettingsUI?: boolean;
34 49 showFacebookPixelSettingsUI?: boolean;
35 50 showGoogleAnalyticsSettingsUI?: boolean;
36 51 flexiblePaymentsEnabled?: boolean;
52 + // Growth + Agency tier modules — set by their respective Pro
53 + // modules via yatra_admin_localized_data filter, OR by the
54 + // free plugin's AdminAssetsProvider (canonical source via
55 + // ModuleManager::isModuleEnabled). useModules() also writes
56 + // these at runtime once /modules resolves.
57 + aiAssistantEnabled?: boolean;
58 + whiteLabelEnabled?: boolean;
59 + whatsappEnabled?: boolean;
60 + channelManagerEnabled?: boolean;
61 + webhooksEnabled?: boolean;
62 + scheduledPaymentsEnabled?: boolean;
37 63 currency?: string;
38 64 date_format?: string;
39 65 time_format?: string;
40 66 calendar_name?: string;
@@ -93,8 +119,33 @@
93 119 connected?: boolean;
94 120 redirect_uri?: string;
95 121 last_sync?: string | null;
96 122 };
123 + // Team & Access (Agency-tier) — injected by Team module's
124 + // LocalizedData service. Absent when module isn't installed.
125 + teamEnabled?: boolean;
126 + /**
127 + * Forward-looking "keep access on module disable" setting.
128 + * Only consulted when the Team & Access module is DISABLED:
129 + * - `false` (default): yatra_* caps are stripped for non-admin
130 + * users until the module is re-enabled.
131 + * - `true`: WP-native role machinery keeps resolving caps from
132 + * the stored role records — team members keep their access
133 + * even after disabling the module.
134 + *
135 + * When the module is enabled, this setting is irrelevant —
136 + * caps resolve normally through the full layered chain (admin
137 + * fallback, expiry, revoke, role, grant).
138 + */
139 + teamKeepAccessOnModuleDisable?: boolean;
140 + isWpAdmin?: boolean;
141 + userCaps?: string[];
142 + userScopes?: {
143 + destinations: number[];
144 + activities: number[];
145 + trips: number[];
146 + categories: number[];
147 + };
97 148 };
98 149 }
99 150 }
100 151
@@ -102,13 +153,35 @@
102 153 * Internationalization (i18n) utility
103 154 * Handles translations for UI text
104 155 */
105 156
106 -import { __ as wpI18n__, _x as wpI18n_x } from "@wordpress/i18n";
157 +import {
158 + __ as wpI18n__,
159 + _x as wpI18n_x,
160 + sprintf as wpSprintf,
161 +} from "@wordpress/i18n";
107 162
108 163 function __(key: string): string;
109 164 function __(key: string, textDomain: string): string;
110 165 function __(key: string, textDomain?: string): string {
166 + // If the frontend bootstrapped a translations map (e.g., account page),
167 + // use it as the highest priority source. This allows Loco Translate / PHP
168 + // string catalogs to power React UIs without requiring JS translation JSON files.
169 + if (typeof window !== "undefined") {
170 + const w = window as unknown as {
171 + yatraAccountPage?: { translations?: Record<string, string> };
172 + yatraAdmin?: { translations?: Record<string, string> };
173 + };
174 + const fromAccount = w.yatraAccountPage?.translations?.[key];
175 + if (typeof fromAccount === "string" && fromAccount !== "") {
176 + return fromAccount;
177 + }
178 + const fromAdmin = w.yatraAdmin?.translations?.[key];
179 + if (typeof fromAdmin === "string" && fromAdmin !== "") {
180 + return fromAdmin;
181 + }
182 + }
183 +
111 184 // Use direct WordPress i18n function which is working correctly
112 185 if (typeof window !== "undefined" && (window as any).wp?.i18n?.__) {
113 186 return (window as any).wp.i18n.__(key, textDomain || "yatra");
114 187 }
@@ -126,16 +199,55 @@
126 199 // Fallback to @wordpress/i18n
127 200 return wpI18n_x(key, context, textDomain || "yatra");
128 201 }
129 202
130 -export { __, _x };
203 +function sprintf(format: string, ...args: (string | number)[]): string {
204 + if (typeof window !== "undefined" && (window as any).wp?.i18n?.sprintf) {
205 + return (window as any).wp.i18n.sprintf(format, ...args);
206 + }
207 + return (wpSprintf as (fmt: string, ...a: (string | number)[]) => string)(
208 + format,
209 + ...args,
210 + );
211 +}
131 212
132 213 /**
214 + * Operator brand name — "Yatra" by default, or whatever the operator
215 + * has set in the White Label module (Agency tier).
216 + *
217 + * Use this in user-visible strings instead of hardcoding "Yatra":
218 + *
219 + * const brand = brandName();
220 + * sprintf(__("%s role", "yatra"), brand) // "Acme role" if rebranded
221 + *
222 + * Always pass the brand as an interpolated argument so the translatable
223 + * string stays generic — that keeps `make-pot` extraction working AND
224 + * means a translator only has to translate "%s role" once, regardless
225 + * of brand.
226 + */
227 +function brandName(): string {
228 + if (typeof window === "undefined") return "Yatra";
229 + return (window.yatraAdmin?.brandName as string | undefined) || "Yatra";
230 +}
231 +
232 +export { __, _x, sprintf, brandName };
233 +
234 +/**
133 235 * Get translated string with number
134 236 * @param single - Single form
135 237 * @param plural - Plural form
136 238 * @param number - Number to determine form
239 + * @param textDomain - Optional text domain; accepted for API parity with
240 + * WordPress's own `_n()` so call sites that already pass
241 + * `"yatra"` as a fourth arg type-check. Currently
242 + * unused — `__()` does its own domain resolution via
243 + * the translations map injected on `window.yatraAdmin`.
137 244 * @returns Translated string
138 245 */
139 -export const _n = (single: string, plural: string, number: number): string => {
246 +export const _n = (
247 + single: string,
248 + plural: string,
249 + number: number,
250 + _textDomain?: string,
251 +): string => {
140 252 return number === 1 ? __(single) : __(plural);
141 253 };