Mehrsprachigkeit

Mit Joomla! ist es möglich, eine mehrsprachige Website einzurichten, ohne Erweiterungen von Dritten zu installieren. In diesem Tutorial zeige ich dir, wie du deine Komponente so programmierst, dass sie Sprachverknüpfungen unterstützt.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

Für Ungeduldige

Sieh dir den geänderten Programmcode in der Diff-Ansicht an und übernimm diese Änderungen in deine Entwicklungsversion.

// https://github.com/astridx/boilerplate/compare/t14b...t15a.diff

diff --git a/src/administrator/components/com_foos/forms/foo.xml b/src/administrator/components/com_foos/forms/foo.xml
index 29030084..48811dd9 100644
-- a/src/administrator/components/com_foos/forms/foo.xml
++ b/src/administrator/components/com_foos/forms/foo.xml
@@ -1,6 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <form>
	<fieldset addruleprefix="FooNamespace\Component\Foos\Administrator\Rule">
	<fieldset
		addruleprefix="FooNamespace\Component\Foos\Administrator\Rule"
		addfieldprefix="FooNamespace\Component\Foos\Administrator\Field"
	>
 		<field
 			name="id"
 			type="number"
@@ -28,6 +31,14 @@
 			hint="JFIELD_ALIAS_PLACEHOLDER"
 		/>

		<field
			name="language"
			type="contentlanguage"
			label="JFIELD_LANGUAGE_LABEL"
			>
			<option value="*">JALL</option>
		</field>

 		<field
 			name="published"
 			type="list"
diff --git a/src/administrator/components/com_foos/services/provider.php b/src/administrator/components/com_foos/services/provider.php
index 47fb5974..0ccbffc4 100644
-- a/src/administrator/components/com_foos/services/provider.php
++ b/src/administrator/components/com_foos/services/provider.php
@@ -20,6 +20,8 @@
 use Joomla\DI\Container;
 use Joomla\DI\ServiceProviderInterface;
 use FooNamespace\Component\Foos\Administrator\Extension\FoosComponent;
