feat(editor): translate Save / Share / LoginPrompt modals (Editor block 3)
The three modal dialogs that fire during the editor's routine save +
share + auth-required flows are now fully localised across all 9
locales.
LoginPromptModal
- Title, body, and the three buttons (Sign in / Create account /
Cancel). Sign in / Sign up Links use localize() so a Spanish
reader prompted to log in lands at /es/login rather than dropping
back to English.
SaveProjectModal
- Title (toggles between Save / Update), name + description fields
with placeholders, save button (toggles between Save / Update /
Saving…), Cancel button.
- Visibility toggle: Public / Private label + hint copy under the
icon.
- All four error paths now go through t() with a {{status}}
interpolation for the generic HTTP failure message.
ShareModal
- Title, public/private label + hint pair, "Make private" /
"Make public" toggle, Copy button, the warning shown when the
project is private, and the Close button.
Hand-curated translations for all 8 non-English locales. Status
codes (403) and shortcut markers preserved.
This commit is contained in:
parent
7f0ac2a74c
commit
fa4f3d6e80
|
|
@ -1,28 +1,34 @@
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useLocalizedHref } from '../../i18n/useLocalizedNavigate';
|
||||||
|
|
||||||
interface LoginPromptModalProps {
|
interface LoginPromptModalProps {
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const LoginPromptModal: React.FC<LoginPromptModalProps> = ({ onClose }) => (
|
export const LoginPromptModal: React.FC<LoginPromptModalProps> = ({ onClose }) => {
|
||||||
<div style={styles.overlay} onClick={onClose}>
|
const { t } = useTranslation();
|
||||||
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
const localize = useLocalizedHref();
|
||||||
<h2 style={styles.title}>Sign in to save your project</h2>
|
return (
|
||||||
<p style={styles.body}>Create a free account to save and share your projects.</p>
|
<div style={styles.overlay} onClick={onClose}>
|
||||||
<div style={styles.actions}>
|
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
||||||
<Link to="/login" style={styles.primaryBtn}>
|
<h2 style={styles.title}>{t('editor.loginPrompt.title')}</h2>
|
||||||
Sign in
|
<p style={styles.body}>{t('editor.loginPrompt.body')}</p>
|
||||||
</Link>
|
<div style={styles.actions}>
|
||||||
<Link to="/register" style={styles.secondaryBtn}>
|
<Link to={localize('/login')} style={styles.primaryBtn}>
|
||||||
Create account
|
{t('header.auth.signIn')}
|
||||||
</Link>
|
</Link>
|
||||||
<button onClick={onClose} style={styles.cancelBtn}>
|
<Link to={localize('/register')} style={styles.secondaryBtn}>
|
||||||
Cancel
|
{t('editor.loginPrompt.createAccount')}
|
||||||
</button>
|
</Link>
|
||||||
|
<button onClick={onClose} style={styles.cancelBtn}>
|
||||||
|
{t('editor.loginPrompt.cancel')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
const styles: Record<string, React.CSSProperties> = {
|
const styles: Record<string, React.CSSProperties> = {
|
||||||
overlay: {
|
overlay: {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useProjectStore } from '../../store/useProjectStore';
|
import { useProjectStore } from '../../store/useProjectStore';
|
||||||
import { createProject, updateProject } from '../../services/projectService';
|
import { createProject, updateProject } from '../../services/projectService';
|
||||||
import { trackCreateProject, trackSaveProject } from '../../utils/analytics';
|
import { trackCreateProject, trackSaveProject } from '../../utils/analytics';
|
||||||
|
|
@ -10,6 +11,7 @@ interface SaveProjectModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) => {
|
export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const currentProject = useProjectStore((s) => s.currentProject);
|
const currentProject = useProjectStore((s) => s.currentProject);
|
||||||
const setCurrentProject = useProjectStore((s) => s.setCurrentProject);
|
const setCurrentProject = useProjectStore((s) => s.setCurrentProject);
|
||||||
|
|
@ -32,7 +34,7 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
const handleSave = async (e: React.FormEvent) => {
|
const handleSave = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!name.trim()) {
|
if (!name.trim()) {
|
||||||
setError('Project name is required.');
|
setError(t('editor.saveProject.errors.nameRequired'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
|
|
@ -67,11 +69,14 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (!err?.response) {
|
if (!err?.response) {
|
||||||
setError('Server unreachable. Check your connection and try again.');
|
setError(t('editor.saveProject.errors.unreachable'));
|
||||||
} else if (err.response.status === 401) {
|
} else if (err.response.status === 401) {
|
||||||
setError('Not authenticated. Please log in and try again.');
|
setError(t('editor.saveProject.errors.notAuth'));
|
||||||
} else {
|
} else {
|
||||||
setError(err.response?.data?.detail || `Save failed (${err.response.status}).`);
|
setError(
|
||||||
|
err.response?.data?.detail ||
|
||||||
|
t('editor.saveProject.errors.failedStatus', { status: err.response.status })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setSaving(false);
|
setSaving(false);
|
||||||
|
|
@ -81,12 +86,14 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
return (
|
return (
|
||||||
<div style={styles.overlay} onClick={onClose}>
|
<div style={styles.overlay} onClick={onClose}>
|
||||||
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
||||||
<h2 style={styles.title}>{isUpdate ? 'Update project' : 'Save project'}</h2>
|
<h2 style={styles.title}>
|
||||||
|
{isUpdate ? t('editor.saveProject.titleUpdate') : t('editor.saveProject.titleSave')}
|
||||||
|
</h2>
|
||||||
|
|
||||||
{error && <div style={styles.error}>{error}</div>}
|
{error && <div style={styles.error}>{error}</div>}
|
||||||
|
|
||||||
<form onSubmit={handleSave} style={styles.form}>
|
<form onSubmit={handleSave} style={styles.form}>
|
||||||
<label style={styles.label}>Project name *</label>
|
<label style={styles.label}>{t('editor.saveProject.nameLabel')}</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={name}
|
value={name}
|
||||||
|
|
@ -94,16 +101,16 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
required
|
required
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder="My awesome project"
|
placeholder={t('editor.saveProject.namePlaceholder')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<label style={styles.label}>Description</label>
|
<label style={styles.label}>{t('editor.saveProject.descriptionLabel')}</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
value={description}
|
value={description}
|
||||||
onChange={(e) => setDescription(e.target.value)}
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
placeholder="Optional"
|
placeholder={t('editor.saveProject.descriptionPlaceholder')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|
@ -147,10 +154,14 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
<div
|
<div
|
||||||
style={{ color: isPublic ? '#4ade80' : '#f59e0b', fontSize: 13, fontWeight: 600 }}
|
style={{ color: isPublic ? '#4ade80' : '#f59e0b', fontSize: 13, fontWeight: 600 }}
|
||||||
>
|
>
|
||||||
{isPublic ? 'Public' : 'Private'}
|
{isPublic
|
||||||
|
? t('editor.saveProject.visibility.public')
|
||||||
|
: t('editor.saveProject.visibility.private')}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: '#888', fontSize: 11 }}>
|
<div style={{ color: '#888', fontSize: 11 }}>
|
||||||
{isPublic ? 'Anyone with the link can view' : 'Only you can see this'}
|
{isPublic
|
||||||
|
? t('editor.saveProject.visibility.publicHint')
|
||||||
|
: t('editor.saveProject.visibility.privateHint')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -158,10 +169,14 @@ export const SaveProjectModal: React.FC<SaveProjectModalProps> = ({ onClose }) =
|
||||||
|
|
||||||
<div style={styles.actions}>
|
<div style={styles.actions}>
|
||||||
<button type="submit" disabled={saving} style={styles.saveBtn}>
|
<button type="submit" disabled={saving} style={styles.saveBtn}>
|
||||||
{saving ? 'Saving…' : isUpdate ? 'Update' : 'Save'}
|
{saving
|
||||||
|
? t('editor.saveProject.saving')
|
||||||
|
: isUpdate
|
||||||
|
? t('editor.saveProject.update')
|
||||||
|
: t('editor.saveProject.save')}
|
||||||
</button>
|
</button>
|
||||||
<button type="button" onClick={onClose} style={styles.cancelBtn}>
|
<button type="button" onClick={onClose} style={styles.cancelBtn}>
|
||||||
Cancel
|
{t('editor.saveProject.cancel')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useProjectStore } from '../../store/useProjectStore';
|
import { useProjectStore } from '../../store/useProjectStore';
|
||||||
import { updateProject } from '../../services/projectService';
|
import { updateProject } from '../../services/projectService';
|
||||||
|
|
||||||
|
|
@ -12,6 +13,7 @@ interface ShareModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
const currentProject = useProjectStore((s) => s.currentProject);
|
const currentProject = useProjectStore((s) => s.currentProject);
|
||||||
const setVisibility = useProjectStore((s) => s.setVisibility);
|
const setVisibility = useProjectStore((s) => s.setVisibility);
|
||||||
const [copied, setCopied] = useState(false);
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
@ -44,7 +46,7 @@ export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
||||||
return createPortal(
|
return createPortal(
|
||||||
<div style={styles.overlay} onClick={onClose}>
|
<div style={styles.overlay} onClick={onClose}>
|
||||||
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
<div style={styles.modal} onClick={(e) => e.stopPropagation()}>
|
||||||
<h2 style={styles.title}>Share project</h2>
|
<h2 style={styles.title}>{t('editor.share.title')}</h2>
|
||||||
|
|
||||||
{/* Visibility toggle */}
|
{/* Visibility toggle */}
|
||||||
<div style={styles.visibilityRow}>
|
<div style={styles.visibilityRow}>
|
||||||
|
|
@ -83,13 +85,11 @@ export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
||||||
<span
|
<span
|
||||||
style={{ color: isPublic ? '#4ade80' : '#f59e0b', fontWeight: 600, fontSize: 13 }}
|
style={{ color: isPublic ? '#4ade80' : '#f59e0b', fontWeight: 600, fontSize: 13 }}
|
||||||
>
|
>
|
||||||
{isPublic ? 'Public' : 'Private'}
|
{isPublic ? t('editor.share.public') : t('editor.share.private')}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span style={{ color: '#888', fontSize: 12 }}>
|
<span style={{ color: '#888', fontSize: 12 }}>
|
||||||
{isPublic
|
{isPublic ? t('editor.share.publicHint') : t('editor.share.privateHint')}
|
||||||
? 'Anyone with the link can view this project'
|
|
||||||
: 'Only you can see this project'}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|
@ -100,7 +100,11 @@ export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
||||||
opacity: toggling ? 0.5 : 1,
|
opacity: toggling ? 0.5 : 1,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{toggling ? '...' : isPublic ? 'Make private' : 'Make public'}
|
{toggling
|
||||||
|
? '...'
|
||||||
|
: isPublic
|
||||||
|
? t('editor.share.makePrivate')
|
||||||
|
: t('editor.share.makePublic')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -128,20 +132,18 @@ export const ShareModal: React.FC<ShareModalProps> = ({ onClose }) => {
|
||||||
<polyline points="20 6 9 17 4 12" />
|
<polyline points="20 6 9 17 4 12" />
|
||||||
</svg>
|
</svg>
|
||||||
) : (
|
) : (
|
||||||
'Copy'
|
t('editor.share.copy')
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!isPublic && (
|
{!isPublic && (
|
||||||
<div style={styles.warning}>
|
<div style={styles.warning}>{t('editor.share.privateWarning')}</div>
|
||||||
This project is private. Others will see a 403 error when opening this link.
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div style={styles.actions}>
|
<div style={styles.actions}>
|
||||||
<button onClick={onClose} style={styles.closeBtn}>
|
<button onClick={onClose} style={styles.closeBtn}>
|
||||||
Close
|
{t('editor.share.close')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Datei mit nicht gespeicherten Änderungen schließen?",
|
"confirmClose": "Datei mit nicht gespeicherten Änderungen schließen?",
|
||||||
"closeAnyway": "Trotzdem schließen",
|
"closeAnyway": "Trotzdem schließen",
|
||||||
"cancel": "Abbrechen"
|
"cancel": "Abbrechen"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Anmelden, um dein Projekt zu speichern",
|
||||||
|
"body": "Erstelle ein kostenloses Konto, um deine Projekte zu speichern und zu teilen.",
|
||||||
|
"createAccount": "Konto erstellen",
|
||||||
|
"cancel": "Abbrechen"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Projekt speichern",
|
||||||
|
"titleUpdate": "Projekt aktualisieren",
|
||||||
|
"nameLabel": "Projektname *",
|
||||||
|
"namePlaceholder": "Mein tolles Projekt",
|
||||||
|
"descriptionLabel": "Beschreibung",
|
||||||
|
"descriptionPlaceholder": "Optional",
|
||||||
|
"save": "Speichern",
|
||||||
|
"update": "Aktualisieren",
|
||||||
|
"saving": "Wird gespeichert…",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Öffentlich",
|
||||||
|
"publicHint": "Jeder mit dem Link kann es sehen",
|
||||||
|
"private": "Privat",
|
||||||
|
"privateHint": "Nur du kannst es sehen"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "Projektname ist erforderlich.",
|
||||||
|
"unreachable": "Server nicht erreichbar. Verbindung prüfen und erneut versuchen.",
|
||||||
|
"notAuth": "Nicht angemeldet. Bitte anmelden und erneut versuchen.",
|
||||||
|
"failedStatus": "Speichern fehlgeschlagen ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Projekt teilen",
|
||||||
|
"public": "Öffentlich",
|
||||||
|
"private": "Privat",
|
||||||
|
"publicHint": "Jeder mit dem Link kann dieses Projekt sehen",
|
||||||
|
"privateHint": "Nur du kannst dieses Projekt sehen",
|
||||||
|
"makePrivate": "Auf privat setzen",
|
||||||
|
"makePublic": "Auf öffentlich setzen",
|
||||||
|
"copy": "Kopieren",
|
||||||
|
"privateWarning": "Dieses Projekt ist privat. Andere sehen beim Öffnen des Links einen 403-Fehler.",
|
||||||
|
"close": "Schließen"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Close file with unsaved changes?",
|
"confirmClose": "Close file with unsaved changes?",
|
||||||
"closeAnyway": "Close anyway",
|
"closeAnyway": "Close anyway",
|
||||||
"cancel": "Cancel"
|
"cancel": "Cancel"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Sign in to save your project",
|
||||||
|
"body": "Create a free account to save and share your projects.",
|
||||||
|
"createAccount": "Create account",
|
||||||
|
"cancel": "Cancel"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Save project",
|
||||||
|
"titleUpdate": "Update project",
|
||||||
|
"nameLabel": "Project name *",
|
||||||
|
"namePlaceholder": "My awesome project",
|
||||||
|
"descriptionLabel": "Description",
|
||||||
|
"descriptionPlaceholder": "Optional",
|
||||||
|
"save": "Save",
|
||||||
|
"update": "Update",
|
||||||
|
"saving": "Saving…",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Public",
|
||||||
|
"publicHint": "Anyone with the link can view",
|
||||||
|
"private": "Private",
|
||||||
|
"privateHint": "Only you can see this"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "Project name is required.",
|
||||||
|
"unreachable": "Server unreachable. Check your connection and try again.",
|
||||||
|
"notAuth": "Not authenticated. Please log in and try again.",
|
||||||
|
"failedStatus": "Save failed ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Share project",
|
||||||
|
"public": "Public",
|
||||||
|
"private": "Private",
|
||||||
|
"publicHint": "Anyone with the link can view this project",
|
||||||
|
"privateHint": "Only you can see this project",
|
||||||
|
"makePrivate": "Make private",
|
||||||
|
"makePublic": "Make public",
|
||||||
|
"copy": "Copy",
|
||||||
|
"privateWarning": "This project is private. Others will see a 403 error when opening this link.",
|
||||||
|
"close": "Close"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "¿Cerrar archivo con cambios sin guardar?",
|
"confirmClose": "¿Cerrar archivo con cambios sin guardar?",
|
||||||
"closeAnyway": "Cerrar igualmente",
|
"closeAnyway": "Cerrar igualmente",
|
||||||
"cancel": "Cancelar"
|
"cancel": "Cancelar"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Inicia sesión para guardar tu proyecto",
|
||||||
|
"body": "Crea una cuenta gratis para guardar y compartir tus proyectos.",
|
||||||
|
"createAccount": "Crear cuenta",
|
||||||
|
"cancel": "Cancelar"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Guardar proyecto",
|
||||||
|
"titleUpdate": "Actualizar proyecto",
|
||||||
|
"nameLabel": "Nombre del proyecto *",
|
||||||
|
"namePlaceholder": "Mi proyecto increíble",
|
||||||
|
"descriptionLabel": "Descripción",
|
||||||
|
"descriptionPlaceholder": "Opcional",
|
||||||
|
"save": "Guardar",
|
||||||
|
"update": "Actualizar",
|
||||||
|
"saving": "Guardando…",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Público",
|
||||||
|
"publicHint": "Cualquiera con el enlace puede verlo",
|
||||||
|
"private": "Privado",
|
||||||
|
"privateHint": "Solo tú puedes verlo"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "El nombre del proyecto es obligatorio.",
|
||||||
|
"unreachable": "Servidor no disponible. Comprueba la conexión e inténtalo de nuevo.",
|
||||||
|
"notAuth": "No autenticado. Inicia sesión e inténtalo de nuevo.",
|
||||||
|
"failedStatus": "Error al guardar ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Compartir proyecto",
|
||||||
|
"public": "Público",
|
||||||
|
"private": "Privado",
|
||||||
|
"publicHint": "Cualquiera con el enlace puede ver este proyecto",
|
||||||
|
"privateHint": "Solo tú puedes ver este proyecto",
|
||||||
|
"makePrivate": "Hacer privado",
|
||||||
|
"makePublic": "Hacer público",
|
||||||
|
"copy": "Copiar",
|
||||||
|
"privateWarning": "Este proyecto es privado. Otros verán un error 403 al abrir este enlace.",
|
||||||
|
"close": "Cerrar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Fermer le fichier avec des modifications non enregistrées ?",
|
"confirmClose": "Fermer le fichier avec des modifications non enregistrées ?",
|
||||||
"closeAnyway": "Fermer quand même",
|
"closeAnyway": "Fermer quand même",
|
||||||
"cancel": "Annuler"
|
"cancel": "Annuler"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Connectez-vous pour enregistrer votre projet",
|
||||||
|
"body": "Créez un compte gratuit pour enregistrer et partager vos projets.",
|
||||||
|
"createAccount": "Créer un compte",
|
||||||
|
"cancel": "Annuler"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Enregistrer le projet",
|
||||||
|
"titleUpdate": "Mettre à jour le projet",
|
||||||
|
"nameLabel": "Nom du projet *",
|
||||||
|
"namePlaceholder": "Mon super projet",
|
||||||
|
"descriptionLabel": "Description",
|
||||||
|
"descriptionPlaceholder": "Optionnel",
|
||||||
|
"save": "Enregistrer",
|
||||||
|
"update": "Mettre à jour",
|
||||||
|
"saving": "Enregistrement…",
|
||||||
|
"cancel": "Annuler",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Public",
|
||||||
|
"publicHint": "Toute personne avec le lien peut voir",
|
||||||
|
"private": "Privé",
|
||||||
|
"privateHint": "Vous seul pouvez le voir"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "Le nom du projet est obligatoire.",
|
||||||
|
"unreachable": "Serveur injoignable. Vérifiez votre connexion et réessayez.",
|
||||||
|
"notAuth": "Non authentifié. Connectez-vous et réessayez.",
|
||||||
|
"failedStatus": "Échec de l'enregistrement ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Partager le projet",
|
||||||
|
"public": "Public",
|
||||||
|
"private": "Privé",
|
||||||
|
"publicHint": "Toute personne avec le lien peut voir ce projet",
|
||||||
|
"privateHint": "Vous seul pouvez voir ce projet",
|
||||||
|
"makePrivate": "Rendre privé",
|
||||||
|
"makePublic": "Rendre public",
|
||||||
|
"copy": "Copier",
|
||||||
|
"privateWarning": "Ce projet est privé. Les autres verront une erreur 403 en ouvrant ce lien.",
|
||||||
|
"close": "Fermer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Chiudere il file con modifiche non salvate?",
|
"confirmClose": "Chiudere il file con modifiche non salvate?",
|
||||||
"closeAnyway": "Chiudi comunque",
|
"closeAnyway": "Chiudi comunque",
|
||||||
"cancel": "Annulla"
|
"cancel": "Annulla"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Accedi per salvare il tuo progetto",
|
||||||
|
"body": "Crea un account gratuito per salvare e condividere i tuoi progetti.",
|
||||||
|
"createAccount": "Crea account",
|
||||||
|
"cancel": "Annulla"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Salva progetto",
|
||||||
|
"titleUpdate": "Aggiorna progetto",
|
||||||
|
"nameLabel": "Nome del progetto *",
|
||||||
|
"namePlaceholder": "Il mio fantastico progetto",
|
||||||
|
"descriptionLabel": "Descrizione",
|
||||||
|
"descriptionPlaceholder": "Opzionale",
|
||||||
|
"save": "Salva",
|
||||||
|
"update": "Aggiorna",
|
||||||
|
"saving": "Salvataggio…",
|
||||||
|
"cancel": "Annulla",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Pubblico",
|
||||||
|
"publicHint": "Chiunque abbia il link può vederlo",
|
||||||
|
"private": "Privato",
|
||||||
|
"privateHint": "Solo tu puoi vederlo"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "Il nome del progetto è obbligatorio.",
|
||||||
|
"unreachable": "Server irraggiungibile. Controlla la connessione e riprova.",
|
||||||
|
"notAuth": "Non autenticato. Effettua l'accesso e riprova.",
|
||||||
|
"failedStatus": "Salvataggio fallito ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Condividi progetto",
|
||||||
|
"public": "Pubblico",
|
||||||
|
"private": "Privato",
|
||||||
|
"publicHint": "Chiunque abbia il link può vedere questo progetto",
|
||||||
|
"privateHint": "Solo tu puoi vedere questo progetto",
|
||||||
|
"makePrivate": "Rendi privato",
|
||||||
|
"makePublic": "Rendi pubblico",
|
||||||
|
"copy": "Copia",
|
||||||
|
"privateWarning": "Questo progetto è privato. Gli altri vedranno un errore 403 aprendo il link.",
|
||||||
|
"close": "Chiudi"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "未保存の変更があるファイルを閉じますか?",
|
"confirmClose": "未保存の変更があるファイルを閉じますか?",
|
||||||
"closeAnyway": "それでも閉じる",
|
"closeAnyway": "それでも閉じる",
|
||||||
"cancel": "キャンセル"
|
"cancel": "キャンセル"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "プロジェクトを保存するにはサインインしてください",
|
||||||
|
"body": "無料アカウントを作成して、プロジェクトを保存・共有しましょう。",
|
||||||
|
"createAccount": "アカウントを作成",
|
||||||
|
"cancel": "キャンセル"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "プロジェクトを保存",
|
||||||
|
"titleUpdate": "プロジェクトを更新",
|
||||||
|
"nameLabel": "プロジェクト名 *",
|
||||||
|
"namePlaceholder": "私の素敵なプロジェクト",
|
||||||
|
"descriptionLabel": "説明",
|
||||||
|
"descriptionPlaceholder": "任意",
|
||||||
|
"save": "保存",
|
||||||
|
"update": "更新",
|
||||||
|
"saving": "保存中…",
|
||||||
|
"cancel": "キャンセル",
|
||||||
|
"visibility": {
|
||||||
|
"public": "公開",
|
||||||
|
"publicHint": "リンクを持つ人なら誰でも閲覧できます",
|
||||||
|
"private": "非公開",
|
||||||
|
"privateHint": "あなただけが閲覧できます"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "プロジェクト名は必須です。",
|
||||||
|
"unreachable": "サーバーに接続できません。接続を確認してもう一度お試しください。",
|
||||||
|
"notAuth": "認証されていません。ログインしてもう一度お試しください。",
|
||||||
|
"failedStatus": "保存に失敗しました({{status}})。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "プロジェクトを共有",
|
||||||
|
"public": "公開",
|
||||||
|
"private": "非公開",
|
||||||
|
"publicHint": "リンクを持つ人なら誰でもこのプロジェクトを閲覧できます",
|
||||||
|
"privateHint": "このプロジェクトはあなただけが閲覧できます",
|
||||||
|
"makePrivate": "非公開にする",
|
||||||
|
"makePublic": "公開にする",
|
||||||
|
"copy": "コピー",
|
||||||
|
"privateWarning": "このプロジェクトは非公開です。他の人がこのリンクを開くと 403 エラーが表示されます。",
|
||||||
|
"close": "閉じる"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Fechar arquivo com alterações não salvas?",
|
"confirmClose": "Fechar arquivo com alterações não salvas?",
|
||||||
"closeAnyway": "Fechar mesmo assim",
|
"closeAnyway": "Fechar mesmo assim",
|
||||||
"cancel": "Cancelar"
|
"cancel": "Cancelar"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Entre para salvar seu projeto",
|
||||||
|
"body": "Crie uma conta gratuita para salvar e compartilhar seus projetos.",
|
||||||
|
"createAccount": "Criar conta",
|
||||||
|
"cancel": "Cancelar"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Salvar projeto",
|
||||||
|
"titleUpdate": "Atualizar projeto",
|
||||||
|
"nameLabel": "Nome do projeto *",
|
||||||
|
"namePlaceholder": "Meu projeto incrível",
|
||||||
|
"descriptionLabel": "Descrição",
|
||||||
|
"descriptionPlaceholder": "Opcional",
|
||||||
|
"save": "Salvar",
|
||||||
|
"update": "Atualizar",
|
||||||
|
"saving": "Salvando…",
|
||||||
|
"cancel": "Cancelar",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Público",
|
||||||
|
"publicHint": "Qualquer pessoa com o link pode visualizar",
|
||||||
|
"private": "Privado",
|
||||||
|
"privateHint": "Somente você pode ver"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "O nome do projeto é obrigatório.",
|
||||||
|
"unreachable": "Servidor inacessível. Verifique sua conexão e tente novamente.",
|
||||||
|
"notAuth": "Não autenticado. Faça login e tente novamente.",
|
||||||
|
"failedStatus": "Falha ao salvar ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Compartilhar projeto",
|
||||||
|
"public": "Público",
|
||||||
|
"private": "Privado",
|
||||||
|
"publicHint": "Qualquer pessoa com o link pode ver este projeto",
|
||||||
|
"privateHint": "Somente você pode ver este projeto",
|
||||||
|
"makePrivate": "Tornar privado",
|
||||||
|
"makePublic": "Tornar público",
|
||||||
|
"copy": "Copiar",
|
||||||
|
"privateWarning": "Este projeto é privado. Outros verão um erro 403 ao abrir este link.",
|
||||||
|
"close": "Fechar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "Закрыть файл с несохранёнными изменениями?",
|
"confirmClose": "Закрыть файл с несохранёнными изменениями?",
|
||||||
"closeAnyway": "Всё равно закрыть",
|
"closeAnyway": "Всё равно закрыть",
|
||||||
"cancel": "Отмена"
|
"cancel": "Отмена"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "Войдите, чтобы сохранить проект",
|
||||||
|
"body": "Создайте бесплатный аккаунт, чтобы сохранять и делиться своими проектами.",
|
||||||
|
"createAccount": "Создать аккаунт",
|
||||||
|
"cancel": "Отмена"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "Сохранить проект",
|
||||||
|
"titleUpdate": "Обновить проект",
|
||||||
|
"nameLabel": "Имя проекта *",
|
||||||
|
"namePlaceholder": "Мой потрясающий проект",
|
||||||
|
"descriptionLabel": "Описание",
|
||||||
|
"descriptionPlaceholder": "Необязательно",
|
||||||
|
"save": "Сохранить",
|
||||||
|
"update": "Обновить",
|
||||||
|
"saving": "Сохранение…",
|
||||||
|
"cancel": "Отмена",
|
||||||
|
"visibility": {
|
||||||
|
"public": "Публичный",
|
||||||
|
"publicHint": "Любой по ссылке может посмотреть",
|
||||||
|
"private": "Приватный",
|
||||||
|
"privateHint": "Видите только вы"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "Имя проекта обязательно.",
|
||||||
|
"unreachable": "Сервер недоступен. Проверьте соединение и попробуйте снова.",
|
||||||
|
"notAuth": "Не авторизованы. Войдите и попробуйте снова.",
|
||||||
|
"failedStatus": "Сохранение не удалось ({{status}})."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "Поделиться проектом",
|
||||||
|
"public": "Публичный",
|
||||||
|
"private": "Приватный",
|
||||||
|
"publicHint": "Любой по ссылке может посмотреть этот проект",
|
||||||
|
"privateHint": "Этот проект видите только вы",
|
||||||
|
"makePrivate": "Сделать приватным",
|
||||||
|
"makePublic": "Сделать публичным",
|
||||||
|
"copy": "Копировать",
|
||||||
|
"privateWarning": "Этот проект приватный. Другие увидят ошибку 403 при открытии ссылки.",
|
||||||
|
"close": "Закрыть"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,48 @@
|
||||||
"confirmClose": "确定关闭包含未保存更改的文件吗?",
|
"confirmClose": "确定关闭包含未保存更改的文件吗?",
|
||||||
"closeAnyway": "仍然关闭",
|
"closeAnyway": "仍然关闭",
|
||||||
"cancel": "取消"
|
"cancel": "取消"
|
||||||
|
},
|
||||||
|
"loginPrompt": {
|
||||||
|
"title": "登录以保存您的项目",
|
||||||
|
"body": "免费创建账户即可保存并分享您的项目。",
|
||||||
|
"createAccount": "创建账户",
|
||||||
|
"cancel": "取消"
|
||||||
|
},
|
||||||
|
"saveProject": {
|
||||||
|
"titleSave": "保存项目",
|
||||||
|
"titleUpdate": "更新项目",
|
||||||
|
"nameLabel": "项目名称 *",
|
||||||
|
"namePlaceholder": "我的精彩项目",
|
||||||
|
"descriptionLabel": "描述",
|
||||||
|
"descriptionPlaceholder": "可选",
|
||||||
|
"save": "保存",
|
||||||
|
"update": "更新",
|
||||||
|
"saving": "保存中…",
|
||||||
|
"cancel": "取消",
|
||||||
|
"visibility": {
|
||||||
|
"public": "公开",
|
||||||
|
"publicHint": "任何拥有此链接的人都可以查看",
|
||||||
|
"private": "私有",
|
||||||
|
"privateHint": "仅您可见"
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"nameRequired": "项目名称必填。",
|
||||||
|
"unreachable": "无法连接到服务器。请检查网络后重试。",
|
||||||
|
"notAuth": "未登录。请登录后重试。",
|
||||||
|
"failedStatus": "保存失败 ({{status}})。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"title": "分享项目",
|
||||||
|
"public": "公开",
|
||||||
|
"private": "私有",
|
||||||
|
"publicHint": "任何拥有此链接的人都可以查看本项目",
|
||||||
|
"privateHint": "仅您可见本项目",
|
||||||
|
"makePrivate": "设为私有",
|
||||||
|
"makePublic": "设为公开",
|
||||||
|
"copy": "复制",
|
||||||
|
"privateWarning": "此项目为私有。他人打开此链接将看到 403 错误。",
|
||||||
|
"close": "关闭"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue