@nocios/crudify-components 2.0.32 → 2.0.38

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.
Files changed (178) hide show
  1. package/coverage/base.css +224 -0
  2. package/coverage/block-navigation.js +87 -0
  3. package/coverage/components/CrudiaAutoGenerate.tsx.html +583 -0
  4. package/coverage/components/CrudiaFileField/CrudiaFileField.tsx.html +1276 -0
  5. package/coverage/components/CrudiaFileField/components/DeleteConfirmationDialog.tsx.html +355 -0
  6. package/coverage/components/CrudiaFileField/components/DropZone.tsx.html +433 -0
  7. package/coverage/components/CrudiaFileField/components/FileItemRow.tsx.html +751 -0
  8. package/coverage/components/CrudiaFileField/components/FileThumbnail.tsx.html +1195 -0
  9. package/coverage/components/CrudiaFileField/components/index.html +176 -0
  10. package/coverage/components/CrudiaFileField/components/index.ts.html +115 -0
  11. package/coverage/components/CrudiaFileField/hooks/index.html +146 -0
  12. package/coverage/components/CrudiaFileField/hooks/index.ts.html +112 -0
  13. package/coverage/components/CrudiaFileField/hooks/useDeleteConfirmation.ts.html +421 -0
  14. package/coverage/components/CrudiaFileField/hooks/useDragDrop.ts.html +403 -0
  15. package/coverage/components/CrudiaFileField/index.html +131 -0
  16. package/coverage/components/CrudiaFileField/index.ts.html +112 -0
  17. package/coverage/components/CrudiaFileField/utils/formatters.ts.html +163 -0
  18. package/coverage/components/CrudiaFileField/utils/icons.tsx.html +253 -0
  19. package/coverage/components/CrudiaFileField/utils/index.html +131 -0
  20. package/coverage/components/CrudiaMarkdownField.tsx.html +619 -0
  21. package/coverage/components/CrudifyLogin/Forms/CheckCodeForm.tsx.html +586 -0
  22. package/coverage/components/CrudifyLogin/Forms/ForgotPasswordForm.tsx.html +694 -0
  23. package/coverage/components/CrudifyLogin/Forms/LoginForm.tsx.html +835 -0
  24. package/coverage/components/CrudifyLogin/Forms/ResetPasswordForm.tsx.html +1180 -0
  25. package/coverage/components/CrudifyLogin/Forms/components/CodeInput.tsx.html +283 -0
  26. package/coverage/components/CrudifyLogin/Forms/components/FormAlert.tsx.html +202 -0
  27. package/coverage/components/CrudifyLogin/Forms/components/PasswordInput.tsx.html +340 -0
  28. package/coverage/components/CrudifyLogin/Forms/components/index.html +161 -0
  29. package/coverage/components/CrudifyLogin/Forms/components/index.ts.html +106 -0
  30. package/coverage/components/CrudifyLogin/Forms/index.html +161 -0
  31. package/coverage/components/CrudifyLogin/Forms/utils/errorTranslation.ts.html +268 -0
  32. package/coverage/components/CrudifyLogin/Forms/utils/index.html +161 -0
  33. package/coverage/components/CrudifyLogin/Forms/utils/index.ts.html +106 -0
  34. package/coverage/components/CrudifyLogin/Forms/utils/paramUtils.ts.html +478 -0
  35. package/coverage/components/CrudifyLogin/Forms/utils/validation.ts.html +289 -0
  36. package/coverage/components/CrudifyLogin/components/CrudifyInitializer.tsx.html +262 -0
  37. package/coverage/components/CrudifyLogin/components/index.html +116 -0
  38. package/coverage/components/CrudifyLogin/context/CrudifyProvider.tsx.html +382 -0
  39. package/coverage/components/CrudifyLogin/context/I18nProvider.tsx.html +397 -0
  40. package/coverage/components/CrudifyLogin/context/LoginStateProvider.tsx.html +1249 -0
  41. package/coverage/components/CrudifyLogin/context/index.html +146 -0
  42. package/coverage/components/CrudifyLogin/hooks/index.html +116 -0
  43. package/coverage/components/CrudifyLogin/hooks/useTranslationsFromUrl.ts.html +292 -0
  44. package/coverage/components/CrudifyLogin/index.html +116 -0
  45. package/coverage/components/CrudifyLogin/index.tsx.html +475 -0
  46. package/coverage/components/GlobalNotificationProvider.tsx.html +781 -0
  47. package/coverage/components/LoginComponent.tsx.html +727 -0
  48. package/coverage/components/PasswordRequirements/index.html +116 -0
  49. package/coverage/components/PasswordRequirements/index.tsx.html +226 -0
  50. package/coverage/components/PublicPolicies/FieldSelector/FieldSelector.tsx.html +982 -0
  51. package/coverage/components/PublicPolicies/FieldSelector/index.html +131 -0
  52. package/coverage/components/PublicPolicies/FieldSelector/index.ts.html +85 -0
  53. package/coverage/components/PublicPolicies/Policies.tsx.html +610 -0
  54. package/coverage/components/PublicPolicies/PolicyItem/PolicyItem.tsx.html +856 -0
  55. package/coverage/components/PublicPolicies/PolicyItem/index.html +131 -0
  56. package/coverage/components/PublicPolicies/PolicyItem/index.ts.html +85 -0
  57. package/coverage/components/PublicPolicies/constants.ts.html +127 -0
  58. package/coverage/components/PublicPolicies/index.html +131 -0
  59. package/coverage/components/SessionTimeIndicator/index.html +116 -0
  60. package/coverage/components/SessionTimeIndicator/index.tsx.html +505 -0
  61. package/coverage/components/UserProfile/UserProfileDisplay.tsx.html +826 -0
  62. package/coverage/components/UserProfile/index.html +131 -0
  63. package/coverage/components/UserProfile/index.ts.html +85 -0
  64. package/coverage/components/index.html +176 -0
  65. package/coverage/components/index.ts.html +160 -0
  66. package/coverage/core/CrossTabSyncManager.ts.html +814 -0
  67. package/coverage/core/CrudifyInitializationManager.ts.html +1132 -0
  68. package/coverage/core/SessionManager.ts.html +2764 -0
  69. package/coverage/core/index.html +146 -0
  70. package/coverage/coverage-final.json +87 -0
  71. package/coverage/favicon.png +0 -0
  72. package/coverage/hooks/index.html +131 -0
  73. package/coverage/hooks/useAutoGenerate.ts.html +562 -0
  74. package/coverage/hooks/useFileUpload/index.html +131 -0
  75. package/coverage/hooks/useFileUpload/index.ts.html +112 -0
  76. package/coverage/hooks/useFileUpload/services/index.html +116 -0
  77. package/coverage/hooks/useFileUpload/services/uploadService.ts.html +610 -0
  78. package/coverage/hooks/useFileUpload/useFileUpload.ts.html +1870 -0
  79. package/coverage/hooks/useFileUpload/utils/fileUtils.ts.html +271 -0
  80. package/coverage/hooks/useFileUpload/utils/index.html +146 -0
  81. package/coverage/hooks/useFileUpload/utils/mimeTypes.ts.html +235 -0
  82. package/coverage/hooks/useFileUpload/utils/validation.ts.html +379 -0
  83. package/coverage/hooks/useSession/constants.ts.html +217 -0
  84. package/coverage/hooks/useSession/hooks/index.html +176 -0
  85. package/coverage/hooks/useSession/hooks/useAuthEventSubscriber.ts.html +331 -0
  86. package/coverage/hooks/useSession/hooks/useCrossTabSync.ts.html +433 -0
  87. package/coverage/hooks/useSession/hooks/useSessionActions.ts.html +664 -0
  88. package/coverage/hooks/useSession/hooks/useSessionState.ts.html +295 -0
  89. package/coverage/hooks/useSession/hooks/useTokenRefreshScheduler.ts.html +490 -0
  90. package/coverage/hooks/useSession/index.html +161 -0
  91. package/coverage/hooks/useSession/index.ts.html +127 -0
  92. package/coverage/hooks/useSession/types.ts.html +427 -0
  93. package/coverage/hooks/useSession/useSession.ts.html +526 -0
  94. package/coverage/hooks/useSession/utils/index.html +131 -0
  95. package/coverage/hooks/useSession/utils/initializeSession.ts.html +424 -0
  96. package/coverage/hooks/useSession/utils/tokenUtils.ts.html +280 -0
  97. package/coverage/hooks/useUserProfile.ts.html +658 -0
  98. package/coverage/index.html +566 -0
  99. package/coverage/prettify.css +1 -0
  100. package/coverage/prettify.js +2 -0
  101. package/coverage/providers/SessionProvider.tsx.html +1150 -0
  102. package/coverage/providers/TranslationsProvider.tsx.html +1450 -0
  103. package/coverage/providers/index.html +131 -0
  104. package/coverage/services/credentialsEventBus.ts.html +310 -0
  105. package/coverage/services/index.html +131 -0
  106. package/coverage/services/translationService.ts.html +1318 -0
  107. package/coverage/sort-arrow-sprite.png +0 -0
  108. package/coverage/sorter.js +210 -0
  109. package/coverage/translations/critical.ts.html +1195 -0
  110. package/coverage/translations/index.html +116 -0
  111. package/coverage/types/index.html +116 -0
  112. package/coverage/types/password.ts.html +178 -0
  113. package/coverage/utils/authEventBus.ts.html +454 -0
  114. package/coverage/utils/configResolver.ts.html +460 -0
  115. package/coverage/utils/cookieSync.ts.html +580 -0
  116. package/coverage/utils/errorHandler.ts.html +1264 -0
  117. package/coverage/utils/errorTranslation.ts.html +862 -0
  118. package/coverage/utils/index.html +296 -0
  119. package/coverage/utils/jwtUtils.ts.html +301 -0
  120. package/coverage/utils/logger.ts.html +901 -0
  121. package/coverage/utils/navigationTracker.ts.html +565 -0
  122. package/coverage/utils/passwordValidation.ts.html +259 -0
  123. package/coverage/utils/redirectSecurity.ts.html +715 -0
  124. package/coverage/utils/tenantConfig.ts.html +700 -0
  125. package/coverage/utils/tokenStorage.ts.html +1768 -0
  126. package/coverage/utils/webCrypto.ts.html +472 -0
  127. package/dist/{CrudiaMarkdownField-C54-A_J3.d.mts → CrudiaMarkdownField-BvJn2GL8.d.mts} +17 -7
  128. package/dist/{CrudiaMarkdownField-C8HQh7s5.d.ts → CrudiaMarkdownField-CggOpcBM.d.ts} +17 -7
  129. package/dist/chunk-44VU4TSP.mjs +1 -0
  130. package/dist/chunk-4LMFQECS.js +1 -0
  131. package/dist/chunk-77UKXG5L.mjs +1 -0
  132. package/dist/{chunk-4VN5YRYZ.js → chunk-BXFEQ6KP.js} +1 -1
  133. package/dist/{chunk-6ONAT4QU.js → chunk-H6XXWDUT.js} +1 -1
  134. package/dist/chunk-NIRLP2TC.js +1 -0
  135. package/dist/chunk-O4FUHIQG.mjs +1 -0
  136. package/dist/chunk-SYHNHKFA.mjs +1 -0
  137. package/dist/chunk-W4ZYKPOK.js +1 -0
  138. package/dist/{chunk-RJBX4MWF.mjs → chunk-WMLIOPUC.mjs} +1 -1
  139. package/dist/components.d.mts +1 -1
  140. package/dist/components.d.ts +1 -1
  141. package/dist/components.js +1 -1
  142. package/dist/components.mjs +1 -1
  143. package/dist/errorTranslation-D-Y7uNN_.d.mts +141 -0
  144. package/dist/errorTranslation-DDlAXpMl.d.ts +141 -0
  145. package/dist/hooks.d.mts +2 -2
  146. package/dist/hooks.d.ts +2 -2
  147. package/dist/hooks.js +1 -1
  148. package/dist/hooks.mjs +1 -1
  149. package/dist/{index-DY90WVQQ.d.mts → index-U--xRr8A.d.mts} +225 -191
  150. package/dist/{index-d1vE803G.d.ts → index-dXVRVcEB.d.ts} +225 -191
  151. package/dist/index.d.mts +179 -6
  152. package/dist/index.d.ts +179 -6
  153. package/dist/index.js +2 -2
  154. package/dist/index.mjs +1 -1
  155. package/dist/{errorTranslation-By5Av0tL.d.ts → tenantConfig-DqJqQkoR.d.mts} +116 -139
  156. package/dist/{errorTranslation-DeeDj7Vt.d.mts → tenantConfig-DqJqQkoR.d.ts} +116 -139
  157. package/dist/utils.d.mts +2 -2
  158. package/dist/utils.d.ts +2 -2
  159. package/dist/utils.js +1 -1
  160. package/dist/utils.mjs +1 -1
  161. package/package.json +1 -1
  162. package/coverage/.tmp/coverage-102.json +0 -1
  163. package/coverage/.tmp/coverage-103.json +0 -1
  164. package/coverage/.tmp/coverage-104.json +0 -1
  165. package/coverage/.tmp/coverage-105.json +0 -1
  166. package/coverage/.tmp/coverage-106.json +0 -1
  167. package/coverage/.tmp/coverage-107.json +0 -1
  168. package/dist/api-B4uXiHF0.d.mts +0 -118
  169. package/dist/api-B4uXiHF0.d.ts +0 -118
  170. package/dist/chunk-4ILUXVPW.mjs +0 -1
  171. package/dist/chunk-5XBTRBE5.js +0 -1
  172. package/dist/chunk-CR5KJUST.js +0 -1
  173. package/dist/chunk-H5M2Q6PB.mjs +0 -1
  174. package/dist/chunk-JAPL7EZJ.mjs +0 -1
  175. package/dist/chunk-L7GKP6XY.mjs +0 -1
  176. package/dist/chunk-NSV6ECYO.js +0 -1
  177. package/dist/chunk-PTUSZGL4.mjs +0 -1
  178. package/dist/chunk-T6R65ROU.js +0 -1