use FooNamespace\Component\Foos\Administrator\Helper\AssociationsHelper;
use Joomla\CMS\Association\AssociationExtensionInterface;

 /**
  * The foos service provider.
@@ -40,9 +42,11 @@
 	 */
 	public function register(Container $container)
 	{
		$container->registerServiceProvider(new CategoryFactory('\\FooNamespace\\Component\\Foos'));
		$container->registerServiceProvider(new MVCFactory('\\FooNamespace\\Component\\Foos'));
		$container->registerServiceProvider(new ComponentDispatcherFactory('\\FooNamespace\\Component\\Foos'));
		$container->set(AssociationExtensionInterface::class, new AssociationsHelper);

		$container->registerServiceProvider(new CategoryFactory('\\Joomla\\Component\\Foos'));
		$container->registerServiceProvider(new MVCFactory('\\Joomla\\Component\\Foos'));
		$container->registerServiceProvider(new ComponentDispatcherFactory('\\Joomla\\Component\\Foos'));

 		$container->set(
 			ComponentInterface::class,
@@ -53,6 +57,7 @@ function (Container $container)
 				$component->setRegistry($container->get(Registry::class));
 				$component->setMVCFactory($container->get(MVCFactoryInterface::class));
 				$component->setCategoryFactory($container->get(CategoryFactoryInterface::class));
				$component->setAssociationExtension($container->get(AssociationExtensionInterface::class));

 				return $component;
 			}
diff --git a/src/administrator/components/com_foos/sql/install.mysql.utf8.sql b/src/administrator/components/com_foos/sql/install.mysql.utf8.sql
index 87a3a0a0..5517b4c3 100644
-- a/src/administrator/components/com_foos/sql/install.mysql.utf8.sql
++ b/src/administrator/components/com_foos/sql/install.mysql.utf8.sql
@@ -27,3 +27,7 @@ ALTER TABLE `#__foos_details` ADD COLUMN  `publish_up` datetime AFTER `alias`;
 ALTER TABLE `#__foos_details` ADD COLUMN  `publish_down` datetime AFTER `alias`;

 ALTER TABLE `#__foos_details` ADD KEY `idx_state` (`published`);

ALTER TABLE `#__foos_details` ADD COLUMN  `language` char(7) NOT NULL DEFAULT '*' AFTER `alias`;

ALTER TABLE `#__foos_details` ADD KEY `idx_language` (`language`);
diff --git a/src/administrator/components/com_foos/sql/updates/mysql/15.0.0.sql b/src/administrator/components/com_foos/sql/updates/mysql/15.0.0.sql
new file mode 100644
index 00000000..d3ab7545
-- /dev/null
++ b/src/administrator/components/com_foos/sql/updates/mysql/15.0.0.sql
@@ -0,0 +1,3 @@
ALTER TABLE `#__foos_details` ADD COLUMN  `language` char(7) NOT NULL DEFAULT '*' AFTER `alias`;

ALTER TABLE `#__foos_details` ADD KEY `idx_language` (`language`);
diff --git a/src/administrator/components/com_foos/src/Extension/FoosComponent.php b/src/administrator/components/com_foos/src/Extension/FoosComponent.php
index 831a13f6..0aca19d5 100644
-- a/src/administrator/components/com_foos/src/Extension/FoosComponent.php
++ b/src/administrator/components/com_foos/src/Extension/FoosComponent.php
@@ -11,6 +11,8 @@

 defined('JPATH_PLATFORM') or die;

use Joomla\CMS\Association\AssociationServiceInterface;
use Joomla\CMS\Association\AssociationServiceTrait;
 use Joomla\CMS\Categories\CategoryServiceInterface;
 use Joomla\CMS\Categories\CategoryServiceTrait;
 use Joomla\CMS\Extension\BootableExtensionInterface;
@@ -25,9 +27,11 @@
  *
  * @since  __BUMP_VERSION__
  */
class FoosComponent extends MVCComponent implements BootableExtensionInterface, CategoryServiceInterface
class FoosComponent extends MVCComponent
implements BootableExtensionInterface, CategoryServiceInterface, AssociationServiceInterface
 {
 	use CategoryServiceTrait;
	use AssociationServiceTrait;
 	use HTMLRegistryAwareTrait;

 	/**
diff --git a/src/administrator/components/com_foos/src/Field/Modal/FooField.php b/src/administrator/components/com_foos/src/Field/Modal/FooField.php
index e8704d68..1387c0be 100644
-- a/src/administrator/components/com_foos/src/Field/Modal/FooField.php
++ b/src/administrator/components/com_foos/src/Field/Modal/FooField.php
@@ -81,10 +81,14 @@ function jSelectFoo_"
 		// Setup variables for display.
 		$linkFoos = 'index.php?option=com_foos&amp;view=foos&amp;layout=modal&amp;tmpl=component&amp;'
 			. Session::getFormToken() . '=1';
		$linkFoo  = 'index.php?option=com_foos&amp;view=foo&amp;layout=modal&amp;tmpl=component&amp;'
			. Session::getFormToken() . '=1';
 		$modalTitle   = Text::_('COM_FOOS_CHANGE_FOO');

		if (isset($this->element['language']))
		{
			$linkFoos .= '&amp;forcedLanguage=' . $this->element['language'];
			$modalTitle .= ' &#8212; ' . $this->element['label'];
		}

 		$urlSelect = $linkFoos . '&amp;function=jSelectFoo_' . $this->id;

 		if ($value)
diff --git a/src/administrator/components/com_foos/src/Helper/AssociationsHelper.php b/src/administrator/components/com_foos/src/Helper/AssociationsHelper.php
new file mode 100644
index 00000000..0f7181ac
-- /dev/null
++ b/src/administrator/components/com_foos/src/Helper/AssociationsHelper.php
@@ -0,0 +1,237 @@
<?php
/**
* @package     Joomla.Administrator
* @subpackage  com_foos
*
* @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license     GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace FooNamespace\Component\Foos\Administrator\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Association\AssociationExtensionHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Table\Table;
use FooNamespace\Component\Foos\Site\Helper\AssociationHelper;

/**
* Content associations helper.
*
* @since  __BUMP_VERSION__
*/
class AssociationsHelper extends AssociationExtensionHelper
{
	/**
	 * The extension name
	 *
	 * @var     array   $extension
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected $extension = 'com_foos';

	/**
	 * Array of item types
	 *
	 * @var     array   $itemTypes
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected $itemTypes = array('foo', 'category');

	/**
	 * Has the extension association support
	 *
	 * @var     boolean   $associationsSupport
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected $associationsSupport = true;

	/**
	 * Method to get the associations for a given item.
	 *
	 * @param   integer  $id    Id of the item
	 * @param   string   $view  Name of the view
	 *
	 * @return  array   Array of associations for the item
	 *
	 * @since  __BUMP_VERSION__
	 */
	public function getAssociationsForItem($id = 0, $view = null)
	{
		return AssociationHelper::getAssociations($id, $view);
	}

	/**
	 * Get the associated items for an item
	 *
	 * @param   string  $typeName  The item type
	 * @param   int     $id        The id of item for which we need the associated items
	 *
	 * @return  array
	 *
	 * @since   __BUMP_VERSION__
	 */
	public function getAssociations($typeName, $id)
	{
		$type = $this->getType($typeName);

		$context    = $this->extension . '.item';
		$catidField = 'catid';

		if ($typeName === 'category')
		{
			$context    = 'com_categories.item';
			$catidField = '';
		}

		// Get the associations.
		$associations = Associations::getAssociations(
			$this->extension,
			$type['tables']['a'],
			$context,
			$id,
			'id',
			'alias',
			$catidField
		);

		return $associations;
	}

	/**
	 * Get item information
	 *
	 * @param   string  $typeName  The item type
	 * @param   int     $id        The id of item for which we need the associated items
	 *
	 * @return  Table|null
	 *
	 * @since   __BUMP_VERSION__
	 */
	public function getItem($typeName, $id)
	{
		if (empty($id))
		{
			return null;
		}

		$table = null;

		switch ($typeName)
		{
			case 'foo':
				$table = Table::getInstance('FooTable', 'Joomla\\Component\\Foos\\Administrator\\Table\\');
				break;

			case 'category':
				$table = Table::getInstance('Category');
				break;
		}

		if (empty($table))
		{
			return null;
		}

		$table->load($id);

		return $table;
	}

	/**
	 * Get information about the type
	 *
	 * @param   string  $typeName  The item type
	 *
	 * @return  array  Array of item types
	 *
	 * @since   __BUMP_VERSION__
	 */
	public function getType($typeName = '')
	{
		$fields  = $this->getFieldsTemplate();
		$tables  = array();
		$joins   = array();
		$support = $this->getSupportTemplate();
		$title   = '';

		if (in_array($typeName, $this->itemTypes))
		{
			switch ($typeName)
			{
				case 'foo':
					$fields['title'] = 'a.name';
					$fields['state'] = 'a.published';

					$support['state'] = true;
					$support['acl'] = true;
					$support['category'] = true;
					$support['save2copy'] = true;

					$tables = array(
						'a' => '#__foos_details'
					);

					$title = 'foo';
					break;

				case 'category':
					$fields['created_user_id'] = 'a.created_user_id';
					$fields['ordering'] = 'a.lft';
					$fields['level'] = 'a.level';
					$fields['catid'] = '';
					$fields['state'] = 'a.published';

					$support['state'] = true;
					$support['acl'] = true;
					$support['checkout'] = false;
					$support['level'] = false;

					$tables = array(
						'a' => '#__categories'
					);

					$title = 'category';
					break;
			}
		}

		return array(
			'fields'  => $fields,
			'support' => $support,
			'tables'  => $tables,
			'joins'   => $joins,
			'title'   => $title
		);
	}

	/**
	 * Get default values for fields array
	 *
	 * @return  array
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected function getFieldsTemplate()
	{
		return array(
			'id'                  => 'a.id',
			'title'               => 'a.title',
			'alias'               => 'a.alias',
			'ordering'            => '',
			'menutype'            => '',
			'level'               => '',
			'catid'               => 'a.catid',
			'language'            => 'a.language',
			'access'              => 'a.access',
			'state'               => 'a.state',
			'created_user_id'     => '',
			'checked_out'         => '',
			'checked_out_time'    => ''
		);
	}
}
diff --git a/src/administrator/components/com_foos/src/Model/FooModel.php b/src/administrator/components/com_foos/src/Model/FooModel.php
index 32a964a0..70fdd2e0 100644
-- a/src/administrator/components/com_foos/src/Model/FooModel.php
++ b/src/administrator/components/com_foos/src/Model/FooModel.php
@@ -12,7 +12,9 @@
 \defined('_JEXEC') or die;

 use Joomla\CMS\Factory;
use Joomla\CMS\Language\Associations;
 use Joomla\CMS\MVC\Model\AdminModel;
use Joomla\CMS\Language\LanguageHelper;

 /**
  * Item Model for a Foo.
@@ -29,6 +31,14 @@ class FooModel extends AdminModel
 	 */
 	public $typeAlias = 'com_foos.foo';

	/**
	 * The context used for the associations table
	 *
	 * @var    string
	 * @since  __BUMP_VERSION__
	 */
	protected $associationsContext = 'com_foos.item';

 	/**
 	 * Method to get the row form.
 	 *
@@ -70,6 +80,86 @@ protected function loadFormData()
 		return $data;
 	}

	/**
	 * Method to get a single record.
	 *
	 * @param   integer  $pk  The id of the primary key.
	 *
	 * @return  mixed  Object on success, false on failure.
	 *
	 * @since   __BUMP_VERSION__
	 */
	public function getItem($pk = null)
	{
		$item = parent::getItem($pk);

		// Load associated foo items
		$assoc = Associations::isEnabled();

		if ($assoc)
		{
			$item->associations = array();

			if ($item->id != null)
			{
				$associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $item->id, 'id', null);

				foreach ($associations as $tag => $association)
				{
					$item->associations[$tag] = $association->id;
				}
			}
		}

		return $item;
	}

	/**
	 * Preprocess the form.
	 *
	 * @param   \JForm  $form   Form object.
	 * @param   object  $data   Data object.
	 * @param   string  $group  Group name.
	 *
	 * @return  void
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected function preprocessForm(\JForm $form, $data, $group = 'content')
	{
		if (Associations::isEnabled())
		{
			$languages = LanguageHelper::getContentLanguages(false, true, null, 'ordering', 'asc');

			if (count($languages) > 1)
			{
				$addform = new \SimpleXMLElement('<form />');
				$fields = $addform->addChild('fields');
				$fields->addAttribute('name', 'associations');
				$fieldset = $fields->addChild('fieldset');
				$fieldset->addAttribute('name', 'item_associations');

				foreach ($languages as $language)
				{
					$field = $fieldset->addChild('field');
					$field->addAttribute('name', $language->lang_code);
					$field->addAttribute('type', 'modal_foo');
					$field->addAttribute('language', $language->lang_code);
					$field->addAttribute('label', $language->title);
					$field->addAttribute('translate_label', 'false');
					$field->addAttribute('select', 'true');
					$field->addAttribute('new', 'true');
					$field->addAttribute('edit', 'true');
					$field->addAttribute('clear', 'true');
				}

				$form->load($addform, false);
			}
		}

		parent::preprocessForm($form, $data, $group);
	}

 	/**
 	 * Prepare and sanitise the table prior to saving.
 	 *
diff --git a/src/administrator/components/com_foos/src/Model/FoosModel.php b/src/administrator/components/com_foos/src/Model/FoosModel.php
index 20e61378..a168ab54 100644
-- a/src/administrator/components/com_foos/src/Model/FoosModel.php
++ b/src/administrator/components/com_foos/src/Model/FoosModel.php
@@ -12,6 +12,8 @@
 \defined('_JEXEC') or die;

 use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Factory;

 /**
  * Methods supporting a list of foo records.
@@ -48,7 +50,13 @@ protected function getListQuery()

 		// Select the required fields from the table.
 		$query->select(
			$db->quoteName(array('a.id', 'a.name', 'a.alias', 'a.access', 'a.catid', 'a.published', 'a.publish_up', 'a.publish_down'))
			$db->quoteName(
				array(
					'a.id', 'a.name', 'a.alias', 'a.access',
					'a.catid', 'a.published', 'a.publish_up', 'a.publish_down',
					'a.language'
				)
			)
 		);

 		$query->from($db->quoteName('#__foos_details', 'a'));
@@ -67,6 +75,76 @@ protected function getListQuery()
 				$db->quoteName('#__categories', 'c') . ' ON ' . $db->quoteName('c.id') . ' = ' . $db->quoteName('a.catid')
 			);

		// Join over the language
		$query->select($db->quoteName('l.title', 'language_title'))
			->select($db->quoteName('l.image', 'language_image'))
			->join(
				'LEFT',
				$db->quoteName('#__languages', 'l') . ' ON ' . $db->quoteName('l.lang_code') . ' = ' . $db->quoteName('a.language')
			);

		// Join over the associations.
		if (Associations::isEnabled())
		{
			$subQuery = $db->getQuery(true)
				->select('COUNT(' . $db->quoteName('asso1.id') . ') > 1')
				->from($db->quoteName('#__associations', 'asso1'))
				->join('INNER', $db->quoteName('#__associations', 'asso2'), $db->quoteName('asso1.key') . ' = ' . $db->quoteName('asso2.key'))
				->where(
					[
						$db->quoteName('asso1.id') . ' = ' . $db->quoteName('a.id'),
						$db->quoteName('asso1.context') . ' = ' . $db->quote('com_foos.item'),
					]
				);

			$query->select('(' . $subQuery . ') AS ' . $db->quoteName('association'));
		}

		// Filter on the language.
		if ($language = $this->getState('filter.language'))
		{
			$query->where($db->quoteName('a.language') . ' = ' . $db->quote($language));
		}

 		return $query;
 	}

	/**
	 * Method to auto-populate the model state.
	 *
	 * Note. Calling getState in this method will result in recursion.
	 *
	 * @param   string  $ordering   An optional ordering field.
	 * @param   string  $direction  An optional direction (asc|desc).
	 *
	 * @return  void
	 *
	 * @since   __BUMP_VERSION__
	 */
	protected function populateState($ordering = 'a.name', $direction = 'asc')
	{
		$app = Factory::getApplication();
		$forcedLanguage = $app->input->get('forcedLanguage', '', 'cmd');

		// Adjust the context to support modal layouts.
		if ($layout = $app->input->get('layout'))
		{
			$this->context .= '.' . $layout;
		}

		// Adjust the context to support forced languages.
		if ($forcedLanguage)
		{
			$this->context .= '.' . $forcedLanguage;
		}

		// List state information.
		parent::populateState($ordering, $direction);

		// Force a language.
		if (!empty($forcedLanguage))
		{
			$this->setState('filter.language', $forcedLanguage);
		}
	}
 }
diff --git a/src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php b/src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php
index 10c48b42..b3ca4cb1 100644
-- a/src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php
++ b/src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php
@@ -11,6 +11,12 @@

 defined('JPATH_BASE') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\LayoutHelper;
use Joomla\CMS\Router\Route;

 /**
  * Foo HTML class.
  *
@@ -18,4 +24,70 @@
  */
 class AdministratorService
 {
	/**
	 * Get the associated language flags
	 *
	 * @param   integer  $fooid  The item id to search associations
	 *
	 * @return  string  The language HTML
	 *
	 * @throws  Exception
	 */
	public function association($fooid)
	{
		// Defaults
		$html = '';

		// Get the associations
		if ($associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $fooid, 'id', null))
		{
			foreach ($associations as $tag => $associated)
			{
				$associations[$tag] = (int) $associated->id;
			}

			// Get the associated foo items
			$db = Factory::getDbo();
			$query = $db->getQuery(true)
				->select('c.id, c.name as title')
				->select('l.sef as lang_sef, lang_code')
				->from('#__foos_details as c')
				->select('cat.title as category_title')
				->join('LEFT', '#__categories as cat ON cat.id=c.catid')
				->where('c.id IN (' . implode(',', array_values($associations)) . ')')
				->where('c.id != ' . $fooid)
				->join('LEFT', '#__languages as l ON c.language=l.lang_code')
				->select('l.image')
				->select('l.title as language_title');
			$db->setQuery($query);

			try
			{
				$items = $db->loadObjectList('id');
			}
			catch (\RuntimeException $e)
			{
				throw new \Exception($e->getMessage(), 500, $e);
			}

			if ($items)
			{
				foreach ($items as &$item)
				{
					$text = strtoupper($item->lang_sef);
					$url = Route::_('index.php?option=com_foos&task=foo.edit&id=' . (int) $item->id);
					$tooltip = '<strong>' . htmlspecialchars($item->language_title, ENT_QUOTES, 'UTF-8') . '</strong><br>'
						. htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8') . '<br>' . Text::sprintf('JCATEGORY_SPRINTF', $item->category_title);
					$classes = 'badge badge-secondary';

					$item->link = '<a href="' . $url . '" title="' . $item->language_title . '" class="' . $classes . '">' . $text . '</a>'
						. '<div role="tooltip" id="tip' . (int) $item->id . '">' . $tooltip . '</div>';
				}
			}

			$html = LayoutHelper::render('joomla.content.associations', $items);
		}

		return $html;
	}
 }
