'use client' import { resources } from '@/i18n/i18next-config' import { useEffect, useState } from 'react' import cn from '@/utils/classnames' export default function I18nTest() { const [langs, setLangs] = useState([]) useEffect(() => { setLangs(genLangs()) }, []) return (

Summary

{langs.map(({ locale, count, missing, extra }, idx) => )}
# lang count missing extra
{idx} {locale} {count} {missing.length} {extra.length}

Details

{langs.map(({ locale, missing, extra }, idx) => { return ( ) })}
# lang missing extra
{idx} {locale}
    {missing.map(key => (
  • {key}
  • ))}
    {extra.map(key => (
  • {key}
  • ))}
) } function genLangs() { const langs_: Lang[] = [] let en!: 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[] { const nestedKeys: string[] = [] const iterateKeys = (obj: Record, 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; count: number; missing: string[]; extra: string[]; }