refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
< ? php
return [
'title' => 'Posts' ,
2026-03-31 00:18:07 +00:00
'search' => 'Buscar posts...' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'all_posts' => 'Todos los posts' ,
'new_post' => 'Nuevo post' ,
'no_posts' => 'No se encontraron posts' ,
2026-05-02 15:22:42 +00:00
'no_search_results' => 'Ningún post coincide con tu búsqueda' ,
'try_different_search' => 'Prueba otra palabra clave o limpia la búsqueda.' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'start_creating' => 'Empieza creando tu primer post.' ,
feat(posts): multi-select label filter on the posts list
Adds a combobox-style filter to the posts index toolbar so users can
narrow All / Scheduled / Posted / Drafts views by one or more labels.
- `PostController::index` accepts `?labels[]=<id>` and applies
`whereHas('labels', whereIn(...))` (OR semantics across selected labels).
Workspace labels are exposed to the page (sorted by name) and the
selected set comes back under `filters.labels`.
- New `LabelFilter.vue` component reuses the existing Popover + Command
pattern (matching `FontPicker` in the Brand settings page). Trigger
renders the selected `LabelBadge`s inline (mirroring how each post row
already displays its labels): 1-3 shown directly, 4+ shown as the
first three plus a "+N" overflow indicator. Clear button has a
tooltip and `cursor-pointer`, and stops `click`/`pointerdown`/
`mousedown` so it doesn't reopen the Popover.
- Existing search debounce is shared with the new label watcher via a
single `buildFilterUrl` helper. URL is updated with `preserveState +
replace` so the back stack stays clean.
- i18n in en / pt-BR / es: `filter_by_label`, `label_search_placeholder`,
`no_labels`, `clear_label_filter`.
Tests: 4 new index tests covering the labels prop exposure, single-label
filter, multi-label OR filter, and blank-id sanitization. Full suite:
1509 passed, 2 skipped, 0 failed.
2026-05-14 12:57:55 +00:00
'filter_by_label' => 'Filtrar por etiqueta' ,
'label_search_placeholder' => 'Buscar etiquetas...' ,
'no_labels' => 'No se encontraron etiquetas.' ,
'clear_label_filter' => 'Limpiar filtro de etiquetas' ,
2026-05-02 15:22:42 +00:00
'table' => [
2026-05-06 17:26:18 +00:00
'post' => 'Post' ,
2026-05-02 15:22:42 +00:00
'status' => 'Estado' ,
'content' => 'Contenido' ,
'platforms' => 'Plataformas' ,
'labels' => 'Etiquetas' ,
'scheduled_at' => 'Fecha' ,
'actions' => '' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'manage_posts' => 'Administra todos tus posts' ,
'delete_confirm' => '¿Estás seguro de que deseas eliminar este post?' ,
'by' => 'por' ,
'actions' => [
'view' => 'Ver post' ,
2026-05-04 01:37:51 +00:00
'delete' => 'Eliminar' ,
'duplicate' => 'Duplicar' ,
'copy_id' => 'Copiar ID' ,
'copied' => 'ID copiado al portapapeles' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'form' => [
'post_type' => 'Tipo de post' ,
'board' => 'Tablero' ,
'select_board' => 'Seleccionar tablero' ,
'search_board' => 'Buscar tablero...' ,
'no_board_found' => 'No se encontró tablero' ,
'media' => 'Multimedia' ,
'min' => 'Min' ,
'uploading' => 'Subiendo...' ,
'drop_to_upload' => 'Suelta para subir' ,
'drag_and_drop' => 'Arrastra y suelta o haz clic para subir' ,
'photos_and_videos' => 'Fotos y videos' ,
'photos_only' => 'Solo fotos' ,
'videos_only' => 'Solo videos' ,
'drag_to_reorder' => 'Arrastra para reordenar' ,
'caption' => 'Descripción' ,
'write_caption' => 'Escribe tu descripción...' ,
2026-05-11 22:39:41 +00:00
'content_exceeds_platform' => ':platform: demasiado largo por :over caracteres (máx :limit).' ,
2026-04-02 20:57:06 +00:00
'tiktok' => [
'settings' => 'Configuración de TikTok' ,
feat(tiktok): photo carousel support + UX Content Sharing API compliance
## Photo carousel support
- Adds `ContentType::TikTokPhoto` enum case (max 35 photos, 1:1 aspect,
supportsImage true, supportsVideo false) and JS mirror in content-type.ts.
- Variant pill picker (Video / Photo carousel) at the top of TikTokSettings,
mirroring the Instagram pattern. Wired through ScheduleTab to the parent
editor's existing update:platformContentType emit.
- i18n keys for variant_label / variant.video / variant.photo in en/pt-BR/es.
- Publisher: split buildPostInfo into buildVideoPostInfo (uses `title`,
TikTok cap 2200 chars) and buildPhotoPostInfo (uses `description`, cap
4000 chars; omits Duet/Stitch/AIGC since they don't apply). Removed the
no-longer-needed queryCreatorInfo() call from publishVideo/publishPhotos
— its only previous consumer (silent privacy_level fallback) is gone.
## UX Content Sharing API compliance
Per TikTok review feedback citing
https://developers.tiktok.com/doc/content-sharing-guidelines#required_ux_implementation_in_your_app
Point 1 — already satisfied (creator_info fetch + nickname display).
Point 2/4 — Music Usage Confirmation declaration is now always visible
in TikTokSettings; text changes between "Music Usage Confirmation" and
"Branded Content Policy and Music Usage Confirmation" based on toggle
state. Previously the entire `<p>` block was conditional on a brand
toggle being selected, hiding the baseline declaration.
Point 2b — privacy_level may not have a default. UI was already correct;
backend hardened: UpdatePostRequest now requires meta.privacy_level for
tiktok platforms when status is publishing/scheduled (via withValidator);
TikTokPublisher::resolveRequiredPrivacyLevel throws TikTokPublishException
(ContentPolicy category) when missing instead of silently falling back to
the creator's preferred level.
Point 2c — interaction settings now condition on content type:
- Photo posts hide Duet/Stitch (they don't apply per TikTok docs).
- Photo posts hide AIGC (also video-only).
- Video posts hide Auto Add Music (photos-only feature).
- Max-duration warning hidden when not a video post.
Source of truth is the user-selected contentType prop, not inferred
from media — ensures the UI reacts immediately to the variant pill.
Point 3a — publish button stays disabled when Disclose toggle is on
without a sub-selection (already the case via tiktokComplianceValid).
The disabled tooltip now uses the verbatim TikTok-required text "You
need to indicate if your content promotes yourself, a third party, or
both." instead of the generic "Some platform settings are incomplete..."
when the only blocker is TikTok disclosure incompleteness.
Point 3b — SELF_ONLY (Only me) privacy option is no longer filtered out
when Branded Content is checked. It is rendered disabled with a hover
tooltip "Branded content visibility cannot be set to private." plus a
persistent amber warning paragraph below the dropdown. When the user
toggles Branded Content while privacy is SELF_ONLY, the privacy clears
and a vue-sonner warning toast surfaces the change.
## Cross-cutting
- New `resources/js/enums/platform.ts` mirrors the PHP Platform enum,
used in Edit.vue (tiktokComplianceValid + tiktokDisclosureIncomplete)
and ScheduleTab.vue (all selected*Platforms computeds) to replace
string literal comparisons against `'tiktok'` / `'facebook'` / etc.
- PostPlatformFactory tiktok() state defaults meta.privacy_level to
SELF_ONLY so existing test fixtures keep passing under the new
publisher/FormRequest requirements.
## Tests
- New tests/Unit/Enums/PostPlatform/TikTokPhotoContentTypeTest.php
covering the new enum case (4 tests).
- TikTokPublisherTest: added "video uses title not description" and
"throws when meta.privacy_level missing" regression tests; renamed
two existing tests that depended on the removed silent fallback.
- New tests/Feature/UpdatePostRequestTest.php with 3 tests covering
the FormRequest's privacy_level enforcement (publish-rejected,
publish-passes, draft-allowed).
Full Pest suite: 1490 passed, 2 skipped (pre-existing).
2026-05-09 15:47:49 +00:00
'variant_label' => 'Tipo de publicación' ,
'variant' => [
'video' => 'Video' ,
'photo' => 'Carrusel de fotos' ,
],
2026-04-23 16:23:24 +00:00
'posting_to' => 'Publicando en' ,
2026-04-02 20:57:06 +00:00
'privacy_level' => '¿Quién puede ver este video?' ,
2026-05-29 13:16:04 +00:00
'privacy_placeholder' => 'Selecciona quién puede ver esta publicación' ,
2026-04-02 20:57:06 +00:00
'privacy' => [
'public' => 'Público para todos' ,
'friends' => 'Amigos mutuos' ,
'followers' => 'Seguidores' ,
'private' => 'Solo yo' ,
feat(tiktok): photo carousel support + UX Content Sharing API compliance
## Photo carousel support
- Adds `ContentType::TikTokPhoto` enum case (max 35 photos, 1:1 aspect,
supportsImage true, supportsVideo false) and JS mirror in content-type.ts.
- Variant pill picker (Video / Photo carousel) at the top of TikTokSettings,
mirroring the Instagram pattern. Wired through ScheduleTab to the parent
editor's existing update:platformContentType emit.
- i18n keys for variant_label / variant.video / variant.photo in en/pt-BR/es.
- Publisher: split buildPostInfo into buildVideoPostInfo (uses `title`,
TikTok cap 2200 chars) and buildPhotoPostInfo (uses `description`, cap
4000 chars; omits Duet/Stitch/AIGC since they don't apply). Removed the
no-longer-needed queryCreatorInfo() call from publishVideo/publishPhotos
— its only previous consumer (silent privacy_level fallback) is gone.
## UX Content Sharing API compliance
Per TikTok review feedback citing
https://developers.tiktok.com/doc/content-sharing-guidelines#required_ux_implementation_in_your_app
Point 1 — already satisfied (creator_info fetch + nickname display).
Point 2/4 — Music Usage Confirmation declaration is now always visible
in TikTokSettings; text changes between "Music Usage Confirmation" and
"Branded Content Policy and Music Usage Confirmation" based on toggle
state. Previously the entire `<p>` block was conditional on a brand
toggle being selected, hiding the baseline declaration.
Point 2b — privacy_level may not have a default. UI was already correct;
backend hardened: UpdatePostRequest now requires meta.privacy_level for
tiktok platforms when status is publishing/scheduled (via withValidator);
TikTokPublisher::resolveRequiredPrivacyLevel throws TikTokPublishException
(ContentPolicy category) when missing instead of silently falling back to
the creator's preferred level.
Point 2c — interaction settings now condition on content type:
- Photo posts hide Duet/Stitch (they don't apply per TikTok docs).
- Photo posts hide AIGC (also video-only).
- Video posts hide Auto Add Music (photos-only feature).
- Max-duration warning hidden when not a video post.
Source of truth is the user-selected contentType prop, not inferred
from media — ensures the UI reacts immediately to the variant pill.
Point 3a — publish button stays disabled when Disclose toggle is on
without a sub-selection (already the case via tiktokComplianceValid).
The disabled tooltip now uses the verbatim TikTok-required text "You
need to indicate if your content promotes yourself, a third party, or
both." instead of the generic "Some platform settings are incomplete..."
when the only blocker is TikTok disclosure incompleteness.
Point 3b — SELF_ONLY (Only me) privacy option is no longer filtered out
when Branded Content is checked. It is rendered disabled with a hover
tooltip "Branded content visibility cannot be set to private." plus a
persistent amber warning paragraph below the dropdown. When the user
toggles Branded Content while privacy is SELF_ONLY, the privacy clears
and a vue-sonner warning toast surfaces the change.
## Cross-cutting
- New `resources/js/enums/platform.ts` mirrors the PHP Platform enum,
used in Edit.vue (tiktokComplianceValid + tiktokDisclosureIncomplete)
and ScheduleTab.vue (all selected*Platforms computeds) to replace
string literal comparisons against `'tiktok'` / `'facebook'` / etc.
- PostPlatformFactory tiktok() state defaults meta.privacy_level to
SELF_ONLY so existing test fixtures keep passing under the new
publisher/FormRequest requirements.
## Tests
- New tests/Unit/Enums/PostPlatform/TikTokPhotoContentTypeTest.php
covering the new enum case (4 tests).
- TikTokPublisherTest: added "video uses title not description" and
"throws when meta.privacy_level missing" regression tests; renamed
two existing tests that depended on the removed silent fallback.
- New tests/Feature/UpdatePostRequestTest.php with 3 tests covering
the FormRequest's privacy_level enforcement (publish-rejected,
publish-passes, draft-allowed).
Full Pest suite: 1490 passed, 2 skipped (pre-existing).
2026-05-09 15:47:49 +00:00
'private_disabled_branded' => 'El contenido de marca no puede ser privado.' ,
2026-04-02 20:57:06 +00:00
],
'privacy_hint' => 'Las opciones disponibles dependen de la configuración de tu cuenta de TikTok.' ,
'auto_add_music' => 'Agregar música automáticamente' ,
'auto_add_music_hint' => 'Disponible solo para fotos. Agrega una música predeterminada que puedes cambiar después.' ,
'yes' => 'Sí' ,
'no' => 'No' ,
'allow_users' => 'Permitir a los usuarios:' ,
'comments' => 'Comentar' ,
'duet' => 'Dueto' ,
'stitch' => 'Stitch' ,
'is_aigc' => 'Video hecho con IA' ,
2026-04-23 16:23:24 +00:00
'disclose' => 'Divulgar contenido del video' ,
'disclose_hint' => 'Activa para divulgar que este video promueve bienes o servicios a cambio de algo de valor. Tu video puede promocionarte a ti, a un tercero o ambos.' ,
'promotional_organic_title' => 'Tu foto/video será etiquetado como "Contenido Promocional".' ,
'promotional_paid_title' => 'Tu foto/video será etiquetado como "Asociación pagada".' ,
'promotional_description' => 'Esto no se puede cambiar una vez publicado el video.' ,
'compliance_incomplete' => 'Debes indicar si tu contenido promociona a ti mismo, a un tercero o a ambos.' ,
2026-05-09 16:56:00 +00:00
'privacy_required' => 'La visibilidad de TikTok es obligatoria al publicar.' ,
feat(tiktok): photo carousel support + UX Content Sharing API compliance
## Photo carousel support
- Adds `ContentType::TikTokPhoto` enum case (max 35 photos, 1:1 aspect,
supportsImage true, supportsVideo false) and JS mirror in content-type.ts.
- Variant pill picker (Video / Photo carousel) at the top of TikTokSettings,
mirroring the Instagram pattern. Wired through ScheduleTab to the parent
editor's existing update:platformContentType emit.
- i18n keys for variant_label / variant.video / variant.photo in en/pt-BR/es.
- Publisher: split buildPostInfo into buildVideoPostInfo (uses `title`,
TikTok cap 2200 chars) and buildPhotoPostInfo (uses `description`, cap
4000 chars; omits Duet/Stitch/AIGC since they don't apply). Removed the
no-longer-needed queryCreatorInfo() call from publishVideo/publishPhotos
— its only previous consumer (silent privacy_level fallback) is gone.
## UX Content Sharing API compliance
Per TikTok review feedback citing
https://developers.tiktok.com/doc/content-sharing-guidelines#required_ux_implementation_in_your_app
Point 1 — already satisfied (creator_info fetch + nickname display).
Point 2/4 — Music Usage Confirmation declaration is now always visible
in TikTokSettings; text changes between "Music Usage Confirmation" and
"Branded Content Policy and Music Usage Confirmation" based on toggle
state. Previously the entire `<p>` block was conditional on a brand
toggle being selected, hiding the baseline declaration.
Point 2b — privacy_level may not have a default. UI was already correct;
backend hardened: UpdatePostRequest now requires meta.privacy_level for
tiktok platforms when status is publishing/scheduled (via withValidator);
TikTokPublisher::resolveRequiredPrivacyLevel throws TikTokPublishException
(ContentPolicy category) when missing instead of silently falling back to
the creator's preferred level.
Point 2c — interaction settings now condition on content type:
- Photo posts hide Duet/Stitch (they don't apply per TikTok docs).
- Photo posts hide AIGC (also video-only).
- Video posts hide Auto Add Music (photos-only feature).
- Max-duration warning hidden when not a video post.
Source of truth is the user-selected contentType prop, not inferred
from media — ensures the UI reacts immediately to the variant pill.
Point 3a — publish button stays disabled when Disclose toggle is on
without a sub-selection (already the case via tiktokComplianceValid).
The disabled tooltip now uses the verbatim TikTok-required text "You
need to indicate if your content promotes yourself, a third party, or
both." instead of the generic "Some platform settings are incomplete..."
when the only blocker is TikTok disclosure incompleteness.
Point 3b — SELF_ONLY (Only me) privacy option is no longer filtered out
when Branded Content is checked. It is rendered disabled with a hover
tooltip "Branded content visibility cannot be set to private." plus a
persistent amber warning paragraph below the dropdown. When the user
toggles Branded Content while privacy is SELF_ONLY, the privacy clears
and a vue-sonner warning toast surfaces the change.
## Cross-cutting
- New `resources/js/enums/platform.ts` mirrors the PHP Platform enum,
used in Edit.vue (tiktokComplianceValid + tiktokDisclosureIncomplete)
and ScheduleTab.vue (all selected*Platforms computeds) to replace
string literal comparisons against `'tiktok'` / `'facebook'` / etc.
- PostPlatformFactory tiktok() state defaults meta.privacy_level to
SELF_ONLY so existing test fixtures keep passing under the new
publisher/FormRequest requirements.
## Tests
- New tests/Unit/Enums/PostPlatform/TikTokPhotoContentTypeTest.php
covering the new enum case (4 tests).
- TikTokPublisherTest: added "video uses title not description" and
"throws when meta.privacy_level missing" regression tests; renamed
two existing tests that depended on the removed silent fallback.
- New tests/Feature/UpdatePostRequestTest.php with 3 tests covering
the FormRequest's privacy_level enforcement (publish-rejected,
publish-passes, draft-allowed).
Full Pest suite: 1490 passed, 2 skipped (pre-existing).
2026-05-09 15:47:49 +00:00
'branded_cleared_private' => 'La visibilidad se borró porque el contenido de marca no puede ser privado.' ,
2026-05-29 13:16:04 +00:00
'interaction_disabled_by_creator' => 'Desactivado en la configuración de tu cuenta TikTok' ,
2026-04-23 16:23:24 +00:00
'max_duration_exceeded' => 'El video dura :duration s pero esta cuenta solo permite videos de hasta :max s.' ,
'processing_hint' => 'Después de publicar, puede tardar unos minutos en procesarse y aparecer en tu perfil de TikTok.' ,
'brand_organic' => 'Tu marca' ,
'brand_organic_hint' => 'Estás promocionándote a ti mismo o a tu propia marca. Este video será clasificado como Brand Organic.' ,
'brand_content' => 'Contenido patrocinado' ,
'brand_content_hint' => 'Estás promocionando otra marca o a un tercero. Este video será clasificado como Branded Content.' ,
'compliance' => [
'agree' => 'Al publicar, aceptas la' ,
'music_usage' => 'Confirmación de Uso de Música' ,
'and' => 'y la' ,
'branded_policy' => 'Política de Contenido Patrocinado' ,
],
2026-04-02 20:57:06 +00:00
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'instagram' => [
'settings' => 'Configuración de Instagram' ,
'posting_to' => 'Publicando en' ,
'variant_label' => 'Tipo de publicación' ,
'variant' => [
'feed' => 'Publicación' ,
'reel' => 'Reel' ,
'story' => 'Historia' ,
],
2026-05-02 15:22:42 +00:00
'aspect_label' => 'Proporción' ,
'aspect' => [
'square' => 'Cuadrado (1:1)' ,
'portrait' => 'Vertical (4:5)' ,
'landscape' => 'Horizontal (16:9)' ,
'original' => 'Original' ,
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
],
'facebook' => [
'settings' => 'Configuración de Facebook' ,
'posting_to' => 'Publicando en' ,
'variant_label' => 'Tipo de publicación' ,
'variant' => [
'post' => 'Publicación' ,
'reel' => 'Reel' ,
'story' => 'Historia' ,
],
2026-06-05 21:01:45 +00:00
'aspect_label' => 'Proporción' ,
'aspect' => [
'square' => 'Cuadrado (1:1)' ,
'portrait' => 'Vertical (4:5)' ,
'landscape' => 'Horizontal (16:9)' ,
'original' => 'Original' ,
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
],
2026-05-02 17:50:36 +00:00
'linkedin' => [
'settings' => 'Configuración de LinkedIn' ,
'settings_page' => 'Configuración de la Página de LinkedIn' ,
'posting_to' => 'Publicando en' ,
2026-06-25 00:05:09 +00:00
'document_title' => 'Título del documento' ,
'document_title_placeholder' => 'Se muestra en tu publicación de documento PDF' ,
2026-05-02 17:50:36 +00:00
],
'pinterest' => [
'settings' => 'Configuración de Pinterest' ,
'posting_to' => 'Publicando en' ,
'variant_label' => 'Tipo de pin' ,
'variant' => [
'pin' => 'Pin' ,
'video_pin' => 'Video Pin' ,
'carousel' => 'Carrusel' ,
],
2026-05-15 14:51:20 +00:00
'board' => 'Tablero' ,
'select_board' => 'Selecciona un tablero' ,
'no_boards' => 'No se encontraron tableros de Pinterest. Crea uno en tu cuenta de Pinterest primero.' ,
'search_board' => 'Buscar tableros...' ,
'no_board_found' => 'Ningún tablero coincide con tu búsqueda.' ,
'board_required' => 'Selecciona un tablero de Pinterest para publicar este post.' ,
2026-05-02 17:50:36 +00:00
],
feat(channels): add Discord as a social channel
Connect a Discord server via OAuth (bot authorization) and schedule/publish
messages to its channels, with mentions and rich embeds.
- Connect: custom Socialite Discord provider (bot scope) maps the authorized
guild to a SocialAccount; throws if no server was authorized.
- Publish: DiscordPublisher posts via the global bot token, validates the chosen
channel belongs to the connected guild (anti cross-guild), optimizes media,
builds allowed_mentions only from explicit mention chips (no accidental pings),
and renders rich embeds.
- Compose: per-post channel picker (live lookup), mention autocomplete and an
embed editor, gated by a required-channel compliance rule; Discord post preview.
- Enum/config/content-type wiring, ConnectionVerifier health check, throttled
lookup endpoints, i18n (en/es/pt-BR), and tests.
Operators must create a Discord application and set DISCORD_CLIENT_ID,
DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN and DISCORD_CLIENT_REDIRECT.
2026-06-16 17:44:00 +00:00
'discord' => [
'settings' => 'Configuración de Discord' ,
'posting_to' => 'Publicando en' ,
'channel' => 'Canal' ,
'select_channel' => 'Selecciona un canal' ,
'loading_channels' => 'Cargando canales…' ,
2026-06-16 18:53:20 +00:00
'search_channel' => 'Buscar canales…' ,
'no_channels' => 'No se encontraron canales.' ,
feat(channels): add Discord as a social channel
Connect a Discord server via OAuth (bot authorization) and schedule/publish
messages to its channels, with mentions and rich embeds.
- Connect: custom Socialite Discord provider (bot scope) maps the authorized
guild to a SocialAccount; throws if no server was authorized.
- Publish: DiscordPublisher posts via the global bot token, validates the chosen
channel belongs to the connected guild (anti cross-guild), optimizes media,
builds allowed_mentions only from explicit mention chips (no accidental pings),
and renders rich embeds.
- Compose: per-post channel picker (live lookup), mention autocomplete and an
embed editor, gated by a required-channel compliance rule; Discord post preview.
- Enum/config/content-type wiring, ConnectionVerifier health check, throttled
lookup endpoints, i18n (en/es/pt-BR), and tests.
Operators must create a Discord application and set DISCORD_CLIENT_ID,
DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN and DISCORD_CLIENT_REDIRECT.
2026-06-16 17:44:00 +00:00
'channel_required' => 'Selecciona un canal de Discord para publicar este post.' ,
'mentions' => 'Menciones' ,
'search_mention' => 'Menciona un rol o miembro…' ,
'embeds' => 'Embeds' ,
'embed' => 'Embed' ,
'add_embed' => 'Añadir embed' ,
'embed_title' => 'Título del embed' ,
'embed_description' => 'Descripción del embed' ,
'embed_url' => 'URL del embed' ,
'embed_image' => 'URL de la imagen' ,
'embed_color' => 'Color' ,
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'warnings' => [
'no_variant' => 'Elige un tipo de publicación para continuar.' ,
'requires_media' => 'Este tipo requiere al menos una imagen o video.' ,
'max_files_exceeded' => 'Este tipo acepta hasta :max archivos (tienes :current).' ,
'min_files_required' => 'Este tipo requiere al menos :min archivos (tienes :current).' ,
'no_video_allowed' => 'Este tipo no acepta videos.' ,
'no_image_allowed' => 'Este tipo acepta solo videos.' ,
feat(linkedin): support PDF document (carousel) posts
Add LinkedIn document posts — the swipeable PDF carousel — for both personal profiles and company pages. This is the format every major competitor exposes via native PDF upload, and the reason a trial user churned.
- New 'document' media type (application/pdf) across the upload pipeline (Type enum, HasMedia, FormRequests incl. chunked, Platform media types)
- New LinkedInDocument / LinkedInPageDocument content types: PDF-only, single-file, with a supportsDocument() flag
- Publisher flow: documents initializeUpload -> PUT -> poll AVAILABLE -> post with content.media.{id,title}; optional document_title meta (falls back to file name)
- PDF is mutually exclusive with image/video, enforced in ContentTypeCompatibleWithMedia
- Frontend: 'Document (PDF)' variant, media rules (100MB cap), composer/gallery/detail PDF cards, real PDF embed in the LinkedIn editor preview, i18n in en/es/pt-BR
- Tests: publishers (personal + page, incl. processing-failure path), enums, compatibility rule, chunked PDF upload, API + MCP document_title round-trip
LinkedIn caps documents at 100MB / 300 pages (Documents API). The page limit is enforced by LinkedIn at publish, not validated client-side.
2026-06-24 19:32:27 +00:00
'no_document_allowed' => 'Este tipo no acepta documentos PDF.' ,
2026-06-25 00:05:09 +00:00
'no_mixed_media' => 'No se pueden combinar imágenes y un video en la misma publicación.' ,
2026-06-25 12:45:15 +00:00
'document_not_alone' => 'Un PDF debe publicarse solo, sin otras imágenes ni videos.' ,
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'gif_not_allowed' => 'Esta red no acepta GIF. Elimínalo o selecciona otra red.' ,
'image_too_large' => 'La imagen supera el límite de :max (la tuya es :current).' ,
'video_too_large' => 'El video supera el límite de :max (el tuyo es :current).' ,
feat(linkedin): support PDF document (carousel) posts
Add LinkedIn document posts — the swipeable PDF carousel — for both personal profiles and company pages. This is the format every major competitor exposes via native PDF upload, and the reason a trial user churned.
- New 'document' media type (application/pdf) across the upload pipeline (Type enum, HasMedia, FormRequests incl. chunked, Platform media types)
- New LinkedInDocument / LinkedInPageDocument content types: PDF-only, single-file, with a supportsDocument() flag
- Publisher flow: documents initializeUpload -> PUT -> poll AVAILABLE -> post with content.media.{id,title}; optional document_title meta (falls back to file name)
- PDF is mutually exclusive with image/video, enforced in ContentTypeCompatibleWithMedia
- Frontend: 'Document (PDF)' variant, media rules (100MB cap), composer/gallery/detail PDF cards, real PDF embed in the LinkedIn editor preview, i18n in en/es/pt-BR
- Tests: publishers (personal + page, incl. processing-failure path), enums, compatibility rule, chunked PDF upload, API + MCP document_title round-trip
LinkedIn caps documents at 100MB / 300 pages (Documents API). The page limit is enforced by LinkedIn at publish, not validated client-side.
2026-06-24 19:32:27 +00:00
'document_too_large' => 'El PDF supera el límite de :max (el tuyo es :current).' ,
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'video_too_long' => 'El video dura :current, pero este tipo permite hasta :max.' ,
'aspect_ratio_too_narrow' => 'La proporción :current es demasiado alta (mínimo :min).' ,
'aspect_ratio_too_wide' => 'La proporción :current es demasiado ancha (máximo :max).' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'status' => [
2026-03-30 19:55:14 +00:00
'pending' => 'Pendiente' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'draft' => 'Borrador' ,
'scheduled' => 'Programado' ,
'publishing' => 'Publicando' ,
2026-05-19 13:03:30 +00:00
'retrying' => 'Reintentando' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'published' => 'Publicado' ,
'partially_published' => 'Parcialmente publicado' ,
'failed' => 'Fallido' ,
],
'descriptions' => [
'draft' => 'Posts esperando ser programados' ,
'scheduled' => 'Posts programados para publicar' ,
'published' => 'Posts ya publicados' ,
],
2026-05-03 12:36:50 +00:00
'ai' => [
'generate' => [
'button_tooltip' => 'Generar con IA' ,
'title' => 'Generar post con IA' ,
'description' => 'Describe sobre qué debe ser el post. La IA usará el contexto de tu marca para escribirlo.' ,
'prompt_label' => '¿De qué trata este post?' ,
'prompt_placeholder' => 'ej: anunciar nuestra nueva función de generación de imágenes para carruseles' ,
'preview_label' => 'Vista previa' ,
'start' => 'Generar' ,
'apply' => 'Usar este contenido' ,
'retry' => 'Intentar de nuevo' ,
'cancel' => 'Cancelar' ,
],
'review' => [
'button_tooltip' => 'Revisar con IA' ,
'title' => 'Revisar post con IA' ,
2026-05-03 16:44:13 +00:00
'description' => 'La IA analiza gramática, ortografía y claridad. Aplica las sugerencias con las que estés de acuerdo.' ,
2026-05-03 12:36:50 +00:00
'loading' => 'Revisando tu texto...' ,
'no_issues' => 'No se encontraron problemas. Todo bien.' ,
'original' => 'Original' ,
'suggestion' => 'Sugerencia' ,
'apply' => 'Aplicar' ,
2026-05-03 16:44:13 +00:00
'apply_all' => 'Aplicar todas' ,
'applied' => 'Aplicada' ,
'cancel' => 'Cancelar' ,
2026-05-03 12:36:50 +00:00
],
2026-05-21 19:27:55 +00:00
'image_regenerate' => [
'button' => 'Ajustar' ,
'title' => 'Ajustar imagen con IA' ,
'description' => 'Describe la corrección. La nueva imagen reemplaza la actual y mantiene su posición en el carrusel.' ,
'instruction_label' => 'Instrucción' ,
'instruction_placeholder' => 'ej: Corregir el error en el titular y aclarar el fondo.' ,
'processing' => 'Regenerando imagen... esto puede tardar unos segundos.' ,
'submit' => 'Regenerar imagen' ,
'cancel' => 'Cancelar' ,
'success' => 'Imagen actualizada. La nueva versión reemplazó la anterior en la publicación.' ,
'fallback_title' => 'Mejorar este texto de imagen' ,
'errors' => [
'required' => 'La instrucción es obligatoria.' ,
'start_failed' => 'No se pudo iniciar la regeneración.' ,
'unavailable' => 'No se pudo regenerar esta imagen en este momento.' ,
'timeout' => 'La regeneración está tardando más de lo esperado. Inténtalo de nuevo en un momento.' ,
'media_not_found' => 'No se encontró el archivo multimedia.' ,
'not_ai_media' => 'Solo se puede regenerar contenido generado por IA.' ,
],
],
2026-06-17 20:37:51 +00:00
'templates' => [
'image_card' => [
'name' => 'Publicación con imagen' ,
'description' => 'Imagen con IA, titular y descripción.' ,
],
'carousel' => [
'name' => 'Carrusel' ,
'description' => 'Carrusel de varias diapositivas con descripción.' ,
],
'tweet_card' => [
'name' => 'Tarjeta de tweet' ,
'description' => 'Tu publicación con estilo de post de X/Twitter.' ,
],
2026-06-17 22:43:21 +00:00
'tweet_card_image' => [
'name' => 'Tarjeta de tweet con foto' ,
'description' => 'Tu publicación como tarjeta de X/Twitter sobre una foto difuminada.' ,
],
2026-06-17 20:37:51 +00:00
],
2026-05-03 12:36:50 +00:00
],
2026-05-02 15:22:42 +00:00
'show' => [
'title' => 'Detalles del post' ,
'edit' => 'Editar' ,
refactor: in-page page headers, indies tabs, and post details polish
- Replace global AppHeader slots with in-page headers on Calendar, Edit,
and Show pages — full-width canvas with the page-specific controls
living in their own ink-bordered bar.
- Remove sidebar collapse mechanism: drop Cmd+B keyboard shortcut, force
defaultOpen=true (ignore persisted cookie), make toggleSidebar a no-op
on desktop. Sidebar is permanent on desktop, sheet behavior preserved
on mobile.
- Redesign Tabs to match the design system: each TabsTrigger renders as
a standalone sticker button (border-2 + rounded-md + shadow-xs), with
amber-200 active state mirroring the "POST" badge from post-templates.
- Show page layout: cap preview Card to max-w-xl, preserve natural
aspect for single-image posts (object-contain, max-h-[480px]), drop
redundant stats grid, swap header sides (Back button left, status +
date right with date first).
- Assets: bump GalleryBrowser search inputs to h-12 for comfortable
browsing across uploads, Unsplash, and Giphy tabs.
- Fix PostPlatformMetrics loading-forever bug: hoist useHttp out of the
onMounted callback into setup, and read the response array directly
(backend returns the array at root, not under .data).
- i18n: rename posts.show.back_to_posts → posts.show.back; remove unused
posts.show.summary.* keys.
2026-05-06 19:22:55 +00:00
'back' => 'Volver' ,
2026-05-02 15:22:42 +00:00
'no_content' => 'Sin texto' ,
'platforms' => 'Plataformas' ,
'no_platforms' => 'Ninguna plataforma seleccionada.' ,
'view_on_platform' => 'Ver en la plataforma' ,
'published_on' => 'Publicado el :date' ,
'scheduled_for' => 'Programado para el :date' ,
'draft' => 'Borrador' ,
'status_pending' => 'Pendiente' ,
'metrics' => 'Métricas' ,
'metrics_loading' => 'Cargando métricas…' ,
'metrics_unavailable' => 'Métricas aún no disponibles para esta plataforma.' ,
'metrics_empty' => 'No se devolvieron métricas.' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'edit' => [
'title' => 'Editar post' ,
'view_title' => 'Ver post' ,
'labels' => 'Etiquetas' ,
2026-05-03 18:23:30 +00:00
'signatures' => 'Firmas' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'schedule' => 'Programar' ,
'delete' => 'Eliminar' ,
'schedule_for' => 'Programar para' ,
2026-05-06 17:26:18 +00:00
'unschedule' => 'Desprogramar' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'saving' => 'Guardando...' ,
'saved' => 'Guardado' ,
2026-04-17 02:05:51 +00:00
'draft' => 'Borrador' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'media' => 'Multimedia' ,
2026-04-17 02:05:51 +00:00
'add_media' => 'Añadir media' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'caption' => 'Descripción' ,
2026-04-17 02:05:51 +00:00
'caption_placeholder' => 'Escribe tu descripción...' ,
'compose_title' => 'Crear un post' ,
'compose_subtitle' => 'Compón tu mensaje y agrega media' ,
2026-05-02 17:50:36 +00:00
'preview_empty' => [
'title' => 'Ninguna plataforma seleccionada' ,
'description' => 'Selecciona una plataforma para publicar y ver la vista previa.' ,
],
2026-05-02 18:32:55 +00:00
'drop_zone_title' => 'Añadir media' ,
'drop_zone_subtitle' => 'Arrastra archivos o haz clic para seleccionar' ,
'add' => 'Añadir' ,
2026-04-17 02:05:51 +00:00
'publish_to' => 'Publicar en' ,
'organize' => 'Organizar' ,
'no_labels' => 'Todavía no hay etiquetas creadas' ,
'pick_time' => 'Elegir hora' ,
2026-05-19 19:26:40 +00:00
'pick_time_past' => 'Elige una fecha y hora en el futuro.' ,
2026-04-17 02:05:51 +00:00
'post_now' => 'Publicar ahora' ,
'time' => 'Hora' ,
'cancel' => 'Cancelar' ,
'schedule_date' => 'Fecha de programación' ,
'view_on_platform' => 'Ver en la plataforma' ,
'platform_status' => 'Estado de la plataforma' ,
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'compliance_incomplete' => 'Algunas configuraciones de plataforma están incompletas o son incompatibles con los medios adjuntos.' ,
2026-05-02 15:22:42 +00:00
'compliance' => [
2026-05-19 17:18:13 +00:00
'requires_content_or_media' => 'Agrega texto o multimedia para publicar.' ,
2026-05-02 15:22:42 +00:00
'requires_media' => 'Agrega una imagen o video para publicar aquí.' ,
'too_many_files' => 'Solo se permiten :max archivo(s) en este formato.' ,
'too_few_files' => 'Agrega al menos :min archivos para este formato.' ,
'no_videos' => 'Solo se permiten imágenes en este formato.' ,
'no_images' => 'Solo se permiten videos en este formato.' ,
2026-06-23 17:30:38 +00:00
'no_mixed_media' => 'No se pueden combinar imágenes y videos en la misma publicación.' ,
2026-05-02 15:22:42 +00:00
'no_gifs' => 'Los GIFs no son compatibles aquí.' ,
2026-06-24 20:36:39 +00:00
'no_documents' => 'Los documentos PDF no son compatibles con este formato.' ,
2026-06-25 12:45:15 +00:00
'document_not_alone' => 'Un PDF debe publicarse solo, sin otras imágenes ni videos.' ,
2026-05-02 15:22:42 +00:00
'video_too_large' => 'El video supera el límite de tamaño de esta plataforma.' ,
'video_too_long' => 'El video debe durar menos de :seconds segundos en este formato.' ,
'image_too_large' => 'La imagen supera el límite de tamaño de esta plataforma.' ,
2026-06-24 20:36:39 +00:00
'document_too_large' => 'El PDF supera el límite de tamaño de esta plataforma.' ,
2026-05-02 15:22:42 +00:00
'aspect_ratio_invalid' => 'La proporción de aspecto no es compatible con este formato.' ,
'no_content_type' => 'Elige un tipo de contenido para esta plataforma.' ,
2026-06-25 22:59:51 +00:00
'requires_text' => 'Agrega texto — este formato necesita un título.' ,
2026-05-02 15:22:42 +00:00
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'publishing' => 'Publicando...' ,
'publishing_overlay_title' => 'Tu publicación se está enviando' ,
'publishing_overlay_subtitle' => 'Esto puede tardar unos momentos. Puedes salir de esta página sin problemas.' ,
2026-05-11 23:47:53 +00:00
'scheduled_overlay_title' => 'Esta publicación está programada' ,
'scheduled_overlay_subtitle' => 'Programada para :date. Cancela la programación para hacer cambios.' ,
'unschedule_cta' => 'Cancelar para editar' ,
2026-04-17 02:05:51 +00:00
'tabs' => [
2026-07-17 21:38:20 +00:00
'compose' => 'Redactar' ,
2026-04-17 02:05:51 +00:00
'preview' => 'Vista previa' ,
2026-06-10 19:06:02 +00:00
'channels' => 'Canales' ,
2026-04-17 02:05:51 +00:00
'comments' => 'Comentarios' ,
'comments_empty' => 'Todavía no hay comentarios.' ,
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'media_picker' => [
'title' => 'Elegir de la galería' ,
'search' => 'Buscar media...' ,
'empty' => 'Aún no hay archivos en tu galería' ,
'cancel' => 'Cancelar' ,
'add' => 'Agregar' ,
'add_count' => 'Agregar :count' ,
],
2026-07-11 12:45:52 +00:00
'alt_text' => [
'label' => 'Texto alternativo' ,
'edit' => 'Editar texto alternativo' ,
'placeholder' => 'Describe esta imagen para las personas que usan lectores de pantalla' ,
'hint' => 'Se publica en las plataformas que admiten descripciones de imágenes.' ,
'save' => 'Guardar' ,
],
feat: media gallery picker, custom emoji picker, preview tabs, real platform logos
- gallery: extract /assets tabs (uploads, Unsplash, Giphy) into shared
GalleryBrowser used by both /assets and a new MediaPickerDialog inside the
post editor; add JSON search endpoint for workspace assets with tests
- emoji: replace broken emoji-picker-element web component with a custom
EmojiPicker (full Unicode set, search, categories, recently-used,
light/dark, i18n)
- preview tab: platform selector pills, variant tabs (data-driven from
content_types map) so the user can switch Feed/Reel/Story etc. and have
it autosave through the same handler ScheduleTab uses
- platform logos: shared usePlatformLogo composable (logo + label + content
types); replaces inline maps across 5 components, fixes
instagram-facebook falling back to default.png
- tooltips: hover details (display_name · @username + platform label) on
platform avatars across editor, posts list and calendar
- settings cards: show ` · @username` in the title bar so multiple accounts
on the same network are distinguishable
- routes: drop the throttle:6,1 group middleware on social connect routes
(was 429ing legitimate OAuth retries) and rely on the default limiter
2026-05-01 17:53:49 +00:00
'emoji_picker' => [
'search' => 'Buscar emoji' ,
'empty' => 'No se encontraron emojis' ,
'recent' => 'Usados con frecuencia' ,
'smileys' => 'Caritas y emociones' ,
'people' => 'Personas y cuerpo' ,
'nature' => 'Animales y naturaleza' ,
'food' => 'Comida y bebida' ,
'activities' => 'Actividades' ,
'travel' => 'Viajes y lugares' ,
'objects' => 'Objetos' ,
'symbols' => 'Símbolos' ,
'flags' => 'Banderas' ,
],
2026-04-17 02:05:51 +00:00
'status' => [
2026-06-22 19:47:27 +00:00
'pending' => 'Pendiente' ,
2026-05-06 17:26:18 +00:00
'scheduled' => 'Programado' ,
2026-04-17 02:05:51 +00:00
'published' => 'Publicado' ,
'publishing' => 'Publicando...' ,
2026-05-19 13:03:30 +00:00
'retrying' => 'Reintentando...' ,
2026-04-17 02:05:51 +00:00
'failed' => 'Fallido' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'delete_modal' => [
'title' => 'Eliminar post' ,
'description' => '¿Estás seguro de que deseas eliminar este post? Esta acción no se puede deshacer.' ,
'action' => 'Eliminar' ,
'cancel' => 'Cancelar' ,
],
'sync_enable' => [
'title' => '¿Activar sincronización?' ,
'description' => 'Todas las plataformas compartirán el mismo contenido. Las ediciones personalizadas realizadas en plataformas individuales serán reemplazadas con el contenido actual.' ,
'cancel' => 'Cancelar' ,
'action' => 'Activar sincronización' ,
],
'sync_disable' => [
'title' => '¿Desactivar sincronización?' ,
'description' => 'Cada plataforma mantendrá su contenido actual, pero las ediciones futuras solo se aplicarán a la plataforma que estés editando.' ,
'customize_note' => 'Podrás personalizar el contenido de cada plataforma individualmente.' ,
'cancel' => 'Cancelar' ,
'action' => 'Desactivar sincronización' ,
],
'platforms_dialog' => [
'title' => 'Seleccionar plataformas' ,
'description' => 'Elige en qué plataformas publicar este post.' ,
],
2026-05-03 18:23:30 +00:00
'signatures_modal' => [
'search' => 'Buscar firmas...' ,
'no_results' => 'No se encontraron firmas.' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'validation' => [
'select_board' => 'Selecciona un tablero' ,
'images_not_supported' => 'Imágenes no soportadas' ,
'videos_not_supported' => 'Videos no soportados' ,
'max_images' => 'Máximo :count imágenes' ,
'requires_media' => 'Requiere multimedia' ,
2026-04-01 18:12:56 +00:00
'requires_content' => 'Se requiere texto' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'exceeded' => ':count excedido' ,
'does_not_support_images' => ':platform no soporta imágenes' ,
'supports_up_to_images' => ':platform soporta hasta :count imágenes' ,
'does_not_support_videos' => ':platform no soporta videos' ,
],
],
'content_types' => [
'instagram_feed' => [
'label' => 'Post del feed' ,
'description' => 'Aparece en tu feed y perfil' ,
],
'instagram_reel' => [
'label' => 'Reel' ,
'description' => 'Video corto de hasta 90 segundos' ,
],
'instagram_story' => [
'label' => 'Historia' ,
'description' => 'Desaparece después de 24 horas' ,
],
'linkedin_post' => [
'label' => 'Post' ,
2026-06-25 00:05:09 +00:00
'description' => 'Post estándar — imagen, varias imágenes, video o PDF' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'linkedin_page_post' => [
'label' => 'Post' ,
2026-06-25 00:05:09 +00:00
'description' => 'Post estándar — imagen, varias imágenes, video o PDF' ,
feat(linkedin): support PDF document (carousel) posts
Add LinkedIn document posts — the swipeable PDF carousel — for both personal profiles and company pages. This is the format every major competitor exposes via native PDF upload, and the reason a trial user churned.
- New 'document' media type (application/pdf) across the upload pipeline (Type enum, HasMedia, FormRequests incl. chunked, Platform media types)
- New LinkedInDocument / LinkedInPageDocument content types: PDF-only, single-file, with a supportsDocument() flag
- Publisher flow: documents initializeUpload -> PUT -> poll AVAILABLE -> post with content.media.{id,title}; optional document_title meta (falls back to file name)
- PDF is mutually exclusive with image/video, enforced in ContentTypeCompatibleWithMedia
- Frontend: 'Document (PDF)' variant, media rules (100MB cap), composer/gallery/detail PDF cards, real PDF embed in the LinkedIn editor preview, i18n in en/es/pt-BR
- Tests: publishers (personal + page, incl. processing-failure path), enums, compatibility rule, chunked PDF upload, API + MCP document_title round-trip
LinkedIn caps documents at 100MB / 300 pages (Documents API). The page limit is enforced by LinkedIn at publish, not validated client-side.
2026-06-24 19:32:27 +00:00
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'facebook_post' => [
'label' => 'Post' ,
'description' => 'Post estándar en tu página' ,
],
'facebook_reel' => [
'label' => 'Reel' ,
'description' => 'Video corto de hasta 90 segundos' ,
],
'facebook_story' => [
'label' => 'Historia' ,
2026-05-22 00:21:11 +00:00
'description' => 'Historia en video vertical, hasta 60 segundos' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'tiktok_video' => [
'label' => 'Video' ,
'description' => 'Contenido de video corto' ,
],
2026-05-09 16:56:00 +00:00
'tiktok_photo' => [
'label' => 'Carrusel de fotos' ,
'description' => 'Hasta 35 fotos en un carrusel deslizable' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'youtube_short' => [
'label' => 'Short' ,
'description' => 'Video vertical de hasta 60 segundos' ,
],
'x_post' => [
'label' => 'Post' ,
'description' => 'Tweet con texto y multimedia' ,
],
'threads_post' => [
'label' => 'Post' ,
'description' => 'Post de texto con multimedia opcional' ,
],
'pinterest_pin' => [
'label' => 'Pin' ,
2026-05-09 16:56:00 +00:00
'description' => 'Pin de imagen estándar' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'pinterest_video_pin' => [
'label' => 'Pin de video' ,
2026-05-09 16:56:00 +00:00
'description' => 'Pin de video (4s - 15min)' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'pinterest_carousel' => [
'label' => 'Carrusel' ,
2026-05-09 16:56:00 +00:00
'description' => 'Carrusel multi-imagen (2-5 imágenes)' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'bluesky_post' => [
'label' => 'Post' ,
'description' => 'Post de texto con imágenes opcionales' ,
],
'mastodon_post' => [
'label' => 'Post' ,
'description' => 'Post de texto con multimedia opcional' ,
],
2026-06-14 01:10:12 +00:00
'telegram_post' => [
'label' => 'Post' ,
'description' => 'Post de texto con multimedia opcional' ,
],
feat(channels): add Discord as a social channel
Connect a Discord server via OAuth (bot authorization) and schedule/publish
messages to its channels, with mentions and rich embeds.
- Connect: custom Socialite Discord provider (bot scope) maps the authorized
guild to a SocialAccount; throws if no server was authorized.
- Publish: DiscordPublisher posts via the global bot token, validates the chosen
channel belongs to the connected guild (anti cross-guild), optimizes media,
builds allowed_mentions only from explicit mention chips (no accidental pings),
and renders rich embeds.
- Compose: per-post channel picker (live lookup), mention autocomplete and an
embed editor, gated by a required-channel compliance rule; Discord post preview.
- Enum/config/content-type wiring, ConnectionVerifier health check, throttled
lookup endpoints, i18n (en/es/pt-BR), and tests.
Operators must create a Discord application and set DISCORD_CLIENT_ID,
DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN and DISCORD_CLIENT_REDIRECT.
2026-06-16 17:44:00 +00:00
'discord_message' => [
'label' => 'Mensaje' ,
'description' => 'Mensaje a un canal de Discord con multimedia y embeds opcionales' ,
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
'platforms' => [
'linkedin' => 'LinkedIn' ,
'linkedin-page' => 'Página de LinkedIn' ,
'x' => 'X' ,
'tiktok' => 'TikTok' ,
'youtube' => 'YouTube Shorts' ,
'facebook' => 'Página de Facebook' ,
'instagram' => 'Instagram' ,
'threads' => 'Threads' ,
'pinterest' => 'Pinterest' ,
'bluesky' => 'Bluesky' ,
'mastodon' => 'Mastodon' ,
],
'flash' => [
'scheduled' => '¡Post programado correctamente!' ,
'deleted' => '¡Post eliminado correctamente!' ,
2026-05-04 01:37:51 +00:00
'duplicated' => 'Post duplicado como borrador.' ,
fix(facebook): empty-message rejection + state consistency + no re-publish on terminal
Production incident: a customer's Facebook Page post failed with 'The post
is empty. Please enter a message to share.' (error code 197) and ended up
with a contradictory DB state (status=published + error_message=set).
Three independent bugs were uncovered:
A. FacebookPublisher sends 'message'/'description' as null when the user
posts media without text. Graph API requires the key be omitted, not
null. Fixed in publishSingleImagePost, publishMultiImagePost,
publishVideoPost, publishReel.
B. markAsPublished/markAsFailed leak stale fields across transitions
(a published row could retain error_message from a prior failure,
vice-versa). Both transitions now explicitly clear the opposite
side's fields.
C. status='failed' was editable in the UI and the backend, so users
were re-clicking Publish, generating duplicate failure emails and
the contradictory state from bug B. The frontend isReadOnly check
and the UpdatePost backend guard now treat Published/PartiallyPublished/
Failed/Publishing as terminal. To retry, the user duplicates the post.
11 new tests guarantee these can't regress silently: FB payload shape
per content type, PostPlatform field-clearing on transitions, and the
terminal-status block at the controller level.
2026-05-15 16:01:49 +00:00
'cannot_edit_finalized' => 'Este post ya fue procesado y no puede republicarse. Duplícalo para intentar de nuevo.' ,
2026-05-02 15:22:42 +00:00
'cannot_delete_published' => 'Los posts publicados no se pueden eliminar.' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
'connect_first' => 'Conecta al menos una red social antes de crear un post.' ,
],
'errors' => [
'account_disconnected' => 'Cuenta social desconectada' ,
2026-03-31 00:18:07 +00:00
'account_inactive' => 'Cuenta social desactivada' ,
2026-05-12 21:46:06 +00:00
'account_token_expired' => 'Sesión de la cuenta social expirada — reconecta la cuenta' ,
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
],
2026-05-03 12:36:50 +00:00
2026-05-03 13:17:01 +00:00
'delete' => [
'title' => '¿Eliminar post?' ,
'description' => 'Esta acción no se puede deshacer. El post y todos sus archivos multimedia se eliminarán de forma permanente.' ,
'confirm' => 'Sí, eliminar' ,
'cancel' => 'Cancelar' ,
],
2026-05-03 12:36:50 +00:00
'create' => [
'title' => 'Crear nuevo post' ,
'description' => 'Elige cómo quieres empezar.' ,
'scratch_title' => 'Empezar desde cero' ,
'scratch_description' => 'Abre un post en blanco para escribirlo todo.' ,
'ai_title' => 'Generar con IA' ,
'ai_description' => 'Describe lo que quieres y la IA genera el contenido por ti.' ,
'ai_configure_description' => 'Elige un formato y describe el post que quieres crear.' ,
2026-06-17 20:42:23 +00:00
'ai_pick_template_description' => 'Elige un estilo para tu post generado por IA.' ,
2026-05-03 12:36:50 +00:00
'template_title' => 'Usar una plantilla' ,
'template_description' => 'Elige una de nuestras plantillas y personalízala.' ,
2026-05-03 13:06:02 +00:00
'preview' => [
'image_title' => 'Título de la imagen' ,
'image_body' => 'Texto de la imagen' ,
],
2026-05-03 12:36:50 +00:00
'coming_soon' => 'Próximamente' ,
'steps' => [
2026-06-17 20:42:23 +00:00
'template_picker_title' => 'Elige un estilo' ,
2026-05-03 12:36:50 +00:00
'format_title' => 'Elige un formato' ,
'format_description' => 'Selecciona el tipo de post que quieres crear.' ,
'account_title' => 'Elige una cuenta' ,
'account_description' => 'Selecciona la cuenta social donde publicar.' ,
'media_title' => 'Opciones de medios' ,
'media_carousel' => '¿Cuántas diapositivas?' ,
'media_optional' => '¿Incluir imágenes?' ,
'media_optional_label' => '¿Cuántas imágenes?' ,
'media_none' => 'Ninguna' ,
'media_count_label' => 'Número de imágenes' ,
'prompt_title' => 'Describe tu post' ,
'prompt_label' => '¿De qué trata este post?' ,
'prompt_placeholder' => 'Ej. Anuncia nuestra nueva función de carrusel para Instagram' ,
'preview_error' => 'Algo salió mal. Por favor, inténtalo de nuevo.' ,
2026-05-08 21:30:11 +00:00
'loading_page_title' => 'Generando tu publicación' ,
'loading_eta' => 'Tiempo estimado: cerca de :minutes.' ,
'loading_eta_minute_one' => '1 minuto' ,
'loading_eta_minute_other' => ':count minutos' ,
'loading_leave_title' => 'Puedes seguir trabajando.' ,
'loading_leave_body' => 'Te avisamos cuando la publicación esté lista.' ,
'loading_leave_cta' => 'Ir al calendario' ,
'loading_create_another_cta' => 'Crear otra publicación' ,
'loading_tip_credits' => 'Cada imagen IA usa unos 15 créditos.' ,
'loading_tip_edit' => 'Podrás editar todo cuando la publicación esté lista.' ,
'loading_tip_draft' => 'Las publicaciones generadas van directo a tus borradores.' ,
'loading_tip_brand' => 'Ajusta tu marca para influir en las próximas publicaciones.' ,
'loading_tip_carousel' => 'Los carruseles generan una diapositiva por imagen solicitada.' ,
'loading_tip_quality' => 'La calidad balancea velocidad y costo.' ,
2026-05-03 12:36:50 +00:00
'create' => 'Crear post' ,
'back' => 'Atrás' ,
'next' => 'Continuar' ,
'cancel' => 'Cancelar' ,
'discard' => 'Descartar' ,
'retry' => 'Intentar de nuevo' ,
'no_platforms' => 'Sin cuentas conectadas' ,
'connect_first' => 'Conecta al menos una cuenta social para usar la generación con IA.' ,
2026-06-17 21:09:02 +00:00
'no_account_for_template' => 'Conecta una cuenta compatible para usar esta plantilla.' ,
2026-05-03 12:36:50 +00:00
'format' => [
'instagram_feed' => 'Post de Feed de Instagram' ,
'instagram_carousel' => 'Carrusel de Instagram' ,
'linkedin_post' => 'Post de LinkedIn' ,
'linkedin_page_post' => 'Post de Página de LinkedIn' ,
'x_post' => 'Post en X' ,
'bluesky_post' => 'Post en Bluesky' ,
'threads_post' => 'Post en Threads' ,
'mastodon_post' => 'Post en Mastodon' ,
2026-06-14 01:10:12 +00:00
'telegram_post' => 'Post en Telegram' ,
feat(channels): add Discord as a social channel
Connect a Discord server via OAuth (bot authorization) and schedule/publish
messages to its channels, with mentions and rich embeds.
- Connect: custom Socialite Discord provider (bot scope) maps the authorized
guild to a SocialAccount; throws if no server was authorized.
- Publish: DiscordPublisher posts via the global bot token, validates the chosen
channel belongs to the connected guild (anti cross-guild), optimizes media,
builds allowed_mentions only from explicit mention chips (no accidental pings),
and renders rich embeds.
- Compose: per-post channel picker (live lookup), mention autocomplete and an
embed editor, gated by a required-channel compliance rule; Discord post preview.
- Enum/config/content-type wiring, ConnectionVerifier health check, throttled
lookup endpoints, i18n (en/es/pt-BR), and tests.
Operators must create a Discord application and set DISCORD_CLIENT_ID,
DISCORD_CLIENT_SECRET, DISCORD_BOT_TOKEN and DISCORD_CLIENT_REDIRECT.
2026-06-16 17:44:00 +00:00
'discord_message' => 'Mensaje de Discord' ,
2026-05-03 12:36:50 +00:00
'facebook_post' => 'Post en Facebook' ,
'pinterest_pin' => 'Pin de Pinterest' ,
'instagram_story' => 'Story de Instagram' ,
'facebook_story' => 'Story de Facebook' ,
],
],
],
'templates' => [
'browser_title' => 'Elige una plantilla' ,
'browser_description' => 'Comienza con una plantilla curada y adáptala.' ,
'search_placeholder' => 'Buscar plantillas…' ,
'no_search_results' => 'Ninguna plantilla coincide con tu búsqueda' ,
'try_different_search' => 'Prueba otra palabra clave o limpia la búsqueda.' ,
'slides_count' => '{count} slide|{count} slides' ,
'all_platforms' => 'Todas las plataformas' ,
2026-05-06 17:26:18 +00:00
'platform_search_placeholder' => 'Buscar plataforma…' ,
'no_platform_match' => 'Ninguna plataforma coincide.' ,
2026-05-03 12:36:50 +00:00
'use_this' => 'Usar esta plantilla' ,
'no_templates' => 'No hay plantillas disponibles.' ,
'applying' => 'Aplicando plantilla…' ,
'category' => [
'product_launch' => 'Lanzamiento de producto' ,
'promotion' => 'Promoción' ,
'educational' => 'Educativo' ,
'behind_the_scenes' => 'Detrás de cámaras' ,
'testimonial' => 'Testimonio' ,
'industry_tip' => 'Consejo del sector' ,
'event' => 'Evento' ,
'engagement' => 'Interacción' ,
],
],
refactor: settings redesign, Spanish translations, language system, strict_types
Settings pages:
- Redesign layout to match Sendkit (max-w-4xl, space-y-12, Separator sections)
- Merge Members page into Workspace settings with Table, invite Dialog, ConfirmDeleteModal
- Add workspace logo upload/delete routes and controller methods
- Translate all hardcoded strings in Workspace.vue modals
Language system:
- Drop languages table, replace language_id FK with locale string column on users
- Create config/languages.php for available languages and default locale
- Add Spanish (es) translations (13 files)
- Simplify HandleInertiaRequests, ProfileController, RegisteredUserController
Code quality:
- Add declare(strict_types=1) to all PHP files
- Fix MastodonPublisher using wrong attribute (filename -> original_filename)
- Fix HasMediaTest for new has_photo/photo_url accessors
- Fix PublishToSocialPlatformTest type error revealed by strict_types
- Remove orphaned Language model from AppServiceProvider morph map
- Update User TypeScript interface (has_photo, photo_url, locale)
- Eager load media relation on workspaces to prevent N+1
- Add 8 new tests for workspace logo upload/delete
- Update workspace settings test to assert members/invitations props
All 710 tests passing.
2026-03-30 03:20:43 +00:00
];