diff --git a/src/administrator/components/com_foos/src/View/Foo/HtmlView.php b/src/administrator/components/com_foos/src/View/Foo/HtmlView.php
index 094a0a9f..206f748c 100644
-- a/src/administrator/components/com_foos/src/View/Foo/HtmlView.php
++ b/src/administrator/components/com_foos/src/View/Foo/HtmlView.php
@@ -49,6 +49,17 @@ public function display($tpl = null)
 		$this->form  = $this->get('Form');
 		$this->item = $this->get('Item');

		// If we are forcing a language in modal (used for associations).
		if ($this->getLayout() === 'modal' && $forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'cmd'))
		{
			// Set the language field to the forcedLanguage and disable changing it.
			$this->form->setValue('language', null, $forcedLanguage);
			$this->form->setFieldAttribute('language', 'readonly', 'true');

			// Only allow to select categories with All language or with the forced language.
			$this->form->setFieldAttribute('catid', 'language', '*,' . $forcedLanguage);
		}

 		$this->addToolbar();

 		return parent::display($tpl);
diff --git a/src/administrator/components/com_foos/src/View/Foos/HtmlView.php b/src/administrator/components/com_foos/src/View/Foos/HtmlView.php
index b80449d8..af7c2fa6 100644
-- a/src/administrator/components/com_foos/src/View/Foos/HtmlView.php
++ b/src/administrator/components/com_foos/src/View/Foos/HtmlView.php
@@ -18,6 +18,7 @@
 use Joomla\CMS\Toolbar\Toolbar;
 use Joomla\CMS\Toolbar\ToolbarHelper;
 use FooNamespace\Component\Foos\Administrator\Helper\FooHelper;
