@gradio/core 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/src/Blocks.svelte +6 -2
  3. package/dist/src/Render.svelte +2 -2
  4. package/dist/src/RenderComponent.svelte +21 -1
  5. package/dist/src/api_docs/ApiDocs.svelte +18 -3
  6. package/dist/src/gradio_helper.d.ts +1 -11
  7. package/dist/src/gradio_helper.js +3 -19
  8. package/dist/src/i18n.d.ts +12 -5
  9. package/dist/src/i18n.js +93 -12
  10. package/dist/src/init.js +36 -20
  11. package/dist/src/lang/en.json +2 -1
  12. package/dist/src/lang/es.json +2 -1
  13. package/dist/src/lang/fr.json +2 -1
  14. package/dist/src/lang/ja.json +2 -1
  15. package/dist/src/lang/ko.json +2 -1
  16. package/dist/src/lang/lt.json +2 -1
  17. package/dist/src/lang/nb.json +2 -1
  18. package/dist/src/lang/nl.json +2 -1
  19. package/dist/src/lang/pl.json +2 -1
  20. package/dist/src/lang/pt-BR.json +1 -0
  21. package/dist/src/lang/pt.json +2 -1
  22. package/dist/src/lang/ro.json +2 -1
  23. package/dist/src/lang/ru.json +2 -1
  24. package/dist/src/lang/sv.json +2 -1
  25. package/dist/src/lang/ta.json +2 -1
  26. package/dist/src/lang/th.json +2 -1
  27. package/dist/src/lang/tr.json +2 -1
  28. package/dist/src/lang/uk.json +2 -1
  29. package/dist/src/lang/ur.json +2 -1
  30. package/dist/src/lang/uz.json +2 -1
  31. package/dist/src/lang/zh-CN.json +2 -1
  32. package/dist/src/lang/zh-TW.json +2 -1
  33. package/package.json +53 -53
  34. package/src/Blocks.svelte +7 -3
  35. package/src/Render.svelte +2 -2
  36. package/src/RenderComponent.svelte +21 -1
  37. package/src/api_docs/ApiDocs.svelte +19 -3
  38. package/src/gradio_helper.ts +5 -21
  39. package/src/i18n.test.ts +120 -1
  40. package/src/i18n.ts +126 -24
  41. package/src/init.ts +47 -26
  42. package/src/lang/en.json +2 -1
  43. package/src/lang/es.json +2 -1
  44. package/src/lang/fr.json +2 -1
  45. package/src/lang/ja.json +2 -1
  46. package/src/lang/ko.json +2 -1
  47. package/src/lang/lt.json +2 -1
  48. package/src/lang/nb.json +2 -1
  49. package/src/lang/nl.json +2 -1
  50. package/src/lang/pl.json +2 -1
  51. package/src/lang/pt-BR.json +1 -0
  52. package/src/lang/pt.json +2 -1
  53. package/src/lang/ro.json +2 -1
  54. package/src/lang/ru.json +2 -1
  55. package/src/lang/sv.json +2 -1
  56. package/src/lang/ta.json +2 -1
  57. package/src/lang/th.json +2 -1
  58. package/src/lang/tr.json +2 -1
  59. package/src/lang/uk.json +2 -1
  60. package/src/lang/ur.json +2 -1
  61. package/src/lang/uz.json +2 -1
  62. package/src/lang/zh-CN.json +2 -1
  63. package/src/lang/zh-TW.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @gradio/core
2
2
 
