-
diff --git a/src/core/plugins/i18n/actions.js b/src/core/plugins/i18n/actions.js
new file mode 100644
index 00000000000..a1562d952d7
--- /dev/null
+++ b/src/core/plugins/i18n/actions.js
@@ -0,0 +1,20 @@
+/**
+ * @prettier
+ */
+
+export const SET_LOCALE = "i18n_set_locale"
+export const LOAD_MESSAGES = "i18n_load_messages"
+
+export function setLocale(locale) {
+ return {
+ type: SET_LOCALE,
+ payload: locale,
+ }
+}
+
+export function loadMessages(locale, messages) {
+ return {
+ type: LOAD_MESSAGES,
+ payload: { locale, messages },
+ }
+}
diff --git a/src/core/plugins/i18n/fn.js b/src/core/plugins/i18n/fn.js
new file mode 100644
index 00000000000..046c6468a87
--- /dev/null
+++ b/src/core/plugins/i18n/fn.js
@@ -0,0 +1,40 @@
+/**
+ * @prettier
+ */
+import en from "./locales/en"
+
+/**
+ * Pure translation helper.
+ * Looks up `key` in `localeMsgs` (a plain JS object), then falls back to
+ * `fallbackMsgs`. Interpolates `{{varName}}` placeholders with values from
+ * `vars`. Returns the key itself when no match is found.
+ *
+ * @param {object} localeMsgs - Key→value map for the active locale (may be null/undefined)
+ * @param {object} fallbackMsgs - Key→value map for the fallback locale (usually "en")
+ * @param {string} key - Message key, e.g. "button.cancel"
+ * @param {object} [vars] - Interpolation variables, e.g. { line: 42 }
+ * @returns {string}
+ */
+export function translate(localeMsgs, fallbackMsgs, key, vars) {
+ const own = Object.prototype.hasOwnProperty
+ const raw =
+ localeMsgs && own.call(localeMsgs, key)
+ ? localeMsgs[key]
+ : fallbackMsgs && own.call(fallbackMsgs, key)
+ ? fallbackMsgs[key]
+ : key
+
+ if (!vars) return String(raw)
+ return String(raw).replace(/\{\{(\w+)\}\}/g, (_, k) =>
+ own.call(vars, k) ? String(vars[k]) : `{{${k}}}`
+ )
+}
+
+/**
+ * Default translation function that uses the built-in English locale.
+ * Used as a fallback in components when no `t` prop is injected (e.g. in
+ * unit tests that do not go through the Redux system).
+ */
+export function fallbackT(key, vars) {
+ return translate(null, en, key, vars)
+}
diff --git a/src/core/plugins/i18n/index.js b/src/core/plugins/i18n/index.js
new file mode 100644
index 00000000000..21e696a9186
--- /dev/null
+++ b/src/core/plugins/i18n/index.js
@@ -0,0 +1,75 @@
+/**
+ * @prettier
+ */
+import reducers from "./reducers"
+import * as actions from "./actions"
+import * as selectors from "./selectors"
+import en from "./locales/en"
+import builtinLocales from "./locales"
+import win from "core/window"
+
+export default function I18nPlugin() {
+ return {
+ afterLoad(system) {
+ // ── 1. Load built-in English messages ────────────────────────────────
+ system.i18nActions.loadMessages("en", en)
+
+ // ── 2. Determine locale ──────────────────────────────────────────────
+ const { locale: configLocale } = system.getConfigs()
+ let locale
+ if (configLocale) {
+ // Normalize configured locale to base language code, same as auto-detection
+ locale = configLocale.split("-")[0].toLowerCase()
+ } else {
+ const browserLang =
+ (win.navigator &&
+ win.navigator.languages &&
+ win.navigator.languages[0]) ||
+ (win.navigator && win.navigator.language) ||
+ "en"
+ locale = browserLang.split("-")[0].toLowerCase()
+ }
+ system.i18nActions.setLocale(locale)
+
+ // ── 3. Auto-load matching built-in locale (if any) ───────────────────
+ if (locale !== "en" && builtinLocales[locale]) {
+ system.i18nActions.loadMessages(locale, builtinLocales[locale])
+ }
+
+ // ── 4. Register the t() translation function ─────────────────────────
+ this.rootInjects = this.rootInjects || {}
+ const own = Object.prototype.hasOwnProperty
+ this.rootInjects.t = (key, vars) => {
+ const allMessages = system.i18nSelectors.getMessages()
+ const currentLocale = system.i18nSelectors.getLocale()
+
+ // Use Immutable-native lookups — avoids expensive .toJS() on every call
+ const localeMap = allMessages.get(currentLocale)
+ const enMap = allMessages.get("en")
+
+ let raw
+ if (localeMap && localeMap.has(key)) {
+ raw = localeMap.get(key)
+ } else if (enMap && enMap.has(key)) {
+ raw = enMap.get(key)
+ } else {
+ // Ultimate fallback: static en object (always available without Redux)
+ raw = own.call(en, key) ? en[key] : key
+ }
+
+ if (!vars) return String(raw)
+ return String(raw).replace(/\{\{(\w+)\}\}/g, (_, k) =>
+ own.call(vars, k) ? String(vars[k]) : `{{${k}}}`
+ )
+ }
+ },
+
+ statePlugins: {
+ i18n: {
+ reducers,
+ actions,
+ selectors,
+ },
+ },
+ }
+}
diff --git a/src/core/plugins/i18n/locales/ca.js b/src/core/plugins/i18n/locales/ca.js
new file mode 100644
index 00000000000..9d6b0fa4d75
--- /dev/null
+++ b/src/core/plugins/i18n/locales/ca.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Catalan (Català) message catalog.
+ */
+const ca = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autoritza",
+ "button.cancel": "Cancel·la",
+ "button.clear": "Neteja",
+ "button.close": "Tanca",
+ "button.copy_to_clipboard": "Copia al porta-retalls",
+ "button.download_file": "Descarrega el fitxer",
+ "button.edit": "Edita",
+ "button.execute": "Executa",
+ "button.explore": "Explora",
+ "button.hide": "Amaga",
+ "button.logout": "Tanca sessió",
+ "button.reset": "Restableix",
+ "button.show": "Mostra",
+ "button.try_it_out": "Prova-ho",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Codi",
+ "label.description": "Descripció",
+ "label.details": "Detalls",
+ "label.examples": "Exemples",
+ "label.headers": "Capçaleres:",
+ "label.links": "Enllaços",
+ "label.media_type": "Tipus de mitjà",
+ "label.models": "Models",
+ "label.name": "Nom",
+ "label.no_links": "Sense enllaços",
+ "label.no_parameters": "Sense paràmetres",
+ "label.parameter_content_type": "Tipus de contingut del paràmetre",
+ "label.parameters": "Paràmetres",
+ "label.request_body": "Cos de la sol·licitud",
+ "label.request_duration": "Durada de la sol·licitud",
+ "label.request_url": "URL de la sol·licitud",
+ "label.response_body": "Cos de la resposta",
+ "label.response_content_type": "Tipus de contingut de la resposta",
+ "label.response_headers": "Capçaleres de la resposta",
+ "label.responses": "Respostes",
+ "label.schemas": "Esquemes",
+ "label.server_response": "Resposta del servidor",
+ "label.snippets": "Fragments",
+ "label.type": "Tipus",
+ "label.undocumented": "No documentat",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "A:",
+ "auth.api_key_name": "Nom:",
+ "auth.api_key_value": "Valor:",
+ "auth.application": "Aplicació:",
+ "auth.authorization_header": "Capçalera d'autorització",
+ "auth.authorization_url": "URL d'autorització:",
+ "auth.authorized": "Autoritzat",
+ "auth.basic_authorization_title": "Autorització bàsica",
+ "auth.client_credentials_location": "Ubicació de les credencials del client:",
+ "auth.flow": "Flux:",
+ "auth.openid_connect_url": "URL de connexió OpenID:",
+ "auth.password": "contrasenya:",
+ "auth.password_cap": "Contrasenya:",
+ "auth.request_body_option": "Cos de la sol·licitud",
+ "auth.scopes_description":
+ "Els àmbits s'utilitzen per atorgar a una aplicació diferents nivells d'accés a les dades en nom de l'usuari final. Cada API pot declarar un o més àmbits.",
+ "auth.scopes_required":
+ "L'API requereix els àmbits següents. Seleccioneu quins voleu atorgar a Swagger UI.",
+ "auth.scopes_title": "Àmbits:",
+ "auth.select_all": "selecciona-ho tot",
+ "auth.select_none": "no en seleccionis cap",
+ "auth.token_url": "URL del testimoni:",
+ "auth.username": "nom d'usuari:",
+ "auth.username_cap": "Nom d'usuari:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Aplica les credencials",
+ "aria.apply_oauth2_credentials": "Aplica les credencials OAuth2 indicades",
+ "aria.authorization_button_locked": "botó d'autorització bloquejat",
+ "aria.authorization_button_unlocked": "botó d'autorització desbloquejat",
+ "aria.collapse_operation": "Replega l'operació",
+ "aria.expand_operation": "Expandeix l'operació",
+ "aria.remove_authorization": "Elimina l'autorització",
+ "aria.request_content_type": "Tipus de contingut de la sol·licitud",
+ "aria.response_content_type": "Tipus de contingut de la resposta",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Vés a la línia {{line}}",
+ "errors.title": "Errors",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtra per etiqueta",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Controla la capçalera ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "No es pot analitzar el JSON. Resultat sense format:\n\n",
+ "response.no_blob_support":
+ "S'han detectat capçaleres de descàrrega, però el vostre navegador no suporta la descàrrega de dades binàries via XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Tipus de resposta no reconegut; es mostra el contingut com a text.",
+ "response.unrecognized_type_unable_to_display":
+ "Tipus de resposta no reconegut; no es pot mostrar.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Selecciona una definició",
+}
+
+export default ca
diff --git a/src/core/plugins/i18n/locales/de.js b/src/core/plugins/i18n/locales/de.js
new file mode 100644
index 00000000000..89d664c06cf
--- /dev/null
+++ b/src/core/plugins/i18n/locales/de.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * German (Deutsch) message catalog.
+ */
+const de = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autorisieren",
+ "button.cancel": "Abbrechen",
+ "button.clear": "Löschen",
+ "button.close": "Schließen",
+ "button.copy_to_clipboard": "In die Zwischenablage kopieren",
+ "button.download_file": "Datei herunterladen",
+ "button.edit": "Bearbeiten",
+ "button.execute": "Ausführen",
+ "button.explore": "Erkunden",
+ "button.hide": "Verbergen",
+ "button.logout": "Abmelden",
+ "button.reset": "Zurücksetzen",
+ "button.show": "Anzeigen",
+ "button.try_it_out": "Ausprobieren",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Code",
+ "label.description": "Beschreibung",
+ "label.details": "Details",
+ "label.examples": "Beispiele",
+ "label.headers": "Header:",
+ "label.links": "Links",
+ "label.media_type": "Medientyp",
+ "label.models": "Modelle",
+ "label.name": "Name",
+ "label.no_links": "Keine Links",
+ "label.no_parameters": "Keine Parameter",
+ "label.parameter_content_type": "Parameter-Inhaltstyp",
+ "label.parameters": "Parameter",
+ "label.request_body": "Anfrage-Body",
+ "label.request_duration": "Anfragedauer",
+ "label.request_url": "Anfrage-URL",
+ "label.response_body": "Antwort-Body",
+ "label.response_content_type": "Antwort-Inhaltstyp",
+ "label.response_headers": "Antwortheader",
+ "label.responses": "Antworten",
+ "label.schemas": "Schemas",
+ "label.server_response": "Serverantwort",
+ "label.snippets": "Snippets",
+ "label.type": "Typ",
+ "label.undocumented": "Nicht dokumentiert",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "In:",
+ "auth.api_key_name": "Name:",
+ "auth.api_key_value": "Wert:",
+ "auth.application": "Anwendung:",
+ "auth.authorization_header": "Autorisierungsheader",
+ "auth.authorization_url": "Autorisierungs-URL:",
+ "auth.authorized": "Autorisiert",
+ "auth.basic_authorization_title": "Basisautorisierung",
+ "auth.client_credentials_location": "Speicherort der Client-Anmeldedaten:",
+ "auth.flow": "Flow:",
+ "auth.openid_connect_url": "OpenID Connect-URL:",
+ "auth.password": "Passwort:",
+ "auth.password_cap": "Passwort:",
+ "auth.request_body_option": "Anfrage-Body",
+ "auth.scopes_description":
+ "Scopes werden verwendet, um einer Anwendung verschiedene Zugriffsebenen auf Daten im Namen des Endbenutzers zu gewähren. Jede API kann einen oder mehrere Scopes deklarieren.",
+ "auth.scopes_required":
+ "Die API erfordert die folgenden Scopes. Wählen Sie aus, welche Sie Swagger UI gewähren möchten.",
+ "auth.scopes_title": "Scopes:",
+ "auth.select_all": "Alle auswählen",
+ "auth.select_none": "Keine auswählen",
+ "auth.token_url": "Token-URL:",
+ "auth.username": "Benutzername:",
+ "auth.username_cap": "Benutzername:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Anmeldedaten anwenden",
+ "aria.apply_oauth2_credentials": "Angegebene OAuth2-Anmeldedaten anwenden",
+ "aria.authorization_button_locked": "Autorisierungsschaltfläche gesperrt",
+ "aria.authorization_button_unlocked": "Autorisierungsschaltfläche entsperrt",
+ "aria.collapse_operation": "Operation einklappen",
+ "aria.expand_operation": "Operation ausklappen",
+ "aria.remove_authorization": "Autorisierung entfernen",
+ "aria.request_content_type": "Anfrage-Inhaltstyp",
+ "aria.response_content_type": "Antwort-Inhaltstyp",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Zur Zeile {{line}} springen",
+ "errors.title": "Fehler",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Nach Tag filtern",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Steuert den ",
+ "response.controls_accept_header_suffix": "-Header.",
+ "response.json_parse_error":
+ "JSON konnte nicht verarbeitet werden. Rohergebnis:\n\n",
+ "response.no_blob_support":
+ "Download-Header erkannt, aber Ihr Browser unterstützt kein Herunterladen von Binärdaten via XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Unbekannter Antworttyp; Inhalt wird als Text angezeigt.",
+ "response.unrecognized_type_unable_to_display":
+ "Unbekannter Antworttyp; kann nicht angezeigt werden.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Definition auswählen",
+}
+
+export default de
diff --git a/src/core/plugins/i18n/locales/en.js b/src/core/plugins/i18n/locales/en.js
new file mode 100644
index 00000000000..60b5989e251
--- /dev/null
+++ b/src/core/plugins/i18n/locales/en.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * English message catalog — the canonical reference and ultimate fallback.
+ * Keys use a namespaced dot-notation:
..
+ */
+const en = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Authorize",
+ "button.cancel": "Cancel",
+ "button.clear": "Clear",
+ "button.close": "Close",
+ "button.copy_to_clipboard": "Copy to clipboard",
+ "button.download_file": "Download file",
+ "button.edit": "Edit",
+ "button.execute": "Execute",
+ "button.explore": "Explore",
+ "button.hide": "Hide",
+ "button.logout": "Logout",
+ "button.reset": "Reset",
+ "button.show": "Show",
+ "button.try_it_out": "Try it out",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Code",
+ "label.description": "Description",
+ "label.details": "Details",
+ "label.examples": "Examples",
+ "label.headers": "Headers:",
+ "label.links": "Links",
+ "label.media_type": "Media type",
+ "label.models": "Models",
+ "label.name": "Name",
+ "label.no_links": "No links",
+ "label.no_parameters": "No parameters",
+ "label.parameter_content_type": "Parameter content type",
+ "label.parameters": "Parameters",
+ "label.request_body": "Request body",
+ "label.request_duration": "Request duration",
+ "label.request_url": "Request URL",
+ "label.response_body": "Response body",
+ "label.response_content_type": "Response content type",
+ "label.response_headers": "Response headers",
+ "label.responses": "Responses",
+ "label.schemas": "Schemas",
+ "label.server_response": "Server response",
+ "label.snippets": "Snippets",
+ "label.type": "Type",
+ "label.undocumented": "Undocumented",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "In:",
+ "auth.api_key_name": "Name:",
+ "auth.api_key_value": "Value:",
+ "auth.application": "Application:",
+ "auth.authorization_header": "Authorization header",
+ "auth.authorization_url": "Authorization URL:",
+ "auth.authorized": "Authorized",
+ "auth.basic_authorization_title": "Basic authorization",
+ "auth.client_credentials_location": "Client credentials location:",
+ "auth.flow": "Flow:",
+ "auth.openid_connect_url": "OpenID Connect URL:",
+ "auth.password": "password:",
+ "auth.password_cap": "Password:",
+ "auth.request_body_option": "Request body",
+ "auth.scopes_description":
+ "Scopes are used to grant an application different levels of access to data on behalf of the end user. Each API may declare one or more scopes.",
+ "auth.scopes_required":
+ "API requires the following scopes. Select which ones you want to grant to Swagger UI.",
+ "auth.scopes_title": "Scopes:",
+ "auth.select_all": "select all",
+ "auth.select_none": "select none",
+ "auth.token_url": "Token URL:",
+ "auth.username": "username:",
+ "auth.username_cap": "Username:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Apply credentials",
+ "aria.apply_oauth2_credentials": "Apply given OAuth2 credentials",
+ "aria.authorization_button_locked": "authorization button locked",
+ "aria.authorization_button_unlocked": "authorization button unlocked",
+ "aria.collapse_operation": "Collapse operation",
+ "aria.expand_operation": "Expand operation",
+ "aria.remove_authorization": "Remove authorization",
+ "aria.request_content_type": "Request content type",
+ "aria.response_content_type": "Response content type",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Jump to line {{line}}",
+ "errors.title": "Errors",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filter by tag",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Controls ",
+ "response.controls_accept_header_suffix": " header.",
+ "response.json_parse_error": "Can't parse JSON. Raw result:\n\n",
+ "response.no_blob_support":
+ "Download headers detected but your browser does not support downloading binary via XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Unrecognized response type; displaying content as text.",
+ "response.unrecognized_type_unable_to_display":
+ "Unrecognized response type; unable to display.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Select a definition",
+}
+
+export default en
diff --git a/src/core/plugins/i18n/locales/es.js b/src/core/plugins/i18n/locales/es.js
new file mode 100644
index 00000000000..f52b7b66759
--- /dev/null
+++ b/src/core/plugins/i18n/locales/es.js
@@ -0,0 +1,114 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Spanish (Español) message catalog.
+ */
+const es = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autorizar",
+ "button.cancel": "Cancelar",
+ "button.clear": "Limpiar",
+ "button.close": "Cerrar",
+ "button.copy_to_clipboard": "Copiar al portapapeles",
+ "button.download_file": "Descargar archivo",
+ "button.edit": "Editar",
+ "button.execute": "Ejecutar",
+ "button.explore": "Explorar",
+ "button.hide": "Ocultar",
+ "button.logout": "Cerrar sesión",
+ "button.reset": "Restablecer",
+ "button.show": "Mostrar",
+ "button.try_it_out": "Pruébalo",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Código",
+ "label.description": "Descripción",
+ "label.details": "Detalles",
+ "label.examples": "Ejemplos",
+ "label.headers": "Cabeceras:",
+ "label.links": "Vínculos",
+ "label.media_type": "Tipo de medio",
+ "label.models": "Modelos",
+ "label.name": "Nombre",
+ "label.no_links": "Sin vínculos",
+ "label.no_parameters": "Sin parámetros",
+ "label.parameter_content_type": "Tipo de contenido del parámetro",
+ "label.parameters": "Parámetros",
+ "label.request_body": "Cuerpo de la solicitud",
+ "label.request_duration": "Duración de la solicitud",
+ "label.request_url": "URL de la solicitud",
+ "label.response_body": "Cuerpo de la respuesta",
+ "label.response_content_type": "Tipo de contenido de la respuesta",
+ "label.response_headers": "Cabeceras de respuesta",
+ "label.responses": "Respuestas",
+ "label.schemas": "Esquemas",
+ "label.server_response": "Respuesta del servidor",
+ "label.snippets": "Fragmentos",
+ "label.type": "Tipo",
+ "label.undocumented": "No documentado",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "En:",
+ "auth.api_key_name": "Nombre:",
+ "auth.api_key_value": "Valor:",
+ "auth.application": "Aplicación:",
+ "auth.authorization_header": "Cabecera de autorización",
+ "auth.authorization_url": "URL de autorización:",
+ "auth.authorized": "Autorizado",
+ "auth.basic_authorization_title": "Autorización básica",
+ "auth.client_credentials_location": "Ubicación de credenciales del cliente:",
+ "auth.flow": "Flujo:",
+ "auth.openid_connect_url": "URL de OpenID Connect:",
+ "auth.password": "contraseña:",
+ "auth.password_cap": "Contraseña:",
+ "auth.request_body_option": "Cuerpo de la solicitud",
+ "auth.scopes_description":
+ "Los scopes se utilizan para otorgar a una aplicación diferentes niveles de acceso a los datos en nombre del usuario final. Cada API puede declarar uno o más scopes.",
+ "auth.scopes_required":
+ "La API requiere los siguientes scopes. Seleccione cuáles desea otorgar a Swagger UI.",
+ "auth.scopes_title": "Scopes:",
+ "auth.select_all": "seleccionar todos",
+ "auth.select_none": "seleccionar ninguno",
+ "auth.token_url": "URL del token:",
+ "auth.username": "nombre de usuario:",
+ "auth.username_cap": "Nombre de usuario:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Aplicar credenciales",
+ "aria.apply_oauth2_credentials":
+ "Aplicar las credenciales OAuth2 proporcionadas",
+ "aria.authorization_button_locked": "botón de autorización bloqueado",
+ "aria.authorization_button_unlocked": "botón de autorización desbloqueado",
+ "aria.collapse_operation": "Contraer operación",
+ "aria.expand_operation": "Expandir operación",
+ "aria.remove_authorization": "Eliminar autorización",
+ "aria.request_content_type": "Tipo de contenido de la solicitud",
+ "aria.response_content_type": "Tipo de contenido de la respuesta",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Saltar a la línea {{line}}",
+ "errors.title": "Errores",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtrar por etiqueta",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Controla la cabecera ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "No se puede analizar el JSON. Resultado sin formato:\n\n",
+ "response.no_blob_support":
+ "Encabezados de descarga detectados, pero su navegador no es compatible con la descarga de datos binarios mediante XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Tipo de respuesta no reconocido; mostrando contenido como texto.",
+ "response.unrecognized_type_unable_to_display":
+ "Tipo de respuesta no reconocido; no se puede mostrar.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Seleccionar una definición",
+}
+
+export default es
diff --git a/src/core/plugins/i18n/locales/fr.js b/src/core/plugins/i18n/locales/fr.js
new file mode 100644
index 00000000000..1688322cb21
--- /dev/null
+++ b/src/core/plugins/i18n/locales/fr.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * French (Français) message catalog.
+ */
+const fr = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autoriser",
+ "button.cancel": "Annuler",
+ "button.clear": "Effacer",
+ "button.close": "Fermer",
+ "button.copy_to_clipboard": "Copier dans le presse-papiers",
+ "button.download_file": "Télécharger le fichier",
+ "button.edit": "Modifier",
+ "button.execute": "Exécuter",
+ "button.explore": "Explorer",
+ "button.hide": "Masquer",
+ "button.logout": "Se déconnecter",
+ "button.reset": "Réinitialiser",
+ "button.show": "Afficher",
+ "button.try_it_out": "Essayer",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Code",
+ "label.description": "Description",
+ "label.details": "Détails",
+ "label.examples": "Exemples",
+ "label.headers": "En-têtes :",
+ "label.links": "Liens",
+ "label.media_type": "Type de média",
+ "label.models": "Modèles",
+ "label.name": "Nom",
+ "label.no_links": "Aucun lien",
+ "label.no_parameters": "Aucun paramètre",
+ "label.parameter_content_type": "Type de contenu du paramètre",
+ "label.parameters": "Paramètres",
+ "label.request_body": "Corps de la requête",
+ "label.request_duration": "Durée de la requête",
+ "label.request_url": "URL de la requête",
+ "label.response_body": "Corps de la réponse",
+ "label.response_content_type": "Type de contenu de la réponse",
+ "label.response_headers": "En-têtes de réponse",
+ "label.responses": "Réponses",
+ "label.schemas": "Schémas",
+ "label.server_response": "Réponse du serveur",
+ "label.snippets": "Extraits",
+ "label.type": "Type",
+ "label.undocumented": "Non documenté",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "Dans :",
+ "auth.api_key_name": "Nom :",
+ "auth.api_key_value": "Valeur :",
+ "auth.application": "Application :",
+ "auth.authorization_header": "En-tête d'autorisation",
+ "auth.authorization_url": "URL d'autorisation :",
+ "auth.authorized": "Autorisé",
+ "auth.basic_authorization_title": "Autorisation de base",
+ "auth.client_credentials_location": "Emplacement des identifiants client :",
+ "auth.flow": "Flux :",
+ "auth.openid_connect_url": "URL OpenID Connect :",
+ "auth.password": "mot de passe :",
+ "auth.password_cap": "Mot de passe :",
+ "auth.request_body_option": "Corps de la requête",
+ "auth.scopes_description":
+ "Les scopes sont utilisés pour accorder à une application différents niveaux d'accès aux données au nom de l'utilisateur final. Chaque API peut déclarer un ou plusieurs scopes.",
+ "auth.scopes_required":
+ "L'API nécessite les scopes suivants. Sélectionnez ceux que vous souhaitez accorder à Swagger UI.",
+ "auth.scopes_title": "Scopes :",
+ "auth.select_all": "tout sélectionner",
+ "auth.select_none": "ne rien sélectionner",
+ "auth.token_url": "URL du token :",
+ "auth.username": "nom d'utilisateur :",
+ "auth.username_cap": "Nom d'utilisateur :",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Appliquer les identifiants",
+ "aria.apply_oauth2_credentials": "Appliquer les identifiants OAuth2 fournis",
+ "aria.authorization_button_locked": "bouton d'autorisation verrouillé",
+ "aria.authorization_button_unlocked": "bouton d'autorisation déverrouillé",
+ "aria.collapse_operation": "Réduire l'opération",
+ "aria.expand_operation": "Développer l'opération",
+ "aria.remove_authorization": "Supprimer l'autorisation",
+ "aria.request_content_type": "Type de contenu de la requête",
+ "aria.response_content_type": "Type de contenu de la réponse",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Aller à la ligne {{line}}",
+ "errors.title": "Erreurs",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtrer par étiquette",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Contrôle l'en-tête ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "Impossible d'analyser le JSON. Résultat brut\u00a0:\n\n",
+ "response.no_blob_support":
+ "En-têtes de téléchargement détectés, mais votre navigateur ne prend pas en charge le téléchargement de données binaires via XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Type de réponse non reconnu\u00a0; affichage du contenu en texte.",
+ "response.unrecognized_type_unable_to_display":
+ "Type de réponse non reconnu\u00a0; impossible d'afficher.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Sélectionner une définition",
+}
+
+export default fr
diff --git a/src/core/plugins/i18n/locales/index.js b/src/core/plugins/i18n/locales/index.js
new file mode 100644
index 00000000000..9c76d38119c
--- /dev/null
+++ b/src/core/plugins/i18n/locales/index.js
@@ -0,0 +1,27 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Built-in locale catalogs bundled with Swagger UI.
+ * Exported as a plain object keyed by BCP 47 base language code.
+ */
+import en from "./en"
+import ca from "./ca"
+import de from "./de"
+import es from "./es"
+import fr from "./fr"
+import is from "./is"
+import it from "./it"
+import ja from "./ja"
+import ka from "./ka"
+import ko from "./ko"
+import pl from "./pl"
+import pt from "./pt"
+import ru from "./ru"
+import tr from "./tr"
+import zh from "./zh"
+
+const builtinLocales = { en, ca, de, es, fr, is, it, ja, ka, ko, pl, pt, ru, tr, zh }
+
+export default builtinLocales
diff --git a/src/core/plugins/i18n/locales/is.js b/src/core/plugins/i18n/locales/is.js
new file mode 100644
index 00000000000..106570cfe99
--- /dev/null
+++ b/src/core/plugins/i18n/locales/is.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Icelandic (Íslenska) message catalog.
+ */
+const is = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Heimila",
+ "button.cancel": "Hætta við",
+ "button.clear": "Hreinsa",
+ "button.close": "Loka",
+ "button.copy_to_clipboard": "Afrita á klippiborð",
+ "button.download_file": "Sækja skrá",
+ "button.edit": "Breyta",
+ "button.execute": "Keyra",
+ "button.explore": "Kanna",
+ "button.hide": "Fela",
+ "button.logout": "Útskrá",
+ "button.reset": "Endurstilla",
+ "button.show": "Sýna",
+ "button.try_it_out": "Prófaðu",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Kóði",
+ "label.description": "Lýsing",
+ "label.details": "Upplýsingar",
+ "label.examples": "Dæmi",
+ "label.headers": "Hausar:",
+ "label.links": "Tenglar",
+ "label.media_type": "Miðilsgerð",
+ "label.models": "Líkön",
+ "label.name": "Nafn",
+ "label.no_links": "Engir tenglar",
+ "label.no_parameters": "Engar breytur",
+ "label.parameter_content_type": "Innihaldsgerð breytu",
+ "label.parameters": "Breytur",
+ "label.request_body": "Meginmál beiðni",
+ "label.request_duration": "Lengd beiðni",
+ "label.request_url": "Slóð beiðni",
+ "label.response_body": "Meginmál svars",
+ "label.response_content_type": "Innihaldsgerð svars",
+ "label.response_headers": "Hausar svars",
+ "label.responses": "Svör",
+ "label.schemas": "Skema",
+ "label.server_response": "Svar þjóns",
+ "label.snippets": "Brot",
+ "label.type": "Tegund",
+ "label.undocumented": "Óskráð",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "Í:",
+ "auth.api_key_name": "Nafn:",
+ "auth.api_key_value": "Gildi:",
+ "auth.application": "Forrit:",
+ "auth.authorization_header": "Heimildarhausur",
+ "auth.authorization_url": "Heimildarvefslóð:",
+ "auth.authorized": "Heimilt",
+ "auth.basic_authorization_title": "Grunnheimild",
+ "auth.client_credentials_location": "Staðsetning skilríkja biðlara:",
+ "auth.flow": "Flæði:",
+ "auth.openid_connect_url": "OpenID Connect vefslóð:",
+ "auth.password": "lykilorð:",
+ "auth.password_cap": "Lykilorð:",
+ "auth.request_body_option": "Meginmál beiðni",
+ "auth.scopes_description":
+ "Scopes eru notaðar til að veita forriti mismunandi aðgangsstig að gögnum fyrir hönd notandans. Sérhver API getur lýst yfir einum eða fleiri scopes.",
+ "auth.scopes_required":
+ "API krefst eftirfarandi scopes. Veldu þær sem þú vilt veita Swagger UI.",
+ "auth.scopes_title": "Scopes:",
+ "auth.select_all": "velja allt",
+ "auth.select_none": "velja ekkert",
+ "auth.token_url": "Token vefslóð:",
+ "auth.username": "notandanafn:",
+ "auth.username_cap": "Notandanafn:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Nota skilríki",
+ "aria.apply_oauth2_credentials": "Nota tilgreind OAuth2-skilríki",
+ "aria.authorization_button_locked": "heimildarhnappur læstur",
+ "aria.authorization_button_unlocked": "heimildarhnappur opinn",
+ "aria.collapse_operation": "Fella saman aðgerð",
+ "aria.expand_operation": "Víkka út aðgerð",
+ "aria.remove_authorization": "Fjarlægja heimild",
+ "aria.request_content_type": "Innihaldsgerð beiðni",
+ "aria.response_content_type": "Innihaldsgerð svars",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Fara í línu {{line}}",
+ "errors.title": "Villur",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Sía eftir merki",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Stýrir ",
+ "response.controls_accept_header_suffix": "-hausi.",
+ "response.json_parse_error":
+ "Ekki tókst að þátta JSON. Hrá niðurstaða:\n\n",
+ "response.no_blob_support":
+ "Niðurhalshaus greindir, en vafrinn þinn styður ekki niðurhal á tvíundagögnum í gegnum XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Óþekkt svargerð; sýni efni sem texta.",
+ "response.unrecognized_type_unable_to_display":
+ "Óþekkt svargerð; get ekki sýnt.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Velja skilgreiningu",
+}
+
+export default is
diff --git a/src/core/plugins/i18n/locales/it.js b/src/core/plugins/i18n/locales/it.js
new file mode 100644
index 00000000000..501edc6ba2c
--- /dev/null
+++ b/src/core/plugins/i18n/locales/it.js
@@ -0,0 +1,115 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Italian (Italiano) message catalog.
+ */
+const it = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autorizza",
+ "button.cancel": "Annulla",
+ "button.clear": "Cancella",
+ "button.close": "Chiudi",
+ "button.copy_to_clipboard": "Copia negli appunti",
+ "button.download_file": "Scarica file",
+ "button.edit": "Modifica",
+ "button.execute": "Esegui",
+ "button.explore": "Esplora",
+ "button.hide": "Nascondi",
+ "button.logout": "Esci",
+ "button.reset": "Reimposta",
+ "button.show": "Mostra",
+ "button.try_it_out": "Prova",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callback",
+ "label.code": "Codice",
+ "label.description": "Descrizione",
+ "label.details": "Dettagli",
+ "label.examples": "Esempi",
+ "label.headers": "Intestazioni:",
+ "label.links": "Link",
+ "label.media_type": "Tipo di media",
+ "label.models": "Modelli",
+ "label.name": "Nome",
+ "label.no_links": "Nessun link",
+ "label.no_parameters": "Nessun parametro",
+ "label.parameter_content_type": "Tipo di contenuto del parametro",
+ "label.parameters": "Parametri",
+ "label.request_body": "Corpo della richiesta",
+ "label.request_duration": "Durata della richiesta",
+ "label.request_url": "URL della richiesta",
+ "label.response_body": "Corpo della risposta",
+ "label.response_content_type": "Tipo di contenuto della risposta",
+ "label.response_headers": "Intestazioni della risposta",
+ "label.responses": "Risposte",
+ "label.schemas": "Schemi",
+ "label.server_response": "Risposta del server",
+ "label.snippets": "Frammenti",
+ "label.type": "Tipo",
+ "label.undocumented": "Non documentato",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "In:",
+ "auth.api_key_name": "Nome:",
+ "auth.api_key_value": "Valore:",
+ "auth.application": "Applicazione:",
+ "auth.authorization_header": "Intestazione di autorizzazione",
+ "auth.authorization_url": "URL di autorizzazione:",
+ "auth.authorized": "Autorizzato",
+ "auth.basic_authorization_title": "Autorizzazione di base",
+ "auth.client_credentials_location":
+ "Posizione delle credenziali del client:",
+ "auth.flow": "Flusso:",
+ "auth.openid_connect_url": "URL OpenID Connect:",
+ "auth.password": "password:",
+ "auth.password_cap": "Password:",
+ "auth.request_body_option": "Corpo della richiesta",
+ "auth.scopes_description":
+ "Gli scope vengono utilizzati per concedere a un'applicazione diversi livelli di accesso ai dati per conto dell'utente finale. Ogni API può dichiarare uno o più scope.",
+ "auth.scopes_required":
+ "L'API richiede i seguenti scope. Seleziona quelli che desideri concedere a Swagger UI.",
+ "auth.scopes_title": "Scope:",
+ "auth.select_all": "seleziona tutto",
+ "auth.select_none": "deseleziona tutto",
+ "auth.token_url": "URL del token:",
+ "auth.username": "nome utente:",
+ "auth.username_cap": "Nome utente:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Applica credenziali",
+ "aria.apply_oauth2_credentials": "Applica le credenziali OAuth2 fornite",
+ "aria.authorization_button_locked": "pulsante di autorizzazione bloccato",
+ "aria.authorization_button_unlocked":
+ "pulsante di autorizzazione sbloccato",
+ "aria.collapse_operation": "Comprimi operazione",
+ "aria.expand_operation": "Espandi operazione",
+ "aria.remove_authorization": "Rimuovi autorizzazione",
+ "aria.request_content_type": "Tipo di contenuto della richiesta",
+ "aria.response_content_type": "Tipo di contenuto della risposta",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Vai alla riga {{line}}",
+ "errors.title": "Errori",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtra per tag",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Controlla l'intestazione ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "Impossibile analizzare il JSON. Risultato grezzo:\n\n",
+ "response.no_blob_support":
+ "Intestazioni di download rilevate ma il browser non supporta il download di dati binari tramite XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Tipo di risposta non riconosciuto; visualizzazione del contenuto come testo.",
+ "response.unrecognized_type_unable_to_display":
+ "Tipo di risposta non riconosciuto; impossibile visualizzare.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Seleziona una definizione",
+}
+
+export default it
diff --git a/src/core/plugins/i18n/locales/ja.js b/src/core/plugins/i18n/locales/ja.js
new file mode 100644
index 00000000000..162d6922a6a
--- /dev/null
+++ b/src/core/plugins/i18n/locales/ja.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Japanese (日本語) message catalog.
+ */
+const ja = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "認証",
+ "button.cancel": "キャンセル",
+ "button.clear": "クリア",
+ "button.close": "閉じる",
+ "button.copy_to_clipboard": "クリップボードにコピー",
+ "button.download_file": "ファイルをダウンロード",
+ "button.edit": "編集",
+ "button.execute": "実行",
+ "button.explore": "探索",
+ "button.hide": "非表示",
+ "button.logout": "ログアウト",
+ "button.reset": "リセット",
+ "button.show": "表示",
+ "button.try_it_out": "試してみる",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "コールバック",
+ "label.code": "コード",
+ "label.description": "説明",
+ "label.details": "詳細",
+ "label.examples": "例",
+ "label.headers": "ヘッダ:",
+ "label.links": "リンク",
+ "label.media_type": "メディアタイプ",
+ "label.models": "モデル",
+ "label.name": "名前",
+ "label.no_links": "リンクなし",
+ "label.no_parameters": "パラメータなし",
+ "label.parameter_content_type": "パラメータのコンテンツタイプ",
+ "label.parameters": "パラメータ",
+ "label.request_body": "リクエストボディ",
+ "label.request_duration": "リクエスト時間",
+ "label.request_url": "リクエストURL",
+ "label.response_body": "レスポンスボディ",
+ "label.response_content_type": "レスポンスのコンテンツタイプ",
+ "label.response_headers": "レスポンスヘッダ",
+ "label.responses": "レスポンス",
+ "label.schemas": "スキーマ",
+ "label.server_response": "サーバレスポンス",
+ "label.snippets": "スニペット",
+ "label.type": "タイプ",
+ "label.undocumented": "未ドキュメント",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "場所:",
+ "auth.api_key_name": "名前:",
+ "auth.api_key_value": "値:",
+ "auth.application": "アプリケーション:",
+ "auth.authorization_header": "認証ヘッダ",
+ "auth.authorization_url": "認証URL:",
+ "auth.authorized": "認証済み",
+ "auth.basic_authorization_title": "基本認証",
+ "auth.client_credentials_location": "クライアント認証情報の場所:",
+ "auth.flow": "フロー:",
+ "auth.openid_connect_url": "OpenID Connect URL:",
+ "auth.password": "パスワード:",
+ "auth.password_cap": "パスワード:",
+ "auth.request_body_option": "リクエストボディ",
+ "auth.scopes_description":
+ "スコープは、エンドユーザーに代わってアプリケーションにデータへの異なるアクセスレベルを付与するために使用されます。各APIは1つ以上のスコープを宣言できます。",
+ "auth.scopes_required":
+ "APIには以下のスコープが必要です。Swagger UIに付与するスコープを選択してください。",
+ "auth.scopes_title": "スコープ:",
+ "auth.select_all": "すべて選択",
+ "auth.select_none": "選択なし",
+ "auth.token_url": "トークンURL:",
+ "auth.username": "ユーザ名:",
+ "auth.username_cap": "ユーザ名:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "認証情報を適用",
+ "aria.apply_oauth2_credentials": "指定されたOAuth2認証情報を適用",
+ "aria.authorization_button_locked": "認証ボタンがロックされています",
+ "aria.authorization_button_unlocked": "認証ボタンがロック解除されています",
+ "aria.collapse_operation": "操作を折りたたむ",
+ "aria.expand_operation": "操作を展開する",
+ "aria.remove_authorization": "認証を削除",
+ "aria.request_content_type": "リクエストのコンテンツタイプ",
+ "aria.response_content_type": "レスポンスのコンテンツタイプ",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "{{line}}行目に移動",
+ "errors.title": "エラー",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "タグで絞り込む",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "",
+ "response.controls_accept_header_suffix": "ヘッダを制御します。",
+ "response.json_parse_error":
+ "JSONを解析できません。 未加工の結果:\n\n",
+ "response.no_blob_support":
+ "ダウンロードヘッダが検出されましたが、お使いのブラウザはXHR (Blob) を通じたバイナリデータのダウンロードをサポートしていません。",
+ "response.unrecognized_type_display_as_text":
+ "認識できないレスポンスタイプです。コンテンツをテキストとして表示します。",
+ "response.unrecognized_type_unable_to_display":
+ "認識できないレスポンスタイプです。表示できません。",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "定義を選択",
+}
+
+export default ja
diff --git a/src/core/plugins/i18n/locales/ka.js b/src/core/plugins/i18n/locales/ka.js
new file mode 100644
index 00000000000..3bdc53eea9d
--- /dev/null
+++ b/src/core/plugins/i18n/locales/ka.js
@@ -0,0 +1,114 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Georgian (ქართული) message catalog.
+ * ISO 639-1 code: ka (bibliographic "geo" used in the original dist/lang/geo.js)
+ */
+const ka = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "ავტორიზაცია",
+ "button.cancel": "გაუქმება",
+ "button.clear": "გასუფთავება",
+ "button.close": "დახურვა",
+ "button.copy_to_clipboard": "ბუფერში კოპირება",
+ "button.download_file": "ფაილის ჩამოტვირთვა",
+ "button.edit": "რედაქტირება",
+ "button.execute": "გაშვება",
+ "button.explore": "ნახვა",
+ "button.hide": "დამალვა",
+ "button.logout": "გასვლა",
+ "button.reset": "გადატვირთვა",
+ "button.show": "გამოჩენა",
+ "button.try_it_out": "ცადე",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "კოდი",
+ "label.description": "აღწერა",
+ "label.details": "დეტალები",
+ "label.examples": "მაგალითები",
+ "label.headers": "ჰედერები:",
+ "label.links": "ლინკები",
+ "label.media_type": "მედიის ტიპი",
+ "label.models": "მოდელები",
+ "label.name": "სახელი",
+ "label.no_links": "ლინკი არ არის",
+ "label.no_parameters": "პარამეტრი არ არის",
+ "label.parameter_content_type": "პარამეტრის კონტენტის ტიპი",
+ "label.parameters": "პარამეტრები",
+ "label.request_body": "მოთხოვნის სხეული",
+ "label.request_duration": "მოთხოვნის ხანგრძლივობა",
+ "label.request_url": "მოთხოვნის URL",
+ "label.response_body": "პასუხის სხეული",
+ "label.response_content_type": "პასუხის კონტენტის ტიპი",
+ "label.response_headers": "პასუხის ჰედერები",
+ "label.responses": "პასუხები",
+ "label.schemas": "სქემები",
+ "label.server_response": "სერვერის პასუხი",
+ "label.snippets": "ფრაგმენტები",
+ "label.type": "ტიპი",
+ "label.undocumented": "დოკუმენტირებული არ არის",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "სად:",
+ "auth.api_key_name": "სახელი:",
+ "auth.api_key_value": "მნიშვნელობა:",
+ "auth.application": "აპლიკაცია:",
+ "auth.authorization_header": "ავტორიზაციის ჰედერი",
+ "auth.authorization_url": "ავტორიზაციის URL:",
+ "auth.authorized": "ავტორიზებულია",
+ "auth.basic_authorization_title": "საბაზო ავტორიზაცია",
+ "auth.client_credentials_location": "კლიენტის სერთიფიკატების მდებარეობა:",
+ "auth.flow": "ნაკადი:",
+ "auth.openid_connect_url": "OpenID Connect URL:",
+ "auth.password": "პაროლი:",
+ "auth.password_cap": "პაროლი:",
+ "auth.request_body_option": "მოთხოვნის სხეული",
+ "auth.scopes_description":
+ "Scope-ები გამოიყენება აპლიკაციისთვის მომხმარებლის სახელით მონაცემებზე განსხვავებული წვდომის დონის მინიჭებისთვის. თითოეული API-ი შეიძლება ერთ ან მეტ scope-ს ეყრდნობოდეს.",
+ "auth.scopes_required":
+ "API-ს სჭირდება შემდეგი scope-ები. აირჩიეთ, რომელი გსურთ Swagger UI-სთვის.",
+ "auth.scopes_title": "Scope-ები:",
+ "auth.select_all": "ყველას მონიშვნა",
+ "auth.select_none": "მოხსენება",
+ "auth.token_url": "ტოკენის URL:",
+ "auth.username": "მოხმარებელი:",
+ "auth.username_cap": "მოხმარებელი:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "სერთიფიკატების გამოყენება",
+ "aria.apply_oauth2_credentials": "მოცემული OAuth2 სერთიფიკატების გამოყენება",
+ "aria.authorization_button_locked": "ავტორიზაციის ღილაკი დაბლოკილია",
+ "aria.authorization_button_unlocked": "ავტორიზაციის ღილაკი განბლოკილია",
+ "aria.collapse_operation": "ოპერაციის ჩაკეცვა",
+ "aria.expand_operation": "ოპერაციის გაშლა",
+ "aria.remove_authorization": "ავტორიზაციის წაშლა",
+ "aria.request_content_type": "მოთხოვნის კონტენტის ტიპი",
+ "aria.response_content_type": "პასუხის კონტენტის ტიპი",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "{{line}} სტრიქონზე გადასვლა",
+ "errors.title": "შეცდომები",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "ტეგით გაფილტვრა",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "",
+ "response.controls_accept_header_suffix": " ჰედერს მართავს.",
+ "response.json_parse_error":
+ "JSON-ის დამუშავება ვერ მოხერხდა. ნედლი შედეგი:\n\n",
+ "response.no_blob_support":
+ "ჩამოტვირთვის ჰედერები გამოვლინდა, მაგრამ თქვენი ბრაუზერი XHR (Blob) საშუალებით ბინარული მონაცემების ჩამოტვირთვას არ უჭერს მხარს.",
+ "response.unrecognized_type_display_as_text":
+ "პასუხის ტიპი ვერ ამოვიცანით; კონტენტს ტექსტად ვაჩვენებთ.",
+ "response.unrecognized_type_unable_to_display":
+ "პასუხის ტიპი ვერ ამოვიცანით; ვერ ვაჩვენებთ.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "განსაზღვრების არჩევა",
+}
+
+export default ka
diff --git a/src/core/plugins/i18n/locales/ko.js b/src/core/plugins/i18n/locales/ko.js
new file mode 100644
index 00000000000..e0909042a2b
--- /dev/null
+++ b/src/core/plugins/i18n/locales/ko.js
@@ -0,0 +1,112 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Korean (한국어) message catalog.
+ */
+const ko = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "인증",
+ "button.cancel": "취소",
+ "button.clear": "지우기",
+ "button.close": "닫기",
+ "button.copy_to_clipboard": "클립보드에 복사",
+ "button.download_file": "파일 다운로드",
+ "button.edit": "수정",
+ "button.execute": "실행",
+ "button.explore": "탐색",
+ "button.hide": "숨기기",
+ "button.logout": "로그아웃",
+ "button.reset": "초기화",
+ "button.show": "표시",
+ "button.try_it_out": "직접 해보기",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "콜백",
+ "label.code": "코드",
+ "label.description": "설명",
+ "label.details": "세부 정보",
+ "label.examples": "예시",
+ "label.headers": "헤더:",
+ "label.links": "링크",
+ "label.media_type": "미디어 유형",
+ "label.models": "모델",
+ "label.name": "이름",
+ "label.no_links": "링크 없음",
+ "label.no_parameters": "파라미터 없음",
+ "label.parameter_content_type": "파라미터 콘텐츠 유형",
+ "label.parameters": "파라미터",
+ "label.request_body": "요청 본문",
+ "label.request_duration": "요청 시간",
+ "label.request_url": "요청 URL",
+ "label.response_body": "응답 본문",
+ "label.response_content_type": "응답 콘텐츠 유형",
+ "label.response_headers": "응답 헤더",
+ "label.responses": "응답",
+ "label.schemas": "스키마",
+ "label.server_response": "서버 응답",
+ "label.snippets": "스니펫",
+ "label.type": "유형",
+ "label.undocumented": "미문서화",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "위치:",
+ "auth.api_key_name": "이름:",
+ "auth.api_key_value": "값:",
+ "auth.application": "애플리케이션:",
+ "auth.authorization_header": "인증 헤더",
+ "auth.authorization_url": "인증 URL:",
+ "auth.authorized": "인증됨",
+ "auth.basic_authorization_title": "기본 인증",
+ "auth.client_credentials_location": "클라이언트 자격증명 위치:",
+ "auth.flow": "흐름:",
+ "auth.openid_connect_url": "OpenID Connect URL:",
+ "auth.password": "비밀번호:",
+ "auth.password_cap": "비밀번호:",
+ "auth.request_body_option": "요청 본문",
+ "auth.scopes_description":
+ "스코프는 최종 사용자를 대신하여 애플리케이션에 데이터에 대한 다양한 수준의 액세스를 부여하는 데 사용됩니다. 각 API는 하나 이상의 스코프를 선언할 수 있습니다.",
+ "auth.scopes_required":
+ "API에는 다음 스코프가 필요합니다. Swagger UI에 부여할 스코프를 선택하세요.",
+ "auth.scopes_title": "스코프:",
+ "auth.select_all": "전체 선택",
+ "auth.select_none": "전체 해제",
+ "auth.token_url": "토큰 URL:",
+ "auth.username": "사용자 이름:",
+ "auth.username_cap": "사용자 이름:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "자격증명 적용",
+ "aria.apply_oauth2_credentials": "주어진 OAuth2 자격증명 적용",
+ "aria.authorization_button_locked": "인증 버튼 잠김",
+ "aria.authorization_button_unlocked": "인증 버튼 잠금 해제",
+ "aria.collapse_operation": "작업 축소",
+ "aria.expand_operation": "작업 확장",
+ "aria.remove_authorization": "인증 제거",
+ "aria.request_content_type": "요청 콘텐츠 유형",
+ "aria.response_content_type": "응답 콘텐츠 유형",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "{{line}}번 줄로 이동",
+ "errors.title": "오류",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "태그로 필터링",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "",
+ "response.controls_accept_header_suffix": " 헤더를 제어합니다.",
+ "response.json_parse_error": "JSON을 파싱할 수 없습니다. 원시 결과:\n\n",
+ "response.no_blob_support":
+ "다운로드 헤더가 감지되었지만 브라우저가 XHR (Blob)을 통한 바이너리 다운로드를 지원하지 않습니다.",
+ "response.unrecognized_type_display_as_text":
+ "인식되지 않는 응답 유형입니다. 내용을 텍스트로 표시합니다.",
+ "response.unrecognized_type_unable_to_display":
+ "인식되지 않는 응답 유형입니다. 표시할 수 없습니다.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "정의 선택",
+}
+
+export default ko
diff --git a/src/core/plugins/i18n/locales/pl.js b/src/core/plugins/i18n/locales/pl.js
new file mode 100644
index 00000000000..41343dcbfa0
--- /dev/null
+++ b/src/core/plugins/i18n/locales/pl.js
@@ -0,0 +1,115 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Polish (Polski) message catalog.
+ */
+const pl = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autoryzuj",
+ "button.cancel": "Anuluj",
+ "button.clear": "Wyczyść",
+ "button.close": "Zamknij",
+ "button.copy_to_clipboard": "Kopiuj do schowka",
+ "button.download_file": "Pobierz plik",
+ "button.edit": "Edytuj",
+ "button.execute": "Wykonaj",
+ "button.explore": "Eksploruj",
+ "button.hide": "Ukryj",
+ "button.logout": "Wyloguj",
+ "button.reset": "Resetuj",
+ "button.show": "Pokaż",
+ "button.try_it_out": "Wypróbuj",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacki",
+ "label.code": "Kod",
+ "label.description": "Opis",
+ "label.details": "Szczegóły",
+ "label.examples": "Przykłady",
+ "label.headers": "Nagłówki:",
+ "label.links": "Łącza",
+ "label.media_type": "Typ mediów",
+ "label.models": "Modele",
+ "label.name": "Nazwa",
+ "label.no_links": "Brak łączy",
+ "label.no_parameters": "Brak parametrów",
+ "label.parameter_content_type": "Typ zawartości parametru",
+ "label.parameters": "Parametry",
+ "label.request_body": "Treść żądania",
+ "label.request_duration": "Czas żądania",
+ "label.request_url": "URL żądania",
+ "label.response_body": "Treść odpowiedzi",
+ "label.response_content_type": "Typ zawartości odpowiedzi",
+ "label.response_headers": "Nagłówki odpowiedzi",
+ "label.responses": "Odpowiedzi",
+ "label.schemas": "Schematy",
+ "label.server_response": "Odpowiedź serwera",
+ "label.snippets": "Fragmenty",
+ "label.type": "Typ",
+ "label.undocumented": "Nieudokumentowane",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "W:",
+ "auth.api_key_name": "Nazwa:",
+ "auth.api_key_value": "Wartość:",
+ "auth.application": "Aplikacja:",
+ "auth.authorization_header": "Nagłówek autoryzacji",
+ "auth.authorization_url": "URL autoryzacji:",
+ "auth.authorized": "Autoryzowano",
+ "auth.basic_authorization_title": "Autoryzacja podstawowa",
+ "auth.client_credentials_location":
+ "Lokalizacja danych uwierzytelniających klienta:",
+ "auth.flow": "Przepływ:",
+ "auth.openid_connect_url": "URL OpenID Connect:",
+ "auth.password": "hasło:",
+ "auth.password_cap": "Hasło:",
+ "auth.request_body_option": "Treść żądania",
+ "auth.scopes_description":
+ "Zakresy są używane do przyznawania aplikacji różnych poziomów dostępu do danych w imieniu użytkownika końcowego. Każde API może zadeklarować jeden lub więcej zakresów.",
+ "auth.scopes_required":
+ "API wymaga następujących zakresów. Wybierz, które chcesz przyznać Swagger UI.",
+ "auth.scopes_title": "Zakresy:",
+ "auth.select_all": "zaznacz wszystkie",
+ "auth.select_none": "odznacz wszystkie",
+ "auth.token_url": "URL tokenu:",
+ "auth.username": "nazwa użytkownika:",
+ "auth.username_cap": "Nazwa użytkownika:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Zastosuj dane uwierzytelniające",
+ "aria.apply_oauth2_credentials":
+ "Zastosuj podane dane uwierzytelniające OAuth2",
+ "aria.authorization_button_locked": "przycisk autoryzacji zablokowany",
+ "aria.authorization_button_unlocked": "przycisk autoryzacji odblokowany",
+ "aria.collapse_operation": "Zwiń operację",
+ "aria.expand_operation": "Rozwiń operację",
+ "aria.remove_authorization": "Usuń autoryzację",
+ "aria.request_content_type": "Typ zawartości żądania",
+ "aria.response_content_type": "Typ zawartości odpowiedzi",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Przejdź do linii {{line}}",
+ "errors.title": "Błędy",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtruj według tagu",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Kontroluje nagłówek ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "Nie można przetworzyć JSON. Nieprzetworzone dane:\n\n",
+ "response.no_blob_support":
+ "Wykryto nagłówki pobierania, ale przeglądarka nie obsługuje pobierania danych binarnych przez XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Nierozpoznany typ odpowiedzi; wyświetlanie zawartości jako tekstu.",
+ "response.unrecognized_type_unable_to_display":
+ "Nierozpoznany typ odpowiedzi; nie można wyświetlić.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Wybierz definicję",
+}
+
+export default pl
diff --git a/src/core/plugins/i18n/locales/pt.js b/src/core/plugins/i18n/locales/pt.js
new file mode 100644
index 00000000000..b367afbd876
--- /dev/null
+++ b/src/core/plugins/i18n/locales/pt.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Portuguese / Brazilian Portuguese (Português do Brasil) message catalog.
+ */
+const pt = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Autorizar",
+ "button.cancel": "Cancelar",
+ "button.clear": "Limpar",
+ "button.close": "Fechar",
+ "button.copy_to_clipboard": "Copiar para a área de transferência",
+ "button.download_file": "Baixar arquivo",
+ "button.edit": "Editar",
+ "button.execute": "Executar",
+ "button.explore": "Explorar",
+ "button.hide": "Ocultar",
+ "button.logout": "Sair",
+ "button.reset": "Redefinir",
+ "button.show": "Mostrar",
+ "button.try_it_out": "Experimente",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Código",
+ "label.description": "Descrição",
+ "label.details": "Detalhes",
+ "label.examples": "Exemplos",
+ "label.headers": "Cabeçalhos:",
+ "label.links": "Links",
+ "label.media_type": "Tipo de mídia",
+ "label.models": "Modelos",
+ "label.name": "Nome",
+ "label.no_links": "Sem links",
+ "label.no_parameters": "Sem parâmetros",
+ "label.parameter_content_type": "Tipo de conteúdo do parâmetro",
+ "label.parameters": "Parâmetros",
+ "label.request_body": "Corpo da requisição",
+ "label.request_duration": "Duração da requisição",
+ "label.request_url": "URL da requisição",
+ "label.response_body": "Corpo da resposta",
+ "label.response_content_type": "Tipo de conteúdo da resposta",
+ "label.response_headers": "Cabeçalhos da resposta",
+ "label.responses": "Respostas",
+ "label.schemas": "Esquemas",
+ "label.server_response": "Resposta do servidor",
+ "label.snippets": "Trechos",
+ "label.type": "Tipo",
+ "label.undocumented": "Não documentado",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "Em:",
+ "auth.api_key_name": "Nome:",
+ "auth.api_key_value": "Valor:",
+ "auth.application": "Aplicação:",
+ "auth.authorization_header": "Cabeçalho de autorização",
+ "auth.authorization_url": "URL de autorização:",
+ "auth.authorized": "Autorizado",
+ "auth.basic_authorization_title": "Autorização básica",
+ "auth.client_credentials_location": "Localização das credenciais do cliente:",
+ "auth.flow": "Fluxo:",
+ "auth.openid_connect_url": "URL do OpenID Connect:",
+ "auth.password": "senha:",
+ "auth.password_cap": "Senha:",
+ "auth.request_body_option": "Corpo da requisição",
+ "auth.scopes_description":
+ "Os escopos são usados para conceder a um aplicativo diferentes níveis de acesso aos dados em nome do usuário final. Cada API pode declarar um ou mais escopos.",
+ "auth.scopes_required":
+ "A API requer os seguintes escopos. Selecione quais você deseja conceder ao Swagger UI.",
+ "auth.scopes_title": "Escopos:",
+ "auth.select_all": "selecionar todos",
+ "auth.select_none": "selecionar nenhum",
+ "auth.token_url": "URL do token:",
+ "auth.username": "nome de usuário:",
+ "auth.username_cap": "Nome de usuário:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Aplicar credenciais",
+ "aria.apply_oauth2_credentials": "Aplicar as credenciais OAuth2 fornecidas",
+ "aria.authorization_button_locked": "botão de autorização bloqueado",
+ "aria.authorization_button_unlocked": "botão de autorização desbloqueado",
+ "aria.collapse_operation": "Recolher operação",
+ "aria.expand_operation": "Expandir operação",
+ "aria.remove_authorization": "Remover autorização",
+ "aria.request_content_type": "Tipo de conteúdo da requisição",
+ "aria.response_content_type": "Tipo de conteúdo da resposta",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Ir para a linha {{line}}",
+ "errors.title": "Erros",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Filtrar por tag",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Controla o cabeçalho ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "Não foi possível analisar o JSON. Resultado bruto:\n\n",
+ "response.no_blob_support":
+ "Cabeçalhos de download detectados, mas seu navegador não suporta download de dados binários via XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Tipo de resposta não reconhecido; exibindo conteúdo como texto.",
+ "response.unrecognized_type_unable_to_display":
+ "Tipo de resposta não reconhecido; não é possível exibir.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Selecionar uma definição",
+}
+
+export default pt
diff --git a/src/core/plugins/i18n/locales/ru.js b/src/core/plugins/i18n/locales/ru.js
new file mode 100644
index 00000000000..5e2c6bffe6d
--- /dev/null
+++ b/src/core/plugins/i18n/locales/ru.js
@@ -0,0 +1,113 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Russian (Русский) message catalog.
+ */
+const ru = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Авторизовать",
+ "button.cancel": "Отмена",
+ "button.clear": "Очистить",
+ "button.close": "Закрыть",
+ "button.copy_to_clipboard": "Копировать в буфер обмена",
+ "button.download_file": "Скачать файл",
+ "button.edit": "Редактировать",
+ "button.execute": "Выполнить",
+ "button.explore": "Исследовать",
+ "button.hide": "Скрыть",
+ "button.logout": "Выйти",
+ "button.reset": "Сбросить",
+ "button.show": "Показать",
+ "button.try_it_out": "Попробовать",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Коллбэки",
+ "label.code": "Код",
+ "label.description": "Описание",
+ "label.details": "Детали",
+ "label.examples": "Примеры",
+ "label.headers": "Заголовки:",
+ "label.links": "Ссылки",
+ "label.media_type": "Тип медиа",
+ "label.models": "Модели",
+ "label.name": "Имя",
+ "label.no_links": "Нет ссылок",
+ "label.no_parameters": "Нет параметров",
+ "label.parameter_content_type": "Тип содержимого параметра",
+ "label.parameters": "Параметры",
+ "label.request_body": "Тело запроса",
+ "label.request_duration": "Продолжительность запроса",
+ "label.request_url": "URL запроса",
+ "label.response_body": "Тело ответа",
+ "label.response_content_type": "Тип содержимого ответа",
+ "label.response_headers": "Заголовки ответа",
+ "label.responses": "Ответы",
+ "label.schemas": "Схемы",
+ "label.server_response": "Ответ сервера",
+ "label.snippets": "Фрагменты",
+ "label.type": "Тип",
+ "label.undocumented": "Не задокументировано",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "В:",
+ "auth.api_key_name": "Имя:",
+ "auth.api_key_value": "Значение:",
+ "auth.application": "Приложение:",
+ "auth.authorization_header": "Заголовок авторизации",
+ "auth.authorization_url": "URL авторизации:",
+ "auth.authorized": "Авторизован",
+ "auth.basic_authorization_title": "Базовая авторизация",
+ "auth.client_credentials_location": "Местонахождение учётных данных клиента:",
+ "auth.flow": "Поток:",
+ "auth.openid_connect_url": "URL OpenID Connect:",
+ "auth.password": "пароль:",
+ "auth.password_cap": "Пароль:",
+ "auth.request_body_option": "Тело запроса",
+ "auth.scopes_description":
+ "Области используются для предоставления приложению разных уровней доступа к данным от имени конечного пользователя. Каждый API может объявлять одну или несколько областей.",
+ "auth.scopes_required":
+ "API требует следующих областей. Выберите те, которые вы хотите предоставить Swagger UI.",
+ "auth.scopes_title": "Области:",
+ "auth.select_all": "выбрать все",
+ "auth.select_none": "снять выбор",
+ "auth.token_url": "URL токена:",
+ "auth.username": "имя пользователя:",
+ "auth.username_cap": "Имя пользователя:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Применить учётные данные",
+ "aria.apply_oauth2_credentials": "Применить указанные учётные данные OAuth2",
+ "aria.authorization_button_locked": "кнопка авторизации заблокирована",
+ "aria.authorization_button_unlocked": "кнопка авторизации разблокирована",
+ "aria.collapse_operation": "Свернуть операцию",
+ "aria.expand_operation": "Развернуть операцию",
+ "aria.remove_authorization": "Удалить авторизацию",
+ "aria.request_content_type": "Тип содержимого запроса",
+ "aria.response_content_type": "Тип содержимого ответа",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "Перейти к строке {{line}}",
+ "errors.title": "Ошибки",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Фильтровать по тегу",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "Управляет заголовком ",
+ "response.controls_accept_header_suffix": ".",
+ "response.json_parse_error":
+ "Не удаётся разобрать JSON. Необработанный результат:\n\n",
+ "response.no_blob_support":
+ "Обнаружены заголовки загрузки, но ваш браузер не поддерживает загрузку двоичных данных через XHR (Blob).",
+ "response.unrecognized_type_display_as_text":
+ "Нераспознанный тип ответа; содержимое отображается как текст.",
+ "response.unrecognized_type_unable_to_display":
+ "Нераспознанный тип ответа; отображение невозможно.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Выбрать определение",
+}
+
+export default ru
diff --git a/src/core/plugins/i18n/locales/tr.js b/src/core/plugins/i18n/locales/tr.js
new file mode 100644
index 00000000000..b6d9538cc1b
--- /dev/null
+++ b/src/core/plugins/i18n/locales/tr.js
@@ -0,0 +1,112 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Turkish (Türkçe) message catalog.
+ */
+const tr = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "Yetkilendir",
+ "button.cancel": "İptal",
+ "button.clear": "Temizle",
+ "button.close": "Kapat",
+ "button.copy_to_clipboard": "Panoya kopyala",
+ "button.download_file": "Dosyayı indir",
+ "button.edit": "Düzenle",
+ "button.execute": "Çalıştır",
+ "button.explore": "Keşfet",
+ "button.hide": "Gizle",
+ "button.logout": "Çıkış yap",
+ "button.reset": "Sıfırla",
+ "button.show": "Göster",
+ "button.try_it_out": "Dene",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "Callbacks",
+ "label.code": "Kod",
+ "label.description": "Açıklama",
+ "label.details": "Detaylar",
+ "label.examples": "Örnekler",
+ "label.headers": "Başlıklar:",
+ "label.links": "Bağlantılar",
+ "label.media_type": "Medya türü",
+ "label.models": "Modeller",
+ "label.name": "Ad",
+ "label.no_links": "Bağlantı yok",
+ "label.no_parameters": "Parametre yok",
+ "label.parameter_content_type": "Parametre içerik türü",
+ "label.parameters": "Parametreler",
+ "label.request_body": "İstek gövdesi",
+ "label.request_duration": "İstek süresi",
+ "label.request_url": "İstek URL'i",
+ "label.response_body": "Yanıt gövdesi",
+ "label.response_content_type": "Yanıt içerik türü",
+ "label.response_headers": "Yanıt başlıkları",
+ "label.responses": "Yanıtlar",
+ "label.schemas": "Şemalar",
+ "label.server_response": "Sunucu yanıtı",
+ "label.snippets": "Parçacıklar",
+ "label.type": "Tür",
+ "label.undocumented": "Belgelenmemiş",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "İçinde:",
+ "auth.api_key_name": "Ad:",
+ "auth.api_key_value": "Değer:",
+ "auth.application": "Uygulama:",
+ "auth.authorization_header": "Yetkilendirme başlığı",
+ "auth.authorization_url": "Yetkilendirme URL'i:",
+ "auth.authorized": "Yetkilendirildi",
+ "auth.basic_authorization_title": "Temel yetkilendirme",
+ "auth.client_credentials_location": "İstemci kimlik bilgilerinin konumu:",
+ "auth.flow": "Akış:",
+ "auth.openid_connect_url": "OpenID Connect URL'i:",
+ "auth.password": "şifre:",
+ "auth.password_cap": "Şifre:",
+ "auth.request_body_option": "İstek gövdesi",
+ "auth.scopes_description":
+ "Kapsamlar, son kullanıcı adına bir uygulamaya verilere farklı erişim düzeyleri tanımlamak için kullanılır. Her API bir veya daha fazla kapsam tanımlayabilir.",
+ "auth.scopes_required":
+ "API aşağıdaki kapsamları gerektirmektedir. Swagger UI'ye hangi kapsamları vermek istediğinizi seçin.",
+ "auth.scopes_title": "Kapsamlar:",
+ "auth.select_all": "tümünü seç",
+ "auth.select_none": "hiçbirini seçme",
+ "auth.token_url": "Token URL'i:",
+ "auth.username": "kullanıcı adı:",
+ "auth.username_cap": "Kullanıcı Adı:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "Kimlik bilgilerini uygula",
+ "aria.apply_oauth2_credentials": "Verilen OAuth2 kimlik bilgilerini uygula",
+ "aria.authorization_button_locked": "yetkilendirme düğmesi kilitli",
+ "aria.authorization_button_unlocked": "yetkilendirme düğmesi kilidi açık",
+ "aria.collapse_operation": "İşlemi daralt",
+ "aria.expand_operation": "İşlemi genişlet",
+ "aria.remove_authorization": "Yetkilendirmeyi kaldır",
+ "aria.request_content_type": "İstek içerik türü",
+ "aria.response_content_type": "Yanıt içerik türü",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "{{line}} satırına git",
+ "errors.title": "Hatalar",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "Etikete göre filtrele",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "",
+ "response.controls_accept_header_suffix": " başlığını kontrol eder.",
+ "response.json_parse_error": "JSON ayrıştırılamıyor. Ham sonuç:\n\n",
+ "response.no_blob_support":
+ "İndirme başlıkları algılandı, ancak tarayıcınız XHR (Blob) aracılığıyla ikili veri indirmeyi desteklemiyor.",
+ "response.unrecognized_type_display_as_text":
+ "Tanınmayan yanıt türü; içerik metin olarak görüntüleniyor.",
+ "response.unrecognized_type_unable_to_display":
+ "Tanınmayan yanıt türü; görüntülenemiyor.",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "Bir tanım seçin",
+}
+
+export default tr
diff --git a/src/core/plugins/i18n/locales/zh.js b/src/core/plugins/i18n/locales/zh.js
new file mode 100644
index 00000000000..11f59c86f64
--- /dev/null
+++ b/src/core/plugins/i18n/locales/zh.js
@@ -0,0 +1,112 @@
+/**
+ * @prettier
+ */
+
+/**
+ * Chinese Simplified (简体中文) message catalog.
+ */
+const zh = {
+ // ── Buttons / actions ─────────────────────────────────────────────────────
+ "button.authorize": "授权",
+ "button.cancel": "取消",
+ "button.clear": "清除",
+ "button.close": "关闭",
+ "button.copy_to_clipboard": "复制到剪贴板",
+ "button.download_file": "下载文件",
+ "button.edit": "编辑",
+ "button.execute": "执行",
+ "button.explore": "探索",
+ "button.hide": "隐藏",
+ "button.logout": "退出登录",
+ "button.reset": "重置",
+ "button.show": "显示",
+ "button.try_it_out": "试一下",
+
+ // ── Section / column labels ────────────────────────────────────────────────
+ "label.callbacks": "回调",
+ "label.code": "代码",
+ "label.description": "描述",
+ "label.details": "详情",
+ "label.examples": "示例",
+ "label.headers": "标头:",
+ "label.links": "链接",
+ "label.media_type": "媒体类型",
+ "label.models": "模型",
+ "label.name": "名称",
+ "label.no_links": "无链接",
+ "label.no_parameters": "无参数",
+ "label.parameter_content_type": "参数内容类型",
+ "label.parameters": "参数",
+ "label.request_body": "请求体",
+ "label.request_duration": "请求时长",
+ "label.request_url": "请求 URL",
+ "label.response_body": "响应体",
+ "label.response_content_type": "响应内容类型",
+ "label.response_headers": "响应头",
+ "label.responses": "响应",
+ "label.schemas": "模式",
+ "label.server_response": "服务器响应",
+ "label.snippets": "代码片段",
+ "label.type": "类型",
+ "label.undocumented": "未文档化",
+
+ // ── Authentication ─────────────────────────────────────────────────────────
+ "auth.api_key_in": "位置:",
+ "auth.api_key_name": "名称:",
+ "auth.api_key_value": "值:",
+ "auth.application": "应用程序:",
+ "auth.authorization_header": "授权请求头",
+ "auth.authorization_url": "授权 URL:",
+ "auth.authorized": "已授权",
+ "auth.basic_authorization_title": "基本授权",
+ "auth.client_credentials_location": "客户端凭据位置:",
+ "auth.flow": "流程:",
+ "auth.openid_connect_url": "OpenID Connect URL:",
+ "auth.password": "密码:",
+ "auth.password_cap": "密码:",
+ "auth.request_body_option": "请求体",
+ "auth.scopes_description":
+ "范围用于代表最终用户向应用程序授予对数据的不同访问级别。每个 API 可以声明一个或多个范围。",
+ "auth.scopes_required":
+ "API 需要以下范围。请选择您想要授予 Swagger UI 的范围。",
+ "auth.scopes_title": "范围:",
+ "auth.select_all": "全选",
+ "auth.select_none": "取消全选",
+ "auth.token_url": "令牌 URL:",
+ "auth.username": "用户名:",
+ "auth.username_cap": "用户名:",
+
+ // ── Accessibility (aria-labels / titles) ───────────────────────────────────
+ "aria.apply_credentials": "应用凭据",
+ "aria.apply_oauth2_credentials": "应用给定的 OAuth2 凭据",
+ "aria.authorization_button_locked": "授权按钮已锁定",
+ "aria.authorization_button_unlocked": "授权按钮已解锁",
+ "aria.collapse_operation": "折叠操作",
+ "aria.expand_operation": "展开操作",
+ "aria.remove_authorization": "删除授权",
+ "aria.request_content_type": "请求内容类型",
+ "aria.response_content_type": "响应内容类型",
+
+ // ── Errors ────────────────────────────────────────────────────────────────
+ "errors.jump_to_line": "跳转到第 {{line}} 行",
+ "errors.title": "错误",
+
+ // ── Placeholders ──────────────────────────────────────────────────────────
+ "placeholder.filter_by_tag": "按标签过滤",
+
+ // ── Response ──────────────────────────────────────────────────────────────
+ "response.controls_accept_header_prefix": "控制 ",
+ "response.controls_accept_header_suffix": " 请求头。",
+ "response.json_parse_error": "无法解析 JSON。原始结果:\n\n",
+ "response.no_blob_support":
+ "检测到下载标头,但您的浏览器不支持通过 XHR (Blob) 下载二进制文件。",
+ "response.unrecognized_type_display_as_text":
+ "无法识别的响应类型;将内容显示为文本。",
+ "response.unrecognized_type_unable_to_display":
+ "无法识别的响应类型;无法显示。",
+
+ // ── Topbar ────────────────────────────────────────────────────────────────
+ "topbar.select_definition": "选择一个定义",
+}
+
+export default zh
diff --git a/src/core/plugins/i18n/reducers.js b/src/core/plugins/i18n/reducers.js
new file mode 100644
index 00000000000..2f1de565be4
--- /dev/null
+++ b/src/core/plugins/i18n/reducers.js
@@ -0,0 +1,14 @@
+/**
+ * @prettier
+ */
+import { Map } from "immutable"
+import { SET_LOCALE, LOAD_MESSAGES } from "./actions"
+
+export default {
+ [SET_LOCALE]: (state, { payload: locale }) => state.set("locale", locale),
+
+ [LOAD_MESSAGES]: (state, { payload: { locale, messages } }) =>
+ state.updateIn(["messages", locale], (existing = Map()) =>
+ existing.merge(Map(messages))
+ ),
+}
diff --git a/src/core/plugins/i18n/selectors.js b/src/core/plugins/i18n/selectors.js
new file mode 100644
index 00000000000..c9e0c16b8ad
--- /dev/null
+++ b/src/core/plugins/i18n/selectors.js
@@ -0,0 +1,8 @@
+/**
+ * @prettier
+ */
+import { Map } from "immutable"
+
+export const getLocale = (state) => state.get("locale", "en")
+
+export const getMessages = (state) => state.get("messages", Map())
diff --git a/src/core/plugins/json-schema-5/components/models.jsx b/src/core/plugins/json-schema-5/components/models.jsx
index e9023f36f3e..ff77d70b927 100644
--- a/src/core/plugins/json-schema-5/components/models.jsx
+++ b/src/core/plugins/json-schema-5/components/models.jsx
@@ -1,6 +1,7 @@
import React, { Component } from "react"
import Im, { Map } from "immutable"
import PropTypes from "prop-types"
+import { fallbackT } from "core/plugins/i18n/fn"
/* eslint-disable react/jsx-no-bind */
@@ -11,7 +12,12 @@ export default class Models extends Component {
specActions: PropTypes.object.isRequired,
layoutSelectors: PropTypes.object,
layoutActions: PropTypes.object,
- getConfigs: PropTypes.func.isRequired
+ getConfigs: PropTypes.func.isRequired,
+ t: PropTypes.func,
+ }
+
+ static defaultProps = {
+ t: fallbackT,
}
getSchemaBasePath = () => {
@@ -45,7 +51,7 @@ export default class Models extends Component {
}
render(){
- let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs } = this.props
+ let { specSelectors, getComponent, layoutSelectors, layoutActions, getConfigs, t } = this.props
let definitions = specSelectors.definitions()
let { docExpansion, defaultModelsExpandDepth } = getConfigs()
if (!definitions.size || defaultModelsExpandDepth < 0) return null
@@ -68,7 +74,7 @@ export default class Models extends Component {
className="models-control"
onClick={() => layoutActions.show(specPathBase, !showModels)}
>
- {isOAS3 ? "Schemas" : "Models"}
+ {isOAS3 ? t("label.schemas") : t("label.models")}
{showModels ? : }
diff --git a/src/core/plugins/request-snippets/request-snippets.jsx b/src/core/plugins/request-snippets/request-snippets.jsx
index 3fbb127a3bc..eb01dcc64f2 100644
--- a/src/core/plugins/request-snippets/request-snippets.jsx
+++ b/src/core/plugins/request-snippets/request-snippets.jsx
@@ -2,6 +2,7 @@ import React, { useRef, useEffect, useState } from "react"
import classNames from "classnames"
import PropTypes from "prop-types"
import { CopyToClipboard } from "react-copy-to-clipboard"
+import { fallbackT } from "core/plugins/i18n/fn"
const style = {
cursor: "pointer",
@@ -33,7 +34,7 @@ const activeStyle = {
borderBottom: "none"
}
-const RequestSnippets = ({ request, requestSnippetsSelectors, getComponent }) => {
+const RequestSnippets = ({ request, requestSnippetsSelectors, getComponent, t }) => {
const rootRef = useRef(null)
const ArrowIcon = getComponent("ArrowUpIcon")
@@ -104,11 +105,11 @@ const RequestSnippets = ({ request, requestSnippetsSelectors, getComponent }) =>
handleSetIsExpanded()}
style={{ cursor: "pointer" }}
- >Snippets
+ >{t("label.snippets")}
@@ -158,6 +159,11 @@ RequestSnippets.propTypes = {
requestSnippetsSelectors: PropTypes.object.isRequired,
getComponent: PropTypes.func.isRequired,
requestSnippetsActions: PropTypes.object,
+ t: PropTypes.func,
+}
+
+RequestSnippets.defaultProps = {
+ t: fallbackT,
}
export default RequestSnippets
diff --git a/src/core/presets/base/index.js b/src/core/presets/base/index.js
index 15b7f6acd24..ff3a8f42104 100644
--- a/src/core/presets/base/index.js
+++ b/src/core/presets/base/index.js
@@ -6,6 +6,7 @@ import ConfigsPlugin from "core/plugins/configs"
import DeepLinkingPlugin from "core/plugins/deep-linking"
import ErrPlugin from "core/plugins/err"
import FilterPlugin from "core/plugins/filter"
+import I18nPlugin from "core/plugins/i18n"
import IconsPlugin from "core/plugins/icons"
import LayoutPlugin from "core/plugins/layout"
import LogsPlugin from "core/plugins/logs"
@@ -29,6 +30,7 @@ import FormComponentsPlugin from "core/presets/base/plugins/form-components"
const BasePreset = () => [
ConfigsPlugin,
UtilPlugin,
+ I18nPlugin,
LogsPlugin,
ViewPlugin,
ViewLegacyPlugin,
diff --git a/src/standalone/plugins/top-bar/components/TopBar.jsx b/src/standalone/plugins/top-bar/components/TopBar.jsx
index c19f5af228d..99a1f6e2aaf 100644
--- a/src/standalone/plugins/top-bar/components/TopBar.jsx
+++ b/src/standalone/plugins/top-bar/components/TopBar.jsx
@@ -1,5 +1,6 @@
import React, { cloneElement } from "react"
import PropTypes from "prop-types"
+import { fallbackT } from "core/plugins/i18n/fn"
import {parseSearch, serializeSearch} from "core/utils"
@@ -7,7 +8,16 @@ class TopBar extends React.Component {
static propTypes = {
layoutActions: PropTypes.object.isRequired,
- authActions: PropTypes.object.isRequired
+ authActions: PropTypes.object.isRequired,
+ specSelectors: PropTypes.object.isRequired,
+ specActions: PropTypes.object.isRequired,
+ getComponent: PropTypes.func.isRequired,
+ getConfigs: PropTypes.func.isRequired,
+ t: PropTypes.func,
+ }
+
+ static defaultProps = {
+ t: fallbackT,
}
constructor(props, context) {
@@ -133,7 +143,7 @@ class TopBar extends React.Component {
})
control.push(
-