use Joomla\CMS\Factory;

 /**
  * View class for a list of foos.
@@ -53,7 +54,22 @@ public function display($tpl = null): void
 	{
 		$this->items = $this->get('Items');

		$this->addToolbar();
		// We don't need toolbar in the modal window.
		if ($this->getLayout() !== 'modal')
		{
			$this->addToolbar();
			$this->sidebar = \JHtmlSidebar::render();
		}
		else
		{
			// In article associations modal we need to remove language filter if forcing a language.
			// We also need to change the category filter to show show categories with All or the forced language.
			if ($forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'CMD'))
			{
				// If the language is forced we can't allow to select the language, so transform the language selector filter into a hidden field.
				$languageXml = new \SimpleXMLElement('<field name="language" type="hidden" default="' . $forcedLanguage . '" />');
			}
		}

 		parent::display($tpl);
 	}
diff --git a/src/administrator/components/com_foos/tmpl/foo/edit.php b/src/administrator/components/com_foos/tmpl/foo/edit.php
index c195acf8..e1dddc2e 100644
-- a/src/administrator/components/com_foos/tmpl/foo/edit.php
++ b/src/administrator/components/com_foos/tmpl/foo/edit.php
@@ -11,6 +11,7 @@

 use Joomla\CMS\Factory;
 use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Associations;
 use Joomla\CMS\Router\Route;
 use Joomla\CMS\Language\Text;
 use Joomla\CMS\Layout\LayoutHelper;
@@ -18,6 +19,9 @@
 $app = Factory::getApplication();
 $input = $app->input;

$assoc = Associations::isEnabled();

$this->ignore_fieldsets = array('item_associations');
 $this->useCoreUI = true;

 $wa = $this->document->getWebAssetManager();
@@ -45,12 +49,19 @@
 						<?php echo $this->getForm()->renderField('publish_up'); ?>
 						<?php echo $this->getForm()->renderField('publish_down'); ?>
 						<?php echo $this->getForm()->renderField('catid'); ?>
						<?php echo $this->getForm()->renderField('language'); ?>
 					</div>
 				</div>
 			</div>
 		</div>
 		<?php echo HTMLHelper::_('uitab.endTab'); ?>

		<?php if ($assoc) : ?>
			<?php echo HTMLHelper::_('uitab.addTab', 'myTab', 'associations', Text::_('JGLOBAL_FIELDSET_ASSOCIATIONS')); ?>
			<?php echo $this->loadTemplate('associations'); ?>
			<?php echo HTMLHelper::_('uitab.endTab'); ?>
		<?php endif; ?>

 		<?php echo LayoutHelper::render('joomla.edit.params', $this); ?>

 		<?php echo HTMLHelper::_('uitab.endTabSet'); ?>
diff --git a/src/administrator/components/com_foos/tmpl/foo/edit_associations.php b/src/administrator/components/com_foos/tmpl/foo/edit_associations.php
new file mode 100644
index 00000000..71442d04
-- /dev/null
++ b/src/administrator/components/com_foos/tmpl/foo/edit_associations.php
@@ -0,0 +1,14 @@
<?php
/**
* @package     Joomla.Administrator
* @subpackage  com_foos
*
* @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license     GNU General Public License version 2 or later; see LICENSE.txt
*/