3
+ ## 0.17.0
4
+
5
+ ### Features
6
+
7
+ - [#11155](https://github.com/gradio-app/gradio/pull/11155) [`30a1d9e`](https://github.com/gradio-app/gradio/commit/30a1d9e2ac3013d9c844b236410010bce97ffaf5) - Improvements to MCP page. Thanks @abidlabs!
8
+ - [#11047](https://github.com/gradio-app/gradio/pull/11047) [`6d4b8a7`](https://github.com/gradio-app/gradio/commit/6d4b8a7f10daefc9c79aa224635da23fbaeebb76) - Implement custom i18n. Thanks @hannahblair!
9
+
10
+ ### Fixes
11
+
12
+ - [#11206](https://github.com/gradio-app/gradio/pull/11206) [`c196ac2`](https://github.com/gradio-app/gradio/commit/c196ac25b7744e9dcfa788b1ac8edf6551eec1ff) - Render key fixes. Thanks @aliabid94!
13
+
14
+ ### Dependency updates
15
+
16
+ - @gradio/code@0.14.4
17
+ - @gradio/paramviewer@0.7.9
18
+ - @gradio/statustracker@0.10.11
19
+ - @gradio/atoms@0.16.1
20
+ - @gradio/client@1.15.0
21
+ - @gradio/upload@0.16.5
22
+ - @gradio/button@0.5.0
23
+ - @gradio/image@0.22.6
24
+ - @gradio/video@0.14.14
25
+ - @gradio/file@0.12.18
26
+ - @gradio/column@0.2.0
27
+ - @gradio/gallery@0.15.19
28
+ - @gradio/plot@0.9.16
29
+ - @gradio/textbox@0.10.11
30
+ - @gradio/checkbox@0.4.21
31
+
32
+ ## 0.16.1
33
+
34
+ ### Dependency updates
35
+
36
+ - @gradio/tabs@0.4.4
37
+ - @gradio/tabitem@0.4.4
38
+
39
+ ## 0.16.1
40
+
41
+ ### Fixes
42
+
43
+ - [#11115](https://github.com/gradio-app/gradio/pull/11115) [`49e7a0d`](https://github.com/gradio-app/gradio/commit/49e7a0dd18174196b262d32e6c59d93ca40b1c73) - update STDIO instructions to specify sse-only transport. Thanks @evalstate!
44
+
45
+ ### Dependency updates
46
+
47
+ - @gradio/code@0.14.3
48
+ - @gradio/button@0.4.18
49
+ - @gradio/video@0.14.13
50
+ - @gradio/upload@0.16.4
51
+ - @gradio/image@0.22.5
52
+ - @gradio/gallery@0.15.18
53
+ - @gradio/file@0.12.17
54
+
3
55
  ## 0.16.0
4
56
 
5
57
  ### Features
@@ -10,7 +10,6 @@ import logo from "./images/logo.svg";
10
10
  import api_logo from "./api_docs/img/api-logo.svg";
11
11
  import settings_logo from "./api_docs/img/settings-logo.svg";
12
12
  import { create_components, AsyncFunction } from "./init";
13
- setupi18n();
14
13
  export let root;
15
14
  export let components;
16
15
  export let layout;
@@ -34,6 +33,7 @@ export let api_prefix = "";
34
33
  export let max_file_size = void 0;
35
34
  export let initial_layout = void 0;
36
35
  export let css = null;
36
+ setupi18n(app.config?.i18n_translations ?? void 0);
37
37
  let {
38
38
  layout: _layout,
39
39
  targets,
@@ -659,7 +659,11 @@ onMount(() => {
659
659
  }}
660
660
  class="show-api"
661
661
  >
662
- {$_("errors.use_via_api")}
662
+ {#if app.config?.mcp_server}
663
+ {$_("errors.use_via_api_or_mcp")}
664
+ {:else}
665
+ {$_("errors.use_via_api")}
666
+ {/if}
663
667
  <img src={api_logo} alt={$_("common.logo")} />
664
668
  </button>
665
669
  <div class="divider show-api-divider">·</div>
@@ -1,4 +1,4 @@
1
- <script>import { Gradio, formatter } from "./gradio_helper";
1
+ <script>import { Gradio, reactive_formatter } from "./gradio_helper";
2
2
  import { onMount, createEventDispatcher, setContext } from "svelte";
3
3
  import RenderComponent from "./RenderComponent.svelte";
4
4
  import { load_component } from "virtual:component-loader";
@@ -55,7 +55,7 @@ $:
55
55
  root,
56
56
  autoscroll,
57
57
  max_file_size,
58
- formatter,
58
+ $reactive_formatter,
59
59
  client,
60
60
  load_component
61
61
  );
@@ -1,6 +1,7 @@
1
1
  <svelte:options immutable={true} />
2
2
 
3
- <script>import { bind, binding_callbacks } from "svelte/internal";
3
+ <script>import { translate_if_needed } from "./i18n";
4
+ import { bind, binding_callbacks } from "svelte/internal";
4
5
  export let root;
5
6
  export let component;
6
7
  export let target;
@@ -34,6 +35,25 @@ function wrap(component2) {
34
35
  return ProxiedMyClass;
35
36
  }
36
37
  const _component = wrap(component);
38
+ const supported_props = [
39
+ "description",
40
+ "info",
41
+ "title",
42
+ "placeholder",
43
+ "value",
44
+ "label"
45
+ ];
46
+ function translate_prop(obj) {
47
+ for (const key in obj) {
48
+ if (supported_props.includes(key)) {
49
+ obj[key] = translate_if_needed(obj[key]);
50
+ }
51
+ }
52
+ }
53
+ $:
54
+ translate_prop($$restProps);
55
+ $:
56
+ value = translate_if_needed(value);
37
57
  </script>
38
58
 
39
59
  <!-- {#if visible} -->
@@ -23,6 +23,7 @@ const js_docs = "https://www.gradio.app/guides/getting-started-with-the-js-clien
23
23
  const py_docs = "https://www.gradio.app/guides/getting-started-with-the-python-client";
24
24
  const bash_docs = "https://www.gradio.app/guides/querying-gradio-apps-with-curl";
25
25
  const spaces_docs_suffix = "#connecting-to-a-hugging-face-space";
26
+ const mcp_docs = "https://www.gradio.app/guides/building-mcp-server-with-gradio";
26
27
  let api_count = dependencies.filter(
27
28
  (dependency) => dependency.show_api
28
29
  ).length;
@@ -290,7 +291,12 @@ onMount(() => {
290
291
  mcpServers: {
291
292
  gradio: {
292
293
  command: "npx",
293
- args: ["mcp-remote", mcp_server_url]
294
+ args: [
295
+ "mcp-remote",
296
+ mcp_server_url,
297
+ "--transport",
298
+ "sse-only"
299
+ ]
294
300
  }
295
301
  }
296
302
  },
@@ -305,7 +311,12 @@ onMount(() => {
305
311
  mcpServers: {
306
312
  gradio: {
307
313
  command: "npx",
308
- arguments: ["mcp-remote", mcp_server_url]
314
+ args: [
315
+ "mcp-remote",
316
+ mcp_server_url,
317
+ "--transport",
318
+ "sse-only"
319
+ ]
309
320
  }
310
321
  }
311
322
  },
@@ -316,7 +327,11 @@ onMount(() => {
316
327
  </code>
317
328
  </Block>
318
329
  <p>&nbsp;</p>
319
- <p>&nbsp;</p>
330
+ <p>
331
+ <a href={mcp_docs} target="_blank">
332
+ Read more about MCP in the Gradio docs
333
+ </a>
334
+ </p>
320
335
  {:else}
321
336
  This Gradio app can also serve as an MCP server, with an MCP
322
337
  tool corresponding to each API endpoint. To enable this, launch
@@ -1,14 +1,4 @@
1
1
  export { Gradio } from "@gradio/utils";
2
2
  export type I18nFormatter = typeof formatter;
3
- /**
4
- * i18n formatter with fallback to svelte-i18n's format function.
5
- *
6
- * @param value - The string to translate or format
7
- * @returns The translated string
8
- *
9
- * This formatter attempts translation in the following order:
10
- * 1. Direct translation of the input string
11
- * 2. Checks if input matches any common key names
12
- * 3. Falls back to svelte-i18n's format function
13
- */
14
3
  export declare function formatter(value: string | null | undefined): string;
4
+ export declare const reactive_formatter: import("svelte/store").Readable<typeof formatter>;
@@ -1,25 +1,13 @@
1
- import { format, _ } from "svelte-i18n";
2
- import { get } from "svelte/store";
3
1
  import { all_common_keys } from "./i18n";
2
+ import { _ } from "svelte-i18n";
3
+ import { get, derived } from "svelte/store";
4
4
  export { Gradio } from "@gradio/utils";
5
- /**
6
- * i18n formatter with fallback to svelte-i18n's format function.
7
- *
8
- * @param value - The string to translate or format
9
- * @returns The translated string
10
- *
11
- * This formatter attempts translation in the following order:
12
- * 1. Direct translation of the input string
13
- * 2. Checks if input matches any common key names
14
- * 3. Falls back to svelte-i18n's format function
15
- */
16
5
  export function formatter(value) {
17
6
  if (value == null) {
18
7
  return "";
19
8
  }
20
9
  const string_value = String(value);
21
10
  const translate = get(_);
22
- const initial_formatter = get(format);
23
11
  let direct_translation = translate(string_value);
24
12
  if (direct_translation !== string_value) {
25
13
  return direct_translation;
@@ -35,10 +23,6 @@ export function formatter(value) {
35
23
  break;
36
24
  }
37
25
  }
38
- // fall back to the svelte-i18n formatter to maintain compatibility
39
- const formatted = initial_formatter(string_value);
40
- if (formatted !== string_value) {
41
- return formatted;
42
- }
43
26
  return string_value;
44
27
  }
28
+ export const reactive_formatter = derived(_, () => formatter);
@@ -1,9 +1,16 @@
1
- type LangsRecord = Record<string, {
2
- [key: string]: any;
3
- }>;
1
+ export interface I18nData {
2
+ __type__: "translation_metadata";
3
+ key: string;
4
+ }
5
+ export interface LangsRecord {
6
+ [lang: string]: any;
7
+ }
8
+ export declare function is_translation_metadata(obj: any): obj is I18nData;
9
+ export declare function translate_if_needed(value: any): string;
4
10
  export declare function process_langs(): LangsRecord;
5
11
  export declare const language_choices: [string, string][];
6
12
  export declare let all_common_keys: Set<string>;
7
- export declare function setupi18n(): Promise<void>;
13
+ export declare function setupi18n(custom_translations?: Record<string, Record<string, string>>): Promise<void>;
8
14
  export declare function changeLocale(new_locale: string): void;
9
- export {};
15
+ export declare function get_initial_locale(browser_locale: string | null, available_locales: string[], fallback_locale?: string): string;
16
+ export declare function load_translations(translations: LangsRecord | null | undefined): void;
package/dist/src/i18n.js CHANGED
@@ -1,27 +1,87 @@
1
- import { addMessages, init, getLocaleFromNavigator, locale, _ } from "svelte-i18n";
1
+ import { addMessages, init, getLocaleFromNavigator, locale } from "svelte-i18n";
2
+ import { formatter } from "./gradio_helper";
2
3
  const langs = import.meta.glob("./lang/*.json", {
3
4
  eager: true
4
5
  });
5
- export function process_langs() {
6
- let _langs = {};
7
- for (const lang in langs) {
8
- const code = lang.split("/").pop().split(".").shift();
9
- _langs[code] = langs[lang].default;
6
+ export function is_translation_metadata(obj) {
7
+ console.log(obj);
8
+ const result = obj &&
9
+ typeof obj === "object" &&
10
+ obj.__type__ === "translation_metadata" &&
11
+ typeof obj.key === "string";
12
+ return result;
13
+ }
14
+ // handles strings with embedded JSON metadata of shape "__i18n__{"key": "some.key"}"
15
+ export function translate_if_needed(value) {
16
+ if (typeof value !== "string") {
17
+ return value;
18
+ }
19
+ const i18n_marker = "__i18n__";
20
+ const marker_index = value.indexOf(i18n_marker);
21
+ if (marker_index === -1) {
22
+ return value;
23
+ }
24
+ try {
25
+ const before_marker = marker_index > 0 ? value.substring(0, marker_index) : "";
26
+ const after_marker_index = marker_index + i18n_marker.length;
27
+ const json_start = value.indexOf("{", after_marker_index);
28
+ let json_end = -1;
29
+ let bracket_count = 0;
30
+ for (let i = json_start; i < value.length; i++) {
31
+ if (value[i] === "{")
32
+ bracket_count++;
33
+ if (value[i] === "}")
34
+ bracket_count--;
35
+ if (bracket_count === 0) {
36
+ json_end = i + 1;
37
+ break;
38
+ }
39
+ }
40
+ if (json_end === -1) {
41
+ console.error("Could not find end of JSON in i18n string");
42
+ return value;
43
+ }
44
+ const metadata_json = value.substring(json_start, json_end);
45
+ const after_json = json_end < value.length ? value.substring(json_end) : "";
46
+ try {
47
+ const metadata = JSON.parse(metadata_json);
48
+ if (metadata && metadata.key) {
49
+ const translated = formatter(metadata.key);
50
+ return before_marker + translated + after_json;
51
+ }
52
+ }
53
+ catch (jsonError) {
54
+ console.error("Error parsing i18n JSON:", jsonError);
55
+ }
56
+ return value;
57
+ }
58
+ catch (e) {
59
+ console.error("Error processing translation:", e);
60
+ return value;
10
61
  }
11
- return _langs;
62
+ }
63
+ export function process_langs() {
64
+ return Object.fromEntries(Object.entries(langs).map(([path, module]) => [
65
+ path.split("/").pop().split(".")[0],
66
+ module.default
67
+ ]));
12
68
  }
13
69
  const processed_langs = process_langs();
14
70
  const available_locales = Object.keys(processed_langs);
15
71
  export const language_choices = Object.entries(processed_langs).map(([code, data]) => [data._name || code, code]);
16
72
  export let all_common_keys = new Set();
17
- for (const lang in processed_langs) {
18
- addMessages(lang, processed_langs[lang]);
19
- }
20
73
  let i18n_initialized = false;
21
- export async function setupi18n() {
22
- if (i18n_initialized) {
74
+ let previous_translations;
75
+ export async function setupi18n(custom_translations) {
76
+ const should_reinitialize = i18n_initialized && custom_translations !== previous_translations;
77
+ if (i18n_initialized && !should_reinitialize) {
23
78
  return;
24
79
  }
80
+ previous_translations = custom_translations;
81
+ load_translations({
82
+ ...processed_langs,
83
+ ...(custom_translations ?? {})
84
+ });
25
85
  const browser_locale = getLocaleFromNavigator();
26
86
  let initial_locale = browser_locale && available_locales.includes(browser_locale)
27
87
  ? browser_locale
@@ -53,3 +113,24 @@ export async function setupi18n() {
53
113
  export function changeLocale(new_locale) {
54
114
  locale.set(new_locale);
55
115
  }
116
+ export function get_initial_locale(browser_locale, available_locales, fallback_locale = "en") {
117
+ if (!browser_locale)
118
+ return fallback_locale;
119
+ if (available_locales.includes(browser_locale)) {
120
+ return browser_locale;
121
+ }
122
+ return fallback_locale;
123
+ }
124
+ export function load_translations(translations) {
125
+ if (!translations) {
126
+ return;
127
+ }
128
+ try {
129
+ for (const lang in translations) {
130
+ addMessages(lang, translations[lang]);
131
+ }
132
+ }
133
+ catch (e) {
134
+ console.error("Error loading translations:", e);
135
+ }
136
+ }
package/dist/src/init.js CHANGED
@@ -24,7 +24,7 @@ export function create_components(initial_layout) {
24
24
  const layout_store = writable(initial_layout);
25
25
  let _components = [];
26
26
  let app;
27
- let keyed_component_values = {};
27
+ let keys_per_render_id = {};
28
28
  let _rootNode;
29
29
  function set_event_specific_args(dependencies) {
30
30
  dependencies.forEach((dep) => {
@@ -42,7 +42,6 @@ export function create_components(initial_layout) {
42
42
  // make sure the state is settled before proceeding
43
43
  flush();
44
44
  app = _app;
45
- store_keyed_values(_components);
46
45
  _components = components;
47
46
  inputs = new Set();
48
47
  outputs = new Set();
@@ -81,7 +80,20 @@ export function create_components(initial_layout) {
81
80
  * Rerender the layout when the config has been modified to attach new components
82
81
  */
83
82
  function rerender_layout({ render_id, components, layout, root, dependencies }) {
84
- let _constructor_map = preload_all_components(components, root);
83
+ let replacement_components = [];
84
+ let new_components = [];
85
+ console.log("old_keys", keys_per_render_id[render_id]);
86
+ console.log("new_keys", components.map((c) => c.key));
87
+ components.forEach((c) => {
88
+ if (c.key == null || !keys_per_render_id[render_id]?.includes(c.key)) {
89
+ new_components.push(c);
90
+ }
91
+ else {
92
+ replacement_components.push(c);
93
+ }
94
+ });
95
+ console.log(new_components.length, replacement_components.length);
96
+ let _constructor_map = preload_all_components(new_components, root);
85
97
  _constructor_map.forEach((v, k) => {
86
98
  constructor_map.set(k, v);
87
99
  });
@@ -104,17 +116,27 @@ export function create_components(initial_layout) {
104
116
  }
105
117
  };
106
118
  add_to_current_children(current_element);
107
- store_keyed_values(all_current_children);
108
119
  Object.entries(instance_map).forEach(([id, component]) => {
109
120
  let _id = Number(id);
110
121
  if (component.rendered_in === render_id) {
111
- delete instance_map[_id];
112
- if (_component_map.has(_id)) {
113
- _component_map.delete(_id);
122
+ let replacement_component = replacement_components.find((c) => c.key === component.key);
123
+ if (component.key != null && replacement_component !== undefined) {
124
+ const instance = instance_map[component.id];
125
+ for (const prop in replacement_component.props) {
126
+ if (!replacement_component.props.preserved_by_key?.includes(prop)) {
127
+ instance.props[prop] = replacement_component.props[prop];
128
+ }
129
+ }
130
+ }
131
+ else {
132
+ delete instance_map[_id];
133
+ if (_component_map.has(_id)) {
134
+ _component_map.delete(_id);
135
+ }
114
136
  }
115
137
  }
116
138
  });
117
- components.forEach((c) => {
139
+ new_components.forEach((c) => {
118
140
  instance_map[c.id] = c;
119
141
  _component_map.set(c.id, c);
120
142
  });
@@ -123,12 +145,17 @@ export function create_components(initial_layout) {
123
145
  }
124
146
  walk_layout(layout, root, _components.concat(components), current_element.parent).then(() => {
125
147
  layout_store.set(_rootNode);
148
+ keys_per_render_id[render_id] = components
149
+ .map((c) => c.key)
150
+ .filter((c) => c != null);
126
151
  });
127
152
  set_event_specific_args(dependencies);
128
153
  }
129
154
  async function walk_layout(node, root, components, parent) {
130
155
  const instance = instance_map[node.id];
131
- instance.component = (await constructor_map.get(instance.component_class_id || instance.type))?.default;
156
+ if (!instance.component) {
157
+ instance.component = (await constructor_map.get(instance.component_class_id || instance.type))?.default;
158
+ }
132
159
  instance.parent = parent;
133
160
  if (instance.type === "dataset") {
134
161
  instance.props.component_map = get_component(instance.type, instance.component_class_id, root, components, instance.props.components).example_components;
@@ -138,10 +165,6 @@ export function create_components(initial_layout) {
138
165
  }
139
166
  instance.props.interactive = determine_interactivity(instance.id, instance.props.interactive, instance.props.value, inputs, outputs);
140
167
  instance.props.server = process_server_fn(instance.id, instance.props.server_fns, app);
141
- if (instance.key != null &&
142
- keyed_component_values[instance.key] !== undefined) {
143
- instance.props.value = keyed_component_values[instance.key];
144
- }
145
168
  _component_map.set(instance.id, instance);
146
169
  if (node.children) {
147
170
  instance.children = await Promise.all(node.children.map((v) => walk_layout(v, root, components, instance)));
@@ -178,13 +201,6 @@ export function create_components(initial_layout) {
178
201
  }
179
202
  let update_scheduled = false;
180
203
  let update_scheduled_store = writable(false);
181
- function store_keyed_values(components) {
182
- components.forEach((c) => {
183
- if (c.key != null) {
184
- keyed_component_values[c.key] = c.props.value;
185
- }
186
- });
187
- }
188
204
  function flush() {
189
205
  layout_store.update((layout) => {
190
206
  for (let i = 0; i < pending_updates.length; i++) {
@@ -98,7 +98,8 @@
98
98
  "runtime_error": "there is a runtime error",
99
99
  "space_not_working": "\"Space isn't working because\" {0}",
100
100
  "space_paused": "the space is paused",
101
- "use_via_api": "Use via API"
101
+ "use_via_api": "Use via API",
102
+ "use_via_api_or_mcp": "Use via API or MCP"
102
103
  },
103
104
  "file": {
104
105
  "uploading": "Uploading..."
@@ -88,7 +88,8 @@
88
88
  "runtime_error": "hay un error de ejecución",
89
89
  "space_not_working": "\"El Space no funciona porque\" {0}",
90
90
  "space_paused": "el space está pausado",
91
- "use_via_api": "Usar vía API"
91
+ "use_via_api": "Usar vía API",
92
+ "use_via_api_or_mcp": "Usar vía API o MCP"
92
93
  },
93
94
  "file": {
94
95
  "uploading": "Subiendo..."
@@ -89,7 +89,8 @@
89
89
  "runtime_error": "il y a une erreur d'exécution",
90
90
  "space_not_working": "\"Le Space ne fonctionne pas car\" {0}",
91
91
  "space_paused": "le Space est en pause",
92
- "use_via_api": "Utiliser via l'API"
92
+ "use_via_api": "Utiliser via API",
93
+ "use_via_api_or_mcp": "Utiliser via API ou MCP"
93
94
  },
94
95
  "file": {
95
96
  "uploading": "Téléchargement..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "ランタイムエラーがあります",
88
88
  "space_not_working": "\"Spaceが動作していません。理由:\" {0}",
89
89
  "space_paused": "Spaceが一時停止されています",
90
- "use_via_api": "APIを介して使用"
90
+ "use_via_api": "APIを介して使用",
91
+ "use_via_api_or_mcp": "APIまたはMCP経由で使用"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "アップロード中..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "런타임 오류가 있습니다",
88
88
  "space_not_working": "\"Space가 작동하지 않는 이유:\" {0}",
89
89
  "space_paused": "space가 일시 중지되었습니다",
90
- "use_via_api": "API를 통해 사용"
90
+ "use_via_api": "API를 통해 사용",
91
+ "use_via_api_or_mcp": "API 또는 MCP를 통해 사용"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "업로드 중..."
@@ -97,7 +97,8 @@
97
97
  "runtime_error": "yra vykdymo klaida",
98
98
  "space_not_working": "\"Erdvė neveikia, nes\" {0}",
99
99
  "space_paused": "erdvė yra pristabdyta",
100
- "use_via_api": "Naudoti per API"
100
+ "use_via_api": "Naudoti per API",
101
+ "use_via_api_or_mcp": "Naudoti per API arba MCP"
101
102
  },
102
103
  "file": {
103
104
  "uploading": "Įkeliama..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Det er en kjøretidsfeil",
88
88
  "space_not_working": "\"Space fungerer ikke fordi\" {0}",
89
89
  "space_paused": "Space er pauset",
90
- "use_via_api": "Bruk via API"
90
+ "use_via_api": "Bruk via API",
91
+ "use_via_api_or_mcp": "Bruk via API eller MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "Laster opp..."
@@ -97,7 +97,8 @@
97
97
  "runtime_error": "Er is een runtime-fout",
98
98
  "space_not_working": "\"Space werkt niet omdat\" {0}",
99
99
  "space_paused": "De Space is gepauzeerd",
100
- "use_via_api": "Gebruik via API"
100
+ "use_via_api": "Gebruik via API",
101
+ "use_via_api_or_mcp": "Gebruik via API of MCP"
101
102
  },
102
103
  "file": {
103
104
  "uploading": "Uploaden..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Wystąpił błąd wykonania",
88
88
  "space_not_working": "\"Space nie działa, ponieważ\" {0}",
89
89
  "space_paused": "Space jest wstrzymany",
90
- "use_via_api": "Użyj przez API"
90
+ "use_via_api": "Użyj przez API",
91
+ "use_via_api_or_mcp": "Użyj przez API lub MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "Przesyłanie..."
@@ -98,6 +98,7 @@
98
98
  "space_not_working": "\"O Space não está funcionando porque\" {0}",
99
99
  "space_paused": "O Space está pausado",
100
100
  "use_via_api": "Usar via API",
101
+ "use_via_api_or_mcp": "Usar via API ou MCP",
101
102
  "runtime_error": "Houve um erro de execução"
102
103
  },
103
104
  "file": {
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Há um erro de execução",
88
88
  "space_not_working": "\"O Space não está a funcionar porque\" {0}",
89
89
  "space_paused": "O Space está em pausa",
90
- "use_via_api": "Utilizar via API"
90
+ "use_via_api": "Usar via API",
91
+ "use_via_api_or_mcp": "Usar via API ou MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "A carregar..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Există o eroare de execuție",
88
88
  "space_not_working": "\"Space-ul nu funcționează deoarece\" {0}",
89
89
  "space_paused": "Space-ul este în pauză",
90
- "use_via_api": "Utilizați prin API"
90
+ "use_via_api": "Utilizați prin API",
91
+ "use_via_api_or_mcp": "Utilizați prin API sau MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "Se încarcă..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Произошла ошибка выполнения",
88
88
  "space_not_working": "\"Space не работает, потому что\" {0}",
89
89
  "space_paused": "Space приостановлен",
90
- "use_via_api": "Использовать через API"
90
+ "use_via_api": "Использовать через API",
91
+ "use_via_api_or_mcp": "Использовать через API или MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "Загрузка..."
@@ -87,7 +87,8 @@
87
87
  "runtime_error": "Det finns ett körtidsfel",
88
88
  "space_not_working": "\"Space fungerar inte eftersom\" {0}",
89
89
  "space_paused": "Space är pausat",
90
- "use_via_api": "Använd via API"
90
+ "use_via_api": "Använd via API",
91
+ "use_via_api_or_mcp": "Använd via API eller MCP"
91
92
  },
92
93
  "file": {
93
94
  "uploading": "Laddar upp..."