66 type StatusEntry ,
77} from '@lunariajs/core'
88import { BaseStyles , CustomStyles } from './styles.ts'
9+ import type { I18nStatus } from '../shared/types/i18n-status.ts'
910
1011export function html (
1112 strings : TemplateStringsArray ,
@@ -33,8 +34,8 @@ function collapsePath(path: string) {
3334
3435export const Page = (
3536 config : LunariaConfig ,
36- status : LunariaStatus ,
37- lunaria : LunariaInstance ,
37+ status : I18nStatus ,
38+ _lunaria : LunariaInstance , // currenly not in use
3839) : string => {
3940 return html `
4041 <!doctype html>
@@ -43,7 +44,7 @@ export const Page = (
4344 ${ Meta } ${ BaseStyles } ${ CustomStyles }
4445 </ head >
4546 < body >
46- ${ Body ( config , status , lunaria ) }
47+ ${ Body ( config , status ) }
4748 </ body >
4849 </ html >
4950 `
@@ -73,144 +74,135 @@ export const Meta = html`
7374 < link rel ="icon " href ="https://npmx.dev/favicon.svg " type ="image/svg+xml " />
7475`
7576
76- export const Body = (
77- config : LunariaConfig ,
78- status : LunariaStatus ,
79- lunaria : LunariaInstance ,
80- ) : string => {
77+ export const Body = ( config : LunariaConfig , status : I18nStatus ) : string => {
8178 return html `
8279 < main >
8380 < div class ="limit-to-viewport ">
8481 < h1 > npmx Translation Status</ h1 >
85- ${ TitleParagraph } ${ StatusByLocale ( config , status , lunaria ) }
82+ ${ TitleParagraph } ${ StatusByLocale ( config , status ) }
8683 </ div >
87- ${ StatusByFile ( config , status , lunaria ) }
8884 </ main >
8985 `
9086}
9187
92- export const StatusByLocale = (
93- config : LunariaConfig ,
94- status : LunariaStatus ,
95- lunaria : LunariaInstance ,
96- ) : string => {
88+ export const StatusByLocale = ( config : LunariaConfig , status : I18nStatus ) : string => {
9789 const { locales } = config
9890 return html `
9991 < h2 id ="by-locale ">
10092 < a href ="#by-locale "> Translation progress by locale</ a >
10193 </ h2 >
102- ${ locales . map ( locale => LocaleDetails ( status , locale , lunaria ) ) }
94+ ${ locales . map ( locale => LocaleDetails ( status , locale ) ) }
10395 `
10496}
10597
106- export const LocaleDetails = (
107- status : LunariaStatus ,
108- locale : Locale ,
109- lunaria : LunariaInstance ,
110- ) : string => {
98+ export const LocaleDetails = ( status : I18nStatus , locale : Locale ) : string => {
11199 const { label, lang } = locale
100+ const localeStatus = status . locales . find ( s => s . lang === lang )
112101
113- const missingFiles = status . filter (
114- file =>
115- file . localizations . find ( localization => localization . lang === lang ) ?. status === 'missing' ,
116- )
117- const outdatedFiles = status . filter ( file => {
118- const localization = file . localizations . find ( localization => localization . lang === lang )
119-
120- if ( ! localization || localization . status === 'missing' ) return false
121- if ( file . type === 'dictionary' )
122- return 'missingKeys' in localization ? localization . missingKeys . length > 0 : false
123-
124- return (
125- localization . status === 'outdated' ||
126- ( 'missingKeys' in localization && localization . missingKeys . length > 0 )
127- )
128- } )
129-
130- const doneLength = status . length - outdatedFiles . length - missingFiles . length
102+ if ( ! localeStatus ) {
103+ return ''
104+ }
131105
132- const links = lunaria . gitHostingLinks ( )
106+ const {
107+ missingKeys,
108+ percentComplete,
109+ totalKeys,
110+ completedKeys,
111+ githubEditUrl,
112+ githubHistoryUrl,
113+ } = localeStatus
133114
134115 return html `
135116 < details class ="progress-details ">
136117 < summary >
137- < strong > ${ label } (${ lang } )</ strong >
138- < br />
139- < span class ="progress-summary ">
140- ${ doneLength . toString ( ) } done, ${ outdatedFiles . length . toString ( ) } outdated,
141- ${ missingFiles . length . toString ( ) } missing
142- </ span >
143- < br />
144- ${ ProgressBar ( status . length , outdatedFiles . length , missingFiles . length ) }
118+ < strong > ${ label } < span class ="lang-code "> ${ lang } </ span > </ strong >
119+ < hr />
120+ < div class ="progress-summary ">
121+ < span >
122+ ${ missingKeys . length ? `${ missingKeys . length . toString ( ) } missing keys` : '✔' }
123+ </ span >
124+ < span > ${ completedKeys } / ${ totalKeys } </ span >
125+ </ div >
126+ ${ ProgressBar ( percentComplete ) }
145127 </ summary >
146- ${ outdatedFiles . length > 0 ? OutdatedFiles ( outdatedFiles , lang , lunaria ) : '' }
128+ < br />
129+ ${ ContentDetailsLinks ( { text : `i18n/locales/${ lang } .json` , url : githubEditUrl } , githubHistoryUrl ) }
130+ < br />
131+ < br />
147132 ${
148- missingFiles . length > 0
149- ? html `< h3 class ="capitalize "> Missing</ h3 >
150- < ul >
151- ${ missingFiles . map ( file => {
152- const localization = file . localizations . find (
153- localization => localization . lang === lang ,
154- ) !
155- return html `
156- < li >
157- ${ Link ( links . source ( file . source . path ) , collapsePath ( file . source . path ) ) }
158- ${ CreateFileLink ( links . create ( localization . path ) , 'Create file' ) }
159- </ li >
160- `
161- } ) }
162- </ ul > `
163- : ''
164- }
165- ${
166- missingFiles . length == 0 && outdatedFiles . length == 0
167- ? html `
133+ missingKeys . length > 0
134+ ? html `${ MissingKeysList ( missingKeys ) } `
135+ : html `
168136 < p > This translation is complete, amazing job! 🎉</ p >
169137 `
170- : ''
171138 }
172139 </ details >
173140 `
174141}
175142
176- export const OutdatedFiles = (
177- outdatedFiles : LunariaStatus ,
178- lang : string ,
179- lunaria : LunariaInstance ,
143+ export const MissingKeysList = ( missingKeys : string [ ] ) : string => {
144+ return html `< details >
145+ < summary > Show missing keys</ summary >
146+ < ul >
147+ ${ missingKeys . map ( key => html `< li > ${ key } </ li > ` ) }
148+ </ ul >
149+ </ details > `
150+ }
151+
152+ export const ContentDetailsLinks = (
153+ githubEditLink : { text : string ; url : string } ,
154+ githubHistoryUrl : string ,
180155) : string => {
181156 return html `
182- < h3 class ="capitalize "> Outdated</ h3 >
183- < ul >
184- ${ outdatedFiles . map ( file => {
185- const localization = file . localizations . find ( localization => localization . lang === lang ) !
186-
187- const isMissingKeys =
188- localization . status !== 'missing' &&
189- 'missingKeys' in localization &&
190- localization . missingKeys . length > 0
191-
192- return html `
193- < li >
194- ${
195- isMissingKeys
196- ? html `
197- < details >
198- < summary > ${ ContentDetailsLinks ( file , lang , lunaria ) } </ summary >
199- < h4 > Missing keys</ h4 >
200- < ul >
201- ${ localization . missingKeys . map ( key => html `< li > ${ ( key as unknown as string [ ] ) . join ( '.' ) } </ li > ` ) }
202- </ ul >
203- </ details >
204- `
205- : html ` ${ ContentDetailsLinks ( file , lang , lunaria ) } `
206- }
207- </ li >
208- `
209- } ) }
210- </ ul >
157+ ${ Link ( githubEditLink . url , githubEditLink . text ) } |
158+ ${ Link ( githubHistoryUrl , 'source change history' ) }
159+ `
160+ }
161+
162+ export const ProgressBar = ( percentComplete : number ) : string => {
163+ let barClass = 'completed'
164+
165+ if ( percentComplete > 99 ) {
166+ barClass = 'completed' // dark-green
167+ } else if ( percentComplete > 90 ) {
168+ barClass = 'very-good' // green
169+ } else if ( percentComplete > 75 ) {
170+ barClass = 'good' // orange
171+ } else if ( percentComplete > 50 ) {
172+ barClass = 'help-needed' // red
173+ } else {
174+ barClass = 'basic' // dark-red
175+ }
176+
177+ return html `
178+ < div class ="progress-bar-wrapper " aria-hidden ="true ">
179+ < div class ="progress-bar ${ barClass } " style ="width:${ percentComplete } %; "> </ div >
180+ </ div >
211181 `
212182}
213183
184+ export const Link = ( href : string , text : string ) : string => {
185+ return html `< a href ="${ href } " target ="_blank "> ${ text } </ a > `
186+ }
187+
188+ export const TitleParagraph = html `
189+ < p >
190+ If you're interested in helping us translate
191+ < a href ="https://npmx.dev/ "> npmx.dev</ a > into one of the languages listed below, you've come to
192+ the right place! This auto-updating page always lists all the content that could use your help
193+ right now.
194+ </ p >
195+ < p >
196+ Before starting, please read our
197+ < a href ="https://github.com/npmx-dev/npmx.dev/blob/main/CONTRIBUTING.md#localization-i18n "
198+ > localization (i18n) guide</ a
199+ >
200+ to learn about our translation process and how you can get involved.
201+ </ p >
202+ `
203+
204+ // Components from here are not used at the moment
205+ // Do not delete as we might use it if we split translations in multiple files for locale
214206export const StatusByFile = (
215207 config : LunariaConfig ,
216208 status : LunariaStatus ,
@@ -265,7 +257,7 @@ export const TableContentStatus = (
265257 lunaria : LunariaInstance ,
266258 fileType ?: string ,
267259) : string => {
268- const localization = localizations . find ( localization => localization . lang === lang ) !
260+ const localization = localizations . find ( l => l . lang === lang ) !
269261 const isMissingKeys = 'missingKeys' in localization && localization . missingKeys . length > 0
270262 // For dictionary files, status is determined solely by key completion:
271263 // if there are missing keys it's "outdated", if all keys are present it's "up-to-date",
@@ -287,37 +279,6 @@ export const TableContentStatus = (
287279 return html `< td > ${ EmojiFileLink ( link , status ) } </ td > `
288280}
289281
290- export const ContentDetailsLinks = (
291- fileStatus : StatusEntry ,
292- lang : string ,
293- lunaria : LunariaInstance ,
294- ) : string => {
295- const localization = fileStatus . localizations . find ( localization => localization . lang === lang ) !
296- const isMissingKeys =
297- localization . status !== 'missing' &&
298- 'missingKeys' in localization &&
299- localization . missingKeys . length > 0
300-
301- const links = lunaria . gitHostingLinks ( )
302-
303- return html `
304- ${ Link ( links . source ( fileStatus . source . path ) , collapsePath ( fileStatus . source . path ) ) }
305- (${ Link (
306- links . source ( localization . path ) ,
307- isMissingKeys ? 'incomplete translation' : 'outdated translation' ,
308- ) } ,
309- ${ Link (
310- links . history (
311- fileStatus . source . path ,
312- 'git' in localization
313- ? new Date ( localization . git . latestTrackedCommit . date ) . toISOString ( )
314- : undefined ,
315- ) ,
316- 'source change history' ,
317- ) } )
318- `
319- }
320-
321282export const EmojiFileLink = (
322283 href : string | null ,
323284 type : 'missing' | 'outdated' | 'up-to-date' ,
@@ -343,56 +304,10 @@ export const EmojiFileLink = (
343304 </ span > `
344305}
345306
346- export const Link = ( href : string , text : string ) : string => {
347- return html `< a href ="${ href } "> ${ text } </ a > `
348- }
349-
350307export const CreateFileLink = ( href : string , text : string ) : string => {
351308 return html `< a class ="create-button " href ="${ href } "> ${ text } </ a > `
352309}
353310
354- export const ProgressBar = (
355- total : number ,
356- outdated : number ,
357- missing : number ,
358- { size = 20 } : { size ?: number } = { } ,
359- ) : string => {
360- const outdatedSize = Math . round ( ( outdated / total ) * size )
361- const missingSize = Math . round ( ( missing / total ) * size )
362- const doneSize = size - outdatedSize - missingSize
363-
364- const getBlocks = ( size : number , type : 'missing' | 'outdated' | 'up-to-date' ) => {
365- const items = [ ]
366- for ( let i = 0 ; i < size ; i ++ ) {
367- items . push ( html `< div class ="${ type } -bar "> </ div > ` )
368- }
369- return items
370- }
371-
372- return html `
373- < div class ="progress-bar " aria-hidden ="true ">
374- ${ getBlocks ( doneSize , 'up-to-date' ) } ${ getBlocks ( outdatedSize , 'outdated' ) }
375- ${ getBlocks ( missingSize , 'missing' ) }
376- </ div >
377- `
378- }
379-
380- export const TitleParagraph = html `
381- < p >
382- If you're interested in helping us translate
383- < a href ="https://npmx.dev/ "> npmx.dev</ a > into one of the languages listed below, you've come to
384- the right place! This auto-updating page always lists all the content that could use your help
385- right now.
386- </ p >
387- < p >
388- Before starting, please read our
389- < a href ="https://github.com/npmx-dev/npmx.dev/blob/main/CONTRIBUTING.md#localization-i18n "
390- > localization (i18n) guide</ a
391- >
392- to learn about our translation process and how you can get involved.
393- </ p >
394- `
395-
396311/**
397312 * Build an SVG file showing a summary of each language's translation progress.
398313 */
@@ -421,11 +336,10 @@ function SvgLocaleSummary(
421336 { label, lang } : Locale ,
422337) : { svg : string ; progress : number } {
423338 const missingFiles = status . filter (
424- file =>
425- file . localizations . find ( localization => localization . lang === lang ) ?. status === 'missing' ,
339+ file => file . localizations . find ( l => l . lang === lang ) ?. status === 'missing' ,
426340 )
427341 const outdatedFiles = status . filter ( file => {
428- const localization = file . localizations . find ( localization => localization . lang === lang )
342+ const localization = file . localizations . find ( l => l . lang === lang )
429343 if ( ! localization || localization . status === 'missing' ) {
430344 return false
431345 } else if ( file . type === 'dictionary' ) {
0 commit comments