\defined('_JEXEC') or die;

use Joomla\CMS\Layout\LayoutHelper;

echo LayoutHelper::render('joomla.edit.associations', $this);
diff --git a/src/administrator/components/com_foos/tmpl/foos/default.php b/src/administrator/components/com_foos/tmpl/foos/default.php
index b72ffc89..5014bb2d 100644
-- a/src/administrator/components/com_foos/tmpl/foos/default.php
++ b/src/administrator/components/com_foos/tmpl/foos/default.php
@@ -11,6 +11,12 @@
 use Joomla\CMS\HTML\HTMLHelper;
 use Joomla\CMS\Language\Text;
 use Joomla\CMS\Router\Route;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Layout\LayoutHelper;

$assoc = Associations::isEnabled();

 ?>
 <form action="<?php echo Route::_('index.php?option=com_foos'); ?>" method="post" name="adminForm" id="adminForm">
 	<div class="row">
@@ -41,6 +47,19 @@
 								<th scope="col" style="width:10%" class="d-none d-md-table-cell">
 									<?php echo TEXT::_('JGRID_HEADING_ACCESS') ?>
 								</th>
								<?php if ($assoc) : ?>
									<th scope="col" style="width:10%">
										<?php echo Text::_('COM_FOOS_HEADING_ASSOCIATION'); ?>
									</th>
								<?php endif; ?>
								<?php if (Multilanguage::isEnabled()) : ?>
									<th scope="col" style="width:10%" class="d-none d-md-table-cell">
										<?php echo Text::_('JGRID_HEADING_LANGUAGE'); ?>
									</th>
								<?php endif; ?>
								<th scope="col" style="width:1%; min-width:85px" class="text-center">
									<?php echo Text::_('JSTATUS'); ?>
								</th>
 								<th scope="col">
 									<?php echo Text::_('COM_FOOS_TABLE_TABLEHEAD_ID'); ?>
 								</th>
@@ -75,6 +94,22 @@
 								<td class="small d-none d-md-table-cell">
 									<?php echo $item->access_level; ?>
 								</td>

								<?php if ($assoc) : ?>
								<td class="d-none d-md-table-cell">
									<?php if ($item->association) : ?>
										<?php
										echo HTMLHelper::_('foosadministrator.association', $item->id);
										?>
									<?php endif; ?>
								</td>
								<?php endif; ?>
								<?php if (Multilanguage::isEnabled()) : ?>
									<td class="small d-none d-md-table-cell">
										<?php echo LayoutHelper::render('joomla.content.language', $item); ?>
									</td>
								<?php endif; ?>

 								<td class="d-none d-md-table-cell">
 									<?php echo $item->id; ?>
 								</td>
diff --git a/src/components/com_foos/src/Helper/AssociationHelper.php b/src/components/com_foos/src/Helper/AssociationHelper.php
new file mode 100644
index 00000000..d92ccc98
-- /dev/null
++ b/src/components/com_foos/src/Helper/AssociationHelper.php
@@ -0,0 +1,67 @@
<?php
/**
* @package     Joomla.Site
* @subpackage  com_foos
*
* @copyright   Copyright (C) 2005 - 2019 Open Source Matters, Inc. All rights reserved.
* @license     GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace FooNamespace\Component\Foos\Site\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Associations;
use Joomla\Component\Categories\Administrator\Helper\CategoryAssociationHelper;
use FooNamespace\Component\Foos\Site\Helper\RouteHelper;

/**
* Foos Component Association Helper
*
* @since  __BUMP_VERSION__
*/
abstract class AssociationHelper extends CategoryAssociationHelper
{
	/**
	 * Method to get the associations for a given item
	 *
	 * @param   integer  $id    Id of the item
	 * @param   string   $view  Name of the view
	 *
	 * @return  array   Array of associations for the item
	 *
	 * @since  __BUMP_VERSION__
	 */
	public static function getAssociations($id = 0, $view = null)
	{
		$jinput = Factory::getApplication()->input;
		$view = $view ?? $jinput->get('view');
		$id = empty($id) ? $jinput->getInt('id') : $id;

		if ($view === 'foos')
		{
			if ($id)
			{
				$associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $id);

				$return = array();

				foreach ($associations as $tag => $item)
				{
					$return[$tag] = RouteHelper::getFoosRoute($item->id, (int) $item->catid, $item->language);
				}

				return $return;
			}
		}

		if ($view === 'category' || $view === 'categories')
		{
			return self::getCategoryAssociations($id, 'com_foos');
		}

		return array();

	}
}
diff --git a/src/components/com_foos/src/Helper/RouteHelper.php b/src/components/com_foos/src/Helper/RouteHelper.php
new file mode 100644
index 00000000..34a574af
-- /dev/null
++ b/src/components/com_foos/src/Helper/RouteHelper.php
@@ -0,0 +1,123 @@
<?php
/**
* @package     Joomla.Site
* @subpackage  com_foos
*
* @copyright   Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved.
* @license     GNU General Public License version 2 or later; see LICENSE.txt
*/

namespace FooNamespace\Component\Foos\Site\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Categories\CategoryNode;
use Joomla\CMS\Language\Multilanguage;

/**
* Foos Component Route Helper
*
* @static
* @package     Joomla.Site
* @subpackage  com_foos
* @since       __DEPLOY_VERSION__
*/
abstract class RouteHelper
{
	/**
	 * Get the URL route for a foos from a foo ID, foos category ID and language
	 *
	 * @param   integer  $id        The id of the foos
	 * @param   integer  $catid     The id of the foos's category
	 * @param   mixed    $language  The id of the language being used.
	 *
	 * @return  string  The link to the foos
	 *
	 * @since   __DEPLOY_VERSION__
	 */
	public static function getFoosRoute($id, $catid, $language = 0)
	{
		// Create the link
		$link = 'index.php?option=com_foos&view=foos&id=' . $id;

		if ($catid > 1)
		{
			$link .= '&catid=' . $catid;
		}

		if ($language && $language !== '*' && Multilanguage::isEnabled())
		{
			$link .= '&lang=' . $language;
		}

		return $link;
	}

	/**
	 * Get the URL route for a foo from a foo ID, foos category ID and language
	 *
	 * @param   integer  $id        The id of the foos
	 * @param   integer  $catid     The id of the foos's category
	 * @param   mixed    $language  The id of the language being used.
	 *
	 * @return  string  The link to the foos
	 *
	 * @since   __DEPLOY_VERSION__
	 */
	public static function getFooRoute($id, $catid, $language = 0)
	{
		// Create the link
		$link = 'index.php?option=com_foos&view=foo&id=' . $id;

		if ($catid > 1)
		{
			$link .= '&catid=' . $catid;
		}

		if ($language && $language !== '*' && Multilanguage::isEnabled())
		{
			$link .= '&lang=' . $language;
		}

		return $link;
	}

