Skip to content

Commit

Permalink
Merge pull request #14235 from craftcms/feature/cms-1234-add-env-var-…
Browse files Browse the repository at this point in the history
…support-to-sites-language-settings

Feature/cms 1234 add env var support to sites language settings
  • Loading branch information
brandonkelly authored Jan 30, 2024
2 parents 983b9f8 + b9eb22d commit bfff9cf
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 69 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG-WIP.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
- Entry types are now managed independently of sections.
- Entry types are no longer required to have a Title Format, if the Title field isn’t shown.
- Entry types now have a “Show the Slug field” setting. ([#13799](https://github.com/craftcms/cms/discussions/13799))
- Sites’ Language settings can now be set to environment variables. ([#14235](https://github.com/craftcms/cms/pull/14235), [#14135](https://github.com/craftcms/cms/discussions/14135))
- Added the “Addresses” field type. ([#11438](https://github.com/craftcms/cms/discussions/11438))
- Matrix fields now manage nested entries, rather than Matrix blocks. During the upgrade, existing Matrix block types will be converted to entry types; their nested fields will be made global; and Matrix blocks will be converted to entries.
- Matrix fields now have “Entry URI Format” and “Template” settings for each site.
Expand Down Expand Up @@ -110,7 +111,7 @@
- Migrations that modify the project config no longer need to worry about whether the same changes were already applied to the incoming project config YAML files.
- Selectize menus no longer apply special styling to options with the value `new`. The `_includes/forms/selectize.twig` control panel template should be used instead (or `craft\helpers\Cp::selectizeHtml()`/`selectizeFieldHtml()`), which will append an styled “Add” option when `addOptionFn` and `addOptionLabel` settings are passed. ([#11946](https://github.com/craftcms/cms/issues/11946))
- Added the `chip()`, `customSelect()`, `disclosureMenu()`, `elementCard()`, `elementChip()`, `elementIndex()`, `iconSvg()`, and `siteMenuItems()` global functions for control panel templates.
- Added the `colorSelect` and `colorSelectField` form macros.
- Added the `colorSelect`, `colorSelectField`, `languageMenu`, and `languageMenuField` form macros.
- The `assets/move-asset` and `assets/move-folder` actions no longer include `success` keys in responses. ([#12159](https://github.com/craftcms/cms/pull/12159))
- The `assets/upload` controller action now includes `errors` object in failure responses. ([#12159](https://github.com/craftcms/cms/pull/12159))
- Element action triggers’ `validateSelection()` and `activate()` methods are now passed an `elementIndex` argument, with a reference to the trigger’s corresponding element index.
Expand Down Expand Up @@ -293,6 +294,8 @@
- Added `craft\models\FieldLayout::getThumbField()`.
- Added `craft\models\FsListing::getAdjustedUri()`.
- Added `craft\models\Section::getCpEditUrl()`.
- Added `craft\models\Site::getLanguage()`.
- Added `craft\models\Site::setLanguage()`.
- Added `craft\models\Volume::$altTranslationKeyFormat`.
- Added `craft\models\Volume::$altTranslationMethod`.
- Added `craft\models\Volume::getSubpath()`.
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release Notes for Craft CMS 5

## Unreleased

- Sites’ Language settings can now be set to environment variables. ([#14235](https://github.com/craftcms/cms/pull/14235), [#14135](https://github.com/craftcms/cms/discussions/14135))
- Added the `languageMenu` and `languageMenuField` form macros.
- Added `craft\models\Site::getLanguage()`.
- Added `craft\models\Site::setLanguage()`.

## 5.0.0-alpha.9 - 2024-01-29

- Added live conditional field support to inline-editable Matrix blocks. ([#14223](https://github.com/craftcms/cms/pull/14223))
Expand Down
2 changes: 1 addition & 1 deletion src/config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
'id' => 'CraftCMS',
'name' => 'Craft CMS',
'version' => '5.0.0-alpha.9',
'schemaVersion' => '5.0.0.16',
'schemaVersion' => '5.0.0.17',
'minVersionRequired' => '4.4.0',
'basePath' => dirname(__DIR__), // Defines the @app alias
'runtimePath' => '@storage/runtime', // Defines the @runtime alias
Expand Down
17 changes: 0 additions & 17 deletions src/controllers/SitesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,30 +266,13 @@ public function actionEditSite(?int $siteId = null, ?Site $siteModel = null, ?in
],
];

$languageOptions = [];
$languageId = Craft::$app->getLocale()->getLanguageID();

foreach (Craft::$app->getI18n()->getAllLocales() as $locale) {
$languageOptions[] = [
'label' => $locale->getDisplayName(Craft::$app->language),
'value' => $locale->id,
'data' => [
'data' => [
'hint' => $locale->id,
'keywords' => $locale->getLanguageID() !== $languageId ? $locale->getDisplayName() : false,
],
],
];
}

return $this->renderTemplate('settings/sites/_edit.twig', [
'brandNewSite' => $brandNewSite,
'title' => $title,
'crumbs' => $crumbs,
'site' => $siteModel,
'groupId' => $groupId,
'groupOptions' => $groupOptions,
'languageOptions' => $languageOptions,
]);
}

Expand Down
41 changes: 5 additions & 36 deletions src/controllers/UsersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use craft\events\InvalidUserTokenEvent;
use craft\events\LoginFailureEvent;
use craft\events\UserEvent;
use craft\helpers\App;
use craft\helpers\ArrayHelper;
use craft\helpers\Assets;
use craft\helpers\Cp;
Expand Down Expand Up @@ -1059,61 +1060,29 @@ public function actionPreferences(): Response
$response = $this->asEditScreen($user, self::SCREEN_PREFERENCES);

$i18n = Craft::$app->getI18n();
$appLocales = $i18n->getAppLocales();
ArrayHelper::multisort($appLocales, fn(Locale $locale) => $locale->getDisplayName());
$languageId = Craft::$app->getLocale()->getLanguageID();

$languageOptions = array_map(fn(Locale $locale) => [
'label' => $locale->getDisplayName(Craft::$app->language),
'value' => $locale->id,
'data' => [
'data' => [
'hint' => $locale->getLanguageID() !== $languageId ? $locale->getDisplayName() : '',
'hintLang' => $locale->id,
],
],
], $appLocales);

// user language
$userLanguage = $user->getPreferredLanguage();

if (
!$userLanguage ||
!ArrayHelper::contains($appLocales, fn(Locale $locale) => $locale->id === $userLanguage)
!ArrayHelper::contains($i18n->getAppLocales(), fn(Locale $locale) => $locale->id === App::parseEnv($userLanguage))
) {
$userLanguage = Craft::$app->language;
}

// Formatting Locale
$allLocales = $i18n->getAllLocales();
ArrayHelper::multisort($allLocales, fn(Locale $locale) => $locale->getDisplayName());

$localeOptions = [
['label' => Craft::t('app', 'Same as language'), 'value' => ''],
];
array_push($localeOptions, ...array_map(fn(Locale $locale) => [
'label' => $locale->getDisplayName(Craft::$app->language),
'value' => $locale->id,
'data' => [
'data' => [
'hint' => $locale->getLanguageID() !== $languageId ? $locale->getDisplayName() : false,
'hintLang' => $locale->id,
],
],
], $allLocales));

// user locale
$userLocale = $user->getPreferredLocale();

if (
!$userLocale ||
!ArrayHelper::contains($allLocales, fn(Locale $locale) => $locale->id === $userLocale)
!ArrayHelper::contains($i18n->getAllLocales(), fn(Locale $locale) => $locale->id === App::parseEnv($userLocale))
) {
$userLocale = Craft::$app->getConfig()->getGeneral()->defaultCpLocale;
}

$response->action('users/save-preferences');
$response->contentTemplate('users/_preferences', compact(
'languageOptions',
'localeOptions',
'userLanguage',
'userLocale',
));
Expand Down
2 changes: 1 addition & 1 deletion src/migrations/Install.php
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ public function createTables(): void
'enabled' => $this->string()->notNull()->defaultValue('true'),
'name' => $this->string()->notNull(),
'handle' => $this->string()->notNull(),
'language' => $this->string(12)->notNull(),
'language' => $this->string()->notNull(),
'hasUrls' => $this->boolean()->defaultValue(false)->notNull(),
'baseUrl' => $this->string(),
'sortOrder' => $this->smallInteger()->unsigned(),
Expand Down
34 changes: 34 additions & 0 deletions src/migrations/m240129_150719_sites_language_amend_length.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace craft\migrations;

use Craft;
use craft\db\Migration;
use craft\db\Table;

/**
* m240129_150719_sites_language_amend_length migration.
*/
class m240129_150719_sites_language_amend_length extends Migration
{
/**
* @inheritdoc
*/
public function safeUp(): bool
{
if (Craft::$app->getDb()->tableExists(Table::SITES)) {
$this->alterColumn(Table::SITES, 'language', $this->string()->notNull());
}

return true;
}

/**
* @inheritdoc
*/
public function safeDown(): bool
{
echo "m240129_150719_sites_language_amend_length cannot be reverted.\n";
return false;
}
}
38 changes: 32 additions & 6 deletions src/models/Site.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* @property bool|string $enabled Enabled
* @property string|null $baseUrl The site’s base URL
* @property string $name The site’s name
* @property string $language The site’s language
* @author Pixel & Tonic, Inc. <[email protected]>
* @since 3.0.0
*/
Expand All @@ -46,11 +47,6 @@ class Site extends Model
*/
public ?string $handle = null;

/**
* @var string|null Name
*/
public ?string $language = null;

/**
* @var bool Primary site?
*/
Expand Down Expand Up @@ -102,6 +98,13 @@ class Site extends Model
*/
private bool|string $_enabled = true;

/**
* @var string|null Language
* @see getLanguage()
* @see setLanguage()
*/
private ?string $_language = null;

/**
* Returns the site’s name.
*
Expand Down Expand Up @@ -182,6 +185,29 @@ public function setEnabled(bool|string $name): void
$this->_enabled = $name;
}

/**
* Returns the site’s language.
*
* @param bool $parse Whether to parse the language for an environment variable
* @return string
* @since 5.0.0
*/
public function getLanguage(bool $parse = true): string
{
return ($parse ? App::parseEnv($this->_language) : $this->_language) ?? '';
}

/**
* Sets the site’s language.
*
* @param string $language
* @since 5.0.0
*/
public function setLanguage(string $language): void
{
$this->_language = $language;
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -299,7 +325,7 @@ public function getConfig(): array
'siteGroup' => $this->getGroup()->uid,
'name' => $this->_name,
'handle' => $this->handle,
'language' => $this->language,
'language' => $this->getLanguage(false),
'hasUrls' => $this->hasUrls,
'baseUrl' => $this->_baseUrl ?: null,
'sortOrder' => $this->sortOrder,
Expand Down
18 changes: 18 additions & 0 deletions src/templates/_includes/forms.twig
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@
{% endmacro %}


{% macro languageMenu(config) %}
{% include "_includes/forms/languageMenu" with config only %}
{% endmacro %}


{% macro fieldLayoutDesigner(config) %}
{% include "_includes/forms/fieldLayoutDesigner" with config only %}
{% endmacro %}
Expand Down Expand Up @@ -434,6 +439,19 @@
{% endmacro %}


{% macro languageMenuField(config) %}
{% set config = config|merge({id: config.id ?? "languagemenu#{random()}"}) %}
{% if (config.includeEnvVars ?? false) and config.tip is not defined and (config.value ?? '')[0:1] != '$' %}
{% set config = config|merge({
tip: 'This can be set to an environment variable with a valid language ID ({examples}).'|t('app', {
examples: '`en`/`en-GB`',
}),
}) %}
{% endif %}
{{ _self.field(config, 'template:_includes/forms/languageMenu') }}
{% endmacro %}


{% macro fieldLayoutDesignerField(config) %}
{{ _self.field({
label: 'Field Layout'|t('app'),
Expand Down
13 changes: 13 additions & 0 deletions src/templates/_includes/forms/languageMenu.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{% set id = id ?? "languagemenu#{random()}" %}
{% set value = value ?? null -%}
{% set options = options ?? [] %}
{% set appOnly = appOnly ?? false %}


{% if includeEnvVars ?? false %}
{% set options = options|merge(craft.cp.getLanguageEnvOptions(appOnly)) %}
{% endif %}

{% include '_includes/forms/selectize' with {
includeEnvVars: false,
} %}
7 changes: 4 additions & 3 deletions src/templates/settings/sites/_edit.twig
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@
required: true
}) }}

{{ forms.selectizeField({
{{ forms.languageMenuField({
label: "Language"|t('app'),
instructions: "The language content in this site will use."|t('app'),
id: 'language',
name: 'language',
value: site.language,
options: languageOptions,
value: site.getLanguage(false),
options: craft.cp.getLanguageOptions(true),
errors: site.getErrors('language'),
includeEnvVars: true,
}) }}

{% if (craft.app.isMultiSite or not site.id) %}
Expand Down
9 changes: 5 additions & 4 deletions src/templates/users/_preferences.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
<div>
<h2>{{ 'General'|t('app') }}</h2>

{{ forms.selectizeField({
{{ forms.languageMenuField({
id: 'preferredLanguage',
name: 'preferredLanguage',
label: 'Language'|t('app'),
instructions: 'The language that the control panel should use.'|t('app'),
options: languageOptions,
options: craft.cp.getLanguageOptions(false, true, true),
value: userLanguage,
appOnly: true,
}) }}

{{ forms.selectizeField({
{{ forms.languageMenuField({
id: 'preferredLocale',
name: 'preferredLocale',
label: 'Formatting Locale'|t('app'),
instructions: 'The locale that should be used for date and number formatting.'|t('app'),
options: localeOptions,
options: [{'label' : 'Same as language'|t('app'), 'value' : ''}]|merge(craft.cp.getLanguageOptions(false, true)),
value: userLocale,
}) }}

Expand Down
1 change: 1 addition & 0 deletions src/translations/en/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,7 @@
'This can be left blank if you just want an unlabeled separator.' => 'This can be left blank if you just want an unlabeled separator.',
'This can be set to an environment variable matching one of the option values.' => 'This can be set to an environment variable matching one of the option values.',
'This can be set to an environment variable with a boolean value ({examples}).' => 'This can be set to an environment variable with a boolean value ({examples}).',
'This can be set to an environment variable with a valid language ID ({examples}).' => 'This can be set to an environment variable with a valid language ID ({examples}).',
'This can be set to an environment variable with a value of a [supported time zone]({url}).' => 'This can be set to an environment variable with a value of a [supported time zone]({url}).',
'This can be set to an environment variable, or a Twig template that outputs an ID.' => 'This can be set to an environment variable, or a Twig template that outputs an ID.',
'This can be set to an environment variable, or begin with an alias.' => 'This can be set to an environment variable, or begin with an alias.',
Expand Down
Loading

0 comments on commit bfff9cf

Please sign in to comment.