@@ -17,19 +17,29 @@ let currentConsumedTimeMs = 0;
1717let clickCount = 0 ;
1818let spamResetTimer : number | null = null ;
1919
20+ function setText ( id : string , value : string ) {
21+ const el = document . getElementById ( id ) ;
22+ if ( el ) el . textContent = value ;
23+ }
24+
2025function updateUITexts ( ) {
2126 const t = i18n . t ;
22- ( document . getElementById ( 'app-title' ) as HTMLElement ) . textContent = t . popup . title ;
23- ( document . getElementById ( 'lbl-max-videos' ) as HTMLElement ) . textContent = t . popup . maxVideos ;
24- ( document . getElementById ( 'lbl-time-limit' ) as HTMLElement ) . textContent = t . popup . timeLimit ;
2527
26- const lblUsageVideos = document . getElementById ( 'lbl-usage-videos' ) ;
27- if ( lblUsageVideos ) lblUsageVideos . textContent = t . popup . videosUnit ;
28- const lblUsageTime = document . getElementById ( 'lbl-usage-time' ) ;
29- if ( lblUsageTime ) lblUsageTime . textContent = t . popup . timeTitle ;
28+ const map : Record < string , string > = {
29+ 'app-title' : t . popup . title ,
30+ 'lbl-max-videos' : t . popup . maxVideos ,
31+ 'lbl-time-limit' : t . popup . timeLimit ,
32+ 'lbl-usage-videos' : t . popup . videosUnit ,
33+ 'lbl-usage-time' : t . popup . timeTitle ,
34+ 'site-badge' : t . popup . checking ,
35+ } ;
36+
37+ Object . entries ( map ) . forEach ( ( [ id , value ] ) => setText ( id , value ) ) ;
3038
3139 btnSave . textContent = t . popup . saveBtn ;
40+
3241 document . body . dir = i18n . language === 'ar' ? 'rtl' : 'ltr' ;
42+
3343 updateProgressBar ( ) ;
3444}
3545
@@ -40,6 +50,7 @@ function updateProgressBar() {
4050 const timeLimit = Number ( timeInput . value ) || 0 ;
4151 const timeSpentMins = Math . floor ( currentConsumedTimeMs / ( 60 * 1000 ) ) ;
4252 const t = i18n . t ;
53+
4354 const containerVideos = document . getElementById ( 'track-container-videos' ) as HTMLElement ;
4455 const containerTime = document . getElementById ( 'track-container-time' ) as HTMLElement ;
4556 const usageSection = document . getElementById ( 'usage-section' ) as HTMLElement ;
@@ -57,8 +68,7 @@ function updateProgressBar() {
5768 let pCount = limit > 0 ? ( currentConsumedCount / limit ) * 100 : 0 ;
5869 if ( pCount > 100 ) pCount = 100 ;
5970
60- ( document . getElementById ( 'stats-videos' ) as HTMLElement ) . textContent =
61- `${ currentConsumedCount } / ${ limit } ${ t . popup . videosUnit } ` ;
71+ setText ( 'stats-videos' , `${ currentConsumedCount } / ${ limit } ${ t . popup . videosUnit } ` ) ;
6272
6373 const fillV = document . getElementById ( 'fill-videos' ) as HTMLElement ;
6474 fillV . setAttribute ( 'style' , `--progress: ${ pCount } %` ) ;
@@ -73,8 +83,7 @@ function updateProgressBar() {
7383 let pTime = timeLimit > 0 ? ( timeSpentMins / timeLimit ) * 100 : 0 ;
7484 if ( pTime > 100 ) pTime = 100 ;
7585
76- ( document . getElementById ( 'stats-time' ) as HTMLElement ) . textContent =
77- `${ timeSpentMins } / ${ timeLimit } ${ t . popup . minsUnit } ` ;
86+ setText ( 'stats-time' , `${ timeSpentMins } / ${ timeLimit } ${ t . popup . minsUnit } ` ) ;
7887
7988 const fillT = document . getElementById ( 'fill-time' ) as HTMLElement ;
8089 fillT . setAttribute ( 'style' , `--progress: ${ pTime } %` ) ;
@@ -118,19 +127,20 @@ async function init() {
118127 chrome . tabs . query ( { active : true , currentWindow : true } , ( tabs ) => {
119128 const currentTab = tabs [ 0 ] ;
120129 const currentUrl = currentTab ?. url || '' ;
130+ const t = i18n . t ;
121131
122132 if ( currentUrl . includes ( 'youtube.com' ) && currentUrl . includes ( '/shorts/' ) ) {
123133 chrome . tabs . sendMessage ( currentTab . id ! , { action : AppAction . PING } , ( response ) => {
124134 if ( chrome . runtime . lastError || ! response || response . status !== 'ALIVE' ) {
125- siteBadge . textContent = '○ Refresh Page' ;
135+ siteBadge . textContent = t . popup . refreshPage ;
126136 setBadgeState ( siteBadge , 'warning' ) ;
127137 } else {
128- siteBadge . textContent = '● YouTube Shorts' ;
138+ siteBadge . textContent = t . popup . youtubeShorts ;
129139 setBadgeState ( siteBadge , 'success' ) ;
130140 }
131141 } ) ;
132142 } else {
133- siteBadge . textContent = '○ Unsupported Site' ;
143+ siteBadge . textContent = t . popup . unsupportedSite ;
134144 setBadgeState ( siteBadge , 'muted' ) ;
135145 }
136146 } ) ;
@@ -161,9 +171,7 @@ function updateActionIcon(isSystemDark: boolean) {
161171 : '../../assets/manifest/32x32-light.png' ;
162172
163173 if ( chrome . action ) {
164- void chrome . action
165- . setIcon ( { path : iconPath } )
166- . catch ( ( err ) => console . error ( '[Limitra] Background Icon Error:' , err ) ) ;
174+ void chrome . action . setIcon ( { path : iconPath } ) . catch ( console . error ) ;
167175 }
168176}
169177
@@ -176,19 +184,20 @@ systemThemeQuery.addEventListener('change', (event) => {
176184
177185btnSave . onclick = async ( ) => {
178186 clickCount ++ ;
187+
179188 if ( spamResetTimer ) clearTimeout ( spamResetTimer ) ;
180- spamResetTimer = window . setTimeout ( ( ) => {
181- clickCount = 0 ;
182- } , 2000 ) ;
189+ spamResetTimer = window . setTimeout ( ( ) => ( clickCount = 0 ) , 2000 ) ;
183190
184191 if ( clickCount >= 10 ) {
185192 btnSave . textContent = i18n . t . popup . stopSpamming ;
186193 btnSave . disabled = true ;
194+
187195 setTimeout ( ( ) => {
188196 btnSave . textContent = i18n . t . popup . saveBtn ;
189197 btnSave . disabled = false ;
190198 clickCount = 0 ;
191199 } , 3000 ) ;
200+
192201 return ;
193202 }
194203
@@ -203,6 +212,7 @@ btnSave.onclick = async () => {
203212 updateProgressBar ( ) ;
204213
205214 btnSave . textContent = i18n . t . popup . savedMsg ;
215+
206216 setTimeout ( ( ) => {
207217 if ( ! btnSave . disabled ) btnSave . textContent = i18n . t . popup . saveBtn ;
208218 } , 1500 ) ;
@@ -215,25 +225,35 @@ btnSettings.onclick = () => {
215225themeToggleBtn . onclick = async ( ) => {
216226 const current = await storage . getTheme ( ) ;
217227 const isSystemDark = window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches ;
228+
218229 const next =
219230 current === 'auto' ? ( isSystemDark ? 'light' : 'dark' ) : current === 'dark' ? 'light' : 'dark' ;
231+
220232 await storage . setTheme ( next ) ;
221233 applyTheme ( next ) ;
222234} ;
223235
224236chrome . storage . onChanged . addListener ( ( changes ) => {
225237 let needsUpdate = false ;
238+
226239 if ( changes [ 'limitra_count' ] ) {
227240 currentConsumedCount = Number ( changes [ 'limitra_count' ] . newValue ) || 0 ;
228241 needsUpdate = true ;
229242 }
243+
230244 if ( changes [ 'limitra_time_spent' ] ) {
231245 currentConsumedTimeMs = Number ( changes [ 'limitra_time_spent' ] . newValue ) || 0 ;
232246 needsUpdate = true ;
233247 }
248+
234249 if ( changes [ 'limitra_theme' ] ) {
235250 applyTheme ( changes [ 'limitra_theme' ] . newValue as string ) ;
236251 }
252+
253+ if ( changes [ 'limitra_language' ] ) {
254+ updateUITexts ( ) ;
255+ }
256+
237257 if ( needsUpdate ) updateProgressBar ( ) ;
238258} ) ;
239259
0 commit comments