Add support for language locales
authorAlexander Ebert <ebert@woltlab.com>
Sat, 15 Oct 2022 11:49:49 +0000 (13:49 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 15 Oct 2022 11:49:49 +0000 (13:49 +0200)
wcfsetup/install/files/acp/templates/languageAdd.tpl
wcfsetup/install/files/lib/acp/form/LanguageAddForm.class.php
wcfsetup/install/files/lib/acp/form/LanguageEditForm.class.php
wcfsetup/install/files/lib/data/language/Language.class.php
wcfsetup/install/lang/de.xml
wcfsetup/install/lang/en.xml
wcfsetup/setup/db/install.sql

index 296313965c666e417274770570eade97558ba933..699145e7e0ed2241163d94383b82004d64f8711f 100644 (file)
                        </dd>
                </dl>
                
+               <dl{if $errorField == 'locale'} class="formError"{/if}>
+                       <dt><label for="locale">{lang}wcf.acp.language.locale{/lang}</label></dt>
+                       <dd>
+                               <select id="locale" name="locale" class="medium" required>
+                                       <option value="">{lang}wcf.global.noSelection{/lang}</option>
+                                       {foreach from=$locales key='identifier' item='displayName'}
+                                               <option value="{$identifier}"{if $identifier === $locale} selected{/if}>{$displayName}</option>
+                                       {/foreach}
+                               </select>
+                               {if $errorField == 'locale'}
+                                       <small class="innerError">
+                                               {if $errorType == 'empty'}
+                                                       {lang}wcf.global.form.error.empty{/lang}
+                                               {else}
+                                                       {lang}wcf.acp.language.add.locale.error.{@$errorType}{/lang}
+                                               {/if}
+                                       </small>
+                               {/if}
+                               <small>{lang}wcf.acp.language.locale.description{/lang}</small>
+                       </dd>
+               </dl>
+               
                {if $action == 'add'}
                        <dl{if $errorField == 'sourceLanguageID'} class="formError"{/if}>
                                <dt><label for="sourceLanguageID">{lang}wcf.acp.language.add.source{/lang}</label></dt>
index 2ba1fa96013dfce8247eb4eebd1f76374bb58329..7a2b02129e553dbd6e5603926fc3b85f0d922859 100644 (file)
@@ -73,6 +73,34 @@ class LanguageAddForm extends AbstractForm
      */
     public $sourceLanguageID = 0;
 
+    /**
+     * @var string[]
+     */
+    public array $locales;
+
+    public string $locale = '';
+
+    /**
+     * @inheritDoc
+     */
+    public function readParameters()
+    {
+        parent::readParameters();
+
+        $locales = \ResourceBundle::getLocales('');
+        if ($locales === false) {
+            throw new \RuntimeException('Unable to query the ICU database to retrieve the available locales.');
+        }
+
+        $displayLocale = WCF::getLanguage()->getLocale();
+        foreach ($locales as $locale) {
+            $this->locales[$locale] = \Locale::getDisplayName($locale, $displayLocale);
+        }
+
+        $collator = new \Collator($displayLocale);
+        $collator->asort($this->locales, \Collator::SORT_STRING);
+    }
+
     /**
      * @inheritDoc
      */
@@ -92,6 +120,9 @@ class LanguageAddForm extends AbstractForm
         if (isset($_POST['sourceLanguageID'])) {
             $this->sourceLanguageID = \intval($_POST['sourceLanguageID']);
         }
+        if (isset($_POST['locale'])) {
+            $this->locale = $_POST['locale'];
+        }
     }
 
     /**
@@ -116,6 +147,10 @@ class LanguageAddForm extends AbstractForm
 
         // source language id
         $this->validateSource();
+
+        if (!isset($this->locales[$this->locale])) {
+            throw new UserInputException('locale');
+        }
     }
 
     /**
@@ -158,6 +193,7 @@ class LanguageAddForm extends AbstractForm
             'countryCode' => \mb_strtolower($this->countryCode),
             'languageName' => $this->languageName,
             'languageCode' => \mb_strtolower($this->languageCode),
+            'locale' => $this->locale,
         ]));
         $languageEditor = new LanguageEditor($this->sourceLanguage);
         $languageEditor->copy($this->language);
@@ -181,7 +217,7 @@ class LanguageAddForm extends AbstractForm
         ]);
 
         // reset values
-        $this->countryCode = $this->languageCode = $this->languageName = '';
+        $this->countryCode = $this->languageCode = $this->languageName = $this->locale = '';
         $this->sourceLanguageID = 0;
     }
 
@@ -208,6 +244,8 @@ class LanguageAddForm extends AbstractForm
             'languageCode' => $this->languageCode,
             'sourceLanguageID' => $this->sourceLanguageID,
             'languages' => $this->languages,
+            'locale' => $this->locale,
+            'locales' => $this->locales,
             'action' => 'add',
         ]);
     }
index 473781e11d8644e87e60ec72c6e1cc11c8c2654f..89a69a13733c0f6c3af8fbfc2a84bc1a21956db6 100644 (file)
@@ -70,6 +70,7 @@ class LanguageEditForm extends LanguageAddForm
             'countryCode' => \mb_strtolower($this->countryCode),
             'languageName' => $this->languageName,
             'languageCode' => \mb_strtolower($this->languageCode),
+            'locale' => $this->locale,
         ]));
         LanguageFactory::getInstance()->clearCache();
         $this->saved();
@@ -89,6 +90,7 @@ class LanguageEditForm extends LanguageAddForm
             $this->countryCode = $this->language->countryCode;
             $this->languageName = $this->language->languageName;
             $this->languageCode = $this->language->languageCode;
+            $this->locale = $this->language->locale;
         }
     }
 
index e0a5a16c2a0d8fee358fdd0a0ec77afd9d832412..fb5203b974df8dfa836b44d638187771aaf5a8e6 100644 (file)
@@ -23,6 +23,7 @@ use wcf\util\StringUtil;
  * @property-read   int $isDefault      is `1` if the language is the default language, otherwise `0`
  * @property-read   int $hasContent     is `1` if the language can be selected when creating language-specific content, otherwise `0`
  * @property-read   int $isDisabled     is `1` if the language is disabled and thus not selectable, otherwise `0`
+ * @property-read string $locale IETF language tag (BCP 47)
  */
 class Language extends DatabaseObject
 {
@@ -305,4 +306,12 @@ class Language extends DatabaseObject
     {
         return !$this->isDefault && $this->languageCode !== 'de' && $this->languageCode !== 'en';
     }
+
+    /**
+     * Returns the selected locale or if empty the set language code.
+     */
+    public function getLocale(): string
+    {
+        return $this->locale ?: $this->languageCode;
+    }
 }
