Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/Actions/Workspace/CreateWorkspace.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace App\Actions\Workspace;

use App\Enums\UserWorkspace\Role;
use App\Enums\Workspace\ContentLanguage;
use App\Models\User;
use App\Models\Workspace;
use Illuminate\Support\Facades\DB;
Expand All @@ -24,7 +25,7 @@ public static function execute(User $user, array $data): Workspace
'brand_color' => data_get($data, 'brand_color'),
'background_color' => data_get($data, 'background_color'),
'text_color' => data_get($data, 'text_color'),
'content_language' => data_get($data, 'content_language', app()->getLocale()),
'content_language' => data_get($data, 'content_language', ContentLanguage::DEFAULT->value),
], static fn ($value): bool => $value !== null);

$workspace = DB::transaction(function () use ($user, $attributes): Workspace {
Expand Down
12 changes: 8 additions & 4 deletions app/Enums/Workspace/ContentLanguage.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
* The set of languages the app supports, and the single source of truth for it:
* request validation, the brand analyzer's structured-output enum, homepage
* language detection, the AI image prompt's language name, the content-language
* picker options, and the right-to-left direction of the UI all derive from it.
* picker options, and the text direction used by supported UI locales all derive
* from it.
*
* The string value is the language code stored on the workspace and passed
* straight to the content prompts (`content_language`); the same codes also back
* the application's UI locales, so `direction()` drives the document `dir` attribute.
* straight to the content prompts (`content_language`). UI locales are a subset
* configured separately in `config/languages.php`.
*/
enum ContentLanguage: string
{
case English = 'en';
case Ukrainian = 'uk';
case PortugueseBrazil = 'pt-BR';
case Spanish = 'es';
case French = 'fr';
Expand All @@ -32,7 +34,7 @@ enum ContentLanguage: string
case Turkish = 'tr';
case Arabic = 'ar';

public const DEFAULT = self::English;
public const DEFAULT = self::Ukrainian;

/**
* The language's own name, shown in the content-language picker.
Expand All @@ -41,6 +43,7 @@ public function label(): string
{
return match ($this) {
self::English => 'English',
self::Ukrainian => 'Українська',
self::PortugueseBrazil => 'Português (Brasil)',
self::Spanish => 'Español',
self::French => 'Français',
Expand All @@ -66,6 +69,7 @@ public function englishName(): string
{
return match ($this) {
self::English => 'English',
self::Ukrainian => 'Ukrainian',
self::PortugueseBrazil => 'Brazilian Portuguese',
self::Spanish => 'Spanish',
self::French => 'French',
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/settings/BrandTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const form = useForm({
text_color: props.workspace.text_color,
brand_font: props.workspace.brand_font ?? 'Inter',
image_style: props.workspace.image_style ?? 'cinematic',
content_language: props.workspace.content_language ?? 'en',
content_language: props.workspace.content_language ?? 'uk',
logo_url: '' as string | null,
});

Expand Down
2 changes: 1 addition & 1 deletion resources/js/pages/workspaces/Create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const form = useForm({
text_color: null as string | null,
brand_font: 'Inter',
image_style: 'cinematic',
content_language: 'en',
content_language: 'uk',
logo_url: '' as string | null,
});

Expand Down
6 changes: 3 additions & 3 deletions tests/Feature/Actions/Workspace/CreateWorkspaceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@
expect($member?->pivot->role)->toBe(Role::Admin->value);
});

test('CreateWorkspace inherits the app locale as content_language when none is given', function () {
test('CreateWorkspace defaults content generation to Ukrainian when none is given', function () {
app()->setLocale('pt-BR');

$account = Account::factory()->create();
$user = User::factory()->create(['account_id' => $account->id]);

$workspace = CreateWorkspace::execute($user, ['name' => 'Acme']);

expect($workspace->content_language)->toBe('pt-BR');
expect($workspace->content_language)->toBe('uk');
});

test('CreateWorkspace keeps an explicit content_language over the app locale', function () {
test('CreateWorkspace keeps an explicit content_language over the default', function () {
app()->setLocale('pt-BR');

$account = Account::factory()->create();
Expand Down
4 changes: 2 additions & 2 deletions tests/Feature/LocalizationParityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
use App\Enums\Workspace\ContentLanguage;
use Illuminate\Support\Arr;

test('every UI language in config matches the ContentLanguage enum', function () {
test('every UI language is also a supported content language', function () {
expect(array_keys(config('languages.available')))
->toEqualCanonicalizing(ContentLanguage::values());
->each->toBeIn(ContentLanguage::values());
});

test('the default UI language is a supported content language', function () {
Expand Down
10 changes: 10 additions & 0 deletions tests/Unit/Ai/Agents/PostContentGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,19 @@

use App\Ai\Agents\PostContentGenerator;
use App\Enums\Ai\GeneratorFormat;
use App\Enums\Workspace\ContentLanguage;
use App\Models\Workspace;
use Illuminate\JsonSchema\JsonSchemaTypeFactory;

test('instructions use Ukrainian for the default content language', function () {
$workspace = Workspace::factory()->make([
'content_language' => ContentLanguage::DEFAULT->value,
]);

expect((new PostContentGenerator(workspace: $workspace))->instructions())
->toContain('Write the output in the language with code: uk.');
});

test('instructions render brand context', function () {
$workspace = Workspace::factory()->make([
'name' => 'TryPost',
Expand Down
12 changes: 8 additions & 4 deletions tests/Unit/Enums/Workspace/ContentLanguageTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@

test('values exposes every supported content-language code', function () {
expect(ContentLanguage::values())->toBe([
'en', 'pt-BR', 'es', 'fr', 'de', 'it', 'nl',
'en', 'uk', 'pt-BR', 'es', 'fr', 'de', 'it', 'nl',
'pl', 'el', 'ja', 'ko', 'zh', 'ru', 'tr', 'ar',
]);
});

test('default language is English', function () {
expect(ContentLanguage::DEFAULT)->toBe(ContentLanguage::English);
expect(ContentLanguage::DEFAULT->value)->toBe('en');
test('default content language is Ukrainian', function () {
expect(ContentLanguage::DEFAULT)->toBe(ContentLanguage::Ukrainian);
expect(ContentLanguage::DEFAULT->value)->toBe('uk');
});

test('options pairs each code with its native and English label', function () {
$options = ContentLanguage::options();

expect($options)->toHaveCount(count(ContentLanguage::cases()));
expect($options[0])->toBe(['value' => 'en', 'label' => 'English', 'englishName' => 'English']);
expect($options)->toContain(['value' => 'uk', 'label' => 'Українська', 'englishName' => 'Ukrainian']);
expect($options)->toContain(['value' => 'pt-BR', 'label' => 'Português (Brasil)', 'englishName' => 'Brazilian Portuguese']);
expect($options)->toContain(['value' => 'ja', 'label' => '日本語', 'englishName' => 'Japanese']);
});
Expand All @@ -29,6 +30,7 @@
expect($language->englishName())->toBe($expected);
})->with([
[ContentLanguage::English, 'English'],
[ContentLanguage::Ukrainian, 'Ukrainian'],
[ContentLanguage::PortugueseBrazil, 'Brazilian Portuguese'],
[ContentLanguage::Spanish, 'Spanish'],
[ContentLanguage::French, 'French'],
Expand All @@ -55,6 +57,7 @@
expect($language->label())->toBe($expected);
})->with([
[ContentLanguage::English, 'English'],
[ContentLanguage::Ukrainian, 'Українська'],
[ContentLanguage::PortugueseBrazil, 'Português (Brasil)'],
[ContentLanguage::Spanish, 'Español'],
[ContentLanguage::French, 'Français'],
Expand Down Expand Up @@ -87,6 +90,7 @@
['pt', ContentLanguage::PortugueseBrazil],
['pt-PT', ContentLanguage::PortugueseBrazil],
['en-US', ContentLanguage::English],
['uk-UA', ContentLanguage::Ukrainian],
['es-MX', ContentLanguage::Spanish],
['fr', ContentLanguage::French],
['ja-JP', ContentLanguage::Japanese],
Expand Down