	/**
	 * Get the URL route for a foos category from a foos category ID and language
	 *
	 * @param   mixed  $catid     The id of the foos's category either an integer id or an instance of CategoryNode
	 * @param   mixed  $language  The id of the language being used.
	 *
	 * @return  string  The link to the foos
	 *
	 * @since   __DEPLOY_VERSION__
	 */
	public static function getCategoryRoute($catid, $language = 0)
	{
		if ($catid instanceof CategoryNode)
		{
			$id = $catid->id;
		}
		else
		{
			$id = (int) $catid;
		}

		if ($id < 1)
		{
			$link = '';
		}
		else
		{
			// Create the link
			$link = 'index.php?option=com_foos&view=category&id=' . $id;

			if ($language && $language !== '*' && Multilanguage::isEnabled())
			{
				$link .= '&lang=' . $language;
			}
		}

		return $link;
	}
}

Schritt für Schritt

Neue Dateien

Damit die Sprache zum Element gespeichert wird, fügen wir eine Spalte in der Datenbanktabelle hinzu. Bei einer Aktualisierung ist das Skript 15.0.0.sql dasjenige, welches für Version 15.0.0. ausgeführt wird.

src/administrator/components/com_foos/sql/updates/mysql/15.0.0.sql

src/administrator/components/com_foos/sql/updates/mysql/15.0.0.sql

ALTER TABLE `#__foos_details` ADD COLUMN  `language` char(7) NOT NULL DEFAULT '*' AFTER `alias`;
ALTER TABLE `#__foos_details` ADD KEY `idx_language` (`language`);

src/administrator/components/com_foos/src/Helper/AssociationsHelper.php

Die Hilfsdatei AssociationsHelper.php ist die Schnittstelle zur Komponente Sprachverknüpfungen com_associations. AssociationsHelper.php gibt es im Frontend und im Backend.

src/administrator/components/com_foos/src/Helper/AssociationsHelper.php

<?php
namespace FooNamespace\Component\Foos\Administrator\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Association\AssociationExtensionHelper;
use Joomla\CMS\Language\Associations;
use Joomla\CMS\Table\Table;
use FooNamespace\Component\Foos\Site\Helper\AssociationHelper;

class AssociationsHelper extends AssociationExtensionHelper
{
	protected $extension = 'com_foos';

	protected $itemTypes = array('foo', 'category');

	protected $associationsSupport = true;

	public function getAssociationsForItem($id = 0, $view = null)
	{
		return AssociationHelper::getAssociations($id, $view);
	}

	public function getAssociations($typeName, $id)
	{
		$type = $this->getType($typeName);

		$context    = $this->extension . '.item';
		$catidField = 'catid';

		if ($typeName === 'category')
		{
			$context    = 'com_categories.item';
			$catidField = '';
		}

		$associations = Associations::getAssociations(
			$this->extension,
			$type['tables']['a'],
			$context,
			$id,
			'id',
			'alias',
			$catidField
		);

		return $associations;
	}

	public function getItem($typeName, $id)
	{
		if (empty($id))
		{
			return null;
		}

		$table = null;

		switch ($typeName)
		{
			case 'foo':
				$table = Table::getInstance('FooTable', 'Joomla\\Component\\Foos\\Administrator\\Table\\');
				break;

			case 'category':
				$table = Table::getInstance('Category');
				break;
		}

		if (empty($table))
		{
			return null;
		}

		$table->load($id);

		return $table;
	}

	public function getType($typeName = '')
	{
		$fields  = $this->getFieldsTemplate();
		$tables  = array();
		$joins   = array();
		$support = $this->getSupportTemplate();
		$title   = '';

		if (in_array($typeName, $this->itemTypes))
		{
			switch ($typeName)
			{
				case 'foo':
					$fields['title'] = 'a.name';
					$fields['state'] = 'a.published';

					$support['state'] = true;
					$support['acl'] = true;
					$support['category'] = true;
					$support['save2copy'] = true;

					$tables = array(
						'a' => '#__foos_details'
					);

					$title = 'foo';
					break;

				case 'category':
					$fields['created_user_id'] = 'a.created_user_id';
					$fields['ordering'] = 'a.lft';
					$fields['level'] = 'a.level';
					$fields['catid'] = '';
					$fields['state'] = 'a.published';

					$support['state'] = true;
					$support['acl'] = true;
					$support['checkout'] = false;
					$support['level'] = false;

					$tables = array(
						'a' => '#__categories'
					);

					$title = 'category';
					break;
			}
		}

		return array(
			'fields'  => $fields,
			'support' => $support,
			'tables'  => $tables,
			'joins'   => $joins,
			'title'   => $title
		);
	}

	protected function getFieldsTemplate()
	{
		return array(
			'id'                  => 'a.id',
			'title'               => 'a.title',
			'alias'               => 'a.alias',
			'ordering'            => '',
			'menutype'            => '',
			'level'               => '',
			'catid'               => 'a.catid',
			'language'            => 'a.language',
			'access'              => 'a.access',
			'state'               => 'a.state',
			'created_user_id'     => '',
			'checked_out'         => '',
			'checked_out_time'    => ''
		);
	}
}

src/administrator/components/comfoos/tmpl/foo/editassociations.php

Wir haben keine speziellen Wünsche und nutzen deshalb das Standardtemplate. Du findest das im Verzeichnis /layouts/joomla/edit/associations.php. Wie du es lädst zeigt dir der nachfolgende Beispielcode.

Falls du spezielle Wünsche hast, kopiere /layouts/joomla/edit/associations.php in deine Komponente und ändere sie wunschgemäß ab. Wie und wo du sie speicherst oder aufrufst, wird in einem späteren Kapitel behandelt.

src/administrator/components/comfoos/tmpl/foo/editassociations.php

defined('_JEXEC') or die;

use Joomla\CMS\Layout\LayoutHelper;

echo LayoutHelper::render('joomla.edit.associations', $this);

src/components/com_foos/src/Helper/AssociationHelper.php

Die Hilfsdatei AssociationsHelper.php ist die Schnittstelle zur Komponente Sprachverknüpfungen com_associations. AssociationsHelper.php gibt es im Frontend und im Backend.

src/components/com_foos/src/Helper/AssociationHelper.php