index 7e7c30c35e0e952cd032328bb620644802e04ac9..b970e127b908a8599d0d5e6f1beb420939b8f974 100644 (file)
@@ -1043,6 +1043,8 @@ Sie erreichen das Fehlerprotokoll unter: {link controller='ExceptionLogView' isE
                <item name="wcf.acp.language.item.languageCategoryID.mode.new"><![CDATA[Neue Sprachvariablen-Kategorie]]></item>
                <item name="wcf.acp.language.add.package"><![CDATA[Paket]]></item>
                <item name="wcf.acp.language.add.package.description"><![CDATA[Die importierten Texte werden dem ausgewählten Paket zugeordnet.]]></item>
+               <item name="wcf.acp.language.locale"><![CDATA[Region]]></item>
+               <item name="wcf.acp.language.locale.description"><![CDATA[Die ausgewählte Region beeinflusst Datumsangaben und die Formatierung von Zahlen.]]></item>
        </category>
        <category name="wcf.acp.menu">
                <item name="wcf.acp.menu.link.management"><![CDATA[Verwaltung]]></item>
index 56e4971de9f2cec8251b3d03ac4c44b3330d2b1b..1ebeb2a1aa6c4101b33f0f1d6c13203e4fea1896 100644 (file)
@@ -1022,6 +1022,8 @@ You can access the error log at: {link controller='ExceptionLogView' isEmail=tru
                <item name="wcf.acp.language.item.languageCategory.error.tooFewSegments"><![CDATA[The entered category contains {#$segmentCount} segment{if $segmentCount > 1}s{/if}.]]></item>
                <item name="wcf.acp.language.add.package"><![CDATA[Package]]></item>
                <item name="wcf.acp.language.add.package.description"><![CDATA[The imported phrases will be assigned to the selected package.]]></item>
+               <item name="wcf.acp.language.locale"><![CDATA[Region]]></item>
+               <item name="wcf.acp.language.locale.description"><![CDATA[The selected region affects dates and the formatting of numbers.]]></item>
        </category>
        <category name="wcf.acp.menu">
                <item name="wcf.acp.menu.link.management"><![CDATA[Management]]></item>
index db331940645b36b0af57ca088147762788419ccf..c0473deda0d1850d31f2e7ee57f9110a5a9f0dd7 100644 (file)
@@ -650,6 +650,7 @@ CREATE TABLE wcf1_language (
        isDefault TINYINT(1) NOT NULL DEFAULT 0,
        hasContent TINYINT(1) NOT NULL DEFAULT 0,
        isDisabled TINYINT(1) NOT NULL DEFAULT 0,
+       locale VARCHAR(50) NOT NULL DEFAULT '',
        UNIQUE KEY languageCode (languageCode)
 );