MCP Server 2.0 (#452)
* MCP Server 2.0 - Updated application version from 2.23.14 to 2.24.0 in package.json. - MCP Server improved with new features - Migrated functionality from Dev Tools to MCP Server - Improved getMonitoringProvider not to crash application when misconfigured
This commit is contained in:
committed by
GitHub
parent
059408a70a
commit
f3ac595d06
@@ -33,27 +33,7 @@ import {
|
||||
import { cn } from '@kit/ui/utils';
|
||||
|
||||
import { updateTranslationAction } from '../lib/server-actions';
|
||||
import type { TranslationData, Translations } from '../lib/translations-loader';
|
||||
|
||||
function flattenTranslations(
|
||||
obj: TranslationData,
|
||||
prefix = '',
|
||||
result: Record<string, string> = {},
|
||||
) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const newKey = prefix ? `${prefix}.${key}` : key;
|
||||
|
||||
if (typeof value === 'string') {
|
||||
result[newKey] = value;
|
||||
} else {
|
||||
flattenTranslations(value, newKey, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
type FlattenedTranslations = Record<string, Record<string, string>>;
|
||||
import type { Translations } from '../lib/translations-loader';
|
||||
|
||||
export function TranslationsComparison({
|
||||
translations,
|
||||
@@ -74,35 +54,24 @@ export function TranslationsComparison({
|
||||
[],
|
||||
);
|
||||
|
||||
const locales = Object.keys(translations);
|
||||
const baseLocale = locales[0]!;
|
||||
const namespaces = Object.keys(translations[baseLocale] || {});
|
||||
const { base_locale, locales, namespaces } = translations;
|
||||
|
||||
const [selectedLocales, setSelectedLocales] = useState<Set<string>>(
|
||||
new Set(locales),
|
||||
);
|
||||
|
||||
// Flatten translations for the selected namespace
|
||||
const flattenedTranslations: FlattenedTranslations = {};
|
||||
|
||||
const [selectedNamespace, setSelectedNamespace] = useState(
|
||||
namespaces[0] as string,
|
||||
namespaces[0] ?? '',
|
||||
);
|
||||
|
||||
for (const locale of locales) {
|
||||
const namespaceData = translations[locale]?.[selectedNamespace];
|
||||
|
||||
if (namespaceData) {
|
||||
flattenedTranslations[locale] = flattenTranslations(namespaceData);
|
||||
} else {
|
||||
flattenedTranslations[locale] = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Get all unique keys across all translations
|
||||
const allKeys = Array.from(
|
||||
new Set(
|
||||
Object.values(flattenedTranslations).flatMap((data) => Object.keys(data)),
|
||||
locales.flatMap((locale) =>
|
||||
Object.keys(
|
||||
translations.translations[locale]?.[selectedNamespace] ?? {},
|
||||
),
|
||||
),
|
||||
),
|
||||
).sort();
|
||||
|
||||
@@ -143,7 +112,7 @@ export function TranslationsComparison({
|
||||
return () => subscription.unsubscribe();
|
||||
}, [subject$]);
|
||||
|
||||
if (locales.length === 0) {
|
||||
if (locales.length === 0 || !base_locale) {
|
||||
return <div>No translations found</div>;
|
||||
}
|
||||
|
||||
@@ -228,12 +197,16 @@ export function TranslationsComparison({
|
||||
</TableCell>
|
||||
|
||||
{visibleLocales.map((locale) => {
|
||||
const translations = flattenedTranslations[locale] ?? {};
|
||||
const translationsForLocale =
|
||||
translations.translations[locale]?.[selectedNamespace] ??
|
||||
{};
|
||||
|
||||
const baseTranslations =
|
||||
flattenedTranslations[baseLocale] ?? {};
|
||||
translations.translations[base_locale]?.[
|
||||
selectedNamespace
|
||||
] ?? {};
|
||||
|
||||
const value = translations[key];
|
||||
const value = translationsForLocale[key];
|
||||
const baseValue = baseTranslations[key];
|
||||
const isMissing = !value;
|
||||
const isDifferent = value !== baseValue;
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
|
||||
import { revalidatePath } from 'next/cache';
|
||||
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:url';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { findWorkspaceRoot } from '@kit/mcp-server/env';
|
||||
import {
|
||||
createKitTranslationsDeps,
|
||||
createKitTranslationsService,
|
||||
} from '@kit/mcp-server/translations';
|
||||
|
||||
const Schema = z.object({
|
||||
locale: z.string().min(1),
|
||||
namespace: z.string().min(1),
|
||||
@@ -20,40 +24,18 @@ const Schema = z.object({
|
||||
export async function updateTranslationAction(props: z.infer<typeof Schema>) {
|
||||
// Validate the input
|
||||
const { locale, namespace, key, value } = Schema.parse(props);
|
||||
const rootPath = findWorkspaceRoot(process.cwd());
|
||||
|
||||
const root = resolve(process.cwd(), '..');
|
||||
const filePath = `${root}apps/web/public/locales/${locale}/${namespace}.json`;
|
||||
const service = createKitTranslationsService(
|
||||
createKitTranslationsDeps(rootPath),
|
||||
);
|
||||
|
||||
try {
|
||||
// Read the current translations file
|
||||
const translationsFile = readFileSync(filePath, 'utf8');
|
||||
const translations = JSON.parse(translationsFile) as Record<string, any>;
|
||||
|
||||
// Update the nested key value
|
||||
const keys = key.split('.') as string[];
|
||||
let current = translations;
|
||||
|
||||
// Navigate through nested objects until the second-to-last key
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
const currentKey = keys[i] as string;
|
||||
|
||||
if (!current[currentKey]) {
|
||||
current[currentKey] = {};
|
||||
}
|
||||
|
||||
current = current[currentKey];
|
||||
}
|
||||
|
||||
// Set the value at the final key
|
||||
const finalKey = keys[keys.length - 1] as string;
|
||||
current[finalKey] = value;
|
||||
|
||||
// Write the updated translations back to the file
|
||||
writeFileSync(filePath, JSON.stringify(translations, null, 2), 'utf8');
|
||||
const result = await service.update({ locale, namespace, key, value });
|
||||
|
||||
revalidatePath(`/translations`);
|
||||
|
||||
return { success: true };
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('Failed to update translation:', error);
|
||||
throw new Error('Failed to update translation');
|
||||
|
||||
@@ -1,50 +1,21 @@
|
||||
import { readFileSync, readdirSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
export type TranslationData = {
|
||||
[key: string]: string | TranslationData;
|
||||
};
|
||||
import { findWorkspaceRoot } from '@kit/mcp-server/env';
|
||||
import {
|
||||
createKitTranslationsDeps,
|
||||
createKitTranslationsService,
|
||||
} from '@kit/mcp-server/translations';
|
||||
|
||||
export type Translations = {
|
||||
[locale: string]: {
|
||||
[namespace: string]: TranslationData;
|
||||
};
|
||||
base_locale: string;
|
||||
locales: string[];
|
||||
namespaces: string[];
|
||||
translations: Record<string, Record<string, Record<string, string>>>;
|
||||
};
|
||||
|
||||
export async function loadTranslations() {
|
||||
const localesPath = join(process.cwd(), '../web/public/locales');
|
||||
const localesDirents = readdirSync(localesPath, { withFileTypes: true });
|
||||
export async function loadTranslations(): Promise<Translations> {
|
||||
const rootPath = findWorkspaceRoot(process.cwd());
|
||||
const service = createKitTranslationsService(
|
||||
createKitTranslationsDeps(rootPath),
|
||||
);
|
||||
|
||||
const locales = localesDirents
|
||||
.filter((dirent) => dirent.isDirectory())
|
||||
.map((dirent) => dirent.name);
|
||||
|
||||
const translations: Translations = {};
|
||||
|
||||
for (const locale of locales) {
|
||||
translations[locale] = {};
|
||||
|
||||
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);
|
||||
const content = readFileSync(filePath, 'utf8');
|
||||
|
||||
translations[locale][namespaceName] = JSON.parse(content);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
`Warning: Translation file not found for locale "${locale}" and namespace "${namespaceName}"`,
|
||||
);
|
||||
|
||||
translations[locale][namespaceName] = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return translations;
|
||||
return service.list();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Metadata } from 'next';
|
||||
|
||||
import { AppBreadcrumbs } from '@kit/ui/app-breadcrumbs';
|
||||
import { Page, PageBody, PageHeader } from '@kit/ui/page';
|
||||
|
||||
import { TranslationsComparison } from './components/translations-comparison';
|
||||
|
||||
Reference in New Issue
Block a user