Initial version
authorMarcel Werk <burntime@woltlab.com>
Fri, 3 Feb 2012 14:15:48 +0000 (15:15 +0100)
committerMarcel Werk <burntime@woltlab.com>
Fri, 3 Feb 2012 14:15:48 +0000 (15:15 +0100)
17 files changed:
.gitignore [new file with mode: 0644]
acpmenu.xml [new file with mode: 0644]
acptemplates/languageAdd.tpl [new file with mode: 0644]
acptemplates/languageEdit.tpl [new file with mode: 0644]
acptemplates/languageExport.tpl [new file with mode: 0644]
acptemplates/languageList.tpl [new file with mode: 0644]
acptemplates/languageServerAdd.tpl [new file with mode: 0644]
acptemplates/languageServerList.tpl [new file with mode: 0644]
files/lib/acp/form/LanguageAddForm.class.php [new file with mode: 0644]
files/lib/acp/form/LanguageExportForm.class.php [new file with mode: 0644]
files/lib/acp/form/LanguageServerAddForm.class.php [new file with mode: 0644]
files/lib/acp/form/LanguageServerEditForm.class.php [new file with mode: 0644]
files/lib/acp/page/LanguageListPage.class.php [new file with mode: 0644]
files/lib/acp/page/LanguageServerListPage.class.php [new file with mode: 0644]
language/de.xml [new file with mode: 0644]
package.xml [new file with mode: 0644]
usergroupoption.xml [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..dc27165
--- /dev/null
@@ -0,0 +1,38 @@
+# Linux
+# backup files
+*~
+
+# Windows
+# thumbnails
+Thumbs.db
+
+# Mac OS X
+# metadata
+.DS_Store
+# thumbnails
+._*
+
+# Visual Studio PHP
+*.sln
+*.phpproj
+*.puo
+*.suo
+*.cache
+
+# Eclipse
+.settings/
+.project
+.buildpath
+
+# Netbeans
+nbproject/
+nbactions.xml
+
+# SVN
+# svn folders
+.svn/
+
+# Community Framework
+# Ignore packages build directly in the workspace. They can however be added manually via git add, if wanted.
+*.tar
+*.tar.gz
diff --git a/acpmenu.xml b/acpmenu.xml
new file mode 100644 (file)
index 0000000..d4e3af2
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/acpmenu.xsd">
+       <import>
+               <acpmenuitem name="wcf.acp.menu.link.language">
+                       <parent>wcf.acp.menu.link.display</parent>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.language.list">
+                       <parent>wcf.acp.menu.link.language</parent>
+                       <link>index.php/LanguageList/</link>
+                       <permissions>admin.language.canEditLanguage,admin.language.canDeleteLanguage</permissions>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.language.add">
+                       <parent>wcf.acp.menu.link.language</parent>
+                       <link>index.php/LanguageAdd/</link>
+                       <permissions>admin.language.canAddLanguage</permissions>
+               </acpmenuitem>
+               
+               <acpmenuitem name="wcf.acp.menu.link.language.server">
+                       <parent>wcf.acp.menu.link.language</parent>
+               </acpmenuitem>
+
+               <acpmenuitem name="wcf.acp.menu.link.language.server.list">
+                       <link>index.php/LanguageServerList/</link>
+                       <parent>wcf.acp.menu.link.language.server</parent>
+                       <permissions>admin.language.canEditServer,admin.language.canDeleteServer</permissions>
+               </acpmenuitem>
+
+               <acpmenuitem name="wcf.acp.menu.link.language.server.add">
+                       <link>index.php/LanguageServerAdd/</link>
+                       <parent>wcf.acp.menu.link.language.server</parent>
+                       <permissions>admin.language.canAddServer</permissions>
+               </acpmenuitem>
+       </import>
+</data>
diff --git a/acptemplates/languageAdd.tpl b/acptemplates/languageAdd.tpl
new file mode 100644 (file)
index 0000000..829e7cd
--- /dev/null
@@ -0,0 +1,122 @@
+{include file='header'}
+
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               new WCF.ToggleOptions('import', [ 'importDiv' ], [ 'copyDiv' ]);
+               new WCF.ToggleOptions('copy', [ 'copyDiv' ], [ 'importDiv' ]);
+       });
+       //]]>
+</script>
+
+<header class="mainHeading">
+       <img src="{@RELATIVE_WCF_DIR}icon/add1.svg" alt="" />
+       <hgroup>
+               <h1>{lang}wcf.acp.language.add{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.global.form.add.success{/lang}</p> 
+{/if}
+
+<div class="contentHeader">
+       <nav>
+               <ul class="largeButtons">
+                       <li><a href="{link controller='LanguageList'}{/link}" title="{lang}wcf.acp.menu.link.language.list{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/language1.svg" alt="" /> <span>{lang}wcf.acp.menu.link.language.list{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+<form enctype="multipart/form-data" method="post" action="{link controller='LanguageAdd'}{/link}">
+       <div class="border content">
+               <dl>
+                       <dt><label for="import">{lang}wcf.acp.language.add.mode{/lang}</label></dt>
+                       <dd>
+                               <label><input type="radio" name="mode" value="import" id="import" {if $mode == 'import'}checked="checked" {/if}/> {lang}wcf.acp.language.add.mode.import{/lang}</label>
+                               <label><input type="radio" name="mode" value="copy" id="copy" {if $mode == 'copy'}checked="checked" {/if}/> {lang}wcf.acp.language.add.mode.copy{/lang}</label>
+                       </dd>
+               </dl>
+               
+               <fieldset id="importDiv">
+                       <legend>{lang}wcf.acp.language.import.source{/lang}</legend>
+                       
+                       <dl{if $errorField == 'languageFile'} class="formError"{/if}>
+                               <dt><label for="languageFile">{lang}wcf.acp.language.import.source.file{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" name="languageFile" id="languageFile" value="{$languageFile}" class="long" />
+                                       {if $errorField == 'languageFile'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}
+                                                               {lang}wcf.global.error.empty{/lang}
+                                                       {else}
+                                                               {lang}wcf.acp.language.import.error{/lang} {$errorType}
+                                                       {/if}
+                                               </small>
+                                       {/if}
+                                       <small>{lang}wcf.acp.language.import.source.file.description{/lang}</small>
+                               </dd>
+                       </dl>
+                       
+                       <dl{if $errorField == 'languageUpload'} class="formError"{/if}>
+                               <dt><label for="languageUpload">{lang}wcf.acp.language.import.source.upload{/lang}</label></dt>
+                               <dd>
+                                       <input type="file" name="languageUpload" id="languageUpload" />
+                                       {if $errorField == 'languageUpload'}
+                                               <small class="innerError">
+                                                       {lang}wcf.acp.language.import.error{/lang} {$errorType}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+               </fieldset>
+       
+               <fieldset id="copyDiv">
+                       <legend>{lang}wcf.acp.language.add.new{/lang}</legend>
+                       
+                       <dl{if $errorField == 'languageCode'} class="formError"{/if}>
+                               <dt><label for="languageCode">{lang}wcf.acp.language.code{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" name="languageCode" id="languageCode" value="{$languageCode}" class="long" />
+                                       {if $errorField == 'languageCode'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}{lang}wcf.global.error.empty{/lang}{/if}
+                                                       {if $errorType == 'notUnique'}{lang}wcf.acp.language.add.languageCode.error.notUnique{/lang}{/if}
+                                               </small>
+                                       {/if}
+                                       <small>{lang}wcf.acp.language.code.description{/lang}</small>
+                               </dd>
+                       </dl>
+                       
+                       <dl{if $errorField == 'sourceLanguageID'} class="formError"{/if}>
+                               <dt><label for="sourceLanguageID">{lang}wcf.acp.language.add.source{/lang}</label></dt>
+                               <dd>
+                                       <select name="sourceLanguageID" id="sourceLanguageID">
+                                               {foreach from=$languages item=language}
+                                                       <option value="{@$language->languageID}"{if $language->languageID == $sourceLanguageID} selected="selected"{/if}>{$language->languageName} ({$language->languageCode})</option>
+                                               {/foreach}
+                                       </select>
+                                       {if $errorField == 'sourceLanguageID'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}{lang}wcf.global.error.empty{/lang}{/if}
+                                               </small>
+                                       {/if}
+                               </dd>
+                       </dl>
+               </fieldset>
+               
+               {if $additionalFields|isset}{@$additionalFields}{/if}
+       </div>
+       
+       <div class="formSubmit">
+               <input type="reset" value="{lang}wcf.global.button.reset{/lang}" accesskey="r" />
+               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+               {@SID_INPUT_TAG}
+       </div>
+</form>
+
+{include file='footer'}
diff --git a/acptemplates/languageEdit.tpl b/acptemplates/languageEdit.tpl
new file mode 100644 (file)
index 0000000..750fb54
--- /dev/null
@@ -0,0 +1,191 @@
+{include file='header'}
+{if $languageItems|count}
+       <script type="text/javascript">
+               //<![CDATA[
+               $(function() {
+                       var $languageItems = [ ];
+                       
+                       // read language item names
+                       $('fieldset.languageItem').each(function(index, languageItem) {
+                               $languageItems.push($(languageItem).data('languageItem').toLowerCase());
+                       });
+                       
+                       // enable quick search
+                       $('#quicksearch').bind('keyup', function() {
+                               var $searchString = $('#quicksearch').val().toLowerCase();
+                               
+                               for (var $i = 0, $length = $languageItems.length; $i < $length; $i++) {
+                                       var $item = $languageItems[$i];
+                                       
+                                       if ($item.indexOf($searchString) >= 0) {
+                                               $('#item' + $.wcfEscapeID($item)).show();
+                                       }
+                                       else {
+                                               $('#item' + $.wcfEscapeID($item)).hide();
+                                       }
+                               }
+                       });
+                       
+                       // disable form submit on RETURN (= 13)
+                       $('#quicksearch').bind('keydown', function(event) {
+                               if (event.which == 13) {
+                                       event.stopPropagation();
+                                       return false;
+                               }
+                       });
+                       
+                       // custom versions
+                       $('input.itemUseCustom').each(function(index, item) {
+                               var $item = $(item);
+                               
+                               if (!$item.attr('checked')) {
+                                       $('#languageCustomItems-' + $item.data('languageItem')).hide();
+                               }
+                               
+                               $item.change(function(event) {
+                                       var $item = $(event.targetElement);
+                                       if ($item.attr('checked')) {
+                                               $('#languageCustomItems-' + $item.data('languageItem')).show();
+                                       }
+                                       else {
+                                               $('#languageCustomItems-' + $item.data('languageItem')).hide();
+                                       }
+                               });
+                       });
+               });
+               //]]>
+       </script>
+{/if}
+
+<div class="mainHeadline">
+       <img src="{@RELATIVE_WCF_DIR}icon/languageEditL.png" alt="" />
+       <div class="headlineContainer">
+               <h2>{lang}wcf.acp.language.edit{/lang}</h2>
+       </div>
+</div>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.acp.language.edit.success{/lang}</p>       
+{/if}
+
+<div class="contentHeader">
+       <div class="largeButtons">
+               <ul><li><a href="index.php?page=LanguageList{@SID_ARG_2ND}"><img src="{@RELATIVE_WCF_DIR}icon/languageM.png" alt="" title="{lang}wcf.acp.menu.link.language.view{/lang}" /> <span>{lang}wcf.acp.menu.link.language.view{/lang}</span></a></li>
+               <li><a href="index.php?form=LanguageSearch{@SID_ARG_2ND}"><img src="{@RELATIVE_WCF_DIR}icon/searchM.png" alt="" title="{lang}wcf.acp.menu.link.language.view{/lang}" /> <span>{lang}wcf.acp.menu.link.language.search{/lang}</span></a></li></ul>
+       </div>
+</div>
+<form method="get" action="index.php">
+       <div class="border content">
+               <div class="container-1">
+                       <div class="formElement">
+                               <p class="formField">
+                                       <span>{lang}wcf.global.language.{@$language->languageCode}{/lang} ({@$language->languageCode})</span>
+                                       <img src="{@RELATIVE_WCF_DIR}icon/language{@$language->languageCode|ucfirst}S.png" alt="" />
+                               </p>
+                       </div>
+                       
+                       <div class="formElement{if $errorField == 'languageCategoryID'} formError{/if}">
+                               <div class="formFieldLabel">
+                                       <label for="languageCategoryID">{lang}wcf.acp.language.category{/lang}</label>
+                               </div>
+                               <div class="formField">
+                                       <select name="languageCategoryID" id="languageCategoryID" onchange="if (this.options[this.selectedIndex].value != 0) this.form.submit();">
+                                               <option value="0"></option>
+                                               {htmlOptions options=$languageCategories selected=$languageCategoryID}
+                                       </select>
+                                       {if $errorField == 'languageCategoryID'}
+                                               <p class="innerError">
+                                                       {if $errorType == 'empty'}{lang}wcf.global.error.empty{/lang}{/if}
+                                               </p>
+                                       {/if}
+                               </div>
+                       </div>
+                       
+                       <div class="formElement">
+                               <div class="formField">
+                                       <label><input onclick="this.form.submit()" type="checkbox" name="customVariables" value="1" {if $customVariables == 1}checked="checked" {/if}/> {lang}wcf.acp.language.showCustomVariables{/lang}</label>
+                               </div>
+                       </div>
+               </div>
+               
+               <input type="hidden" name="form" value="LanguageEdit" />
+               <input type="hidden" name="languageID" value="{@$languageID}" />
+               {@SID_INPUT_TAG}
+       </div>
+</form>
+
+{if $languageItems|count}
+       <form method="post" action="index.php?form=LanguageEdit">
+               <fieldset>
+                       <div class="formElement">
+                               <div class="formFieldLabel">
+                                       {lang}wcf.acp.language.variable.quicksearch{/lang}
+                               </div>
+                               <div class="formField">
+                                       <input class="inputText" type="text" id="quicksearch" value="" />
+                               </div>
+                       </div>
+               </fieldset>
+               
+               {foreach from=$languageItems item=category}
+                       <div class="border content">
+                               <div class="container-1">
+                                       <h3 class="subHeadline">{$category.category}</h3>
+                                       {foreach from=$category.items key=$languageItem item=languageItemValue}
+                                               <a id="languageItem{@$languageItemIDs.$languageItem}"></a>
+                                               
+                                               <fieldset data-languageItem="{$languageItem}" class="languageItem" id="item{$languageItem|strtolower}">
+                                                       <legend>
+                                                               {if $__wcf->getSession()->getPermission('admin.language.canDeleteLanguage')}<a onclick="return confirm('{lang}wcf.acp.language.variable.delete.sure{/lang}')" href="index.php?action=LanguageVariableDelete&amp;languageItem={$languageItem}&amp;languageID={@$languageID}&amp;languageCategoryID={@$languageCategoryID}{@SID_ARG_2ND}"><img src="{@RELATIVE_WCF_DIR}icon/deleteS.png" alt="" title="{lang}wcf.acp.language.variable.delete{/lang}" /></a>{/if}
+                                                               <label for="languageCustomItems-{$languageItem}">{$languageItem}</label>
+                                                       </legend>
+                                                       
+                                                       <div class="formElement">
+                                                               <div class="formFieldLabel">
+                                                                       <label for="languageItems-{$languageItem}">{lang}wcf.acp.language.value{/lang}</label>
+                                                               </div>
+                                                               <div class="formField">
+                                                                       <textarea readonly="readonly" rows="5" cols="60" id="languageItems-{$languageItem}">{$languageItemValue}</textarea>
+                                                               </div>
+                                                       </div>
+                                                       <div class="formElement">
+                                                               <div class="formFieldLabel">
+                                                                       <label for="languageCustomItems-{$languageItem}">{lang}wcf.acp.language.customValue{/lang}</label>
+                                                               </div>
+                                                               <div class="formField">
+                                                                       <textarea rows="5" cols="60" name="languageItems[{$languageItem}]" id="languageCustomItems-{$languageItem}">{if $languageCustomItems.$languageItem}{$languageCustomItems.$languageItem}{/if}</textarea>
+                                                                       <label><input class="itemUseCustom" data-languageItem="{$languageItem}" type="checkbox" name="languageUseCustom[{$languageItem}]" id="languageUseCustom-{$languageItem}" value="1" {if !$languageUseCustom.$languageItem|empty}checked="checked" {/if}/> {lang}wcf.acp.language.useCustomValue{/lang}</label>
+                                                               </div>
+                                                       </div>
+                                               </fieldset>
+                                               
+                                               {if $languageItemID == $languageItemIDs.$languageItem}
+                                                       <script type="text/javascript">
+                                                               //<![CDATA[
+                                                               document.getElementById('languageItems-{$languageItem}').focus();
+                                                               //]]>
+                                                       </script>
+                                               {/if}
+                                       {/foreach}
+                               </div>
+                       </div>
+               {/foreach}
+               
+               {if $additionalFields|isset}{@$additionalFields}{/if}
+               
+               <div class="formSubmit">
+                       <input type="submit" accesskey="s" value="{lang}wcf.global.button.submit{/lang}" />
+                       <input type="reset" accesskey="r" value="{lang}wcf.global.button.reset{/lang}" />
+                       {@SID_INPUT_TAG}
+                       <input type="hidden" name="languageCategoryID" value="{@$languageCategoryID}" />
+                       <input type="hidden" name="customVariables" value="{@$customVariables}" />
+                       <input type="hidden" name="languageID" value="{@$languageID}" />
+               </div>
+       </form>
+{/if}
+
+{include file='footer'}
diff --git a/acptemplates/languageExport.tpl b/acptemplates/languageExport.tpl
new file mode 100644 (file)
index 0000000..b06bce3
--- /dev/null
@@ -0,0 +1,64 @@
+{include file='header'}
+
+<header class="mainHeading">
+       <img src="{@RELATIVE_WCF_DIR}icon/export1.svg" alt="" />
+       <hgroup>
+               <h1>{lang}wcf.acp.language.export{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.acp.language.add.success{/lang}</p>        
+{/if}
+
+<div class="contentHeader">
+       <nav>
+               <ul class="largeButtons">
+                       <li><a href="{link controller='LanguageList'}{/link}" title="{lang}wcf.acp.menu.link.language.list{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/language1.svg" alt="" /> <span>{lang}wcf.acp.menu.link.language.list{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+<form enctype="multipart/form-data" method="post" action="{link controller='LanguageExport' id=$languageID}{/link}">
+       <div class="border content">
+               <dl>
+                       <dt><label for="languageID">{lang}wcf.user.language{/lang}</label></dt>
+                       <dd>
+                               {htmloptions options=$languages selected=$languageID name='languageID' id='languageID'}
+                       </dd>
+               </dl>
+               
+               <dl>
+                       <dt><label for="selectedPackages">{lang}wcf.acp.language.export.selectPackages{/lang}</label></dt>
+                       <dd>
+                               <select id="selectedPackages" name="selectedPackages[]" multiple="multiple" size="20" style="font-family: Monaco, 'Courier New', Courier, monospace">
+                                       <option value="*"{if $selectAllPackages} selected="selected"{/if}>{lang}wcf.acp.language.export.allPackages{/lang}</option>
+                                       <option value="-">--------------------</option>
+                                       {foreach from=$packages item=package}
+                                               {assign var=loop value=$packageNameLength-$package->packageNameLength}
+                                               <option value="{@$package->packageID}"{if $selectedPackages[$package->packageID]|isset} selected="selected"{/if}>{$package->packageName} {section name=i loop=$loop}&nbsp;{/section}&nbsp;&nbsp;{$package->package}</option>
+                                       {/foreach}
+                               </select>
+                       </dd>
+               </dl>
+               
+               <dl>
+                       <dt class="reversed"><label for="exportCustomValues">{lang}wcf.acp.language.export.customValues{/lang}</label></dt>
+                       <dd>
+                               <input type="checkbox" name="exportCustomValues" id="exportCustomValues" value="1" />
+                       </dd>
+               </dl>
+       </div>
+       
+       <div class="formSubmit">
+               <input type="submit" accesskey="s" value="{lang}wcf.global.button.submit{/lang}" />
+               <input type="reset" accesskey="r" value="{lang}wcf.global.button.reset{/lang}" />
+               {@SID_INPUT_TAG}
+       </div>
+</form>
+
+{include file='footer'}
\ No newline at end of file
diff --git a/acptemplates/languageList.tpl b/acptemplates/languageList.tpl
new file mode 100644 (file)
index 0000000..4ab6030
--- /dev/null
@@ -0,0 +1,136 @@
+{include file='header'}
+
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               new WCF.Action.Delete('wcf\\data\\language\\LanguageAction', $('.languageRow'));
+               new WCF.Action.SimpleProxy({
+                       action: 'setAsDefault',
+                       className: 'wcf\\data\\language\\LanguageAction',
+                       elements: $('.languageRow .setAsDefaultButton')
+               }, {
+                       success: function(data, statusText, jqXHR) {
+                               $('.languageRow').each(function(index, row) {
+                                       var $button = $(row).find('.setAsDefaultButton');
+                                       
+                                       if (WCF.inArray($($button).data('objectID'), data.objectIDs)) {
+                                               $($button).attr('src', '{@RELATIVE_WCF_DIR}icon/defaultDisabledS.png');
+                                               $(row).find('.deleteButton').attr('src', '{@RELATIVE_WCF_DIR}icon/deleteDisabledS.png');
+                                       }
+                                       else {
+                                               $($button).attr('src', '{@RELATIVE_WCF_DIR}icon/defaultS.png');
+                                               $(row).find('.deleteButton').attr('src', '{@RELATIVE_WCF_DIR}icon/deleteS.png');
+                                       }
+                               });
+                       }
+               });
+       });
+       //]]>
+</script>
+
+<header class="mainHeading">
+       <img src="{@RELATIVE_WCF_DIR}icon/language1.svg" alt="" />
+       <hgroup>
+               <h1>{lang}wcf.acp.language.list{/lang}</h1>
+       </hgroup>
+</header>
+
+<div class="contentHeader">
+       {pages print=true assign=pagesLinks controller='LanguageList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+       
+       {if $__wcf->getSession()->getPermission('admin.language.canAddLanguage')}
+               <nav>
+                       <ul class="largeButtons">
+                               <li><a href="{link controller='LanguageAdd'}{/link}" title="{lang}wcf.acp.language.add{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/add1.svg" alt="" /> <span>{lang}wcf.acp.language.add{/lang}</span></a></li>
+                               
+                               {event name='largeButtons'}
+                       </ul>
+               </nav>
+       {/if}
+</div>
+
+{if $objects|count}
+       <div class="border boxTitle">
+               <hgroup>
+                       <h1>{lang}wcf.acp.language.list{/lang} <span class="badge" title="{lang}wcf.acp.language.list.count{/lang}">{#$items}</span></h1>
+               </hgroup>
+       
+               <table>
+                       <thead>
+                               <tr>
+                                       <th class="columnID columnLanguageID{if $sortField == 'languageID'} active{/if}" colspan="2"><a href="{link controller='LanguageList'}pageNo={@$pageNo}&sortField=languageID&sortOrder={if $sortField == 'languageID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}{if $sortField == 'languageID'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                                       <th class="columnTitle columnLanguageName{if $sortField == 'languageName'} active{/if}"><a href="{link controller='LanguageList'}pageNo={@$pageNo}&sortField=languageName&sortOrder={if $sortField == 'languageName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.language.name{/lang}{if $sortField == 'languageName'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                                       <th class="columnDigits columnUsers{if $sortField == 'users'} active{/if}"><a href="{link controller='LanguageList'}pageNo={@$pageNo}&sortField=users&sortOrder={if $sortField == 'users' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.language.users{/lang}{if $sortField == 'users'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                                       <th class="columnDigits columnVariables{if $sortField == 'variables'} active{/if}"><a href="{link controller='LanguageList'}pageNo={@$pageNo}&sortField=variables&sortOrder={if $sortField == 'variables' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.language.variables{/lang}{if $sortField == 'variables'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                                       <th class="columnDigits columnCustomVariables{if $sortField == 'customVariables'} active{/if}"><a href="{link controller='LanguageList'}pageNo={@$pageNo}&sortField=customVariables&sortOrder={if $sortField == 'customVariables' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.language.customVariables{/lang}{if $sortField == 'customVariables'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                               </tr>
+                       </thead>
+                       
+                       <tbody>
+                       {foreach from=$objects item=language}
+                               <tr class="languageRow">
+                                       <td class="columnIcon">
+                                               {if $__wcf->getSession()->getPermission('admin.language.canEditLanguage')}
+                                                       <a href="{link controller='LanguageExport' id=$language->languageID}{/link}"><img src="{@RELATIVE_WCF_DIR}icon/download1.svg" alt="" title="{lang}wcf.acp.language.export{/lang}" class="balloonTooltip" /></a>
+                                               {else}
+                                                       <img src="{@RELATIVE_WCF_DIR}icon/download1D.png" alt="" title="{lang}wcf.acp.language.export{/lang}" />
+                                               {/if}
+                                               
+                                               {if $__wcf->getSession()->getPermission('admin.language.canEditLanguage')}
+                                                       {if !$language->isDefault}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/default1.svg" alt="" title="{lang}wcf.acp.language.setAsDefault{/lang}" class="setAsDefaultButton balloonTooltip" data-objectID="{@$language->languageID}" />
+                                                       {else}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/default1D.svg" alt="" title="{lang}wcf.acp.language.setAsDefault{/lang}" class="setAsDefaultButton" data-objectID="{@$language->languageID}" />
+                                                       {/if}
+                                               {else}
+                                                       <img src="{@RELATIVE_WCF_DIR}icon/default1D.svg" alt="" title="{lang}wcf.acp.language.setAsDefault{/lang}" />
+                                               {/if}
+                                               
+                                               {if $__wcf->getSession()->getPermission('admin.language.canEditLanguage')}
+                                                       <a href="{link controller='LanguageEdit' id=$language->languageID}{/link}"><img src="{@RELATIVE_WCF_DIR}icon/edit1.svg" alt="" title="{lang}wcf.global.button.edit{/lang}" class="balloonTooltip" /></a>
+                                               {else}
+                                                       <img src="{@RELATIVE_WCF_DIR}icon/edit1D.svg" alt="" title="{lang}wcf.global.button.edit{/lang}" />
+                                               {/if}
+                                               {if $__wcf->getSession()->getPermission('admin.language.canDeleteLanguage')}
+                                                       {if !$language->isDefault}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/delete1.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" class="balloonTooltip deleteButton" data-objectID="{@$language->languageID}" data-confirmMessage="{lang}wcf.acp.language.delete.sure{/lang}" />
+                                                       {else}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/delete1D.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" class="deleteButton" data-objectID="{@$language->languageID}" data-confirmMessage="{lang}wcf.acp.language.delete.sure{/lang}" />
+                                                       {/if}
+                                               {else}
+                                                       <img src="{@RELATIVE_WCF_DIR}icon/delete1D.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" />
+                                               {/if}
+                                       </td>
+                                       <td class="columnID columnLanguageID">{@$language->languageID}</td>
+                                       <td class="columnTitle columnLanguageName">
+                                               {if $__wcf->getSession()->getPermission('admin.language.canEditLanguage')}
+                                                       <a href="{link controller='LanguageEdit' id=$language->languageID}{/link}">{$language->languageName} ({@$language->languageCode})</a>
+                                               {else}
+                                                       {$language->languageName} ({@$language->languageCode})
+                                               {/if}
+                                       </td>
+                                       <td class="columnDigits columnUsers">{#$language->users}</td>
+                                       <td class="columnDigits columnVariables">{#$language->variables}</td>
+                                       <td class="columnDigits columnCustomVariables">{if $language->customVariables > 0 && $__wcf->getSession()->getPermission('admin.language.canEditLanguage')}<a href="{link controller='LanguageEdit' id=$language->languageID}customVariables=1{/link}">{#$language->customVariables}</a>{else}{#$language->customVariables}{/if}</td>
+                               </tr>
+                       {/foreach}
+                       </tbody>
+               </table>
+       </div>
+
+       <div class="contentFooter">
+               {@$pagesLinks}
+               
+               {if $__wcf->getSession()->getPermission('admin.language.canAddLanguage')}
+                       <nav>
+                               <ul class="largeButtons">
+                                       <li><a href="{link controller='LanguageAdd'}{/link}" title="{lang}wcf.acp.language.add{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/add1.svg" alt="" /> <span>{lang}wcf.acp.language.add{/lang}</span></a></li>
+                                       
+                                       {event name='largeButtons'}
+                               </ul>
+                       </nav>
+               {/if}
+       </div>
+{/if}
+
+{include file='footer'}
diff --git a/acptemplates/languageServerAdd.tpl b/acptemplates/languageServerAdd.tpl
new file mode 100644 (file)
index 0000000..92f74a3
--- /dev/null
@@ -0,0 +1,55 @@
+{include file='header'}
+
+<header class="mainHeading">
+       <img src="{@RELATIVE_WCF_DIR}icon/{$action}1.svg" alt="" />
+       <hgroup>
+               <h1>{lang}wcf.acp.languageServer.{$action}{/lang}</h1>
+       </hgroup>
+</header>
+
+{if $errorField}
+       <p class="error">{lang}wcf.global.form.error{/lang}</p>
+{/if}
+
+{if $success|isset}
+       <p class="success">{lang}wcf.acp.languageServer.{$action}.success{/lang}</p>    
+{/if}
+
+<div class="contentHeader">
+       <nav>
+               <ul class="largeButtons">
+                       <li><a href="{link controller='LanguageServerList'}{/link}" title="{lang}wcf.acp.menu.link.package.server.view{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/language1.svg" alt="" /> <span>{lang}wcf.acp.menu.link.package.server.view{/lang}</span></a></li>
+               </ul>
+       </nav>
+</div>
+
+<form method="post" action="{if $action == 'add'}{link controller='LanguageServerAdd'}{/link}{else}{link controller='LanguageServerEdit' id=$languageServerID}{/link}{/if}">
+       <div class="border content">
+               <fieldset>
+                       <legend>{lang}wcf.acp.languageServer.data{/lang}</legend>
+                       
+                       <dl{if $errorField == 'server'} class="formError"{/if}>
+                               <dt><label for="server">{lang}wcf.acp.languageServer.server{/lang}</label></dt>
+                               <dd>
+                                       <input type="text" name="server" id="server" value="{$server}" class="long" />
+                                       {if $errorField == 'server'}
+                                               <small class="innerError">
+                                                       {if $errorType == 'empty'}{lang}wcf.global.error.empty{/lang}{/if}
+                                                       {if $errorType == 'notValid'}{lang}wcf.acp.languageServer.server.error.notValid{/lang}{/if}
+                                               </small>
+                                       {/if}
+                                       <small>{lang}wcf.acp.languageServer.server.description{/lang}</small>
+                               </dd>
+                       </dl>
+               
+               </fieldset>
+       </div>
+       
+       <div class="formSubmit">
+               <input type="reset" value="{lang}wcf.global.button.reset{/lang}" accesskey="r" />
+               <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s" />
+               {@SID_INPUT_TAG}
+       </div>
+</form>
+
+{include file='footer'}
diff --git a/acptemplates/languageServerList.tpl b/acptemplates/languageServerList.tpl
new file mode 100644 (file)
index 0000000..8079922
--- /dev/null
@@ -0,0 +1,99 @@
+{include file='header'}
+
+<script type="text/javascript">
+       //<![CDATA[
+       $(function() {
+               {if $__wcf->getSession()->getPermission('admin.language.canDeleteServer')}new WCF.Action.Delete('wcf\\data\\language\\server\\LanguageServerAction', $('.languageServerRow'));{/if}
+               {if $__wcf->getSession()->getPermission('admin.language.canEditServer')}new WCF.Action.Toggle('wcf\\data\\language\\server\\LanguageServerAction', $('.languageServerRow'));{/if}
+       });
+       //]]>
+</script>
+
+<header class="mainHeading">
+       <img src="{@RELATIVE_WCF_DIR}icon/language1.svg" alt="" />
+       <hgroup>
+               <h1>{lang}wcf.acp.languageServer.list{/lang}</h1>
+       </hgroup>
+</header>
+
+<div class="contentHeader">
+       {pages print=true assign=pagesLinks controller='LanguageServerList' link="pageNo=%d&sortField=$sortField&sortOrder=$sortOrder"}
+       
+       {if $__wcf->getSession()->getPermission('admin.language.canAddServer')}
+               <nav>
+                       <ul class="largeButtons">
+                               <li><a href="{link controller='LanguageServerAdd'}{/link}" title="{lang}wcf.acp.languageServer.add{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/add1.svg" alt="" /> <span>{lang}wcf.acp.languageServer.add{/lang}</span></a></li>
+                               
+                               {event name='largeButtons'}
+                       </ul>
+               </nav>
+       {/if}
+</div>
+
+{if !$languageServers|count}
+       <div class="border content">
+               <div class="container-1">
+                       <p>{lang}wcf.acp.languageServer.view.noneAvailable{/lang}</p>
+               </div>
+       </div>
+{else}
+       <div class="border boxTitle">
+               <hgroup>
+                       <h1>{lang}wcf.acp.languageServer.list{/lang} <span class="badge" title="{lang}wcf.acp.languageServer.list.count{/lang}">{#$items}</span></h1>
+               </hgroup>
+       
+               <table>
+                       <thead>
+                               <tr>
+                                       <th class="columnID columnLanguageServerID{if $sortField == 'languageServerID'} active{/if}" colspan="2"><a href="{link controller='LanguageServerList'}pageNo={@$pageNo}&sortField=languageServerID&sortOrder={if $sortField == 'languageServerID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}{if $sortField == 'languageServerID'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                                       <th class="columnTitle columnServerURL{if $sortField == 'serverURL'} active{/if}"><a href="{link controller='LanguageServerList'}pageNo={@$pageNo}&sortField=serverURL&sortOrder={if $sortField == 'serverURL' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.acp.languageServer.serverURL{/lang}{if $sortField == 'serverURL'} <img src="{@RELATIVE_WCF_DIR}icon/sort{@$sortOrder}.svg" alt="" />{/if}</a></th>
+                               </tr>
+                       </thead>
+                       <tbody>
+                               {foreach from=$languageServers item=languageServer}
+                                       <tr class="languageServerRow">
+                                               <td class="columnIcon">
+                                                       {if $__wcf->getSession()->getPermission('admin.language.canEditServer')}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/{if !$languageServer->disabled}enabled{else}disabled{/if}1.svg" alt="" title="{lang}wcf.global.button.{if !$languageServer->disabled}disable{else}enable{/if}{/lang}" class="toggleButton balloonTooltip" data-object-id="{@$languageServer->languageServerID}" data-disable-message="{lang}wcf.global.button.disable{/lang}" data-enable-message="{lang}wcf.global.button.enable{/lang}" />
+                                                               <a href="{link controller='LanguageServerEdit' id=$languageServer->languageServerID}{/link}"><img src="{@RELATIVE_WCF_DIR}icon/edit1.svg" alt="" title="{lang}wcf.global.button.edit{/lang}" class="balloonTooltip" /></a>
+                                                       {else}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/{if !$languageServer->disabled}enabled{else}disabled{/if}1D.svg" alt="" title="{lang}wcf.global.button.{if !$languageServer->disabled}disable{else}enable{/if}{/lang}" />
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/edit1D.svg" alt="" title="{lang}wcf.global.button.edit{/lang}" />
+                                                       {/if}
+                                                       
+                                                       {if $__wcf->getSession()->getPermission('admin.language.canDeleteServer')}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/delete1.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" class="balloonTooltip deleteButton" data-object-id="{@$languageServer->languageServerID}" data-confirm-message="{lang}wcf.acp.languageServer.delete.sure{/lang}" />
+                                                       {else}
+                                                               <img src="{@RELATIVE_WCF_DIR}icon/delete1D.svg" alt="" title="{lang}wcf.global.button.delete{/lang}" />
+                                                       {/if}
+                                               </td>
+                                               <td class="columnID columnLanguageServerID">{@$languageServer->languageServerID}</td>
+                                               <td class="columnTitle columnServerURL">
+                                                       {if $__wcf->getSession()->getPermission('admin.language.canEditServer')}
+                                                               <a href="{link controller='LanguageServerEdit' id=$languageServer->languageServerID}{/link}">{@$languageServer->serverURL}</a>
+                                                       {else}
+                                                               {@$languageServer->serverURL}
+                                                       {/if}
+                                               </td>
+                                       </tr>
+                               {/foreach}
+                       </tbody>
+               </table>
+       </div>
+       
+       <div class="contentFooter">
+               {@$pagesLinks}
+               
+               {if $__wcf->getSession()->getPermission('admin.language.canAddServer')}
+                       <nav>
+                               <ul class="largeButtons">
+                                       <li><a href="{link controller='LanguageServerAdd'}{/link}" title="{lang}wcf.acp.languageServer.add{/lang}" class="button"><img src="{@RELATIVE_WCF_DIR}icon/add1.svg" alt="" /> <span>{lang}wcf.acp.languageServer.add{/lang}</span></a></li>
+                                       
+                                       {event name='largeButtons'}
+                               </ul>
+                       </nav>
+               {/if}
+       </div>
+{/if}
+
+{include file='footer'}
diff --git a/files/lib/acp/form/LanguageAddForm.class.php b/files/lib/acp/form/LanguageAddForm.class.php
new file mode 100644 (file)
index 0000000..e911b86
--- /dev/null
@@ -0,0 +1,192 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\language\LanguageEditor;
+use wcf\system\exception\UserInputException;
+use wcf\system\language\LanguageFactory;
+use wcf\system\WCF;
+use wcf\system\WCFACP;
+use wcf\util\StringUtil;
+use wcf\util\XML;
+
+/**
+ * Shows the language add form.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf.acp.language
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class LanguageAddForm extends ACPForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.language.add';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canAddLanguage');
+       
+       public $mode = 'import';
+       public $languageFile = '';
+       public $languageCode = '';
+       public $sourceLanguageID = 0;
+       public $filename = '';
+       public $sourceLanguage, $language;
+       public $importField = 'languageFile';
+       public $languages = array();
+       
+       /**
+        * @see wcf\form\Form::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               // mode
+               if (isset($_POST['mode'])) $this->mode = $_POST['mode'];
+               
+               // copy
+               if (isset($_POST['languageCode'])) $this->languageCode = $_POST['languageCode'];
+               if (isset($_POST['sourceLanguageID'])) $this->sourceLanguageID = intval($_POST['sourceLanguageID']);
+               
+               // import
+               if (isset($_POST['languageFile']) && !empty($_POST['languageFile'])) {
+                       $this->languageFile = $_POST['languageFile'];
+                       $this->filename = $_POST['languageFile'];
+               }
+               if (isset($_FILES['languageUpload']) && !empty($_FILES['languageUpload']['tmp_name'])) {
+                       $this->importField = 'languageUpload';
+                       $this->filename = $_FILES['languageUpload']['tmp_name'];
+               }
+       }
+       
+       /**
+        * @see wcf\form\Form::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               if ($this->mode == 'copy') {
+                       // language code
+                       if (empty($this->languageCode)) {
+                               throw new UserInputException('languageCode');
+                       }
+                       
+                       // 
+                       if (LanguageFactory::getInstance()->getLanguageByCode($this->languageCode)) {
+                               throw new UserInputException('languageCode', 'notUnique');
+                       }
+                       
+                       // source language id
+                       if (empty($this->sourceLanguageID)) {
+                               throw new UserInputException('sourceLanguageID');
+                       }
+                       
+                       // get language
+                       $this->sourceLanguage = LanguageFactory::getInstance()->getLanguage($this->sourceLanguageID);;
+                       if (!$this->sourceLanguage->languageID) {
+                               throw new UserInputException('sourceLanguageID');
+                       }
+               }
+               else {
+                       // check file
+                       if (!file_exists($this->filename)) {
+                               throw new UserInputException('languageFile');
+                       }
+                       
+                       // try to import
+                       try {
+                               // open xml document
+                               $xml = new XML();
+                               $xml->load($this->filename);
+                               
+                               // import xml document
+                               $this->language = LanguageEditor::importFromXML($xml, PACKAGE_ID);
+                       }
+                       catch (SystemException $e) {
+                               throw new UserInputException($this->importField, $e->getMessage());
+                       }
+               }
+       }
+       
+       /**
+        * @see wcf\form\Form::save()
+        */
+       public function save() {
+               parent::save();
+               
+               if ($this->mode == 'copy') {
+                       $this->language = LanguageEditor::create(array(
+                               'languageCode' => StringUtil::toLowerCase($this->languageCode)
+                       ));
+                       $languageEditor = new LanguageEditor($this->sourceLanguage);
+                       $languageEditor->copy($this->language);
+               }
+               
+               // add language to this package
+               $sql = "SELECT  COUNT(*) AS count
+                       FROM    wcf".WCF_N."_language_to_package
+                       WHERE   languageID = ?
+                               AND packageID = ?";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array(
+                       $this->language->languageID,
+                       PACKAGE_ID
+               ));
+               
+               $row = $statement->fetchArray();
+               if (!$row['count']) {
+                       $sql = "INSERT INTO     wcf".WCF_N."_language_to_package
+                                               (languageID, packageID)
+                               VALUES          (?, ?)";
+                       $statement = WCF::getDB()->prepareStatement($sql);
+                       $statement->execute(array(
+                               $this->language->languageID,
+                               PACKAGE_ID
+                       ));
+               }
+               
+               LanguageFactory::getInstance()->clearCache();
+               
+               $this->saved();
+               
+               // show success message
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\Page::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               $this->languages = LanguageFactory::getInstance()->getLanguages();
+       }
+       
+       /**
+        * @see wcf\page\Page::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'mode' => $this->mode,
+                       'languageCode' => $this->languageCode,
+                       'sourceLanguageID' => $this->sourceLanguageID,
+                       'languages' => $this->languages,
+                       'languageFile' => $this->languageFile
+               ));
+       }
+       
+       /**
+        * @see wcf\page\Page::show()
+        */
+       public function show() {
+               // check master password
+               WCFACP::checkMasterPassword();
+               
+               parent::show();
+       }
+}
diff --git a/files/lib/acp/form/LanguageExportForm.class.php b/files/lib/acp/form/LanguageExportForm.class.php
new file mode 100644 (file)
index 0000000..dc28456
--- /dev/null
@@ -0,0 +1,169 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\language\Language;
+use wcf\data\language\LanguageEditor;
+use wcf\data\package\Package;
+use wcf\system\exception\IllegalLinkException;
+use wcf\system\language\LanguageFactory;
+use wcf\system\WCF;
+use wcf\util\ArrayUtil;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the language export form.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf.acp.language
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class LanguageExportForm extends ACPForm {
+       /**
+        * @see wcf\page\AbstractPage::$templateName
+        */
+       public $templateName = 'languageExport';
+       
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.language';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canEditLanguage');
+       
+       /**
+        * language id
+        * @var integer
+        */
+       public $languageID = 0;
+       
+       /**
+        * language editor object
+        * @var wcf\data\language\LanguageEditor
+        */
+       public $language = null;
+       
+       /**
+        * selected packages
+        * @var array<string>
+        */
+       public $selectedPackages = array();
+       
+       /**
+        * available packages
+        * @var array<string>
+        */
+       public $packages = array();
+       
+       /**
+        * true to export custom variables
+        * @var boolean
+        */
+       public $exportCustomValues = false;
+       
+       /**
+        * maximum package name length
+        * TODO: still necessary?
+        * @var integer
+        */
+       public $packageNameLength = 0;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               // get language editor object
+               if (isset($_REQUEST['id'])) $this->languageID = intval($_REQUEST['id']);
+               $language = LanguageFactory::getInstance()->getLanguage($this->languageID);
+               if ($language === null) {
+                       throw new IllegalLinkException();
+               }
+               $this->language = new LanguageEditor($language);
+       }
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               if (isset($_POST['selectedPackages']) && is_array($_POST['selectedPackages'])) {
+                       $selectedPackages = ArrayUtil::toIntegerArray($_POST['selectedPackages']);
+                       $this->selectedPackages = array_combine($selectedPackages, $selectedPackages);
+                       if (isset($this->selectedPackages[0])) unset($this->selectedPackages[0]);
+               }
+               
+               if (isset($_POST['exportCustomValues'])) {
+                       $this->exportCustomValues = intval($_POST['exportCustomValues']);
+               }
+       }
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               $this->readPackages();
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               // send headers
+               header('Content-Type: text/xml; charset=UTF-8');
+               header('Content-Disposition: attachment; filename="'.$this->language->languageCode.'.xml"');
+               $this->language->export($this->selectedPackages, $this->exportCustomValues);
+               exit;
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'languageID' => $this->languageID,
+                       'languages' => LanguageFactory::getInstance()->getLanguages(),
+                       'selectedPackages' => $this->selectedPackages,
+                       'packages' => $this->packages,
+                       'selectAllPackages' => true,
+                       'packageNameLength' => $this->packageNameLength
+               ));
+       }
+       
+       /**
+        * Read available packages.
+        */
+       protected function readPackages() {
+               $sql = "SELECT          package.*,
+                                       CASE WHEN instanceName <> '' THEN instanceName ELSE packageName END AS packageName
+                       FROM            wcf".WCF_N."_package_dependency package_dependency
+                       LEFT JOIN       wcf".WCF_N."_language_to_package language_to_package
+                       ON              (language_to_package.languageID = ? AND language_to_package.packageID = package_dependency.dependency)
+                       LEFT JOIN       wcf".WCF_N."_package package
+                       ON              (package.packageID = package_dependency.dependency)
+                       WHERE           package_dependency.packageID = ".PACKAGE_ID."
+                                       AND language_to_package.languageID IS NOT NULL
+                       ORDER BY        packageName";
+               $statement = WCF::getDB()->prepareStatement($sql);
+               $statement->execute(array($this->languageID));
+               while ($row = $statement->fetchArray()) {
+                       $row['packageNameLength'] = StringUtil::length($row['packageName']);
+                       $this->packages[] = new Package(null, $row);
+                       if ($row['packageNameLength'] > $this->packageNameLength) {
+                               $this->packageNameLength = $row['packageNameLength'];   
+                       }
+               }
+       }
+}
diff --git a/files/lib/acp/form/LanguageServerAddForm.class.php b/files/lib/acp/form/LanguageServerAddForm.class.php
new file mode 100644 (file)
index 0000000..6ed5245
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\language\server\LanguageServerAction;
+use wcf\data\package\update\server\PackageUpdateServer;
+use wcf\system\WCF;
+use wcf\system\WCFACP;
+use wcf\system\exception\UserInputException;
+use wcf\util\StringUtil;
+
+/**
+ * Shows the language server add form.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class LanguageServerAddForm extends ACPForm {
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.language.server.add';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canAddServer');
+       
+       /**
+        * server url
+        * @var string
+        */
+       public $server = '';
+       
+       /**
+        * @see wcf\form\IForm::readFormParameters()
+        */
+       public function readFormParameters() {
+               parent::readFormParameters();
+               
+               if (isset($_POST['server'])) $this->server = StringUtil::trim($_POST['server']);
+       }
+       
+       /**
+        * @see wcf\form\IForm::validate()
+        */
+       public function validate() {
+               parent::validate();
+               
+               if (empty($this->server)) {
+                       throw new UserInputException('server');
+               }
+               
+               if (!PackageUpdateServer::isValidServerURL($this->server)) {
+                       throw new UserInputException('server', 'notValid');
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               parent::save();
+               
+               // save server
+               $languageServerAction = new LanguageServerAction(array(), 'create', array('data' => array(
+                       'serverURL' => $this->server
+               )));
+               $languageServerAction->executeAction();
+               $this->saved();
+               
+               // reset values
+               $this->server = '';
+               
+               // show success message
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'server' => $this->server,
+                       'action' => 'add'
+               ));
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function show() {
+               // check master password
+               WCFACP::checkMasterPassword();
+               
+               parent::show();
+       }
+}
diff --git a/files/lib/acp/form/LanguageServerEditForm.class.php b/files/lib/acp/form/LanguageServerEditForm.class.php
new file mode 100644 (file)
index 0000000..c00819e
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+namespace wcf\acp\form;
+use wcf\data\language\server\LanguageServer;
+use wcf\data\language\server\LanguageServerAction;
+use wcf\form\AbstractForm;
+use wcf\system\WCF;
+use wcf\system\exception\IllegalLinkException;
+
+/**
+ * Shows the language server edit form.
+ *
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.form
+ * @category   Community Framework
+ */
+class LanguageServerEditForm extends LanguageServerAddForm {
+       /**
+        * @see wcf\page\AbstractPage::$templateName
+        */
+       public $templateName = 'languageServerAdd';
+       
+       /**
+        * @see wcf\acp\form\ACPForm::$activeMenuItem
+        */
+       public $activeMenuItem = 'wcf.acp.menu.link.language.server';
+       
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canAddServer');
+       
+       /**
+        * language server id
+        * @var integer
+        */
+       public $languageServerID = 0;
+       
+       /**
+        * active language server
+        * @var wcf\data\language\server\LanguageServer
+        */
+       public $languageServer = null;
+       
+       /**
+        * @see wcf\page\IPage::readParameters()
+        */
+       public function readParameters() {
+               parent::readParameters();
+               
+               if (isset($_REQUEST['id'])) $this->languageServerID = intval($_REQUEST['id']);
+               $this->languageServer = new LanguageServer($this->languageServerID);
+               if (!$this->languageServer->languageServerID) {
+                       throw new IllegalLinkException();
+               }
+       }
+       
+       /**
+        * @see wcf\form\IForm::save()
+        */
+       public function save() {
+               AbstractForm::save();
+               
+               // save server
+               $languageServerAction = new LanguageServerAction(array($this->languageServerID), 'update', array('data' => array(
+                       'serverURL' => $this->server
+               )));
+               $languageServerAction->executeAction();
+               $this->saved();
+               
+               // show success message
+               WCF::getTPL()->assign('success', true);
+       }
+       
+       /**
+        * @see wcf\page\IPage::readData()
+        */
+       public function readData() {
+               parent::readData();
+               
+               if (!count($_POST)) {
+                       $this->server = $this->languageServer->serverURL;
+               }
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+                       
+               WCF::getTPL()->assign(array(
+                       'languageServerID' => $this->languageServerID,
+                       'languageServer' => $this->languageServer,
+                       'action' => 'edit'
+               ));
+       }
+}
diff --git a/files/lib/acp/page/LanguageListPage.class.php b/files/lib/acp/page/LanguageListPage.class.php
new file mode 100644 (file)
index 0000000..45b9a77
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+namespace wcf\acp\page;
+use wcf\system\menu\acp\ACPMenu;
+use wcf\page\SortablePage;
+use wcf\system\WCF;
+
+/**
+ * Shows a list of all installed languages.
+ * 
+ * @author     Marcel Werk
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf.acp.language
+ * @subpackage acp.page
+ * @category   Community Framework
+ */
+class LanguageListPage extends SortablePage {
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canEditLanguage', 'admin.language.canDeleteLanguage');
+       
+       /**
+        * @see wcf\page\SortablePage::$defaultSortField
+        */
+       public $defaultSortField = 'languageName';
+       
+       /**
+        * @see wcf\page\SortablePage::$validSortFields
+        */
+       public $validSortFields = array('languageID', 'languageCode', 'languageName', 'users', 'variables', 'customVariables');
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::$objectListClassName
+        */     
+       public $objectListClassName = 'wcf\data\language\LanguageList';
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::initObjectList()
+        */     
+       public function initObjectList() {
+               parent::initObjectList();
+               
+               $this->objectList->sqlSelects = "(SELECT COUNT(*) FROM wcf".WCF_N."_user user WHERE languageID = language.languageID) AS users,";
+               $this->objectList->sqlSelects .= "(SELECT COUNT(*) FROM wcf".WCF_N."_language_item WHERE languageID = language.languageID) AS variables,";
+               $this->objectList->sqlSelects .= "(SELECT COUNT(*) FROM wcf".WCF_N."_language_item WHERE languageID = language.languageID AND languageCustomItemValue <> NULL) AS customVariables";
+               $this->sqlOrderBy = "cronjob.".$this->sortField." ".$this->sortOrder;
+       }
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'languages' => $this->objectList->getObjects()
+               ));
+       }
+       
+       /**
+        * @see wcf\page\IPage::show()
+        */
+       public function show() {
+               // set active menu item
+               ACPMenu::getInstance()->setActiveMenuItem('wcf.acp.menu.link.language.list');
+               
+               parent::show();
+       }
+}
diff --git a/files/lib/acp/page/LanguageServerListPage.class.php b/files/lib/acp/page/LanguageServerListPage.class.php
new file mode 100644 (file)
index 0000000..64b4728
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+namespace wcf\acp\page;
+use wcf\page\SortablePage;
+use wcf\system\menu\acp\ACPMenu;
+use wcf\system\WCF;
+
+/**
+ * Shows information about available language servers.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2012 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package    com.woltlab.wcf
+ * @subpackage acp.page
+ * @category   Community Framework
+ */
+class LanguageServerListPage extends SortablePage {
+       /**
+        * @see wcf\page\AbstractPage::$neededPermissions
+        */
+       public $neededPermissions = array('admin.language.canEditServer', 'admin.language.canDeleteServer');
+       
+       /**
+        * @see wcf\page\SortablePage::$defaultSortField
+        */
+       public $defaultSortField = 'serverURL';
+       
+       /**
+        * @see wcf\page\SortablePage::$validSortFields
+        */
+       public $validSortFields = array('languageServerID', 'serverURL');
+       
+       /**
+        * @see wcf\page\MultipleLinkPage::$objectListClassName
+        */     
+       public $objectListClassName = 'wcf\data\language\server\LanguageServerList';
+       
+       /**
+        * @see wcf\page\IPage::assignVariables()
+        */
+       public function assignVariables() {
+               parent::assignVariables();
+               
+               WCF::getTPL()->assign(array(
+                       'languageServers' => $this->objectList->getObjects()
+               ));
+       }
+       
+       /**
+        * @see wcf\page\IPage::show()
+        */
+       public function show() {
+               // enable menu item
+               ACPMenu::getInstance()->setActiveMenuItem('wcf.acp.menu.link.language.server.list');
+               
+               parent::show();
+       }
+}
diff --git a/language/de.xml b/language/de.xml
new file mode 100644 (file)
index 0000000..08eaf3b
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<language xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/language.xsd" languagecode="de">
+       <category name="wcf.acp.menu">
+               <item name="wcf.acp.menu.link.language"><![CDATA[Sprachen]]></item>
+               <item name="wcf.acp.menu.link.language.add"><![CDATA[Sprache hinzufügen]]></item>
+               <item name="wcf.acp.menu.link.language.list"><![CDATA[Sprachen auflisten]]></item>
+               <item name="wcf.acp.menu.link.language.server.add"><![CDATA[Server hinzufügen]]></item>
+               <item name="wcf.acp.menu.link.language.server.list"><![CDATA[Server auflisten]]></item>
+       </category>
+       
+       <category name="wcf.acp.language">
+               <item name="wcf.acp.language.list"><![CDATA[Sprachen]]></item>
+               <item name="wcf.acp.language.list.count"><![CDATA[{#$items} Sprache{if $items != 1}n{/if}]]></item>
+               <item name="wcf.acp.language.name"><![CDATA[Name]]></item>
+               <item name="wcf.acp.language.users"><![CDATA[Verwendet von]]></item>
+               <item name="wcf.acp.language.variables"><![CDATA[Variablen]]></item>
+               <item name="wcf.acp.language.customVariables"><![CDATA[Veränderte Variablen]]></item>
+               <item name="wcf.acp.language.export"><![CDATA[Sprache exportieren]]></item>
+               <item name="wcf.acp.language.setAsDefault"><![CDATA[Zur Standardsprache machen]]></item>
+               <item name="wcf.acp.language.add"><![CDATA[Sprache hinzufügen]]></item>
+               <item name="wcf.acp.language.edit"><![CDATA[Sprache bearbeiten]]></item>
+               <item name="wcf.acp.language.add.languageCode.error.notUnique"><![CDATA[Dieser Sprachcode wird bereits von einer anderen im System installierten Sprache verwendet.]]></item>
+               <item name="wcf.acp.language.add.mode"><![CDATA[Sprache erstellen durch]]></item>
+               <item name="wcf.acp.language.add.mode.copy"><![CDATA[Übersetzen einer vorhandenen Sprache]]></item>
+               <item name="wcf.acp.language.add.mode.import"><![CDATA[Importieren einer Sprachdatei]]></item>
+               <item name="wcf.acp.language.add.new"><![CDATA[Neue Sprache]]></item>
+               <item name="wcf.acp.language.add.source"><![CDATA[Zu übersetzende Sprache]]></item>
+               <item name="wcf.acp.language.code"><![CDATA[Sprachcode]]></item>
+               <item name="wcf.acp.language.code.description"><![CDATA[Geben Sie hier den passenden Sprachcode nach <strong>ISO 639-1</strong> an. Weitere Informationen zu Sprachcodes finden Sie unter <a href="http://de.wikipedia.org/wiki/ISO_639-1" class="externalURL">http://de.wikipedia.org/wiki/ISO_639-1</a>.]]></item>
+               <item name="wcf.acp.language.delete.sure"><![CDATA[Wollen Sie die Sprache &raquo;{$language->languageName}&laquo; wirklich löschen?]]></item>
+               <item name="wcf.acp.language.export.allPackages"><![CDATA[Alle Pakete]]></item>
+               <item name="wcf.acp.language.export.customValues"><![CDATA[Veränderte Variablen exportieren]]></item>
+               <item name="wcf.acp.language.export.selectPackages"><![CDATA[Pakete auswählen]]></item>
+               <item name="wcf.acp.language.import.error"><![CDATA[Beim Importieren der Sprachdatei ist folgender Fehler aufgetreten:]]></item>
+               <item name="wcf.acp.language.import.source"><![CDATA[Quelle]]></item>
+               <item name="wcf.acp.language.import.source.file"><![CDATA[Pfad zur Sprachdatei]]></item>
+               <item name="wcf.acp.language.import.source.file.description"><![CDATA[Geben Sie hier den relativen Pfad zu einer gültigen XML-Sprachdatei an.]]></item>
+               <item name="wcf.acp.language.import.source.upload"><![CDATA[Sprachdatei vom lokalen Computer hochladen]]></item>
+       </category>
+</language>
\ No newline at end of file
diff --git a/package.xml b/package.xml
new file mode 100644 (file)
index 0000000..59d48c8
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package name="com.woltlab.wcf.acp.language" xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/package.xsd">
+       <packageinformation>
+               <packagename>Language Administration</packagename>
+               <packagedescription>Comprehensive language manager</packagedescription>
+               <version>1.0.0 Alpha 1</version>
+               <date>2011-06-30</date>
+       </packageinformation>
+       
+       <authorinformation>
+               <author>WoltLab GmbH</author>
+               <authorurl>http://www.woltlab.com</authorurl>
+       </authorinformation>
+       
+       <requiredpackages>
+               <requiredpackage minversion="2.0.0 Alpha 1">com.woltlab.wcf</requiredpackage>
+       </requiredpackages>
+       
+       <instructions type="install">
+               <instruction type="acpMenu">acpmenu.xml</instruction>
+               <instruction type="acpTemplate">acptemplates.tar</instruction>
+               <instruction type="file">files.tar</instruction>
+               <instruction type="userGroupOption">usergroupoption.xml</instruction>
+               <instruction type="language">language/*.xml</instruction>
+       </instructions>
+</package>
diff --git a/usergroupoption.xml b/usergroupoption.xml
new file mode 100644 (file)
index 0000000..16f85e2
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/usergroupoptions.xsd">
+       <import>
+               <options>
+                       <option name="admin.language.canAddLanguage">
+                               <categoryname>admin.language</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
+                       
+                       <option name="admin.language.canEditLanguage">
+                               <categoryname>admin.language</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
+                       
+                       <option name="admin.language.canDeleteLanguage">
+                               <categoryname>admin.language</categoryname>
+                               <optiontype>boolean</optiontype>
+                               <defaultvalue>0</defaultvalue>
+                               <admindefaultvalue>1</admindefaultvalue>
+                       </option>
+               </options>
+       </import>
+</data>