@zohodesk/i18n 1.0.0-beta.33 → 1.0.0-beta.35-murphy
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/docs/murphy/01-MURPHY_OVERVIEW.md +148 -0
- package/docs/murphy/02-MURPHY_ARCHITECTURE.md +283 -0
- package/docs/murphy/03-MURPHY_BACKEND_CONFIG.md +337 -0
- package/docs/murphy/04-MURPHY_FRONTEND_INIT.md +437 -0
- package/docs/murphy/05-MURPHY_DESK_CLIENT_USAGE.md +467 -0
- package/docs/murphy/06-MURPHY_I18N_INTEGRATION.md +402 -0
- package/docs/murphy/07-MURPHY_WHY_I18N_APPROACH.md +391 -0
- package/es/components/DateTimeDiffFormat.js +5 -19
- package/es/components/FormatText.js +2 -2
- package/es/components/HOCI18N.js +32 -43
- package/es/components/I18N.js +2 -13
- package/es/components/I18NProvider.js +0 -9
- package/es/components/PluralFormat.js +3 -5
- package/es/components/UserTimeDiffFormat.js +5 -9
- package/es/components/__tests__/DateTimeDiffFormat.spec.js +157 -221
- package/es/components/__tests__/FormatText.spec.js +2 -2
- package/es/components/__tests__/HOCI18N.spec.js +2 -4
- package/es/components/__tests__/I18N.spec.js +6 -4
- package/es/components/__tests__/I18NProvider.spec.js +4 -4
- package/es/components/__tests__/PluralFormat.spec.js +2 -2
- package/es/components/__tests__/UserTimeDiffFormat.spec.js +249 -348
- package/es/index.js +2 -0
- package/es/utils/__tests__/jsxTranslations.spec.js +3 -7
- package/es/utils/errorReporter.js +31 -0
- package/es/utils/index.js +42 -92
- package/es/utils/jsxTranslations.js +53 -61
- package/lib/I18NContext.js +2 -7
- package/lib/components/DateTimeDiffFormat.js +46 -87
- package/lib/components/FormatText.js +18 -41
- package/lib/components/HOCI18N.js +24 -59
- package/lib/components/I18N.js +27 -64
- package/lib/components/I18NProvider.js +27 -63
- package/lib/components/PluralFormat.js +24 -50
- package/lib/components/UserTimeDiffFormat.js +43 -72
- package/lib/components/__tests__/DateTimeDiffFormat.spec.js +95 -165
- package/lib/components/__tests__/FormatText.spec.js +3 -10
- package/lib/components/__tests__/HOCI18N.spec.js +3 -14
- package/lib/components/__tests__/I18N.spec.js +4 -12
- package/lib/components/__tests__/I18NProvider.spec.js +8 -23
- package/lib/components/__tests__/PluralFormat.spec.js +3 -11
- package/lib/components/__tests__/UserTimeDiffFormat.spec.js +157 -225
- package/lib/index.js +32 -22
- package/lib/utils/__tests__/jsxTranslations.spec.js +1 -12
- package/lib/utils/errorReporter.js +39 -0
- package/lib/utils/index.js +49 -125
- package/lib/utils/jsxTranslations.js +79 -105
- package/package.json +1 -1
- package/src/index.js +6 -0
- package/src/utils/errorReporter.js +36 -0
- package/src/utils/index.js +8 -1
- package/src/utils/jsxTranslations.js +31 -12
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# Why Murphy in i18n Library (Not Desk Client)
|
|
2
|
+
|
|
3
|
+
## The Question
|
|
4
|
+
|
|
5
|
+
When implementing Murphy error tracking for i18n failures, we had two options:
|
|
6
|
+
|
|
7
|
+
1. **Option A:** Add tracking in the desk client application
|
|
8
|
+
2. **Option B:** Add tracking in the i18n library itself
|
|
9
|
+
|
|
10
|
+
This document explains why Option B is the correct choice.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Option A: Murphy in Desk Client App
|
|
15
|
+
|
|
16
|
+
### How It Would Work
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
+-------------------------------------------------------------------+
|
|
20
|
+
| OPTION A: DESK CLIENT APPROACH (NOT RECOMMENDED) |
|
|
21
|
+
+-------------------------------------------------------------------+
|
|
22
|
+
| |
|
|
23
|
+
| // In desk client app component |
|
|
24
|
+
| const text = getI18NValue(i18n, 'my.key'); |
|
|
25
|
+
| |
|
|
26
|
+
| // Try to detect if it failed... somehow? |
|
|
27
|
+
| if (text === 'my.key' || text.startsWith('Missing')) { |
|
|
28
|
+
| deskCustomError(...); // Report to Murphy |
|
|
29
|
+
| } |
|
|
30
|
+
| |
|
|
31
|
+
+-------------------------------------------------------------------+
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Problems with This Approach
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
+-------------------------------------------------------------------+
|
|
38
|
+
| PROBLEM 1: WHERE TO HOOK? |
|
|
39
|
+
+-------------------------------------------------------------------+
|
|
40
|
+
| |
|
|
41
|
+
| getI18NValue('missing.key') |
|
|
42
|
+
| | |
|
|
43
|
+
| v |
|
|
44
|
+
| Returns: "missing.key" or "Missing: missing.key" |
|
|
45
|
+
| | |
|
|
46
|
+
| v |
|
|
47
|
+
| App receives a string - doesn't know it FAILED! |
|
|
48
|
+
| |
|
|
49
|
+
| Detection requires GUESSING: |
|
|
50
|
+
| +---------------------------------------------------------------+ |
|
|
51
|
+
| | // HACKY: Check if result equals the key | |
|
|
52
|
+
| | if (result === key) { /* maybe failed? */ } | |
|
|
53
|
+
| | | |
|
|
54
|
+
| | // HACKY: Check for "Missing" prefix | |
|
|
55
|
+
| | if (result.startsWith('Missing')) { /* maybe failed? */ } | |
|
|
56
|
+
| | | |
|
|
57
|
+
| | // FALSE POSITIVES: What if translation IS "Missing: ..."? | |
|
|
58
|
+
| | // FALSE NEGATIVES: What if fallback format changes? | |
|
|
59
|
+
| +---------------------------------------------------------------+ |
|
|
60
|
+
| |
|
|
61
|
+
+-------------------------------------------------------------------+
|
|
62
|
+
|
|
63
|
+
+-------------------------------------------------------------------+
|
|
64
|
+
| PROBLEM 2: EVERY APP NEEDS SAME CODE |
|
|
65
|
+
+-------------------------------------------------------------------+
|
|
66
|
+
| |
|
|
67
|
+
| Multiple apps use @zohodesk/i18n: |
|
|
68
|
+
| |
|
|
69
|
+
| +-------------------+ |
|
|
70
|
+
| | supportapp | --> Must add Murphy wrapper (duplicate) |
|
|
71
|
+
| +-------------------+ |
|
|
72
|
+
| + |
|
|
73
|
+
| +-------------------+ |
|
|
74
|
+
| | portal app | --> Must add Murphy wrapper (duplicate) |
|
|
75
|
+
| +-------------------+ |
|
|
76
|
+
| + |
|
|
77
|
+
| +-------------------+ |
|
|
78
|
+
| | ASAP widget | --> Must add Murphy wrapper (duplicate) |
|
|
79
|
+
| +-------------------+ |
|
|
80
|
+
| + |
|
|
81
|
+
| +-------------------+ |
|
|
82
|
+
| | future apps | --> Must remember to add! (easy to miss)|
|
|
83
|
+
| +-------------------+ |
|
|
84
|
+
| |
|
|
85
|
+
+-------------------------------------------------------------------+
|
|
86
|
+
|
|
87
|
+
+-------------------------------------------------------------------+
|
|
88
|
+
| PROBLEM 3: MAINTENANCE NIGHTMARE |
|
|
89
|
+
+-------------------------------------------------------------------+
|
|
90
|
+
| |
|
|
91
|
+
| Scenario: i18n library changes fallback text format |
|
|
92
|
+
| |
|
|
93
|
+
| Before: Returns "missing.key" |
|
|
94
|
+
| After: Returns "MISSING_TRANSLATION: missing.key" |
|
|
95
|
+
| |
|
|
96
|
+
| Required action: |
|
|
97
|
+
| +-- Update supportapp detection logic |
|
|
98
|
+
| +-- Update portal app detection logic |
|
|
99
|
+
| +-- Update ASAP widget detection logic |
|
|
100
|
+
| +-- Update all future apps... |
|
|
101
|
+
| |
|
|
102
|
+
| Risk: Inconsistent implementations, bugs, missed updates |
|
|
103
|
+
| |
|
|
104
|
+
+-------------------------------------------------------------------+
|
|
105
|
+
|
|
106
|
+
+-------------------------------------------------------------------+
|
|
107
|
+
| PROBLEM 4: APPS WITHOUT MURPHY |
|
|
108
|
+
+-------------------------------------------------------------------+
|
|
109
|
+
| |
|
|
110
|
+
| Some apps might not have Murphy configured: |
|
|
111
|
+
| |
|
|
112
|
+
| - New internal tools |
|
|
113
|
+
| - Test environments |
|
|
114
|
+
| - Third-party integrations |
|
|
115
|
+
| |
|
|
116
|
+
| Each app must: |
|
|
117
|
+
| +-- Check if murphy exists |
|
|
118
|
+
| +-- Handle the case where it doesn't |
|
|
119
|
+
| +-- Duplicate this safety check everywhere |
|
|
120
|
+
| |
|
|
121
|
+
+-------------------------------------------------------------------+
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Option B: Murphy in i18n Library
|
|
127
|
+
|
|
128
|
+
### How It Works
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
+-------------------------------------------------------------------+
|
|
132
|
+
| OPTION B: I18N LIBRARY APPROACH (RECOMMENDED) |
|
|
133
|
+
+-------------------------------------------------------------------+
|
|
134
|
+
| |
|
|
135
|
+
| // Inside getI18NValue() in i18n library |
|
|
136
|
+
| export const getI18NValue = (i18n) => (key, values) => { |
|
|
137
|
+
| let i18nStr = i18n[key]; |
|
|
138
|
+
| |
|
|
139
|
+
| if (i18nStr === undefined) { |
|
|
140
|
+
| // WE KNOW IT FAILED - Right here, right now! |
|
|
141
|
+
| reportI18NError(I18N_ERROR_TYPES.MISSING_KEY, key); |
|
|
142
|
+
| return getFallbackText(key); |
|
|
143
|
+
| } |
|
|
144
|
+
| |
|
|
145
|
+
| return processTranslation(i18nStr, values); |
|
|
146
|
+
| }; |
|
|
147
|
+
| |
|
|
148
|
+
+-------------------------------------------------------------------+
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Benefits of This Approach
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
+-------------------------------------------------------------------+
|
|
155
|
+
| BENEFIT 1: KNOWS EXACTLY WHEN FAILURE OCCURS |
|
|
156
|
+
+-------------------------------------------------------------------+
|
|
157
|
+
| |
|
|
158
|
+
| // Inside getI18NValue() |
|
|
159
|
+
| if (i18nStr === undefined) { |
|
|
160
|
+
| // We are INSIDE the function that processes the key |
|
|
161
|
+
| // We KNOW with 100% certainty it failed |
|
|
162
|
+
| // No guessing, no heuristics, no false positives |
|
|
163
|
+
| reportI18NError(MISSING_KEY, key); |
|
|
164
|
+
| } |
|
|
165
|
+
| |
|
|
166
|
+
+-------------------------------------------------------------------+
|
|
167
|
+
|
|
168
|
+
+-------------------------------------------------------------------+
|
|
169
|
+
| BENEFIT 2: FIX ONCE, WORKS EVERYWHERE |
|
|
170
|
+
+-------------------------------------------------------------------+
|
|
171
|
+
| |
|
|
172
|
+
| +-------------------+ |
|
|
173
|
+
| | i18n library | <-- Fix here once |
|
|
174
|
+
| +--------+----------+ |
|
|
175
|
+
| | |
|
|
176
|
+
| +-----------------+-----------------+ |
|
|
177
|
+
| | | | |
|
|
178
|
+
| v v v |
|
|
179
|
+
| +-------------+ +-------------+ +-------------+ |
|
|
180
|
+
| | supportapp | | portal app | | ASAP widget | |
|
|
181
|
+
| | OK | | OK | | OK | |
|
|
182
|
+
| +-------------+ +-------------+ +-------------+ |
|
|
183
|
+
| |
|
|
184
|
+
| All apps automatically get Murphy tracking! |
|
|
185
|
+
| No code changes in consuming apps needed! |
|
|
186
|
+
| |
|
|
187
|
+
+-------------------------------------------------------------------+
|
|
188
|
+
|
|
189
|
+
+-------------------------------------------------------------------+
|
|
190
|
+
| BENEFIT 3: SAFE FOR APPS WITHOUT MURPHY |
|
|
191
|
+
+-------------------------------------------------------------------+
|
|
192
|
+
| |
|
|
193
|
+
| // errorReporter.js |
|
|
194
|
+
| function isMurphyAvailable() { |
|
|
195
|
+
| return typeof murphy !== 'undefined' && |
|
|
196
|
+
| typeof murphy.error === 'function'; |
|
|
197
|
+
| } |
|
|
198
|
+
| |
|
|
199
|
+
| export function reportI18NError(type, key) { |
|
|
200
|
+
| // ... deduplication logic ... |
|
|
201
|
+
| |
|
|
202
|
+
| if (isMurphyAvailable()) { |
|
|
203
|
+
| murphy.error(...); // Report if Murphy exists |
|
|
204
|
+
| } |
|
|
205
|
+
| // Otherwise: silently skip - no crash, no error! |
|
|
206
|
+
| } |
|
|
207
|
+
| |
|
|
208
|
+
| Result: |
|
|
209
|
+
| +-- App WITH Murphy -> Errors reported to dashboard |
|
|
210
|
+
| +-- App WITHOUT Murphy -> Silently skipped, app works fine |
|
|
211
|
+
| |
|
|
212
|
+
+-------------------------------------------------------------------+
|
|
213
|
+
|
|
214
|
+
+-------------------------------------------------------------------+
|
|
215
|
+
| BENEFIT 4: ZERO OVERHEAD ON HAPPY PATH |
|
|
216
|
+
+-------------------------------------------------------------------+
|
|
217
|
+
| |
|
|
218
|
+
| // Normal case: Translation exists |
|
|
219
|
+
| let i18nStr = i18n[key]; // "Save Ticket" |
|
|
220
|
+
| |
|
|
221
|
+
| if (i18nStr !== undefined) { |
|
|
222
|
+
| // Happy path - no Murphy calls at all! |
|
|
223
|
+
| // Zero performance impact |
|
|
224
|
+
| return processTranslation(i18nStr, values); |
|
|
225
|
+
| } |
|
|
226
|
+
| |
|
|
227
|
+
| // Murphy only called when there's actually an error |
|
|
228
|
+
| |
|
|
229
|
+
+-------------------------------------------------------------------+
|
|
230
|
+
|
|
231
|
+
+-------------------------------------------------------------------+
|
|
232
|
+
| BENEFIT 5: DATACENTER AGNOSTIC |
|
|
233
|
+
+-------------------------------------------------------------------+
|
|
234
|
+
| |
|
|
235
|
+
| i18n library doesn't know or care which datacenter it's in: |
|
|
236
|
+
| |
|
|
237
|
+
| US Server: Murphy already configured with US credentials |
|
|
238
|
+
| JP Server: Murphy already configured with JP credentials |
|
|
239
|
+
| IN Server: Murphy already configured with IN credentials |
|
|
240
|
+
| |
|
|
241
|
+
| i18n library just calls: murphy.error(...) |
|
|
242
|
+
| Murphy SDK handles routing to correct datacenter! |
|
|
243
|
+
| |
|
|
244
|
+
| Same code works everywhere without modification. |
|
|
245
|
+
| |
|
|
246
|
+
+-------------------------------------------------------------------+
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Side-by-Side Comparison
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
+-------------------------------------------------------------------+
|
|
255
|
+
| COMPARISON TABLE |
|
|
256
|
+
+-------------------------------------------------------------------+
|
|
257
|
+
| |
|
|
258
|
+
| Aspect | Desk Client | i18n Library |
|
|
259
|
+
|---------------------|-----------------|---------------------------|
|
|
260
|
+
| Detection accuracy | Guessing | 100% accurate |
|
|
261
|
+
| Implementation | Every app | Once in library |
|
|
262
|
+
| Maintenance | Update all apps | Update one place |
|
|
263
|
+
| New apps | Must remember | Automatic |
|
|
264
|
+
| Performance | Extra checks | Zero overhead on success |
|
|
265
|
+
| Murphy safety | Each app checks | Built-in check |
|
|
266
|
+
| DC handling | Each app config | Automatic |
|
|
267
|
+
| Code duplication | High | None |
|
|
268
|
+
| |
|
|
269
|
+
+-------------------------------------------------------------------+
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## The Doctor Analogy
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
+-------------------------------------------------------------------+
|
|
278
|
+
| DOCTOR ANALOGY |
|
|
279
|
+
+-------------------------------------------------------------------+
|
|
280
|
+
| |
|
|
281
|
+
| Option A (Desk Client): |
|
|
282
|
+
| +---------------------------------------------------------------+ |
|
|
283
|
+
| | | |
|
|
284
|
+
| | Patient: "I feel fine" | |
|
|
285
|
+
| | | |
|
|
286
|
+
| | App: "The i18n function returned something..." | |
|
|
287
|
+
| | App: "I THINK it might have failed?" | |
|
|
288
|
+
| | App: "Let me guess based on the output..." | |
|
|
289
|
+
| | | |
|
|
290
|
+
| +---------------------------------------------------------------+ |
|
|
291
|
+
| |
|
|
292
|
+
| Option B (i18n Library): |
|
|
293
|
+
| +---------------------------------------------------------------+ |
|
|
294
|
+
| | | |
|
|
295
|
+
| | Doctor (i18n lib): "I examined the patient" | |
|
|
296
|
+
| | Doctor (i18n lib): "The key doesn't exist - I KNOW this" | |
|
|
297
|
+
| | Doctor (i18n lib): *Reports directly to hospital (Murphy)* | |
|
|
298
|
+
| | | |
|
|
299
|
+
| +---------------------------------------------------------------+ |
|
|
300
|
+
| |
|
|
301
|
+
| The doctor KNOWS the diagnosis. |
|
|
302
|
+
| Don't ask the patient to diagnose themselves! |
|
|
303
|
+
| |
|
|
304
|
+
+-------------------------------------------------------------------+
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Real-World Flow
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
+-------------------------------------------------------------------+
|
|
313
|
+
| REAL-WORLD FLOW: I18N LIBRARY APPROACH |
|
|
314
|
+
+-------------------------------------------------------------------+
|
|
315
|
+
| |
|
|
316
|
+
| 1. User visits page in US datacenter |
|
|
317
|
+
| |
|
|
318
|
+
| 2. Murphy already configured: |
|
|
319
|
+
| desk_urls.murphyAppDomain = "murphy.zoho.com" |
|
|
320
|
+
| murphy.install() already called |
|
|
321
|
+
| |
|
|
322
|
+
| 3. React component renders: |
|
|
323
|
+
| <I18N i18nKey="tickets.status.label" /> |
|
|
324
|
+
| |
|
|
325
|
+
| 4. i18n library processes: |
|
|
326
|
+
| getI18NValue(i18n)('tickets.status.label') |
|
|
327
|
+
| -> i18n['tickets.status.label'] = undefined! |
|
|
328
|
+
| -> reportI18NError(MISSING_KEY, 'tickets.status.label') |
|
|
329
|
+
| -> Returns fallback: "tickets.status.label" |
|
|
330
|
+
| |
|
|
331
|
+
| 5. Murphy SDK sends to murphy.zoho.com: |
|
|
332
|
+
| { |
|
|
333
|
+
| error: "i18n I18N_MISSING_KEY: tickets.status.label", |
|
|
334
|
+
| customTags: { |
|
|
335
|
+
| errorType: "I18N_MISSING_KEY", |
|
|
336
|
+
| i18nKey: "tickets.status.label", |
|
|
337
|
+
| category: "i18n" |
|
|
338
|
+
| } |
|
|
339
|
+
| } |
|
|
340
|
+
| |
|
|
341
|
+
| 6. Developer sees in Murphy dashboard: |
|
|
342
|
+
| "Missing i18n key: tickets.status.label" |
|
|
343
|
+
| -> Adds translation |
|
|
344
|
+
| -> User no longer sees raw key |
|
|
345
|
+
| |
|
|
346
|
+
+-------------------------------------------------------------------+
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Conclusion
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
+-------------------------------------------------------------------+
|
|
355
|
+
| FINAL RECOMMENDATION |
|
|
356
|
+
+-------------------------------------------------------------------+
|
|
357
|
+
| |
|
|
358
|
+
| Murphy integration belongs in the i18n LIBRARY because: |
|
|
359
|
+
| |
|
|
360
|
+
| 1. ACCURACY: |
|
|
361
|
+
| The library knows EXACTLY when a translation fails |
|
|
362
|
+
| No guessing or heuristics required |
|
|
363
|
+
| |
|
|
364
|
+
| 2. DRY (Don't Repeat Yourself): |
|
|
365
|
+
| One implementation serves all consuming apps |
|
|
366
|
+
| No code duplication |
|
|
367
|
+
| |
|
|
368
|
+
| 3. SAFETY: |
|
|
369
|
+
| Built-in check for Murphy availability |
|
|
370
|
+
| Works with or without Murphy |
|
|
371
|
+
| |
|
|
372
|
+
| 4. PERFORMANCE: |
|
|
373
|
+
| Zero overhead when translations exist |
|
|
374
|
+
| Only reports when there's an actual failure |
|
|
375
|
+
| |
|
|
376
|
+
| 5. MAINTENANCE: |
|
|
377
|
+
| Fix once, benefits all apps |
|
|
378
|
+
| New apps automatically get tracking |
|
|
379
|
+
| |
|
|
380
|
+
| This is the correct architectural decision. |
|
|
381
|
+
| |
|
|
382
|
+
+-------------------------------------------------------------------+
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Related Documents
|
|
388
|
+
|
|
389
|
+
- [05-MURPHY_DESK_CLIENT_USAGE.md](./05-MURPHY_DESK_CLIENT_USAGE.md) - How desk client uses Murphy
|
|
390
|
+
- [06-MURPHY_I18N_INTEGRATION.md](./06-MURPHY_I18N_INTEGRATION.md) - i18n integration details
|
|
391
|
+
- [02-MURPHY_ARCHITECTURE.md](./02-MURPHY_ARCHITECTURE.md) - Overall architecture
|
|
@@ -8,10 +8,8 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
8
8
|
super(props);
|
|
9
9
|
this.getSuffix = this.getSuffix.bind(this);
|
|
10
10
|
}
|
|
11
|
-
|
|
12
11
|
getSuffix(min) {
|
|
13
12
|
let suffix;
|
|
14
|
-
|
|
15
13
|
if (this.props.ago && min < 0) {
|
|
16
14
|
suffix = this.props.ago || '';
|
|
17
15
|
} else if (this.props.later || min > 0) {
|
|
@@ -19,10 +17,8 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
19
17
|
} else {
|
|
20
18
|
suffix = '';
|
|
21
19
|
}
|
|
22
|
-
|
|
23
20
|
return suffix;
|
|
24
21
|
}
|
|
25
|
-
|
|
26
22
|
render() {
|
|
27
23
|
const {
|
|
28
24
|
type,
|
|
@@ -95,9 +91,10 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
95
91
|
timeFormat: timeFormat,
|
|
96
92
|
datePattern: datePattern,
|
|
97
93
|
dateTimePattern: `${datePattern} ${timeFormat}`
|
|
98
|
-
};
|
|
99
|
-
//In else part we'll set the date format as it is
|
|
94
|
+
};
|
|
100
95
|
|
|
96
|
+
//In if condition we'll remove year and set date format if the current year is not required
|
|
97
|
+
//In else part we'll set the date format as it is
|
|
101
98
|
if (isEnabledCurrentYear === true && diffObj1.years === 0 && diffObj1.tYear === diffObj1.crntYear) {
|
|
102
99
|
let dateFormat = getDatePatternWithoutYear(datePattern);
|
|
103
100
|
diffObj1.dateFormat = dateFormat;
|
|
@@ -106,12 +103,10 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
106
103
|
diffObj1.dateFormat = datePattern;
|
|
107
104
|
diffObj1.dateTimeFormat = `${datePattern} ${timeFormat}`;
|
|
108
105
|
}
|
|
109
|
-
|
|
110
106
|
let key = '';
|
|
111
107
|
let values = [];
|
|
112
108
|
let text = null;
|
|
113
109
|
let isSuffixEnable = false;
|
|
114
|
-
|
|
115
110
|
if (format) {
|
|
116
111
|
let years, months, days, hours, minutes, seconds;
|
|
117
112
|
years = diffObj1.years > 1 ? '2' : diffObj1.years;
|
|
@@ -128,15 +123,12 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
128
123
|
} else {
|
|
129
124
|
res = res + next;
|
|
130
125
|
}
|
|
131
|
-
|
|
132
126
|
return res;
|
|
133
127
|
}, '');
|
|
134
128
|
let value = format(diffObj1, pattern);
|
|
135
|
-
|
|
136
129
|
if (value && typeof value === 'object') {
|
|
137
130
|
key = value.key;
|
|
138
131
|
values = getValues(value.params, diffObj);
|
|
139
|
-
|
|
140
132
|
if (pattern.indexOf('00000') === 0) {
|
|
141
133
|
//suffix ignore for second hook
|
|
142
134
|
isSuffixEnable = false;
|
|
@@ -149,32 +141,28 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
149
141
|
} else {
|
|
150
142
|
let dateObj = new Date(toDateObj);
|
|
151
143
|
let curDateObj = new Date(fromDateObj);
|
|
152
|
-
let diffDayType = diffObj1.yDays;
|
|
144
|
+
let diffDayType = diffObj1.yDays;
|
|
153
145
|
|
|
146
|
+
//In this condition, to calculate different days we have copied it from live --> diffDayType
|
|
154
147
|
if (isOverdue && dateObj.getDate() < curDateObj.getDate() && diffObj1.yDays == 0) {
|
|
155
148
|
diffDayType = -1;
|
|
156
149
|
}
|
|
157
|
-
|
|
158
150
|
if (!isOverdue) {
|
|
159
151
|
let diffHr = dateObj.getHours() - curDateObj.getHours();
|
|
160
|
-
|
|
161
152
|
if (diffHr < 0) {
|
|
162
153
|
diffDayType += 1;
|
|
163
154
|
} else if (diffHr == 0) {
|
|
164
155
|
let diffMins = dateObj.getMinutes() - curDateObj.getMinutes();
|
|
165
|
-
|
|
166
156
|
if (diffMins < 0) {
|
|
167
157
|
diffDayType += 1;
|
|
168
158
|
} else if (diffMins == 0) {
|
|
169
159
|
let diffSec = dateObj.getSeconds() - curDateObj.getSeconds();
|
|
170
|
-
|
|
171
160
|
if (diffSec < 0) {
|
|
172
161
|
diffDayType += 1;
|
|
173
162
|
}
|
|
174
163
|
}
|
|
175
164
|
}
|
|
176
165
|
}
|
|
177
|
-
|
|
178
166
|
if (diff.y === 0 && (diffDayType === 0 || diffDayType === 1)) {
|
|
179
167
|
if (dateObj.getDate() === curDateObj.getDate()) {
|
|
180
168
|
var value = today && today(diffObj1) || others(diffObj1);
|
|
@@ -191,7 +179,6 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
191
179
|
text = formatDate(toDateObj, value);
|
|
192
180
|
}
|
|
193
181
|
}
|
|
194
|
-
|
|
195
182
|
return text ? /*#__PURE__*/React.createElement("span", {
|
|
196
183
|
className: className,
|
|
197
184
|
"data-title": title,
|
|
@@ -204,7 +191,6 @@ export default class DateTimeDiffFormat extends React.Component {
|
|
|
204
191
|
"data-title": title
|
|
205
192
|
});
|
|
206
193
|
}
|
|
207
|
-
|
|
208
194
|
}
|
|
209
195
|
DateTimeDiffFormat.propTypes = {
|
|
210
196
|
ago: PropTypes.string,
|
|
@@ -3,10 +3,10 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import I18N from "./I18N";
|
|
4
4
|
export default class FormatText extends React.Component {
|
|
5
5
|
render() {
|
|
6
|
-
return /*#__PURE__*/React.createElement(I18N, {
|
|
6
|
+
return /*#__PURE__*/React.createElement(I18N, {
|
|
7
|
+
...this.props
|
|
7
8
|
});
|
|
8
9
|
}
|
|
9
|
-
|
|
10
10
|
}
|
|
11
11
|
FormatText.propTypes = {
|
|
12
12
|
i18NKey: PropTypes.string.isRequired,
|
package/es/components/HOCI18N.js
CHANGED
|
@@ -2,49 +2,38 @@ import React, { Children } from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { replaceI18NValuesWithRegex, unescapeUnicode } from "../utils";
|
|
4
4
|
import { I18NContext } from "../I18NContext";
|
|
5
|
-
export default (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} = this.context || {};
|
|
18
|
-
|
|
19
|
-
if (typeof i18n === 'undefined') {
|
|
20
|
-
return key;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let i18nStr = i18n[key];
|
|
24
|
-
|
|
25
|
-
if (i18nStr === undefined) {
|
|
26
|
-
return key;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return unescapeUnicode(i18nStr);
|
|
5
|
+
export default (i18NKeys = []) => Component => {
|
|
6
|
+
class HOCI18N extends React.Component {
|
|
7
|
+
constructor(props) {
|
|
8
|
+
super(props);
|
|
9
|
+
this.getI18NValue = this.getI18NValue.bind(this);
|
|
10
|
+
}
|
|
11
|
+
getI18NValue(key) {
|
|
12
|
+
const {
|
|
13
|
+
i18n
|
|
14
|
+
} = this.context || {};
|
|
15
|
+
if (typeof i18n === 'undefined') {
|
|
16
|
+
return key;
|
|
30
17
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
if (this.props[key]) {
|
|
35
|
-
result[key] = this.getI18NValue(this.props[key]);
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return result;
|
|
39
|
-
}, {});
|
|
40
|
-
return /*#__PURE__*/React.createElement(Component, { ...this.props,
|
|
41
|
-
...i18nProps
|
|
42
|
-
});
|
|
18
|
+
let i18nStr = i18n[key];
|
|
19
|
+
if (i18nStr === undefined) {
|
|
20
|
+
return key;
|
|
43
21
|
}
|
|
44
|
-
|
|
22
|
+
return unescapeUnicode(i18nStr);
|
|
23
|
+
}
|
|
24
|
+
render() {
|
|
25
|
+
let i18nProps = i18NKeys.reduce((result, key) => {
|
|
26
|
+
if (this.props[key]) {
|
|
27
|
+
result[key] = this.getI18NValue(this.props[key]);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
}, {});
|
|
31
|
+
return /*#__PURE__*/React.createElement(Component, {
|
|
32
|
+
...this.props,
|
|
33
|
+
...i18nProps
|
|
34
|
+
});
|
|
45
35
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
});
|
|
36
|
+
}
|
|
37
|
+
HOCI18N.contextType = I18NContext;
|
|
38
|
+
return HOCI18N;
|
|
39
|
+
};
|
package/es/components/I18N.js
CHANGED
|
@@ -9,7 +9,6 @@ export default class I18N extends React.Component {
|
|
|
9
9
|
this.getI18NValue = this.getI18NValue.bind(this);
|
|
10
10
|
this.createElement = this.createElement.bind(this);
|
|
11
11
|
}
|
|
12
|
-
|
|
13
12
|
getI18NValue() {
|
|
14
13
|
const {
|
|
15
14
|
i18NKey: key,
|
|
@@ -18,35 +17,28 @@ export default class I18N extends React.Component {
|
|
|
18
17
|
const {
|
|
19
18
|
i18n
|
|
20
19
|
} = this.context || {};
|
|
21
|
-
|
|
22
20
|
if (typeof i18n === 'undefined') {
|
|
23
21
|
return key;
|
|
24
22
|
}
|
|
25
|
-
|
|
26
23
|
let i18nStr = i18n[key];
|
|
27
|
-
|
|
28
24
|
if (i18nStr === undefined) {
|
|
29
25
|
return key;
|
|
30
26
|
}
|
|
31
|
-
|
|
32
27
|
i18nStr = replaceI18NValuesWithRegex(i18nStr, values);
|
|
33
28
|
return unescapeUnicode(i18nStr);
|
|
34
29
|
}
|
|
35
|
-
|
|
36
30
|
createElement() {
|
|
37
31
|
const props = Object.keys(this.props).reduce((result, nextKey) => {
|
|
38
32
|
if (nextKey != 'i18NKey' && nextKey != 'tag' && nextKey != 'values' && nextKey != 'isHtml' && nextKey != 'dataId') {
|
|
39
33
|
result[nextKey] = this.props[nextKey];
|
|
40
34
|
}
|
|
41
|
-
|
|
42
35
|
return result;
|
|
43
|
-
}, {});
|
|
44
|
-
|
|
36
|
+
}, {});
|
|
37
|
+
//const child=this.getI18NValue();
|
|
45
38
|
if (this.props.dataId) {
|
|
46
39
|
props['data-id'] = this.props.dataId;
|
|
47
40
|
props['data-test-id'] = this.props.dataId;
|
|
48
41
|
}
|
|
49
|
-
|
|
50
42
|
if (this.props.isHtml) {
|
|
51
43
|
let dangerouslySetInnerHTML = {
|
|
52
44
|
__html: HTMLPurifier.sanitize(this.getI18NValue())
|
|
@@ -55,14 +47,11 @@ export default class I18N extends React.Component {
|
|
|
55
47
|
dangerouslySetInnerHTML
|
|
56
48
|
}));
|
|
57
49
|
}
|
|
58
|
-
|
|
59
50
|
return /*#__PURE__*/React.createElement(this.props.tag, props, this.getI18NValue());
|
|
60
51
|
}
|
|
61
|
-
|
|
62
52
|
render() {
|
|
63
53
|
return this.createElement();
|
|
64
54
|
}
|
|
65
|
-
|
|
66
55
|
}
|
|
67
56
|
I18N.propTypes = {
|
|
68
57
|
i18NKey: PropTypes.string.isRequired,
|