namespace FooNamespace\Component\Foos\Site\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Associations;
use Joomla\Component\Categories\Administrator\Helper\CategoryAssociationHelper;
use FooNamespace\Component\Foos\Site\Helper\Route as FoosHelperRoute;

abstract class AssociationHelper extends CategoryAssociationHelper
{
	public static function getAssociations($id = 0, $view = null)
	{
		$jinput = Factory::getApplication()->input;
		$view = $view ?? $jinput->get('view');
		$id = empty($id) ? $jinput->getInt('id') : $id;

		if ($view === 'foos')
		{
			if ($id)
			{
				$associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $id);

				$return = array();

				foreach ($associations as $tag => $item)
				{
					$return[$tag] = FoosHelperRoute::getFoosRoute($item->id, (int) $item->catid, $item->language);
				}

				return $return;
			}
		}

		if ($view === 'category' || $view === 'categories')
		{
			return self::getCategoryAssociations($id, 'com_foos');
		}

		return array();

	}
}

src/components/com_foos/src/Helper/Route.php

Wir erzeugen die Klasse Route, damit die Links korrekt zusammengesetzt werden, die wir in diesem Kapitel erstellen.

src/components/com_foos/src/Helper/Route.php

<?php
namespace FooNamespace\Component\Foos\Site\Helper;

\defined('_JEXEC') or die;

use Joomla\CMS\Categories\CategoryNode;
use Joomla\CMS\Language\Multilanguage;

abstract class Route
{
	public static function getFoosRoute($id, $catid, $language = 0)
	{
		$link = 'index.php?option=com_foos&view=foo&id=' . $id;

		if ($catid > 1)
		{
			$link .= '&catid=' . $catid;
		}

		if ($language && $language !== '*' && Multilanguage::isEnabled())
		{
			$link .= '&lang=' . $language;
		}

		return $link;
	}

	public static function getCategoryRoute($catid, $language = 0)
	{
		if ($catid instanceof CategoryNode)
		{
			$id = $catid->id;
		}
		else
		{
			$id = (int) $catid;
		}

		if ($id < 1)
		{
			$link = '';
		}
		else
		{
			$link = 'index.php?option=com_foos&view=category&id=' . $id;

			if ($language && $language !== '*' && Multilanguage::isEnabled())
			{
				$link .= '&lang=' . $language;
			}
		}

		return $link;
	}
}

Geänderte Dateien

src/administrator/components/com_foos/forms/foo.xml

Wir erstellen ein Feld, über das du die Sprachverknüpfung auswählst. Damit Joomla dieses Feld findet, gibst du Pfad in der Form addfieldprefix="FooNamespace\Component\Foos\Administrator\Field" an.

Außerdem fügen wir ein Feld hinzu, in dem dein Item einer Sprache zugeordnet wird.

src/administrator/components/com_foos/forms/foo.xml

...
<fieldset
		addruleprefix="FooNamespace\Component\Foos\Administrator\Rule"
		addfieldprefix="FooNamespace\Component\Foos\Administrator\Field"
>
...
...
<field
			name="language"
			type="contentlanguage"
			label="JFIELD_LANGUAGE_LABEL"
			>
			<option value="*">JALL</option>
</field>

...

src/administrator/components/com_foos/services/provider.php

Im Provider registrieren wir den Service.

src/administrator/components/com_foos/services/provider.php

...
  $container->set(AssociationExtensionInterface::class, new AssociationsHelper);
...
...
	$component->setAssociationExtension($container->get(AssociationExtensionInterface::class));
...

src/administrator/components/com_foos/sql/install.mysql.utf8.sql

src/administrator/components/com_foos/sql/install.mysql.utf8.sql

Damit die Sprache zum Element gespeichert wird, fügen wir eine Spalte in der Datenbanktabelle hinzu. Bei Neuinstallationen ist das Skript install.mysql.utf8.sql dasjenige, welches aufgerufen wird.

...
...
ALTER TABLE `#__foos_details` ADD COLUMN  `language` char(7) NOT NULL DEFAULT '*' AFTER `alias`;
ALTER TABLE `#__foos_details` ADD KEY `idx_language` (`language`);

src/administrator/components/com_foos/src/Extension/FoosComponent.php

In FoosComponent ergänzen wir den AssociationServiceTrait.

Traits sind ein Mechanismus zur Wiederverwendung von Code, der in Programmiersprachen mit einfacher Vererbung wie PHP verwendet wird.

src/administrator/components/com_foos/src/Extension/FoosComponent.php

...
class FoosComponent extends MVCComponent
implements BootableExtensionInterface, CategoryServiceInterface, AssociationServiceInterface
{
	use CategoryServiceTrait;
	use AssociationServiceTrait;
  use HTMLRegistryAwareTrait;
...

src/administrator/components/com_foos/src/Field/Modal/FooField.php

Das Modal haben wir bisher genutzt, um beim Anlegen eines Menüpunkts ein Foo-Element auszuwählen. Jetzt verwenden wir es wieder, um eine Sprachverknüpfung zu selektieren. Damit nur die passenden Sprachen angezeigt werden, erweitern wir die URL.

src/administrator/components/com_foos/src/Field/Modal/FooField.php

...
if (isset($this->element['language'])) {
  $linkFoos .= '&amp;forcedLanguage=' . $this->element['language'];
  $modalTitle .= ' &#8212; ' . $this->element['label'];
}
...

src/administrator/components/com_foos/src/Model/FooModel.php

Das Model passen wir bezüglich der Sprache an. Dabei spielen getItem und preprocessForm die wesentliche Rolle.

src/administrator/components/com_foos/src/Model/FooModel.php

...
public function getItem($pk = null)
	{
		$item = parent::getItem($pk);

		// Load associated foo items
		$assoc = Associations::isEnabled();

		if ($assoc)
		{
			$item->associations = array();

			if ($item->id != null)
			{
				$associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $item->id, 'id', null);

				foreach ($associations as $tag => $association)
				{
					$item->associations[$tag] = $association->id;
				}
			}
		}

		return $item;
	}

	protected function preprocessForm(\JForm $form, $data, $group = 'content')
	{
		if (Associations::isEnabled())
		{
			$languages = LanguageHelper::getContentLanguages(false, true, null, 'ordering', 'asc');

			if (count($languages) > 1)
			{
				$addform = new \SimpleXMLElement('<form />');
				$fields = $addform->addChild('fields');
				$fields->addAttribute('name', 'associations');
				$fieldset = $fields->addChild('fieldset');
				$fieldset->addAttribute('name', 'item_associations');

				foreach ($languages as $language)
				{
					$field = $fieldset->addChild('field');
					$field->addAttribute('name', $language->lang_code);
					$field->addAttribute('type', 'modal_foo');
					$field->addAttribute('language', $language->lang_code);
					$field->addAttribute('label', $language->title);
					$field->addAttribute('translate_label', 'false');
					$field->addAttribute('select', 'true');
					$field->addAttribute('new', 'true');
					$field->addAttribute('edit', 'true');
					$field->addAttribute('clear', 'true');
				}

				$form->load($addform, false);
			}
		}

		parent::preprocessForm($form, $data, $group);
	}
