Joomla Developer Manual
Manual Index
Language Extension Example
Introduction
Official Joomla language extensions are normally installed via the System → Install → Languages route. However, there may be occasions when it is necessary to install a language extension via the Install → Extensions → Upload & Install route. This example is for Scottish Gaelic with all of the English to Gaelic translation obtained using openai.com at a cost of just under $5. It is an unofficial language extension because it really needs the translations verified by Gaelic speakers, perhaps unlikely as there are only 60,000 of them in total. Creation of the extension was inspired by the coincidence of an enquiry in the Forum and a personal visit to the ruins or Carnasserie Castle where the very first printed document in Scottish Gaelic was produced in 1567.
Repository File Structure
The following structure includes a build.xml file, used to build the package using phing, and a .gitignore file, neither of which are present in the GitHub repository. The .ini files are translations of the original English .ini files. The method of translation is covered in a separate article.
cefjdemos-pkg-gd-gb
gd-GB
admin_gd-GB
454 *.ini files
install.xml
langmetadata.xml
localise.php
api_gd-GB
2 *.ini files
install.xml
langmetadata.xml
site_gd-GB
69 *.ini files
install.xml
langmetadata.xml
localise.php
admin_gd-GB.zip
api_gd-GB.zip
pkg_gd-GB.xml
script.php
site_gd-GB.zip
.gitignore
build.xml
LICENSE
pkg_gd-GB.zip
README.md
update-hashes.php
updates.xml
The pkg_gd-GB.zip file contains the three client zip files, the script.php file and the pkg_gd-GB.xml file but not the contents of each client folder as they are in the individual zips.
The pkg_gd-GB.xml File
Note that gd-GB is the ISO code for Scottish Gaelic. Most of the fields in the pkg_gd-GB.xml file are self-explanatory. It is possible to create separate Site and Administrator language extensions. However, the Administrator install.xml and langmetadata.xml files are required for language administration and the localise.php file is required for use by some plugins.
<?xml version="1.0" encoding="UTF-8"?>
<extension type="package" method="upgrade">
<name>Scottish Gaelic Language Pack</name>
<packagename>gd-GB</packagename>
<version>5.3.1.1</version>
<creationDate>2025-06-18</creationDate>
<author>Clifford E Ford</author>
<authorEmail>cliff@ford.myzen.co.uk</authorEmail>
<authorUrl>https://github.com/ceford/cefjdemos-pkg-gd-gb</authorUrl>
<copyright>(C) 2025 Clifford E Ford. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<url>https://github.com/ceford/cefjdemos-pkg-gd-gb</url>
<packager>Clifford E Ford</packager>
<packagerurl>https://github.com/ceford/cefjdemos-pkg-gd-gb</packagerurl>
<description><![CDATA[Scottish Gaelic translation created by openai.com]]></description>
<blockChildUninstall>true</blockChildUninstall>
<scriptfile>script.php</scriptfile>
<files>
<file type="language" client="site" id="gd-GB">site_gd-GB.zip</file>
<file type="language" client="administrator" id="gd-GB">admin_gd-GB.zip</file>
<file type="language" client="api" id="gd-GB">api_gd-GB.zip</file>
</files>
<updateservers>
<server type="extension" priority="2" name="Scottish Gaelic Update Site">https://github.com/ceford/cefjdemos-pkg-gd-gb/raw/main/pkg_gd-GB.zip</server>
</updateservers>
</extension>
The extension version is usually the same as the Joomla version for which it was created. An optional extra parameter may be used for updates, for example 5.3.1.1. When creating a third party extension take care not to copy any Official Joomla! elements. The JED Checker will flag some as invalid.
The script.php file
This file is used to perform additional changes during extension install, update or uninstall. It is stored in the administrator/manifests/packages/gd-GB folder.
<?php
/**
* @package Joomla.Language
*
* @copyright (C) 2025
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Installer\InstallerScript;
/**
* Installation class to perform additional changes during install/uninstall/update
*
* @since 4.0.0v1
*/
class Pkg_gdGBInstallerScript extends InstallerScript
{
/**
* Extension script constructor.
*
* @since 4.0.0v1
*/
public function __construct()
{
// Define the minimum versions to be supported.
$this->minimumJoomla = '5.0';
$this->minimumPhp = '8.1.0';
$this->deleteFiles = [
// Previous available version was for 2.5 - assume already removed
// Old files from Joomla 3 language packs - assume already removed
// Old files from Joomla 4 language packs - assume already removed
// Old files from Joomla 5 language packs (Only relevant for Joomla 6, should then be included in the deletion array with the 6.0-dev branch once created)
// '/administrator/language/gd-GB/plg_captcha_recaptcha_invisible.ini',
// '/administrator/language/gd-GB/plg_captcha_recaptcha_invisible.sys.ini',
];
}
/**
* Function to perform changes during postflight
*
* @param string $type The action being performed
* @param ComponentAdapter $parent The class calling this method
*
* @return void
*
* @since 4.0.0v1
*/
public function postflight($type, $parent)
{
$this->removeFiles();
}
}
Administrator
The admin folder contains a large number of individual .ini
files and three others: install.xml
, langmetadata.xml
and localise.php
.
install.xml
This file is used for installation and removal of the language extension.
<?xml version="1.0" encoding="UTF-8"?>
<extension client="administrator" type="language" method="upgrade">
<name>Scottish Gaelic</name>
<tag>gd-GB</tag>
<version>5.3.1.1</version>
<creationDate>2025-06-18</creationDate>
<author>Clifford E Ford</author>
<authorEmail>cliff@ford.myzen.co.uk</authorEmail>
<authorUrl>https://github.com/ceford/cefjdemos-pkg-gd-gb</authorUrl>
<copyright>(C) 2025 Clifford E Ford. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<description><![CDATA[Scottish Gaelic translation created by openai.com]]></description>
<files>
<folder>/</folder>
<filename file="meta">langmetadata.xml</filename>
<filename file="meta">install.xml</filename>
</files>
</extension>
langmetadata.xml
This file is used for language management purposes.
<?xml version="1.0" encoding="UTF-8"?>
<metafile client="administrator">
<name>Scottish Gaelic</name>
<tag>gd-GB</tag>
<version>5.3.1.1</version>
<creationDate>2025-06-18</creationDate>
<author>Clifford E Ford</author>
<authorEmail>cliff@ford.myzen.co.uk</authorEmail>
<authorUrl>https://github.com/ceford/cefjdemos-pkg-gd-gb</authorUrl>
<copyright>(C) 2025 Clifford E Ford. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<description><![CDATA[Scottish Gaelic translation created by openai.com]]></description>
<metadata>
<name>Scottish Gaelic</name>
<nativeName>Gàidhlig na h-Alba</nativeName>
<tag>gd-GB</tag>
<rtl>0</rtl>
<locale>gd_GB.utf8, gd_GB.UTF-8, gd_GB, gd, gla, gd-GB, scottish gaelic, gaelic, scots gaelic, scotland, uk, united kingdom</locale>
<firstDay>1</firstDay>
<weekEnd>0,6</weekEnd>
<calendar>gregorian</calendar>
</metadata>
<params />
</metafile>
Notes
- The
<name>
tag should be in English. - The
<nativeName>
tag should be in the extension language. - The
<locale>
tag is used for sorting purposes. It should include:- Standard POSIX-style locale codes (e.g., gd_GB.utf8)
- Alternate capitalizations or encodings (gd_GB.UTF-8, gd_GB)
- ISO language and country codes (gd, gla, gd-GB)
- Human-readable names and aliases (scottish gaelic, scots gaelic, gaelic, etc.)
- Country/region-related terms (scotland, uk if applicable)
- The
<firstDay>
tag is used to specify the first day of the week in that language. 0 is Sunday, 1 is Monday, etc. - The
<weekEnd>
tag is used to define the days considered to be weekend and often greyed. 0,6 is Saturday & Sunday, 1 would be Friday. - The
<calendar>
tag uses gregorian by default. Other calendars may be available for some languages.
localise.php
This file is used to cope with language peculiarities.
<?php
/**
* @package Joomla.Language
*
* @copyright (C) 2025 Clifford E Ford. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*
* @phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
*
* @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace
*/
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* gd-GB localise class.
*
* @since 1.6
*/
abstract class Gd_GBLocalise
{
/**
* Returns the potential suffixes for a specific number of items
*
* @param int $count The number of items.
*
* @return array An array of potential suffixes.
*
* @since 1.6
*/
public static function getPluralSuffixes($count)
{
if ($count == 0) {
return ['0'];
} elseif ($count == 1) {
return ['ONE', '1'];
} else {
return ['OTHER', 'MORE'];
}
}
/**
* Returns the ignored search words
*
* @return array An array of ignored search words.
*
* @since 1.6
*
* @deprecated 5.1 will be removed in 7.0 without replacement
*/
public static function getIgnoredSearchWords()
{
return ['agus', 'ann', 'air', 'an', 'am', 'aig', 'le', 'do', 'gu'];
}
/**
* Returns the lower length limit of search words
*
* @return integer The lower length limit of search words.
*
* @since 1.6
*
* @deprecated 5.1 will be removed in 7.0 without replacement
*/
public static function getLowerLimitSearchWord()
{
return 3;
}
/**
* Returns the upper length limit of search words
*
* @return integer The upper length limit of search words.
*
* @since 1.6
*
* @deprecated 5.1 will be removed in 7.0 without replacement
*/
public static function getUpperLimitSearchWord()
{
return 20;
}
/**
* Returns the number of chars to display when searching
*
* @return int The number of chars to display when searching.
*
* @since 1.6
*
* @deprecated 5.1 will be removed in 7.0 without replacement
*
*/
public static function getSearchDisplayedCharactersNumber()
{
return 200;
}
}
API and Site
The files in these folders are similar to those in the admin folder except that the client attribute is set to api and site respectively and there are fewer *.ini files. The files are not reproduced here. See the en-GB versions for examples.
Result
The following screenshot shows the Home Dashboard with Scottish Gaelic as the Administrator language:
You may notice that some words are in English! They are the module headings that were entered in English. The modules could be edited and the module titles changed to the default language.
The Build
To convert the repository structure into an installable package a build process is required. Phing is a PHP based build tool suitable for this purpose. It uses a build.xml file containing the build instructions and requires a method to call it.
This particular build is very simple. Each of the client folders needs to be compressed into separate zip files and then incorporated into the package zip file.
The build.xml file
<?xml version="1.0" encoding="UTF-8"?>
<project name="gaelic" basedir="." default="main">
<fileset dir="./gd-GB/admin_gd-GB" id="adminfiles">
<include name="**" />
</fileset>
<fileset dir="./gd-GB/api_gd-GB" id="apifiles">
<include name="**" />
</fileset>
<fileset dir="./gd-GB/site_gd-GB" id="sitefiles">
<include name="**" />
</fileset>
<fileset dir="./gd-GB" id="pkgfiles">
<include name="*.zip" />
<include name="pkg_gd-GB.xml" />
<include name="script.php" />
</fileset>
<target name="main" description="main target">
<zip destfile="./gd-GB/admin_gd-GB.zip">
<fileset refid="adminfiles" />
</zip>
<zip destfile="./gd-GB/api_gd-GB.zip">
<fileset refid="apifiles" />
</zip>
<zip destfile="./gd-GB/site_gd-GB.zip">
<fileset refid="sitefiles" />
</zip>
<zip destfile="./pkg_gd-GB.zip">
<fileset refid="pkgfiles" />
</zip>
<exec command="php update-hashes.php pkg_gd-GB.zip updates.xml" passthru="true"/>
</target>
</project>
The build process is then called from a VSCode tasks file.
The .vscode/tasks.json file
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build pkg_gd-GB",
"type": "shell",
"command": "php ~/bin/phing-latest.phar",
"windows": {
"command": "php ~/bin/phing-latest.phar"
},
"group": "build",
"presentation": {
"reveal": "always",
"panel": "shared"
}
}
]
}
The update-hashes.php file
In the last stage of the build the SHA256, SHA384 and SHA512 values are calculated for use in the updates.xml
file. This is accomplished by executing a short PHP script:
<?php
if ($argc !== 3) {
fwrite(STDERR, "Usage: php update-hashes.php <zip-file> <xml-file>\n");
exit(1);
}
$zipFile = $argv[1];
$xmlFile = $argv[2];
// Calculate hashes
$sha256 = hash_file('sha256', $zipFile);
$sha384 = hash_file('sha384', $zipFile);
$sha512 = hash_file('sha512', $zipFile);
// Load and update XML
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->formatOutput = true;
$doc->load($xmlFile);
if (($sha256Node = $doc->getElementsByTagName('sha256')->item(0)) !== null) {
$sha256Node->nodeValue = $sha256;
}
if (($sha384Node = $doc->getElementsByTagName('sha384')->item(0)) !== null) {
$sha384Node->nodeValue = $sha384;
}
if (($sha512Node = $doc->getElementsByTagName('sha512')->item(0)) !== null) {
$sha512Node->nodeValue = $sha512;
}
$doc->save($xmlFile);
echo "Updated hashes in $xmlFile\n";
The updates.xml file
This file is referred to in the installation pkg_gd-GB.xml file so that the integrity of the extension can be checked before it is unpacked.
<?xml version="1.0" encoding="UTF-8"?>
<updates>
<update>
<name>Scottish Gaelic</name>
<description>Scottish Gaelic Language Pack</description>
<element>gd-GB</element>
<type>language</type>
<version>5.3.1.2</version>
<client>administrator</client>
<infourl title="Scottish Gaelic Language Pack">https://github.com/ceford/cefjdemos-pkg-gd-gb/blob/main/README.md</infourl>
<downloads>
<downloadurl type="full" format="zip">https://github.com/ceford/cefjdemos-pkg-gd-gb/raw/main/pkg_gd-GB.zip</downloadurl>
</downloads>
<sha256>9f87ff34e266f9cf7aa69ade02a05c633023cd938d7bd618bc8ff43f16600daf</sha256>
<sha384>63c1ce944c5a5f79ebbde758c1c10f803c4684fcb1dab6df7aa138eab1c98260e7c93ebb652f577ed65ce308d0d29ff2</sha384>
<sha512>98868560977f1a8bcec9b9b223a65ba33f1abdd5146b027b8fb768ce9eb5fef7fbb866990208b9850520d89a435c8f11b28ceff10e86c543ecb2967a36f8e1d4</sha512>
<changelogurl>https://raw.githubusercontent.com/ceford/cefjdemos-pkg-gd-gb/refs/heads/main/changelog.xml</changelogurl>
<tags>
<tag>stable</tag>
</tags>
<targetplatform name="joomla" version="[456].[012345]"/>
</update>
</updates>
JED Checker
Although this extension is not destined for the Joomla Extensions Directory, the JED Checker is an invaluable development tool. This is what it reports:
The XML Manifest errors appear to be a JED Checker bug that has been reported. There are no other problems.