@@ -0,0 +1,1450 @@
1
+
2
+ <!doctype html>
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <title>Code coverage report for providers/TranslationsProvider.tsx</title>
7
+ <meta charset="utf-8" />
8
+ <link rel="stylesheet" href="../prettify.css" />
9
+ <link rel="stylesheet" href="../base.css" />
10
+ <link rel="shortcut icon" type="image/x-icon" href="../favicon.png" />
11
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12
+ <style type='text/css'>
13
+ .coverage-summary .sorter {
14
+ background-image: url(../sort-arrow-sprite.png);
15
+ }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <div class='wrapper'>
21
+ <div class='pad1'>
22
+ <h1><a href="../index.html">All files</a> / <a href="index.html">providers</a> TranslationsProvider.tsx</h1>
23
+ <div class='clearfix'>
24
+
25
+ <div class='fl pad1y space-right2'>
26
+ <span class="strong">85.27% </span>
27
+ <span class="quiet">Statements</span>
28
+ <span class='fraction'>388/455</span>
29
+ </div>
30
+
31
+
32
+ <div class='fl pad1y space-right2'>
33
+ <span class="strong">69.44% </span>
34
+ <span class="quiet">Branches</span>
35
+ <span class='fraction'>50/72</span>
36
+ </div>
37
+
38
+
39
+ <div class='fl pad1y space-right2'>
40
+ <span class="strong">100% </span>
41
+ <span class="quiet">Functions</span>
42
+ <span class='fraction'>4/4</span>
43
+ </div>
44
+
45
+
46
+ <div class='fl pad1y space-right2'>
47
+ <span class="strong">85.27% </span>
48
+ <span class="quiet">Lines</span>
49
+ <span class='fraction'>388/455</span>
50
+ </div>
51
+
52
+
53
+ </div>
54
+ <p class="quiet">
55
+ Press <em>n</em> or <em>j</em> to go to the next uncovered block, <em>b</em>, <em>p</em> or <em>k</em> for the previous block.
56
+ </p>
57
+ <template id="filterTemplate">
58
+ <div class="quiet">
59
+ Filter:
60
+ <input type="search" id="fileSearch">
61
+ </div>
62
+ </template>
63
+ </div>
64
+ <div class='status-line high'></div>
65
+ <pre><table class="coverage">
66
+ <tr><td class="line-count quiet"><a name='L1'></a><a href='#L1'>1</a>
67
+ <a name='L2'></a><a href='#L2'>2</a>
68
+ <a name='L3'></a><a href='#L3'>3</a>
69
+ <a name='L4'></a><a href='#L4'>4</a>
70
+ <a name='L5'></a><a href='#L5'>5</a>
71
+ <a name='L6'></a><a href='#L6'>6</a>
72
+ <a name='L7'></a><a href='#L7'>7</a>
73
+ <a name='L8'></a><a href='#L8'>8</a>
74
+ <a name='L9'></a><a href='#L9'>9</a>
75
+ <a name='L10'></a><a href='#L10'>10</a>
76
+ <a name='L11'></a><a href='#L11'>11</a>
77
+ <a name='L12'></a><a href='#L12'>12</a>
78
+ <a name='L13'></a><a href='#L13'>13</a>
79
+ <a name='L14'></a><a href='#L14'>14</a>
80
+ <a name='L15'></a><a href='#L15'>15</a>
81
+ <a name='L16'></a><a href='#L16'>16</a>
82
+ <a name='L17'></a><a href='#L17'>17</a>
83
+ <a name='L18'></a><a href='#L18'>18</a>
84
+ <a name='L19'></a><a href='#L19'>19</a>
85
+ <a name='L20'></a><a href='#L20'>20</a>
86
+ <a name='L21'></a><a href='#L21'>21</a>
87
+ <a name='L22'></a><a href='#L22'>22</a>
88
+ <a name='L23'></a><a href='#L23'>23</a>
89
+ <a name='L24'></a><a href='#L24'>24</a>
90
+ <a name='L25'></a><a href='#L25'>25</a>
91
+ <a name='L26'></a><a href='#L26'>26</a>
92
+ <a name='L27'></a><a href='#L27'>27</a>
93
+ <a name='L28'></a><a href='#L28'>28</a>
94
+ <a name='L29'></a><a href='#L29'>29</a>
95
+ <a name='L30'></a><a href='#L30'>30</a>
96
+ <a name='L31'></a><a href='#L31'>31</a>
97
+ <a name='L32'></a><a href='#L32'>32</a>
98
+ <a name='L33'></a><a href='#L33'>33</a>
99
+ <a name='L34'></a><a href='#L34'>34</a>
100
+ <a name='L35'></a><a href='#L35'>35</a>
101
+ <a name='L36'></a><a href='#L36'>36</a>
102
+ <a name='L37'></a><a href='#L37'>37</a>
103
+ <a name='L38'></a><a href='#L38'>38</a>
104
+ <a name='L39'></a><a href='#L39'>39</a>
105
+ <a name='L40'></a><a href='#L40'>40</a>
106
+ <a name='L41'></a><a href='#L41'>41</a>
107
+ <a name='L42'></a><a href='#L42'>42</a>
108
+ <a name='L43'></a><a href='#L43'>43</a>
109
+ <a name='L44'></a><a href='#L44'>44</a>
110
+ <a name='L45'></a><a href='#L45'>45</a>
111
+ <a name='L46'></a><a href='#L46'>46</a>
112
+ <a name='L47'></a><a href='#L47'>47</a>
113
+ <a name='L48'></a><a href='#L48'>48</a>
114
+ <a name='L49'></a><a href='#L49'>49</a>
115
+ <a name='L50'></a><a href='#L50'>50</a>
116
+ <a name='L51'></a><a href='#L51'>51</a>
117
+ <a name='L52'></a><a href='#L52'>52</a>
118
+ <a name='L53'></a><a href='#L53'>53</a>
119
+ <a name='L54'></a><a href='#L54'>54</a>
120
+ <a name='L55'></a><a href='#L55'>55</a>
121
+ <a name='L56'></a><a href='#L56'>56</a>
122
+ <a name='L57'></a><a href='#L57'>57</a>
123
+ <a name='L58'></a><a href='#L58'>58</a>
124
+ <a name='L59'></a><a href='#L59'>59</a>
125
+ <a name='L60'></a><a href='#L60'>60</a>
126
+ <a name='L61'></a><a href='#L61'>61</a>
127
+ <a name='L62'></a><a href='#L62'>62</a>
128
+ <a name='L63'></a><a href='#L63'>63</a>
129
+ <a name='L64'></a><a href='#L64'>64</a>
130
+ <a name='L65'></a><a href='#L65'>65</a>
131
+ <a name='L66'></a><a href='#L66'>66</a>
132
+ <a name='L67'></a><a href='#L67'>67</a>
133
+ <a name='L68'></a><a href='#L68'>68</a>
134
+ <a name='L69'></a><a href='#L69'>69</a>
135
+ <a name='L70'></a><a href='#L70'>70</a>
136
+ <a name='L71'></a><a href='#L71'>71</a>
137
+ <a name='L72'></a><a href='#L72'>72</a>
138
+ <a name='L73'></a><a href='#L73'>73</a>
139
+ <a name='L74'></a><a href='#L74'>74</a>
140
+ <a name='L75'></a><a href='#L75'>75</a>
141
+ <a name='L76'></a><a href='#L76'>76</a>
142
+ <a name='L77'></a><a href='#L77'>77</a>
143
+ <a name='L78'></a><a href='#L78'>78</a>
144
+ <a name='L79'></a><a href='#L79'>79</a>
145
+ <a name='L80'></a><a href='#L80'>80</a>
146
+ <a name='L81'></a><a href='#L81'>81</a>
147
+ <a name='L82'></a><a href='#L82'>82</a>
148
+ <a name='L83'></a><a href='#L83'>83</a>
149
+ <a name='L84'></a><a href='#L84'>84</a>
150
+ <a name='L85'></a><a href='#L85'>85</a>
151
+ <a name='L86'></a><a href='#L86'>86</a>
152
+ <a name='L87'></a><a href='#L87'>87</a>
153
+ <a name='L88'></a><a href='#L88'>88</a>
154
+ <a name='L89'></a><a href='#L89'>89</a>
155
+ <a name='L90'></a><a href='#L90'>90</a>
156
+ <a name='L91'></a><a href='#L91'>91</a>
157
+ <a name='L92'></a><a href='#L92'>92</a>
158
+ <a name='L93'></a><a href='#L93'>93</a>
159
+ <a name='L94'></a><a href='#L94'>94</a>
160
+ <a name='L95'></a><a href='#L95'>95</a>
161
+ <a name='L96'></a><a href='#L96'>96</a>
162
+ <a name='L97'></a><a href='#L97'>97</a>
163
+ <a name='L98'></a><a href='#L98'>98</a>
164
+ <a name='L99'></a><a href='#L99'>99</a>
165
+ <a name='L100'></a><a href='#L100'>100</a>
166
+ <a name='L101'></a><a href='#L101'>101</a>
167
+ <a name='L102'></a><a href='#L102'>102</a>
168
+ <a name='L103'></a><a href='#L103'>103</a>
169
+ <a name='L104'></a><a href='#L104'>104</a>
170
+ <a name='L105'></a><a href='#L105'>105</a>
171
+ <a name='L106'></a><a href='#L106'>106</a>
172
+ <a name='L107'></a><a href='#L107'>107</a>
173
+ <a name='L108'></a><a href='#L108'>108</a>
174
+ <a name='L109'></a><a href='#L109'>109</a>
175
+ <a name='L110'></a><a href='#L110'>110</a>
176
+ <a name='L111'></a><a href='#L111'>111</a>
177
+ <a name='L112'></a><a href='#L112'>112</a>
178
+ <a name='L113'></a><a href='#L113'>113</a>
179
+ <a name='L114'></a><a href='#L114'>114</a>
180
+ <a name='L115'></a><a href='#L115'>115</a>
181
+ <a name='L116'></a><a href='#L116'>116</a>
182
+ <a name='L117'></a><a href='#L117'>117</a>
183
+ <a name='L118'></a><a href='#L118'>118</a>
184
+ <a name='L119'></a><a href='#L119'>119</a>
185
+ <a name='L120'></a><a href='#L120'>120</a>
186
+ <a name='L121'></a><a href='#L121'>121</a>
187
+ <a name='L122'></a><a href='#L122'>122</a>
188
+ <a name='L123'></a><a href='#L123'>123</a>
189
+ <a name='L124'></a><a href='#L124'>124</a>
190
+ <a name='L125'></a><a href='#L125'>125</a>
191
+ <a name='L126'></a><a href='#L126'>126</a>
192
+ <a name='L127'></a><a href='#L127'>127</a>
193
+ <a name='L128'></a><a href='#L128'>128</a>
194
+ <a name='L129'></a><a href='#L129'>129</a>
195
+ <a name='L130'></a><a href='#L130'>130</a>
196
+ <a name='L131'></a><a href='#L131'>131</a>
197
+ <a name='L132'></a><a href='#L132'>132</a>
198
+ <a name='L133'></a><a href='#L133'>133</a>
199
+ <a name='L134'></a><a href='#L134'>134</a>
200
+ <a name='L135'></a><a href='#L135'>135</a>
201
+ <a name='L136'></a><a href='#L136'>136</a>
202
+ <a name='L137'></a><a href='#L137'>137</a>
203
+ <a name='L138'></a><a href='#L138'>138</a>
204
+ <a name='L139'></a><a href='#L139'>139</a>
205
+ <a name='L140'></a><a href='#L140'>140</a>
206
+ <a name='L141'></a><a href='#L141'>141</a>
207
+ <a name='L142'></a><a href='#L142'>142</a>
208
+ <a name='L143'></a><a href='#L143'>143</a>
209
+ <a name='L144'></a><a href='#L144'>144</a>
210
+ <a name='L145'></a><a href='#L145'>145</a>
211
+ <a name='L146'></a><a href='#L146'>146</a>
212
+ <a name='L147'></a><a href='#L147'>147</a>
213
+ <a name='L148'></a><a href='#L148'>148</a>
214
+ <a name='L149'></a><a href='#L149'>149</a>
215
+ <a name='L150'></a><a href='#L150'>150</a>
216
+ <a name='L151'></a><a href='#L151'>151</a>
217
+ <a name='L152'></a><a href='#L152'>152</a>
218
+ <a name='L153'></a><a href='#L153'>153</a>
219
+ <a name='L154'></a><a href='#L154'>154</a>
220
+ <a name='L155'></a><a href='#L155'>155</a>
221
+ <a name='L156'></a><a href='#L156'>156</a>
222
+ <a name='L157'></a><a href='#L157'>157</a>
223
+ <a name='L158'></a><a href='#L158'>158</a>
224
+ <a name='L159'></a><a href='#L159'>159</a>
225
+ <a name='L160'></a><a href='#L160'>160</a>
226
+ <a name='L161'></a><a href='#L161'>161</a>
227
+ <a name='L162'></a><a href='#L162'>162</a>
228
+ <a name='L163'></a><a href='#L163'>163</a>
229
+ <a name='L164'></a><a href='#L164'>164</a>
230
+ <a name='L165'></a><a href='#L165'>165</a>
231
+ <a name='L166'></a><a href='#L166'>166</a>
232
+ <a name='L167'></a><a href='#L167'>167</a>
233
+ <a name='L168'></a><a href='#L168'>168</a>
234
+ <a name='L169'></a><a href='#L169'>169</a>
235
+ <a name='L170'></a><a href='#L170'>170</a>
236
+ <a name='L171'></a><a href='#L171'>171</a>
237
+ <a name='L172'></a><a href='#L172'>172</a>
238
+ <a name='L173'></a><a href='#L173'>173</a>
239
+ <a name='L174'></a><a href='#L174'>174</a>
240
+ <a name='L175'></a><a href='#L175'>175</a>
241
+ <a name='L176'></a><a href='#L176'>176</a>
242
+ <a name='L177'></a><a href='#L177'>177</a>
243
+ <a name='L178'></a><a href='#L178'>178</a>
244
+ <a name='L179'></a><a href='#L179'>179</a>
245
+ <a name='L180'></a><a href='#L180'>180</a>
246
+ <a name='L181'></a><a href='#L181'>181</a>
247
+ <a name='L182'></a><a href='#L182'>182</a>
248
+ <a name='L183'></a><a href='#L183'>183</a>
249
+ <a name='L184'></a><a href='#L184'>184</a>
250
+ <a name='L185'></a><a href='#L185'>185</a>
251
+ <a name='L186'></a><a href='#L186'>186</a>
252
+ <a name='L187'></a><a href='#L187'>187</a>
253
+ <a name='L188'></a><a href='#L188'>188</a>
254
+ <a name='L189'></a><a href='#L189'>189</a>
255
+ <a name='L190'></a><a href='#L190'>190</a>
256
+ <a name='L191'></a><a href='#L191'>191</a>
257
+ <a name='L192'></a><a href='#L192'>192</a>
258
+ <a name='L193'></a><a href='#L193'>193</a>
259
+ <a name='L194'></a><a href='#L194'>194</a>
260
+ <a name='L195'></a><a href='#L195'>195</a>
261
+ <a name='L196'></a><a href='#L196'>196</a>
262
+ <a name='L197'></a><a href='#L197'>197</a>
263
+ <a name='L198'></a><a href='#L198'>198</a>
264
+ <a name='L199'></a><a href='#L199'>199</a>
265
+ <a name='L200'></a><a href='#L200'>200</a>
266
+ <a name='L201'></a><a href='#L201'>201</a>
267
+ <a name='L202'></a><a href='#L202'>202</a>
268
+ <a name='L203'></a><a href='#L203'>203</a>
269
+ <a name='L204'></a><a href='#L204'>204</a>
270
+ <a name='L205'></a><a href='#L205'>205</a>
271
+ <a name='L206'></a><a href='#L206'>206</a>
272
+ <a name='L207'></a><a href='#L207'>207</a>
273
+ <a name='L208'></a><a href='#L208'>208</a>
274
+ <a name='L209'></a><a href='#L209'>209</a>
275
+ <a name='L210'></a><a href='#L210'>210</a>
276
+ <a name='L211'></a><a href='#L211'>211</a>
277
+ <a name='L212'></a><a href='#L212'>212</a>
278
+ <a name='L213'></a><a href='#L213'>213</a>
279
+ <a name='L214'></a><a href='#L214'>214</a>
280
+ <a name='L215'></a><a href='#L215'>215</a>
281
+ <a name='L216'></a><a href='#L216'>216</a>
282
+ <a name='L217'></a><a href='#L217'>217</a>
283
+ <a name='L218'></a><a href='#L218'>218</a>
284
+ <a name='L219'></a><a href='#L219'>219</a>
285
+ <a name='L220'></a><a href='#L220'>220</a>
286
+ <a name='L221'></a><a href='#L221'>221</a>
287
+ <a name='L222'></a><a href='#L222'>222</a>
288
+ <a name='L223'></a><a href='#L223'>223</a>
289
+ <a name='L224'></a><a href='#L224'>224</a>
290
+ <a name='L225'></a><a href='#L225'>225</a>
291
+ <a name='L226'></a><a href='#L226'>226</a>
292
+ <a name='L227'></a><a href='#L227'>227</a>
293
+ <a name='L228'></a><a href='#L228'>228</a>
294
+ <a name='L229'></a><a href='#L229'>229</a>
295
+ <a name='L230'></a><a href='#L230'>230</a>
296
+ <a name='L231'></a><a href='#L231'>231</a>
297
+ <a name='L232'></a><a href='#L232'>232</a>
298
+ <a name='L233'></a><a href='#L233'>233</a>
299
+ <a name='L234'></a><a href='#L234'>234</a>
300
+ <a name='L235'></a><a href='#L235'>235</a>
301
+ <a name='L236'></a><a href='#L236'>236</a>
302
+ <a name='L237'></a><a href='#L237'>237</a>
303
+ <a name='L238'></a><a href='#L238'>238</a>
304
+ <a name='L239'></a><a href='#L239'>239</a>
305
+ <a name='L240'></a><a href='#L240'>240</a>
306
+ <a name='L241'></a><a href='#L241'>241</a>
307
+ <a name='L242'></a><a href='#L242'>242</a>
308
+ <a name='L243'></a><a href='#L243'>243</a>
309
+ <a name='L244'></a><a href='#L244'>244</a>
310
+ <a name='L245'></a><a href='#L245'>245</a>
311
+ <a name='L246'></a><a href='#L246'>246</a>
312
+ <a name='L247'></a><a href='#L247'>247</a>
313
+ <a name='L248'></a><a href='#L248'>248</a>
314
+ <a name='L249'></a><a href='#L249'>249</a>
315
+ <a name='L250'></a><a href='#L250'>250</a>
316
+ <a name='L251'></a><a href='#L251'>251</a>
317
+ <a name='L252'></a><a href='#L252'>252</a>
318
+ <a name='L253'></a><a href='#L253'>253</a>
319
+ <a name='L254'></a><a href='#L254'>254</a>
320
+ <a name='L255'></a><a href='#L255'>255</a>
321
+ <a name='L256'></a><a href='#L256'>256</a>
322
+ <a name='L257'></a><a href='#L257'>257</a>
323
+ <a name='L258'></a><a href='#L258'>258</a>
324
+ <a name='L259'></a><a href='#L259'>259</a>
325
+ <a name='L260'></a><a href='#L260'>260</a>
326
+ <a name='L261'></a><a href='#L261'>261</a>
327
+ <a name='L262'></a><a href='#L262'>262</a>
328
+ <a name='L263'></a><a href='#L263'>263</a>
329
+ <a name='L264'></a><a href='#L264'>264</a>
330
+ <a name='L265'></a><a href='#L265'>265</a>
331
+ <a name='L266'></a><a href='#L266'>266</a>
332
+ <a name='L267'></a><a href='#L267'>267</a>
333
+ <a name='L268'></a><a href='#L268'>268</a>
334
+ <a name='L269'></a><a href='#L269'>269</a>
335
+ <a name='L270'></a><a href='#L270'>270</a>
336
+ <a name='L271'></a><a href='#L271'>271</a>
337
+ <a name='L272'></a><a href='#L272'>272</a>
338
+ <a name='L273'></a><a href='#L273'>273</a>
339
+ <a name='L274'></a><a href='#L274'>274</a>
340
+ <a name='L275'></a><a href='#L275'>275</a>
341
+ <a name='L276'></a><a href='#L276'>276</a>
342
+ <a name='L277'></a><a href='#L277'>277</a>
343
+ <a name='L278'></a><a href='#L278'>278</a>
344
+ <a name='L279'></a><a href='#L279'>279</a>
345
+ <a name='L280'></a><a href='#L280'>280</a>
346
+ <a name='L281'></a><a href='#L281'>281</a>
347
+ <a name='L282'></a><a href='#L282'>282</a>
348
+ <a name='L283'></a><a href='#L283'>283</a>
349
+ <a name='L284'></a><a href='#L284'>284</a>
350
+ <a name='L285'></a><a href='#L285'>285</a>
351
+ <a name='L286'></a><a href='#L286'>286</a>
352
+ <a name='L287'></a><a href='#L287'>287</a>
353
+ <a name='L288'></a><a href='#L288'>288</a>
354
+ <a name='L289'></a><a href='#L289'>289</a>
355
+ <a name='L290'></a><a href='#L290'>290</a>
356
+ <a name='L291'></a><a href='#L291'>291</a>
357
+ <a name='L292'></a><a href='#L292'>292</a>
358
+ <a name='L293'></a><a href='#L293'>293</a>
359
+ <a name='L294'></a><a href='#L294'>294</a>
360
+ <a name='L295'></a><a href='#L295'>295</a>
361
+ <a name='L296'></a><a href='#L296'>296</a>
362
+ <a name='L297'></a><a href='#L297'>297</a>
363
+ <a name='L298'></a><a href='#L298'>298</a>
364
+ <a name='L299'></a><a href='#L299'>299</a>
365
+ <a name='L300'></a><a href='#L300'>300</a>
366
+ <a name='L301'></a><a href='#L301'>301</a>
367
+ <a name='L302'></a><a href='#L302'>302</a>
368
+ <a name='L303'></a><a href='#L303'>303</a>
369
+ <a name='L304'></a><a href='#L304'>304</a>
370
+ <a name='L305'></a><a href='#L305'>305</a>
371
+ <a name='L306'></a><a href='#L306'>306</a>
372
+ <a name='L307'></a><a href='#L307'>307</a>
373
+ <a name='L308'></a><a href='#L308'>308</a>
374
+ <a name='L309'></a><a href='#L309'>309</a>
375
+ <a name='L310'></a><a href='#L310'>310</a>
376
+ <a name='L311'></a><a href='#L311'>311</a>
377
+ <a name='L312'></a><a href='#L312'>312</a>
378
+ <a name='L313'></a><a href='#L313'>313</a>
379
+ <a name='L314'></a><a href='#L314'>314</a>
380
+ <a name='L315'></a><a href='#L315'>315</a>
381
+ <a name='L316'></a><a href='#L316'>316</a>
382
+ <a name='L317'></a><a href='#L317'>317</a>
383
+ <a name='L318'></a><a href='#L318'>318</a>
384
+ <a name='L319'></a><a href='#L319'>319</a>
385
+ <a name='L320'></a><a href='#L320'>320</a>
386
+ <a name='L321'></a><a href='#L321'>321</a>
387
+ <a name='L322'></a><a href='#L322'>322</a>
388
+ <a name='L323'></a><a href='#L323'>323</a>
389
+ <a name='L324'></a><a href='#L324'>324</a>
390
+ <a name='L325'></a><a href='#L325'>325</a>
391
+ <a name='L326'></a><a href='#L326'>326</a>
392
+ <a name='L327'></a><a href='#L327'>327</a>
393
+ <a name='L328'></a><a href='#L328'>328</a>
394
+ <a name='L329'></a><a href='#L329'>329</a>
395
+ <a name='L330'></a><a href='#L330'>330</a>
396
+ <a name='L331'></a><a href='#L331'>331</a>
397
+ <a name='L332'></a><a href='#L332'>332</a>
398
+ <a name='L333'></a><a href='#L333'>333</a>
399
+ <a name='L334'></a><a href='#L334'>334</a>
400
+ <a name='L335'></a><a href='#L335'>335</a>
401
+ <a name='L336'></a><a href='#L336'>336</a>
402
+ <a name='L337'></a><a href='#L337'>337</a>
403
+ <a name='L338'></a><a href='#L338'>338</a>
404
+ <a name='L339'></a><a href='#L339'>339</a>
405
+ <a name='L340'></a><a href='#L340'>340</a>
406
+ <a name='L341'></a><a href='#L341'>341</a>
407
+ <a name='L342'></a><a href='#L342'>342</a>
408
+ <a name='L343'></a><a href='#L343'>343</a>
409
+ <a name='L344'></a><a href='#L344'>344</a>
410
+ <a name='L345'></a><a href='#L345'>345</a>
411
+ <a name='L346'></a><a href='#L346'>346</a>
412
+ <a name='L347'></a><a href='#L347'>347</a>
413
+ <a name='L348'></a><a href='#L348'>348</a>
414
+ <a name='L349'></a><a href='#L349'>349</a>
415
+ <a name='L350'></a><a href='#L350'>350</a>
416
+ <a name='L351'></a><a href='#L351'>351</a>
417
+ <a name='L352'></a><a href='#L352'>352</a>
418
+ <a name='L353'></a><a href='#L353'>353</a>
419
+ <a name='L354'></a><a href='#L354'>354</a>
420
+ <a name='L355'></a><a href='#L355'>355</a>
421
+ <a name='L356'></a><a href='#L356'>356</a>
422
+ <a name='L357'></a><a href='#L357'>357</a>
423
+ <a name='L358'></a><a href='#L358'>358</a>
424
+ <a name='L359'></a><a href='#L359'>359</a>
425
+ <a name='L360'></a><a href='#L360'>360</a>
426
+ <a name='L361'></a><a href='#L361'>361</a>
427
+ <a name='L362'></a><a href='#L362'>362</a>
428
+ <a name='L363'></a><a href='#L363'>363</a>
429
+ <a name='L364'></a><a href='#L364'>364</a>
430
+ <a name='L365'></a><a href='#L365'>365</a>
431
+ <a name='L366'></a><a href='#L366'>366</a>
432
+ <a name='L367'></a><a href='#L367'>367</a>
433
+ <a name='L368'></a><a href='#L368'>368</a>
434
+ <a name='L369'></a><a href='#L369'>369</a>
435
+ <a name='L370'></a><a href='#L370'>370</a>
436
+ <a name='L371'></a><a href='#L371'>371</a>
437
+ <a name='L372'></a><a href='#L372'>372</a>
438
+ <a name='L373'></a><a href='#L373'>373</a>
439
+ <a name='L374'></a><a href='#L374'>374</a>
440
+ <a name='L375'></a><a href='#L375'>375</a>
441
+ <a name='L376'></a><a href='#L376'>376</a>
442
+ <a name='L377'></a><a href='#L377'>377</a>
443
+ <a name='L378'></a><a href='#L378'>378</a>
444
+ <a name='L379'></a><a href='#L379'>379</a>
445
+ <a name='L380'></a><a href='#L380'>380</a>
446
+ <a name='L381'></a><a href='#L381'>381</a>
447
+ <a name='L382'></a><a href='#L382'>382</a>
448
+ <a name='L383'></a><a href='#L383'>383</a>
449
+ <a name='L384'></a><a href='#L384'>384</a>
450
+ <a name='L385'></a><a href='#L385'>385</a>
451
+ <a name='L386'></a><a href='#L386'>386</a>
452
+ <a name='L387'></a><a href='#L387'>387</a>
453
+ <a name='L388'></a><a href='#L388'>388</a>
454
+ <a name='L389'></a><a href='#L389'>389</a>
455
+ <a name='L390'></a><a href='#L390'>390</a>
456
+ <a name='L391'></a><a href='#L391'>391</a>
457
+ <a name='L392'></a><a href='#L392'>392</a>
458
+ <a name='L393'></a><a href='#L393'>393</a>
459
+ <a name='L394'></a><a href='#L394'>394</a>
460
+ <a name='L395'></a><a href='#L395'>395</a>
461
+ <a name='L396'></a><a href='#L396'>396</a>
462
+ <a name='L397'></a><a href='#L397'>397</a>
463
+ <a name='L398'></a><a href='#L398'>398</a>
464
+ <a name='L399'></a><a href='#L399'>399</a>
465
+ <a name='L400'></a><a href='#L400'>400</a>
466
+ <a name='L401'></a><a href='#L401'>401</a>
467
+ <a name='L402'></a><a href='#L402'>402</a>
468
+ <a name='L403'></a><a href='#L403'>403</a>
469
+ <a name='L404'></a><a href='#L404'>404</a>
470
+ <a name='L405'></a><a href='#L405'>405</a>
471
+ <a name='L406'></a><a href='#L406'>406</a>
472
+ <a name='L407'></a><a href='#L407'>407</a>
473
+ <a name='L408'></a><a href='#L408'>408</a>
474
+ <a name='L409'></a><a href='#L409'>409</a>
475
+ <a name='L410'></a><a href='#L410'>410</a>
476
+ <a name='L411'></a><a href='#L411'>411</a>
477
+ <a name='L412'></a><a href='#L412'>412</a>
478
+ <a name='L413'></a><a href='#L413'>413</a>
479
+ <a name='L414'></a><a href='#L414'>414</a>
480
+ <a name='L415'></a><a href='#L415'>415</a>
481
+ <a name='L416'></a><a href='#L416'>416</a>
482
+ <a name='L417'></a><a href='#L417'>417</a>
483
+ <a name='L418'></a><a href='#L418'>418</a>
484
+ <a name='L419'></a><a href='#L419'>419</a>
485
+ <a name='L420'></a><a href='#L420'>420</a>
486
+ <a name='L421'></a><a href='#L421'>421</a>
487
+ <a name='L422'></a><a href='#L422'>422</a>
488
+ <a name='L423'></a><a href='#L423'>423</a>
489
+ <a name='L424'></a><a href='#L424'>424</a>
490
+ <a name='L425'></a><a href='#L425'>425</a>
491
+ <a name='L426'></a><a href='#L426'>426</a>
492
+ <a name='L427'></a><a href='#L427'>427</a>
493
+ <a name='L428'></a><a href='#L428'>428</a>
494
+ <a name='L429'></a><a href='#L429'>429</a>
495
+ <a name='L430'></a><a href='#L430'>430</a>
496
+ <a name='L431'></a><a href='#L431'>431</a>
497
+ <a name='L432'></a><a href='#L432'>432</a>
498
+ <a name='L433'></a><a href='#L433'>433</a>
499
+ <a name='L434'></a><a href='#L434'>434</a>
500
+ <a name='L435'></a><a href='#L435'>435</a>
501
+ <a name='L436'></a><a href='#L436'>436</a>
502
+ <a name='L437'></a><a href='#L437'>437</a>
503
+ <a name='L438'></a><a href='#L438'>438</a>
504
+ <a name='L439'></a><a href='#L439'>439</a>
505
+ <a name='L440'></a><a href='#L440'>440</a>
506
+ <a name='L441'></a><a href='#L441'>441</a>
507
+ <a name='L442'></a><a href='#L442'>442</a>
508
+ <a name='L443'></a><a href='#L443'>443</a>
509
+ <a name='L444'></a><a href='#L444'>444</a>
510
+ <a name='L445'></a><a href='#L445'>445</a>
511
+ <a name='L446'></a><a href='#L446'>446</a>
512
+ <a name='L447'></a><a href='#L447'>447</a>
513
+ <a name='L448'></a><a href='#L448'>448</a>
514
+ <a name='L449'></a><a href='#L449'>449</a>
515
+ <a name='L450'></a><a href='#L450'>450</a>
516
+ <a name='L451'></a><a href='#L451'>451</a>
517
+ <a name='L452'></a><a href='#L452'>452</a>
518
+ <a name='L453'></a><a href='#L453'>453</a>
519
+ <a name='L454'></a><a href='#L454'>454</a>
520
+ <a name='L455'></a><a href='#L455'>455</a>
521
+ <a name='L456'></a><a href='#L456'>456</a></td><td class="line-coverage quiet"><span class="cline-any cline-yes">1x</span>
522
+ <span class="cline-any cline-yes">1x</span>
523
+ <span class="cline-any cline-yes">1x</span>
524
+ <span class="cline-any cline-yes">1x</span>
525
+ <span class="cline-any cline-yes">1x</span>
526
+ <span class="cline-any cline-yes">1x</span>
527
+ <span class="cline-any cline-yes">1x</span>
528
+ <span class="cline-any cline-yes">1x</span>
529
+ <span class="cline-any cline-yes">1x</span>
530
+ <span class="cline-any cline-yes">1x</span>
531
+ <span class="cline-any cline-yes">1x</span>
532
+ <span class="cline-any cline-yes">1x</span>
533
+ <span class="cline-any cline-yes">1x</span>
534
+ <span class="cline-any cline-yes">1x</span>
535
+ <span class="cline-any cline-yes">1x</span>
536
+ <span class="cline-any cline-yes">1x</span>
537
+ <span class="cline-any cline-yes">1x</span>
538
+ <span class="cline-any cline-yes">1x</span>
539
+ <span class="cline-any cline-yes">1x</span>
540
+ <span class="cline-any cline-yes">1x</span>
541
+ <span class="cline-any cline-yes">1x</span>
542
+ <span class="cline-any cline-yes">1x</span>
543
+ <span class="cline-any cline-yes">1x</span>
544
+ <span class="cline-any cline-yes">1x</span>
545
+ <span class="cline-any cline-yes">1x</span>
546
+ <span class="cline-any cline-yes">1x</span>
547
+ <span class="cline-any cline-yes">1x</span>
548
+ <span class="cline-any cline-yes">1x</span>
549
+ <span class="cline-any cline-yes">1x</span>
550
+ <span class="cline-any cline-yes">1x</span>
551
+ <span class="cline-any cline-yes">1x</span>
552
+ <span class="cline-any cline-yes">1x</span>
553
+ <span class="cline-any cline-yes">1x</span>
554
+ <span class="cline-any cline-yes">1x</span>
555
+ <span class="cline-any cline-yes">1x</span>
556
+ <span class="cline-any cline-yes">1x</span>
557
+ <span class="cline-any cline-yes">1x</span>
558
+ <span class="cline-any cline-yes">1x</span>
559
+ <span class="cline-any cline-yes">1x</span>
560
+ <span class="cline-any cline-yes">1x</span>
561
+ <span class="cline-any cline-yes">1x</span>
562
+ <span class="cline-any cline-yes">1x</span>
563
+ <span class="cline-any cline-yes">1x</span>
564
+ <span class="cline-any cline-yes">1x</span>
565
+ <span class="cline-any cline-yes">1x</span>
566
+ <span class="cline-any cline-yes">1x</span>
567
+ <span class="cline-any cline-yes">1x</span>
568
+ <span class="cline-any cline-yes">1x</span>
569
+ <span class="cline-any cline-yes">1x</span>
570
+ <span class="cline-any cline-yes">1x</span>
571
+ <span class="cline-any cline-yes">1x</span>
572
+ <span class="cline-any cline-yes">1x</span>
573
+ <span class="cline-any cline-yes">46x</span>
574
+ <span class="cline-any cline-yes">46x</span>
575
+ <span class="cline-any cline-yes">46x</span>
576
+ <span class="cline-any cline-yes">46x</span>
577
+ <span class="cline-any cline-yes">46x</span>
578
+ <span class="cline-any cline-yes">46x</span>
579
+ <span class="cline-any cline-yes">46x</span>
580
+ <span class="cline-any cline-yes">46x</span>
581
+ <span class="cline-any cline-yes">46x</span>
582
+ <span class="cline-any cline-yes">46x</span>
583
+ <span class="cline-any cline-yes">46x</span>
584
+ <span class="cline-any cline-yes">1x</span>
585
+ <span class="cline-any cline-yes">1x</span>
586
+ <span class="cline-any cline-yes">1x</span>
587
+ <span class="cline-any cline-yes">1x</span>
588
+ <span class="cline-any cline-yes">1x</span>
589
+ <span class="cline-any cline-yes">47x</span>
590
+ <span class="cline-any cline-yes">47x</span>
591
+ <span class="cline-any cline-yes">47x</span>
592
+ <span class="cline-any cline-yes">47x</span>
593
+ <span class="cline-any cline-yes">47x</span>
594
+ <span class="cline-any cline-yes">47x</span>
595
+ <span class="cline-any cline-yes">47x</span>
596
+ <span class="cline-any cline-yes">47x</span>
597
+ <span class="cline-any cline-yes">46x</span>
598
+ <span class="cline-any cline-yes">2x</span>
599
+ <span class="cline-any cline-yes">2x</span>
600
+ <span class="cline-any cline-yes">44x</span>
601
+ <span class="cline-any cline-yes">44x</span>
602
+ <span class="cline-any cline-yes">46x</span>
603
+ <span class="cline-any cline-yes">46x</span>
604
+ <span class="cline-any cline-yes">46x</span>
605
+ <span class="cline-any cline-yes">34x</span>
606
+ <span class="cline-any cline-no">&nbsp;</span>
607
+ <span class="cline-any cline-no">&nbsp;</span>
608
+ <span class="cline-any cline-yes">34x</span>
609
+ <span class="cline-any cline-yes">34x</span>
610
+ <span class="cline-any cline-yes">10x</span>
611
+ <span class="cline-any cline-yes">24x</span>
612
+ <span class="cline-any cline-yes">2x</span>
613
+ <span class="cline-any cline-yes">2x</span>
614
+ <span class="cline-any cline-yes">2x</span>
615
+ <span class="cline-any cline-yes">2x</span>
616
+ <span class="cline-any cline-yes">2x</span>
617
+ <span class="cline-any cline-yes">10x</span>
618
+ <span class="cline-any cline-yes">10x</span>
619
+ <span class="cline-any cline-yes">10x</span>
620
+ <span class="cline-any cline-yes">10x</span>
621
+ <span class="cline-any cline-yes">10x</span>
622
+ <span class="cline-any cline-yes">10x</span>
623
+ <span class="cline-any cline-yes">10x</span>
624
+ <span class="cline-any cline-yes">2x</span>
625
+ <span class="cline-any cline-yes">2x</span>
626
+ <span class="cline-any cline-yes">10x</span>
627
+ <span class="cline-any cline-yes">10x</span>
628
+ <span class="cline-any cline-yes">10x</span>
629
+ <span class="cline-any cline-yes">10x</span>
630
+ <span class="cline-any cline-yes">46x</span>
631
+ <span class="cline-any cline-yes">2x</span>
632
+ <span class="cline-any cline-yes">2x</span>
633
+ <span class="cline-any cline-yes">2x</span>
634
+ <span class="cline-any cline-no">&nbsp;</span>
635
+ <span class="cline-any cline-no">&nbsp;</span>
636
+ <span class="cline-any cline-yes">2x</span>
637
+ <span class="cline-any cline-yes">47x</span>
638
+ <span class="cline-any cline-yes">47x</span>
639
+ <span class="cline-any cline-yes">1x</span>
640
+ <span class="cline-any cline-yes">1x</span>
641
+ <span class="cline-any cline-yes">1x</span>
642
+ <span class="cline-any cline-yes">1x</span>
643
+ <span class="cline-any cline-yes">1x</span>
644
+ <span class="cline-any cline-yes">1x</span>
645
+ <span class="cline-any cline-yes">1x</span>
646
+ <span class="cline-any cline-yes">1x</span>
647
+ <span class="cline-any cline-yes">1x</span>
648
+ <span class="cline-any cline-yes">1x</span>
649
+ <span class="cline-any cline-yes">1x</span>
650
+ <span class="cline-any cline-yes">1x</span>
651
+ <span class="cline-any cline-yes">1x</span>
652
+ <span class="cline-any cline-yes">1x</span>
653
+ <span class="cline-any cline-yes">1x</span>
654
+ <span class="cline-any cline-yes">1x</span>
655
+ <span class="cline-any cline-yes">1x</span>
656
+ <span class="cline-any cline-yes">1x</span>
657
+ <span class="cline-any cline-yes">1x</span>
658
+ <span class="cline-any cline-yes">1x</span>
659
+ <span class="cline-any cline-yes">1x</span>
660
+ <span class="cline-any cline-yes">1x</span>
661
+ <span class="cline-any cline-yes">1x</span>
662
+ <span class="cline-any cline-yes">1x</span>
663
+ <span class="cline-any cline-yes">1x</span>
664
+ <span class="cline-any cline-yes">1x</span>
665
+ <span class="cline-any cline-yes">1x</span>
666
+ <span class="cline-any cline-yes">1x</span>
667
+ <span class="cline-any cline-yes">1x</span>
668
+ <span class="cline-any cline-yes">1x</span>
669
+ <span class="cline-any cline-yes">1x</span>
670
+ <span class="cline-any cline-yes">1x</span>
671
+ <span class="cline-any cline-yes">1x</span>
672
+ <span class="cline-any cline-yes">1x</span>
673
+ <span class="cline-any cline-yes">1x</span>
674
+ <span class="cline-any cline-yes">1x</span>
675
+ <span class="cline-any cline-yes">1x</span>
676
+ <span class="cline-any cline-yes">1x</span>
677
+ <span class="cline-any cline-yes">1x</span>
678
+ <span class="cline-any cline-yes">1x</span>
679
+ <span class="cline-any cline-yes">1x</span>
680
+ <span class="cline-any cline-yes">1x</span>
681
+ <span class="cline-any cline-yes">1x</span>
682
+ <span class="cline-any cline-yes">1x</span>
683
+ <span class="cline-any cline-yes">1x</span>
684
+ <span class="cline-any cline-yes">1x</span>
685
+ <span class="cline-any cline-yes">1x</span>
686
+ <span class="cline-any cline-yes">1x</span>
687
+ <span class="cline-any cline-yes">1x</span>
688
+ <span class="cline-any cline-yes">1x</span>
689
+ <span class="cline-any cline-yes">1x</span>
690
+ <span class="cline-any cline-yes">47x</span>
691
+ <span class="cline-any cline-yes">47x</span>
692
+ <span class="cline-any cline-yes">47x</span>
693
+ <span class="cline-any cline-yes">47x</span>
694
+ <span class="cline-any cline-yes">47x</span>
695
+ <span class="cline-any cline-yes">47x</span>
696
+ <span class="cline-any cline-yes">47x</span>
697
+ <span class="cline-any cline-yes">47x</span>
698
+ <span class="cline-any cline-yes">47x</span>
699
+ <span class="cline-any cline-yes">47x</span>
700
+ <span class="cline-any cline-yes">47x</span>
701
+ <span class="cline-any cline-yes">47x</span>
702
+ <span class="cline-any cline-yes">47x</span>
703
+ <span class="cline-any cline-yes">47x</span>
704
+ <span class="cline-any cline-yes">47x</span>
705
+ <span class="cline-any cline-yes">47x</span>
706
+ <span class="cline-any cline-yes">47x</span>
707
+ <span class="cline-any cline-yes">22x</span>
708
+ <span class="cline-any cline-yes">22x</span>
709
+ <span class="cline-any cline-yes">22x</span>
710
+ <span class="cline-any cline-yes">22x</span>
711
+ <span class="cline-any cline-yes">22x</span>
712
+ <span class="cline-any cline-yes">22x</span>
713
+ <span class="cline-any cline-yes">47x</span>
714
+ <span class="cline-any cline-yes">47x</span>
715
+ <span class="cline-any cline-yes">47x</span>
716
+ <span class="cline-any cline-yes">47x</span>
717
+ <span class="cline-any cline-yes">47x</span>
718
+ <span class="cline-any cline-yes">47x</span>
719
+ <span class="cline-any cline-yes">47x</span>
720
+ <span class="cline-any cline-yes">47x</span>
721
+ <span class="cline-any cline-yes">47x</span>
722
+ <span class="cline-any cline-yes">47x</span>
723
+ <span class="cline-any cline-yes">47x</span>
724
+ <span class="cline-any cline-yes">47x</span>
725
+ <span class="cline-any cline-yes">47x</span>
726
+ <span class="cline-any cline-yes">47x</span>
727
+ <span class="cline-any cline-yes">47x</span>
728
+ <span class="cline-any cline-yes">26x</span>
729
+ <span class="cline-any cline-yes">26x</span>
730
+ <span class="cline-any cline-no">&nbsp;</span>
731
+ <span class="cline-any cline-no">&nbsp;</span>
732
+ <span class="cline-any cline-no">&nbsp;</span>
733
+ <span class="cline-any cline-no">&nbsp;</span>
734
+ <span class="cline-any cline-no">&nbsp;</span>
735
+ <span class="cline-any cline-yes">26x</span>
736
+ <span class="cline-any cline-yes">26x</span>
737
+ <span class="cline-any cline-yes">26x</span>
738
+ <span class="cline-any cline-yes">3x</span>
739
+ <span class="cline-any cline-yes">3x</span>
740
+ <span class="cline-any cline-yes">3x</span>
741
+ <span class="cline-any cline-yes">23x</span>
742
+ <span class="cline-any cline-yes">23x</span>
743
+ <span class="cline-any cline-yes">23x</span>
744
+ <span class="cline-any cline-yes">23x</span>
745
+ <span class="cline-any cline-yes">26x</span>
746
+ <span class="cline-any cline-no">&nbsp;</span>
747
+ <span class="cline-any cline-no">&nbsp;</span>
748
+ <span class="cline-any cline-no">&nbsp;</span>
749
+ <span class="cline-any cline-yes">23x</span>
750
+ <span class="cline-any cline-yes">23x</span>
751
+ <span class="cline-any cline-yes">26x</span>
752
+ <span class="cline-any cline-no">&nbsp;</span>
753
+ <span class="cline-any cline-no">&nbsp;</span>
754
+ <span class="cline-any cline-no">&nbsp;</span>
755
+ <span class="cline-any cline-no">&nbsp;</span>
756
+ <span class="cline-any cline-no">&nbsp;</span>
757
+ <span class="cline-any cline-no">&nbsp;</span>
758
+ <span class="cline-any cline-no">&nbsp;</span>
759
+ <span class="cline-any cline-no">&nbsp;</span>
760
+ <span class="cline-any cline-no">&nbsp;</span>
761
+ <span class="cline-any cline-no">&nbsp;</span>
762
+ <span class="cline-any cline-no">&nbsp;</span>
763
+ <span class="cline-any cline-yes">23x</span>
764
+ <span class="cline-any cline-yes">23x</span>
765
+ <span class="cline-any cline-yes">23x</span>
766
+ <span class="cline-any cline-yes">23x</span>
767
+ <span class="cline-any cline-yes">23x</span>
768
+ <span class="cline-any cline-yes">23x</span>
769
+ <span class="cline-any cline-yes">23x</span>
770
+ <span class="cline-any cline-yes">23x</span>
771
+ <span class="cline-any cline-yes">23x</span>
772
+ <span class="cline-any cline-yes">23x</span>
773
+ <span class="cline-any cline-yes">26x</span>
774
+ <span class="cline-any cline-no">&nbsp;</span>
775
+ <span class="cline-any cline-no">&nbsp;</span>
776
+ <span class="cline-any cline-no">&nbsp;</span>
777
+ <span class="cline-any cline-no">&nbsp;</span>
778
+ <span class="cline-any cline-no">&nbsp;</span>
779
+ <span class="cline-any cline-no">&nbsp;</span>
780
+ <span class="cline-any cline-no">&nbsp;</span>
781
+ <span class="cline-any cline-no">&nbsp;</span>
782
+ <span class="cline-any cline-no">&nbsp;</span>
783
+ <span class="cline-any cline-no">&nbsp;</span>
784
+ <span class="cline-any cline-no">&nbsp;</span>
785
+ <span class="cline-any cline-no">&nbsp;</span>
786
+ <span class="cline-any cline-no">&nbsp;</span>
787
+ <span class="cline-any cline-no">&nbsp;</span>
788
+ <span class="cline-any cline-no">&nbsp;</span>
789
+ <span class="cline-any cline-no">&nbsp;</span>
790
+ <span class="cline-any cline-no">&nbsp;</span>
791
+ <span class="cline-any cline-no">&nbsp;</span>
792
+ <span class="cline-any cline-no">&nbsp;</span>
793
+ <span class="cline-any cline-no">&nbsp;</span>
794
+ <span class="cline-any cline-no">&nbsp;</span>
795
+ <span class="cline-any cline-no">&nbsp;</span>
796
+ <span class="cline-any cline-no">&nbsp;</span>
797
+ <span class="cline-any cline-no">&nbsp;</span>
798
+ <span class="cline-any cline-yes">23x</span>
799
+ <span class="cline-any cline-yes">23x</span>
800
+ <span class="cline-any cline-yes">23x</span>
801
+ <span class="cline-any cline-yes">23x</span>
802
+ <span class="cline-any cline-yes">23x</span>
803
+ <span class="cline-any cline-yes">23x</span>
804
+ <span class="cline-any cline-yes">23x</span>
805
+ <span class="cline-any cline-yes">23x</span>
806
+ <span class="cline-any cline-yes">23x</span>
807
+ <span class="cline-any cline-yes">23x</span>
808
+ <span class="cline-any cline-yes">23x</span>
809
+ <span class="cline-any cline-yes">23x</span>
810
+ <span class="cline-any cline-yes">23x</span>
811
+ <span class="cline-any cline-yes">23x</span>
812
+ <span class="cline-any cline-yes">20x</span>
813
+ <span class="cline-any cline-yes">20x</span>
814
+ <span class="cline-any cline-yes">20x</span>
815
+ <span class="cline-any cline-yes">20x</span>
816
+ <span class="cline-any cline-yes">20x</span>
817
+ <span class="cline-any cline-yes">40x</span>
818
+ <span class="cline-any cline-yes">40x</span>
819
+ <span class="cline-any cline-yes">40x</span>
820
+ <span class="cline-any cline-yes">40x</span>
821
+ <span class="cline-any cline-yes">40x</span>
822
+ <span class="cline-any cline-yes">20x</span>
823
+ <span class="cline-any cline-yes">20x</span>
824
+ <span class="cline-any cline-yes">23x</span>
825
+ <span class="cline-any cline-yes">1x</span>
826
+ <span class="cline-any cline-yes">1x</span>
827
+ <span class="cline-any cline-yes">1x</span>
828
+ <span class="cline-any cline-yes">1x</span>
829
+ <span class="cline-any cline-yes">1x</span>
830
+ <span class="cline-any cline-yes">20x</span>
831
+ <span class="cline-any cline-yes">20x</span>
832
+ <span class="cline-any cline-yes">23x</span>
833
+ <span class="cline-any cline-yes">3x</span>
834
+ <span class="cline-any cline-yes">3x</span>
835
+ <span class="cline-any cline-yes">3x</span>
836
+ <span class="cline-any cline-yes">3x</span>
837
+ <span class="cline-any cline-yes">3x</span>
838
+ <span class="cline-any cline-yes">3x</span>
839
+ <span class="cline-any cline-yes">3x</span>
840
+ <span class="cline-any cline-yes">6x</span>
841
+ <span class="cline-any cline-yes">6x</span>
842
+ <span class="cline-any cline-yes">6x</span>
843
+ <span class="cline-any cline-yes">6x</span>
844
+ <span class="cline-any cline-yes">6x</span>
845
+ <span class="cline-any cline-yes">6x</span>
846
+ <span class="cline-any cline-yes">6x</span>
847
+ <span class="cline-any cline-yes">3x</span>
848
+ <span class="cline-any cline-yes">3x</span>
849
+ <span class="cline-any cline-yes">3x</span>
850
+ <span class="cline-any cline-no">&nbsp;</span>
851
+ <span class="cline-any cline-no">&nbsp;</span>
852
+ <span class="cline-any cline-yes">3x</span>
853
+ <span class="cline-any cline-yes">3x</span>
854
+ <span class="cline-any cline-yes">3x</span>
855
+ <span class="cline-any cline-yes">23x</span>
856
+ <span class="cline-any cline-yes">23x</span>
857
+ <span class="cline-any cline-yes">23x</span>
858
+ <span class="cline-any cline-yes">23x</span>
859
+ <span class="cline-any cline-yes">23x</span>
860
+ <span class="cline-any cline-yes">23x</span>
861
+ <span class="cline-any cline-yes">23x</span>
862
+ <span class="cline-any cline-yes">23x</span>
863
+ <span class="cline-any cline-yes">23x</span>
864
+ <span class="cline-any cline-yes">23x</span>
865
+ <span class="cline-any cline-yes">23x</span>
866
+ <span class="cline-any cline-yes">23x</span>
867
+ <span class="cline-any cline-yes">23x</span>
868
+ <span class="cline-any cline-yes">23x</span>
869
+ <span class="cline-any cline-yes">23x</span>
870
+ <span class="cline-any cline-yes">23x</span>
871
+ <span class="cline-any cline-yes">23x</span>
872
+ <span class="cline-any cline-yes">23x</span>
873
+ <span class="cline-any cline-yes">26x</span>
874
+ <span class="cline-any cline-yes">47x</span>
875
+ <span class="cline-any cline-yes">47x</span>
876
+ <span class="cline-any cline-yes">47x</span>
877
+ <span class="cline-any cline-yes">26x</span>
878
+ <span class="cline-any cline-yes">26x</span>
879
+ <span class="cline-any cline-yes">26x</span>
880
+ <span class="cline-any cline-yes">26x</span>
881
+ <span class="cline-any cline-yes">26x</span>
882
+ <span class="cline-any cline-yes">26x</span>
883
+ <span class="cline-any cline-yes">47x</span>
884
+ <span class="cline-any cline-yes">47x</span>
885
+ <span class="cline-any cline-yes">47x</span>
886
+ <span class="cline-any cline-yes">47x</span>
887
+ <span class="cline-any cline-yes">46x</span>
888
+ <span class="cline-any cline-yes">11x</span>
889
+ <span class="cline-any cline-yes">11x</span>
890
+ <span class="cline-any cline-yes">11x</span>
891
+ <span class="cline-any cline-yes">11x</span>
892
+ <span class="cline-any cline-yes">11x</span>
893
+ <span class="cline-any cline-no">&nbsp;</span>
894
+ <span class="cline-any cline-no">&nbsp;</span>
895
+ <span class="cline-any cline-no">&nbsp;</span>
896
+ <span class="cline-any cline-no">&nbsp;</span>
897
+ <span class="cline-any cline-no">&nbsp;</span>
898
+ <span class="cline-any cline-no">&nbsp;</span>
899
+ <span class="cline-any cline-no">&nbsp;</span>
900
+ <span class="cline-any cline-no">&nbsp;</span>
901
+ <span class="cline-any cline-yes">11x</span>
902
+ <span class="cline-any cline-yes">11x</span>
903
+ <span class="cline-any cline-yes">11x</span>
904
+ <span class="cline-any cline-no">&nbsp;</span>
905
+ <span class="cline-any cline-no">&nbsp;</span>
906
+ <span class="cline-any cline-no">&nbsp;</span>
907
+ <span class="cline-any cline-yes">11x</span>
908
+ <span class="cline-any cline-yes">11x</span>
909
+ <span class="cline-any cline-yes">11x</span>
910
+ <span class="cline-any cline-yes">1x</span>
911
+ <span class="cline-any cline-yes">1x</span>
912
+ <span class="cline-any cline-yes">1x</span>
913
+ <span class="cline-any cline-yes">1x</span>
914
+ <span class="cline-any cline-yes">1x</span>
915
+ <span class="cline-any cline-yes">11x</span>
916
+ <span class="cline-any cline-yes">11x</span>
917
+ <span class="cline-any cline-yes">11x</span>
918
+ <span class="cline-any cline-yes">47x</span>
919
+ <span class="cline-any cline-yes">47x</span>
920
+ <span class="cline-any cline-yes">47x</span>
921
+ <span class="cline-any cline-yes">47x</span>
922
+ <span class="cline-any cline-yes">47x</span>
923
+ <span class="cline-any cline-yes">47x</span>
924
+ <span class="cline-any cline-yes">47x</span>
925
+ <span class="cline-any cline-yes">47x</span>
926
+ <span class="cline-any cline-yes">47x</span>
927
+ <span class="cline-any cline-yes">47x</span>
928
+ <span class="cline-any cline-yes">47x</span>
929
+ <span class="cline-any cline-yes">47x</span>
930
+ <span class="cline-any cline-yes">47x</span>
931
+ <span class="cline-any cline-yes">47x</span>
932
+ <span class="cline-any cline-yes">47x</span>
933
+ <span class="cline-any cline-yes">47x</span>
934
+ <span class="cline-any cline-yes">47x</span>
935
+ <span class="cline-any cline-no">&nbsp;</span>
936
+ <span class="cline-any cline-no">&nbsp;</span>
937
+ <span class="cline-any cline-no">&nbsp;</span>
938
+ <span class="cline-any cline-no">&nbsp;</span>
939
+ <span class="cline-any cline-no">&nbsp;</span>
940
+ <span class="cline-any cline-no">&nbsp;</span>
941
+ <span class="cline-any cline-no">&nbsp;</span>
942
+ <span class="cline-any cline-yes">47x</span>
943
+ <span class="cline-any cline-yes">47x</span>
944
+ <span class="cline-any cline-yes">47x</span>
945
+ <span class="cline-any cline-yes">47x</span>
946
+ <span class="cline-any cline-yes">22x</span>
947
+ <span class="cline-any cline-yes">22x</span>
948
+ <span class="cline-any cline-yes">22x</span>
949
+ <span class="cline-any cline-yes">22x</span>
950
+ <span class="cline-any cline-yes">22x</span>
951
+ <span class="cline-any cline-yes">22x</span>
952
+ <span class="cline-any cline-yes">22x</span>
953
+ <span class="cline-any cline-yes">22x</span>
954
+ <span class="cline-any cline-yes">25x</span>
955
+ <span class="cline-any cline-yes">25x</span>
956
+ <span class="cline-any cline-yes">25x</span>
957
+ <span class="cline-any cline-yes">1x</span>
958
+ <span class="cline-any cline-yes">1x</span>
959
+ <span class="cline-any cline-yes">1x</span>
960
+ <span class="cline-any cline-yes">1x</span>
961
+ <span class="cline-any cline-yes">1x</span>
962
+ <span class="cline-any cline-yes">1x</span>
963
+ <span class="cline-any cline-yes">1x</span>
964
+ <span class="cline-any cline-yes">1x</span>
965
+ <span class="cline-any cline-yes">1x</span>
966
+ <span class="cline-any cline-yes">1x</span>
967
+ <span class="cline-any cline-yes">1x</span>
968
+ <span class="cline-any cline-yes">1x</span>
969
+ <span class="cline-any cline-yes">1x</span>
970
+ <span class="cline-any cline-yes">35x</span>
971
+ <span class="cline-any cline-yes">35x</span>
972
+ <span class="cline-any cline-yes">2x</span>
973
+ <span class="cline-any cline-yes">2x</span>
974
+ <span class="cline-any cline-yes">33x</span>
975
+ <span class="cline-any cline-yes">33x</span>
976
+ <span class="cline-any cline-neutral">&nbsp;</span></td><td class="text"><pre class="prettyprint lang-js">import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from "react";
977
+ import { translationService } from "../services/translationService";
978
+ import { CRITICAL_TRANSLATIONS } from "../translations/critical";
979
+ import { resolveConfig } from "../utils/configResolver";
980
+ import { logger } from "../utils/logger";
981
+ &nbsp;
982
+ // Global flag to prevent duplicate fetch calls across multiple provider instances
983
+ let globalFetchPromise: Promise&lt;Record&lt;string, Record&lt;string, string&gt;&gt;&gt; | null = null;
984
+ let globalFetchInProgress = false;
985
+ &nbsp;
986
+ /** i18next instance interface for auto-syncing translations */
987
+ export interface I18nInstance {
988
+ addResourceBundle: (lang: string, ns: string, resources: Record&lt;string, string&gt;, deep?: boolean, overwrite?: boolean) =&gt; void;
989
+ language?: string;
990
+ changeLanguage?: (lang: string) =&gt; void;
991
+ }
992
+ &nbsp;
993
+ export interface TranslationsProviderProps {
994
+ children: React.ReactNode;
995
+ apiKey?: string;
996
+ crudifyEnv?: "dev" | "stg" | "api" | "prod";
997
+ featureKeys?: string[];
998
+ language?: string; // Current language (for i18next integration)
999
+ devTranslations?: Record&lt;string, string&gt;; // Props override (dev/testing)
1000
+ translationUrl?: string; // URL to fetch translation overrides
1001
+ enableDebug?: boolean;
1002
+ skipAutoInit?: boolean; // Skip automatic crudify initialization (app is responsible for init)
1003
+ autoSyncI18n?: boolean; // Auto-sync translations with i18next (default: true)
1004
+ i18nInstance?: I18nInstance; // i18next instance for auto-syncing translations
1005
+ loadingFallback?: React.ReactNode; // Optional loading component for initial load
1006
+ waitForInitialLoad?: boolean; // Wait for translations on first load (default: true)
1007
+ }
1008
+ &nbsp;
1009
+ export interface TranslationsContextValue {
1010
+ t: (key: string, variables?: Record&lt;string, string | number&gt;) =&gt; string;
1011
+ language: string;
1012
+ availableLanguages: string[];
1013
+ translations: Record&lt;string, Record&lt;string, string&gt;&gt;;
1014
+ isLoading: boolean;
1015
+ error: string | null;
1016
+ refreshTranslations: () =&gt; Promise&lt;void&gt;;
1017
+ }
1018
+ &nbsp;
1019
+ const TranslationsContext = createContext&lt;TranslationsContextValue | null&gt;(null);
1020
+ &nbsp;
1021
+ /**
1022
+ * Merge translations with prioritization
1023
+ * Priority (lowest to highest):
1024
+ * 1. Critical bundle (fallback)
1025
+ * 2. API translations (system + subscriber merged by backend, then merged with URL translations by service)
1026
+ * 3. Dev translations (props - only for development/testing)
1027
+ */
1028
+ function mergeTranslations(
1029
+ critical: Record&lt;string, string&gt;,
1030
+ api: Record&lt;string, string&gt;,
1031
+ dev?: Record&lt;string, string&gt;
1032
+ ): Record&lt;string, string&gt; {
1033
+ return {
1034
+ ...critical,
1035
+ ...api,
1036
+ ...(dev || {}),
1037
+ };
1038
+ }
1039
+ &nbsp;
1040
+ /**
1041
+ * Hook for auto-syncing translations with i18next
1042
+ * Automatically detects and syncs with i18next instance
1043
+ */
1044
+ function useI18nAutoSync(
1045
+ translations: Record&lt;string, Record&lt;string, string&gt;&gt;,
1046
+ language: string,
1047
+ i18nInstance: I18nInstance | undefined,
1048
+ enabled: boolean,
1049
+ enableDebug: boolean
1050
+ ) {
1051
+ useEffect(() =&gt; {
1052
+ if (!enabled || !translations || !language) {
1053
+ return;
1054
+ }
1055
+ &nbsp;
1056
+ // Try to detect i18next instance
1057
+ const i18n = i18nInstance || (typeof window !== "undefined" &amp;&amp; window.i18next) || (typeof window !== "undefined" &amp;&amp; window.i18n);
1058
+ &nbsp;
1059
+ if (!i18n || !i18n.addResourceBundle) {
1060
+ if (enableDebug) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1061
+ <span class="cstat-no" title="statement not covered" > logger.debug("[TranslationsProvider] i18next not found, skipping auto-sync");</span>
1062
+ <span class="cstat-no" title="statement not covered" > }</span>
1063
+ return;
1064
+ }
1065
+ &nbsp;
1066
+ if (enableDebug) {
1067
+ logger.debug("[TranslationsProvider] Auto-syncing translations with i18next", {
1068
+ languages: Object.keys(translations),
1069
+ currentLanguage: language,
1070
+ });
1071
+ }
1072
+ &nbsp;
1073
+ // Add translations to i18next for all available languages
1074
+ Object.keys(translations).forEach((lang) =&gt; {
1075
+ if (translations[lang] &amp;&amp; Object.keys(translations[lang]).length &gt; 0) {
1076
+ i18n.addResourceBundle(lang, "translation", translations[lang], true, true);
1077
+ &nbsp;
1078
+ if (enableDebug) {
1079
+ logger.debug(`[TranslationsProvider] Synced ${Object.keys(translations[lang]).length} keys for language: ${lang}`);
1080
+ }
1081
+ }
1082
+ });
1083
+ &nbsp;
1084
+ // Change language if necessary
1085
+ if (i18n.language !== language &amp;&amp; i18n.changeLanguage) {
1086
+ i18n.changeLanguage(language);
1087
+ &nbsp;
1088
+ if (enableDebug) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1089
+ <span class="cstat-no" title="statement not covered" > logger.debug(`[TranslationsProvider] Changed i18next language to: ${language}`);</span>
1090
+ <span class="cstat-no" title="statement not covered" > }</span>
1091
+ }
1092
+ }, [translations, language, i18nInstance, enabled, enableDebug]);
1093
+ }
1094
+ &nbsp;
1095
+ /**
1096
+ * TranslationsProvider
1097
+ *
1098
+ * Provides translation functionality to the application
1099
+ * Handles fetching, caching, and fallback strategies
1100
+ *
1101
+ * Note: The app MUST initialize crudify before mounting TranslationsProvider
1102
+ *
1103
+ * @example Basic usage
1104
+ * ```tsx
1105
+ * // App must initialize crudify first
1106
+ * await crudify.init(publicApiKey, 'debug')
1107
+ *
1108
+ * &lt;TranslationsProvider
1109
+ * apiKey="xxx"
1110
+ * language="es"
1111
+ * translationUrl="https://example.com/locales/es/translation.json"
1112
+ * skipAutoInit={true}
1113
+ * &gt;
1114
+ * &lt;App /&gt;
1115
+ * &lt;/TranslationsProvider&gt;
1116
+ * ```
1117
+ *
1118
+ * @example With custom loading fallback (recommended for better UX)
1119
+ * ```tsx
1120
+ * &lt;TranslationsProvider
1121
+ * apiKey="xxx"
1122
+ * crudifyEnv="prod"
1123
+ * language={i18n.language}
1124
+ * autoSyncI18n={true}
1125
+ * i18nInstance={i18n}
1126
+ * waitForInitialLoad={true} // Default - waits on first visit
1127
+ * loadingFallback={&lt;LoadingSpinner /&gt;} // Custom loading component
1128
+ * &gt;
1129
+ * &lt;App /&gt;
1130
+ * &lt;/TranslationsProvider&gt;
1131
+ * ```
1132
+ *
1133
+ * @example Disable waiting (legacy behavior - may show keys briefly)
1134
+ * ```tsx
1135
+ * &lt;TranslationsProvider
1136
+ * apiKey="xxx"
1137
+ * language="es"
1138
+ * waitForInitialLoad={false} // Don't wait - render immediately
1139
+ * &gt;
1140
+ * &lt;App /&gt;
1141
+ * &lt;/TranslationsProvider&gt;
1142
+ * ```
1143
+ */
1144
+ export const TranslationsProvider: React.FC&lt;TranslationsProviderProps&gt; = ({
1145
+ children,
1146
+ apiKey: propsApiKey,
1147
+ crudifyEnv: propsEnv = "prod",
1148
+ featureKeys: propsFeatureKeys,
1149
+ language = "es",
1150
+ devTranslations,
1151
+ translationUrl,
1152
+ enableDebug = false,
1153
+ skipAutoInit = true, // Default true - assumes app handles crudify.init()
1154
+ autoSyncI18n = true, // Default true - auto-sync with i18next
1155
+ i18nInstance,
1156
+ loadingFallback,
1157
+ waitForInitialLoad = true, // Default true - wait for first load to prevent showing keys
1158
+ }) =&gt; {
1159
+ // Resolve configuration using configResolver (cookies &gt; props)
1160
+ // This ensures TranslationsProvider uses the same config as CrudifyInitializer/SessionProvider
1161
+ const resolvedConfig = useMemo(() =&gt; {
1162
+ return resolveConfig({
1163
+ publicApiKey: propsApiKey,
1164
+ env: propsEnv,
1165
+ featureKeys: propsFeatureKeys,
1166
+ enableDebug,
1167
+ });
1168
+ }, [propsApiKey, propsEnv, propsFeatureKeys, enableDebug]);
1169
+ &nbsp;
1170
+ const apiKey = resolvedConfig.<span class="branch-0 cbranch-no" title="branch not covered" >publicApiKey || "";</span>
1171
+ const crudifyEnv = resolvedConfig.<span class="branch-0 cbranch-no" title="branch not covered" >env || <span class="branch-0 cbranch-no" title="branch not covered" >propsEnv || "</span>prod";</span>
1172
+ const featureKeys = resolvedConfig.featureKeys || propsFeatureKeys;
1173
+ &nbsp;
1174
+ const [translations, setTranslations] = useState&lt;Record&lt;string, Record&lt;string, string&gt;&gt;&gt;({});
1175
+ const [isLoading, setIsLoading] = useState(true);
1176
+ const [isInitialLoad, setIsInitialLoad] = useState(true); // Track if this is the first load
1177
+ const [error, setError] = useState&lt;string | null&gt;(null);
1178
+ const [urlTranslations, setUrlTranslations] = useState&lt;Record&lt;string, string&gt; | undefined&gt;(undefined);
1179
+ const [hasFailedPermanently, setHasFailedPermanently] = useState(false);
1180
+ &nbsp;
1181
+ // Load translations
1182
+ const loadTranslations = useCallback(async () =&gt; {
1183
+ // Skip if no apiKey available
1184
+ if (!apiKey) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1185
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) logger.debug("[TranslationsProvider] No apiKey - skipping translation fetch");</span>
1186
+ <span class="cstat-no" title="statement not covered" > setIsLoading(false);</span>
1187
+ <span class="cstat-no" title="statement not covered" > setIsInitialLoad(false);</span>
1188
+ <span class="cstat-no" title="statement not covered" > return;</span>
1189
+ <span class="cstat-no" title="statement not covered" > }</span>
1190
+ &nbsp;
1191
+ // Skip if already failed permanently
1192
+ if (hasFailedPermanently) {
1193
+ if (enableDebug) <span class="branch-0 cbranch-no" title="branch not covered" >logger.debug("[TranslationsProvider] Skipping reload - using fallback translations");</span>
1194
+ return;
1195
+ }
1196
+ &nbsp;
1197
+ // Check if we have valid cache before starting the load
1198
+ // This allows us to render immediately with cached data on subsequent visits
1199
+ const hasValidCache = translationService.hasValidCache(apiKey);
1200
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >hasValidCache &amp;&amp; isInitialLoad) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
1201
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) logger.debug("[TranslationsProvider] Valid cache found - not blocking initial render");</span>
1202
+ <span class="cstat-no" title="statement not covered" > setIsInitialLoad(false); // We have cache, so not truly initial</span>
1203
+ <span class="cstat-no" title="statement not covered" > }</span>
1204
+ &nbsp;
1205
+ // Global lock: Prevent duplicate fetches across multiple provider instances
1206
+ if (<span class="branch-0 cbranch-no" title="branch not covered" >globalFetchInProgress &amp;&amp; globalFetchPromise) <span class="branch-0 cbranch-no" title="branch not covered" >{</span></span>
1207
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) logger.debug("[TranslationsProvider] Fetch already in progress, waiting for existing promise");</span>
1208
+ <span class="cstat-no" title="statement not covered" > try {</span>
1209
+ <span class="cstat-no" title="statement not covered" > const result = await globalFetchPromise;</span>
1210
+ <span class="cstat-no" title="statement not covered" > setTranslations(result);</span>
1211
+ <span class="cstat-no" title="statement not covered" > setIsLoading(false);</span>
1212
+ <span class="cstat-no" title="statement not covered" > return;</span>
1213
+ <span class="cstat-no" title="statement not covered" > } catch (err) {</span>
1214
+ <span class="cstat-no" title="statement not covered" > // If global fetch failed, fall through to try again</span>
1215
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) logger.warn("[TranslationsProvider] Global fetch failed, retrying");</span>
1216
+ <span class="cstat-no" title="statement not covered" > }</span>
1217
+ <span class="cstat-no" title="statement not covered" > }</span>
1218
+ &nbsp;
1219
+ // Mark fetch as in progress
1220
+ globalFetchInProgress = true;
1221
+ &nbsp;
1222
+ setIsLoading(true);
1223
+ setError(null);
1224
+ &nbsp;
1225
+ // Fetch translations from URL if provided
1226
+ let fetchedUrlTranslations: Record&lt;string, string&gt; | undefined = undefined;
1227
+ &nbsp;
1228
+ if (translationUrl) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1229
+ <span class="cstat-no" title="statement not covered" > try {</span>
1230
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) {</span>
1231
+ <span class="cstat-no" title="statement not covered" > logger.debug(`[TranslationsProvider] Fetching translations from URL: ${translationUrl}`);</span>
1232
+ <span class="cstat-no" title="statement not covered" > }</span>
1233
+ <span class="cstat-no" title="statement not covered" ></span>
1234
+ <span class="cstat-no" title="statement not covered" > const response = await fetch(translationUrl);</span>
1235
+ <span class="cstat-no" title="statement not covered" > if (!response.ok) {</span>
1236
+ <span class="cstat-no" title="statement not covered" > throw new Error(`Failed to fetch translations: ${response.statusText}`);</span>
1237
+ <span class="cstat-no" title="statement not covered" > }</span>
1238
+ <span class="cstat-no" title="statement not covered" ></span>
1239
+ <span class="cstat-no" title="statement not covered" > fetchedUrlTranslations = await response.json();</span>
1240
+ <span class="cstat-no" title="statement not covered" > setUrlTranslations(fetchedUrlTranslations);</span>
1241
+ <span class="cstat-no" title="statement not covered" ></span>
1242
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) {</span>
1243
+ <span class="cstat-no" title="statement not covered" > logger.debug("[TranslationsProvider] URL translations loaded:", {</span>
1244
+ <span class="cstat-no" title="statement not covered" > keysCount: fetchedUrlTranslations ? Object.keys(fetchedUrlTranslations).length : 0,</span>
1245
+ <span class="cstat-no" title="statement not covered" > });</span>
1246
+ <span class="cstat-no" title="statement not covered" > }</span>
1247
+ <span class="cstat-no" title="statement not covered" > } catch (err: unknown) {</span>
1248
+ <span class="cstat-no" title="statement not covered" > logger.error("[TranslationsProvider] Failed to load URL translations", err instanceof Error ? err : { message: String(err) });</span>
1249
+ <span class="cstat-no" title="statement not covered" > fetchedUrlTranslations = undefined;</span>
1250
+ <span class="cstat-no" title="statement not covered" > setUrlTranslations(undefined);</span>
1251
+ <span class="cstat-no" title="statement not covered" > }</span>
1252
+ <span class="cstat-no" title="statement not covered" > }</span>
1253
+ &nbsp;
1254
+ // Wrap the main fetch in a global promise
1255
+ const fetchPromise = (async () =&gt; {
1256
+ try {
1257
+ // Set debug mode for translation service
1258
+ translationService.setDebug(enableDebug);
1259
+ &nbsp;
1260
+ // Fetch dynamic translations (system + subscriber + URL merged by service)
1261
+ const dynamicTranslations = await translationService.fetchTranslations({
1262
+ apiKey,
1263
+ crudifyEnv,
1264
+ featureKeys,
1265
+ urlTranslations: fetchedUrlTranslations,
1266
+ });
1267
+ &nbsp;
1268
+ // Merge with prioritization
1269
+ const merged: Record&lt;string, Record&lt;string, string&gt;&gt; = {};
1270
+ &nbsp;
1271
+ Object.keys(dynamicTranslations).forEach((lang) =&gt; {
1272
+ const critical = (CRITICAL_TRANSLATIONS[lang as keyof typeof CRITICAL_TRANSLATIONS<span class="branch-0 cbranch-no" title="branch not covered" >] as Record&lt;string, string&gt;) || {};</span>
1273
+ const fromAPI = dynamicTranslations[lang<span class="branch-0 cbranch-no" title="branch not covered" >] || {};</span>
1274
+ // Note: fromAPI already contains system + subscriber + URL merged
1275
+ &nbsp;
1276
+ merged[lang] = mergeTranslations(critical, fromAPI, devTranslations);
1277
+ });
1278
+ &nbsp;
1279
+ if (enableDebug) {
1280
+ logger.debug("[TranslationsProvider] Loaded translations:", {
1281
+ languages: Object.keys(merged),
1282
+ keysCount: Object.keys(merged[language<span class="branch-0 cbranch-no" title="branch not covered" >] || {})</span>.length,
1283
+ });
1284
+ }
1285
+ &nbsp;
1286
+ return merged;
1287
+ } catch (err: unknown) {
1288
+ logger.error("[TranslationsProvider] Failed to load", err instanceof Error ? <span class="branch-0 cbranch-no" title="branch not covered" >err : { message: String(err) })</span>;
1289
+ setError(err instanceof Error ? err.<span class="branch-0 cbranch-no" title="branch not covered" >message : String(err))</span>;
1290
+ setHasFailedPermanently(true); // Mark as failed permanently to prevent retries
1291
+ &nbsp;
1292
+ // Fallback: critical bundle + URL translations + dev overrides
1293
+ const fallback: Record&lt;string, Record&lt;string, string&gt;&gt; = {};
1294
+ Object.keys(CRITICAL_TRANSLATIONS).forEach((lang) =&gt; {
1295
+ const critical = CRITICAL_TRANSLATIONS[lang as keyof typeof CRITICAL_TRANSLATIONS] as Record&lt;string, string&gt;;
1296
+ &nbsp;
1297
+ // If we have URL translations, use them as fallback (they have priority over critical)
1298
+ // Use fetchedUrlTranslations if just loaded, otherwise use state urlTranslations
1299
+ const urlFallback = fetchedUrlTranslations || urlTranslations || {};
1300
+ &nbsp;
1301
+ fallback[lang] = mergeTranslations(critical, urlFallback, devTranslations);
1302
+ });
1303
+ &nbsp;
1304
+ if (enableDebug) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1305
+ <span class="cstat-no" title="statement not covered" > logger.debug("[TranslationsProvider] Using fallback translations (critical + URL)");</span>
1306
+ <span class="cstat-no" title="statement not covered" > }</span>
1307
+ &nbsp;
1308
+ return fallback;
1309
+ }
1310
+ })();
1311
+ &nbsp;
1312
+ // Store as global promise
1313
+ globalFetchPromise = fetchPromise;
1314
+ &nbsp;
1315
+ try {
1316
+ const result = await fetchPromise;
1317
+ setTranslations(result);
1318
+ } finally {
1319
+ setIsLoading(false);
1320
+ setIsInitialLoad(false); // Mark that initial load is complete
1321
+ // Clear global flag after fetch completes
1322
+ globalFetchInProgress = false;
1323
+ // Clear promise after a delay to allow other instances to catch it
1324
+ setTimeout(() =&gt; {
1325
+ globalFetchPromise = null;
1326
+ }, 1000);
1327
+ }
1328
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1329
+ }, [apiKey, crudifyEnv, featureKeys, translationUrl, devTranslations, enableDebug, language, hasFailedPermanently]);
1330
+ &nbsp;
1331
+ useEffect(() =&gt; {
1332
+ loadTranslations();
1333
+ &nbsp;
1334
+ // Auto-refresh every hour
1335
+ const interval = setInterval(loadTranslations, 60 * 60 * 1000);
1336
+ &nbsp;
1337
+ return () =&gt; clearInterval(interval);
1338
+ }, [loadTranslations]);
1339
+ &nbsp;
1340
+ // Translation function with variable interpolation
1341
+ const t = useMemo(() =&gt; {
1342
+ return (key: string, variables?: Record&lt;string, string | number&gt;) =&gt; {
1343
+ const currentLang = translations[language<span class="branch-0 cbranch-no" title="branch not covered" >] || {};</span>
1344
+ let value = currentLang[key];
1345
+ &nbsp;
1346
+ // Fallback: search in other languages
1347
+ if (!value) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1348
+ <span class="cstat-no" title="statement not covered" > const allLangs = Object.keys(translations);</span>
1349
+ <span class="cstat-no" title="statement not covered" > for (const lang of allLangs) {</span>
1350
+ <span class="cstat-no" title="statement not covered" > if (translations[lang][key]) {</span>
1351
+ <span class="cstat-no" title="statement not covered" > value = translations[lang][key];</span>
1352
+ <span class="cstat-no" title="statement not covered" > break;</span>
1353
+ <span class="cstat-no" title="statement not covered" > }</span>
1354
+ <span class="cstat-no" title="statement not covered" > }</span>
1355
+ <span class="cstat-no" title="statement not covered" > }</span>
1356
+ &nbsp;
1357
+ // If not found, return key
1358
+ if (!value) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1359
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) logger.warn(`[TranslationsProvider] Missing translation: "${key}"`);</span>
1360
+ <span class="cstat-no" title="statement not covered" > value = key;</span>
1361
+ <span class="cstat-no" title="statement not covered" > }</span>
1362
+ &nbsp;
1363
+ // Replace variables
1364
+ if (variables &amp;&amp; typeof value === "string") {
1365
+ Object.entries(variables).forEach(([varKey, varValue]) =&gt; {
1366
+ const regex = new RegExp(`{{${varKey}}}`, "g");
1367
+ value = (value as string).replace(regex, String(varValue));
1368
+ });
1369
+ }
1370
+ &nbsp;
1371
+ return value as string;
1372
+ };
1373
+ }, [translations, language, enableDebug]);
1374
+ &nbsp;
1375
+ // Auto-sync translations with i18next
1376
+ useI18nAutoSync(translations, language, i18nInstance, autoSyncI18n, enableDebug);
1377
+ &nbsp;
1378
+ const contextValue: TranslationsContextValue = {
1379
+ t,
1380
+ language,
1381
+ availableLanguages: Object.keys(translations),
1382
+ translations,
1383
+ isLoading,
1384
+ error,
1385
+ refreshTranslations: loadTranslations,
1386
+ };
1387
+ &nbsp;
1388
+ // Early validation: If no apiKey available, skip translations but render children
1389
+ if (!apiKey) <span class="branch-0 cbranch-no" title="branch not covered" >{</span>
1390
+ <span class="cstat-no" title="statement not covered" > if (enableDebug) {</span>
1391
+ <span class="cstat-no" title="statement not covered" > logger.warn(</span>
1392
+ <span class="cstat-no" title="statement not covered" > "[TranslationsProvider] No API key available. Skipping translations. Provide apiKey via props or ensure cookies are set by Lambda."</span>
1393
+ <span class="cstat-no" title="statement not covered" > );</span>
1394
+ <span class="cstat-no" title="statement not covered" > }</span>
1395
+ <span class="cstat-no" title="statement not covered" > return &lt;&gt;{children}&lt;/&gt;;</span>
1396
+ <span class="cstat-no" title="statement not covered" > }</span>
1397
+ &nbsp;
1398
+ // Block rendering on initial load to prevent showing translation keys
1399
+ // On subsequent loads (cache available), render immediately and update in background
1400
+ if (waitForInitialLoad &amp;&amp; isInitialLoad &amp;&amp; isLoading) {
1401
+ return (
1402
+ loadingFallback || (
1403
+ &lt;div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }}&gt;
1404
+ &lt;div&gt;Loading translations...&lt;/div&gt;
1405
+ &lt;/div&gt;
1406
+ )
1407
+ );
1408
+ }
1409
+ &nbsp;
1410
+ return &lt;TranslationsContext.Provider value={contextValue}&gt;{children}&lt;/TranslationsContext.Provider&gt;;
1411
+ };
1412
+ &nbsp;
1413
+ /**
1414
+ * Hook to use translations
1415
+ *
1416
+ * @example
1417
+ * ```tsx
1418
+ * const MyComponent = () =&gt; {
1419
+ * const { t } = useTranslations();
1420
+ * return &lt;h1&gt;{t('welcome.title')}&lt;/h1&gt;;
1421
+ * };
1422
+ * ```
1423
+ */
1424
+ export const useTranslations = (): TranslationsContextValue =&gt; {
1425
+ const context = useContext(TranslationsContext);
1426
+ if (!context) {
1427
+ throw new Error("useTranslations must be used within TranslationsProvider");
1428
+ }
1429
+ return context;
1430
+ };
1431
+ &nbsp;</pre></td></tr></table></pre>
1432
+
1433
+ <div class='push'></div><!-- for sticky footer -->
1434
+ </div><!-- /wrapper -->
1435
+ <div class='footer quiet pad2 space-top1 center small'>
1436
+ Code coverage generated by
1437
+ <a href="https://istanbul.js.org/" target="_blank" rel="noopener noreferrer">istanbul</a>
1438
+ at 2026-01-28T06:22:15.683Z
1439
+ </div>
1440
+ <script src="../prettify.js"></script>
1441
+ <script>
1442
+ window.onload = function () {
1443
+ prettyPrint();
1444
+ };
1445
+ </script>
1446
+ <script src="../sorter.js"></script>
1447
+ <script src="../block-navigation.js"></script>
1448
+ </body>
1449
+ </html>
1450
+