...

src/administrator/components/com_foos/src/Model/FoosModel.php

Im Model der Liste ist es neben dem Hinzufügen der Sprachinformationen jetzt wichtig, den Status zu aktualisieren. Anderfalls ist nicht jederzeit die passende Sprache aktiv.

src/administrator/components/com_foos/src/Model/FoosModel.php

...
	protected function populateState($ordering = 'a.name', $direction = 'asc')
	{
		$app = Factory::getApplication();
		$forcedLanguage = $app->input->get('forcedLanguage', '', 'cmd');

		// Adjust the context to support modal layouts.
		if ($layout = $app->input->get('layout'))
		{
			$this->context .= '.' . $layout;
		}

		// Adjust the context to support forced languages.
		if ($forcedLanguage)
		{
			$this->context .= '.' . $forcedLanguage;
		}

		// List state information.
		parent::populateState($ordering, $direction);

		// Force a language.
		if (!empty($forcedLanguage))
		{
			$this->setState('filter.language', $forcedLanguage);
		}
	}

src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php

Wir implementieren den Service association in AdministratorService.php.

src/administrator/components/com_foos/src/Service/HTML/AdministratorService.php

...
	public function association($fooid)
	{
		$html = '';

		if ($associations = Associations::getAssociations('com_foos', '#__foos_details', 'com_foos.item', $fooid, 'id', null))
		{
			foreach ($associations as $tag => $associated)
			{
				$associations[$tag] = (int) $associated->id;
			}

			$db = Factory::getDbo();
			$query = $db->getQuery(true)
				->select('c.id, c.name as title')
				->select('l.sef as lang_sef, lang_code')
				->from('#__foos_details as c')
				->select('cat.title as category_title')
				->join('LEFT', '#__categories as cat ON cat.id=c.catid')
				->where('c.id IN (' . implode(',', array_values($associations)) . ')')
				->where('c.id != ' . $fooid)
				->join('LEFT', '#__languages as l ON c.language=l.lang_code')
				->select('l.image')
				->select('l.title as language_title');
			$db->setQuery($query);

			try
			{
				$items = $db->loadObjectList('id');
			}
			catch (\RuntimeException $e)
			{
				throw new \Exception($e->getMessage(), 500, $e);
			}

			if ($items)
			{
				foreach ($items as &$item)
				{
					$text = strtoupper($item->lang_sef);
					$url = Route::_('index.php?option=com_foos&task=foo.edit&id=' . (int) $item->id);
					$tooltip = '<strong>' . htmlspecialchars($item->language_title, ENT_QUOTES, 'UTF-8') . '</strong><br>'
						. htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8') . '<br>' . Text::sprintf('JCATEGORY_SPRINTF', $item->category_title);
					$classes = 'badge badge-secondary';

					$item->link = '<a href="' . $url . '" title="' . $item->language_title . '" class="' . $classes . '">' . $text . '</a>'
						. '<div role="tooltip" id="tip' . (int) $item->id . '">' . $tooltip . '</div>';
				}
			}

			$html = LayoutHelper::render('joomla.content.associations', $items);
		}

		return $html;
	}
...

src/administrator/components/com_foos/src/View/Foo/HtmlView.php

src/administrator/components/com_foos/src/View/Foo/HtmlView.php

Wenn nur eine Sprache möglich ist, setzte den Wert des Sprachauswahlfeldes und schützte es vor Schreibzugriff. Außerdem sind nur Kategorien dieser Sprache auswählbar.

...
  if ($this->getLayout() === 'modal' && $forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'cmd'))
  {
    $this->form->setValue('language', null, $forcedLanguage);
    $this->form->setFieldAttribute('language', 'readonly', 'true');

    $this->form->setFieldAttribute('catid', 'language', '*,' . $forcedLanguage);
  }
...

src/administrator/components/com_foos/src/View/Foos/HtmlView.php

src/administrator/components/com_foos/src/View/Foos/HtmlView.php

...
  if ($this->getLayout() !== 'modal')
  {
    $this->addToolbar();
    $this->sidebar = \JHtmlSidebar::render();
  }
  else
  {
    if ($forcedLanguage = Factory::getApplication()->input->get('forcedLanguage', '', 'CMD'))
    {
      $languageXml = new \SimpleXMLElement('<field name="language" type="hidden" default="' . $forcedLanguage . '" />');
    }
  }
...

src/administrator/components/com_foos/tmpl/foo/edit.php

src/administrator/components/com_foos/tmpl/foo/edit.php

src/administrator/components/com_foos/tmpl/foos/default.php

Teste deine Joomla-Komponente

  1. Installiere deine Komponente in Joomla! Version 4, um sie zu testen:

Kopiere die Dateien im administrator Ordner in den administrator Ordner deiner Joomla! 4 Installation.
Kopiere die Dateien im components Ordner in den components Ordner deiner Joomla! 4 Installation.
Kopiere die Dateien im media Ordner in den media Ordner deiner Joomla! 4 Installation.

  1. Die Datenbank ist geändert worden, so dass es erforderlich ist, sie zu aktualisieren. Öffne den Bereich System | Information | Database, wie in Teil 16 beschrieben. Wähle deine Komponente aus und klicke auf Update Structure.

Joomla! Published

  1. Installiere über System | Install | Languages mindestens eine weitere Sprache.
  2. Stelle über System | Manage | Plugins sicher, dass das Plugin Sample Data - Multilingual veröffentlicht ist.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

  1. Wechsele zurück zum Home Dashboard und installiere die Beispieldateien Multilinguale Sample Data.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

  1. Öffne die Ansicht eines Items deiner Komponente im Administrationsbereich und überzeuge dich davon, dass der Status Language änderbar ist. Ändere diesen von All in eine beliebige Sprache.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

  1. Spiele mit den Sprachverknüpfungen und überzeuge dich davon, dass alles korrekt verknüpft wird.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

  1. Erweitere die Tests auf die Komponente Multilingual Associations. Diese unterstützt deine Erweiterung ebenfalls.

Joomla! Sprachverknüpfungen – Multilinguale Associations in deiner Erweiterung

Geänderte Dateien

Übersicht

Vor oder zurück ...