Skip to content

Commit bb5d4ee

Browse files
objectstack-fleet[bot]claudeos-project-manager
authored
fix: plugin-ai i18n wiring and Studio times in the display locale (objectui#10232) (#10328)
Fixes #10232 Clause-②: no Both display-locale faces on objectui#10232, in one PR. Implemented by `session_01D486C1axmXnrkJMNUfz2eb` (seat `domain:ui#3`), based on `8b1f06619`. ## What changed ### Item 2: Studio faces no longer use `useMetadataLocale()` as an `Intl` locale - `StudioHomePage`: the "recently viewed" `relativeTime` now gets `useDisplayLocale()`. It used to get `useMetadataLocale()`. - `StudioDesignSurface` (`DataPillar`): the last-saved time (`savedAt.toLocaleTimeString`) also uses `useDisplayLocale()`. The sentence around it still comes from the designer's string table. - `metadata-admin/i18n.ts`: the `useMetadataLocale` docblock now says it must never be used as an `Intl` locale, because it is `'en-US'` for every language except zh. It is kept for the two-language `t()` / `tFormat()` tables. - Premise re-derived on `8b1f06619`. The hook is still `/^zh/i.test(language) ? 'zh-CN' : 'en-US'`. I checked every file that calls `useMetadataLocale()` for `Intl.*` / `toLocale*` / `*Format(… locale …)` uses, and these two faces are the only ones. The other `Intl` sites in those files (`ResourceHistoryPage`, `JobPreview`, `ExternalDatasourcePanel`, `DatasetPreview`) already use the display locale since objectui#9909. ### Item 1: `@object-ui/plugin-ai` wired to `@object-ui/i18n` as a whole - `packages/plugin-ai/package.json` adds `@object-ui/i18n` (dependency) and `@object-ui/test-support` (devDependency). `pnpm-lock.yaml` was regenerated by `pnpm install` (6 added lines in the plugin-ai importer), not edited by hand. - New `src/useAiTranslation.ts` follows the plugin-chatbot `useAiApprovalsTranslation.ts` shape. It holds a `createSafeTranslation` defaults map that mirrors the `en` pack, plus `formatPercent(score, locale)`. - Strings: 17 keys in a new `ai.*` namespace (`ai.nlQuery.*` 7, `ai.formAssist.*` 7, `ai.recommendations.*` 3), translated in all ten packs. Counts use the repo's two-key plural convention (`*One` is picked at the call site when the count is exactly one, as with `search.itemsAvailableOne`). - Display locale: the `nl-query` history date is now `toLocaleDateString(displayLocale)`. It was a bare `toLocaleDateString()`, which uses the machine's locale. The confidence and score percentages go through `Intl.NumberFormat(displayLocale, percent)` instead of a `Math.round(...)` followed by a literal percent sign. - README: new "Localization" section. `content/docs/plugins/plugin-ai.mdx` points readers to the README. ### Census coverage (hypothesis 4) The objectui#9909 census is `packages/i18n/src/__tests__/machineLocaleCensus-9909.test.ts`. It builds its population from every workspace manifest that names `@object-ui/i18n`, so after this change it covers `packages/plugin-ai` with no edit to the census file. With the fix, the history-date expression passes the census. With the ablation below (the bare call put back), the census goes red on its `no call site passes nothing, undefined or the default pseudo-tag unless it is declared` case. ### One PR, not two Triage allowed a split. I kept one PR because both items are small, their file sets don't overlap, and the claim names this one branch. A second PR would need a second branch that no claim names, plus a second write. ## Tests (source tree at `5bab5d4d7`; `e957b05fc` adds only the README section) - New `packages/plugin-ai/src/aiComponents.i18n-10232.test.tsx`: history date de-DE `4.3.2020` vs en `3/4/2020`; the two sessions differ; runtime tripwire; de strings; the singular key at one; de-DE percent; English with no provider; the defaults map mirrors the `en` pack in both directions. - New `packages/app-shell/src/views/metadata-admin/StudioHomePage.displayLocale-10232.test.tsx`: `vor 3 Tagen` vs `3 days ago` with the UI language `en` in both sessions, plus the tripwire. - New `packages/app-shell/src/views/studio-design/DataPillar.savedAtDisplayLocale-10232.test.tsx`: a real auto-save lands, de-DE shows a 24-hour time, en shows AM/PM, plus the tripwire. - `vitest run packages/plugin-ai/ packages/i18n/src/__tests__/`: 73 files, 1182 tests passed (includes the census and all-locales key parity). - `vitest run` DataPillar* + studio-locale + metadataAdminFaces-9909 + StudioHomePage-10232 + the two AppContent route suites: 12 files, 97 tests passed. `StudioDesignSurface*`: 23 files, 118 tests passed. - `pnpm --filter @object-ui/plugin-ai run type-check` and `build` exit 0. `pnpm --filter @object-ui/app-shell run type-check` exits 0 after building its dependency closure. - Ablation (committed first, trap restore, then `git diff HEAD` checked empty): three edits confirmed on disk by `grep -c` (mutant 1 1 1, fix 0 0 0). Result: 9 failed, 15 passed across the 4 files, including the census case above. Tree restored. ## Gates (exit codes captured to files before reading) `check:i18n-keys` 0 · `check:i18n-drift` 0 (17 keys added, 0 en values changed) · `check:i18n-dead-keys` 0 (no `ai.*` key listed) · `check:i18n-designer-parity` 0 · `check:phantom-deps` 0 · `check:unused-deps` 0 · `check:control-bytes` 0 · `check:new-line-citations` 0 · `check:published-tsconfig-exclude` 0 · `check:lockfile-integrity` 0 · `check:lockfile-dedupe` 0 · `check:vi-mock-*` 0 · `check:test-path-roots` 0 · `check:changeset-claims` 0 · `check:pending-changeset-literals` 0 · `check:esm-specifiers` 0 · `check:governed-queue-guard` 0 · `check:unreferenced-sources` 0 · `check:self-import` 0 · changeset presence 0 · no-major 0 · eslint on the 20 touched ts/tsx files: 0 errors (20 warnings, all on lines this PR does not touch). - NOT MEASURED: `check:eager-locale-catalogues`, reason: PREREQUISITE NOT MET (needs a built `apps/console/dist`). `check:dist-completeness`, reason: `packages/app-shell/dist` was not built locally (only its dependency closure was). Full app-shell and console suites and a repo-wide lint are left to CI. ## Acceptance notes - The plugin-ai icon-only buttons (refresh, dismiss, apply, reject) have no accessible names. That is outside this card, and no carrier was identified. - The `ComponentRegistry` labels in `plugin-ai/src/index.tsx` are English designer metadata, like every other plugin's registration labels. They are not translated here. - `ai-recommendations` offers `layout: 'carousel'` (in the schema type and the registration enum), but the renderer shows it as a list. Reported to the seat, not changed here. - Draft PR objectui#8941 also edits `packages/plugin-ai/package.json` and `pnpm-lock.yaml`. Whichever lands second regenerates the lockfile. --- _Generated by [Claude Code](https://claude.ai/code/session_01D486C1axmXnrkJMNUfz2eb)_ --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Leehom <pm@objectstack.ai>
1 parent b57107d commit bb5d4ee

24 files changed

Lines changed: 785 additions & 20 deletions
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/plugin-ai': patch
4+
'@object-ui/i18n': patch
5+
---
6+
7+
Two display-locale faces now follow the session's display locale (objectui#10232).
8+
9+
- `@object-ui/plugin-ai` is wired to `@object-ui/i18n` as a whole. The `nl-query`,
10+
`ai-form-assist` and `ai-recommendations` components read their strings from a new
11+
`ai.*` namespace, translated in all ten locale packs, instead of hard-coded English.
12+
The `nl-query` history date, which was formatted in the machine's locale, and the
13+
confidence and score percentages now format in the display locale
14+
(`useDisplayLocale()`). The package's manifest now names `@object-ui/i18n`, which also
15+
puts it inside the repo-wide machine-locale census.
16+
- `@object-ui/app-shell`: the Studio home page's "recently viewed" times and the Data
17+
pillar's last-saved time format in the display locale. They used to be handed
18+
`useMetadataLocale()`, which picks the designer's string table and is `en-US` for every
19+
language other than zh, so a de-DE session read US English. That hook's doc comment
20+
now says it must never be used as an `Intl` locale.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
/**
10+
* Studio home's "recently viewed" times read the DISPLAY locale, not the
11+
* designer's string-table language (objectui#10232).
12+
*
13+
* The page carries a `locale` of its own — `useMetadataLocale()`, which picks
14+
* one of the metadata-admin `t()` tables and is therefore `'en-US'` for every
15+
* language that is not zh. `relativeTime` used to be handed that value, so a
16+
* de-DE session read "3 days ago". The face now formats with
17+
* `useDisplayLocale()`, the channel objectui#9909's surfaces already use.
18+
*
19+
* Each session is read with the UI language `en` on both sides, so the
20+
* string-table language is `'en-US'` in both and only the declared display
21+
* locale differs: a reading that still followed `useMetadataLocale()` says the
22+
* same thing twice.
23+
*/
24+
25+
import '@testing-library/jest-dom/vitest';
26+
import * as React from 'react';
27+
import { describe, it, expect, vi, afterEach } from 'vitest';
28+
import { render, cleanup, screen } from '@testing-library/react';
29+
import { MemoryRouter } from 'react-router-dom';
30+
import { I18nProvider, LocalizationProvider } from '@object-ui/i18n';
31+
import { isMachineLocale, recordLocaleArgumentsAsync } from '@object-ui/test-support';
32+
33+
const THREE_DAYS = 3 * 24 * 60 * 60 * 1000;
34+
35+
vi.mock('./useMetadata.js', async (importOriginal) => ({
36+
...(await importOriginal<Record<string, unknown>>()),
37+
useMetadataClient: () => ({ list: async () => [] }),
38+
useMetadataTypes: () => ({ loading: false, entries: [] }),
39+
useGlobalDiagnostics: () => ({ summary: { total: 0 }, countsByType: {}, packagesByType: {}, loading: false }),
40+
}));
41+
42+
vi.mock('./QuickFind.js', () => ({ MetadataQuickFind: () => null }));
43+
44+
vi.mock('../../context/RecentItemsProvider.js', async (importOriginal) => ({
45+
...(await importOriginal<Record<string, unknown>>()),
46+
useRecentItems: () => ({
47+
recentItems: [
48+
{
49+
id: 'object:account',
50+
label: 'Account',
51+
href: '/studio/object/account',
52+
type: 'object',
53+
visitedAt: new Date(Date.now() - THREE_DAYS).toISOString(),
54+
},
55+
],
56+
addRecentItem: () => {},
57+
clearRecentItems: () => {},
58+
}),
59+
}));
60+
61+
import { StudioHomePage } from './StudioHomePage';
62+
63+
afterEach(cleanup);
64+
65+
/** Mounts the page under a declared display `locale` and returns the recent item's time. */
66+
async function readVisitTime(locale: string): Promise<string> {
67+
render(
68+
<I18nProvider config={{ defaultLanguage: 'en', detectBrowserLanguage: false }} persistLanguage={false}>
69+
<LocalizationProvider value={{ locale }}>
70+
<MemoryRouter>
71+
<StudioHomePage />
72+
</MemoryRouter>
73+
</LocalizationProvider>
74+
</I18nProvider>,
75+
);
76+
const label = await screen.findByText('Account');
77+
const text = label.parentElement?.textContent ?? '';
78+
cleanup();
79+
return text.replace(/\s+/g, ' ');
80+
}
81+
82+
describe('Studio home — recently viewed times follow the display locale (objectui#10232)', () => {
83+
it('says the de-DE face under a de-DE session', async () => {
84+
const text = await readVisitTime('de-DE');
85+
expect(text, `got: ${text}`).toMatch(/vor 3 Tagen/);
86+
});
87+
88+
it('keeps the en face under an en session', async () => {
89+
const text = await readVisitTime('en');
90+
expect(text, `got: ${text}`).toMatch(/3 days ago/);
91+
});
92+
93+
it('is a reading of the display locale, not of the string-table language', async () => {
94+
expect(await readVisitTime('de-DE')).not.toBe(await readVisitTime('en'));
95+
});
96+
97+
it('every locale-taking call receives the declared tag', async () => {
98+
const calls = await recordLocaleArgumentsAsync(async () => {
99+
await readVisitTime('de-DE');
100+
});
101+
expect(calls.some((c) => c.locale === 'de-DE'), `saw: ${JSON.stringify(calls).slice(0, 2000)}`).toBe(true);
102+
expect(calls.filter(isMachineLocale), 'these call sites formatted in the machine locale').toEqual([]);
103+
});
104+
});

‎packages/app-shell/src/views/metadata-admin/StudioHomePage.tsx‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
Table2,
4545
} from 'lucide-react';
4646
import { Button } from '@object-ui/components';
47+
import { useDisplayLocale } from '@object-ui/i18n';
4748
import { useRecentItems, type RecentItem } from '../../context/RecentItemsProvider.js';
4849
import {
4950
useMetadataClient,
@@ -118,6 +119,11 @@ function greetingKey(): string {
118119
* the last hard-coded strings in this file.
119120
*
120121
* `numeric: 'auto'` is what turns "1 day ago" into "yesterday" / 「昨天」.
122+
*
123+
* `locale` is the DISPLAY locale (`useDisplayLocale()`), never the designer's
124+
* string-table language from `useMetadataLocale()`: that one collapses every
125+
* non-zh language to `'en-US'`, so a de-DE session read "3 days ago" in US
126+
* English (objectui#10232).
121127
*/
122128
function relativeTime(iso: string, locale: string): string {
123129
const then = new Date(iso).getTime();
@@ -141,6 +147,9 @@ export function StudioHomePage() {
141147
const { loading, entries } = useMetadataTypes(client);
142148
const { recentItems } = useRecentItems();
143149
const locale = useMetadataLocale();
150+
// The visit times read the DISPLAY locale — not `locale` above, which picks
151+
// this page's strings (objectui#10232).
152+
const displayLocale = useDisplayLocale();
144153
const [searchParams, setSearchParams] = useSearchParams();
145154

146155
const [projectPackages, setProjectPackages] = React.useState<
@@ -421,7 +430,7 @@ export function StudioHomePage() {
421430
<span className="min-w-0 flex-1">
422431
<span className="block truncate text-sm font-medium">{item.label}</span>
423432
<span className="block text-[11px] text-muted-foreground">
424-
{relativeTime(item.visitedAt, locale)}
433+
{relativeTime(item.visitedAt, displayLocale)}
425434
</span>
426435
</span>
427436
<ArrowRight className="h-3.5 w-3.5 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100" />

‎packages/app-shell/src/views/metadata-admin/i18n.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4756,6 +4756,14 @@ export function detectLocale(): SupportedLocale {
47564756
* follows the live `useObjectTranslation().language`, so the Studio pillars
47574757
* re-render in lock-step with the console locale — the same source the rest of
47584758
* the app (Home, forms, list views) renders from.
4759+
*
4760+
* ⛔ Never hand this value to `Intl` (`Intl.*Format`, `toLocale*String`) as the
4761+
* locale a date, time or number is formatted in. It picks one of this file's
4762+
* TWO string tables, so it is `'en-US'` for every language that is not zh — a
4763+
* de-DE session would read its faces in US English (objectui#10232). Faces
4764+
* format with `useDisplayLocale()` from `@object-ui/i18n`, the channel every
4765+
* date and number renderer resolves through; keep this value for `t()` /
4766+
* `tFormat()` and the other lookups into the tables here.
47594767
*/
47604768
export function useMetadataLocale(): SupportedLocale {
47614769
const { language } = useObjectTranslation();
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
/**
10+
* The Data pillar's last-saved hint reads the DISPLAY locale, not the
11+
* designer's string-table language (objectui#10232).
12+
*
13+
* The pillar's `locale` is `useMetadataLocale()`, which picks one of the
14+
* metadata-admin `t()` tables and is `'en-US'` for every language that is not
15+
* zh. The saved time used to be formatted with it, so a de-DE session read
16+
* "Saved 03:30 PM". The time is now formatted with `useDisplayLocale()`; the
17+
* sentence around it keeps the string-table language.
18+
*
19+
* The UI language is `en` in both sessions, so only the declared display
20+
* locale differs. The saved time is "now", so the faces are told apart by the
21+
* convention, not by a fixed clock: a 24-hour de-DE time carries no day
22+
* period, an en one does.
23+
*/
24+
25+
import '@testing-library/jest-dom/vitest';
26+
import * as React from 'react';
27+
import { afterEach, describe, expect, it, vi } from 'vitest';
28+
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
29+
import { MemoryRouter } from 'react-router-dom';
30+
import { I18nProvider, LocalizationProvider } from '@object-ui/i18n';
31+
import { isMachineLocale, recordLocaleArgumentsAsync } from '@object-ui/test-support';
32+
33+
const objectDef = {
34+
name: 'showcase_task',
35+
label: 'Task',
36+
fields: [{ name: 'title', label: 'Title', type: 'text' }],
37+
};
38+
39+
const mockClient = {
40+
list: vi.fn(async () => [{ name: 'showcase_task', label: 'Task' }]),
41+
listDrafts: vi.fn(async () => []),
42+
layered: vi.fn(async () => ({ effective: objectDef, code: objectDef })),
43+
getDraft: vi.fn(async () => null),
44+
save: vi.fn(async () => ({})),
45+
};
46+
47+
vi.mock('../metadata-admin/useMetadata', async (importOriginal) => {
48+
const mod = await importOriginal<typeof import('../metadata-admin/useMetadata')>();
49+
return {
50+
...mod,
51+
useMetadataClient: () => mockClient,
52+
useMetadataTypes: () => ({ entries: [] }),
53+
};
54+
});
55+
56+
vi.mock('./packages-io', async (importOriginal) => {
57+
const mod = await importOriginal<typeof import('./packages-io')>();
58+
return { ...mod, fetchPackages: vi.fn(async () => []) };
59+
});
60+
61+
vi.mock('@object-ui/react', async (importOriginal) => {
62+
const mod = await importOriginal<typeof import('@object-ui/react')>();
63+
return { ...mod, useAdapter: () => ({}) };
64+
});
65+
66+
import { DataPillar } from './StudioDesignSurface';
67+
68+
afterEach(cleanup);
69+
70+
/** Mounts the pillar under a declared display `locale`, makes an edit, and returns the saved hint once the auto-save lands. */
71+
async function readSavedHint(locale: string): Promise<string> {
72+
render(
73+
<I18nProvider config={{ defaultLanguage: 'en', detectBrowserLanguage: false }} persistLanguage={false}>
74+
<LocalizationProvider value={{ locale }}>
75+
<MemoryRouter initialEntries={['/studio/com.example.showcase/data']}>
76+
<DataPillar packageId="com.example.showcase" />
77+
</MemoryRouter>
78+
</LocalizationProvider>
79+
</I18nProvider>,
80+
);
81+
fireEvent.click(await screen.findByRole('button', { name: 'Form' }));
82+
// An edit sets `dirty`; the debounced auto-save lands it and shows the hint.
83+
fireEvent.click((await screen.findAllByRole('button', { name: /Add field/i }))[0]);
84+
const hint = await screen.findByTestId('data-saved-at', undefined, { timeout: 5000 });
85+
const text = hint.textContent ?? '';
86+
cleanup();
87+
return text;
88+
}
89+
90+
describe('Data pillar — the last-saved time follows the display locale (objectui#10232)', () => {
91+
it('says the de-DE face under a de-DE session', async () => {
92+
const text = await readSavedHint('de-DE');
93+
expect(text, `got: ${text}`).toMatch(/\b\d{2}:\d{2}\b/);
94+
expect(text, `got: ${text}`).not.toMatch(/\b(AM|PM)\b/);
95+
});
96+
97+
it('keeps the en face under an en session', async () => {
98+
const text = await readSavedHint('en');
99+
expect(text, `got: ${text}`).toMatch(/\d{2}:\d{2}\s(AM|PM)/);
100+
});
101+
102+
it('every locale-taking call receives the declared tag', async () => {
103+
const calls = await recordLocaleArgumentsAsync(async () => {
104+
await readSavedHint('de-DE');
105+
});
106+
expect(calls.some((c) => c.locale === 'de-DE'), `saw: ${JSON.stringify(calls).slice(0, 2000)}`).toBe(true);
107+
expect(calls.filter(isMachineLocale), 'these call sites formatted in the machine locale').toEqual([]);
108+
});
109+
});

‎packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ import { SurfaceDeepLinkProvider, useRequestedSurface } from './surfaceDeepLinkC
116116
import { buildObjectSkeleton, buildFlowSkeleton, buildAppSkeleton, buildPermissionSkeleton } from './skeletons.js';
117117
import { OWD_CREATE_MODELS, OWD_DEFAULT, type OwdCreateModel } from './owd-sharing.js';
118118
import { t, tFormat, translateMetadataType, useMetadataLocale } from '../metadata-admin/i18n.js';
119+
import { useDisplayLocale } from '@object-ui/i18n';
119120
import { SuggestedBindingsPanel } from '../../components/SuggestedBindingsPanel.js';
120121
import { AppNavCanvas } from '../metadata-admin/previews/AppNavCanvas.js';
121122
import {
@@ -2656,6 +2657,10 @@ export function DataPillar({
26562657
const client = useMetadataClient();
26572658
const adapter = useAdapter();
26582659
const locale = useMetadataLocale();
2660+
// The last-saved time reads the DISPLAY locale — not `locale` above, which
2661+
// picks the pillar's strings and is `'en-US'` for every non-zh language
2662+
// (objectui#10232).
2663+
const displayLocale = useDisplayLocale();
26592664
// Live server JSONSchemas per metadata type (`/meta/types`) — handed to the
26602665
// Actions/Hooks config panels so their forms are driven by the real metadata
26612666
// contract (and stay forward-compatible when the server spec adds fields).
@@ -3173,7 +3178,7 @@ export function DataPillar({
31733178
) : savedAt && !dirty ? (
31743179
<span className="ml-auto text-[11px] text-muted-foreground" data-testid="data-saved-at">
31753180
{tFormat('engine.studio.data.lastSaved', locale, {
3176-
time: savedAt.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' }),
3181+
time: savedAt.toLocaleTimeString(displayLocale, { hour: '2-digit', minute: '2-digit' }),
31773182
})}
31783183
</span>
31793184
) : null}

‎packages/i18n/src/locales/ar.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2927,6 +2927,31 @@ const ar = {
29272927
openProduction: "فتح بيئة الإنتاج",
29282928
manageEnvironments: "إدارة البيئات",
29292929
},
2930+
ai: {
2931+
nlQuery: {
2932+
placeholder: "اطرح سؤالًا حول بياناتك…",
2933+
ask: "اسأل",
2934+
results: "النتائج",
2935+
match: "نسبة التطابق: {{percent}}",
2936+
simulatedSummary: "نتائج: {{query}}",
2937+
noResults: "لم يتم العثور على سجلات مطابقة",
2938+
recentQueries: "الاستعلامات الأخيرة",
2939+
},
2940+
formAssist: {
2941+
title: "اقتراحات الذكاء الاصطناعي",
2942+
suggestionCount: "عدد الاقتراحات: {{count}}",
2943+
suggestionCountOne: "عدد الاقتراحات: {{count}}",
2944+
applyAll: "تطبيق الكل",
2945+
confidence: "الثقة: {{percent}}",
2946+
appliedCount: "عدد الاقتراحات المطبّقة: {{count}}",
2947+
appliedCountOne: "عدد الاقتراحات المطبّقة: {{count}}",
2948+
},
2949+
recommendations: {
2950+
title: "التوصيات",
2951+
generating: "جارٍ إنشاء التوصيات…",
2952+
empty: "لا توجد توصيات متاحة",
2953+
},
2954+
},
29302955
aiApprovals: {
29312956
title: "موافقات الذكاء الاصطناعي",
29322957
description: "إجراءات اقترحها وكيل ذكاء اصطناعي وتحتاج إلى مراجعة بشرية قبل تنفيذها.",

‎packages/i18n/src/locales/de.ts‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2915,6 +2915,31 @@ const de = {
29152915
openProduction: "Produktion öffnen",
29162916
manageEnvironments: "Umgebungen verwalten",
29172917
},
2918+
ai: {
2919+
nlQuery: {
2920+
placeholder: "Stellen Sie eine Frage zu Ihren Daten…",
2921+
ask: "Fragen",
2922+
results: "Ergebnisse",
2923+
match: "{{percent}} Übereinstimmung",
2924+
simulatedSummary: "Ergebnisse für: {{query}}",
2925+
noResults: "Keine passenden Datensätze gefunden",
2926+
recentQueries: "Letzte Abfragen",
2927+
},
2928+
formAssist: {
2929+
title: "KI-Vorschläge",
2930+
suggestionCount: "{{count}} Vorschläge",
2931+
suggestionCountOne: "{{count}} Vorschlag",
2932+
applyAll: "Alle übernehmen",
2933+
confidence: "{{percent}} Konfidenz",
2934+
appliedCount: "{{count}} Vorschläge übernommen",
2935+
appliedCountOne: "{{count}} Vorschlag übernommen",
2936+
},
2937+
recommendations: {
2938+
title: "Empfehlungen",
2939+
generating: "Empfehlungen werden generiert…",
2940+
empty: "Keine Empfehlungen verfügbar",
2941+
},
2942+
},
29182943
aiApprovals: {
29192944
title: "KI-Genehmigungen",
29202945
description: "Von einem KI-Agenten vorgeschlagene Aktionen, die vor der Ausführung eine menschliche Prüfung benötigen.",

0 commit comments

Comments
 (0)