|
|
|
@@ -1,175 +0,0 @@ |
|
|
|
'use client' |
|
|
|
import { loadLangResources } from '@/i18n-config/i18next-config' |
|
|
|
import { useCallback, useEffect, useState } from 'react' |
|
|
|
import cn from '@/utils/classnames' |
|
|
|
import { LanguagesSupported } from '@/i18n-config/language' |
|
|
|
|
|
|
|
export default function I18nTest() { |
|
|
|
const [langs, setLangs] = useState<Lang[]>([]) |
|
|
|
|
|
|
|
const getLangs = useCallback(async () => { |
|
|
|
const langs = await genLangs() |
|
|
|
setLangs(langs) |
|
|
|
}, []) |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
getLangs() |
|
|
|
}, []) |
|
|
|
|
|
|
|
return ( |
|
|
|
<div |
|
|
|
style={{ |
|
|
|
height: 'calc(100% - 6em)', |
|
|
|
overflowY: 'auto', |
|
|
|
margin: '1em 1em 5em', |
|
|
|
}} |
|
|
|
> |
|
|
|
|
|
|
|
<div style={{ minHeight: '75vh' }}> |
|
|
|
<h2>Summary</h2> |
|
|
|
|
|
|
|
<table |
|
|
|
className={cn('mt-2 min-w-[340px] border-collapse border-0')} |
|
|
|
> |
|
|
|
<thead className="system-xs-medium-uppercase text-text-tertiary"> |
|
|
|
<tr> |
|
|
|
<td className="w-5 min-w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1"> |
|
|
|
# |
|
|
|
</td> |
|
|
|
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
lang |
|
|
|
</td> |
|
|
|
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
count |
|
|
|
</td> |
|
|
|
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
missing |
|
|
|
</td> |
|
|
|
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
extra |
|
|
|
</td> |
|
|
|
</tr> |
|
|
|
</thead> |
|
|
|
<tbody className="system-sm-regular text-text-secondary"> |
|
|
|
{langs.map(({ locale, count, missing, extra }, idx) => <tr key={locale}> |
|
|
|
<td className="">{idx}</td> |
|
|
|
<td className="p-1.5">{locale}</td> |
|
|
|
<td>{count}</td> |
|
|
|
<td>{missing.length}</td> |
|
|
|
<td>{extra.length}</td> |
|
|
|
</tr>)} |
|
|
|
</tbody> |
|
|
|
</table> |
|
|
|
</div> |
|
|
|
|
|
|
|
<h2>Details</h2> |
|
|
|
|
|
|
|
<table |
|
|
|
className={cn('mt-2 w-full min-w-[340px] border-collapse border-0')} |
|
|
|
> |
|
|
|
<thead className="system-xs-medium-uppercase text-text-tertiary"> |
|
|
|
<tr> |
|
|
|
<td className="w-5 min-w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1"> |
|
|
|
# |
|
|
|
</td> |
|
|
|
<td className="w-20 min-w-20 whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
lang |
|
|
|
</td> |
|
|
|
<td className="w-full whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
missing |
|
|
|
</td> |
|
|
|
<td className="w-full whitespace-nowrap bg-background-section-burn py-1.5 pl-3"> |
|
|
|
extra |
|
|
|
</td> |
|
|
|
</tr> |
|
|
|
</thead> |
|
|
|
|
|
|
|
<tbody> |
|
|
|
{langs.map(({ locale, missing, extra }, idx) => { |
|
|
|
return (<tr key={locale}> |
|
|
|
<td className="py-2 align-top">{idx}</td> |
|
|
|
<td className="py-2 align-top">{locale}</td> |
|
|
|
<td className="py-2 align-top"> |
|
|
|
<ul> |
|
|
|
{missing.map(key => ( |
|
|
|
<li key={key}>{key}</li> |
|
|
|
))} |
|
|
|
</ul> |
|
|
|
</td> |
|
|
|
<td className="py-2 align-top"> |
|
|
|
<ul> |
|
|
|
{extra.map(key => ( |
|
|
|
<li key={key}>{key}</li> |
|
|
|
))} |
|
|
|
</ul> |
|
|
|
</td> |
|
|
|
</tr> |
|
|
|
) |
|
|
|
})} |
|
|
|
</tbody> |
|
|
|
</table> |
|
|
|
|
|
|
|
</div> |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
async function genLangs() { |
|
|
|
const langs_: Lang[] = [] |
|
|
|
let en!: Lang |
|
|
|
|
|
|
|
const resources: Record<string, any> = {} |
|
|
|
// Initialize empty resource object |
|
|
|
for (const lang of LanguagesSupported) |
|
|
|
resources[lang] = await loadLangResources(lang) |
|
|
|
|
|
|
|
for (const [key, value] of Object.entries(resources)) { |
|
|
|
const keys = getNestedKeys(value.translation) |
|
|
|
const lang: Lang = { |
|
|
|
locale: key, |
|
|
|
keys: new Set(keys), |
|
|
|
count: keys.length, |
|
|
|
missing: [], |
|
|
|
extra: [], |
|
|
|
} |
|
|
|
|
|
|
|
langs_.push(lang) |
|
|
|
if (key === 'en-US') en = lang |
|
|
|
} |
|
|
|
|
|
|
|
for (const lang of langs_) { |
|
|
|
const missing: string[] = [] |
|
|
|
const extra: string[] = [] |
|
|
|
|
|
|
|
for (const key of lang.keys) |
|
|
|
if (!en.keys.has(key)) extra.push(key) |
|
|
|
|
|
|
|
for (const key of en.keys) |
|
|
|
if (!lang.keys.has(key)) missing.push(key) |
|
|
|
|
|
|
|
lang.missing = missing |
|
|
|
lang.extra = extra |
|
|
|
} |
|
|
|
return langs_ |
|
|
|
} |
|
|
|
|
|
|
|
function getNestedKeys(translation: Record<string, any>): string[] { |
|
|
|
const nestedKeys: string[] = [] |
|
|
|
const iterateKeys = (obj: Record<string, any>, prefix = '') => { |
|
|
|
for (const key in obj) { |
|
|
|
const nestedKey = prefix ? `${prefix}.${key}` : key |
|
|
|
// nestedKeys.push(nestedKey); |
|
|
|
if (typeof obj[key] === 'object') iterateKeys(obj[key], nestedKey) |
|
|
|
else if (typeof obj[key] === 'string') nestedKeys.push(nestedKey) |
|
|
|
} |
|
|
|
} |
|
|
|
iterateKeys(translation) |
|
|
|
return nestedKeys |
|
|
|
} |
|
|
|
|
|
|
|
type Lang = { |
|
|
|
locale: string; |
|
|
|
keys: Set<string>; |
|
|
|
count: number; |
|
|
|
missing: string[]; |
|
|
|
extra: string[]; |
|
|
|
} |