Commit graph

6 commits

Author SHA1 Message Date
Axi
3baf2e9c41
Add Ukrainian as a supported platform language (#219)
* Default AI content language to Ukrainian

* Keep English as the default content language

* refactor: update content language handling in workspace creation

- Changed the default content language in CreateWorkspace to inherit the app's locale instead of defaulting to English.
- Updated related tests to reflect this change, ensuring that the content language aligns with the application's current locale settings.
- Cleaned up unnecessary code in the BrandTab component for better readability.

* Add Ukrainian as a full platform UI locale.

Wire uk into languages config with complete lang/uk translations and restore ContentLanguage↔UI parity checks.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Wire Ukrainian into dayjs and locale coverage tests.

Import the uk dayjs locale with Monday week-start and cover uk/uk-UA in brand autofill and SetLocale assertions.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Harden Ukrainian UI and AI content-language coverage.

Cover generator/reviewer/humanizer/image prompts, workspace pickers, persona labels, UI locale switch, and README for uk as a first-class platform language.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add Ukrainian Pinterest form strings after main merge.

Restore lang/uk posts.php key parity for the new pin title and destination link fields.

Co-authored-by: Cursor <cursoragent@cursor.com>

* List every supported UI language in the README.

Replace the abbreviated multi-language blurb with the full locale set from config.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Paulo Castellano <paulo@castellanos.llc>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 19:45:30 -03:00
Paulo Castellano
c9209cb2a9 Replace the boolean isRtl() with a direction() accessor on ContentLanguage
isRtl() existed only to be mapped to an 'rtl'/'ltr' string in SetLocale, so the
boolean was the redundant concept. direction() returns the string the one caller
needs, which drops the null-safe-plus-nested-ternary from the middleware and lets
it resolve the language once with an explicit DEFAULT fallback.
2026-07-03 18:57:09 -03:00
Paulo Castellano
c7be1af124 Detect all 15 content languages on autofill, harden RTL/i18n, and cover the gaps with tests
- Brand-analyzer prompt now lists every supported language instead of only
  en/pt-BR/es, so onboarding autofill can detect the 12 added languages. The
  backtick-formatted list is built in BrandAnalyzer::instructions(), keeping the
  Blade clean and the enum free of prompt presentation.
- Translate the delete-confirmation keyword for el/ja/zh/ar (the four locales
  that still shipped the English "delete").
- Make the language and font comboboxes RTL-correct (logical ms-* instead of
  physical ml-*), and let the language combobox be searched by English name via
  a visually-hidden label (ContentLanguage::options() now exposes englishName).
- Correct the ContentLanguage class docblock: the enum is also the source of
  truth for the UI locales' text direction.

Tests: SetLocale middleware dir/RTL, isRtl and the full 15-language
englishName/label match arms, LLM language detection beyond en/es/pt-BR, and
store-path persistence of a non-default content language plus rejection of an
unsupported one.
2026-07-03 18:52:45 -03:00
Paulo Castellano
c59adb4871 Cover every supported language in ContentLanguage detection tests
Extend the homepage-language detection dataset to assert all 15 supported
languages resolve from their <html lang> subtag, and pin the primary-subtag
matching so a malformed tag ("english") no longer resolves via a two-letter
prefix.
2026-07-03 15:39:35 -03:00
Paulo Castellano
f7ef13c116 Centralize supported content languages in a ContentLanguage enum
The new content-language options were hand-duplicated across request
validation, the UI picker, and homepage detection, while the brand
analyzer's structured-output enum and the AI image prompt's language
name still only knew about en/pt-BR/es. That left autofill unable to
detect the new languages and made image text fall back to English for
them.

Introduce App\Enums\Workspace\ContentLanguage as the single source of
truth and derive every site from it:

- Store/UpdateWorkspaceRequest validate against ContentLanguage::values()
- BrandAnalyzer's language enum uses ContentLanguage::values()
- AiImageClient::languageName() resolves via the enum's englishName()
- HomepageMetaExtractor detects through ContentLanguage::fromHtmlLang()
- BrandForm consumes availableContentLanguages from the backend, like
  availableFonts/availableImageStyles, instead of a hardcoded list

Also fix two labels: nl "Nederlandse" -> "Nederlands", zh -> "中文".
2026-07-03 14:12:25 -03:00
Paulo Castellano
148a2f432f feat: AI image generation pipeline and post creation overhaul
Core changes:
- Replace Unsplash slide pipeline with gpt-image-2 via Laravel AI SDK.
  New AiImageClient builds prompts from a Blade template seeded by the
  workspace's ImageStyle enum, content language, brand color (mapped to a
  human-readable name via HexColorName helper) and brand description.
- Drop Template B from TemplateImageGenerator: every slide now renders as
  Template A (full-bleed photo + bottom gradient + white/grey overlay).
  Removes renderTemplateB, roundCorners, blendHex, ensureContrast and the
  closing-slide pipeline.
- StreamPostCreation creates the Post directly and dispatches
  PostCreationReady with post_id; the wizard kills its preview step and
  redirects straight to the post editor on completion. Finalize endpoint
  removed.
- New Workspace.image_style enum field with an 8-option visual picker
  shared by /workspaces/create and /settings/workspace/brand via a single
  BrandForm component (autofill is a prop). 8 sample webp thumbs ship
  under public/images/branding/image-styles/.
- Media items gain optional source ('ai'|'unsplash'|'giphy') and
  source_meta (recipe needed to regenerate AI images later); the gallery
  picker tags Unsplash/Giphy attachments.
- Brand-color autofill: new CssColorFrequencyExtractor parses every
  hex/rgb/hsl value in the homepage CSS, clusters perceptually similar
  shades in CIE LAB (Delta E 76 < 12), filters neutrals and returns the
  most frequent cluster. Solves Tailwind/utility-CSS sites where no
  semantic --primary variable is exposed.
- Credits: gpt-image-2 metered at 15 credits/image (low quality default).
- Layout: AuthSplitLayout right column is sticky/h-svh so the form
  textarea growth no longer stretches the marketing slider.
- i18n cleanup: localized labels follow the no-em-dash convention.
2026-05-08 13:38:30 -03:00