From f95da27b8f055b3131cadc4fc75d9e7c11d4dc56 Mon Sep 17 00:00:00 2001 From: gbuomprisco Date: Sat, 14 Jun 2025 00:00:10 +0800 Subject: [PATCH] refactor(translations): replace default namespaces with dynamic loading from filesystem --- .../components/translations-comparison.tsx | 12 ++++----- .../translations/lib/translations-loader.ts | 27 +++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/apps/dev-tool/app/translations/components/translations-comparison.tsx b/apps/dev-tool/app/translations/components/translations-comparison.tsx index 7d051b01d..50bdd679a 100644 --- a/apps/dev-tool/app/translations/components/translations-comparison.tsx +++ b/apps/dev-tool/app/translations/components/translations-comparison.tsx @@ -32,7 +32,6 @@ import { } from '@kit/ui/table'; import { cn } from '@kit/ui/utils'; -import { defaultI18nNamespaces } from '../../../../web/lib/i18n/i18n.settings'; import { translateWithAIAction, updateTranslationAction, @@ -67,10 +66,6 @@ export function TranslationsComparison({ const [search, setSearch] = useState(''); const [isTranslating, setIsTranslating] = useState(false); - const [selectedNamespace, setSelectedNamespace] = useState( - defaultI18nNamespaces[0] as string, - ); - // Create RxJS Subject for handling translation updates const subject$ = useMemo( () => @@ -85,6 +80,7 @@ export function TranslationsComparison({ const locales = Object.keys(translations); const baseLocale = locales[0]!; + const namespaces = Object.keys(translations[baseLocale] || {}); const [selectedLocales, setSelectedLocales] = useState>( new Set(locales), @@ -93,6 +89,10 @@ export function TranslationsComparison({ // Flatten translations for the selected namespace const flattenedTranslations: FlattenedTranslations = {}; + const [selectedNamespace, setSelectedNamespace] = useState( + namespaces[0] as string, + ); + for (const locale of locales) { const namespaceData = translations[locale]?.[selectedNamespace]; @@ -254,7 +254,7 @@ export function TranslationsComparison({ - {defaultI18nNamespaces.map((namespace: string) => ( + {namespaces.map((namespace: string) => ( {namespace} diff --git a/apps/dev-tool/app/translations/lib/translations-loader.ts b/apps/dev-tool/app/translations/lib/translations-loader.ts index 0c7f42426..77739b00d 100644 --- a/apps/dev-tool/app/translations/lib/translations-loader.ts +++ b/apps/dev-tool/app/translations/lib/translations-loader.ts @@ -1,15 +1,6 @@ import { readFileSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; -const defaultI18nNamespaces = [ - 'common', - 'auth', - 'account', - 'teams', - 'billing', - 'marketing', -]; - export type TranslationData = { [key: string]: string | TranslationData; }; @@ -28,16 +19,24 @@ export async function loadTranslations() { for (const locale of locales) { translations[locale] = {}; - for (const namespace of defaultI18nNamespaces) { + const namespaces = readdirSync(join(localesPath, locale)).filter( + (file) => file.endsWith('.json'), + ); + + for (const namespace of namespaces) { + const namespaceName = namespace.replace('.json', ''); + try { - const filePath = join(localesPath, locale, `${namespace}.json`); + const filePath = join(localesPath, locale, namespace); const content = readFileSync(filePath, 'utf8'); - translations[locale][namespace] = JSON.parse(content); + + translations[locale][namespaceName] = JSON.parse(content); } catch (error) { console.warn( - `Warning: Translation file not found for locale "${locale}" and namespace "${namespace}"`, + `Warning: Translation file not found for locale "${locale}" and namespace "${namespaceName}"`, ); - translations[locale][namespace] = {}; + + translations[locale][namespaceName] = {}; } } }