Proyecto App Linux
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
* Spanish copy for the Xtream / workspace shell UI (replaces merged English in es.json).
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const esPath = path.resolve(
|
||||
__dirname,
|
||||
'..',
|
||||
'..',
|
||||
'apps/web/src/assets/i18n/es.json'
|
||||
);
|
||||
|
||||
const j = JSON.parse(fs.readFileSync(esPath, 'utf8'));
|
||||
|
||||
const shell = {
|
||||
GO_TO_DASHBOARD: 'Volver al panel',
|
||||
GO_TO_SOURCES: 'Ir a fuentes',
|
||||
DROP_OVERLAY_TITLE: 'Suelta para añadir lista',
|
||||
DROP_OVERLAY_BODY:
|
||||
'Suelta un archivo .m3u o .m3u8 en cualquier parte del espacio de trabajo para importarlo.',
|
||||
DROP_OVERLAY_REJECTED_BODY:
|
||||
'Suelta un archivo .m3u o .m3u8. Pulsa Esc para cerrar.',
|
||||
DROP_OVERLAY_REJECTED_UNSUPPORTED: 'Tipo de archivo no admitido',
|
||||
DROP_OVERLAY_REJECTED_EMPTY: 'Ese archivo está vacío',
|
||||
DROP_OVERLAY_REJECTED_READ_ERROR: 'No se pudo leer el archivo',
|
||||
DROP_IMPORT_SUCCESS: 'Importando «{{title}}»…',
|
||||
EXTERNAL_PLAYBACK_CLOSE: 'Cerrar reproductor',
|
||||
BRAND_ALT: 'IPTVnator',
|
||||
RAIL_DASHBOARD: 'Panel',
|
||||
OPEN_DASHBOARD: 'Abrir panel',
|
||||
RAIL_SOURCES: 'Fuentes',
|
||||
OPEN_SOURCES: 'Abrir fuentes',
|
||||
RAIL_GLOBAL_FAVORITES: 'Favoritos globales',
|
||||
RAIL_GLOBAL_RECENT: 'Visto recientemente',
|
||||
RAIL_SETTINGS: 'Ajustes',
|
||||
OPEN_SETTINGS: 'Abrir ajustes',
|
||||
RAIL_LIBRARY: 'Biblioteca',
|
||||
RAIL_MOVIES: 'Películas',
|
||||
RAIL_LIVE: 'TV en directo',
|
||||
RAIL_SERIES: 'Series',
|
||||
RAIL_RECENTLY_ADDED: 'Añadidos recientemente',
|
||||
RAIL_SEARCH: 'Búsqueda avanzada',
|
||||
RAIL_RECENT: 'Visto recientemente',
|
||||
RAIL_FAVORITES: 'Favoritos',
|
||||
RAIL_DOWNLOADS: 'Descargas',
|
||||
RAIL_ALL_CHANNELS: 'Todos los canales',
|
||||
RAIL_GROUPS: 'Grupos',
|
||||
RAIL_CONTEXT_ACTIONS: 'Acciones de la sección',
|
||||
SEARCH_LABEL: 'Buscar',
|
||||
SEARCH_SOURCES_PLACEHOLDER: 'Buscar fuentes (todas las listas)…',
|
||||
SEARCH_PLAYLIST_PLACEHOLDER: 'Buscar en esta lista…',
|
||||
SEARCH_SECTION_PLACEHOLDER: 'Buscar en esta sección…',
|
||||
FILTER_SECTION_PLACEHOLDER: 'Filtrar esta sección…',
|
||||
SEARCH_STATUS_LOADED_ONLY: 'Solo canales cargados',
|
||||
COMMAND_PALETTE_SHORTCUT: 'Paleta de comandos (Ctrl/Cmd+K)',
|
||||
OPEN_COMMAND_PALETTE: 'Abrir paleta de comandos',
|
||||
ADD_PLAYLIST_ALL: 'Añadir lista',
|
||||
ADD_PLAYLIST: 'Añadir lista',
|
||||
OPEN_DOWNLOADS: 'Abrir descargas',
|
||||
OPEN_CONTEXT_ACTIONS: 'Abrir acciones de la sección',
|
||||
NO_SECTION_ACTIONS: 'No hay acciones para esta sección',
|
||||
PLAYLIST_INFO: 'Info de la lista',
|
||||
ACCOUNT_INFO: 'Info de la cuenta',
|
||||
REFRESH_PLAYLIST: 'Actualizar lista',
|
||||
CLEAR_COMPLETED_DOWNLOADS_ALL: 'Borrar descargas completadas (todas las listas)',
|
||||
CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA:
|
||||
'Borrar descargas completadas de todas las listas',
|
||||
CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST:
|
||||
'Borrar descargas completadas (esta lista)',
|
||||
CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST_ARIA:
|
||||
'Borrar descargas completadas de esta lista',
|
||||
CLEAR_RECENTLY_VIEWED_SECTION: 'Borrar visto recientemente',
|
||||
CLEAR_RECENTLY_VIEWED_SECTION_ARIA:
|
||||
'Borrar visto recientemente de esta sección',
|
||||
CLEAR_RECENTLY_VIEWED_TYPE: 'Borrar visto recientemente ({{type}})',
|
||||
CLEAR_RECENTLY_VIEWED_DIALOG_TITLE:
|
||||
'¿Borrar visto recientemente ({{type}})?',
|
||||
CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_PLAYLIST:
|
||||
'Se quitarán del historial todos los elementos de {{type}} de esta lista. No se puede deshacer.',
|
||||
CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_ALL:
|
||||
'Se quitarán del historial todos los elementos de {{type}} de todas las listas. No se puede deshacer.',
|
||||
CLEAR_FAVORITES_TYPE: 'Borrar favoritos de {{type}}',
|
||||
CLEAR_FAVORITES_DIALOG_TITLE: '¿Quitar todos los favoritos de {{type}}?',
|
||||
CLEAR_FAVORITES_DIALOG_MESSAGE_PLAYLIST:
|
||||
'Se quitarán todos los favoritos de {{type}} de esta lista. No se puede deshacer.',
|
||||
CLEAR_FAVORITES_DIALOG_MESSAGE_ALL:
|
||||
'Se quitarán todos los favoritos de {{type}} de todas las listas. No se puede deshacer.',
|
||||
XTREAM_CODE: 'Código Xtream',
|
||||
STALKER_PORTAL: 'Portal Stalker',
|
||||
CHANNELS_COUNT: '{{count}} canales',
|
||||
NO_SOURCES_AVAILABLE: 'No hay fuentes disponibles',
|
||||
ONE_SOURCE_AVAILABLE: '1 fuente disponible',
|
||||
SOURCES_AVAILABLE: '{{count}} fuentes disponibles',
|
||||
XTREAM_IMPORT_TITLE: 'Sincronizando lista',
|
||||
XTREAM_IMPORT_REMOTE_BADGE: 'Fuente remota',
|
||||
XTREAM_IMPORT_LOCAL_BADGE: 'Biblioteca local',
|
||||
XTREAM_IMPORT_DETAIL_REMOTE: 'Esperando respuesta del proveedor.',
|
||||
XTREAM_IMPORT_DETAIL_LOCAL:
|
||||
'Preparando un cambio de lista más rápido para la próxima visita.',
|
||||
XTREAM_IMPORT_PREPARING: 'Preparando biblioteca local…',
|
||||
XTREAM_IMPORT_LOADING: 'Obteniendo datos de la lista…',
|
||||
XTREAM_IMPORT_SAVING: 'Guardando datos de la lista en local…',
|
||||
XTREAM_IMPORT_RESTORING_FAVORITES: 'Restaurando favoritos desde local…',
|
||||
XTREAM_IMPORT_RESTORING_RECENT: 'Restaurando visto recientemente desde local…',
|
||||
XTREAM_IMPORT_PROGRESS: '{{type}} importados: {{current}} / {{total}}',
|
||||
XTREAM_IMPORT_CANCEL: 'Detener sincronización',
|
||||
XTREAM_IMPORT_CANCELLING: 'Deteniendo sincronización…',
|
||||
};
|
||||
|
||||
const shellCommands = {
|
||||
ADD_PLAYLIST_M3U_LABEL: 'Añadir lista M3U',
|
||||
ADD_PLAYLIST_M3U_DESCRIPTION:
|
||||
'Abrir el diálogo en la pestaña de archivo o URL M3U',
|
||||
ADD_PLAYLIST_XTREAM_LABEL: 'Añadir lista Xtream Codes',
|
||||
ADD_PLAYLIST_XTREAM_DESCRIPTION:
|
||||
'Abrir el diálogo en la pestaña Xtream Codes',
|
||||
ADD_PLAYLIST_STALKER_LABEL: 'Añadir portal Stalker',
|
||||
ADD_PLAYLIST_STALKER_DESCRIPTION:
|
||||
'Abrir el diálogo en la pestaña Portal Stalker',
|
||||
GLOBAL_SEARCH_LABEL: 'Buscar en todas las listas Xtream',
|
||||
GLOBAL_SEARCH_DESCRIPTION: 'Abrir búsqueda global',
|
||||
PLAYLIST_SEARCH_LABEL: 'Búsqueda avanzada en esta lista',
|
||||
PLAYLIST_SEARCH_DESCRIPTION: 'Abrir búsqueda avanzada de la lista',
|
||||
OPEN_GLOBAL_FAVORITES_LABEL: 'Abrir favoritos globales',
|
||||
OPEN_GLOBAL_FAVORITES_DESCRIPTION: 'Ir a favoritos agregados',
|
||||
OPEN_DOWNLOADS_LABEL: 'Abrir descargas',
|
||||
OPEN_DOWNLOADS_DESCRIPTION: 'Ir a la vista de descargas',
|
||||
OPEN_GLOBAL_RECENT_LABEL: 'Abrir visto recientemente',
|
||||
OPEN_GLOBAL_RECENT_DESCRIPTION: 'Abrir página global de recientes',
|
||||
OPEN_SETTINGS_LABEL: 'Abrir ajustes',
|
||||
OPEN_SETTINGS_DESCRIPTION: 'Ir a los ajustes de la aplicación',
|
||||
OPEN_SOURCES_LABEL: 'Gestionar fuentes',
|
||||
OPEN_SOURCES_DESCRIPTION: 'Ir a la gestión de fuentes',
|
||||
OPEN_DASHBOARD_LABEL: 'Abrir panel',
|
||||
OPEN_DASHBOARD_DESCRIPTION: 'Ir al panel',
|
||||
ADD_PLAYLIST_LABEL: 'Añadir fuente',
|
||||
ADD_PLAYLIST_DESCRIPTION: 'Abrir diálogo para añadir lista',
|
||||
REFRESH_PLAYLIST_LABEL: 'Actualizar lista',
|
||||
REFRESH_PLAYLIST_DESCRIPTION: 'Volver a sincronizar con el origen',
|
||||
PLAYLIST_INFO_LABEL: 'Detalles de la lista',
|
||||
PLAYLIST_INFO_DESCRIPTION: 'Mostrar información de la lista actual',
|
||||
ACCOUNT_INFO_LABEL: 'Info de la cuenta',
|
||||
ACCOUNT_INFO_DESCRIPTION: 'Mostrar datos de la cuenta Xtream',
|
||||
OPEN_VIEW_DESCRIPTION: 'Ir a {{view}}',
|
||||
CLEAR_CURRENT_VIEW_DESCRIPTION:
|
||||
'Borrar todos los elementos visibles de {{type}} en esta vista',
|
||||
OPEN_MULTI_EPG_DESCRIPTION: 'Abrir la guía multi-canal',
|
||||
GO_TO_VOD_LABEL: 'Películas',
|
||||
GO_TO_VOD_DESCRIPTION: 'Ir a películas',
|
||||
GO_TO_LIVE_LABEL: 'TV en directo',
|
||||
GO_TO_LIVE_DESCRIPTION: 'Ir a TV en directo',
|
||||
GO_TO_SERIES_LABEL: 'Series',
|
||||
GO_TO_SERIES_DESCRIPTION: 'Ir a series',
|
||||
};
|
||||
|
||||
const context = {
|
||||
CATEGORIES: 'Categorías',
|
||||
MOVIE_CATEGORIES: 'Categorías de películas',
|
||||
SERIES_CATEGORIES: 'Categorías de series',
|
||||
LIVE_CATEGORIES: 'Categorías en directo',
|
||||
XTREAM_SYNCING_MOVIES: 'Sincronizando categorías de películas…',
|
||||
XTREAM_SYNCING_SERIES: 'Sincronizando categorías de series…',
|
||||
XTREAM_SYNCING_LIVE: 'Sincronizando categorías en directo…',
|
||||
XTREAM_SOURCE: 'Fuente Xtream',
|
||||
STALKER_PORTAL: 'Portal Stalker',
|
||||
MANAGE_CATEGORIES: 'Gestionar categorías',
|
||||
LOAD_CATEGORIES_ERROR: 'No se pudieron cargar las categorías',
|
||||
LOAD_CATEGORIES_ERROR_HINT:
|
||||
'Reintenta o comprueba la configuración del portal.',
|
||||
FILTER_BY_TYPE: 'Filtrar por tipo',
|
||||
ITEM_COUNT_ONE: '1 elemento',
|
||||
ITEM_COUNT_OTHER: '{{count}} elementos',
|
||||
SEARCH: 'Buscar',
|
||||
SEARCH_CATEGORIES: 'Buscar categorías',
|
||||
};
|
||||
|
||||
const commandPalette = {
|
||||
TITLE: 'Paleta de comandos',
|
||||
SUBTITLE: 'Acciones globales y del contexto',
|
||||
SEARCH_PLACEHOLDER: 'Escribe para filtrar comandos',
|
||||
SEARCH_LABEL: 'Filtrar comandos',
|
||||
EMPTY: 'No se encontraron comandos',
|
||||
GROUP_GLOBAL: 'Acciones globales',
|
||||
GROUP_PLAYLIST: 'Esta lista',
|
||||
GROUP_VIEW: 'Vista actual',
|
||||
GROUP_SECTION: 'Esta sección',
|
||||
};
|
||||
|
||||
j.WORKSPACE = j.WORKSPACE || {};
|
||||
j.WORKSPACE.SHELL = { ...j.WORKSPACE.SHELL, ...shell };
|
||||
j.WORKSPACE.SHELL.COMMANDS = {
|
||||
...j.WORKSPACE.SHELL.COMMANDS,
|
||||
...shellCommands,
|
||||
};
|
||||
j.WORKSPACE.CONTEXT = { ...j.WORKSPACE.CONTEXT, ...context };
|
||||
j.WORKSPACE.COMMAND_PALETTE = {
|
||||
...j.WORKSPACE.COMMAND_PALETTE,
|
||||
...commandPalette,
|
||||
};
|
||||
|
||||
if (j.PORTALS) {
|
||||
j.PORTALS.SELECT_CATEGORY = 'Selecciona una categoría';
|
||||
}
|
||||
|
||||
if (j.CANCEL === 'Cancel') j.CANCEL = 'Cancelar';
|
||||
if (j.CLEAR === 'Clear') j.CLEAR = 'Limpiar';
|
||||
if (j.SHOW_MORE === 'More') j.SHOW_MORE = 'Más';
|
||||
if (j.SHOW_LESS === 'Less') j.SHOW_LESS = 'Menos';
|
||||
if (j.PLAYLISTS === 'Playlists') j.PLAYLISTS = 'Listas de reproducción';
|
||||
|
||||
if (j.REMOTE_CONTROL?.TITLE === 'Remote control') {
|
||||
j.REMOTE_CONTROL = {
|
||||
...j.REMOTE_CONTROL,
|
||||
TITLE: 'Control remoto',
|
||||
SUBTITLE: 'Controla el reproductor IPTV a distancia',
|
||||
UP_CHANNEL: 'Canal siguiente',
|
||||
DOWN_CHANNEL: 'Canal anterior',
|
||||
HEADER: 'Control remoto IPTVnator',
|
||||
FOOTER: 'Control remoto IPTVnator',
|
||||
};
|
||||
}
|
||||
|
||||
fs.writeFileSync(esPath, JSON.stringify(j, null, 4) + '\n');
|
||||
console.log('Applied Spanish UI strings for WORKSPACE shell / PORTALS / root keys.');
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Recursively copies missing keys from en.json into es.json (does not overwrite
|
||||
* existing Spanish strings). Fixes ngx-translate showing raw keys like WORKSPACE.SHELL.*.
|
||||
*
|
||||
* After running this, optionally run `node tools/i18n/apply-shell-es-ui.mjs` to
|
||||
* replace merged English workspace shell strings with Spanish for KiraTV / es UI.
|
||||
*/
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.resolve(__dirname, '..', '..');
|
||||
const enPath = path.join(root, 'apps/web/src/assets/i18n/en.json');
|
||||
const esPath = path.join(root, 'apps/web/src/assets/i18n/es.json');
|
||||
|
||||
function fillMissing(enVal, esVal) {
|
||||
if (enVal === null || typeof enVal !== 'object' || Array.isArray(enVal)) {
|
||||
return esVal !== undefined ? esVal : enVal;
|
||||
}
|
||||
const out =
|
||||
esVal !== null && typeof esVal === 'object' && !Array.isArray(esVal)
|
||||
? { ...esVal }
|
||||
: {};
|
||||
for (const [k, v] of Object.entries(enVal)) {
|
||||
if (out[k] === undefined) {
|
||||
out[k] = Array.isArray(v) ? [...v] : v;
|
||||
} else if (
|
||||
v !== null &&
|
||||
typeof v === 'object' &&
|
||||
!Array.isArray(v) &&
|
||||
typeof out[k] === 'object' &&
|
||||
!Array.isArray(out[k])
|
||||
) {
|
||||
out[k] = fillMissing(v, out[k]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const en = JSON.parse(fs.readFileSync(enPath, 'utf8'));
|
||||
const es = JSON.parse(fs.readFileSync(esPath, 'utf8'));
|
||||
const merged = fillMissing(en, es);
|
||||
fs.writeFileSync(esPath, JSON.stringify(merged, null, 4) + '\n');
|
||||
console.log('Merged missing i18n keys from en.json into es.json');
|
||||
Reference in New Issue
Block a user