Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2008-12-26 17:37:46 +0300
committermatt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105>2008-12-26 17:37:46 +0300
commitd389561c0ccb76536d18239c9b7f81cce3d02fc1 (patch)
tree2bac760977afe8e7f3ae7890d7cd286e37109d88
parent47f4495a2adba4cbce5d1c3d3510ce26f8650f69 (diff)
parentb86d75c79c557a7c89899939055ee7306f40d28a (diff)
-rwxr-xr-xconfig/global.ini.php20
-rw-r--r--core/API/APIable.php54
-rw-r--r--core/API/DataTableGenericFilter.php133
-rw-r--r--core/API/DocumentationGenerator.php181
-rw-r--r--core/API/Proxy.php413
-rw-r--r--core/API/Request.php53
-rw-r--r--core/API/ResponseBuilder.php140
-rw-r--r--core/Access.php14
-rw-r--r--core/Archive.php486
-rw-r--r--core/Archive/Single.php3
-rw-r--r--core/ArchiveProcessing.php26
-rw-r--r--core/ArchiveProcessing/Day.php207
-rw-r--r--core/ArchiveProcessing/Period.php46
-rw-r--r--core/ArchiveProcessing/Record/BlobArray.php4
-rw-r--r--core/CacheFile.php114
-rw-r--r--core/Common.php137
-rw-r--r--core/Controller.php13
-rw-r--r--core/Cookie.php3
-rw-r--r--core/DataFiles/SearchEngines.php5
-rw-r--r--core/DataTable.php31
-rw-r--r--core/DataTable/Filter.php3
-rw-r--r--core/DataTable/Filter/AddColumnsWhenShowAllColumns.php3
-rw-r--r--core/DataTable/Filter/AddSummaryRow.php3
-rw-r--r--core/DataTable/Filter/ExactMatch.php104
-rw-r--r--core/DataTable/Filter/ExcludeLowPopulation.php20
-rw-r--r--core/DataTable/Filter/Limit.php7
-rw-r--r--core/DataTable/Filter/Pattern.php15
-rw-r--r--core/DataTable/Filter/PatternRecursive.php5
-rw-r--r--core/DataTable/Filter/ReplaceColumnNames.php31
-rw-r--r--core/DataTable/Filter/Sort.php56
-rw-r--r--core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php115
-rw-r--r--core/DataTable/Manager.php39
-rw-r--r--core/DataTable/Renderer/Console.php7
-rw-r--r--core/DataTable/Renderer/Csv.php21
-rw-r--r--core/DataTable/Renderer/Php.php2
-rw-r--r--core/DataTable/Renderer/Rss.php16
-rw-r--r--core/DataTable/Renderer/Xml.php19
-rw-r--r--core/DataTable/Row.php58
-rw-r--r--core/Date.php22
-rw-r--r--core/FrontController.php5
-rw-r--r--core/Log.php2
-rw-r--r--core/Period/Range.php1
-rw-r--r--core/Piwik.php157
-rw-r--r--core/Plugin.php9
-rw-r--r--core/PluginsManager.php4
-rw-r--r--core/SmartyPlugins/function.logoHtml.php32
-rw-r--r--core/SmartyPlugins/function.url.php62
-rw-r--r--core/Timer.php38
-rw-r--r--core/Tracker.php51
-rw-r--r--core/Tracker/Action.php136
-rw-r--r--core/Tracker/Db.php21
-rw-r--r--core/Tracker/Generator.php3
-rw-r--r--core/Tracker/Generator/Tracker.php1
-rw-r--r--core/Tracker/Generator/Visit.php6
-rw-r--r--core/Tracker/GoalManager.php189
-rw-r--r--core/Tracker/Visit.php480
-rw-r--r--core/Updates/0.2.27.php18
-rw-r--r--core/Version.php4
-rw-r--r--core/View.php2
-rw-r--r--core/ViewDataTable.php150
-rw-r--r--core/ViewDataTable/Cloud.php6
-rw-r--r--core/ViewDataTable/GenerateGraphData/ChartEvolution.php384
-rw-r--r--core/ViewDataTable/GenerateGraphHTML.php14
-rw-r--r--core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php26
-rw-r--r--core/ViewDataTable/HtmlTable.php37
-rw-r--r--core/ViewDataTable/HtmlTable/AllColumns.php21
-rw-r--r--core/ViewDataTable/HtmlTable/Goals.php82
-rw-r--r--core/ViewDataTable/Sparkline.php21
-rw-r--r--core/Visualization/ChartEvolution.php152
-rw-r--r--core/iView.php2
-rw-r--r--lang/ca.php1219
-rw-r--r--lang/en.php1
-rw-r--r--lang/fr.php448
-rw-r--r--lang/no.php615
-rw-r--r--lang/pt.php2
-rw-r--r--lang/sk.php618
-rw-r--r--lang/sr.php615
-rw-r--r--lang/sv.php609
-rw-r--r--lang/tw.php20
-rw-r--r--misc/TODO107
-rw-r--r--misc/generateVisits.php8
-rw-r--r--misc/iframeWidget.htm8
-rw-r--r--misc/iframeWidget_localhost.htm7
-rw-r--r--misc/testJavascriptTracker/index.php2
-rw-r--r--piwik.php3
-rw-r--r--plugins/API/Controller.php31
-rw-r--r--plugins/Actions/API.php2
-rw-r--r--plugins/Actions/Actions.php607
-rw-r--r--plugins/Actions/Controller.php16
-rw-r--r--plugins/CoreAdminHome/templates/header.tpl1
-rw-r--r--plugins/CoreAdminHome/templates/styles.css10
-rw-r--r--plugins/CoreHome/Controller.php115
-rw-r--r--plugins/CoreHome/templates/calendar.js2
-rw-r--r--plugins/CoreHome/templates/cloud.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable.css14
-rw-r--r--plugins/CoreHome/templates/datatable.js49
-rw-r--r--plugins/CoreHome/templates/datatable.tpl10
-rw-r--r--plugins/CoreHome/templates/datatable_actions.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_actions_js.tpl6
-rw-r--r--plugins/CoreHome/templates/datatable_actions_recursive.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_actions_subdatable.tpl2
-rw-r--r--plugins/CoreHome/templates/datatable_footer.tpl16
-rw-r--r--plugins/CoreHome/templates/datatable_js.tpl6
-rw-r--r--plugins/CoreHome/templates/graph.tpl2
-rw-r--r--plugins/DBStats/API.php48
-rw-r--r--plugins/DBStats/templates/DBStats.tpl6
-rw-r--r--plugins/ExampleAPI/API.php3
-rw-r--r--plugins/ExamplePlugin/ExamplePlugin.php18
-rw-r--r--plugins/Goals/API.php227
-rw-r--r--plugins/Goals/Controller.php150
-rw-r--r--plugins/Goals/Goals.php206
-rw-r--r--plugins/Goals/templates/GoalForm.js124
-rw-r--r--plugins/Goals/templates/add_edit_goal.tpl49
-rw-r--r--plugins/Goals/templates/add_new_goal.tpl8
-rw-r--r--plugins/Goals/templates/form_add_goal.tpl67
-rw-r--r--plugins/Goals/templates/list_goal_edit.tpl22
-rw-r--r--plugins/Goals/templates/list_top_segment.tpl5
-rw-r--r--plugins/Goals/templates/overview.tpl27
-rw-r--r--plugins/Goals/templates/release_notes.tpl20
-rw-r--r--plugins/Goals/templates/single_goal.tpl37
-rw-r--r--plugins/Goals/templates/title_and_evolution_graph.tpl20
-rw-r--r--plugins/Installation/Controller.php952
-rw-r--r--plugins/Installation/templates/firstWebsiteSetup.tpl3
-rw-r--r--plugins/LanguagesManager/API.php2
-rw-r--r--plugins/Live/API.php143
-rw-r--r--plugins/Live/Controller.php37
-rw-r--r--plugins/Live/Live.php14
-rw-r--r--plugins/Live/Visitor.php262
-rw-r--r--plugins/Live/templates/images/pause.gifbin0 -> 669 bytes
-rw-r--r--plugins/Live/templates/images/pause_disabled.gifbin0 -> 619 bytes
-rw-r--r--plugins/Live/templates/images/play.gifbin0 -> 666 bytes
-rw-r--r--plugins/Live/templates/images/play_disabled.gifbin0 -> 407 bytes
-rw-r--r--plugins/Live/templates/images/returningVisitor.gifbin0 -> 995 bytes
-rw-r--r--plugins/Live/templates/index.tpl83
-rw-r--r--plugins/Live/templates/lastVisits.tpl15
-rw-r--r--plugins/Live/templates/scripts/spy.js139
-rw-r--r--plugins/Login/Controller.php129
-rw-r--r--plugins/Login/templates/login.tpl2
-rw-r--r--plugins/Provider/API.php15
-rw-r--r--plugins/Provider/Controller.php6
-rw-r--r--plugins/Provider/Provider.php3
-rw-r--r--plugins/Referers/API.php6
-rw-r--r--plugins/Referers/Controller.php72
-rw-r--r--plugins/Referers/Referers.php238
-rw-r--r--plugins/Referers/functions.php3
-rw-r--r--plugins/Referers/templates/index.tpl (renamed from plugins/Referers/index.tpl)0
-rw-r--r--plugins/Referers/templates/searchEngines_Keywords.tpl (renamed from plugins/Referers/searchEngines_Keywords.tpl)0
-rwxr-xr-xplugins/SitesManager/API.php4
-rw-r--r--plugins/SitesManager/templates/SitesManager.js16
-rw-r--r--plugins/UserCountry/API.php2
-rw-r--r--plugins/UserCountry/Controller.php28
-rw-r--r--plugins/UserCountry/UserCountry.php43
-rw-r--r--plugins/UserSettings/API.php2
-rw-r--r--plugins/UserSettings/UserSettings.php16
-rwxr-xr-xplugins/UsersManager/API.php4
-rw-r--r--plugins/UsersManager/templates/UsersManager.js2
-rw-r--r--plugins/VisitFrequency/API.php8
-rw-r--r--plugins/VisitFrequency/Controller.php3
-rw-r--r--plugins/VisitFrequency/VisitFrequency.php5
-rw-r--r--plugins/VisitTime/API.php2
-rw-r--r--plugins/VisitTime/Controller.php1
-rw-r--r--plugins/VisitTime/VisitTime.php47
-rw-r--r--plugins/VisitorInterest/API.php2
-rw-r--r--plugins/VisitsSummary/API.php8
-rw-r--r--tests/build-canoo.xml15
-rw-r--r--tests/build.sample.properties5
-rw-r--r--tests/build.xml74
-rwxr-xr-xtests/config_test.php1
-rw-r--r--tests/core/DataTable.test.php18
-rw-r--r--tests/core/DataTable/Renderer.test.php22
-rw-r--r--tests/core/PHP_Related.test.php47
-rw-r--r--tests/core/Piwik.test.php5
-rw-r--r--tests/core/ReleaseCheckList.test.php27
-rw-r--r--tests/datasets/referer-xss.txt7
-rw-r--r--tests/defaults.properties2
-rw-r--r--tests/lib/java/mysql-connector-java-5.1.7.jarbin0 -> 709922 bytes
-rw-r--r--tests/lib/java/schemaSpy_3.1.1.jarbin0 -> 150445 bytes
-rw-r--r--tests/webtest/config/webtest.example.properties44
-rw-r--r--tests/webtest/test_suite.xml50
-rw-r--r--tests/webtest/testcases/level0/test.piwik.index.xml194
-rw-r--r--tests/webtest/testcases/modules/common_pages.xml8
-rw-r--r--tests/webtest/testcases/modules/errors.xml6
-rw-r--r--tests/webtest/testcases/modules/time.xml15
-rw-r--r--themes/default/common.css59
-rw-r--r--themes/default/common.js1
-rwxr-xr-xthemes/default/genericForm.tpl2
-rw-r--r--themes/default/images/feed.pngbin0 -> 691 bytes
-rw-r--r--themes/default/images/goal.pngbin0 -> 672 bytes
188 files changed, 9932 insertions, 3946 deletions
diff --git a/config/global.ini.php b/config/global.ini.php
index 0b713b7d8a..4cf9ad1006 100755
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -61,7 +61,6 @@ PluginsInstalled[] = Installation
[Plugins_Tracker]
-
[Debug]
; if set to true, the archiving process will always be triggered, even if the archive has already been computed
; this is useful when making changes to the archiving code so we can force the archiving process
@@ -81,6 +80,12 @@ time_before_archive_considered_outdated = 10
; Possible values: yesterday, today, or any YYYY-MM-DD
default_day = yesterday
+; When loading piwik interface, Piwik will load by default the CoreHome module
+; You can override the setting to force the user to login.
+; This is useful when you have some websites view "anonymous" access but you want to
+; force users to login instead of viewing the first anonymous website available
+default_module_login = false
+
; When loading the piwik interface in the browser (as opposed to from the PHP-CLI client)
; should we launch the archiving process if the archives have not yet been processed?
; You want to set it to false when triggering the archiving is done through a crontab,
@@ -92,6 +97,9 @@ enable_browser_archiving_triggering = true
; the page first-post in the subcategory development which belongs to the blog category
action_category_delimiter = /
+; currency used by default when reporting money in Piwik
+default_currency = "$"
+
; if you want all your users to use Piwik in only one language, disable the LanguagesManager
; plugin, and set this default_language (users won't see the language drop down)
default_language = en
@@ -146,6 +154,16 @@ campaign_keyword_var_name = piwik_kwd
; name of the cookie used to store the visitor information
cookie_name = piwik_visitor
+; if set to false, any goal conversion will be credited to the last more recent non empty referer.
+; when set to true, the first ever referer used to reach the website will be used
+use_first_referer_to_determine_goal_referer = false
+
+; if set to true, Piwik will try to match visitors without cookie to a previous visitor that has the same
+; configuration: OS, browser, resolution, IP, etc. This heuristic adds an extra SQL query for each page view without cookie.
+; it is advised to set it to true for more accurate detection of unique visitors.
+; However when most users have the same IP, and the same configuration, it is advised to set it to false
+enable_detect_unique_visitor_using_settings = false
+
[log]
;possible values for log: screen, database, file
diff --git a/core/API/APIable.php b/core/API/APIable.php
deleted file mode 100644
index c05f47d3d2..0000000000
--- a/core/API/APIable.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: APIable.php 482 2008-05-18 17:22:35Z matt $
- *
- * @package Piwik_API
- */
-require_once 'Archive.php';
-
-/**
- * This class is the parent class of all the plugins that can be called using the API Proxy.
- * For example a plugin "Provider" can publish its API by creating a file plugins/Provider/API.php
- * that is extending this Piwik_Apiable class.
- * All the Piwik_Apiable classes are read and loaded by the Piwik_API_Proxy class.
- * The public methods of this class are published in the API and are then callable using the API module.
- * The parameters of the function are read directly from the GET request (they must have the same name).
- *
- * For example
- * public function helloWorld($text) { return "hello " . $text; }
- * call be called using
- * ?module=API&method=PluginName.helloWorld&text=world!
- *
- * See the documentation on http://dev.piwik.org > API
- *
- * @package Piwik_API
- * @see Piwik_API_Proxy
- */
-
-abstract class Piwik_Apiable
-{
- /**
- * This array contains the name of the methods of the class we don't want to publish in the API.
- * By default only public methods are published. Names of public methods in this array won't be published.
- *
- * @var array of strings
- */
- static public $methodsNotToPublish = array();
-
- /**
- * @see self::$methodsNotToPublish
- * @param string Method name not to be published
- */
- protected function doNotPublishMethod( $methodName )
- {
- if(!method_exists($this, $methodName))
- {
- throw new Exception("The method $methodName doesn't exist so it can't be added to the list of the methods not to be published in the API.");
- }
- $this->methodsNotToPublish[] = $methodName;
- }
-}
diff --git a/core/API/DataTableGenericFilter.php b/core/API/DataTableGenericFilter.php
new file mode 100644
index 0000000000..c9be367136
--- /dev/null
+++ b/core/API/DataTableGenericFilter.php
@@ -0,0 +1,133 @@
+<?php
+
+class Piwik_API_DataTableGenericFilter
+{
+ function __construct( $datatable, $request )
+ {
+ $this->table = $datatable;
+ $this->request = $request;
+ }
+
+ public function filter()
+ {
+ $this->applyGenericFilters($this->table);
+ }
+
+ /**
+ * Returns an array containing the information of the generic Piwik_DataTable_Filter
+ * to be applied automatically to the data resulting from the API calls.
+ *
+ * Order to apply the filters:
+ * 1 - Filter that remove filtered rows
+ * 2 - Filter that sort the remaining rows
+ * 3 - Filter that keep only a subset of the results
+ * 4 - Presentation filters
+ *
+ * @return array See the code for spec
+ */
+ public static function getGenericFiltersInformation()
+ {
+ $genericFilters = array(
+ 'Pattern' => array(
+ 'filter_column' => array('string'),
+ 'filter_pattern' => array('string'),
+ ),
+ 'PatternRecursive' => array(
+ 'filter_column_recursive' => array('string'),
+ 'filter_pattern_recursive' => array('string'),
+ ),
+ 'ExactMatch' => array(
+ 'filter_exact_column' => array('string'),
+ 'filter_exact_pattern' => array('array'),
+ ),
+ 'ExcludeLowPopulation' => array(
+ 'filter_excludelowpop' => array('string'),
+ 'filter_excludelowpop_value'=> array('float', '0'),
+ ),
+ 'AddColumnsWhenShowAllColumns' => array(
+ 'filter_add_columns_when_show_all_columns' => array('integer')
+ ),
+ 'UpdateColumnsWhenShowAllGoals' => array(
+ 'filter_update_columns_when_show_all_goals' => array('integer')
+ ),
+ 'Sort' => array(
+ 'filter_sort_column' => array('string', Piwik_Archive::INDEX_NB_VISITS),
+ 'filter_sort_order' => array('string', Zend_Registry::get('config')->General->dataTable_default_sort_order),
+ ),
+ 'Limit' => array(
+ 'filter_offset' => array('integer', '0'),
+ 'filter_limit' => array('integer', Zend_Registry::get('config')->General->dataTable_default_limit),
+ ),
+ 'SafeDecodeLabel' => array(),
+ );
+
+ return $genericFilters;
+ }
+
+ /**
+ * Apply generic filters to the DataTable object resulting from the API Call.
+ * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request.
+ *
+ * @param Piwik_DataTable
+ * @return void
+ */
+ protected function applyGenericFilters($datatable)
+ {
+ if($datatable instanceof Piwik_DataTable_Array )
+ {
+ $tables = $datatable->getArray();
+ foreach($tables as $table)
+ {
+ $this->applyGenericFilters($table);
+ }
+ return;
+ }
+
+ $genericFilters = self::getGenericFiltersInformation();
+
+ foreach($genericFilters as $filterName => $parameters)
+ {
+ $filterParameters = array();
+ $exceptionRaised = false;
+ foreach($parameters as $name => $info)
+ {
+ // parameter type to cast to
+ $type = $info[0];
+
+ // default value if specified, when the parameter doesn't have a value
+ $defaultValue = null;
+ if(isset($info[1]))
+ {
+ $defaultValue = $info[1];
+ }
+
+ try {
+ $value = Piwik_Common::getRequestVar($name, $defaultValue, $type, $this->request);
+ settype($value, $type);
+ $filterParameters[] = $value;
+ }
+ catch(Exception $e)
+ {
+ $exceptionRaised = true;
+ break;
+ }
+ }
+
+ if(!$exceptionRaised)
+ {
+ // a generic filter class name must follow this pattern
+ $class = "Piwik_DataTable_Filter_".$filterName;
+ if($filterName == 'Limit')
+ {
+ $datatable->setRowsCountBeforeLimitFilter();
+ }
+ // build the set of parameters for the filter
+ $filterParameters = array_merge(array($datatable), $filterParameters);
+ // use Reflection to create a new instance of the filter, given parameters $filterParameters
+ $reflectionObj = new ReflectionClass($class);
+ $filter = $reflectionObj->newInstanceArgs($filterParameters);
+ }
+ }
+ }
+}
+
diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php
new file mode 100644
index 0000000000..fb64d1a117
--- /dev/null
+++ b/core/API/DocumentationGenerator.php
@@ -0,0 +1,181 @@
+<?php
+
+class Piwik_API_DocumentationGenerator
+{
+ protected $countPluginsLoaded = 0;
+
+ /**
+ * trigger loading all plugins with an API.php file in the Proxy
+ */
+ public function __construct()
+ {
+ $plugins = Piwik_PluginsManager::getInstance()->getLoadedPluginsName();
+ foreach( $plugins as $plugin )
+ {
+ $plugin = Piwik::unprefixClass($plugin);
+ try {
+ Piwik_API_Proxy::getInstance()->registerClass("Piwik_".$plugin."_API");
+ }
+ catch(Exception $e){
+ }
+ }
+ }
+
+ /**
+ * Returns a HTML page containing help for all the successfully loaded APIs.
+ * For each module it will return a mini help with the method names, parameters to give,
+ * links to get the result in Xml/Csv/etc
+ *
+ * @return string
+ */
+ public function getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = '' )
+ {
+ $str = '';
+ $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth();
+ $parametersToSet = array(
+ 'idSite' => Piwik_Common::getRequestVar('idSite', 1, 'int'),
+ 'period' => Piwik_Common::getRequestVar('period', 'day', 'string'),
+ 'date' => Piwik_Common::getRequestVar('date', 'today', 'string')
+ );
+
+ foreach(Piwik_API_Proxy::getInstance()->getMetadata() as $class => $info)
+ {
+ $moduleName = Piwik_API_Proxy::getInstance()->getModuleNameFromClassName($class);
+ $str .= "\n<h2 id='$moduleName'>Module ".$moduleName."</h2>";
+
+ foreach($info as $methodName => $infoMethod)
+ {
+ $params = $this->getStrListParameters($class, $methodName);
+ $str .= "\n" . "- <b>$moduleName.$methodName " . $params . "</b>";
+ $str .= '<small>';
+
+ if($outputExampleUrls)
+ {
+ // we prefix all URLs with $prefixUrls
+ // used when we include this output in the Piwik official documentation for example
+ $str .= "<span class=\"example\">";
+ $exampleUrl = $this->getExampleUrl($class, $methodName, $parametersToSet);
+ if($exampleUrl !== false)
+ {
+ $lastNUrls = '';
+ if( ereg('(&period)|(&date)',$exampleUrl))
+ {
+ $exampleUrlRss1 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last10')) ;
+ $exampleUrlRss2 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last5','period' => 'week',));
+ $lastNUrls = ", RSS of the last <a target=_blank href='$exampleUrlRss1&format=rss$token_auth'>10 days</a>, <a target=_blank href='$exampleUrlRss2&format=Rss'>5 weeks</a>,
+ XML of the <a target=_blank href='$exampleUrlRss1&format=xml$token_auth'>last 10 days</a>";
+ }
+ $exampleUrl = $prefixUrls . $exampleUrl ;
+ $str .= " [ Example in
+ <a target=_blank href='$exampleUrl&format=xml$token_auth'>XML</a>,
+ <a target=_blank href='$exampleUrl&format=PHP&prettyDisplay=true$token_auth'>PHP</a>,
+ <a target=_blank href='$exampleUrl&format=JSON$token_auth'>Json</a>,
+ <a target=_blank href='$exampleUrl&format=Csv$token_auth'>Csv</a>,
+ <a target=_blank href='$exampleUrl&format=Html$token_auth'>Basic html</a>
+ $lastNUrls
+ ]";
+ }
+ else
+ {
+ $str .= " [ No example available ]";
+ }
+ $str .= "</span>";
+ }
+ $str .= '</small>';
+ $str .= "\n<br>";
+ }
+ }
+ return $str;
+ }
+
+ /**
+ * Returns a string containing links to examples on how to call a given method on a given API
+ * It will export links to XML, CSV, HTML, JSON, PHP, etc.
+ * It will not export links for methods such as deleteSite or deleteUser
+ *
+ * @param string the class
+ * @param methodName the method
+ * @return string|false when not possible
+ */
+ protected function getExampleUrl($class, $methodName, $parametersToSet = array())
+ {
+ $knowExampleDefaultParametersValues = array(
+ 'access' => 'view',
+ 'userLogin' => 'test',
+ 'password' => 'passwordExample',
+ 'passwordMd5ied' => 'passwordExample',
+ 'email' => 'test@example.org',
+
+ 'siteName' => 'new example website',
+ 'urls' => 'http://example.org', // used in addSite, updateSite
+
+ 'languageCode' => 'fr',
+ );
+
+ foreach($parametersToSet as $name => $value)
+ {
+ $knowExampleDefaultParametersValues[$name] = $value;
+ }
+
+ // no links for these method names
+ $doNotPrintExampleForTheseMethods = array(
+ 'deleteSite',
+ 'deleteUser',
+ );
+
+ if(in_array($methodName,$doNotPrintExampleForTheseMethods))
+ {
+ return false;
+ }
+
+ // we try to give an URL example to call the API
+ $aParameters = Piwik_API_Proxy::getInstance()->getParametersList($class, $methodName);
+ $moduleName = Piwik_API_Proxy::getInstance()->getModuleNameFromClassName($class);
+ $urlExample = '?module=API&method='.$moduleName.'.'.$methodName.'&';
+ foreach($aParameters as $nameVariable=> $defaultValue)
+ {
+ // if there isn't a default value for a given parameter,
+ // we need a 'know default value' or we can't generate the link
+ if($defaultValue === Piwik_API_Proxy::NO_DEFAULT_VALUE)
+ {
+ if(isset($knowExampleDefaultParametersValues[$nameVariable]))
+ {
+ $exampleValue = $knowExampleDefaultParametersValues[$nameVariable];
+ $urlExample .= $nameVariable . '=' . $exampleValue . '&';
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return substr($urlExample,0,-1);
+ }
+
+
+ /**
+ * Returns the methods $class.$name parameters (and default value if provided) as a string.
+ *
+ * @param string The class name
+ * @param string The method name
+ * @return string For example "(idSite, period, date = 'today')"
+ */
+ protected function getStrListParameters($class, $name)
+ {
+ $aParameters = Piwik_API_Proxy::getInstance()->getParametersList($class, $name);
+ $asParameters = array();
+ foreach($aParameters as $nameVariable=> $defaultValue)
+ {
+ $str = $nameVariable;
+ if($defaultValue !== Piwik_API_Proxy::NO_DEFAULT_VALUE)
+ {
+ $str .= " = '$defaultValue'";
+ }
+ $asParameters[] = $str;
+ }
+ $sParameters = implode(", ", $asParameters);
+ return "($sParameters)";
+ }
+
+}
diff --git a/core/API/Proxy.php b/core/API/Proxy.php
index 41f7191b4c..d9f3e91008 100644
--- a/core/API/Proxy.php
+++ b/core/API/Proxy.php
@@ -11,31 +11,27 @@
/**
- * The API Proxy receives all the API calls requests and forwards them to the given module.
- *
- * It registers all the APIable plugins (@see Piwik_Apiable)
- * The class checks that a call to the API has the correct number of parameters.
- * The proxy is a singleton that has the knowledge of every method available, their parameters and default values.
+ * Proxy is a singleton that has the knowledge of every method available, their parameters
+ * and default values.
+ * Proxy receives all the API calls requests via call() and forwards them to the right
+ * object, with the parameters in the right order.
*
- * It can also log the performances of the API calls (time spent, parameter values, etc.)
+ * It will also log the performance of API calls (time spent, parameter values, etc.) if logger available
*
* @package Piwik_API
*/
class Piwik_API_Proxy
{
- static $classCalled = null;
-
// array of already registered plugins names
protected $alreadyRegistered = array();
- private $api = array();
+ private $metadataArray = array();
// when a parameter doesn't have a default value we use this constant
const NO_DEFAULT_VALUE = null;
static private $instance = null;
- protected function __construct()
- {}
+ protected function __construct() {}
/**
* Singleton, returns instance
@@ -53,90 +49,75 @@ class Piwik_API_Proxy
}
/**
+ * Returns array containing reflection meta data for all the loaded classes
+ * eg. number of parameters, method names, etc.
+ *
+ * @return array
+ */
+ public function getMetadata()
+ {
+ return $this->metadataArray;
+ }
+
+ /**
* Registers the API information of a given module.
*
* The module to be registered must be
- * - extending the Piwik_Apiable class
* - a singleton (providing a getInstance() method)
* - the API file must be located in plugins/ModuleName/API.php
* for example plugins/Referers/API.php
*
* The method will introspect the methods, their parameters, etc.
*
- * @param string ModuleName eg. "UserSettings"
+ * @param string ModuleName eg. "Piwik_UserSettings_API"
*/
- public function registerClass( $moduleName )
+ public function registerClass( $className )
{
- if(isset($this->alreadyRegistered[$moduleName]))
+ if(isset($this->alreadyRegistered[$className]))
{
return;
}
-
- $this->includeApiFile($moduleName);
- $class = $this->getClassNameFromModule($moduleName);
+ $this->includeApiFile( $className );
+ $this->checkClassIsSingleton($className);
- $rClass = new ReflectionClass($class);
- if(!$rClass->isSubclassOf(new ReflectionClass("Piwik_Apiable")))
- {
- throw new Exception("To publish its public methods in the API, the class '$class' must be a subclass of 'Piwik_Apiable'.");
- }
-
- $this->checkClassIsSingleton($class);
-
+ $rClass = new ReflectionClass($className);
foreach($rClass->getMethods() as $method)
{
- $this->loadMethodMetadata($class, $method);
+ $this->loadMethodMetadata($className, $method);
}
- $this->alreadyRegistered[$moduleName] = true;
+ $this->alreadyRegistered[$className] = true;
}
-
/**
- * Checks that the method exists in the class
- *
- * @param string The class name
- * @param string The method name
- * @throws exception If the method is not found
- */
- public function checkMethodExists($className, $methodName)
- {
- if(!$this->isMethodAvailable($className, $methodName))
- {
- throw new Exception("The method '$methodName' does not exist or is not available in the module '".$className."'.");
- }
- }
-
- /**
- * Magic method used to set a flag telling the module named currently being called
- *
+ * Returns number of classes already loaded
+ * @return int
*/
- public function __get($name)
+ public function getCountRegisteredClasses()
{
- self::$classCalled = $name;
- return $this;
- }
+ return count($this->alreadyRegistered);
+ }
/**
- * Method always called when making an API request.
- * It checks several things before actually calling the real method on the given module.
+ * Will execute $className->$methodName($parametersValues)
+ * If any error is detected (wrong number of parameters, method not found, class not found, etc.)
+ * it will throw an exception
*
* It also logs the API calls, with the parameters values, the returned value, the performance, etc.
* You can enable logging in config/global.ini.php (log_api_call)
*
+ * @param string The class name (eg. Piwik_Referers_API)
* @param string The method name
- * @param array The parameters
+ * @param array The parameters pairs (name=>value)
*
* @throws Piwik_Access_NoAccessException
*/
- public function __call($methodName, $parameterValues )
+ public function call($className, $methodName, $parametersRequest )
{
$returnedValue = null;
try {
- $this->registerClass(self::$classCalled);
-
- $className = $this->getClassNameFromModule(self::$classCalled);
+ $this->registerClass($className);
// instanciate the object
$object = call_user_func(array($className, "getInstance"));
@@ -144,22 +125,27 @@ class Piwik_API_Proxy
// check method exists
$this->checkMethodExists($className, $methodName);
- // all parameters to the function call must be non null
- $this->checkParametersAreNotNull($className, $methodName, $parameterValues);
+ // get the list of parameters required by the method
+ $parameterNamesDefaultValues = $this->getParametersList($className, $methodName);
+ // load parameters in the right order, etc.
+ $finalParameters = $this->getRequestParametersArray( $parameterNamesDefaultValues, $parametersRequest );
+
+ // all parameters to the function call must be non null
+ $this->checkParametersAreNotNull($className, $methodName, $finalParameters);
+
// start the timer
$timer = new Piwik_Timer;
// call the method
- $returnedValue = call_user_func_array(array($object, $methodName), $parameterValues);
+ $returnedValue = call_user_func_array(array($object, $methodName), $finalParameters);
// log the API Call
- $parameterNamesDefaultValues = $this->getParametersList($className, $methodName);
Zend_Registry::get('logger_api_call')->log(
- self::$classCalled,
+ $className,
$methodName,
$parameterNamesDefaultValues,
- $parameterValues,
+ $finalParameters,
$timer->getTimeMs(),
$returnedValue
);
@@ -168,14 +154,78 @@ class Piwik_API_Proxy
throw $e;
}
- self::$classCalled = null;
-
return $returnedValue;
}
- protected function includeApiFile($fileName)
+ /**
+ * Returns the parameters names and default values for the method $name
+ * of the class $class
+ *
+ * @param string The class name
+ * @param string The method name
+ * @return array Format array(
+ * 'testParameter' => null, // no default value
+ * 'life' => 42, // default value = 42
+ * 'date' => 'yesterday',
+ * );
+ */
+ public function getParametersList($class, $name)
+ {
+ return $this->metadataArray[$class][$name]['parameters'];
+ }
+
+ /**
+ * Returns the 'moduleName' part of 'Piwik_moduleName_API' classname
+ * @param string "Piwik_Referers_API"
+ * @return string "Referers"
+ */
+ public function getModuleNameFromClassName( $className )
+ {
+ return str_replace(array('Piwik_', '_API'), '', $className);
+ }
+
+ /**
+ * Returns an array containing the values of the parameters to pass to the method to call
+ *
+ * @param array array of (parameter name, default value)
+ * @return array values to pass to the function call
+ * @throws exception If there is a parameter missing from the required function parameters
+ */
+ private function getRequestParametersArray( $requiredParameters, $parametersRequest )
+ {
+ $finalParameters = array();
+ foreach($requiredParameters as $name => $defaultValue)
+ {
+ try{
+ if($defaultValue === Piwik_API_Proxy::NO_DEFAULT_VALUE)
+ {
+ try {
+ $requestValue = Piwik_Common::getRequestVar($name, null, null, $parametersRequest);
+ } catch(Exception $e) {
+ $requestValue = null;
+ }
+ }
+ else
+ {
+ $requestValue = Piwik_Common::getRequestVar($name, $defaultValue, null, $parametersRequest);
+ }
+ } catch(Exception $e) {
+ throw new Exception("The required variable '$name' is not correct or has not been found in the API Request. Add the parameter '&$name=' (with a value) in the URL.");
+ }
+ $finalParameters[] = $requestValue;
+ }
+ return $finalParameters;
+ }
+
+ /**
+ * Includes the class Piwik_UserSettings_API by looking up plugins/UserSettings/API.php
+ *
+ * @param string api class name eg. "Piwik_UserSettings_API"
+ */
+ private function includeApiFile($fileName)
{
- $potentialPaths = array( "plugins/". $fileName ."/API.php", );
+ $module = self::getModuleNameFromClassName($fileName);
+ $potentialPaths = array( "plugins/". $module ."/API.php", );
$found = false;
foreach($potentialPaths as $path)
@@ -190,21 +240,15 @@ class Piwik_API_Proxy
if(!$found)
{
- throw new Exception("API module $fileName not found.");
+ throw new Exception("API module $module not found.");
}
}
-
- protected function loadMethodMetadata($class, $method)
- {
- // use this trick to read the static attribute of the class
- // $class::$methodsNotToPublish doesn't work
- $variablesClass = get_class_vars($class);
- $variablesClass['methodsNotToPublish'][] = 'getInstance';
+ private function loadMethodMetadata($class, $method)
+ {
if($method->isPublic()
&& !$method->isConstructor()
- && !in_array($method->getName(), $variablesClass['methodsNotToPublish'] )
- )
+ && $method->getName() != 'getInstance' )
{
$name = $method->getName();
$parameters = $method->getParameters();
@@ -214,7 +258,7 @@ class Piwik_API_Proxy
{
$nameVariable = $parameter->getName();
- $defaultValue = Piwik_API_Proxy::NO_DEFAULT_VALUE;
+ $defaultValue = self::NO_DEFAULT_VALUE;
if($parameter->isDefaultValueAvailable())
{
$defaultValue = $parameter->getDefaultValue();
@@ -222,196 +266,24 @@ class Piwik_API_Proxy
$aParameters[$nameVariable] = $defaultValue;
}
- $this->api[$class][$name]['parameters'] = $aParameters;
- $this->api[$class][$name]['numberOfRequiredParameters'] = $method->getNumberOfRequiredParameters();
+ $this->metadataArray[$class][$name]['parameters'] = $aParameters;
+ $this->metadataArray[$class][$name]['numberOfRequiredParameters'] = $method->getNumberOfRequiredParameters();
}
}
-
- /**
- * Returns the 'moduleName' part of 'Piwik_moduleName_API' classname
- *
- * @param string moduleName
- * @return string className
- */
- protected function getModuleNameFromClassName( $className )
- {
- $start = strpos($className, '_') + 1;
- return substr($className, $start , strrpos($className, '_') - $start);
- }
-
- /**
- * Returns a string containing links to examples on how to call a given method on a given API
- * It will export links to XML, CSV, HTML, JSON, PHP, etc.
- * It will not export links for methods such as deleteSite or deleteUser
- *
- * @param string the class
- * @param methodName the method
- * @return string|false when not possible
- */
- public function getExampleUrl($class, $methodName, $parametersToSet = array())
- {
- $knowExampleDefaultParametersValues = array(
- 'access' => 'view',
- 'userLogin' => 'test',
- 'password' => 'passwordExample',
- 'passwordMd5ied' => 'passwordExample',
- 'email' => 'test@example.org',
-
- 'siteName' => 'new example website',
- 'urls' => 'http://example.org', // used in addSite, updateSite
-
- 'languageCode' => 'fr',
- );
-
- foreach($parametersToSet as $name => $value)
- {
- $knowExampleDefaultParametersValues[$name] = $value;
- }
-
- // no links for these method names
- $doNotPrintExampleForTheseMethods = array(
- 'deleteSite',
- 'deleteUser',
- );
-
- if(in_array($methodName,$doNotPrintExampleForTheseMethods))
- {
- return false;
- }
-
-
- // we try to give an URL example to call the API
- $aParameters = $this->getParametersList($class, $methodName);
- $moduleName = $this->getModuleNameFromClassName($class);
- $urlExample = '?module=API&method='.$moduleName.'.'.$methodName.'&';
- foreach($aParameters as $nameVariable=> $defaultValue)
- {
- // if there isn't a default value for a given parameter,
- // we need a 'know default value' or we can't generate the link
- if($defaultValue === Piwik_API_Proxy::NO_DEFAULT_VALUE)
- {
- if(isset($knowExampleDefaultParametersValues[$nameVariable]))
- {
- $exampleValue = $knowExampleDefaultParametersValues[$nameVariable];
- $urlExample .= $nameVariable . '=' . $exampleValue . '&';
- }
- else
- {
- return false;
- }
- }
-
- }
-
- return substr($urlExample,0,-1);
- }
-
- /**
- * Returns a HTML page containing help for all the successfully loaded APIs.
- * For each module it will return a mini help with the method names, parameters to give,
- * links to get the result in Xml/Csv/etc
- *
- * @return string
- */
- public function getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = '' )
- {
- $str = '';
- $token_auth = "&token_auth=" . Piwik::getCurrentUserTokenAuth();
- $parametersToSet = array(
- 'idSite' => Piwik_Common::getRequestVar('idSite', 1, 'int'),
- 'period' => Piwik_Common::getRequestVar('period', 'day', 'string'),
- 'date' => Piwik_Common::getRequestVar('date', 'today', 'string')
- );
-
- foreach($this->api as $class => $info)
- {
- $moduleName = $this->getModuleNameFromClassName($class);
- $str .= "\n<h2 id='$moduleName'>Module ".$moduleName."</h2>";
-
- foreach($info as $methodName => $infoMethod)
- {
- $params = $this->getStrListParameters($class, $methodName);
- $str .= "\n" . "- <b>$moduleName.$methodName " . $params . "</b>";
- $str .= '<small>';
-
- if($outputExampleUrls)
- {
- // we prefix all URLs with $prefixUrls
- // used when we include this output in the Piwik official documentation for example
- $str .= "<span class=\"example\">";
- $exampleUrl = $this->getExampleUrl($class, $methodName, $parametersToSet);
- if($exampleUrl !== false)
- {
- $lastNUrls = '';
- if( ereg('(&period)|(&date)',$exampleUrl))
- {
- $exampleUrlRss1 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last10')) ;
- $exampleUrlRss2 = $prefixUrls . $this->getExampleUrl($class, $methodName, $parametersToSet + array('date' => 'last5','period' => 'week',));
- $lastNUrls = ", RSS of the last <a target=_blank href='$exampleUrlRss1&format=rss$token_auth'>10 days</a>, <a target=_blank href='$exampleUrlRss2&format=Rss'>5 weeks</a>,
- XML of the <a target=_blank href='$exampleUrlRss1&format=xml$token_auth'>last 10 days</a>";
- }
- $exampleUrl = $prefixUrls . $exampleUrl ;
- $str .= " [ Example in
- <a target=_blank href='$exampleUrl&format=xml$token_auth'>XML</a>,
- <a target=_blank href='$exampleUrl&format=PHP&prettyDisplay=true$token_auth'>PHP</a>,
- <a target=_blank href='$exampleUrl&format=JSON$token_auth'>Json</a>,
- <a target=_blank href='$exampleUrl&format=Csv$token_auth'>Csv</a>,
- <a target=_blank href='$exampleUrl&format=Html$token_auth'>Basic html</a>
- $lastNUrls
- ]";
- }
- else
- {
- $str .= " [ No example available ]";
- }
- $str .= "</span>";
- }
- $str .= '</small>';
- $str .= "\n<br>";
- }
- }
- return $str;
- }
-
+
/**
- * Returns the methods $class.$name parameters (and default value if provided) as a string.
+ * Checks that the method exists in the class
*
* @param string The class name
* @param string The method name
- * @return string For example "(idSite, period, date = 'today')"
- */
- private function getStrListParameters($class, $name)
+ * @throws exception If the method is not found
+ */
+ private function checkMethodExists($className, $methodName)
{
- $aParameters = $this->getParametersList($class, $name);
- $asParameters = array();
- foreach($aParameters as $nameVariable=> $defaultValue)
+ if(!$this->isMethodAvailable($className, $methodName))
{
- $str = $nameVariable;
- if($defaultValue !== Piwik_API_Proxy::NO_DEFAULT_VALUE)
- {
- $str .= " = '$defaultValue'";
- }
- $asParameters[] = $str;
+ throw new Exception("The method '$methodName' does not exist or is not available in the module '".$className."'.");
}
- $sParameters = implode(", ", $asParameters);
- return "($sParameters)";
- }
-
- /**
- * Returns the parameters names and default values for the method $name
- * of the class $class
- *
- * @param string The class name
- * @param string The method name
- * @return array Format array(
- * 'testParameter' => null, // no default value
- * 'life' => 42, // default value = 42
- * 'date' => 'yesterday',
- * );
- */
- public function getParametersList($class, $name)
- {
- return $this->api[$class][$name]['parameters'];
}
/**
@@ -423,7 +295,7 @@ class Piwik_API_Proxy
*/
private function getNumberOfRequiredParameters($class, $name)
{
- return $this->api[$class][$name]['numberOfRequiredParameters'];
+ return $this->metadataArray[$class][$name]['numberOfRequiredParameters'];
}
/**
@@ -435,13 +307,10 @@ class Piwik_API_Proxy
*/
private function isMethodAvailable( $className, $methodName)
{
- return isset($this->api[$className][$methodName]);
+ return isset($this->metadataArray[$className][$methodName]);
}
/**
- * Checks that all given parameters are not null
- *
- * @param array of values
* @throws exception If any parameter value is null
*/
private function checkParametersAreNotNull($className, $methodName, $parametersValues)
@@ -469,20 +338,4 @@ class Piwik_API_Proxy
throw new Exception("Objects that provide an API must be Singleton and have a 'static public function getInstance()' method.");
}
}
-
- /**
- * Returns the API class name given the module name.
- *
- * For exemple for $module = 'Referers' it returns 'Piwik_Referers_API'
- * Piwik_Referers_API is the class that extends Piwik_Apiable
- * and that contains the methods to be published in the API.
- *
- * @param string module name
- * @return string class name
- */
- protected function getClassNameFromModule($module)
- {
- $class = Piwik::prefixClass($module ."_API");
- return $class;
- }
}
diff --git a/core/API/Request.php b/core/API/Request.php
index 09c96a2de1..aea6371410 100644
--- a/core/API/Request.php
+++ b/core/API/Request.php
@@ -11,6 +11,7 @@
*/
require_once "API/ResponseBuilder.php";
+require_once "API/DataTableGenericFilter.php";
/**
* An API request is the object used to make a call to the API and get the result.
@@ -108,63 +109,17 @@ class Piwik_API_Request
{
throw new Exception_PluginDeactivated($module);
}
- $className = "Piwik_" . $module . "_API";
+ $module = "Piwik_" . $module . "_API";
- // call the method via the API_Proxy class
- $api = Piwik_Api_Proxy::getInstance();
- $api->registerClass($module);
-
- // check method exists
- $api->checkMethodExists($className, $method);
-
- // get the list of parameters required by the method
- $parameters = $api->getParametersList($className, $method);
-
- // load the parameters from the request URL
- $finalParameters = $this->getRequestParametersArray( $parameters );
-
// call the method
- $returnedValue = call_user_func_array( array( $api->$module, $method), $finalParameters );
+ $returnedValue = Piwik_Api_Proxy::getInstance()->call($module, $method, $this->request);
$toReturn = $response->getResponse($returnedValue);
} catch(Exception $e ) {
- return $response->getResponseException( $e );
+ $toReturn = $response->getResponseException( $e );
}
return $toReturn;
}
-
- /**
- * Returns an array containing the values of the parameters to pass to the method to call
- *
- * @param array array of (parameter name, default value)
- * @return array values to pass to the function call
- * @throws exception If there is a parameter missing from the required function parameters
- */
- protected function getRequestParametersArray( $parameters )
- {
- $finalParameters = array();
- foreach($parameters as $name => $defaultValue)
- {
- try{
- if($defaultValue === Piwik_API_Proxy::NO_DEFAULT_VALUE)
- {
- try {
- $requestValue = Piwik_Common::getRequestVar($name, null, null, $this->request);
- } catch(Exception $e) {
- $requestValue = null;
- }
- }
- else
- {
- $requestValue = Piwik_Common::getRequestVar($name, $defaultValue, null, $this->request);
- }
- } catch(Exception $e) {
- throw new Exception("The required variable '$name' is not correct or has not been found in the API Request. Add the parameter '&$name=' (with a value) in the URL.");
- }
- $finalParameters[] = $requestValue;
- }
- return $finalParameters;
- }
/**
* Returns array( $class, $method) from the given string $class.$method
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index d66cdf9679..f0455c95c9 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -124,72 +124,6 @@ class Piwik_API_ResponseBuilder
return $return;
}
-
- /**
- * Returns an array containing the information of the generic Piwik_DataTable_Filter
- * to be applied automatically to the data resulting from the API calls.
- *
- * Order to apply the filters:
- * 1 - Filter that remove filtered rows
- * 2 - Filter that sort the remaining rows
- * 3 - Filter that keep only a subset of the results
- * 4 - Presentation filters
- *
- * @return array See the code for spec
- */
- public static function getGenericFiltersInformation()
- {
- $genericFilters = array(
- 'Pattern' => array(
- 'filter_column' => array('string'),
- 'filter_pattern' => array('string'),
- ),
- 'PatternRecursive' => array(
- 'filter_column_recursive' => array('string'),
- 'filter_pattern_recursive' => array('string'),
- ),
- 'ExactMatch' => array(
- 'filter_exact_column' => array('string'),
- 'filter_exact_pattern' => array('array'),
- ),
- 'ExcludeLowPopulation' => array(
- 'filter_excludelowpop' => array('string'),
- 'filter_excludelowpop_value'=> array('float'),
- ),
- 'AddColumnsWhenShowAllColumns' => array(
- 'filter_add_columns_when_show_all_columns' => array('integer')
- ),
- 'Sort' => array(
- 'filter_sort_column' => array('string', 'nb_visits'),
- 'filter_sort_order' => array('string', Zend_Registry::get('config')->General->dataTable_default_sort_order),
- ),
- 'Limit' => array(
- 'filter_offset' => array('integer', '0'),
- 'filter_limit' => array('integer', Zend_Registry::get('config')->General->dataTable_default_limit),
- ),
- 'SafeDecodeLabel' => array(),
- );
-
- return $genericFilters;
- }
-
- protected function handleDataTableGenericFilters($datatable)
- {
- if($datatable instanceof Piwik_DataTable)
- {
- $this->applyDataTableGenericFilters($datatable);
- }
- elseif($datatable instanceof Piwik_DataTable_Array)
- {
- $tables = $datatable->getArray();
- foreach($tables as $table)
- {
- $this->applyDataTableGenericFilters($table);
- }
- }
- return $datatable;
- }
-
/**
* Returns true if the user requested to serialize the output data (&serialize=1 in the request)
*
@@ -311,9 +245,10 @@ class Piwik_API_ResponseBuilder
protected function handleDataTable($datatable)
{
// if the flag disable_generic_filters is defined we skip the generic filters
- if(Piwik_Common::getRequestVar('disable_generic_filters', 'false', 'string', $this->request) == 'false')
+ if('false' == Piwik_Common::getRequestVar('disable_generic_filters', 'false', 'string', $this->request))
{
- $datatable = $this->handleDataTableGenericFilters($datatable);
+ $genericFilter = new Piwik_API_DataTableGenericFilter($datatable, $this->request);
+ $genericFilter->filter();
}
// if the flag disable_queued_filters is defined we skip the filters that were queued
@@ -345,73 +280,4 @@ class Piwik_API_ResponseBuilder
}
}
- /**
- * Apply generic filters to the DataTable object resulting from the API Call.
- * Disable this feature by setting the parameter disable_generic_filters to 1 in the API call request.
- *
- * @param Piwik_DataTable
- * @return void
- */
- protected function applyDataTableGenericFilters($dataTable)
- {
- if($dataTable instanceof Piwik_DataTable_Array )
- {
- $tables = $dataTable->getArray();
- foreach($tables as $table)
- {
- $this->applyDataTableGenericFilters($table);
- }
- return;
- }
-
- $genericFilters = self::getGenericFiltersInformation();
-
- foreach($genericFilters as $filterName => $parameters)
- {
- $filterParameters = array();
- $exceptionRaised = false;
-
- foreach($parameters as $name => $info)
- {
- // parameter type to cast to
- $type = $info[0];
-
- // default value if specified, when the parameter doesn't have a value
- $defaultValue = null;
- if(isset($info[1]))
- {
- $defaultValue = $info[1];
- }
-
- try {
- $value = Piwik_Common::getRequestVar($name, $defaultValue, $type, $this->request);
- settype($value, $type);
- $filterParameters[] = $value;
- }
- catch(Exception $e)
- {
- $exceptionRaised = true;
- break;
- }
- }
-
- if(!$exceptionRaised)
- {
- // a generic filter class name must follow this pattern
- $class = "Piwik_DataTable_Filter_".$filterName;
-
- if($filterName == 'Limit')
- {
- $dataTable->setRowsCountBeforeLimitFilter();
- }
-
- // build the set of parameters for the filter
- $filterParameters = array_merge(array($dataTable), $filterParameters);
-
- // use Reflection to create a new instance of the filter, given parameters $filterParameters
- $reflectionObj = new ReflectionClass($class);
- $filter = $reflectionObj->newInstanceArgs($filterParameters);
- }
- }
- }
}
diff --git a/core/Access.php b/core/Access.php
index f6251ec2a1..36a91f5c77 100644
--- a/core/Access.php
+++ b/core/Access.php
@@ -253,7 +253,6 @@ class Piwik_Access
/**
* If the user doesn't have an ADMIN access for at least one website, throws an exception
- *
* @throws Exception
*/
public function checkUserHasSomeAdminAccess()
@@ -264,6 +263,19 @@ class Piwik_Access
throw new Piwik_Access_NoAccessException("You can't access this resource as it requires an 'admin' access for at least one website.");
}
}
+
+ /**
+ * If the user doesn't have any view permission, throw exception
+ * @throws Exception
+ */
+ public function checkUserHasSomeViewAccess()
+ {
+ $idSitesAccessible = $this->getSitesIdWithAtLeastViewAccess();
+ if(count($idSitesAccessible) == 0)
+ {
+ throw new Piwik_Access_NoAccessException("You can't access this resource as it requires a 'view' access for at least one website.");
+ }
+ }
/**
* This method checks that the user has ADMIN access for the given list of websites.
diff --git a/core/Archive.php b/core/Archive.php
index b06bc11891..f6ca63c2b6 100644
--- a/core/Archive.php
+++ b/core/Archive.php
@@ -1,255 +1,273 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: Archive.php 585 2008-07-28 00:56:50Z matt $
- *
- * @package Piwik
- */
-
-require_once 'Period.php';
-require_once 'Date.php';
-require_once 'ArchiveProcessing.php';
-require_once 'Archive/Single.php';
-
-/**
- * The archive object is used to query specific data for a day or a period of statistics for a given website.
- *
- * Example:
- * <pre>
- * $archive = Piwik_Archive::build($idSite = 1, $period = 'week', '2008-03-08' );
- * $dataTable = $archive->getDataTable('Provider_hostnameExt');
- * $dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
- * return $dataTable;
- * </pre>
- *
- * Example bis:
- * <pre>
- * $archive = Piwik_Archive::build($idSite = 3, $period = 'day', $date = 'today' );
- * $nbVisits = $archive->getNumeric('nb_visits');
- * return $nbVisits;
- * </pre>
- *
- * If the requested statistics are not yet processed, Archive uses ArchiveProcessing to archive the statistics.
- *
- * @package Piwik
- * @subpackage Piwik_Archive
- */
-abstract class Piwik_Archive
-{
- /**
- * When saving DataTables in the DB, we sometimes replace the columns name by these IDs so we save up lots of bytes
- * Eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least
- * (in php it's actually even much more)
- *
- */
- const INDEX_NB_UNIQ_VISITORS = 1;
- const INDEX_NB_VISITS = 2;
- const INDEX_NB_ACTIONS = 3;
- const INDEX_MAX_ACTIONS = 4;
- const INDEX_SUM_VISIT_LENGTH = 5;
- const INDEX_BOUNCE_COUNT = 6;
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Archive.php 585 2008-07-28 00:56:50Z matt $
+ *
+ * @package Piwik
+ */
- /*
- * Integer indexed column name => string indexed column name
+require_once 'Period.php';
+require_once 'Date.php';
+require_once 'ArchiveProcessing.php';
+require_once 'Archive/Single.php';
+
+/**
+ * The archive object is used to query specific data for a day or a period of statistics for a given website.
+ *
+ * Example:
+ * <pre>
+ * $archive = Piwik_Archive::build($idSite = 1, $period = 'week', '2008-03-08' );
+ * $dataTable = $archive->getDataTable('Provider_hostnameExt');
+ * $dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
+ * return $dataTable;
+ * </pre>
+ *
+ * Example bis:
+ * <pre>
+ * $archive = Piwik_Archive::build($idSite = 3, $period = 'day', $date = 'today' );
+ * $nbVisits = $archive->getNumeric('nb_visits');
+ * return $nbVisits;
+ * </pre>
+ *
+ * If the requested statistics are not yet processed, Archive uses ArchiveProcessing to archive the statistics.
+ *
+ * @package Piwik
+ * @subpackage Piwik_Archive
+ */
+abstract class Piwik_Archive
+{
+ /**
+ * When saving DataTables in the DB, we sometimes replace the columns name by these IDs so we save up lots of bytes
+ * Eg. INDEX_NB_UNIQ_VISITORS is an integer: 4 bytes, but 'nb_uniq_visitors' is 16 bytes at least
+ * (in php it's actually even much more)
+ *
*/
+ const INDEX_NB_UNIQ_VISITORS = 1;
+ const INDEX_NB_VISITS = 2;
+ const INDEX_NB_ACTIONS = 3;
+ const INDEX_MAX_ACTIONS = 4;
+ const INDEX_SUM_VISIT_LENGTH = 5;
+ const INDEX_BOUNCE_COUNT = 6;
+ const INDEX_NB_VISITS_CONVERTED = 7;
+ const INDEX_NB_CONVERSIONS = 8;
+ const INDEX_REVENUE = 9;
+ const INDEX_GOALS = 10;
+
+ const INDEX_GOAL_NB_CONVERSIONS = 1;
+ const INDEX_GOAL_REVENUE = 2;
+
public static $mappingFromIdToName = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors',
- Piwik_Archive::INDEX_NB_VISITS => 'nb_visits',
- Piwik_Archive::INDEX_NB_ACTIONS => 'nb_actions',
- Piwik_Archive::INDEX_MAX_ACTIONS => 'max_actions',
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length',
- Piwik_Archive::INDEX_BOUNCE_COUNT => 'bounce_count',
+ Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 'nb_uniq_visitors',
+ Piwik_Archive::INDEX_NB_VISITS => 'nb_visits',
+ Piwik_Archive::INDEX_NB_ACTIONS => 'nb_actions',
+ Piwik_Archive::INDEX_MAX_ACTIONS => 'max_actions',
+ Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 'sum_visit_length',
+ Piwik_Archive::INDEX_BOUNCE_COUNT => 'bounce_count',
+ Piwik_Archive::INDEX_NB_VISITS_CONVERTED => 'nb_visits_converted',
+ Piwik_Archive::INDEX_NB_CONVERSIONS => 'nb_conversions',
+ Piwik_Archive::INDEX_REVENUE => 'revenue',
+ Piwik_Archive::INDEX_GOALS => 'goals',
);
+
+ public static $mappingFromIdToNameGoal = array(
+ Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => 'nb_conversions',
+ Piwik_Archive::INDEX_GOAL_REVENUE => 'revenue',
+ );
+
/*
* string indexed column name => Integer indexed column name
*/
public static $mappingFromNameToId = array(
- 'nb_uniq_visitors' => Piwik_Archive::INDEX_NB_UNIQ_VISITORS,
- 'nb_visits' => Piwik_Archive::INDEX_NB_VISITS,
- 'nb_actions' => Piwik_Archive::INDEX_NB_ACTIONS,
- 'max_actions' => Piwik_Archive::INDEX_MAX_ACTIONS,
- 'sum_visit_length' => Piwik_Archive::INDEX_SUM_VISIT_LENGTH,
- 'bounce_count' => Piwik_Archive::INDEX_BOUNCE_COUNT,
- );
-
- /**
- * Website Piwik_Site
- *
- * @var Piwik_Site
- */
- protected $site = null;
-
- /**
- * Stores the already built archives.
- * Act as a big caching array
- *
- * @var array of Piwik_Archive
- */
- static protected $alreadyBuilt = array();
-
- /**
- * Builds an Archive object or returns the same archive if previously built.
- *
- * @param string|int idSite integer, or comma separated list of integer
- * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
- * @param string $period 'week' 'day' etc.
- *
- * @return Piwik_Archive
- */
- static public function build($idSite, $period, $strDate )
- {
- if($idSite === 'all')
- {
- $sites = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
- }
- else
- {
- $sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+ 'nb_uniq_visitors' => Piwik_Archive::INDEX_NB_UNIQ_VISITORS,
+ 'nb_visits' => Piwik_Archive::INDEX_NB_VISITS,
+ 'nb_actions' => Piwik_Archive::INDEX_NB_ACTIONS,
+ 'max_actions' => Piwik_Archive::INDEX_MAX_ACTIONS,
+ 'sum_visit_length' => Piwik_Archive::INDEX_SUM_VISIT_LENGTH,
+ 'bounce_count' => Piwik_Archive::INDEX_BOUNCE_COUNT,
+ 'nb_visits_converted' => Piwik_Archive::INDEX_NB_VISITS_CONVERTED,
+ 'nb_conversions' => Piwik_Archive::INDEX_NB_CONVERSIONS,
+ 'revenue' => Piwik_Archive::INDEX_REVENUE,
+ 'goals' => Piwik_Archive::INDEX_GOALS,
+ );
+
+ /**
+ * Website Piwik_Site
+ *
+ * @var Piwik_Site
+ */
+ protected $site = null;
+
+ /**
+ * Stores the already built archives.
+ * Act as a big caching array
+ *
+ * @var array of Piwik_Archive
+ */
+ static protected $alreadyBuilt = array();
+
+ /**
+ * Builds an Archive object or returns the same archive if previously built.
+ *
+ * @param string|int idSite integer, or comma separated list of integer
+ * @param string|Piwik_Date $date 'YYYY-MM-DD' or magic keywords 'today' @see Piwik_Date::factory()
+ * @param string $period 'week' 'day' etc.
+ *
+ * @return Piwik_Archive
+ */
+ static public function build($idSite, $period, $strDate )
+ {
+ if($idSite === 'all')
+ {
+ $sites = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
}
-
- // idSite=1,3 or idSite=all
+ else
+ {
+ $sites = Piwik_Site::getIdSitesFromIdSitesString($idSite);
+ }
+
+ // idSite=1,3 or idSite=all
if( count($sites) > 1
- || $idSite === 'all' )
- {
- require_once 'Archive/Array/IndexedBySite.php';
- $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
- }
- // if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
- elseif(is_string($strDate)
- && (
- ereg('^(last|previous){1}([0-9]*)$', $strDate, $regs)
- || ereg('^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})$', $strDate, $regs)
- )
- )
- {
- $oSite = new Piwik_Site($idSite);
- require_once 'Archive/Array/IndexedByDate.php';
- $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
- }
- // case we request a single archive
- else
- {
- if(is_string($strDate))
- {
- $oDate = Piwik_Date::factory($strDate);
- }
- else
- {
- $oDate = $strDate;
- }
- $date = $oDate->toString();
-
+ || $idSite === 'all' )
+ {
+ require_once 'Archive/Array/IndexedBySite.php';
+ $archive = new Piwik_Archive_Array_IndexedBySite($sites, $period, $strDate);
+ }
+ // if a period date string is detected: either 'last30', 'previous10' or 'YYYY-MM-DD,YYYY-MM-DD'
+ elseif(is_string($strDate)
+ && (
+ ereg('^(last|previous){1}([0-9]*)$', $strDate, $regs)
+ || ereg('^([0-9]{4}-[0-9]{1,2}-[0-9]{1,2}),([0-9]{4}-[0-9]{1,2}-[0-9]{1,2})$', $strDate, $regs)
+ )
+ )
+ {
+ $oSite = new Piwik_Site($idSite);
+ require_once 'Archive/Array/IndexedByDate.php';
+ $archive = new Piwik_Archive_Array_IndexedByDate($oSite, $period, $strDate);
+ }
+ // case we request a single archive
+ else
+ {
+ if(is_string($strDate))
+ {
+ $oDate = Piwik_Date::factory($strDate);
+ }
+ else
+ {
+ $oDate = $strDate;
+ }
+ $date = $oDate->toString();
+
if(isset(self::$alreadyBuilt[$idSite][$date][$period]))
{
- return self::$alreadyBuilt[$idSite][$date][$period];
- }
-
- $oPeriod = Piwik_Period::factory($period, $oDate);
-
- $archive = new Piwik_Archive_Single();
- $archive->setPeriod($oPeriod);
+ return self::$alreadyBuilt[$idSite][$date][$period];
+ }
+
+ $oPeriod = Piwik_Period::factory($period, $oDate);
+
+ $archive = new Piwik_Archive_Single();
+ $archive->setPeriod($oPeriod);
$archive->setSite(new Piwik_Site($idSite));
- $archiveJustProcessed = $archive->prepareArchive();
+ $archiveJustProcessed = $archive->prepareArchive();
//we don't cache the archives just processed, the datatable were freed from memory
if(!$archiveJustProcessed)
- {
+ {
self::$alreadyBuilt[$idSite][$date][$period] = $archive;
- }
- }
-
- return $archive;
- }
-
- abstract public function prepareArchive();
-
- /**
- * Returns the value of the element $name from the current archive
- * The value to be returned is a numeric value and is stored in the archive_numeric_* tables
- *
- * @param string $name For example Referers_distinctKeywords
- * @return float|int|false False if no value with the given name
- */
- abstract public function getNumeric( $name );
-
- /**
- * Returns the value of the element $name from the current archive
- *
- * The value to be returned is a blob value and is stored in the archive_numeric_* tables
- *
- * It can return anything from strings, to serialized PHP arrays or PHP objects, etc.
- *
- * @param string $name For example Referers_distinctKeywords
- * @return mixed False if no value with the given name
- */
- abstract public function getBlob( $name );
+ }
+ }
+
+ return $archive;
+ }
+
+ abstract public function prepareArchive();
+
+ /**
+ * Returns the value of the element $name from the current archive
+ * The value to be returned is a numeric value and is stored in the archive_numeric_* tables
+ *
+ * @param string $name For example Referers_distinctKeywords
+ * @return float|int|false False if no value with the given name
+ */
+ abstract public function getNumeric( $name );
/**
+ * Returns the value of the element $name from the current archive
*
+ * The value to be returned is a blob value and is stored in the archive_numeric_* tables
+ *
+ * It can return anything from strings, to serialized PHP arrays or PHP objects, etc.
+ *
+ * @param string $name For example Referers_distinctKeywords
+ * @return mixed False if no value with the given name
+ */
+ abstract public function getBlob( $name );
+
+ /**
+ *
+ * @return Piwik_DataTable
+ */
+ abstract public function getDataTableFromNumeric( $fields );
+
+ /**
+ * This method will build a dataTable from the blob value $name in the current archive.
+ *
+ * For example $name = 'Referers_searchEngineByKeyword' will return a Piwik_DataTable containing all the keywords
+ * If a idSubTable is given, the method will return the subTable of $name
+ *
+ * @param string $name
+ * @param int $idSubTable or null if requesting the parent table
+ * @return Piwik_DataTable
+ * @throws exception If the value cannot be found
+ */
+ abstract public function getDataTable( $name, $idSubTable = null );
+
+ /**
+ * Same as getDataTable() except that it will also load in memory
+ * all the subtables for the DataTable $name.
+ * You can then access the subtables by using the Piwik_DataTable_Manager getTable()
+ *
+ * @param string $name
+ * @param int $idSubTable or null if requesting the parent table
* @return Piwik_DataTable
- */
- abstract public function getDataTableFromNumeric( $fields );
-
- /**
- * This method will build a dataTable from the blob value $name in the current archive.
- *
- * For example $name = 'Referers_searchEngineByKeyword' will return a Piwik_DataTable containing all the keywords
- * If a idSubTable is given, the method will return the subTable of $name
- *
- * @param string $name
- * @param int $idSubTable or null if requesting the parent table
- * @return Piwik_DataTable
- * @throws exception If the value cannot be found
- */
- abstract public function getDataTable( $name, $idSubTable = null );
-
- /**
- * Same as getDataTable() except that it will also load in memory
- * all the subtables for the DataTable $name.
- * You can then access the subtables by using the Piwik_DataTable_Manager getTable()
- *
- * @param string $name
- * @param int $idSubTable or null if requesting the parent table
- * @return Piwik_DataTable
- */
- abstract public function getDataTableExpanded($name, $idSubTable = null);
-
- /**
- * Sets the site
- *
- * @param Piwik_Site $site
- */
- public function setSite( Piwik_Site $site )
- {
- $this->site = $site;
- }
-
- /**
- * Gets the site
- *
- * @param Piwik_Site $site
- */
- public function getSite()
- {
- return $this->site;
- }
-
- /**
- * Returns the Id site associated with this archive
- *
- * @return int
- */
- public function getIdSite()
- {
- return $this->site->getId();
- }
-
-}
-
-
-
-
-
+ */
+ abstract public function getDataTableExpanded($name, $idSubTable = null);
+
+ /**
+ * Sets the site
+ *
+ * @param Piwik_Site $site
+ */
+ public function setSite( Piwik_Site $site )
+ {
+ $this->site = $site;
+ }
+
+ /**
+ * Gets the site
+ *
+ * @param Piwik_Site $site
+ */
+ public function getSite()
+ {
+ return $this->site;
+ }
+
+ /**
+ * Returns the Id site associated with this archive
+ *
+ * @return int
+ */
+ public function getIdSite()
+ {
+ return $this->site->getId();
+ }
+
+}
+
+
+
+
+
diff --git a/core/Archive/Single.php b/core/Archive/Single.php
index faf53de1c2..4035e2804b 100644
--- a/core/Archive/Single.php
+++ b/core/Archive/Single.php
@@ -372,6 +372,7 @@ class Piwik_Archive_Single extends Piwik_Archive
* 'nb_actions',
* 'sum_visit_length',
* 'bounce_count',
+ * 'nb_visits_converted'
* );
*
* @param string|array $fields Name or array of names of Archive fields
@@ -454,4 +455,4 @@ class Piwik_Archive_Single extends Piwik_Archive
return $dataTableToLoad;
}
}
-?> \ No newline at end of file
+?>
diff --git a/core/ArchiveProcessing.php b/core/ArchiveProcessing.php
index 6a1ef954bb..9a99636841 100644
--- a/core/ArchiveProcessing.php
+++ b/core/ArchiveProcessing.php
@@ -334,6 +334,7 @@ abstract class Piwik_ArchiveProcessing
$this->logTable = Piwik::prefixTable('log_visit');
$this->logVisitActionTable = Piwik::prefixTable('log_link_visit_action');
$this->logActionTable = Piwik::prefixTable('log_action');
+ $this->logConversionTable = Piwik::prefixTable('log_conversion');
}
/**
@@ -430,6 +431,28 @@ abstract class Piwik_ArchiveProcessing
return $this->timestampDateStart;
}
+
+ // exposing the number of visits publicly (number used to compute conversions rates)
+ protected $nb_visits = null;
+ protected $nb_visits_converted = null;
+
+ protected function setNumberOfVisits($nb_visits)
+ {
+ $this->nb_visits = $nb_visits;
+ }
+ public function getNumberOfVisits()
+ {
+ return $this->nb_visits;
+ }
+ protected function setNumberOfVisitsConverted($nb_visits_converted)
+ {
+ $this->nb_visits_converted = $nb_visits_converted;
+ }
+ public function getNumberOfVisitsConverted()
+ {
+ return $this->nb_visits_converted;
+ }
+
/**
* Returns the idArchive we will use for the current archive
*
@@ -499,7 +522,7 @@ abstract class Piwik_ArchiveProcessing
);
$timeStampWhere = " AND UNIX_TIMESTAMP(ts_archived) >= ? ";
$bindSQL[] = $this->maxTimestampArchive;
-
+
$sqlQuery = " SELECT idarchive, value, name, UNIX_TIMESTAMP(date1) as timestamp
FROM ".$this->tableArchiveNumeric->getTableName()."
WHERE idsite = ?
@@ -510,7 +533,6 @@ abstract class Piwik_ArchiveProcessing
OR name = 'nb_visits')
$timeStampWhere
ORDER BY ts_archived DESC";
-
$results = Zend_Registry::get('db')->fetchAll($sqlQuery, $bindSQL );
if(empty($results))
{
diff --git a/core/ArchiveProcessing/Day.php b/core/ArchiveProcessing/Day.php
index f3a4f5d6c7..9d0e3fd975 100644
--- a/core/ArchiveProcessing/Day.php
+++ b/core/ArchiveProcessing/Day.php
@@ -11,8 +11,9 @@
/**
- * Handles the archiving process for a day.
- * The class provides generic methods to manipulate data from the DB, easily create Piwik_DataTable objects.
+ * Handles the archiving process for a day.
+ * The class provides generic helper methods to manipulate data from the DB,
+ * easily create Piwik_DataTable objects from running SELECT ... GROUP BY on the log_visit table.
*
* All the logic of the archiving is done inside the plugins listening to the event 'ArchiveProcessing_Day.compute'
*
@@ -51,7 +52,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$this->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -70,7 +72,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
{
$record = new Piwik_ArchiveProcessing_Record_Numeric($name, $value);
}
-
+ $this->setNumberOfVisits($row['nb_visits']);
+ $this->setNumberOfVisitsConverted($row['nb_visits_converted']);
Piwik_PostEvent('ArchiveProcessing_Day.compute', $this);
}
@@ -138,8 +141,26 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
return $table;
}
+ public function getDataTableFromArray( $array )
+ {
+ $table = new Piwik_DataTable;
+ $table->addRowsFromArrayWithIndexLabel($array);
+ return $table;
+ }
+
/**
- * Helper function that returns common statistics for a given database field distinct values.
+ * Output:
+ * array(
+ * LABEL => array(
+ * Piwik_Archive::INDEX_NB_UNIQ_VISITORS => 0,
+ * Piwik_Archive::INDEX_NB_VISITS => 0
+ * ),
+ * LABEL2 => array(
+ * [...]
+ * )
+ * )
+ *
+ * Helper function that returns an array with common statistics for a given database field distinct values.
*
* The statistics returned are:
* - number of unique visitors
@@ -150,18 +171,18 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* - count of bouncing visits (visits with one page view)
*
* For example if $label = 'config_os' it will return the statistics for every distinct Operating systems
- * The returned DataTable will have a row per distinct operating systems,
- * and a column per stat (nb of visits, max actions, etc)
+ * The returned array will have a row per distinct operating systems,
+ * and a column per stat (nb of visits, max actions, etc)
*
- * label nb_uniq_visitors nb_visits nb_actions max_actions sum_visit_length bounce_count
- * Linux 27 66 66 1 660 66
- * Windows XP 12 39 39 1 390 39
- * Mac OS 15 36 36 1 360 36
+ * 'label' Piwik_Archive::INDEX_NB_UNIQ_VISITORS Piwik_Archive::INDEX_NB_VISITS etc.
+ * Linux 27 66 ...
+ * Windows XP 12 ...
+ * Mac OS 15 36 ...
*
* @param string $label Table log_visit field name to be use to compute common stats
- * @return Piwik_DataTable
+ * @return array
*/
- public function getDataTableInterestForLabel( $label )
+ public function getArrayInterestForLabel($label)
{
$query = "SELECT $label as label,
count(distinct visitor_idcookie) as nb_uniq_visitors,
@@ -169,34 +190,21 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$this->logTable."
WHERE visit_server_date = ?
AND idsite = ?
GROUP BY label";
-
$query = $this->db->query($query, array( $this->strDateStart, $this->idsite ) );
$interest = array();
- while($rowBefore = $query->fetch())
+ while($row = $query->fetch())
{
- $row = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => $rowBefore['nb_uniq_visitors'],
- Piwik_Archive::INDEX_NB_VISITS => $rowBefore['nb_visits'],
- Piwik_Archive::INDEX_NB_ACTIONS => $rowBefore['nb_actions'],
- Piwik_Archive::INDEX_MAX_ACTIONS => $rowBefore['max_actions'],
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => $rowBefore['sum_visit_length'],
- Piwik_Archive::INDEX_BOUNCE_COUNT => $rowBefore['bounce_count'],
- 'label' => $rowBefore['label']
- );
-
if(!isset($interest[$row['label']])) $interest[$row['label']]= $this->getNewInterestRow();
$this->updateInterestStats( $row, $interest[$row['label']]);
}
-
- $table = new Piwik_DataTable;
- $table->addRowsFromArrayWithIndexLabel($interest);
- return $table;
+ return $interest;
}
/**
@@ -259,17 +267,19 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
/**
* Helper function that returns the multiple serialized DataTable of the given PHP array.
* The DataTable here associates a subtable to every row of the level 0 array.
- * This is used for example for search engines. Every search engine (level 0) has a subtable containing the
- * keywords.
+ * This is used for example for search engines.
+ * Every search engine (level 0) has a subtable containing the keywords.
*
* The $arrayLevel0 must have the format
* Example: array (
+ * // Yahoo.com => array( kwd1 => stats, kwd2 => stats )
* LABEL => array(col1 => X, col2 => Y),
* LABEL2 => array(col1 => X, col2 => Y),
* )
*
* The $subArrayLevel1ByKey must have the format
* Example: array(
+ * // Yahoo.com => array( stats )
* LABEL => #Piwik_DataTable_ForLABEL,
* LABEL2 => #Piwik_DataTable_ForLABEL2,
* )
@@ -279,10 +289,9 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* @param array of Piwik_DataTable $subArrayLevel1ByKey
* @return array Array with N elements: the strings of the datatable serialized
*/
- public function getDataTablesSerialized( $arrayLevel0, $subArrayLevel1ByKey, $maximumRowsInDataTableLevelZero = null, $maximumRowsInSubDataTable = null)
+ public function getDataTableWithSubtablesFromArraysIndexedByLabel( $arrayLevel0, $subArrayLevel1ByKey )
{
$tablesByLabel = array();
-
foreach($arrayLevel0 as $label => $aAllRowsForThisLabel)
{
$table = new Piwik_DataTable;
@@ -292,8 +301,7 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
$parentTableLevel0 = new Piwik_DataTable;
$parentTableLevel0->addRowsFromArrayWithIndexLabel($subArrayLevel1ByKey, $tablesByLabel);
- $toReturn = $parentTableLevel0->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- return $toReturn;
+ return $parentTableLevel0;
}
/**
@@ -308,7 +316,8 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
Piwik_Archive::INDEX_NB_ACTIONS => 0,
Piwik_Archive::INDEX_MAX_ACTIONS => 0,
Piwik_Archive::INDEX_SUM_VISIT_LENGTH => 0,
- Piwik_Archive::INDEX_BOUNCE_COUNT => 0
+ Piwik_Archive::INDEX_BOUNCE_COUNT => 0,
+ Piwik_Archive::INDEX_NB_VISITS_CONVERTED=> 0,
);
}
@@ -339,13 +348,123 @@ class Piwik_ArchiveProcessing_Day extends Piwik_ArchiveProcessing
* @param array $oldRowToUpdate
*/
public function updateInterestStats( $newRowToAdd, &$oldRowToUpdate)
- {
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd[Piwik_Archive::INDEX_NB_UNIQ_VISITORS];
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS] += $newRowToAdd[Piwik_Archive::INDEX_NB_VISITS];
- $oldRowToUpdate[Piwik_Archive::INDEX_NB_ACTIONS] += $newRowToAdd[Piwik_Archive::INDEX_NB_ACTIONS];
- $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd[Piwik_Archive::INDEX_MAX_ACTIONS], $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS]);
- $oldRowToUpdate[Piwik_Archive::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd[Piwik_Archive::INDEX_SUM_VISIT_LENGTH];
- $oldRowToUpdate[Piwik_Archive::INDEX_BOUNCE_COUNT] += $newRowToAdd[Piwik_Archive::INDEX_BOUNCE_COUNT];
+ {
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_UNIQ_VISITORS] += $newRowToAdd['nb_uniq_visitors'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS] += $newRowToAdd['nb_visits'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_ACTIONS] += $newRowToAdd['nb_actions'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS] = (float)max($newRowToAdd['max_actions'], $oldRowToUpdate[Piwik_Archive::INDEX_MAX_ACTIONS]);
+ $oldRowToUpdate[Piwik_Archive::INDEX_SUM_VISIT_LENGTH] += $newRowToAdd['sum_visit_length'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_BOUNCE_COUNT] += $newRowToAdd['bounce_count'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_NB_VISITS_CONVERTED] += $newRowToAdd['nb_visits_converted'];
+ }
+
+ public function queryConversionsBySegment($segments = '')
+ {
+ if(!empty($segments))
+ {
+ $segments = ", ". $segments;
+ }
+ $query = "SELECT idgoal,
+ count(*) as nb_conversions,
+ sum(revenue) as revenue
+ $segments
+ FROM ".$this->logConversionTable."
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idgoal $segments";
+ $query = $this->db->query($query, array( $this->strDateStart, $this->idsite ));
+ return $query;
+ }
+
+ public function queryConversionsBySingleSegment($segment)
+ {
+ $query = "SELECT idgoal,
+ count(*) as nb_conversions,
+ sum(revenue) as revenue,
+ $segment as label
+ FROM ".$this->logConversionTable."
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idgoal, label";
+ $query = $this->db->query($query, array( $this->strDateStart, $this->idsite ));
+ return $query;
+ }
+
+ /**
+ * Input:
+ * array(
+ * LABEL => array( Piwik_Archive::INDEX_NB_VISITS => X,
+ * Piwik_Archive::INDEX_GOALS => array(
+ * idgoal1 => array( [...] ),
+ * idgoal2 => array( [...] ),
+ * ),
+ * [...] ),
+ * LABEL2 => array( Piwik_Archive::INDEX_NB_VISITS => Y, [...] )
+ * );
+ *
+ * Output:
+ * array(
+ * LABEL => array( Piwik_Archive::INDEX_NB_VISITS => X,
+ *
+ * Piwik_Archive::INDEX_GOALS => array(
+ * idgoal1 => array( [...] ),
+ * idgoal2 => array( [...] ),
+ * ),
+ * [...] ),
+ * LABEL2 => array( Piwik_Archive::INDEX_NB_VISITS => Y, [...] )
+ * );
+ * )
+ * @param array by reference, will be modified
+ * @return void (array by reference is modified)
+ */
+ function enrichConversionsByLabelArray(&$interestByLabel)
+ {
+ foreach($interestByLabel as $label => &$values)
+ {
+ if(isset($values[Piwik_Archive::INDEX_GOALS]))
+ {
+ $revenue = $conversions = 0;
+ foreach($values[Piwik_Archive::INDEX_GOALS] as $idgoal => $goalValues)
+ {
+ $revenue += $goalValues[Piwik_Archive::INDEX_GOAL_REVENUE];
+ $conversions += $goalValues[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS];
+ }
+ $values[Piwik_Archive::INDEX_NB_CONVERSIONS] = $conversions;
+ $values[Piwik_Archive::INDEX_REVENUE] = $revenue;
+ }
+ }
+ }
+
+ /**
+ * @param array $interestByLabelAndSubLabel
+ * @return void (array by reference is modified)
+ */
+ function enrichConversionsByLabelArrayHasTwoLevels(&$interestByLabelAndSubLabel)
+ {
+ foreach($interestByLabelAndSubLabel as $mainLabel => &$interestBySubLabel)
+ {
+ $this->enrichConversionsByLabelArray($interestBySubLabel);
+ }
+ }
+
+ function updateGoalStats($newRowToAdd, &$oldRowToUpdate)
+ {
+ $oldRowToUpdate[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS] += $newRowToAdd['nb_conversions'];
+ $oldRowToUpdate[Piwik_Archive::INDEX_GOAL_REVENUE] += $newRowToAdd['revenue'];
+ }
+
+ function getNewGoalRow()
+ {
+ return array( Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => 0,
+ Piwik_Archive::INDEX_GOAL_REVENUE => 0,
+ );
+ }
+
+ function getGoalRowFromQueryRow($queryRow)
+ {
+ return array( Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS => $queryRow['nb_conversions'],
+ Piwik_Archive::INDEX_GOAL_REVENUE => $queryRow['revenue'],
+ );
}
}
diff --git a/core/ArchiveProcessing/Period.php b/core/ArchiveProcessing/Period.php
index 7e834bec62..a4deaa3faf 100644
--- a/core/ArchiveProcessing/Period.php
+++ b/core/ArchiveProcessing/Period.php
@@ -119,7 +119,7 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
/**
- * This powerful method will compute the sum of DataTables over the period for the given fields $aRecordName.
+ * This method will compute the sum of DataTables over the period for the given fields $aRecordName.
* The resulting DataTable will be then added to queue of data to be recorded in the database.
* It will usually be called in a plugin that listens to the hook 'ArchiveProcessing_Period.compute'
*
@@ -223,20 +223,24 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
{
$this->archiveNumericValuesMax( 'max_actions' );
$toSum = array(
- 'nb_uniq_visitors',
+ 'nb_uniq_visitors', //TODO fix
'nb_visits',
'nb_actions',
'sum_visit_length',
'bounce_count',
+ 'nb_visits_converted',
);
$record = $this->archiveNumericValuesSum($toSum);
- $this->isThereSomeVisits = ($record['nb_visits']->value != 0);
+ $nbVisits = $record['nb_visits']->value;
+ $nbVisitsConverted = $record['nb_visits_converted']->value;
+ $this->isThereSomeVisits = ( $nbVisits!= 0);
if($this->isThereSomeVisits === false)
{
return;
}
-
+ $this->setNumberOfVisits($nbVisits);
+ $this->setNumberOfVisitsConverted($nbVisitsConverted);
Piwik_PostEvent('ArchiveProcessing_Period.compute', $this);
}
@@ -250,21 +254,25 @@ class Piwik_ArchiveProcessing_Period extends Piwik_ArchiveProcessing
{
parent::postCompute();
- // we delete records that are now out of date
- // in the case of a period we delete archives that were archived before the end of the period
- // and only if they are at least 1 day old (so we don't delete archives computed today that may be stil valid)
- $blobTable = $this->tableArchiveBlob->getTableName();
- $numericTable = $this->tableArchiveNumeric->getTableName();
-
- $query = " DELETE
- FROM %s
- WHERE period > ?
- AND DATE(ts_archived) <= date2
- AND date(ts_archived) < date_sub(CURRENT_DATE(), INTERVAL 1 DAY)
- ";
-
- Zend_Registry::get('db')->query(sprintf($query, $blobTable), Piwik::$idPeriods['day']);
- Zend_Registry::get('db')->query(sprintf($query, $numericTable), Piwik::$idPeriods['day']);
+ //TODO should be done in a different asynchronous job
+ if(rand(0, 15) == 5)
+ {
+ // we delete records that are now out of date
+ // in the case of a period we delete archives that were archived before the end of the period
+ // and only if they are at least 1 day old (so we don't delete archives computed today that may be stil valid)
+ $blobTable = $this->tableArchiveBlob->getTableName();
+ $numericTable = $this->tableArchiveNumeric->getTableName();
+
+ $query = " DELETE
+ FROM %s
+ WHERE period > ?
+ AND DATE(ts_archived) <= date2
+ AND date(ts_archived) < date_sub(CURRENT_DATE(), INTERVAL 1 DAY)
+ ";
+
+ Zend_Registry::get('db')->query(sprintf($query, $blobTable), Piwik::$idPeriods['day']);
+ Zend_Registry::get('db')->query(sprintf($query, $numericTable), Piwik::$idPeriods['day']);
+ }
}
}
diff --git a/core/ArchiveProcessing/Record/BlobArray.php b/core/ArchiveProcessing/Record/BlobArray.php
index 4e3165489e..de187ac62d 100644
--- a/core/ArchiveProcessing/Record/BlobArray.php
+++ b/core/ArchiveProcessing/Record/BlobArray.php
@@ -32,7 +32,6 @@
*/
class Piwik_ArchiveProcessing_Record_BlobArray extends Piwik_ArchiveProcessing_Record
{
-
function __construct( $name, $aValue)
{
foreach($aValue as $id => $value)
@@ -49,13 +48,14 @@ class Piwik_ArchiveProcessing_Record_BlobArray extends Piwik_ArchiveProcessing_R
$newName = $name . '_' . $id;
}
$record = new Piwik_ArchiveProcessing_Record_Blob( $newName, $value );
-
}
}
+
public function __toString()
{
throw new Exception( 'Not valid' );
}
+
public function delete()
{
throw new Exception( 'Not valid' );
diff --git a/core/CacheFile.php b/core/CacheFile.php
new file mode 100644
index 0000000000..a254788c52
--- /dev/null
+++ b/core/CacheFile.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik
+ */
+
+/**
+ * Code originally inspired from OpenX
+ * - openx/plugins_repo/openXDeliveryCacheStore/extensions/deliveryCacheStore/oxCacheFile/oxCacheFile.class.php
+ * - openx/plugins_repo/openXDeliveryCacheStore/extensions/deliveryCacheStore/oxCacheFile/oxCacheFile.delivery.php
+ *
+ * We may want to add support for cache expire, storing last modification time in the file. See code in:
+ * - openx/lib/max/Delivery/cache.php
+ */
+class Piwik_CacheFile
+{
+ protected $cachePath;
+ protected $cachePrefix;
+
+ function __construct($directory)
+ {
+ $this->cachePath = PIWIK_INCLUDE_PATH . "/tmp/cache/";
+ $this->cachePath .= $directory . "/";
+// echo $this->cachePath;exit;
+ }
+
+ /**
+ * Function to fetch a cache entry
+ *
+ * @param string $filename The name of file where cache entry is stored
+ * @return mixed False on error, or array the cache content
+ */
+ function get($id)
+ {
+ $cache_complete = false;
+ $content = '';
+
+ // We are assuming that most of the time cache will exists
+ $ok = @include($this->cachePath . $id);
+
+ if ($ok && $cache_complete == true) {
+ return $content;
+ }
+
+ return false;
+ }
+
+ /**
+ * A function to store content a cache entry.
+ *
+ * @param string $id The filename where cache entry is stored
+ * @param array $content The cache content
+ * @return bool True if the entry was succesfully stored
+ */
+ function set($id, $content)
+ {
+ if( !is_dir($this->cachePath))
+ {
+ Piwik_Common::mkdir($this->cachePath);
+ }
+ if (!is_writable($this->cachePath)) {
+ return false;
+ }
+
+ $id = $this->cachePath . $id . ".php";
+
+ $cache_literal = "<"."?php\n\n";
+ $cache_literal .= "$"."content = ".var_export($content, true).";\n\n";
+ $cache_literal .= "$"."cache_complete = true;\n\n";
+ $cache_literal .= "?".">";
+
+ // Write cache to a temp file, then rename it, overwritng the old cache
+ // On *nix systems this should guarantee atomicity
+ $tmp_filename = tempnam($this->cachePath, 'tmp_');
+ if ($fp = @fopen($tmp_filename, 'wb')) {
+ @fwrite ($fp, $cache_literal, strlen($cache_literal));
+ @fclose ($fp);
+
+ if (!@rename($tmp_filename, $id)) {
+ // On some systems rename() doesn't overwrite destination
+ @unlink($id);
+ if (!@rename($tmp_filename, $id)) {
+ // Make sure that no temporary file is left over
+ // if the destination is not writable
+ @unlink($tmp_filename);
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * A function to delete a single cache entry
+ *
+ * @param string $filename The cache entry filename (hashed name)
+ * @return bool True if the entres were succesfully deleted
+ */
+ function delete($id)
+ {
+ $filename = $this->cachePath . $id;
+ if (file_exists($filename)) {
+ @unlink ($filename);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/core/Common.php b/core/Common.php
index 2cca73ce91..194e66a4c8 100644
--- a/core/Common.php
+++ b/core/Common.php
@@ -36,6 +36,77 @@ class Piwik_Common
*/
const HTML_ENCODING_QUOTE_STYLE = ENT_COMPAT;
+
+ /**
+ * Returns the table name prefixed by the table prefix.
+ * Works in both Tracker and UI mode.
+ *
+ * @param string The table name to prefix, ie "log_visit"
+ * @return string The table name prefixed, ie "piwik-production_log_visit"
+ */
+ static public function prefixTable($table)
+ {
+ $prefixTable = false;
+ if(class_exists('Piwik_Tracker_Config'))
+ {
+ $prefixTable = Piwik_Tracker_Config::getInstance()->database['tables_prefix'];
+ }
+ else
+ {
+ $config = Zend_Registry::get('config');
+ if($config !== false)
+ {
+ $prefixTable = $config->database->tables_prefix;
+ }
+ }
+ return $prefixTable . $table;
+ }
+
+ /**
+ * Returns array containing data about the website: goals, URLs, etc.
+ *
+ * @param int $idSite
+ * @return array
+ */
+ static function getCacheWebsiteAttributes( $idSite )
+ {
+ static $cache = null;
+ if(is_null($cache))
+ {
+ require_once "CacheFile.php";
+ $cache = new Piwik_CacheFile('tracker');
+ }
+ $filename = $idSite;
+ $cacheContent = $cache->get($filename);
+ if($cacheContent !== false)
+ {
+ return $cacheContent;
+ }
+
+ if(!class_exists('Zend_Registry'))
+ {
+ require_once "Zend/Registry.php";
+ Zend_Registry::set('db', Piwik_Tracker::getDatabase());
+ }
+ $content = array();
+ Piwik_PostEvent('Common.fetchWebsiteAttributes', &$content, $idSite);
+ $cache->set($filename, $content);
+ return $content;
+ }
+
+ static public function regenerateCacheWebsiteAttributes($idSite)
+ {
+ self::deleteCacheWebsiteAttributes($idSite);
+ self::getCacheWebsiteAttributes($idSite);
+ }
+
+ static public function deleteCacheWebsiteAttributes( $idSite )
+ {
+ require_once "CacheFile.php";
+ $cache = new Piwik_CacheFile('tracker');
+ $filename = $idSite;
+ $cache->delete($filename);
+ }
/**
* Returns the path and query part from a URL.
@@ -124,27 +195,61 @@ class Piwik_Common
if( false !== strpos($value, '='))
{
$exploded = explode('=',$value);
- $name = $exploded[0];
-
- // if array without indexes
- if( substr($name,-2,2) == '[]' )
- {
- $name = substr($name, 0, -2);
- if( isset($nameToValue[$name]) == false || is_array($nameToValue[$name]) == false )
- {
- $nameToValue[$name] = array();
- }
- array_push($nameToValue[$name],$exploded[1]);
- }
- else
- {
- $nameToValue[$name] = $exploded[1];
- }
+ $name = $exploded[0];
+
+ // if array without indexes
+ if( substr($name,-2,2) == '[]' )
+ {
+ $name = substr($name, 0, -2);
+ if( isset($nameToValue[$name]) == false || is_array($nameToValue[$name]) == false )
+ {
+ $nameToValue[$name] = array();
+ }
+ array_push($nameToValue[$name],$exploded[1]);
+ }
+ else
+ {
+ $nameToValue[$name] = $exploded[1];
+ }
}
}
return $nameToValue;
}
+ static public function mkdir( $path, $mode = 0755, $denyAccess = true )
+ {
+ if(!is_dir($path))
+ {
+ $directoryParent = Piwik_Common::realpath(dirname($path));
+ if( is_writable($directoryParent) )
+ {
+ mkdir($path, $mode, true);
+ }
+ }
+
+ if($denyAccess)
+ {
+ self::createHtAccess($path);
+ }
+ }
+
+ /**
+ * path without trailing slash
+ */
+ static public function createHtAccess( $path )
+ {
+ @file_put_contents($path . "/.htaccess", "Deny from all");
+ }
+
+ static public function realpath($path)
+ {
+ if (file_exists($path))
+ {
+ return realpath($path);
+ }
+ return $path;
+ }
+
/**
* Returns true if the string is a valid filename
* File names that start with a-Z or 0-9 and contain a-Z, 0-9, underscore(_), dash(-), and dot(.) will be accepted.
diff --git a/core/Controller.php b/core/Controller.php
index 221523cb10..e544796d58 100644
--- a/core/Controller.php
+++ b/core/Controller.php
@@ -9,6 +9,7 @@
* @package Piwik
*/
+require_once "ViewDataTable.php";
/**
* Parent class of all plugins Controllers (located in /plugins/PluginName/Controller.php
* It defines some helper functions controllers can use.
@@ -78,6 +79,15 @@ abstract class Piwik_Controller
*/
protected function renderView( Piwik_ViewDataTable $view, $fetch)
{
+ Piwik_PostEvent( 'Controller.renderView',
+ $this,
+ array( 'view' => $view,
+ 'controllerName' => $view->getCurrentControllerName(),
+ 'controllerAction' => $view->getCurrentControllerAction(),
+ 'apiMethodToRequestDataTable' => $view->getApiMethodToRequestDataTable(),
+ 'controllerActionCalledWhenRequestSubTable' => $view->getControllerActionCalledWhenRequestSubTable(),
+ )
+ );
$view->main();
$rendered = $view->getView()->render();
if($fetch)
@@ -223,7 +233,6 @@ abstract class Piwik_Controller
} catch(Exception $e) {
self::redirectToIndex(Piwik::getModule(), Piwik::getAction());
}
-
$otherPeriodsAvailable = array('day', 'week', 'month', 'year');
$otherPeriodsNames = array(
'day' => Piwik_Translate('CoreHome_PeriodDay'),
@@ -243,7 +252,7 @@ abstract class Piwik_Controller
$view->periodsNames = $otherPeriodsNames;
}
- function redirectToIndex($moduleToRedirect = 'CoreHome', $actionToRedirect = 'index')
+ function redirectToIndex($moduleToRedirect, $actionToRedirect)
{
$sitesId = Piwik_SitesManager_API::getSitesIdWithAtLeastViewAccess();
if(!empty($sitesId))
diff --git a/core/Cookie.php b/core/Cookie.php
index 192ebc3b3b..ef98bb3561 100644
--- a/core/Cookie.php
+++ b/core/Cookie.php
@@ -79,7 +79,7 @@ class Piwik_Cookie
*/
protected function getDefaultExpire()
{
- return time() + 86400*365*10;
+ return time() + 86400*365*2;
}
/**
@@ -154,7 +154,6 @@ class Piwik_Cookie
protected function loadContentFromCookie()
{
$cookieStr = $_COOKIE[$this->name];
-
$values = explode( self::VALUE_SEPARATOR, $cookieStr);
foreach($values as $nameValue)
{
diff --git a/core/DataFiles/SearchEngines.php b/core/DataFiles/SearchEngines.php
index af8891dca3..1076b56ff7 100644
--- a/core/DataFiles/SearchEngines.php
+++ b/core/DataFiles/SearchEngines.php
@@ -66,8 +66,9 @@ if(!isset($GLOBALS['Piwik_SearchEngines'] ))
//Alice Adsl
"rechercher.aliceadsl.fr" => array("Alice Adsl", "qs"),
- "search.alice.it" => array("Alice (Virgilio)", "qt"),
-
+ "search.alice.it" => array("Alice (powered by Virgilio)", "qt"),
+ "ricerca.alice.it" => array("Alice (powered by Virgilio)", "qs"),
+
//Allesklar
"www.allesklar.de" => array("Allesklar", "words"),
diff --git a/core/DataTable.php b/core/DataTable.php
index 4d7abc40ac..3f52385512 100644
--- a/core/DataTable.php
+++ b/core/DataTable.php
@@ -170,6 +170,13 @@ class Piwik_DataTable
protected $indexNotUpToDate = false;
/**
+ * Column name of last time the table was sorted
+ *
+ * @var string
+ */
+ protected $tableSortedBy = false;
+
+ /**
* List of Piwik_DataTable_Filter queued to this table
*
* @var array
@@ -218,10 +225,12 @@ class Piwik_DataTable
* Sort the dataTable rows using the php callback function
*
* @param string $functionCallback
+ * @param string $columnSortedBy The column name. Used to then ask the datatable what column are you sorted by
*/
- public function sort( $functionCallback )
+ public function sort( $functionCallback, $columnSortedBy )
{
$this->indexNotUpToDate = true;
+ $this->tableSortedBy = $columnSortedBy;
usort( $this->rows, $functionCallback );
if($this->enableRecursiveSort === true)
@@ -232,12 +241,17 @@ class Piwik_DataTable
{
$table = Piwik_DataTable_Manager::getInstance()->getTable($idSubtable);
$table->enableRecursiveSort();
- $table->sort($functionCallback);
+ $table->sort($functionCallback, $columnSortedBy);
}
}
}
}
+ public function getSortedByColumnName()
+ {
+ return $this->tableSortedBy;
+ }
+
/**
* Enables the recursive sort. Means that when using $table->sort()
* it will also sort all subtables using the same callback
@@ -734,6 +748,7 @@ class Piwik_DataTable
* serialized DataTable contained in this DataTable.
* We save DataTable in serialized format in the Database.
* Each row of this returned PHP array will be a row in the DB table.
+ * At the end of the method execution, the dataTable may be truncated (if $maximum* parameters are set).
*
* The keys of the array are very important as they are used to define the DataTable
*
@@ -771,7 +786,6 @@ class Piwik_DataTable
{
throw new Exception("Maximum recursion level of ".self::MAXIMUM_DEPTH_LEVEL_ALLOWED. " reached. You have probably set a DataTable_Row with an associated DataTable which belongs already to its parent hierarchy.");
}
-
if( !is_null($maximumRowsInDataTable) )
{
$filter = new Piwik_DataTable_Filter_AddSummaryRow($this, $maximumRowsInDataTable - 1);
@@ -779,7 +793,7 @@ class Piwik_DataTable
// For each row, get the serialized row
// If it is associated to a sub table, get the serialized table recursively ;
- // but returns all serialized tables and subtable in an array of 1 dimension!
+ // but returns all serialized tables and subtable in an array of 1 dimension
$aSerializedDataTable = array();
foreach($this->rows as $row)
{
@@ -814,7 +828,7 @@ class Piwik_DataTable
*
* The function creates all the necessary DataTable_Row
*
- * @param string Serialized string of a datatable
+ * @param string string of serialized datatable
* @return void
*/
public function addRowsFromSerializedArray( $stringSerialized )
@@ -1000,14 +1014,17 @@ class Piwik_DataTable
$cleanRow = array();
foreach($array as $label => $row)
{
+ // TODO I think this requirement is not true anymore:
// we make sure that the label column is first in the list!
- // important for the UI javascript mainly...
+ // important for the UI javascript mainly...
+
// array_merge doesn't work here as it reindex the numeric value
// see the test testMergeArray in PHP_Related.test.php
+ $cleanRow[Piwik_DataTable_Row::DATATABLE_ASSOCIATED] = null;
$cleanRow[Piwik_DataTable_Row::COLUMNS] = array('label' => $label) + $row;
if(!is_null($subtablePerLabel)
// some rows of this table don't have subtables
- // (for examplecase of the campaign without keywords )
+ // (for example case of campaigns without keywords)
&& isset($subtablePerLabel[$label])
)
{
diff --git a/core/DataTable/Filter.php b/core/DataTable/Filter.php
index de03b1cfec..46984d5426 100644
--- a/core/DataTable/Filter.php
+++ b/core/DataTable/Filter.php
@@ -59,4 +59,5 @@ require_once "DataTable/Filter/AddSummaryRow.php";
require_once "DataTable/Filter/ReplaceSummaryRowLabel.php";
require_once "DataTable/Filter/ExactMatch.php";
require_once "DataTable/Filter/SafeDecodeLabel.php";
-require_once "DataTable/Filter/AddColumnsWhenShowAllColumns.php";
+require_once "DataTable/Filter/AddColumnsWhenShowAllColumns.php";
+require_once "DataTable/Filter/UpdateColumnsWhenShowAllGoals.php";
diff --git a/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php b/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
index fd5810512e..7e5427570f 100644
--- a/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
+++ b/core/DataTable/Filter/AddColumnsWhenShowAllColumns.php
@@ -24,4 +24,5 @@ class Piwik_DataTable_Filter_AddColumnsWhenShowAllColumns extends Piwik_DataTabl
$row->addColumn('bounce_rate', $bounceRate);
}
}
-} \ No newline at end of file
+}
+
diff --git a/core/DataTable/Filter/AddSummaryRow.php b/core/DataTable/Filter/AddSummaryRow.php
index b8d956dd43..a62c5dc2da 100644
--- a/core/DataTable/Filter/AddSummaryRow.php
+++ b/core/DataTable/Filter/AddSummaryRow.php
@@ -43,7 +43,7 @@ class Piwik_DataTable_Filter_AddSummaryRow extends Piwik_DataTable_Filter
protected function filter()
{
$filter = new Piwik_DataTable_Filter_Sort($this->table, $this->columnToSortByBeforeTruncating, 'desc');
-
+
$rows = $this->table->getRows();
$count = $this->table->getRowsCount();
$newRow = new Piwik_DataTable_Row();
@@ -60,6 +60,7 @@ class Piwik_DataTable_Filter_AddSummaryRow extends Piwik_DataTable_Filter
$newRow->sumRow($rows[$i]);
}
}
+
$newRow->addColumn('label', $this->labelSummaryRow);
$filter = new Piwik_DataTable_Filter_Limit($this->table, 0, $this->startRowToSummarize);
$this->table->addSummaryRow($newRow);
diff --git a/core/DataTable/Filter/ExactMatch.php b/core/DataTable/Filter/ExactMatch.php
index 1027fc62a6..3f68658d61 100644
--- a/core/DataTable/Filter/ExactMatch.php
+++ b/core/DataTable/Filter/ExactMatch.php
@@ -1,52 +1,52 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_DataTable
- */
-
-/**
- * Delete all rows for which the given $columnToFilter do not equal $patternToSearch
- * This filter can be used on both integer and string columns.
- * You can pass an array of integers in $patternToSearch parameter.
- *
- * @package Piwik_DataTable
- * @subpackage Piwik_DataTable_Filter
- */
-class Piwik_DataTable_Filter_ExactMatch extends Piwik_DataTable_Filter
-{
- private $columnToFilter;
- private $patternToSearch;
-
- public function __construct( $table, $columnToFilter, $patternToSearch )
- {
- parent::__construct($table);
- $this->patternToSearch = $patternToSearch;
- $this->columnToFilter = $columnToFilter;
- $this->filter();
- }
-
- protected function filter()
- {
- foreach($this->table->getRows() as $key => $row)
- {
- if( is_array($this->patternToSearch) )
- {
- if( in_array($row->getColumn($this->columnToFilter), $this->patternToSearch) == false )
- {
- $this->table->deleteRow($key);
- }
- }
- else if( $row->getColumn($this->columnToFilter) != $this->patternToSearch )
- {
- $k = $row->getColumn($this->columnToFilter);
- $this->table->deleteRow($key);
- }
- }
- }
-}
-
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_DataTable
+ */
+
+/**
+ * Delete all rows for which the given $columnToFilter do not equal $patternToSearch
+ * This filter can be used on both integer and string columns.
+ * You can pass an array of integers in $patternToSearch parameter.
+ *
+ * @package Piwik_DataTable
+ * @subpackage Piwik_DataTable_Filter
+ */
+class Piwik_DataTable_Filter_ExactMatch extends Piwik_DataTable_Filter
+{
+ private $columnToFilter;
+ private $patternToSearch;
+
+ public function __construct( $table, $columnToFilter, $patternToSearch )
+ {
+ parent::__construct($table);
+ $this->patternToSearch = $patternToSearch;
+ $this->columnToFilter = $columnToFilter;
+ $this->filter();
+ }
+
+ protected function filter()
+ {
+ foreach($this->table->getRows() as $key => $row)
+ {
+ if( is_array($this->patternToSearch) )
+ {
+ if( in_array($row->getColumn($this->columnToFilter), $this->patternToSearch) == false )
+ {
+ $this->table->deleteRow($key);
+ }
+ }
+ else if( $row->getColumn($this->columnToFilter) != $this->patternToSearch )
+ {
+ $k = $row->getColumn($this->columnToFilter);
+ $this->table->deleteRow($key);
+ }
+ }
+ }
+}
+
diff --git a/core/DataTable/Filter/ExcludeLowPopulation.php b/core/DataTable/Filter/ExcludeLowPopulation.php
index cb038d6d78..94acd0baea 100644
--- a/core/DataTable/Filter/ExcludeLowPopulation.php
+++ b/core/DataTable/Filter/ExcludeLowPopulation.php
@@ -24,21 +24,29 @@ class Piwik_DataTable_Filter_ExcludeLowPopulation extends Piwik_DataTable_Filter
static public $minimumValue;
public function __construct( $table, $columnToFilter, $minimumValue )
{
+ parent::__construct($table);
$this->columnToFilter = $columnToFilter;
+
+ if($minimumValue == 0)
+ {
+ $minimumPercentageThreshold = 0.02;
+ $allValues = $this->table->getColumn($this->columnToFilter);
+ $sumValues = array_sum($allValues);
+ $minimumValue = $sumValues * $minimumPercentageThreshold;
+ }
self::$minimumValue = $minimumValue;
- parent::__construct($table);
- $this->filter();
+ if(self::$minimumValue > 1)
+ {
+ $this->filter();
+ }
}
function filter()
{
- $function = array("Piwik_DataTable_Filter_ExcludeLowPopulation",
- "excludeLowPopulation");
-
$filter = new Piwik_DataTable_Filter_ColumnCallbackDeleteRow(
$this->table,
$this->columnToFilter,
- $function
+ array("Piwik_DataTable_Filter_ExcludeLowPopulation", "excludeLowPopulation")
);
}
diff --git a/core/DataTable/Filter/Limit.php b/core/DataTable/Filter/Limit.php
index b292a39aeb..d59ba38e29 100644
--- a/core/DataTable/Filter/Limit.php
+++ b/core/DataTable/Filter/Limit.php
@@ -35,7 +35,6 @@ class Piwik_DataTable_Filter_Limit extends Piwik_DataTable_Filter
$limit = -1;
}
$this->limit = $limit;
-
$this->filter();
}
@@ -45,8 +44,10 @@ class Piwik_DataTable_Filter_Limit extends Piwik_DataTable_Filter
$rowsCount = $table->getRowsCount();
// we delete from 0 to offset
- $table->deleteRowsOffset( 0, $this->offset );
-
+ if($this->offset > 0)
+ {
+ $table->deleteRowsOffset( 0, $this->offset );
+ }
// at this point the array has offset less elements. We delete from limit to the end
if( $this->limit >= 0 )
{
diff --git a/core/DataTable/Filter/Pattern.php b/core/DataTable/Filter/Pattern.php
index 723e918ddc..0bc67c5a99 100644
--- a/core/DataTable/Filter/Pattern.php
+++ b/core/DataTable/Filter/Pattern.php
@@ -21,15 +21,28 @@ class Piwik_DataTable_Filter_Pattern extends Piwik_DataTable_Filter
{
private $columnToFilter;
private $patternToSearch;
+ private $patternToSearchQuoted;
public function __construct( $table, $columnToFilter, $patternToSearch )
{
parent::__construct($table);
$this->patternToSearch = $patternToSearch;
+ $this->patternToSearchQuoted = self::getPatternQuoted($patternToSearch);
$this->columnToFilter = $columnToFilter;
$this->filter();
}
+ static public function getPatternQuoted( $pattern )
+ {
+ return "/". preg_quote($pattern, '/') ."/";
+ }
+
+ static public function match($pattern, $patternQuoted, $string)
+ {
+ return preg_match($patternQuoted, $string) == 1
+ && stripos($string, $pattern) !== false;
+ }
+
protected function filter()
{
foreach($this->table->getRows() as $key => $row)
@@ -38,7 +51,7 @@ class Piwik_DataTable_Filter_Pattern extends Piwik_DataTable_Filter
// - negative search with -piwik
// - exact match with ""
// see (?!pattern) A subexpression that performs a negative lookahead search, which matches the search string at any point where a string not matching pattern begins.
- if( stripos($row->getColumn($this->columnToFilter), $this->patternToSearch) === false)
+ if( !self::match($this->patternToSearch, $this->patternToSearchQuoted, $row->getColumn($this->columnToFilter)))
{
$this->table->deleteRow($key);
}
diff --git a/core/DataTable/Filter/PatternRecursive.php b/core/DataTable/Filter/PatternRecursive.php
index a0743aa116..10a8bd4149 100644
--- a/core/DataTable/Filter/PatternRecursive.php
+++ b/core/DataTable/Filter/PatternRecursive.php
@@ -24,10 +24,13 @@ class Piwik_DataTable_Filter_PatternRecursive extends Piwik_DataTable_Filter
{
private $columnToFilter;
private $patternToSearch;
+ private $patternToSearchQuoted;
public function __construct( $table, $columnToFilter, $patternToSearch )
{
parent::__construct($table);
+ $this->patternToSearch = $patternToSearch;
+ $this->patternToSearchQuoted = Piwik_DataTable_Filter_Pattern::getPatternQuoted($patternToSearch);
$this->patternToSearch = $patternToSearch;//preg_quote($patternToSearch);
$this->columnToFilter = $columnToFilter;
$this->filter();
@@ -64,7 +67,7 @@ class Piwik_DataTable_Filter_PatternRecursive extends Piwik_DataTable_Filter
}
if( $patternNotFoundInChildren
- && (stripos($row->getColumn($this->columnToFilter), $this->patternToSearch) === false)
+ && !Piwik_DataTable_Filter_Pattern::match($this->patternToSearch, $this->patternToSearchQuoted, $row->getColumn($this->columnToFilter))
)
{
$table->deleteRow($key);
diff --git a/core/DataTable/Filter/ReplaceColumnNames.php b/core/DataTable/Filter/ReplaceColumnNames.php
index f1bc174c4a..8d25c960ac 100644
--- a/core/DataTable/Filter/ReplaceColumnNames.php
+++ b/core/DataTable/Filter/ReplaceColumnNames.php
@@ -55,7 +55,9 @@ class Piwik_DataTable_Filter_ReplaceColumnNames extends Piwik_DataTable_Filter
{
foreach($table->getRows() as $key => $row)
{
- $this->renameColumns($row);
+ $oldColumns = $row->getColumns();
+ $newColumns = $this->getRenamedColumns($oldColumns);
+ $row->setColumns( $newColumns );
try {
$subTable = Piwik_DataTable_Manager::getInstance()->getTable( $row->getIdSubDataTable() );
$this->filterTable($subTable);
@@ -65,18 +67,31 @@ class Piwik_DataTable_Filter_ReplaceColumnNames extends Piwik_DataTable_Filter
}
}
- protected function renameColumns($row)
+ protected function getRenamedColumns($columns)
{
- $columns = $row->getColumns();
- foreach($this->mappingToApply as $oldName => $newName)
+ $newColumns = array();
+ foreach($columns as $columnName => $columnValue)
{
- if(isset($columns[$oldName]))
+ if(isset(Piwik_Archive::$mappingFromIdToName[$columnName]))
{
- $columns[$newName] = $columns[$oldName];
- unset($columns[$oldName]);
+ $columnName = Piwik_Archive::$mappingFromIdToName[$columnName];
+ if($columnName == 'goals')
+ {
+ $newSubColumns = array();
+ foreach($columnValue as $idGoal => $goalValues)
+ {
+ foreach($goalValues as $id => $goalValue)
+ {
+ $subColumnName = Piwik_Archive::$mappingFromIdToNameGoal[$id];
+ $newSubColumns['idgoal='.$idGoal][$subColumnName] = $goalValue;
+ }
+ }
+ $columnValue = $newSubColumns;
+ }
}
+ $newColumns[$columnName] = $columnValue;
}
- $row->setColumns($columns);
+ return $newColumns;
}
}
diff --git a/core/DataTable/Filter/Sort.php b/core/DataTable/Filter/Sort.php
index 805a8ed28e..148bb5b6e1 100644
--- a/core/DataTable/Filter/Sort.php
+++ b/core/DataTable/Filter/Sort.php
@@ -85,6 +85,40 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
);
}
+ /**
+ * @param Piwik_DataTable_Row
+ */
+ protected function selectColumnToSort($row)
+ {
+ $value = $row->getColumn($this->columnToSort);
+ if($value !== false)
+ {
+ return $this->columnToSort;
+ }
+
+ // sorting by "nb_visits" but the index is Piwik_Archive::INDEX_NB_VISITS in the table
+ if(isset(Piwik_Archive::$mappingFromNameToId[$this->columnToSort]))
+ {
+ $column = Piwik_Archive::$mappingFromNameToId[$this->columnToSort];
+ $value = $row->getColumn($column);
+
+ if($value !== false)
+ {
+ return $column;
+ }
+ }
+
+ // eg. was previously sorted by revenue_per_visit, but this table
+ // doesn't have this column; defaults with nb_visits
+ $column = Piwik_Archive::INDEX_NB_VISITS;
+ $value = $row->getColumn($column);
+ if($value !== false)
+ {
+ return $column;
+ }
+
+ return false;
+ }
protected function filter()
{
if($this->table instanceof Piwik_DataTable_Simple)
@@ -97,26 +131,14 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
return;
}
$row = current($rows);
- $value = $row->getColumn($this->columnToSort);
+ $this->columnToSort = $this->selectColumnToSort($row);
- if($value === false)
+ if($this->columnToSort === false)
{
- if(!isset(Piwik_Archive::$mappingFromNameToId[$this->columnToSort]))
- {
- // we don't throw the exception because we sometimes export a DataTable without a column labelled '2'
- // and when the generic filters tries to sort by default using this column 2, this shouldnt raise an exception...
- //throw new Exception("The column to sort by '".$this->columnToSort."' is unknown in the row ". implode(array_keys($row->getColumns()), ','));
- return;
- }
- // case we are sorting by "nb_visits" but the column is still integer indexed
- $this->columnToSort = Piwik_Archive::$mappingFromNameToId[$this->columnToSort];
- $value = $row->getColumn($this->columnToSort);
- if($value === false)
- {
- return;
- }
+ return;
}
+ $value = $row->getColumn($this->columnToSort);
if( Piwik::isNumeric($value))
{
$methodToUse = "sort";
@@ -132,7 +154,7 @@ class Piwik_DataTable_Filter_Sort extends Piwik_DataTable_Filter
$methodToUse = "sortString";
}
}
- $this->table->sort( array($this,$methodToUse) );
+ $this->table->sort( array($this,$methodToUse), $this->columnToSort );
}
}
diff --git a/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php b/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php
new file mode 100644
index 0000000000..61ce48a8cc
--- /dev/null
+++ b/core/DataTable/Filter/UpdateColumnsWhenShowAllGoals.php
@@ -0,0 +1,115 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_DataTable
+ */
+
+/**
+ * @package Piwik_DataTable
+ * @subpackage Piwik_DataTable_Filter
+ */
+class Piwik_DataTable_Filter_UpdateColumnsWhenShowAllGoals extends Piwik_DataTable_Filter
+{
+ protected $mappingIdToNameGoal;
+
+ public function __construct( $table, $mappingToApply = null )
+ {
+ parent::__construct($table);
+ $this->mappingIdToNameGoal = Piwik_Archive::$mappingFromIdToNameGoal;
+ $this->filter();
+ }
+
+ protected function filter()
+ {
+ $invalidDivision = 'N/A';
+ $roundingPrecision = 2;
+ $expectedColumns = array();
+ foreach($this->table->getRows() as $key => $row)
+ {
+ $currentColumns = $row->getColumns();
+ $newColumns = array();
+
+ $nbVisits = 0;
+ // visits could be undefined when there is a convertion but no visit
+ if(isset($currentColumns[Piwik_Archive::INDEX_NB_VISITS]))
+ {
+ $nbVisits = $currentColumns[Piwik_Archive::INDEX_NB_VISITS];
+ }
+ $newColumns['nb_visits'] = $nbVisits;
+ $newColumns['label'] = $currentColumns['label'];
+
+ if(isset($currentColumns[Piwik_Archive::INDEX_GOALS]))
+ {
+ $nbVisitsConverted = $revenue = 0;
+ if(isset($currentColumns[Piwik_Archive::INDEX_NB_VISITS_CONVERTED]))
+ {
+ $nbVisitsConverted = $currentColumns[Piwik_Archive::INDEX_NB_VISITS_CONVERTED];
+ $revenue = $currentColumns[Piwik_Archive::INDEX_REVENUE];
+ }
+
+ if($nbVisitsConverted == 0)
+ {
+ $conversionRate = $invalidDivision;
+ }
+ else
+ {
+ $conversionRate = round(100 * $nbVisitsConverted / $nbVisits, $roundingPrecision);
+ }
+
+ if($nbVisits == 0)
+ {
+ $revenuePerVisit = $invalidDivision;
+ }
+ else
+ {
+ $revenuePerVisit = round( $revenue / $nbVisits, $roundingPrecision );
+ }
+ foreach($currentColumns[Piwik_Archive::INDEX_GOALS] as $goalId => $columnValue)
+ {
+ $name = 'goal_' . $goalId . '_conversion_rate';
+ if($nbVisits == 0)
+ {
+ $value = $invalidDivision;
+ }
+ else
+ {
+ $value = round(100 * $columnValue[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS] / $nbVisits, $roundingPrecision);
+ }
+ $newColumns[$name] = $value;
+ $expectedColumns[$name] = true;
+
+ $name = 'goal_' . $goalId . '_nb_conversions';
+ $newColumns[$name] = $columnValue[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS];
+ $expectedColumns[$name] = true;
+ }
+ $newColumns['revenue_per_visit'] = $revenuePerVisit;
+ $newColumns['goals_conversion_rate'] = $conversionRate;
+ }
+
+ $row->setColumns($newColumns);
+ }
+ $expectedColumns['revenue_per_visit'] = true;
+ $expectedColumns['goals_conversion_rate'] = true;
+
+ // make sure all goals values are set, 0 by default
+ // if no value then sorting would put at the end
+ $expectedColumns = array_keys($expectedColumns);
+ $rows = $this->table->getRows();
+ foreach($rows as &$row)
+ {
+ foreach($expectedColumns as $name)
+ {
+ if(false === $row->getColumn($name))
+ {
+ $row->addColumn($name, 0);
+ }
+ }
+ }
+ }
+}
+
diff --git a/core/DataTable/Manager.php b/core/DataTable/Manager.php
index 79b3c7c8a5..50ee38e486 100644
--- a/core/DataTable/Manager.php
+++ b/core/DataTable/Manager.php
@@ -40,7 +40,14 @@ class Piwik_DataTable_Manager
* @var array
*/
protected $tables = array();
-
+
+ /**
+ * Id of the last inserted table in the Manager
+ *
+ * @var int
+ */
+ protected $lastTableid = 0;
+
/**
* Add a DataTable to the registry
*
@@ -50,7 +57,8 @@ class Piwik_DataTable_Manager
public function addTable( $table )
{
$this->tables[] = $table;
- return count($this->tables) - 1;
+ $this->lastTableId++;
+ return $this->lastTableId - 1;
}
/**
@@ -78,6 +86,7 @@ class Piwik_DataTable_Manager
public function deleteAll()
{
$this->tables = array();
+ $this->lastTableId = 0;
}
/**
@@ -94,13 +103,29 @@ class Piwik_DataTable_Manager
}
/**
- * Returns the number of DataTable currently registered.
- *
- * @return int
+ * Debug only. Dumps all tables currently registered in the Manager
+ *
+ * @return void
*/
- public function count()
+ public function dumpAllTables()
{
- return count($this->tables);
+ echo "<hr>Piwik_DataTable_Manager->dumpAllTables()<br>";
+ foreach($this->tables as $id => $table)
+ {
+ if(!($table instanceof Piwik_DataTable ))
+ {
+ echo "Error table $id is not instance of datatable<br>";
+ var_dump($table);
+ }
+ else
+ {
+ echo "<hr>";
+ echo "Table (index=$id) TableId = ". $table->getId() . "<br>";
+ echo $table;
+ echo "<br>";
+ }
+ }
+ echo "<br>-- End Piwik_DataTable_Manager->dumpAllTables()<hr>";
}
}
diff --git a/core/DataTable/Renderer/Console.php b/core/DataTable/Renderer/Console.php
index 59ea9bc55f..d85a42dadf 100644
--- a/core/DataTable/Renderer/Console.php
+++ b/core/DataTable/Renderer/Console.php
@@ -75,6 +75,7 @@ class Piwik_DataTable_Renderer_Console extends Piwik_DataTable_Renderer
break;
}
if(is_string($value)) $value = "'$value'";
+ elseif(is_array($value)) $value = var_export($value, true);
$columns[] = "'$column' => $value";
}
@@ -87,10 +88,8 @@ class Piwik_DataTable_Renderer_Console extends Piwik_DataTable_Renderer
$metadata = array();
foreach($row->getMetadata() as $name => $value)
{
- if(is_string($value))
- {
- $value = "'$value'";
- }
+ if(is_string($value)) $value = "'$value'";
+ elseif(is_array($value)) $value = var_export($value, true);
$metadata[] = "'$name' => $value";
}
$metadata = implode(", ", $metadata);
diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php
index e686ba9023..d311981c51 100644
--- a/core/DataTable/Renderer/Csv.php
+++ b/core/DataTable/Renderer/Csv.php
@@ -132,11 +132,28 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
$columns = $row->getColumns();
foreach($columns as $name => $value)
{
- if(!isset($allColumns[$name]))
+ //goals => array( 'idgoal=1' =>array(..), 'idgoal=2' => array(..))
+ if(is_array($value))
+ {
+ foreach($value as $key => $subValues)
+ {
+ if(is_array($subValues))
+ {
+ foreach($subValues as $subKey => $subValue)
+ {
+ // goals_idgoal=1
+ $columnName = $name . "_" . $key . "_" . $subKey;
+ $allColumns[$columnName] = true;
+ $csvRow[$columnName] = $subValue;
+ }
+ }
+ }
+ }
+ else
{
$allColumns[$name] = true;
+ $csvRow[$name] = $value;
}
- $csvRow[$name] = $value;
}
if($this->exportMetadata)
diff --git a/core/DataTable/Renderer/Php.php b/core/DataTable/Renderer/Php.php
index 5e472d7519..fee43640f1 100644
--- a/core/DataTable/Renderer/Php.php
+++ b/core/DataTable/Renderer/Php.php
@@ -173,7 +173,7 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer
'columns' => $row->getColumns(),
'metadata' => $row->getMetadata(),
'idsubdatatable' => $row->getIdSubDataTable(),
- );
+ );
if($this->renderSubTables
&& $row->getIdSubDataTable() !== null)
diff --git a/core/DataTable/Renderer/Rss.php b/core/DataTable/Renderer/Rss.php
index 18574dfcd5..7f7efa1b23 100644
--- a/core/DataTable/Renderer/Rss.php
+++ b/core/DataTable/Renderer/Rss.php
@@ -97,7 +97,7 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
<lastBuildDate>$generationDate</lastBuildDate>";
return $header;
}
-
+
protected function renderDataTable($table)
{
@@ -110,7 +110,7 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
{
$table->deleteColumn('label');
}
-
+
$i = 1;
$tableStructure = array();
@@ -125,6 +125,12 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
{
foreach($row->getColumns() as $column => $value)
{
+ // for example, goals data is array: not supported in export RSS
+ // in the future we shall reuse ViewDataTable for html exports in RSS anyway
+ if(is_array($value))
+ {
+ continue;
+ }
$allColumns[$column] = true;
$tableStructure[$i][$column] = $value;
}
@@ -146,14 +152,14 @@ class Piwik_DataTable_Renderer_Rss extends Piwik_DataTable_Renderer
foreach($tableStructure as $row)
{
$html .= "\n\n<tr>";
- foreach($allColumns as $name => $toDisplay)
+ foreach($allColumns as $columnName => $toDisplay)
{
if($toDisplay !== false)
{
$value = "-";
- if(isset($row[$name]))
+ if(isset($row[$columnName]))
{
- $value = urldecode($row[$name]);
+ $value = urldecode($row[$columnName]);
}
$html .= "\n\t<td>$value</td>";
diff --git a/core/DataTable/Renderer/Xml.php b/core/DataTable/Renderer/Xml.php
index 425f506ae3..1b3a77866d 100644
--- a/core/DataTable/Renderer/Xml.php
+++ b/core/DataTable/Renderer/Xml.php
@@ -29,6 +29,7 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
function render()
{
+// var_dump($this->table);exit;
return $this->renderTable($this->table);
}
@@ -41,7 +42,7 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
protected function renderTable($table, $returnOnlyDataTableXml = false, $prefixLines = '')
{
$array = $this->getArrayFromDataTable($table);
-
+// var_dump($array);exit;
if($table instanceof Piwik_DataTable_Array)
{
$out = $this->renderDataTableArray($table, $array, $prefixLines);
@@ -235,9 +236,21 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer
protected function renderDataTable( $array, $prefixLine = "" )
{
$out = '';
- foreach($array as $row)
+ foreach($array as $rowId => $row)
{
- $out .= $prefixLine."\t<row>";
+ if(!is_array($row))
+ {
+ $value = $this->formatValue($row);
+ $out .= $prefixLine."\t\t<$rowId>".$value."</$rowId>\n";
+ continue;
+ }
+ $rowAttribute = '';
+ if(($equalFound = strstr($rowId, '=')) !== false)
+ {
+ $rowAttribute = explode('=', $rowId);
+ $rowAttribute = " " . $rowAttribute[0] . "='" . $rowAttribute[1] . "'";
+ }
+ $out .= $prefixLine."\t<row$rowAttribute>";
if(count($row) === 1
&& key($row) === 0)
diff --git a/core/DataTable/Row.php b/core/DataTable/Row.php
index 119eac3797..abc6aea288 100644
--- a/core/DataTable/Row.php
+++ b/core/DataTable/Row.php
@@ -107,16 +107,15 @@ class Piwik_DataTable_Row
foreach($this->getColumns() as $column => $value)
{
if(is_string($value)) $value = "'$value'";
+ elseif(is_array($value)) $value = var_export($value, true);
$columns[] = "'$column' => $value";
}
$columns = implode(", ", $columns);
$metadata = array();
foreach($this->getMetadata() as $name => $value)
{
- if(is_string($value))
- {
- $value = "'$value'";
- }
+ if(is_string($value)) $value = "'$value'";
+ elseif(is_array($value)) $value = var_export($value, true);
$metadata[] = "'$name' => $value";
}
$metadata = implode(", ", $metadata);
@@ -330,22 +329,51 @@ class Piwik_DataTable_Row
*/
public function sumRow( Piwik_DataTable_Row $rowToSum )
{
- foreach($rowToSum->getColumns() as $name => $value)
+ foreach($rowToSum->getColumns() as $columnToSumName => $columnToSumValue)
+ {
+ if($columnToSumName != 'label')
+ {
+ $thisColumnValue = $this->getColumn($columnToSumName);
+ $newValue = $this->sumRowArray($thisColumnValue, $columnToSumValue);
+ $this->setColumn( $columnToSumName, $newValue);
+ }
+ }
+ }
+
+ protected function sumRowArray( $thisColumnValue, $columnToSumValue )
+ {
+ $newValue = 0;
+ if(Piwik::isNumeric($columnToSumValue))
{
- if($name != 'label'
- && Piwik::isNumeric($value))
+ if($thisColumnValue === false)
{
- $current = $this->getColumn($name);
- if($current === false)
+ $thisColumnValue = 0;
+ }
+ $newValue = $thisColumnValue + $columnToSumValue;
+ }
+ elseif(is_array($columnToSumValue))
+ {
+ $newValue = array();
+ if($thisColumnValue == false)
+ {
+ $newValue = $columnToSumValue;
+ }
+ else
+ {
+ $newValue = $thisColumnValue;
+ foreach($columnToSumValue as $arrayIndex => $arrayValue)
{
- $current = 0;
+ if(!isset($newValue[$arrayIndex]))
+ {
+ $newValue[$arrayIndex] = false;
+ }
+ $newValue[$arrayIndex] = $this->sumRowArray($newValue[$arrayIndex], $arrayValue);
}
- $this->setColumn( $name, $current + $value);
}
}
+ return $newValue;
}
-
/**
* Helper function to test if two rows are equal.
*
@@ -363,11 +391,7 @@ class Piwik_DataTable_Row
//same columns
$cols1 = $row1->getColumns();
$cols2 = $row2->getColumns();
-
- uksort($cols1, 'strnatcasecmp');
- uksort($cols2, 'strnatcasecmp');
-
- if($cols1 != $cols2)
+ if(array_diff($cols1, $cols2) !== array_diff($cols2, $cols1))
{
return false;
}
diff --git a/core/Date.php b/core/Date.php
index 450682df68..efcc526da4 100644
--- a/core/Date.php
+++ b/core/Date.php
@@ -41,6 +41,18 @@ class Piwik_Date
return new Piwik_Date($dateString);
}
+ protected $timestamp = null;
+
+ /**
+ * Returns the unix timestamp of the date
+ *
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ return $this->timestamp;
+ }
+
/**
* Builds a Piwik_Date object
*
@@ -79,16 +91,6 @@ class Piwik_Date
}
/**
- * Returns the unix timestamp of the date
- *
- * @return int
- */
- public function getTimestamp()
- {
- return $this->timestamp;
- }
-
- /**
* Returns true if the current date is older than the given $date
*
* @param Piwik_Date $date
diff --git a/core/FrontController.php b/core/FrontController.php
index fcbba59e26..718f4e997c 100644
--- a/core/FrontController.php
+++ b/core/FrontController.php
@@ -23,11 +23,13 @@ require_once "Zend/Auth/Adapter/DbTable.php";
*/
require_once "Timer.php";
require_once "core/Piwik.php";
-require_once "API/APIable.php";
require_once "Access.php";
require_once "Auth.php";
require_once "API/Proxy.php";
+require_once "Archive.php";
require_once "Site.php";
+require_once "Date.php";
+require_once "DataTable.php";
require_once "Translate.php";
require_once "Mail.php";
require_once "Url.php";
@@ -140,7 +142,6 @@ class Piwik_FrontController
{
throw new Exception("Action $action not found in the controller $controllerClassName.");
}
-
try {
return call_user_func_array( array($controller, $action ), $parameters);
} catch(Piwik_Access_NoAccessException $e) {
diff --git a/core/Log.php b/core/Log.php
index 3291065e26..59f91c025b 100644
--- a/core/Log.php
+++ b/core/Log.php
@@ -52,7 +52,7 @@ abstract class Piwik_Log extends Zend_Log
function addWriteToFile()
{
$writerFile = new Zend_Log_Writer_Stream($this->logToFileFilename);
- Piwik::mkdir(Zend_Registry::get('config')->path->log);
+ Piwik_Common::mkdir(Zend_Registry::get('config')->path->log);
$writerFile->setFormatter( $this->fileFormatter );
$this->addWriter($writerFile);
}
diff --git a/core/Period/Range.php b/core/Period/Range.php
index 03c97d3e23..d2cfb8dcf9 100644
--- a/core/Period/Range.php
+++ b/core/Period/Range.php
@@ -131,7 +131,6 @@ class Piwik_Period_Range extends Piwik_Period
{
throw new Exception("The date '$this->strDate' is not a date range. Should have the following format: 'lastN' or 'previousN' or 'YYYY-MM-DD,YYYY-MM-DD'.");
}
-
$endSubperiod = Piwik_Period::factory($this->strPeriod, $endDate);
$arrayPeriods= array();
diff --git a/core/Piwik.php b/core/Piwik.php
index daa5dc2ba3..aafe16655a 100644
--- a/core/Piwik.php
+++ b/core/Piwik.php
@@ -34,31 +34,6 @@ class Piwik
);
/**
- * path without trailing slash
- */
- static public function createHtAccess( $path )
- {
- @file_put_contents($path . "/.htaccess", "Deny from all");
- }
-
- static public function mkdir( $path, $mode = 0755, $denyAccess = true )
- {
- if(!is_dir($path))
- {
- $directoryParent = Piwik::realpath(dirname($path));
- if( is_writable($directoryParent) )
- {
- mkdir($path, $mode, true);
- }
- }
-
- if($denyAccess)
- {
- Piwik::createHtAccess($path);
- }
- }
-
- /**
* Checks that the directories Piwik needs write access are actually writable
* Displays a nice error page if permissions are missing on some directories
*
@@ -72,7 +47,7 @@ class Piwik
$directoryList = '';
foreach($resultCheck as $dir => $bool)
{
- $realpath = Piwik::realpath($dir);
+ $realpath = Piwik_Common::realpath($dir);
if(!empty($realpath) && $bool === false)
{
$directoryList .= "<code>chmod 777 $realpath</code><br>";
@@ -100,7 +75,6 @@ class Piwik
if( $directoriesToCheck == null )
{
$directoriesToCheck = array(
- '/',
'/config',
'/tmp',
'/tmp/templates_c',
@@ -118,10 +92,10 @@ class Piwik
if(!file_exists($directoryToCheck))
{
- Piwik::mkdir($directoryToCheck, 0755, false);
+ Piwik_Common::mkdir($directoryToCheck, 0755, false);
}
- $directory = Piwik::realpath($directoryToCheck);
+ $directory = Piwik_Common::realpath($directoryToCheck);
$resultCheck[$directory] = false;
if($directory !== false // realpath() returns FALSE on failure
&& is_writable($directoryToCheck))
@@ -132,15 +106,6 @@ class Piwik
return $resultCheck;
}
- static public function realpath($path)
- {
- if (file_exists($path))
- {
- return realpath($path);
- }
- return $path;
- }
-
/**
* Returns the Javascript code to be inserted on every page to track
*
@@ -400,6 +365,23 @@ class Piwik
}
}
+ static public function getPrettySizeFromBytes($size)
+ {
+ $bytes = array('','K','M','G','T');
+ foreach($bytes as $val)
+ {
+ if($size > 1024)
+ {
+ $size = $size / 1024;
+ }
+ else
+ {
+ break;
+ }
+ }
+ return round($size, 1)." ".$val;
+ }
+
static public function isPhpCliMode()
{
return in_array(substr(php_sapi_name(), 0, 3), array('cgi', 'cli'));
@@ -407,7 +389,23 @@ class Piwik
static public function isNumeric($value)
{
- return !is_array($value) && ereg('^([-]{0,1}[0-9]{1,}[.]{0,1}[0-9]*)$', $value);
+ return is_numeric($value);
+ }
+
+ static public function getCurrency()
+ {
+ static $symbol = null;
+ if(is_null($symbol))
+ {
+ $symbol = Zend_Registry::get('config')->General->default_currency;
+ }
+ return $symbol;
+ }
+
+ static public function getPrettyMoney($value)
+ {
+ $symbol = self::getCurrency();
+ return sprintf("$symbol%.2f", $value);
}
static public function getPrettyTimeFromSeconds($numberOfSeconds)
@@ -515,6 +513,19 @@ class Piwik
)
",
+ 'goal' => " CREATE TABLE `{$prefixTables}goal` (
+ `idsite` int(11) NOT NULL,
+ `idgoal` int(11) NOT NULL,
+ `name` varchar(50) NOT NULL,
+ `match_attribute` varchar(20) NOT NULL,
+ `pattern` varchar(255) NOT NULL,
+ `pattern_type` varchar(10) NOT NULL,
+ `case_sensitive` tinyint(4) NOT NULL,
+ `revenue` float NOT NULL,
+ `deleted` tinyint(4) NOT NULL default '0',
+ PRIMARY KEY (`idsite`,`idgoal`)
+ )
+ ",
'logger_message' => "CREATE TABLE {$prefixTables}logger_message (
idlogger_message INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
@@ -585,6 +596,7 @@ class Piwik
visit_entry_idaction INTEGER(11) NOT NULL,
visit_total_actions SMALLINT(5) UNSIGNED NOT NULL,
visit_total_time SMALLINT(5) UNSIGNED NOT NULL,
+ visit_goal_converted TINYINT(1) NOT NULL,
referer_type INTEGER UNSIGNED NULL,
referer_name VARCHAR(70) NULL,
referer_url TEXT NOT NULL,
@@ -611,6 +623,30 @@ class Piwik
)
",
+ 'log_conversion' => "CREATE TABLE `{$prefixTables}log_conversion` (
+ `idvisit` int(10) unsigned NOT NULL,
+ `idsite` int(10) unsigned NOT NULL,
+ `visitor_idcookie` char(32) NOT NULL,
+ `server_time` datetime NOT NULL,
+ `visit_server_date` date NOT NULL,
+ `idaction` int(11) NOT NULL,
+ `idlink_va` int(11) NOT NULL,
+ `referer_idvisit` int(10) unsigned default NULL,
+ `referer_visit_server_date` date default NULL,
+ `referer_type` int(10) unsigned default NULL,
+ `referer_name` varchar(70) default NULL,
+ `referer_keyword` varchar(255) default NULL,
+ `visitor_returning` tinyint(1) NOT NULL,
+ `location_country` char(3) NOT NULL,
+ `location_continent` char(3) NOT NULL,
+ `url` text NOT NULL,
+ `idgoal` int(10) unsigned NOT NULL,
+ `revenue` float default NULL,
+ PRIMARY KEY (`idvisit`,`idgoal`),
+ KEY `index_idsite_date` (`idsite`,`visit_server_date`)
+ )
+ ",
+
'log_link_visit_action' => "CREATE TABLE {$prefixTables}log_link_visit_action (
idlink_va INTEGER(11) NOT NULL AUTO_INCREMENT,
idvisit INTEGER(10) UNSIGNED NOT NULL,
@@ -647,7 +683,8 @@ class Piwik
period TINYINT UNSIGNED NULL,
ts_archived DATETIME NULL,
value FLOAT NULL,
- PRIMARY KEY(idarchive, name)
+ PRIMARY KEY(idarchive, name),
+ KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`)
)
",
'archive_blob' => "CREATE TABLE {$prefixTables}archive_blob (
@@ -659,7 +696,8 @@ class Piwik
period TINYINT UNSIGNED NULL,
ts_archived DATETIME NULL,
value MEDIUMBLOB NULL,
- PRIMARY KEY(idarchive, name)
+ PRIMARY KEY(idarchive, name),
+ KEY `index_all` (`idsite`,`date1`,`date2`,`name`,`ts_archived`)
)
",
);
@@ -686,6 +724,13 @@ class Piwik
return Piwik_PluginsManager::getInstance()->getLoadedPlugin(Piwik::getModule());
}
+ /**
+ * Returns true if the current user is either the super user, or the user $theUser
+ * Used when modifying user preference: this usually requires super user or being the user itself.
+ *
+ * @param string $theUser
+ * @return bool
+ */
static public function isUserIsSuperUserOrTheUser( $theUser )
{
try{
@@ -696,7 +741,10 @@ class Piwik
}
}
- // Accessible either to the user itself
+ /**
+ * @param string $theUser
+ * @throws exception if the user is neither the super user nor the user $theUser
+ */
static public function checkUserIsSuperUserOrTheUser( $theUser )
{
try{
@@ -710,6 +758,10 @@ class Piwik
}
}
+ /**
+ * Returns true if the current user is the Super User
+ * @return bool
+ */
static public function isUserIsSuperUser()
{
try{
@@ -720,6 +772,10 @@ class Piwik
}
}
+ /**
+ * Helper method user to set the current as Super User.
+ * This should be used with great care as this gives the user all permissions.
+ */
static public function setUserIsSuperUser()
{
Zend_Registry::get('access')->setSuperUser();
@@ -760,6 +816,11 @@ class Piwik
Zend_Registry::get('access')->checkUserHasSomeAdminAccess();
}
+ static public function checkUserHasSomeViewAccess()
+ {
+ Zend_Registry::get('access')->checkUserHasSomeViewAccess();
+ }
+
static public function isUserHasViewAccess( $idSites )
{
try{
@@ -835,11 +896,13 @@ class Piwik
return false;
}
+ /**
+ * API was simplified in 0.2.27, but we maintain backward compatibility
+ * when calling Piwik::prefixTable
+ */
static public function prefixTable( $table )
{
- $config = Zend_Registry::get('config');
- $prefixTables = $config->database->tables_prefix;
- return $prefixTables . $table;
+ return Piwik_Common::prefixTable($table);
}
/**
@@ -1091,8 +1154,8 @@ class Piwik
static public function install()
{
- Piwik::mkdir(Zend_Registry::get('config')->smarty->compile_dir);
- Piwik::mkdir(Zend_Registry::get('config')->smarty->cache_dir);
+ Piwik_Common::mkdir(Zend_Registry::get('config')->smarty->compile_dir);
+ Piwik_Common::mkdir(Zend_Registry::get('config')->smarty->cache_dir);
}
static public function uninstall()
diff --git a/core/Plugin.php b/core/Plugin.php
index f606751736..de3e3a7f72 100644
--- a/core/Plugin.php
+++ b/core/Plugin.php
@@ -71,15 +71,6 @@ abstract class Piwik_Plugin
}
/**
- * Returns the names of the required plugins
- * @var array
- */
- public function getListRequiredPlugins()
- {
- return array();
- }
-
- /**
* Returns the plugin name
* @var string
*/
diff --git a/core/PluginsManager.php b/core/PluginsManager.php
index 60c4f42f7a..a27bd2c937 100644
--- a/core/PluginsManager.php
+++ b/core/PluginsManager.php
@@ -401,9 +401,7 @@ class Piwik_PluginsManager
}
/**
- * TODO horrible dirty hack because the Config class is not clean enough. Needs to rewrite the Config
- * __set and __get in a cleaner way, also see the __destruct which writes the configuration file.
- *
+ * TODO horrible dirty hack. Fix config class by merging both config files before reading.
* @return array
*/
public function getInstalledPluginsName()
diff --git a/core/SmartyPlugins/function.logoHtml.php b/core/SmartyPlugins/function.logoHtml.php
new file mode 100644
index 0000000000..85a57b02e3
--- /dev/null
+++ b/core/SmartyPlugins/function.logoHtml.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package SmartyPlugins
+ */
+
+function smarty_function_logoHtml($params, &$smarty)
+{
+ if(!isset($params['metadata']['logo']))
+ {
+ return;
+ }
+ $width = $height = $alt = '';
+ if(isset($params['metadata']['logoWidth']))
+ {
+ $width = "width=".$params['metadata']['logoWidth'];
+ }
+ if(isset($params['metadata']['logoHeight']))
+ {
+ $height = "height=".$params['metadata']['logoHeight'];
+ }
+ if(isset($params['alt']))
+ {
+ $alt = "title='".$params['alt']."' alt='".$params['alt']."'";
+ }
+ return " <img $alt $width $height src=".$params['metadata']['logo']." />";
+}
diff --git a/core/SmartyPlugins/function.url.php b/core/SmartyPlugins/function.url.php
index adadea3beb..a837a8459b 100644
--- a/core/SmartyPlugins/function.url.php
+++ b/core/SmartyPlugins/function.url.php
@@ -1,31 +1,31 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: function.url.php 525 2008-06-25 23:49:13Z matt $
- *
- * @package SmartyPlugins
- */
-
-require_once "Url.php";
-
-/**
- * Smarty {url} function plugin.
- * Generates a piwik URL with the specified parameters modified.
- *
- * Examples:
- * <pre>
- * {url module="API"} will rewrite the URL modifying the module GET parameter
- * {url module="API" method="getKeywords"} will rewrite the URL modifying the parameters module=API method=getKeywords
- * </pre>
- *
- * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
- * @param $name=$value of the parameters to modify in the generated URL
- * @return string Something like index.php?module=X&action=Y
- */
-function smarty_function_url($params, &$smarty)
-{
- return htmlspecialchars(Piwik_Url::getCurrentScriptName() . Piwik_Url::getCurrentQueryStringWithParametersModified( $params ));
-}
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: function.url.php 525 2008-06-25 23:49:13Z matt $
+ *
+ * @package SmartyPlugins
+ */
+
+require_once "Url.php";
+
+/**
+ * Smarty {url} function plugin.
+ * Generates a piwik URL with the specified parameters modified.
+ *
+ * Examples:
+ * <pre>
+ * {url module="API"} will rewrite the URL modifying the module GET parameter
+ * {url module="API" method="getKeywords"} will rewrite the URL modifying the parameters module=API method=getKeywords
+ * </pre>
+ *
+ * @see Piwik_Url::getCurrentQueryStringWithParametersModified()
+ * @param $name=$value of the parameters to modify in the generated URL
+ * @return string Something like index.php?module=X&action=Y
+ */
+function smarty_function_url($params, &$smarty)
+{
+ return htmlspecialchars(Piwik_Url::getCurrentScriptName() . Piwik_Url::getCurrentQueryStringWithParametersModified( $params ));
+}
diff --git a/core/Timer.php b/core/Timer.php
index 8e71b41ba5..07c2adbd01 100644
--- a/core/Timer.php
+++ b/core/Timer.php
@@ -15,36 +15,48 @@
*/
class Piwik_Timer
{
- private $m_Start;
+ private $timerStart;
+ private $memoryStart;
public function __construct()
{
- $this->m_Start = 0.0;
$this->init();
}
- private function getMicrotime()
- {
- list($micro_seconds, $seconds) = explode(" ", microtime());
- return ((float)$micro_seconds + (float)$seconds);
- }
-
public function init()
{
- $this->m_Start = $this->getMicrotime();
+ $this->timerStart = $this->getMicrotime();
+ $this->memoryStart = $this->getMemoryUsage();
}
- public function getTime($decimals = 2)
+ public function getTime($decimals = 3)
{
- return number_format($this->getMicrotime() - $this->m_Start, $decimals, '.', '');
+ return number_format($this->getMicrotime() - $this->timerStart, $decimals, '.', '');
}
- public function getTimeMs($decimals = 2)
+
+ public function getTimeMs($decimals = 3)
{
- return number_format(1000*($this->getMicrotime() - $this->m_Start), $decimals, '.', '');
+ return number_format(1000*($this->getMicrotime() - $this->timerStart), $decimals, '.', '');
}
+ public function getMemoryLeak()
+ {
+ return "Memory delta: ".Piwik::getPrettySizeFromBytes($this->getMemoryUsage() - $this->memoryStart);
+ }
+
public function __toString()
{
return "Time elapsed: ". $this->getTime() ."s";
}
+
+ private function getMicrotime()
+ {
+ list($micro_seconds, $seconds) = explode(" ", microtime());
+ return ((float)$micro_seconds + (float)$seconds);
+ }
+
+ private function getMemoryUsage()
+ {
+ return memory_get_usage();
+ }
}
diff --git a/core/Tracker.php b/core/Tracker.php
index 171871efe3..5c3b52e8a3 100644
--- a/core/Tracker.php
+++ b/core/Tracker.php
@@ -11,29 +11,10 @@
/**
* Class used by the logging script piwik.php called by the javascript tag.
- * Handles the visitor & his/her actions on the website, saves the data in the DB, saves information in the cookie, etc.
+ * Handles the visitor & his/her actions on the website, saves the data in the DB,
+ * saves information in the cookie, etc.
*
- * To maximise the performance of the logging module, we use different techniques.
- *
- * On the PHP-only side:
- * - minimize the number of external files included.
- * Ideally only one (the configuration file) in all the normal cases.
- * We load the Loggers only when an error occurs ; this error is logged in the DB/File/etc
- * depending on the loggers settings in the configuration file.
- * - we may have to include external classes but we try to include only very
- * simple code without any dependency, so that we could simply write a script
- * that would merge all this simple code into a big piwik.php file.
- *
- * On the Database-related side:
- * - write all the SQL queries without using any DB abstraction layer. Manual filtering of input values.
- * - minimize the number of SQL queries necessary to complete the algorithm.
- * - carefully index the tables used
- * - try to have fixed length rows
- *
- * [ - use a partitionning by date for the tables ]
- *
- * Configuration options for the statsLogEngine module:
- * - use_cookie ; defines if we try to get/set a cookie to help recognize a unique visitor
+ * We try to include as little files as possible (no dependency on 3rd party modules).
*
* @package Piwik_Tracker
*/
@@ -57,6 +38,12 @@ class Piwik_Tracker
const COOKIE_INDEX_TIMESTAMP_FIRST_ACTION = 3;
const COOKIE_INDEX_ID_VISIT = 4;
const COOKIE_INDEX_ID_LAST_ACTION = 5;
+ const COOKIE_INDEX_REFERER_ID_VISIT = 6;
+ const COOKIE_INDEX_REFERER_TIMESTAMP = 7;
+ const COOKIE_INDEX_REFERER_TYPE = 8;
+ const COOKIE_INDEX_REFERER_NAME = 9;
+ const COOKIE_INDEX_REFERER_KEYWORD = 10;
+ const COOKIE_INDEX_VISITOR_RETURNING = 11;
public function __construct() {}
@@ -68,15 +55,27 @@ class Piwik_Tracker
{
try {
self::connectDatabase();
+
$visit = $this->getNewVisitObject();
$visit->handle();
+ unset($visit);
} catch (PDOException $e) {
$this->setState(self::STATE_LOGGING_DISABLE);
- }
+ }
}
$this->end();
}
+ /**
+ * Returns the date in the "Y-m-d H:i:s" PHP format
+ * @return string
+ */
+ public static function getDatetimeFromTimestamp($timestamp)
+ {
+ return date("Y-m-d H:i:s", $timestamp);
+ }
+
+
protected function init()
{
$this->loadTrackerPlugins();
@@ -155,7 +154,10 @@ class Piwik_Tracker
self::$db = $db;
}
- public static function getDb()
+ /**
+ * @return Piwik_Tracker_Db
+ */
+ public static function getDatabase()
{
return self::$db;
}
@@ -188,7 +190,6 @@ class Piwik_Tracker
throw new Exception("The Visit object set in the plugin must implement Piwik_Tracker_Visit_Interface");
}
- $visit->setDb(self::$db);
return $visit;
}
diff --git a/core/Tracker/Action.php b/core/Tracker/Action.php
index a50baa06b4..6cc1c5ec34 100644
--- a/core/Tracker/Action.php
+++ b/core/Tracker/Action.php
@@ -16,7 +16,7 @@
* @package Piwik_Tracker
*/
interface Piwik_Tracker_Action_Interface {
- public function getActionId();
+ public function getIdAction();
public function record( $idVisit, $idRefererAction, $timeSpentRefererAction );
public function setIdSite( $idSite );
}
@@ -45,41 +45,38 @@ interface Piwik_Tracker_Action_Interface {
*/
class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
{
- private $actionName;
private $url;
- private $defaultActionName;
- private $nameDownloadOutlink;
private $idSite;
+ private $idLinkVisitAction;
+ private $finalActionName;
+ private $actionType;
+ private $idAction = null;
/**
* 3 types of action, Standard action / Download / Outlink click
*/
const TYPE_ACTION = 1;
- const TYPE_DOWNLOAD = 3;
const TYPE_OUTLINK = 2;
+ const TYPE_DOWNLOAD = 3;
+
+ protected function getDefaultActionName()
+ {
+ return Piwik_Tracker_Config::getInstance()->Tracker['default_action_name'];
+ }
/**
- * @param Piwik_Tracker_Db Database object to be used
+ * Returns URL of the page currently being tracked, or the file being downloaded, or the outlink being clicked
+ * @return string
*/
- function __construct( $db )
+ public function getUrl()
{
- $this->actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string');
-
- $downloadVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name'];
- $this->downloadUrl = Piwik_Common::getRequestVar( $downloadVariableName, '', 'string');
-
- $outlinkVariableName = Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name'];
- $this->outlinkUrl = Piwik_Common::getRequestVar( $outlinkVariableName, '', 'string');
-
- $nameVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_outlink_name_var'];
- $this->nameDownloadOutlink = Piwik_Common::getRequestVar( $nameVariableName, '', 'string');
-
- $this->url = Piwik_Common::getRequestVar( 'url', '', 'string');
- $this->db = $db;
- $this->defaultActionName = Piwik_Tracker_Config::getInstance()->Tracker['default_action_name'];
+ return $this->url;
}
-
+ public function getActionType()
+ {
+ return $this->actionType;
+ }
/**
* Returns the idaction of the current action name.
* This idaction is used in the visitor logging table to link the visit information
@@ -91,9 +88,12 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
*
* @return int Id action that is associated to this action name in the Actions table lookup
*/
- function getActionId()
+ function getIdAction()
{
- $this->loadActionId();
+ if(is_null($this->idAction))
+ {
+ $this->idAction = $this->loadActionId();
+ }
return $this->idAction;
}
@@ -116,16 +116,16 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
*/
public function record( $idVisit, $idRefererAction, $timeSpentRefererAction)
{
- $this->db->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".$this->db->prefixTable('log_link_visit_action')
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ".Piwik_Common::prefixTable('log_link_visit_action')
." (idvisit, idaction, idaction_ref, time_spent_ref_action) VALUES (?,?,?,?)",
- array($idVisit, $this->idAction, $idRefererAction, $timeSpentRefererAction)
+ array($idVisit, $this->getIdAction(), $idRefererAction, $timeSpentRefererAction)
);
- $idLinkVisitAction = $this->db->lastInsertId();
+ $this->idLinkVisitAction = Piwik_Tracker::getDatabase()->lastInsertId();
$info = array(
'idSite' => $this->idSite,
- 'idLinkVistAction' => $idLinkVisitAction,
+ 'idLinkVisitAction' => $this->idLinkVisitAction,
'idVisit' => $idVisit,
'idRefererAction' => $idRefererAction,
'timeSpentRefererAction' => $timeSpentRefererAction,
@@ -137,6 +137,16 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
Piwik_PostEvent('Tracker.Action.record', $this, $info);
}
+ /**
+ * Returns the ID of the newly created record in the log_link_visit_action table
+ *
+ * @return int | false
+ */
+ public function getIdLinkVisitAction()
+ {
+ return $this->idLinkVisitAction;
+ }
+
/**
* Generates the name of the action from the URL or the specified name.
* Sets the name as $this->finalActionName
@@ -146,34 +156,44 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
private function generateInfo()
{
$actionName = '';
- if(!empty($this->downloadUrl))
+
+ $downloadVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_url_var_name'];
+ $downloadUrl = Piwik_Common::getRequestVar( $downloadVariableName, '', 'string');
+
+ if(!empty($downloadUrl))
{
$this->actionType = self::TYPE_DOWNLOAD;
- $url = $this->downloadUrl;
- //$actionName = $this->nameDownloadOutlink;
+ $url = $downloadUrl;
$actionName = $url;
}
- elseif(!empty($this->outlinkUrl))
+ else
{
- $this->actionType = self::TYPE_OUTLINK;
- $url = $this->outlinkUrl;
- //remove the last '/' character if it's present
- if(substr($url,-1) == '/')
+ $outlinkVariableName = Piwik_Tracker_Config::getInstance()->Tracker['outlink_url_var_name'];
+ $outlinkUrl = Piwik_Common::getRequestVar( $outlinkVariableName, '', 'string');
+ if(!empty($outlinkUrl))
{
- $url = substr($url,0,-1);
+ $this->actionType = self::TYPE_OUTLINK;
+ $url = $outlinkUrl;
+ //remove the last '/' character if it's present
+ if(substr($url,-1) == '/')
+ {
+ $url = substr($url,0,-1);
+ }
+ $nameVariableName = Piwik_Tracker_Config::getInstance()->Tracker['download_outlink_name_var'];
+ $actionName = Piwik_Common::getRequestVar( $nameVariableName, '', 'string');
+ if( empty($actionName) )
+ {
+ $actionName = $url;
+ }
}
- $actionName = $this->nameDownloadOutlink;
- if( empty($actionName) )
+ else
{
- $actionName = $url;
+ $this->actionType = self::TYPE_ACTION;
+ $url = Piwik_Common::getRequestVar( 'url', '', 'string');
+ $actionName = Piwik_Common::getRequestVar( 'action_name', '', 'string');
}
}
- else
- {
- $this->actionType = self::TYPE_ACTION;
- $url = $this->url;
- $actionName = $this->actionName;
- }
+ $this->url = $url;
// the ActionName wasn't specified
if( empty($actionName) )
@@ -188,7 +208,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
&& $actionName[strlen($actionName)-1] == '/'
)
{
- $actionName.=$this->defaultActionName;
+ $actionName .= $this->getDefaultActionName();
}
}
@@ -224,7 +244,7 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
if(empty($actionName))
{
- $actionName = $this->defaultActionName;
+ $actionName = $this->getDefaultActionName();
}
$this->finalActionName = $actionName;
@@ -233,17 +253,17 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
/**
* Sets the attribute $idAction based on $finalActionName and $actionType.
*
- * @see getActionId()
+ * @see getIdAction()
*/
private function loadActionId()
- {
+ {
$this->generateInfo();
$name = $this->finalActionName;
$type = $this->actionType;
- $idAction = $this->db->fetch("/* SHARDING_ID_SITE = ".$this->idSite." */ SELECT idaction
- FROM ".$this->db->prefixTable('log_action')
+ $idAction = Piwik_Tracker::getDatabase()->fetch("/* SHARDING_ID_SITE = ".$this->idSite." */ SELECT idaction
+ FROM ".Piwik_Common::prefixTable('log_action')
." WHERE name = ? AND type = ?",
array($name, $type)
);
@@ -251,16 +271,18 @@ class Piwik_Tracker_Action implements Piwik_Tracker_Action_Interface
// the action name has not been found, create it
if($idAction === false)
{
- $this->db->query("/* SHARDING_ID_SITE = ".$this->idSite." */ INSERT INTO ". $this->db->prefixTable('log_action'). "( name, type )
- VALUES (?,?)",array($name,$type) );
- $idAction = $this->db->lastInsertId();
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ".$this->idSite." */
+ INSERT INTO ". Piwik_Common::prefixTable('log_action'). "( name, type )
+ VALUES (?,?)",
+ array($name,$type)
+ );
+ $idAction = Piwik_Tracker::getDatabase()->lastInsertId();
}
else
{
$idAction = $idAction['idaction'];
}
-
- $this->idAction = $idAction;
+ return $idAction;
}
}
diff --git a/core/Tracker/Db.php b/core/Tracker/Db.php
index 13d23d1a26..b9a5be2978 100644
--- a/core/Tracker/Db.php
+++ b/core/Tracker/Db.php
@@ -110,21 +110,6 @@ class Piwik_Tracker_Db
}
$this->connection = null;
}
-
- /**
- * Returns the table name prefixed by the table prefix.
- *
- * @param string The table name to prefix, ie "log_visit"
- * @return string The table name prefixed, ie "piwik-production_log_visit"
- */
- static public function prefixTable( $suffix )
- {
- static $prefix;
- if (!isset($prefix)) {
- $prefix = Piwik_Tracker_Config::getInstance()->database['tables_prefix'];
- }
- return $prefix . $suffix;
- }
/**
* Returns an array containing all the rows of a query result, using optional bound parameters.
@@ -175,7 +160,7 @@ class Piwik_Tracker_Db
* Executes a query, using optional bound parameters.
*
* @param string Query
- * @param array Parameters to bind
+ * @param array|string Parameters to bind array('idsite'=> 1)
*
* @return PDOStatement or false if failed
* @throw Exception if an exception occured
@@ -192,6 +177,10 @@ class Piwik_Tracker_Db
$timer = $this->initProfiler();
}
+ if(!is_array($parameters))
+ {
+ $parameters = array( $parameters );
+ }
$sth = $this->connection->prepare($query);
$sth->execute( $parameters );
diff --git a/core/Tracker/Generator.php b/core/Tracker/Generator.php
index 0979b02fea..8a11a7028c 100644
--- a/core/Tracker/Generator.php
+++ b/core/Tracker/Generator.php
@@ -355,7 +355,6 @@ class Piwik_Tracker_Generator
for($i = 0; $i < $nbVisitors; $i++)
{
$nbActions = mt_rand(1, $nbActionsMaxPerVisit);
-
Piwik_Tracker_Generator_Visit::setTimestampToUse($this->getTimestampToUse());
$this->generateNewVisit();
@@ -364,7 +363,6 @@ class Piwik_Tracker_Generator
$this->generateActionVisit();
$this->saveVisit();
}
-
$nbActionsTotal += $nbActions;
}
return $nbActionsTotal;
@@ -655,6 +653,7 @@ class Piwik_Tracker_Generator
$this->setFakeRequest();
$process = new Piwik_Tracker_Generator_Tracker;
$process->main();
+ unset($process);
}
}
diff --git a/core/Tracker/Generator/Tracker.php b/core/Tracker/Generator/Tracker.php
index d4457c33fc..4344e2a515 100644
--- a/core/Tracker/Generator/Tracker.php
+++ b/core/Tracker/Generator/Tracker.php
@@ -47,7 +47,6 @@ class Piwik_Tracker_Generator_Tracker extends Piwik_Tracker
protected function getNewVisitObject()
{
$visit = new Piwik_Tracker_Generator_Visit();
- $visit->setDb(self::$db);
return $visit;
}
diff --git a/core/Tracker/Generator/Visit.php b/core/Tracker/Generator/Visit.php
index 41535f045c..533b0963f5 100644
--- a/core/Tracker/Generator/Visit.php
+++ b/core/Tracker/Generator/Visit.php
@@ -37,11 +37,6 @@ class Piwik_Tracker_Generator_Visit extends Piwik_Tracker_Visit
self::$timestampToUse += mt_rand(4,1840);
return self::$timestampToUse;
}
-
- protected function getDatetimeFromTimestamp($timestamp)
- {
- return date("Y-m-d H:i:s",$timestamp);
- }
protected function updateCookie()
{
@@ -49,3 +44,4 @@ class Piwik_Tracker_Generator_Visit extends Piwik_Tracker_Visit
}
}
+
diff --git a/core/Tracker/GoalManager.php b/core/Tracker/GoalManager.php
new file mode 100644
index 0000000000..d7f3b38726
--- /dev/null
+++ b/core/Tracker/GoalManager.php
@@ -0,0 +1,189 @@
+<?php
+
+class Piwik_Tracker_GoalManager
+{
+ /**
+ * @var Piwik_Cookie
+ */
+ protected $cookie = null;
+ /**
+ * @var Piwik_Tracker_Action
+ */
+ protected $action = null;
+ protected $matchedGoals = array();
+ protected $idsite = null;
+
+ function __construct($action)
+ {
+ $this->action = $action;
+
+
+ }
+
+ function setCookie($cookie)
+ {
+ $this->cookie = $cookie;
+ }
+
+ static public function getGoalDefinitions( $idSite )
+ {
+ $websiteAttributes = Piwik_Common::getCacheWebsiteAttributes( $idSite );
+ $goals = $websiteAttributes['goals'];
+ return $goals;
+ }
+
+ static public function getGoalDefinition( $idSite, $idGoal )
+ {
+ $goals = self::getGoalDefinitions( $idSite );
+ foreach($goals as $goal)
+ {
+ if($goal['idgoal'] == $idGoal)
+ {
+ return $goal;
+ }
+ }
+ throw new Exception("The goal id = $idGoal couldn't be found.");
+ }
+
+ static public function getGoalIds( $idSite )
+ {
+ $goals = self::getGoalDefinitions( $idSite );
+ $goalIds = array();
+ foreach($goals as $goal)
+ {
+ $goalIds[] = $goal['idgoal'];
+ }
+ return $goalIds;
+ }
+
+ //TODO does this code work for manually triggered goals, with custom revenue?
+ function detectGoals($idSite)
+ {
+ if(!Piwik_PluginsManager::getInstance()->isPluginActivated('Goals'))
+ {
+ return false;
+ }
+ $url = $this->action->getUrl();
+ $actionType = $this->action->getActionType();
+ $goals = $this->getGoalDefinitions($idSite);
+ foreach($goals as $goal)
+ {
+ $attribute = $goal['match_attribute'];
+ // if the attribute to match is not the type of the current action
+ if( ($actionType == Piwik_Tracker_Action::TYPE_ACTION && $attribute != 'url')
+ || ($actionType == Piwik_Tracker_Action::TYPE_DOWNLOAD && $attribute != 'file')
+ || ($actionType == Piwik_Tracker_Action::TYPE_OUTLINK && $attribute != 'external_website')
+ )
+ {
+ continue;
+ }
+
+ $pattern_type = $goal['pattern_type'];
+
+ switch($pattern_type)
+ {
+ case 'regex':
+ $pattern = '/' . $goal['pattern'] . '/';
+ if(!$goal['case_sensitive'])
+ {
+ $pattern .= 'i';
+ }
+ $match = (preg_match($pattern, $url) == 1);
+ break;
+ case 'contains':
+ if($goal['case_sensitive'])
+ {
+ $matched = strpos($url, $goal['pattern']);
+ }
+ else
+ {
+ $matched = stripos($url, $goal['pattern']);
+ }
+ $match = ($matched !== false);
+ break;
+ case 'exact':
+ if($goal['case_sensitive'])
+ {
+ $matched = strcmp($goal['pattern'], $url);
+ }
+ else
+ {
+ $matched = strcasecmp($goal['pattern'], $url);
+ }
+ $match = ($matched == 0);
+ break;
+ default:
+ throw new Exception("Pattern type $pattern_type not valid.");
+ break;
+ }
+ if($match)
+ {
+ $this->matchedGoals[] = $goal;
+ }
+ }
+// var_dump($this->matchedGoals);exit;
+ return count($this->matchedGoals) > 0;
+ }
+
+ function recordGoals($visitorInformation)
+ {
+ $location_country = isset($visitorInformation['location_country']) ? $visitorInformation['location_country'] : Piwik_Common::getCountry(Piwik_Common::getBrowserLanguage());
+ $location_continent = isset($visitorInformation['location_continent']) ? $visitorInformation['location_continent'] : Piwik_Common::getContinent($location_country);
+
+ $goal = array(
+ 'idvisit' => $visitorInformation['idvisit'],
+ 'idsite' => $visitorInformation['idsite'],
+ 'visitor_idcookie' => $visitorInformation['visitor_idcookie'],
+ 'server_time' => Piwik_Tracker::getDatetimeFromTimestamp($visitorInformation['visit_last_action_time']),
+ 'visit_server_date' => $visitorInformation['visit_server_date'],
+ 'idaction' => $this->action->getIdAction(),
+ 'idlink_va' => $this->action->getIdLinkVisitAction(),
+ 'location_country' => $location_country,
+ 'location_continent'=> $location_continent,
+ 'url' => $this->action->getUrl(),
+ 'visitor_returning' => $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_VISITOR_RETURNING ),
+ );
+
+ $referer_idvisit = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_ID_VISIT );
+ if($referer_idvisit !== false)
+ {
+ $goal += array(
+ 'referer_idvisit' => $referer_idvisit,
+ 'referer_visit_server_date' => date("Y-m-d", $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TIMESTAMP )),
+ 'referer_type' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE )),
+ 'referer_name' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_NAME )),
+ 'referer_keyword' => htmlspecialchars_decode($this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_KEYWORD )),
+ );
+ }
+
+ foreach($this->matchedGoals as $matchedGoal)
+ {
+ printDebug("- Goal ".$matchedGoal['idgoal'] ." matched. Recording...");
+ $newGoal = $goal;
+ $newGoal['idgoal'] = $matchedGoal['idgoal'];
+ $newGoal['revenue'] = $matchedGoal['revenue'];
+ printDebug($newGoal);
+
+ $fields = implode(", ", array_keys($newGoal));
+ $bindFields = substr(str_repeat( "?,",count($newGoal)),0,-1);
+
+ try {
+ Piwik_Tracker::getDatabase()->query(
+ "INSERT INTO " . Piwik_Common::prefixTable('log_conversion') . " ($fields)
+ VALUES ($bindFields) ", array_values($newGoal)
+ );
+ } catch( Exception $e) {
+ if(strpos($e->getMessage(), '1062') !== false)
+ {
+ // integrity violation when same visit converts to the same goal twice
+ printDebug("--> Goal already recorded for this (idvisit, idgoal)");
+ }
+ else
+ {
+ throw $e;
+ }
+ }
+ //$idlog_goal = Piwik_Tracker::getDatabase()->lastInsertId();
+ }
+ }
+} \ No newline at end of file
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index d7bcc8832d..f0aad50f95 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -12,7 +12,6 @@
interface Piwik_Tracker_Visit_Interface {
function handle();
- function setDb($db);
}
/**
@@ -31,11 +30,14 @@ interface Piwik_Tracker_Visit_Interface {
class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
- protected $cookieLog = null;
+ /**
+ * @var Piwik_Cookie
+ */
+ protected $cookie = null;
protected $visitorInfo = array();
protected $userSettingsInformation = null;
- protected $db = null;
protected $idsite;
+ protected $visitorKnown;
function __construct()
{
@@ -48,9 +50,203 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
$this->idsite = $idsite;
}
- public function setDb($db)
+ /**
+ * Main algorith to handle the visit.
+ *
+ * Once we have the visitor information, we have to define if the visit is a new or a known visit.
+ *
+ * 1) When the last action was done more than 30min ago,
+ * or if the visitor is new, then this is a new visit.
+ *
+ * 2) If the last action is less than 30min ago, then the same visit is going on.
+ * Because the visit goes on, we can get the time spent during the last action.
+ *
+ * NB:
+ * - In the case of a new visit, then the time spent
+ * during the last action of the previous visit is unknown.
+ *
+ * - In the case of a new visit but with a known visitor,
+ * we can set the 'returning visitor' flag.
+ *
+ * In all the cases we set a cookie to the visitor with the new information.
+ */
+ public function handle()
+ {
+ if($this->isExcluded())
+ {
+ return;
+ }
+
+ // current action
+ $action = $this->newAction();
+ $actionId = $action->getIdAction();
+
+ // goal matched?
+ $goalManager = new Piwik_Tracker_GoalManager( $action );
+ $someGoalsConverted = false;
+ if($goalManager->detectGoals($this->idsite))
+ {
+ $someGoalsConverted = true;
+ }
+
+ // the visitor and session
+ $this->recognizeTheVisitor();
+ if( $this->isVisitorKnown()
+ && $this->isLastActionInTheSameVisit())
+ {
+ $this->handleKnownVisit($actionId, $someGoalsConverted);
+ $action->record( $this->visitorInfo['idvisit'],
+ $this->visitorInfo['visit_exit_idaction'],
+ $this->visitorInfo['time_spent_ref_action']
+ );
+ }
+ else
+ {
+ $this->handleNewVisit($actionId, $someGoalsConverted);
+ $action->record( $this->visitorInfo['idvisit'], 0, 0 );
+ }
+
+ // update the cookie with the new visit information
+ $this->updateCookie();
+
+ // record the goals if applicable
+ if($someGoalsConverted)
+ {
+ $goalManager->setCookie($this->cookie);
+ $goalManager->recordGoals($this->visitorInfo);
+ }
+ unset($goalManager);
+ unset($action);
+ }
+
+
+ /**
+ * In the case of a known visit, we have to do the following actions:
+ *
+ * 1) Insert the new action
+ *
+ * 2) Update the visit information
+ */
+ protected function handleKnownVisit($actionId, $someGoalsConverted)
+ {
+ printDebug("Visit known.");
+ $serverTime = $this->getCurrentTimestamp();
+ $datetimeServer = Piwik_Tracker::getDatetimeFromTimestamp($serverTime);
+
+ $sqlUpdateGoalConverted = '';
+ if($someGoalsConverted)
+ {
+ $sqlUpdateGoalConverted = " visit_goal_converted = 1,";
+ }
+
+ Piwik_Tracker::getDatabase()->query("/* SHARDING_ID_SITE = ". $this->idsite ." */
+ UPDATE ". Piwik_Common::prefixTable('log_visit')."
+ SET visit_last_action_time = ?,
+ visit_exit_idaction = ?,
+ visit_total_actions = visit_total_actions + 1,
+ $sqlUpdateGoalConverted
+ visit_total_time = UNIX_TIMESTAMP(visit_last_action_time) - UNIX_TIMESTAMP(visit_first_action_time)
+ WHERE idvisit = ?
+ LIMIT 1",
+ array( $datetimeServer,
+ $actionId,
+ $this->visitorInfo['idvisit'] )
+ );
+ $this->visitorInfo['idsite'] = $this->idsite;
+ $this->visitorInfo['visit_server_date'] = $this->getCurrentDate();
+
+ // will be updated in cookie
+ $this->visitorInfo['visit_last_action_time'] = $serverTime;
+ $this->visitorInfo['visit_exit_idaction'] = $actionId;
+ $this->visitorInfo['time_spent_ref_action'] = $serverTime - $this->visitorInfo['visit_last_action_time'];
+ }
+
+ /**
+ * In the case of a new visit, we have to do the following actions:
+ *
+ * 1) Insert the new action
+ *
+ * 2) Insert the visit information
+ */
+ protected function handleNewVisit($actionId, $someGoalsConverted)
{
- $this->db = $db;
+ printDebug("New Visit.");
+
+ $localTime = Piwik_Common::getRequestVar( 'h', $this->getCurrentDate("H"), 'numeric')
+ .':'. Piwik_Common::getRequestVar( 'm', $this->getCurrentDate("i"), 'numeric')
+ .':'. Piwik_Common::getRequestVar( 's', $this->getCurrentDate("s"), 'numeric');
+ $serverTime = $this->getCurrentTimestamp();
+ $serverDate = $this->getCurrentDate();
+
+ if($this->isVisitorKnown())
+ {
+ $idcookie = $this->visitorInfo['visitor_idcookie'];
+ $returningVisitor = 1;
+ }
+ else
+ {
+ $idcookie = $this->getVisitorUniqueId();
+ $returningVisitor = 0;
+ }
+
+ $defaultTimeOnePageVisit = Piwik_Tracker_Config::getInstance()->Tracker['default_time_one_page_visit'];
+
+ $userInfo = $this->getUserSettingsInformation();
+ $country = Piwik_Common::getCountry($userInfo['location_browser_lang']);
+ $refererInfo = $this->getRefererInformation();
+
+ /**
+ * Save the visitor
+ */
+ $this->visitorInfo = array(
+ 'idsite' => $this->idsite,
+ 'visitor_localtime' => $localTime,
+ 'visitor_idcookie' => $idcookie,
+ 'visitor_returning' => $returningVisitor,
+ 'visit_first_action_time' => Piwik_Tracker::getDatetimeFromTimestamp($serverTime),
+ 'visit_last_action_time' => Piwik_Tracker::getDatetimeFromTimestamp($serverTime),
+ 'visit_server_date' => $serverDate,
+ 'visit_entry_idaction' => $actionId,
+ 'visit_exit_idaction' => $actionId,
+ 'visit_total_actions' => 1,
+ 'visit_total_time' => $defaultTimeOnePageVisit,
+ 'visit_goal_converted' => $someGoalsConverted ? 1: 0,
+ 'referer_type' => $refererInfo['referer_type'],
+ 'referer_name' => $refererInfo['referer_name'],
+ 'referer_url' => $refererInfo['referer_url'],
+ 'referer_keyword' => $refererInfo['referer_keyword'],
+ 'config_md5config' => $userInfo['config_md5config'],
+ 'config_os' => $userInfo['config_os'],
+ 'config_browser_name' => $userInfo['config_browser_name'],
+ 'config_browser_version' => $userInfo['config_browser_version'],
+ 'config_resolution' => $userInfo['config_resolution'],
+ 'config_pdf' => $userInfo['config_pdf'],
+ 'config_flash' => $userInfo['config_flash'],
+ 'config_java' => $userInfo['config_java'],
+ 'config_director' => $userInfo['config_director'],
+ 'config_quicktime' => $userInfo['config_quicktime'],
+ 'config_realplayer' => $userInfo['config_realplayer'],
+ 'config_windowsmedia' => $userInfo['config_windowsmedia'],
+ 'config_cookie' => $userInfo['config_cookie'],
+ 'location_ip' => $userInfo['location_ip'],
+ 'location_browser_lang' => $userInfo['location_browser_lang'],
+ 'location_country' => $country
+ );
+
+ Piwik_PostEvent('Tracker.newVisitorInformation', $this->visitorInfo);
+ $this->visitorInfo['location_continent'] = Piwik_Common::getContinent( $this->visitorInfo['location_country'] );
+
+ $fields = implode(", ", array_keys($this->visitorInfo));
+ $values = substr(str_repeat( "?,",count($this->visitorInfo)),0,-1);
+
+ Piwik_Tracker::getDatabase()->query( "INSERT INTO ".Piwik_Common::prefixTable('log_visit').
+ " ($fields) VALUES ($values)", array_values($this->visitorInfo));
+
+ $idVisit = Piwik_Tracker::getDatabase()->lastInsertId();
+
+ $this->visitorInfo['idvisit'] = $idVisit;
+ $this->visitorInfo['visit_first_action_time'] = $serverTime;
+ $this->visitorInfo['visit_last_action_time'] = $serverTime;
}
/**
@@ -70,15 +266,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
return time();
}
-
- /**
- * Returns the date in the "Y-m-d H:i:s" PHP format
- * @return string
- */
- protected function getDatetimeFromTimestamp($timestamp)
- {
- return date("Y-m-d H:i:s", $timestamp);
- }
/**
* Test if the current visitor is excluded from the statistics.
@@ -144,19 +331,18 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
protected function recognizeTheVisitor()
{
$this->visitorKnown = false;
+ $this->cookie = new Piwik_Cookie( $this->getCookieName() );
- $this->cookieLog = new Piwik_Cookie( $this->getCookieName() );
/*
* Case the visitor has the piwik cookie.
* We make sure all the data that should saved in the cookie is available.
*/
-
- if( false !== ($idVisitor = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_IDVISITOR )) )
+ if( false !== ($idVisitor = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_IDVISITOR )) )
{
- $timestampLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION );
- $timestampFirstAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION );
- $idVisit = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_VISIT );
- $idLastAction = $this->cookieLog->get( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION );
+ $timestampLastAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION );
+ $timestampFirstAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION );
+ $idVisit = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_ID_VISIT );
+ $idLastAction = $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION );
if( $timestampLastAction !== false && is_numeric($timestampLastAction)
&& $timestampFirstAction !== false && is_numeric($timestampFirstAction)
@@ -177,21 +363,22 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
}
/*
- * If the visitor doesn't have the piwik cookie, we look for a visitor that has exactly the same configuration
- * and that visited the website today.
+ * If the visitor doesn't have the piwik cookie, we look for a visitor
+ * that has exactly the same configuration and that visited the website today.
*/
- if( !$this->visitorKnown )
+ if( !$this->visitorKnown
+ && Piwik_Tracker_Config::getInstance()->Tracker['enable_detect_unique_visitor_using_settings'])
{
$userInfo = $this->getUserSettingsInformation();
$md5Config = $userInfo['config_md5config'];
- $visitRow = $this->db->fetch(
+ $visitRow = Piwik_Tracker::getDatabase()->fetch(
" SELECT visitor_idcookie,
UNIX_TIMESTAMP(visit_last_action_time) as visit_last_action_time,
UNIX_TIMESTAMP(visit_first_action_time) as visit_first_action_time,
idvisit,
visit_exit_idaction
- FROM ".$this->db->prefixTable('log_visit').
+ FROM ".Piwik_Common::prefixTable('log_visit').
" WHERE visit_server_date = ?
AND idsite = ?
AND config_md5config = ?
@@ -226,8 +413,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
return $this->userSettingsInformation;
}
-
-
$plugin_Flash = Piwik_Common::getRequestVar( 'fla', 0, 'int');
$plugin_Director = Piwik_Common::getRequestVar( 'dir', 0, 'int');
$plugin_Quicktime = Piwik_Common::getRequestVar( 'qt', 0, 'int');
@@ -249,7 +434,7 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
$ip = Piwik_Common::getIp();
$ip = ip2long($ip);
- $browserLang = substr(Piwik_Common::getBrowserLanguage(), 0, 20);
+ $browserLang = Piwik_Common::getBrowserLanguage();
$configurationHash = $this->getConfigHash(
$os,
@@ -305,47 +490,6 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
return $this->visitorKnown === true;
}
- /**
- * Main algorith to handle the visit.
- *
- * Once we have the visitor information, we have to define if the visit is a new or a known visit.
- *
- * 1) When the last action was done more than 30min ago,
- * or if the visitor is new, then this is a new visit.
- *
- * 2) If the last action is less than 30min ago, then the same visit is going on.
- * Because the visit goes on, we can get the time spent during the last action.
- *
- * NB:
- * - In the case of a new visit, then the time spent
- * during the last action of the previous visit is unknown.
- *
- * - In the case of a new visit but with a known visitor,
- * we can set the 'returning visitor' flag.
- *
- * In all the cases we set a cookie to the visitor with the new information.
- */
- public function handle()
- {
- if($this->isExcluded())
- {
- return;
- }
-
- $this->recognizeTheVisitor();
- if( $this->isVisitorKnown()
- && $this->isLastActionInTheSameVisit())
- {
- $this->handleKnownVisit();
- }
- else
- {
- $this->handleNewVisit();
- }
-
- // we update the cookie with the new visit information
- $this->updateCookie();
- }
/**
* Update the cookie information.
@@ -354,190 +498,50 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
{
printDebug("We manage the cookie...");
+ if( isset($this->visitorInfo['referer_type'])
+ && $this->visitorInfo['referer_type'] != Piwik_Common::REFERER_TYPE_DIRECT_ENTRY)
+ {
+ // if the setting is set to use only the first referer,
+ // we don't update the cookie referer values if they are already set
+ if( !Piwik_Tracker_Config::getInstance()->Tracker['use_first_referer_to_determine_goal_referer']
+ || $this->cookie->get( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE ) == false)
+ {
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_TYPE, $this->visitorInfo['referer_type']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_NAME, $this->visitorInfo['referer_name']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_KEYWORD, $this->visitorInfo['referer_keyword']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_ID_VISIT, $this->visitorInfo['idvisit']);
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_REFERER_TIMESTAMP, $this->getCurrentTimestamp()) ;
+ }
+ }
+
// idcookie has been generated in handleNewVisit or we simply propagate the old value
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_IDVISITOR,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_IDVISITOR,
$this->visitorInfo['visitor_idcookie'] );
// the last action timestamp is the current timestamp
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_LAST_ACTION,
$this->visitorInfo['visit_last_action_time'] );
// the first action timestamp is the timestamp of the first action of the current visit
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_TIMESTAMP_FIRST_ACTION,
$this->visitorInfo['visit_first_action_time'] );
// the idvisit has been generated by mysql in handleNewVisit or simply propagated here
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_ID_VISIT,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_ID_VISIT,
$this->visitorInfo['idvisit'] );
// the last action ID is the current exit idaction
- $this->cookieLog->set( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION,
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_ID_LAST_ACTION,
$this->visitorInfo['visit_exit_idaction'] );
-
- $this->cookieLog->save();
- }
-
-
- /**
- * In the case of a known visit, we have to do the following actions:
- *
- * 1) Insert the new action
- *
- * 2) Update the visit information
- */
- protected function handleKnownVisit()
- {
- printDebug("Visit known.");
-
- /**
- * Init the action
- */
- $action = $this->getActionObject();
- $actionId = $action->getActionId();
- printDebug("idAction = $actionId");
-
- $serverTime = $this->getCurrentTimestamp();
- $datetimeServer = $this->getDatetimeFromTimestamp($serverTime);
-
- $this->db->query("/* SHARDING_ID_SITE = ". $this->idsite ." */
- UPDATE ". $this->db->prefixTable('log_visit')."
- SET visit_last_action_time = ?,
- visit_exit_idaction = ?,
- visit_total_actions = visit_total_actions + 1,
- visit_total_time = UNIX_TIMESTAMP(visit_last_action_time) - UNIX_TIMESTAMP(visit_first_action_time)
- WHERE idvisit = ?
- LIMIT 1",
- array( $datetimeServer,
- $actionId,
- $this->visitorInfo['idvisit'] )
- );
- /**
- * Save the action
- */
- $timespentLastAction = $serverTime - $this->visitorInfo['visit_last_action_time'];
-
- $action->record( $this->visitorInfo['idvisit'],
- $this->visitorInfo['visit_exit_idaction'],
- $timespentLastAction
- );
-
-
- /**
- * Cookie fields to be updated
- */
- $this->visitorInfo['visit_last_action_time'] = $serverTime;
- $this->visitorInfo['visit_exit_idaction'] = $actionId;
-
- }
-
- /**
- * In the case of a new visit, we have to do the following actions:
- *
- * 1) Insert the new action
- *
- * 2) Insert the visit information
- */
- protected function handleNewVisit()
- {
- printDebug("New Visit.");
-
- /**
- * Get the variables from the REQUEST
- */
- $localTime = Piwik_Common::getRequestVar( 'h', $this->getCurrentDate("H"), 'numeric')
- .':'. Piwik_Common::getRequestVar( 'm', $this->getCurrentDate("i"), 'numeric')
- .':'. Piwik_Common::getRequestVar( 's', $this->getCurrentDate("s"), 'numeric');
-
- $serverTime = $this->getCurrentTimestamp();
- $serverDate = $this->getCurrentDate();
-
- if($this->isVisitorKnown())
- {
- $idcookie = $this->visitorInfo['visitor_idcookie'];
- $returningVisitor = 1;
- }
- else
+ // for a new visit, we flag the visit with visitor_returning
+ if(isset($this->visitorInfo['visitor_returning']))
{
- $idcookie = $this->getVisitorUniqueId();
- $returningVisitor = 0;
+ $this->cookie->set( Piwik_Tracker::COOKIE_INDEX_VISITOR_RETURNING,
+ $this->visitorInfo['visitor_returning'] );
}
- $defaultTimeOnePageVisit = Piwik_Tracker_Config::getInstance()->Tracker['default_time_one_page_visit'];
-
- $userInfo = $this->getUserSettingsInformation();
- $country = Piwik_Common::getCountry($userInfo['location_browser_lang']);
-
- $refererInfo = $this->getRefererInformation();
-
- /**
- * Init the action
- */
- $action = $this->getActionObject();
- $actionId = $action->getActionId();
-
- printDebug("idAction = $actionId");
-
-
- /**
- * Save the visitor
- */
- $informationToSave = array(
- 'idsite' => $this->idsite,
- 'visitor_localtime' => $localTime,
- 'visitor_idcookie' => $idcookie,
- 'visitor_returning' => $returningVisitor,
- 'visit_first_action_time' => $this->getDatetimeFromTimestamp($serverTime),
- 'visit_last_action_time' => $this->getDatetimeFromTimestamp($serverTime),
- 'visit_server_date' => $serverDate,
- 'visit_entry_idaction' => $actionId,
- 'visit_exit_idaction' => $actionId,
- 'visit_total_actions' => 1,
- 'visit_total_time' => $defaultTimeOnePageVisit,
- 'referer_type' => $refererInfo['referer_type'],
- 'referer_name' => $refererInfo['referer_name'],
- 'referer_url' => $refererInfo['referer_url'],
- 'referer_keyword' => $refererInfo['referer_keyword'],
- 'config_md5config' => $userInfo['config_md5config'],
- 'config_os' => $userInfo['config_os'],
- 'config_browser_name' => $userInfo['config_browser_name'],
- 'config_browser_version' => $userInfo['config_browser_version'],
- 'config_resolution' => $userInfo['config_resolution'],
- 'config_pdf' => $userInfo['config_pdf'],
- 'config_flash' => $userInfo['config_flash'],
- 'config_java' => $userInfo['config_java'],
- 'config_director' => $userInfo['config_director'],
- 'config_quicktime' => $userInfo['config_quicktime'],
- 'config_realplayer' => $userInfo['config_realplayer'],
- 'config_windowsmedia' => $userInfo['config_windowsmedia'],
- 'config_cookie' => $userInfo['config_cookie'],
- 'location_ip' => $userInfo['location_ip'],
- 'location_browser_lang' => $userInfo['location_browser_lang'],
- 'location_country' => $country
- );
-
- Piwik_PostEvent('Tracker.newVisitorInformation', $informationToSave);
- $informationToSave['location_continent'] = Piwik_Common::getContinent( $informationToSave['location_country'] );
-
- $fields = implode(", ", array_keys($informationToSave));
- $values = substr(str_repeat( "?,",count($informationToSave)),0,-1);
-
- $this->db->query( "INSERT INTO ".$this->db->prefixTable('log_visit').
- " ($fields) VALUES ($values)", array_values($informationToSave));
-
- $idVisit = $this->db->lastInsertId();
-
- // Update the visitor information attribute with this information array
- $this->visitorInfo = $informationToSave;
- $this->visitorInfo['idvisit'] = $idVisit;
-
- // we have to save timestamp in the object properties, whereas mysql eats some other datetime format
- $this->visitorInfo['visit_first_action_time'] = $serverTime;
- $this->visitorInfo['visit_last_action_time'] = $serverTime;
-
- // saves the action
- $action->record( $idVisit, 0, 0 );
-
+ $this->cookie->save();
}
/**
@@ -546,14 +550,14 @@ class Piwik_Tracker_Visit implements Piwik_Tracker_Visit_Interface
*
* @return Piwik_Tracker_Action child or fake but with same public interface
*/
- protected function getActionObject()
+ protected function newAction()
{
$action = null;
Piwik_PostEvent('Tracker.newAction', $action);
if(is_null($action))
{
- $action = new Piwik_Tracker_Action( $this->db );
+ $action = new Piwik_Tracker_Action();
}
elseif(!($action instanceof Piwik_Tracker_Action_Interface))
{
diff --git a/core/Updates/0.2.27.php b/core/Updates/0.2.27.php
new file mode 100644
index 0000000000..4e04ee3eb0
--- /dev/null
+++ b/core/Updates/0.2.27.php
@@ -0,0 +1,18 @@
+<?php
+
+Piwik_Query( "ALTER TABLE `".Piwik::prefixTable('log_visit')."`
+ ADD `visit_goal_converted` VARCHAR( 1 ) NOT NULL AFTER `visit_total_time` ;");
+$tables = Piwik::getTablesCreateSql();
+Piwik_Query( $tables['log_conversion'] );
+Piwik_Query( $tables['goal'] );
+
+$allTablesInstalled = Piwik::getTablesInstalled();
+foreach($allTablesInstalled as $tableName)
+{
+ if(preg_match('/archive_/', $tableName) == 1)
+ {
+ Piwik_Query('CREATE INDEX index_all
+ ON '. $tableName . ' (`idsite`,`date1`,`date2`,`name`,`ts_archived`)');
+
+ }
+}
diff --git a/core/Version.php b/core/Version.php
index d54b22b973..ce5455afda 100644
--- a/core/Version.php
+++ b/core/Version.php
@@ -1,5 +1,5 @@
-<?php
+<?php
final class Piwik_Version {
- const VERSION = '0.2.26';
+ const VERSION = '0.2.27';
}
diff --git a/core/View.php b/core/View.php
index 5d62bd0aa1..7a1a6479c2 100644
--- a/core/View.php
+++ b/core/View.php
@@ -9,7 +9,6 @@
* @package Piwik_Visualization
*/
-require_once "Smarty.php";
require_once "iView.php";
/**
@@ -25,6 +24,7 @@ class Piwik_View implements Piwik_iView
public function __construct( $templateFile, $smConf = array())
{
+ require_once "Smarty.php";
$this->template = $templateFile;
$this->smarty = new Piwik_Smarty();
diff --git a/core/ViewDataTable.php b/core/ViewDataTable.php
index 224e627e60..e13f6b3d71 100644
--- a/core/ViewDataTable.php
+++ b/core/ViewDataTable.php
@@ -36,7 +36,6 @@ require_once "API/Request.php";
* @package Piwik_ViewDataTable
*
*/
-
abstract class Piwik_ViewDataTable
{
/**
@@ -94,13 +93,13 @@ abstract class Piwik_ViewDataTable
* @see init()
* @var string
*/
- protected $actionToLoadTheSubTable = null;
+ protected $controllerActionCalledWhenRequestSubTable = null;
/**
* @see init()
* @var string
*/
- protected $moduleNameAndMethod;
+ protected $apiMethodToRequestDataTable;
/**
* This view should be an implementation of the Interface Piwik_iView
@@ -198,6 +197,11 @@ abstract class Piwik_ViewDataTable
return new Piwik_ViewDataTable_HtmlTable_AllColumns();
break;
+ case 'tableGoals':
+ require_once "ViewDataTable/HtmlTable/Goals.php";
+ return new Piwik_ViewDataTable_HtmlTable_Goals();
+ break;
+
case 'table':
default:
require_once "ViewDataTable/HtmlTable.php";
@@ -209,42 +213,45 @@ abstract class Piwik_ViewDataTable
/**
* Inits the object given the $currentControllerName, $currentControllerAction of
* the calling controller action, eg. 'Referers' 'getLongListOfKeywords'.
- * The initialization also requires the $moduleNameAndMethod of the API method
+ * The initialization also requires the $apiMethodToRequestDataTable of the API method
* to call in order to get the DataTable, eg. 'Referers.getKeywords'.
- * The optional $actionToLoadTheSubTable defines the method name of the API to call when there is a idSubtable.
+ * The optional $controllerActionCalledWhenRequestSubTable defines the method name of the API to call when there is a idSubtable.
* This value would be used by the javascript code building the GET request to the API.
*
* Example:
* For the keywords listing, a click on the row loads the subTable of the Search Engines for this row.
- * In this case $actionToLoadTheSubTable = 'getSearchEnginesFromKeywordId'.
+ * In this case $controllerActionCalledWhenRequestSubTable = 'getSearchEnginesFromKeywordId'.
* The GET request will hit 'Referers.getSearchEnginesFromKeywordId'.
*
* @param string $currentControllerName eg. 'Referers'
* @param string $currentControllerAction eg. 'getKeywords'
- * @param string $moduleNameAndMethod eg. 'Referers.getKeywords'
- * @param string $actionToLoadTheSubTable eg. 'getSearchEnginesFromKeywordId'
+ * @param string $apiMethodToRequestDataTable eg. 'Referers.getKeywords'
+ * @param string $controllerActionCalledWhenRequestSubTable eg. 'getSearchEnginesFromKeywordId'
* @return void
*/
public function init( $currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable = null)
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable = null)
{
$this->currentControllerName = $currentControllerName;
$this->currentControllerAction = $currentControllerAction;
- $this->moduleNameAndMethod = $moduleNameAndMethod;
- $this->actionToLoadTheSubTable = $actionToLoadTheSubTable;
- $this->method = $moduleNameAndMethod;
+ $this->apiMethodToRequestDataTable = $apiMethodToRequestDataTable;
+ $this->controllerActionCalledWhenRequestSubTable = $controllerActionCalledWhenRequestSubTable;
$this->idSubtable = Piwik_Common::getRequestVar('idSubtable', false, 'int');
+ $this->viewProperties['show_goals'] = false;
$this->viewProperties['show_search'] = Piwik_Common::getRequestVar('show_search', true);
$this->viewProperties['show_table_all_columns'] = Piwik_Common::getRequestVar('show_table_all_columns', true);
$this->viewProperties['show_exclude_low_population'] = Piwik_Common::getRequestVar('show_exclude_low_population', true);
$this->viewProperties['show_offset_information'] = Piwik_Common::getRequestVar('show_offset_information', true);;
$this->viewProperties['show_footer'] = Piwik_Common::getRequestVar('show_footer', true);
$this->viewProperties['show_footer_icons'] = ($this->idSubtable == false);
+ $this->viewProperties['apiMethodToRequestDataTable'] = $this->apiMethodToRequestDataTable;
+ $this->viewProperties['uniqueId'] = $this->getUniqueIdViewDataTable();
}
+
/**
* Forces the View to use a given template.
* Usually the template to use is set in the specific ViewDataTable_*
@@ -275,6 +282,26 @@ abstract class Piwik_ViewDataTable
return $this->view;
}
+ public function getCurrentControllerAction()
+ {
+ return $this->currentControllerAction;
+ }
+
+ public function getCurrentControllerName()
+ {
+ return $this->currentControllerName;
+ }
+
+ public function getApiMethodToRequestDataTable()
+ {
+ return $this->apiMethodToRequestDataTable;
+ }
+
+ public function getControllerActionCalledWhenRequestSubTable()
+ {
+ return $this->controllerActionCalledWhenRequestSubTable;
+ }
+
/**
* Returns the DataTable loaded from the API
*
@@ -300,7 +327,7 @@ abstract class Piwik_ViewDataTable
protected function loadDataTableFromAPI()
{
// we build the request string (URL) to call the API
- $requestString = $this->getRequestString();
+ $requestString = $this->getRequestString();
// we make the request to the API
$request = new Piwik_API_Request($requestString);
@@ -320,7 +347,7 @@ abstract class Piwik_ViewDataTable
// we setup the method and format variable
// - we request the method to call to get this specific DataTable
// - the format = original specifies that we want to get the original DataTable structure itself, not rendered
- $requestString = 'method='.$this->moduleNameAndMethod;
+ $requestString = 'method='.$this->apiMethodToRequestDataTable;
$requestString .= '&format=original';
$toSetEventually = array(
@@ -385,7 +412,7 @@ abstract class Piwik_ViewDataTable
* @see datatable.js
* @return string
*/
- protected function getUniqIdTable()
+ protected function getUniqueIdViewDataTable()
{
// if we request a subDataTable the $this->currentControllerAction DIV ID is already there in the page
// we make the DIV ID really unique by appending the ID of the subtable requested
@@ -422,7 +449,7 @@ abstract class Piwik_ViewDataTable
* - etc.
*
* The values are loaded:
- * - from the generic filters that are applied by default @see Piwik_API_ResponseBuilder::getGenericFiltersInformation()
+ * - from the generic filters that are applied by default @see Piwik_API_DataTableGenericFilter.php::getGenericFiltersInformation()
* - from the values already available in the GET array
* - from the values set using methods from this class (eg. setSearchPattern(), setLimit(), etc.)
*
@@ -433,7 +460,7 @@ abstract class Piwik_ViewDataTable
// build javascript variables to set
$javascriptVariablesToSet = array();
- $genericFilters = Piwik_API_ResponseBuilder::getGenericFiltersInformation();
+ $genericFilters = Piwik_API_DataTableGenericFilter::getGenericFiltersInformation();
foreach($genericFilters as $filter)
{
foreach($filter as $filterVariableName => $filterInfo)
@@ -478,13 +505,25 @@ abstract class Piwik_ViewDataTable
$javascriptVariablesToSet[$name] = $value;
}
}
-
+
+ if($this->dataTable instanceof Piwik_DataTable)
+ {
+ // we override the filter_sort_column with the column used for sorting,
+ // which can be different from the one specified (eg. if the column doesn't exist)
+ $javascriptVariablesToSet['filter_sort_column'] = $this->dataTable->getSortedByColumnName();
+ // datatable can return "2" but we want to write "nb_visits" in the js
+ if(isset(Piwik_Archive::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']]))
+ {
+ $javascriptVariablesToSet['filter_sort_column'] = Piwik_Archive::$mappingFromIdToName[$javascriptVariablesToSet['filter_sort_column']];
+ }
+ }
+
$javascriptVariablesToSet['module'] = $this->currentControllerName;
$javascriptVariablesToSet['action'] = $this->currentControllerAction;
$javascriptVariablesToSet['viewDataTable'] = $this->getViewDataTableId();
- if(!is_null($this->actionToLoadTheSubTable))
+ if(!is_null($this->controllerActionCalledWhenRequestSubTable))
{
- $javascriptVariablesToSet['actionToLoadTheSubTable'] = $this->actionToLoadTheSubTable;
+ $javascriptVariablesToSet['controllerActionCalledWhenRequestSubTable'] = $this->controllerActionCalledWhenRequestSubTable;
}
if($this->dataTable)
@@ -497,16 +536,27 @@ abstract class Piwik_ViewDataTable
// are loaded with Piwik_Common::getRequestVar()
foreach($javascriptVariablesToSet as &$value)
{
- if(is_array($value))
- {
- $value = array_map('addslashes',$value);
- }
- else
- {
+ if(is_array($value))
+ {
+ $value = array_map('addslashes',$value);
+ }
+ else
+ {
$value = addslashes($value);
}
- }
+ }
+ $deleteFromJavascriptVariables = array(
+ 'filter_excludelowpop',
+ 'filter_excludelowpop_value',
+ );
+ foreach($deleteFromJavascriptVariables as $name)
+ {
+ if(isset($javascriptVariablesToSet[$name]))
+ {
+ unset($javascriptVariablesToSet[$name]);
+ }
+ }
return $javascriptVariablesToSet;
}
@@ -606,18 +656,30 @@ abstract class Piwik_ViewDataTable
$this->viewProperties['show_table_all_columns'] = false;
}
- /**
- * Sets the pattern to look for in the table (only rows with column equal to the pattern will be kept)
- *
- * @param array $pattern arrays of patterns to look for
- * @param string $column to compare the pattern to
- * @return void
- */
- public function setExactPattern($pattern, $column)
- {
- $this->variablesDefault['filter_exact_pattern'] = $pattern;
- $this->variablesDefault['filter_exact_column'] = $column;
- }
+ /**
+ * Whether or not to show the "goal" icon
+ * @return void
+ */
+ public function enableShowGoals()
+ {
+ if(Piwik_PluginsManager::getInstance()->isPluginActivated('Goals'))
+ {
+ $this->viewProperties['show_goals'] = true;
+ }
+ }
+
+ /**
+ * Sets the pattern to look for in the table (only rows with column equal to the pattern will be kept)
+ *
+ * @param array $pattern arrays of patterns to look for
+ * @param string $column to compare the pattern to
+ * @return void
+ */
+ public function setExactPattern($pattern, $column)
+ {
+ $this->variablesDefault['filter_exact_pattern'] = $pattern;
+ $this->variablesDefault['filter_exact_column'] = $column;
+ }
/**
* Sets the value to use for the Exclude low population filter.
@@ -626,18 +688,12 @@ abstract class Piwik_ViewDataTable
* @param string The name of the column for which we compare the value to $minValue
* @return void
*/
- public function setExcludeLowPopulation( $minValue = null, $columnName = null )
+ public function setExcludeLowPopulation( $columnName = null, $minValue = null )
{
- if( is_null( $minValue) )
- {
- throw new Exception("setExcludeLowPopulation() value shouldn't be null");
- }
-
if(is_null($columnName))
{
$columnName = Piwik_Archive::INDEX_NB_VISITS;
}
-
$this->variablesDefault['filter_excludelowpop'] = $columnName;
$this->variablesDefault['filter_excludelowpop_value'] = $minValue;
}
diff --git a/core/ViewDataTable/Cloud.php b/core/ViewDataTable/Cloud.php
index 179c8959d2..29cb676eab 100644
--- a/core/ViewDataTable/Cloud.php
+++ b/core/ViewDataTable/Cloud.php
@@ -33,11 +33,11 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->dataTableTemplate = 'CoreHome/templates/cloud.tpl';
$this->disableOffsetInformation();
$this->disableExcludeLowPopulation();
@@ -99,8 +99,6 @@ class Piwik_ViewDataTable_Cloud extends Piwik_ViewDataTable
$view->labelMetadata = $labelMetadata;
$view->cloudValues = $cloudValues;
- $view->method = $this->method;
- $view->id = $this->getUniqIdTable();
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
diff --git a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
index 93c69b2a49..8b51c394d6 100644
--- a/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
+++ b/core/ViewDataTable/GenerateGraphData/ChartEvolution.php
@@ -19,198 +19,198 @@ class Piwik_ViewDataTable_GenerateGraphData_ChartEvolution extends Piwik_ViewDat
$this->view = new Piwik_Visualization_ChartEvolution;
}
- var $lineLabels = array();
- var $data = array();
-
- private function generateLine( $dataArray, $columns, $schema = "##label## ##column##" )
- {
- $data = array();
-
- foreach($dataArray as $keyName => $table)
- {
- $table->applyQueuedFilters();
-
- // initialize data (default values for all lines is 0)
- $dataRow = array();
-
- $rows = $table->getRows();
-
- foreach($rows as $row)
+ var $lineLabels = array();
+ var $data = array();
+
+ private function generateLine( $dataArray, $columns, $schema = "##label## ##column##" )
+ {
+ $data = array();
+
+ foreach($dataArray as $keyName => $table)
+ {
+ $table->applyQueuedFilters();
+
+ // initialize data (default values for all lines is 0)
+ $dataRow = array();
+
+ $rows = $table->getRows();
+
+ foreach($rows as $row)
+ {
+ $rowLabel = $schema;
+
+ if( strpos($rowLabel, "##label##") !== false )
+ {
+ $rowLabel = str_replace("##label##", $row->getColumn('label'), $rowLabel);
+ }
+
+ foreach($columns as $col)
+ {
+ $label = $rowLabel;
+
+ if( strpos($label, "##column##") !== false )
+ {
+ $label = str_replace("##column##", $col, $label);
+ }
+
+ if( !isset($this->lineLabels[$label]) )
+ {
+ $this->lineLabels[$label] = count($this->lineLabels);
+ }
+ $lineNb = $this->lineLabels[$label];
+
+ $value = $row->getColumn($col);
+
+ $dataRow['value'.$lineNb] = $value;
+ }
+ }
+ $data[] = $dataRow;
+ }
+ return $data;
+ }
+
+ private function generateLabels( $dataArray )
+ {
+ $data = array();
+
+ foreach($dataArray as $keyName => $table)
+ {
+ $table->applyQueuedFilters();
+
+ $data[] = array('label' => $keyName);
+ }
+
+ return $data;
+ }
+
+ private function addArray( &$data, $newData )
+ {
+ for($i = 0; $i < count($newData); $i++)
+ {
+ foreach($newData[$i] as $key => $value)
+ {
+ $data[$i][$key] = $value;
+ }
+ }
+ }
+
+ private function fillValues( &$data )
+ {
+ $nbLines = count($this->lineLabels);
+
+ for($i = 0; $i < count($data); $i++)
+ {
+ for($j = 0; $j < $nbLines; $j++)
+ {
+ if( !isset($data[$i]['value'.$j]) )
+ {
+ $data[$i]['value'.$j] = 0;
+ }
+ }
+ }
+ }
+
+ /*
+ * generates data for evolution graph from a numeric DataTable (DataTable that has only 'label' and 'value' columns)
+ */
+ protected function generateDataFromNumericDataTable($dataArray, $siteLabel = "")
+ {
+ $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
+
+ // for numeric we want to have only one column name
+ if( count($columnsToDisplay) != 1 )
+ {
+ $columnsToDisplay = array( 'nb_uniq_visitors' );
+ }
+
+ $label = $siteLabel . array_shift($columnsToDisplay);
+
+ $this->addArray($this->data, $this->generateLabels($dataArray));
+ $this->addArray($this->data, $this->generateLine($dataArray,array('value'),$label));
+ $this->fillValues($this->data);
+ }
+
+ /*
+ * generates data for evolution graph from a DataTable that has named columns (i.e. 'nb_hits', 'nb_uniq_visitors')
+ */
+ protected function generateDataFromRegularDataTable($dataArray, $siteLabel = "")
+ {
+ // get list of columns to display i.e. array('nb_hits','nb_uniq_visitors')
+ $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
+
+ // default column
+ if( count($columnsToDisplay) == 0 )
+ {
+ $columnsToDisplay = array( 'nb_uniq_visitors' );
+ }
+
+ $this->addArray($this->data, $this->generateLabels($dataArray));
+ $this->addArray($this->data, $this->generateLine($dataArray, $columnsToDisplay, $siteLabel."##label## ##column##"));
+ $this->fillValues($this->data);
+ }
+
+ protected function handleSiteGenerateDataFromDataTable($dataArray, $siteLabel = "")
+ {
+ // detect if we got numeric Datatable or regular DataTable
+ foreach($dataArray as $table)
+ {
+ $row = $table->getFirstRow();
+
+ if( $row != null )
+ {
+ $columns = $row->getColumns();
+
+ // if we got 2 columns - 'label' and 'value' this is numeric DataTable
+ if( count($columns) == 2 && isset($columns['label']) && isset($columns['value']) )
+ {
+ $this->generateDataFromNumericDataTable($dataArray, $siteLabel);
+ }
+ else
+ {
+ $this->generateDataFromRegularDataTable($dataArray, $siteLabel);
+ }
+ break;
+ }
+ }
+ }
+
+ public function generateDataFromDataTable()
+ {
+ $data = array();
+
+ if( $this->dataTable->getRowsCount() )
+ {
+ $row = null;
+
+ // find first table with rows
+ foreach($this->dataTable->getArray() as $idsite => $table)
{
- $rowLabel = $schema;
-
- if( strpos($rowLabel, "##label##") !== false )
- {
- $rowLabel = str_replace("##label##", $row->getColumn('label'), $rowLabel);
- }
-
- foreach($columns as $col)
- {
- $label = $rowLabel;
-
- if( strpos($label, "##column##") !== false )
- {
- $label = str_replace("##column##", $col, $label);
- }
-
- if( !isset($this->lineLabels[$label]) )
- {
- $this->lineLabels[$label] = count($this->lineLabels);
- }
- $lineNb = $this->lineLabels[$label];
-
- $value = $row->getColumn($col);
-
- $dataRow['value'.$lineNb] = $value;
- }
- }
- $data[] = $dataRow;
- }
- return $data;
- }
-
- private function generateLabels( $dataArray )
- {
- $data = array();
-
- foreach($dataArray as $keyName => $table)
- {
- $table->applyQueuedFilters();
-
- $data[] = array('label' => $keyName);
- }
-
- return $data;
- }
-
- private function addArray( &$data, $newData )
- {
- for($i = 0; $i < count($newData); $i++)
- {
- foreach($newData[$i] as $key => $value)
- {
- $data[$i][$key] = $value;
- }
- }
- }
-
- private function fillValues( &$data )
- {
- $nbLines = count($this->lineLabels);
-
- for($i = 0; $i < count($data); $i++)
- {
- for($j = 0; $j < $nbLines; $j++)
- {
- if( !isset($data[$i]['value'.$j]) )
- {
- $data[$i]['value'.$j] = 0;
- }
- }
- }
- }
-
- /*
- * generates data for evolution graph from a numeric DataTable (DataTable that has only 'label' and 'value' columns)
- */
- protected function generateDataFromNumericDataTable($dataArray, $siteLabel = "")
- {
- $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
-
- // for numeric we want to have only one column name
- if( count($columnsToDisplay) != 1 )
- {
- $columnsToDisplay = array( 'nb_uniq_visitors' );
- }
-
- $label = $siteLabel . array_shift($columnsToDisplay);
-
- $this->addArray($this->data, $this->generateLabels($dataArray));
- $this->addArray($this->data, $this->generateLine($dataArray,array('value'),$label));
- $this->fillValues($this->data);
- }
-
- /*
- * generates data for evolution graph from a DataTable that has named columns (i.e. 'nb_hits', 'nb_uniq_visitors')
- */
- protected function generateDataFromRegularDataTable($dataArray, $siteLabel = "")
- {
- // get list of columns to display i.e. array('nb_hits','nb_uniq_visitors')
- $columnsToDisplay = Piwik_Common::getRequestVar('columns', array(), 'array');
-
- // default column
- if( count($columnsToDisplay) == 0 )
- {
- $columnsToDisplay = array( 'nb_uniq_visitors' );
- }
-
- $this->addArray($this->data, $this->generateLabels($dataArray));
- $this->addArray($this->data, $this->generateLine($dataArray, $columnsToDisplay, $siteLabel."##label## ##column##"));
- $this->fillValues($this->data);
- }
-
- protected function handleSiteGenerateDataFromDataTable($dataArray, $siteLabel = "")
- {
- // detect if we got numeric Datatable or regular DataTable
- foreach($dataArray as $table)
- {
- $row = $table->getFirstRow();
-
- if( $row != null )
- {
- $columns = $row->getColumns();
-
- // if we got 2 columns - 'label' and 'value' this is numeric DataTable
- if( count($columns) == 2 && isset($columns['label']) && isset($columns['value']) )
- {
- $this->generateDataFromNumericDataTable($dataArray, $siteLabel);
- }
- else
- {
- $this->generateDataFromRegularDataTable($dataArray, $siteLabel);
- }
- break;
- }
- }
- }
-
- public function generateDataFromDataTable()
- {
- $data = array();
-
- if( $this->dataTable->getRowsCount() )
- {
- $row = null;
-
- // find first table with rows
- foreach($this->dataTable->getArray() as $idsite => $table)
- {
- // detect if we got data from more than one site
- if( $table instanceof Piwik_DataTable_Array)
- {
- // multiple sites
- $site = new Piwik_Site($idsite);
-
- $this->handleSiteGenerateDataFromDataTable($table->getArray(), $site->getName()." ");
- }
- else if( $table instanceof Piwik_DataTable_Simple && $this->dataTable->getKeyName() == 'idSite')
- {
- // multiple sites (when numeric DataTable)
- $site = new Piwik_Site($idsite);
-
- $this->handleSiteGenerateDataFromDataTable($table->getFirstRow()->getColumn('value')->getArray(), $site->getName()." ");
- }
- else
- {
- // single site
- $this->handleSiteGenerateDataFromDataTable($this->dataTable->getArray());
- break;
- }
- }
-
- }
- array_unshift($this->data, array_keys($this->lineLabels));
-
- return $this->data;
+ // detect if we got data from more than one site
+ if( $table instanceof Piwik_DataTable_Array)
+ {
+ // multiple sites
+ $site = new Piwik_Site($idsite);
+
+ $this->handleSiteGenerateDataFromDataTable($table->getArray(), $site->getName()." ");
+ }
+ else if( $table instanceof Piwik_DataTable_Simple && $this->dataTable->getKeyName() == 'idSite')
+ {
+ // multiple sites (when numeric DataTable)
+ $site = new Piwik_Site($idsite);
+
+ $this->handleSiteGenerateDataFromDataTable($table->getFirstRow()->getColumn('value')->getArray(), $site->getName()." ");
+ }
+ else
+ {
+ // single site
+ $this->handleSiteGenerateDataFromDataTable($this->dataTable->getArray());
+ break;
+ }
+ }
+
+ }
+ array_unshift($this->data, array_keys($this->lineLabels));
+
+ return $this->data;
}
}
diff --git a/core/ViewDataTable/GenerateGraphHTML.php b/core/ViewDataTable/GenerateGraphHTML.php
index 3204361748..58849049d3 100644
--- a/core/ViewDataTable/GenerateGraphHTML.php
+++ b/core/ViewDataTable/GenerateGraphHTML.php
@@ -27,11 +27,11 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->dataTableTemplate = 'CoreHome/templates/graph.tpl';
@@ -74,7 +74,7 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
protected function buildView()
{
$view = new Piwik_View($this->dataTableTemplate);
- $this->id = $this->getUniqIdTable();
+ $this->uniqueIdViewDataTable = $this->getUniqueIdViewDataTable();
$view->graphType = $this->graphType;
$this->parametersToModify['action'] = $this->currentControllerAction;
@@ -82,11 +82,9 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
$view->jsInvocationTag = $this->getFlashInvocationCode($url);
$view->urlGraphData = $url;
- $view->formEmbedId = "formEmbed".$this->id;
+ $view->formEmbedId = "formEmbed".$this->uniqueIdViewDataTable;
$view->graphCodeEmbed = $this->graphCodeEmbed;
- $view->id = $this->id;
- $view->method = $this->method;
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
@@ -105,8 +103,8 @@ abstract class Piwik_ViewDataTable_GenerateGraphHTML extends Piwik_ViewDataTable
// escape the & and stuff:
$url = urlencode($url);
- $obj_id = $this->id . "Chart";
- $div_name = $this->id . "FlashContent";
+ $obj_id = $this->uniqueIdViewDataTable . "Chart";
+ $div_name = $this->uniqueIdViewDataTable . "FlashContent";
$return = '';
if( $use_swfobject )
diff --git a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
index 0eb29034e3..98fa9323a8 100644
--- a/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
+++ b/core/ViewDataTable/GenerateGraphHTML/ChartEvolution.php
@@ -28,24 +28,24 @@ class Piwik_ViewDataTable_GenerateGraphHTML_ChartEvolution extends Piwik_ViewDat
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod )
+ $apiMethodToRequestDataTable )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod );
+ $apiMethodToRequestDataTable );
$this->setParametersToModify(array('date' => Piwik_Common::getRequestVar('date', 'last30', 'string')));
$this->doNotShowFooter();
}
-
- /**
- * Sets the columns that will be displayed on output evolution chart
- * By default all columns are displayed ($columnsNames = array() will display all columns)
- *
- * @param array $columnsNames Array of column names eg. array('nb_visits','nb_hits')
- */
- public function setColumnsToDisplay( $columnsNames)
- {
- $this->setParametersToModify( array('columns' => $columnsNames) );
- }
+
+ /**
+ * Sets the columns that will be displayed on output evolution chart
+ * By default all columns are displayed ($columnsNames = array() will display all columns)
+ *
+ * @param array $columnsNames Array of column names eg. array('nb_visits','nb_hits')
+ */
+ public function setColumnsToDisplay( $columnsNames)
+ {
+ $this->setParametersToModify( array('columns' => $columnsNames) );
+ }
} \ No newline at end of file
diff --git a/core/ViewDataTable/HtmlTable.php b/core/ViewDataTable/HtmlTable.php
index 9c27447417..d656908f85 100644
--- a/core/ViewDataTable/HtmlTable.php
+++ b/core/ViewDataTable/HtmlTable.php
@@ -53,21 +53,22 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
*/
function init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable = null )
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable = null )
{
parent::init($currentControllerName,
$currentControllerAction,
- $moduleNameAndMethod,
- $actionToLoadTheSubTable);
+ $apiMethodToRequestDataTable,
+ $controllerActionCalledWhenRequestSubTable);
$this->dataTableTemplate = 'CoreHome/templates/datatable.tpl';
-
$this->variablesDefault['enable_sort'] = '1';
// load general columns translations
$this->setColumnTranslation('nb_visits', Piwik_Translate('General_ColumnNbVisits'));
$this->setColumnTranslation('label', Piwik_Translate('General_ColumnLabel'));
$this->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnNbUniqVisitors'));
+
+ $this->handleLowPopulation();
}
protected function getViewDataTableId()
@@ -109,7 +110,6 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
$phpArray = $this->getPHPArrayFromDataTable();
$view->arrayDataTable = $phpArray;
- $view->method = $this->method;
$columns = $this->getColumnsToDisplay($phpArray);
$view->dataTableColumns = $columns;
@@ -122,11 +122,23 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
}
$view->nbColumns = $nbColumns;
- $view->id = $this->getUniqIdTable();
$view->javascriptVariablesToSet = $this->getJavascriptVariablesToSet();
$view->properties = $this->getViewProperties();
return $view;
}
+
+ protected function handleLowPopulation( $columnToApplyFilter = null)
+ {
+ if(Piwik_Common::getRequestVar('enable_filter_excludelowpop', '0', 'string' ) == '0')
+ {
+ return;
+ }
+ if(is_null($columnToApplyFilter))
+ {
+ $columnToApplyFilter = Piwik_Archive::INDEX_NB_VISITS;
+ }
+ $this->setExcludeLowPopulation( $columnToApplyFilter);
+ }
/**
* Returns friendly php array from the Piwik_DataTable
@@ -156,6 +168,16 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
}
/**
+ * Adds a column to the list of columns to be displayed
+ *
+ * @param string $columnName
+ */
+ public function addColumnToDisplay( $columnName )
+ {
+ $this->columnsToDisplay[] = $columnName;
+ }
+
+ /**
* Sets translation string for given column
*
* @param string $columnName column name
@@ -217,6 +239,7 @@ class Piwik_ViewDataTable_HtmlTable extends Piwik_ViewDataTable
$columnsToDisplay = $columnsInDataTable;
}
+ $columnsToDisplay = array_unique($columnsToDisplay);
foreach($columnsToDisplay as $columnToDisplay)
{
if(in_array($columnToDisplay, $columnsInDataTable))
diff --git a/core/ViewDataTable/HtmlTable/AllColumns.php b/core/ViewDataTable/HtmlTable/AllColumns.php
index 9ea33f5a85..2a83c9ae80 100644
--- a/core/ViewDataTable/HtmlTable/AllColumns.php
+++ b/core/ViewDataTable/HtmlTable/AllColumns.php
@@ -3,8 +3,6 @@ require_once "ViewDataTable/HtmlTable.php";
class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlTable
{
- const LOW_POPULATION_THRESHOLD_PERCENTAGE_VISIT = 0.005;
-
protected function getViewDataTableId()
{
return 'tableAllColumns';
@@ -12,28 +10,10 @@ class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlT
public function main()
{
- //TODO should be cached at least statically?
$this->viewProperties['show_exclude_low_population'] = true;
- $this->handleLowPopulation();
parent::main();
}
- protected function handleLowPopulation()
- {
- if(Piwik_Common::getRequestVar('filter_excludelowpop', '0', 'string' ) == '0')
- {
- return;
- }
-
- require_once "VisitsSummary/Controller.php";
- $visits = Piwik_VisitsSummary_Controller::getVisits();
- $visitsThreshold = floor( self::LOW_POPULATION_THRESHOLD_PERCENTAGE_VISIT * $visits);
- if($visitsThreshold > 0)
- {
- $this->setExcludeLowPopulation( $visitsThreshold, Piwik_Archive::INDEX_NB_VISITS );
- }
- }
-
protected function getRequestString()
{
$requestString = parent::getRequestString();
@@ -42,6 +22,7 @@ class Piwik_ViewDataTable_HtmlTable_AllColumns extends Piwik_ViewDataTable_HtmlT
protected function postDataTableLoadedFromAPI()
{
+ parent::postDataTableLoadedFromAPI();
$this->setColumnsToDisplay(array('label',
'nb_visits',
'nb_uniq_visitors',
diff --git a/core/ViewDataTable/HtmlTable/Goals.php b/core/ViewDataTable/HtmlTable/Goals.php
new file mode 100644
index 0000000000..6711f7602c
--- /dev/null
+++ b/core/ViewDataTable/HtmlTable/Goals.php
@@ -0,0 +1,82 @@
+<?php
+require_once "ViewDataTable/HtmlTable.php";
+
+class Piwik_ViewDataTable_HtmlTable_Goals extends Piwik_ViewDataTable_HtmlTable
+{
+ protected function getViewDataTableId()
+ {
+ return 'tableGoals';
+ }
+
+ public function main()
+ {
+ $this->viewProperties['show_exclude_low_population'] = true;
+ $this->viewProperties['show_goals'] = true;
+ $this->setColumnsToDisplay( array( 'label',
+ 'nb_visits',
+ 'goals_conversion_rate',
+ 'goal_%s_conversion_rate',
+ 'revenue_per_visit',
+ ));
+ parent::main();
+ }
+
+ public function disableSubTableWhenShowGoals()
+ {
+ $this->controllerActionCalledWhenRequestSubTable = null;
+ }
+
+ protected function getRequestString()
+ {
+ $requestString = parent::getRequestString();
+ return $requestString . '&filter_update_columns_when_show_all_goals=1';
+ }
+
+ protected $columnsToPercentageFilter = array();
+
+ private function getIdSite()
+ {
+ return Piwik_Common::getRequestVar('idSite', null, 'int');
+ }
+
+ public function setColumnsToDisplay($columnsNames)
+ {
+ $newColumnsNames = array();
+ foreach($columnsNames as $columnName)
+ {
+ if($columnName == 'goal_%s_conversion_rate')
+ {
+ require_once "core/Tracker/GoalManager.php";
+ require_once "plugins/Goals/API.php";
+ $goals = Piwik_Goals_API::getGoals( $this->getIdSite() );
+ foreach($goals as $goal)
+ {
+ $idgoal = $goal['idgoal'];
+ $name = $goal['name'];
+ $columnName = 'goal_'.$idgoal.'_conversion_rate';
+ $newColumnsNames[] = $columnName;
+ $this->setColumnTranslation($columnName, $name);
+ $this->columnsToPercentageFilter[] = $columnName;
+ }
+ }
+ else
+ {
+ $newColumnsNames[] = $columnName;
+ }
+ }
+ parent::setColumnsToDisplay($newColumnsNames);
+ }
+
+ protected function postDataTableLoadedFromAPI()
+ {
+ parent::postDataTableLoadedFromAPI();
+ $this->setColumnTranslation('revenue_per_visit', 'Value per Visit');
+ $this->setColumnTranslation('goals_conversion_rate', 'Visits with Conversions');
+ $this->columnsToPercentageFilter[] = 'goals_conversion_rate';
+ foreach($this->columnsToPercentageFilter as $columnName)
+ {
+ $filter = new Piwik_DataTable_Filter_ColumnCallbackReplace($this->dataTable, $columnName, create_function('$rate', 'return $rate."%";'));
+ }
+ $filter = new Piwik_DataTable_Filter_ColumnCallbackReplace($this->dataTable, 'revenue_per_visit', array("Piwik", "getPrettyMoney"));
+ }
+}
diff --git a/core/ViewDataTable/Sparkline.php b/core/ViewDataTable/Sparkline.php
index ab6fce4ce7..f9908a50fa 100644
--- a/core/ViewDataTable/Sparkline.php
+++ b/core/ViewDataTable/Sparkline.php
@@ -24,18 +24,6 @@ class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
}
/**
- * @see Piwik_ViewDataTable::init()
- */
- function init($currentControllerName,
- $currentControllerAction,
- $moduleNameAndMethod )
- {
- parent::init($currentControllerName,
- $currentControllerAction,
- $moduleNameAndMethod );
- }
-
- /**
* @see Piwik_ViewDataTable::main()
*/
public function main()
@@ -64,6 +52,15 @@ class Piwik_ViewDataTable_Sparkline extends Piwik_ViewDataTable
}
/**
+ * Sparkline needs to be fast to load. Currently we only load numeric values
+ * that do not need filtering, we can disable the filters for more performance.
+ */
+ protected function getRequestString()
+ {
+ return parent::getRequestString() . "&disable_generic_filters=1";
+ }
+
+ /**
* Given a Piwik_DataTable_Array made of DataTable_Simple rows, returns a php array with the structure:
* array(
* array( label => X, value => Y),
diff --git a/core/Visualization/ChartEvolution.php b/core/Visualization/ChartEvolution.php
index 9160eb8bc2..82f2da4fa4 100644
--- a/core/Visualization/ChartEvolution.php
+++ b/core/Visualization/ChartEvolution.php
@@ -1,72 +1,72 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: ChartVerticalBar.php 168 2008-01-14 05:26:43Z matt $
- *
- * @package Piwik_Visualization
- */
-
-require_once "Visualization/Chart.php";
-
-/**
- * Customize the Evolution chart style for the flash graph
- *
- * @package Piwik_Visualization
- */
-class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
-{
- function customizeGraph()
- {
- parent::customizeGraph();
- //$this->prepareData();
-
- $colors = array(
- "0x3357A0",
- "0x9933CC",
- "0xCC3399",
- "0x80a033",
- "0xFD9816",
- "0x246AD2",
- "0xFD16EA",
- "0x49C100",
- );
-
- // first row in array contains line labels (legend)
- $legendLabels = array_shift($this->dataGraph);
-
- $line = array();
-
- // define labels
- foreach($legendLabels as $nbLabel => $labelName)
- {
- $line[$nbLabel] = new line_hollow( 1, 3, $colors[$nbLabel] );
- $line[$nbLabel]->key( $labelName, 10 );
- }
-
- $maxData = 0;
- $xLabels = array();
- $cnt = count($this->dataGraph);
-
- // loop over data
- foreach($this->dataGraph as $values)
- {
- // add x axis value (label)
- array_push($xLabels, $values['label']);
-
- // loop over values for all lines (y axis values)
- for($j = 0; $j < count($legendLabels); $j++)
- {
- // get the y axis value for line $j
- $dotValue = $values['value'.$j];
-
- // find maximum y axis value
- if( $dotValue > $maxData )
- {
- $maxData = $dotValue;
- }
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: ChartVerticalBar.php 168 2008-01-14 05:26:43Z matt $
+ *
+ * @package Piwik_Visualization
+ */
+
+require_once "Visualization/Chart.php";
+
+/**
+ * Customize the Evolution chart style for the flash graph
+ *
+ * @package Piwik_Visualization
+ */
+class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
+{
+ function customizeGraph()
+ {
+ parent::customizeGraph();
+ //$this->prepareData();
+
+ $colors = array(
+ "0x3357A0",
+ "0x9933CC",
+ "0xCC3399",
+ "0x80a033",
+ "0xFD9816",
+ "0x246AD2",
+ "0xFD16EA",
+ "0x49C100",
+ );
+
+ // first row in array contains line labels (legend)
+ $legendLabels = array_shift($this->dataGraph);
+
+ $line = array();
+
+ // define labels
+ foreach($legendLabels as $nbLabel => $labelName)
+ {
+ $line[$nbLabel] = new line_hollow( 1, 3, $colors[$nbLabel] );
+ $line[$nbLabel]->key( $labelName, 10 );
+ }
+
+ $maxData = 0;
+ $xLabels = array();
+ $cnt = count($this->dataGraph);
+
+ // loop over data
+ foreach($this->dataGraph as $values)
+ {
+ // add x axis value (label)
+ array_push($xLabels, $values['label']);
+
+ // loop over values for all lines (y axis values)
+ for($j = 0; $j < count($legendLabels); $j++)
+ {
+ // get the y axis value for line $j
+ $dotValue = $values['value'.$j];
+
+ // find maximum y axis value
+ if( $dotValue > $maxData )
+ {
+ $maxData = $dotValue;
+ }
$link = null;
if($this->isLinkEnabled())
@@ -89,12 +89,12 @@ class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
else
{
$line[$j]->add($dotValue);
- }
- }
- }
- $this->data_sets = $line;
- $this->set_y_max( $maxData );
- $this->set_x_labels( $xLabels );
+ }
+ }
+ }
+ $this->data_sets = $line;
+ $this->set_y_max( $maxData );
+ $this->set_x_labels( $xLabels );
}
private function isLinkEnabled()
@@ -105,5 +105,5 @@ class Piwik_Visualization_ChartEvolution extends Piwik_Visualization_Chart
$linkEnabled = !Piwik_Common::getRequestVar('disableLink', 0, 'int');
}
return $linkEnabled;
- }
+ }
}
diff --git a/core/iView.php b/core/iView.php
index c35edafa50..82bb01bcd3 100644
--- a/core/iView.php
+++ b/core/iView.php
@@ -4,7 +4,7 @@
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: APIable.php 162 2008-01-14 04:27:21Z matt $
+ * @version $Id$
*
* @package Piwik_Visualization
*/
diff --git a/lang/ca.php b/lang/ca.php
index 5b039dd977..84962a03ed 100644
--- a/lang/ca.php
+++ b/lang/ca.php
@@ -1,602 +1,619 @@
-<?php
-
-setlocale(LC_TIME, 'ca_ES.UTF-8');
-
-$translations = array(
- 'General_Locale' => 'ca.UTF-8',
- 'General_TranslatorName' => 'Isaac Sánchez Barrera',
- 'General_TranslatorEmail' => 'isb1009@astronomipedia.es',
- 'General_EnglishLanguageName' => 'Catalan',
- 'General_OriginalLanguageName' => 'Català',
- 'General_Unknown' => 'Desconegut',
- 'General_Required' => '%s requerit',
- 'General_Error' => 'Error',
- 'General_Warning' => 'Avís',
- 'General_BackToHomepage' => 'Torna a la pàgina principal de Piwik',
- 'General_Yes' => 'Sí',
- 'General_No' => 'No',
- 'General_Delete' => 'Esborra',
- 'General_Edit' => 'Edita',
- 'General_Ok' => 'D\'acord',
- 'General_Close' => 'Tanca',
- 'General_Logout' => 'Surt',
- 'General_Done' => 'Fet',
- 'General_LoadingData' => 'Les dades s\'estan carregant&hellip;',
- 'General_ErrorRequest' => 'Ups! Hi ha hagut un problema amb la sol&middot;licitud, torneu-ho a intentar.',
- 'General_Next' => 'Seg&uuml;ent',
- 'General_Previous' => 'Anterior',
- 'General_Search' => 'Cerca',
- 'General_Others' => 'Altres',
- 'General_Table' => 'Taula',
- 'General_Piechart' => 'Gràfic de sectors',
- 'General_TagCloud' => 'Núvol d\'etiquetes',
- 'General_VBarGraph' => 'Gràfic de barres',
- 'General_Refresh' => 'Actualitza la pàgina',
- 'General_ColumnNbUniqVisitors' => 'Visitants únics',
- 'General_ColumnNbVisits' => 'Visites',
- 'General_ColumnLabel' => 'Etiqueta',
- 'General_Save' => 'Desa',
- 'General_NoDataForGraph' => 'No hi ha dades...',
- 'API_QuickDocumentation' => '<h2>Guia ràpida de l\'API</h2><p>Si no teniu dades per a avui, podeu <a href=\'misc/generateVisits.php\' target=\'_blank\'>generar-ne fent servir el Generador de visites</a>.</p><p><strong>Si voleu més informació, passeu-vos per la <a href=\'http://dev.piwik.org/trac/wiki/API\'>documentació oficial de l\'API (en anglès)</a> o les <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>referències de l\'API</a>.</strong></p><h2>Autenticació de l\'usuari</h2><p><strong>Si voleu sol&middot;licitar les dades amb un script, una tasca (crontab), etc.</strong>, necessiteu afegir el paràmetre <code><u>&token_auth=%s</u></code> per a poder invocar les URLs de l\'API que necessiten autenticació.</p><p>Aquest <tt>token_auth</tt> és tan secret com el vostre usuari i contrassenya, <strong>no l\'heu de donar a ningú!</strong></p>',
- 'API_LoadedAPIs' => 'S\'ha carregat correctament un total de %s API',
- 'Actions_SubmenuPages' => 'Pàgines',
- 'Actions_SubmenuOutlinks' => 'Enlla&ccedil;os externs',
- 'Actions_SubmenuDownloads' => 'Descàrregues',
- 'Dashboard_AddWidget' => 'Afegeix un giny&hellip;',
- 'Dashboard_DeleteWidgetConfirm' => 'Realment voleu esborrar aquest giny?',
- 'Dashboard_SelectWidget' => 'Escolliu el giny que voleu afegir a la consola',
- 'Dashboard_AddPreviewedWidget' => 'Afegeix el giny previsualitzat a la consola',
- 'Dashboard_WidgetPreview' => 'Previsualització del giny',
- 'Dashboard_TitleWidgetInDashboard_js' => 'Aquest giny ja es troba a la consola',
- 'Dashboard_TitleClickToAdd_js' => 'Feu clic per a afegir-lo a la consola',
- 'Dashboard_LoadingPreview_js' => 'S\'està carregant la previsualització&hellip;',
- 'Dashboard_LoadingWidget_js' => 'S\'està carregant el giny&hellip;',
- 'Dashboard_WidgetNotFound_js' => 'Aquest giny no s\'ha trobat',
- 'CoreHome_NoPrivileges' => 'Heu iniciat la sessió fent servir l\'usuari \'%s\', però sembla que no teniu cap permís configurat al Piwik.<br />Demaneu a l\'administrador que us doni permisos de \'vista\' a algun lloc web.',
- 'CoreHome_JavascriptDisabled' => 'És necessari tenir el JavaScript actiu si voleu fer servir el Piwik dins la vista estàndard.<br />Tot i això, sembla que teniu el JavaScript desactivat o el vostre navegador no el suporta.<br />Per a fer servir la vista estàndard, canvieu la configuració del vostre navegador i activeu el JavaScript. Llavors, %1storneu a accedir a la pàgina%2s.<br />',
- 'CoreHome_TableNoData' => 'No hi ha cap dada per a aquesta taula.',
- 'CoreHome_CategoryNoData' => 'No hi ha dades en aquesta categoria. Proveu d\'<em>incloure tota la població</em>.',
- 'CoreHome_ShowJSCode' => 'Mostra el codi JavaScript necessari',
- 'CoreHome_IncludeAllPopulation_js' => 'Inclou tota la població',
- 'CoreHome_ExcludeLowPopulation_js' => 'Exclou la població baixa',
- 'CoreHome_PageOf_js' => '%s de %s',
- 'CoreHome_Loading_js' => 'Les dades estan carregant&hellip;',
- 'CoreHome_LocalizedDateFormat' => '%A, %d de %B de %Y',
- 'CoreHome_PeriodDay' => 'Dia',
- 'CoreHome_PeriodWeek' => 'Setmana',
- 'CoreHome_PeriodMonth' => 'Mes',
- 'CoreHome_PeriodYear' => 'Any',
- 'CoreHome_DaySu_js' => 'dg',
- 'CoreHome_DayMo_js' => 'dl',
- 'CoreHome_DayTu_js' => 'dt',
- 'CoreHome_DayWe_js' => 'dc',
- 'CoreHome_DayTh_js' => 'dj',
- 'CoreHome_DayFr_js' => 'dv',
- 'CoreHome_DaySa_js' => 'ds',
- 'CoreHome_MonthJanuary_js' => 'Gener',
- 'CoreHome_MonthFebruary_js' => 'Febrer',
- 'CoreHome_MonthMarch_js' => 'Mar&ccedil;',
- 'CoreHome_MonthApril_js' => 'Abril',
- 'CoreHome_MonthMay_js' => 'Maig',
- 'CoreHome_MonthJune_js' => 'Juny',
- 'CoreHome_MonthJuly_js' => 'Juliol',
- 'CoreHome_MonthAugust_js' => 'Agost',
- 'CoreHome_MonthSeptember_js' => 'Setembre',
- 'CoreHome_MonthOctober_js' => 'Octubre',
- 'CoreHome_MonthNovember_js' => 'Novembre',
- 'CoreHome_MonthDecember_js' => 'Desembre',
- 'Installation_Installation' => 'Instal&middot;lació',
- 'Installation_InstallationStatus' => 'Estat de la instal&middot;lació',
- 'Installation_PercentDone' => '%s%% fet',
- 'Installation_NoConfigFound' => 'No s\'ha trobat el fitxer de configuració del Piwik i esteu intentant accedir una pàgina del Piwik.<br /><strong>&nbsp;&nbsp;&raquo;Podeu <a href=\'index.php\'>instal&middot;lar el Piwik ara</a></strong>.<br /><small>Si heu instal·lat el Piwik abans i teniu algunes taules a la vostra base de dades, no us preocupeu; podeu continuar fent servir les mateixes taules i les dades existents es conservaran!</small>',
- 'Installation_MysqlSetup' => 'Configuració de la base de dades MySQL',
- 'Installation_MysqlErrorConnect' => 'Hi ha hagut un error en l\'intent de connexió amb la base de dades.',
- 'Installation_JsTag' => 'Etiqueta JavaScript',
- 'Installation_JsTagHelp' => '<p>Si voleu comptar tots els visitants, heu d\'inserir el codi JavaScript a totes les pàgines.</p><p>No és necessari que estiguin fetes en PHP, el Piwik funcionarà a tots els tipus de pàgines (siguin HTML, ASP, Perl o qualsevol altre).</p><p>Aquí teniu el codi que heu d\'inserir: (copieu-lo i aferreu-lo a totes les pàgines)</p>',
- 'Installation_Congratulations' => 'Felicitats',
- 'Installation_CongratulationsHelp' => '<p>Felicitats! La instal&middot;lació del Piwik ha finalitzat.</p><p>Assegureu-vos que heu inserit el codi JavaScript a totes les pàgines, i espereu els vostres primers visitants!</p>',
- 'Installation_GoToPiwik' => 'Vés al Piwik',
- 'Installation_SetupWebsite' => 'Configura un lloc',
- 'Installation_SetupWebsiteError' => 'Hi ha hagut un problema en el moment d\'afegir el lloc.',
- 'Installation_GeneralSetup' => 'Configuració general',
- 'Installation_GeneralSetupSuccess' => 'La configuració general ha estat un èxit',
- 'Installation_SystemCheck' => 'Comprovació del sistema',
- 'Installation_SystemCheckPhp' => 'Versió del PHP',
- 'Installation_SystemCheckPdo' => 'Extensió Pdo',
- 'Installation_SystemCheckPdoMysql' => 'Extensió Pdo_Mysql',
- 'Installation_SystemCheckPdoError' => 'Necessiteu activar les extensions PDO i PDO_MYSQL al vostre fitxer php.ini',
- 'Installation_SystemCheckPdoHelp' => 'Si teniu un servidor Windows, podeu afegir les línies següents al vostre php.ini %s<br /><br />Si teniu un servidor Linux, podeu compilar el PHP amb les opcions següents %s<br /><br />Podeu trobar més informació al <a style="color:red" href="http://php.net/pdo"lloc web de PHP</a>.',
- 'Installation_SystemCheckPhpXml' => 'Extensió PHP-XML',
- 'Installation_SystemCheckWriteDirs' => 'Directoris amb permisos d\'escriptura',
- 'Installation_SystemCheckWriteDirsHelp' => 'Per a arreglar aquest error al vostre sistema Linux, proveu d\'entrar les ordres següents',
- 'Installation_SystemCheckMemoryLimit' => 'Límit de memòria',
- 'Installation_SystemCheckMemoryLimitHelp' => 'En un lloc web amb trànsit elevat, la creació de l\'arxiu pot necessitar més memòria de l\'acceptada actualment.<br />Feu una ullada al \'memory_limit\' del vostre fitxer php.ini si és necessari.',
- 'Installation_SystemCheckGD' => 'GD &gt; 2.x (gràfics)',
- 'Installation_SystemCheckGDHelp' => 'Els gràfics petits no funcionaran.',
- 'Installation_SystemCheckTimeLimit' => 'El set_time_limit() està permès.',
- 'Installation_SystemCheckTimeLimitHelp' => 'En un lloc web amb trànsit elevat, la creació de l\'arxiu pot necessitar més temps de l\'acceptada actualment.<br />Feu una ullada al \'max_execution_time\' del vostre fitxer php.ini si és necessari.',
- 'Installation_SystemCheckMail' => 'La funció mail() està permesa',
- 'Installation_SystemCheckError' => 'Hi ha hagut un error i s\'ha d\'arreglar abans de que pugueu continuar.',
- 'Installation_SystemCheckWarning' => 'El Piwik funcionarà amb normalitat, però algunes funcions potser no estaran disponibles',
- 'Installation_Tables' => 'S\'estan creant les taules&hellip;',
- 'Installation_TablesWarning' => 'Algunes <span id="linkToggle">taules del Piwik</span> ja estan instal&middot;lades a la base de dades',
- 'Installation_TablesFound' => 'Aquestes taules s\'han trobat a la base de dades:',
- 'Installation_TablesWarningHelp' => 'Podeu escollir entre fer servir les taules existents de la base de dades o fer una instal&middot;lació neta per a esborrar les dades existents a la base de dades.',
- 'Installation_TablesReuse' => 'Fes servir les taules existents',
- 'Installation_TablesDelete' => 'Esborra les taules existents',
- 'Installation_TablesDeletedSuccess' => 'Les taules del Piwik existents s\'han esborrat amb èxit.',
- 'Installation_TablesCreatedSuccess' => 'Les taules s\'han creat amb èxit!',
- 'Installation_TablesDeleteConfirm' => 'Realment voleu esborrar les taules del Piwik existents en aquesta base de dades?',
- 'Installation_Welcome' => 'Benvingut/da!',
- 'Installation_WelcomeHelp' => '<p>El Piwik és un programari d\'anàlisi web de codi obert que facilita la presa d\'informació dels vostres visitants.</p><p>Aquest procés està dividit en %s passos fàcils i trigarà uns 5 minuts.</p>',
- 'Login_PluginDescription' => 'Pàgina d\'inici de sessió, dóna les credencials als usuaris',
- 'Login_LoginPasswordNotCorrect' => 'L\'usuari o la contrasenya no són correctes',
- 'Login_Login' => 'Nom d\'usuari',
- 'Login_Password' => 'Contrasenya',
- 'Login_LoginOrEmail' => 'Nom d\'usuari o correu-e',
- 'Login_LogIn' => 'Inicia la sessió',
- 'Login_Logout' => 'Surt',
- 'Login_LostYourPassword' => 'Heu perdut la contrasenya?',
- 'Login_RemindPassword' => 'Recorda la contrasenya',
- 'Login_PasswordReminder' => 'Si us plau, inseriu el vostre nom d\'usuari o el vostre correu-e. Rebreu una contrasenya nova al vostre correu-e.',
- 'Login_InvalidUsernameEmail' => 'Aquest usuari i/o direcció de correu-e és invàlid.',
- 'Login_MailTopicPasswordRecovery' => 'Recuperació de la contrasenya',
- 'Login_MailBodyPasswordRecovery' => 'Hola %1s! La vostra nova contrasenya és %2s<br />Ara ja podeu iniciar la sessió a %3s',
- 'Login_PasswordSent' => 'La contrasenya s\'acaba d\'enviar. Reviseu el vostre correu-e',
- 'Login_ContactAdmin' => 'Possiblement sigui perquè el vostre proveïdor d\'allotjament ha desactivat la funció mail().<br />Contacteu amb l\'administrador del lloc.',
- 'Login_MailPasswordRecoveryBody' => 'Hola %1s, \n\n La nova contrasenya que teniu és: %2s \n\n Ja podeu iniciar la vostra sessió a %3s',
- 'CorePluginsAdmin_Plugins' => 'Connectors',
- 'CorePluginsAdmin_Activated' => 'Actiu',
- 'CorePluginsAdmin_ActivatedHelp' => 'Aquest connector no es pot desactivar',
- 'CorePluginsAdmin_Deactivate' => 'Desactiva',
- 'CorePluginsAdmin_Activate' => 'Activa',
- 'CorePluginsAdmin_MenuPlugins' => 'Connectors',
- 'Provider_WidgetProviders' => 'Proveïdors',
- 'Provider_SubmenuLocationsProvider' => 'Localitzacions i proveïdors',
- 'Referers_SearchEngines' => 'Cercadors',
- 'Referers_Keywords' => 'Paraules clau',
- 'Referers_DirectEntry' => 'Registre directe',
- 'Referers_Websites' => 'Llocs web',
- 'Referers_Newsletters' => 'Buttletins d\'informació',
- 'Referers_Campaigns' => 'Campanyes',
- 'Referers_Evolution' => 'Evolució durant el període',
- 'Referers_Type' => 'Tipus de referent',
- 'Referers_TypeDirectEntries' => 'Hi ha %s entrades directes',
- 'Referers_TypeSearchEngines' => 'Hi ha %s visites provinents dels motors de cerca',
- 'Referers_TypeWebsites' => 'Hi ha %s visites provinents d\'altres llocs',
- 'Referers_TypeNewsletters' => 'Hi ha %s visites provinents de butlletins',
- 'Referers_TypeCampaigns' => 'Hi ha %s visites provinents de campanyes',
- 'Referers_Other' => 'Altres',
- 'Referers_OtherDistinctSearchEngines' => 'Hi ha %s motors de cerca diferents',
- 'Referers_OtherDistinctKeywords' => 'Hi ha %s paraules clau diferents',
- 'Referers_OtherDistinctWebsites' => 'Hi ha %1s llocs web diferents (fent servir %2s URLs diferents)',
- 'Referers_OtherDistinctCampaigns' => 'Hi ha %s campanyes diferents',
- 'Referers_TagCloud' => 'Núvol d\'etiquetes',
- 'Referers_SubmenuEvolution' => 'Evolució',
- 'Referers_SubmenuSearchEngines' => 'Cercadors i paraules clau',
- 'Referers_SubmenuWebsites' => 'Llocs web',
- 'Referers_SubmenuCampaigns' => 'Campanyes',
- 'Referers_WidgetKeywords' => 'Llistat de paraules clau',
- 'Referers_WidgetCampaigns' => 'Llistat de campanyes',
- 'Referers_WidgetExternalWebsites' => 'Llistat de llocs web externs',
- 'Referers_WidgetSearchEngines' => 'Millors motors de cerca',
- 'Referers_WidgetOverview' => 'Resum',
- 'SitesManager_Sites' => 'Llocs',
- 'SitesManager_JsCode' => 'Codi JavaScript',
- 'SitesManager_JsCodeHelp' => 'Aquí teniu el codi JavaScript que heu d\'incloure a totes les pàgines',
- 'SitesManager_ShowJsCode' => 'mostra el codi',
- 'SitesManager_NoWebsites' => 'No teniu cap lloc que pugueu administrar',
- 'SitesManager_AddSite' => 'Afegeix un lloc nou',
- 'SitesManager_Id' => 'ID',
- 'SitesManager_Name' => 'Nom',
- 'SitesManager_Urls' => 'URLs',
- 'SitesManager_MenuSites' => 'Llocs',
- 'SitesManager_DeleteConfirm_js' => 'Realment voleu esborrar el lloc \'%s\'?',
- 'SitesManager_ExceptionDeleteSite' => 'No és possible eliminar aquest lloc ja que és l\'únic configurat. Afegiu un altre lloc primer i, llavors, ja esborrareu aquest.',
- 'SitesManager_ExceptionNoUrl' => 'Heu d\'especificar una URL com a mínim.',
- 'SitesManager_ExceptionEmptyName' => 'El nom del lloc no pot estar buit.',
- 'SitesManager_ExceptionInvalidUrl' => 'La URL \'%s\' no és vàlida.',
- 'TranslationsAdmin_MenuTranslations' => 'Traduccions',
- 'TranslationsAdmin_MenuLanguages' => 'Idiomes',
- 'TranslationsAdmin_Plugin' => 'Connector',
- 'TranslationsAdmin_Definition' => 'Definició',
- 'TranslationsAdmin_DefaultString' => 'Original (anglès)',
- 'TranslationsAdmin_TranslationString' => 'Traducció (idioma actual: %s)',
- 'TranslationsAdmin_Translations' => 'Traduccions',
- 'TranslationsAdmin_FixPermissions' => 'Si us plau, configureu bé els permisos dels fitxers',
- 'TranslationsAdmin_AvailableLanguages' => 'Idiomes disponibles',
- 'TranslationsAdmin_AddLanguage' => 'Afegeix un idioma',
- 'TranslationsAdmin_LanguageCode' => 'Codi de l\'idioma',
- 'TranslationsAdmin_Export' => 'Exporta un idioma',
- 'TranslationsAdmin_Import' => 'Importa un idioma',
- 'UserCountry_Country' => 'País',
- 'UserCountry_Continent' => 'Continent',
- 'UserCountry_DistinctCountries' => 'Hi ha %s pa&iuml;sos diferents',
- 'UserCountry_SubmenuLocations' => 'Localització',
- 'UserCountry_WidgetContinents' => 'Continents',
- 'UserCountry_WidgetCountries' => 'Pa&iuml;sos',
- 'UserCountry_country_ac' => 'Illes Ascensió',
- 'UserCountry_country_ad' => 'Andorra',
- 'UserCountry_country_ae' => 'Emirats Àrabs Units',
- 'UserCountry_country_af' => 'Afganistan',
- 'UserCountry_country_ag' => 'Antigua i Barbuda',
- 'UserCountry_country_ai' => 'Anguilla',
- 'UserCountry_country_al' => 'Albània',
- 'UserCountry_country_am' => 'Armènia',
- 'UserCountry_country_an' => 'Antilles Neerlandeses',
- 'UserCountry_country_ao' => 'Angola',
- 'UserCountry_country_aq' => 'Antàrtida',
- 'UserCountry_country_ar' => 'Argentina',
- 'UserCountry_country_as' => 'Samoa Nord-americana',
- 'UserCountry_country_at' => 'Àustria',
- 'UserCountry_country_au' => 'Austràlia',
- 'UserCountry_country_aw' => 'Aruba',
- 'UserCountry_country_az' => 'Azerbaidjan',
- 'UserCountry_country_ba' => 'Bòsnia i Herzegovina',
- 'UserCountry_country_bb' => 'Barbados',
- 'UserCountry_country_bd' => 'Bangla Desh',
- 'UserCountry_country_be' => 'Bèlgica',
- 'UserCountry_country_bf' => 'Burkina Faso',
- 'UserCountry_country_bg' => 'Bulgària',
- 'UserCountry_country_bh' => 'Bahrain',
- 'UserCountry_country_bi' => 'Burundi',
- 'UserCountry_country_bj' => 'Benin',
- 'UserCountry_country_bm' => 'Bermuda',
- 'UserCountry_country_bn' => 'Brunei',
- 'UserCountry_country_bo' => 'Bolívia',
- 'UserCountry_country_br' => 'Brasil',
- 'UserCountry_country_bs' => 'Bahames',
- 'UserCountry_country_bt' => 'Bhutan',
- 'UserCountry_country_bv' => 'Bouvet',
- 'UserCountry_country_bw' => 'Botswana',
- 'UserCountry_country_by' => 'Bielorússia',
- 'UserCountry_country_bz' => 'Belize',
- 'UserCountry_country_ca' => 'Canadà',
- 'UserCountry_country_cc' => 'Illes Cocos',
- 'UserCountry_country_cd' => 'República Democràtica del Congo',
- 'UserCountry_country_cf' => 'República Centreafricana',
- 'UserCountry_country_cg' => 'República del Congo',
- 'UserCountry_country_ch' => 'Suïssa',
- 'UserCountry_country_ci' => 'Costa d\'Ivori',
- 'UserCountry_country_ck' => 'Illes Cook',
- 'UserCountry_country_cl' => 'Xile',
- 'UserCountry_country_cm' => 'Camerun',
- 'UserCountry_country_cn' => 'Xina',
- 'UserCountry_country_co' => 'Colòmbia',
- 'UserCountry_country_cr' => 'Costa Rica',
- 'UserCountry_country_cs' => 'Sèrbia i Montenegro',
- 'UserCountry_country_cu' => 'Cuba',
- 'UserCountry_country_cv' => 'Cap Verd',
- 'UserCountry_country_cx' => 'Illa Christmas',
- 'UserCountry_country_cy' => 'Xipre',
- 'UserCountry_country_cz' => 'República Txeca',
- 'UserCountry_country_de' => 'Alemanya',
- 'UserCountry_country_dj' => 'Djibouti',
- 'UserCountry_country_dk' => 'Dinamarca',
- 'UserCountry_country_dm' => 'Dominica',
- 'UserCountry_country_do' => 'República Dominicana',
- 'UserCountry_country_dz' => 'Algèria',
- 'UserCountry_country_ec' => 'Equador',
- 'UserCountry_country_ee' => 'Estònia',
- 'UserCountry_country_eg' => 'Egipte',
- 'UserCountry_country_eh' => 'Sàhara Occidental',
- 'UserCountry_country_er' => 'Eritrea',
- 'UserCountry_country_es' => 'Espanya',
- 'UserCountry_country_et' => 'Etiòpia',
- 'UserCountry_country_fi' => 'Finlàndia',
- 'UserCountry_country_fj' => 'Illes Fiji',
- 'UserCountry_country_fk' => 'Illes Malvines',
- 'UserCountry_country_fm' => 'Estats Federats de Micronèsia',
- 'UserCountry_country_fo' => 'Illes Fèroe',
- 'UserCountry_country_fr' => 'Fran&ccedil;a',
- 'UserCountry_country_ga' => 'Gabon',
- 'UserCountry_country_gd' => 'Grenada',
- 'UserCountry_country_ge' => 'Geòrgia',
- 'UserCountry_country_gf' => 'Guaiana Francesa',
- 'UserCountry_country_gg' => 'Guernsey',
- 'UserCountry_country_gh' => 'Ghana',
- 'UserCountry_country_gi' => 'Gibraltar',
- 'UserCountry_country_gl' => 'Grenlàndia',
- 'UserCountry_country_gm' => 'Gàmbia',
- 'UserCountry_country_gn' => 'Guinea',
- 'UserCountry_country_gp' => 'Illa Guadalupe',
- 'UserCountry_country_gq' => 'Guinea Ecuatorial',
- 'UserCountry_country_gr' => 'Grècia',
- 'UserCountry_country_gs' => 'Illes Geòrgia del Sud i Sandwich del Sud',
- 'UserCountry_country_gt' => 'Guatemala',
- 'UserCountry_country_gu' => 'Guam',
- 'UserCountry_country_gw' => 'Guinea-Bissau',
- 'UserCountry_country_gy' => 'Guyana',
- 'UserCountry_country_hk' => 'Hong Kong',
- 'UserCountry_country_hm' => 'Illes Heard i McDonald',
- 'UserCountry_country_hn' => 'Hondures',
- 'UserCountry_country_hr' => 'Croàcia',
- 'UserCountry_country_ht' => 'Haití',
- 'UserCountry_country_hu' => 'Hongria',
- 'UserCountry_country_id' => 'Indonèsia',
- 'UserCountry_country_ie' => 'Irlanda',
- 'UserCountry_country_il' => 'Israel',
- 'UserCountry_country_im' => 'Man (illa)',
- 'UserCountry_country_in' => 'Índia',
- 'UserCountry_country_io' => 'Territori Britànic de l\'Oceà Índic',
- 'UserCountry_country_iq' => 'Iraq',
- 'UserCountry_country_ir' => 'Iran',
- 'UserCountry_country_is' => 'Islàndia',
- 'UserCountry_country_it' => 'Itàlia',
- 'UserCountry_country_je' => 'Jersey',
- 'UserCountry_country_jm' => 'Jamaica',
- 'UserCountry_country_jo' => 'Jordània',
- 'UserCountry_country_jp' => 'Japó',
- 'UserCountry_country_ke' => 'Kenya',
- 'UserCountry_country_kg' => 'Kirguizistan',
- 'UserCountry_country_kh' => 'Cambodja',
- 'UserCountry_country_ki' => 'Kiribati',
- 'UserCountry_country_km' => 'Comores',
- 'UserCountry_country_kn' => 'Saint Kitts i Nevis',
- 'UserCountry_country_kp' => 'Korea del Nord',
- 'UserCountry_country_kr' => 'Corea del Sud',
- 'UserCountry_country_kw' => 'Kuwait',
- 'UserCountry_country_ky' => 'Illes Caiman',
- 'UserCountry_country_kz' => 'Kazakhstan',
- 'UserCountry_country_la' => 'Laos',
- 'UserCountry_country_lb' => 'Líban',
- 'UserCountry_country_lc' => 'Saint Lucia',
- 'UserCountry_country_li' => 'Liechtenstein',
- 'UserCountry_country_lk' => 'Sri Lanka',
- 'UserCountry_country_lr' => 'Libèria',
- 'UserCountry_country_ls' => 'Lesotho',
- 'UserCountry_country_lt' => 'Lituània',
- 'UserCountry_country_lu' => 'Luxemburg',
- 'UserCountry_country_lv' => 'Letònia',
- 'UserCountry_country_ly' => 'Líbia',
- 'UserCountry_country_ma' => 'Marroc',
- 'UserCountry_country_mc' => 'Mònaco',
- 'UserCountry_country_md' => 'Moldàvia',
- 'UserCountry_country_mg' => 'Madagascar',
- 'UserCountry_country_mh' => 'Illes Marshall',
- 'UserCountry_country_mk' => 'Macedònia',
- 'UserCountry_country_ml' => 'Mañi',
- 'UserCountry_country_mm' => 'Myanmar',
- 'UserCountry_country_mn' => 'Mongòlia',
- 'UserCountry_country_mo' => 'Macau',
- 'UserCountry_country_mp' => 'Illes Mariannes Septentrionals',
- 'UserCountry_country_mq' => 'Martinica',
- 'UserCountry_country_mr' => 'Mauritània',
- 'UserCountry_country_ms' => 'Montserrat',
- 'UserCountry_country_mt' => 'Malta',
- 'UserCountry_country_mu' => 'Maurici',
- 'UserCountry_country_mv' => 'Maldives',
- 'UserCountry_country_mw' => 'Malawi',
- 'UserCountry_country_mx' => 'Mèxic',
- 'UserCountry_country_my' => 'Malàisia',
- 'UserCountry_country_mz' => 'Moçambic',
- 'UserCountry_country_na' => 'Namíbia',
- 'UserCountry_country_nc' => 'Nova Caledònia',
- 'UserCountry_country_ne' => 'Níger',
- 'UserCountry_country_nf' => 'Illa Norfolk',
- 'UserCountry_country_ng' => 'Nigèria',
- 'UserCountry_country_ni' => 'Nicaragua',
- 'UserCountry_country_nl' => 'Pa&iuml;sos Baixos',
- 'UserCountry_country_no' => 'Noruega',
- 'UserCountry_country_np' => 'Nepal',
- 'UserCountry_country_nr' => 'Nauru',
- 'UserCountry_country_nu' => 'Niue',
- 'UserCountry_country_nz' => 'Nova Zelanda',
- 'UserCountry_country_om' => 'Oman',
- 'UserCountry_country_pa' => 'Panamà',
- 'UserCountry_country_pe' => 'Perú',
- 'UserCountry_country_pf' => 'Polinèsia Francesa',
- 'UserCountry_country_pg' => 'Papua Nova Guinea',
- 'UserCountry_country_ph' => 'Filipines',
- 'UserCountry_country_pk' => 'Pakistan',
- 'UserCountry_country_pl' => 'Polònia',
- 'UserCountry_country_pm' => 'Saint-Pierre i Miquelon',
- 'UserCountry_country_pn' => 'Illes Pitcairn',
- 'UserCountry_country_pr' => 'Puerto Rico',
- 'UserCountry_country_ps' => 'Territori Palestí',
- 'UserCountry_country_pt' => 'Portugal',
- 'UserCountry_country_pw' => 'Palau',
- 'UserCountry_country_py' => 'Paraguai',
- 'UserCountry_country_qa' => 'Qatar',
- 'UserCountry_country_re' => 'Illa de la Reunió',
- 'UserCountry_country_ro' => 'Romania',
- 'UserCountry_country_rw' => 'Rwanda',
- 'UserCountry_country_sa' => 'Aràbia Saudita',
- 'UserCountry_country_sb' => 'Illes Salomó',
- 'UserCountry_country_sc' => 'Seychelles',
- 'UserCountry_country_sd' => 'Sudan',
- 'UserCountry_country_se' => 'Suècia',
- 'UserCountry_country_sg' => 'Singapur',
- 'UserCountry_country_sh' => 'Saint Helena',
- 'UserCountry_country_si' => 'Eslovènia',
- 'UserCountry_country_sj' => 'Svalbard',
- 'UserCountry_country_sk' => 'Eslovàquia',
- 'UserCountry_country_sl' => 'Sierra Leone',
- 'UserCountry_country_sm' => 'San Marino',
- 'UserCountry_country_sn' => 'Senegal',
- 'UserCountry_country_so' => 'Somàlia',
- 'UserCountry_country_sr' => 'Surinam',
- 'UserCountry_country_st' => 'São Tomé i Príncipe',
- 'UserCountry_country_su' => 'Antiga URSS',
- 'UserCountry_country_sv' => 'El Salvador',
- 'UserCountry_country_sy' => 'Síria',
- 'UserCountry_country_sz' => 'Swazilàndia',
- 'UserCountry_country_tc' => 'Illes Turks i Caicos',
- 'UserCountry_country_td' => 'Txad',
- 'UserCountry_country_tf' => 'Terres Australs i Antàrtiques Franceses',
- 'UserCountry_country_tg' => 'Togo',
- 'UserCountry_country_th' => 'Tailàndia',
- 'UserCountry_country_tj' => 'Tadjikistan',
- 'UserCountry_country_tk' => 'Tokelau',
- 'UserCountry_country_tm' => 'Turkmenistan',
- 'UserCountry_country_tn' => 'Tunísia',
- 'UserCountry_country_to' => 'Tonga',
- 'UserCountry_country_tp' => 'Timor Oriental',
- 'UserCountry_country_tr' => 'Turquia',
- 'UserCountry_country_tt' => 'Trinitat i Tobago',
- 'UserCountry_country_tv' => 'Tuvalu',
- 'UserCountry_country_tw' => 'Taiwan',
- 'UserCountry_country_tz' => 'Tanzània',
- 'UserCountry_country_ua' => 'Ucraïna',
- 'UserCountry_country_ug' => 'Uganda',
- 'UserCountry_country_uk' => 'Regne Unit',
- 'UserCountry_country_gb' => 'Gran Bretanya',
- 'UserCountry_country_um' => 'Illes Perifèriques Menors dels EUA',
- 'UserCountry_country_us' => 'EUA',
- 'UserCountry_country_uy' => 'Uruguai',
- 'UserCountry_country_uz' => 'Uzbekistan',
- 'UserCountry_country_va' => 'Ciutat del Vaticà',
- 'UserCountry_country_vc' => 'Saint Vincent i les Grenadines',
- 'UserCountry_country_ve' => 'Veneçuela',
- 'UserCountry_country_vg' => 'Illes Verges Britàniques',
- 'UserCountry_country_vi' => 'Illes Verges Americanes',
- 'UserCountry_country_vn' => 'Vietnam',
- 'UserCountry_country_vu' => 'Vanuatu',
- 'UserCountry_country_wf' => 'Wallis i Futuna',
- 'UserCountry_country_ws' => 'Samoa',
- 'UserCountry_country_ye' => 'Iemen',
- 'UserCountry_country_yt' => 'Mayotte',
- 'UserCountry_country_yu' => 'Iugoslàvia',
- 'UserCountry_country_za' => 'Sud-àfrica',
- 'UserCountry_country_zm' => 'Zàmbia',
- 'UserCountry_country_zr' => 'Zaire',
- 'UserCountry_country_zw' => 'Zimbabwe',
- 'UserCountry_continent_eur' => 'Europa',
- 'UserCountry_continent_afr' => 'Àfrica',
- 'UserCountry_continent_asi' => 'Àsia',
- 'UserCountry_continent_ams' => 'Amèrica Central i del Sud',
- 'UserCountry_continent_amn' => 'Amèrica del Nord',
- 'UserCountry_continent_oce' => 'Oceania',
- 'UserSettings_BrowserFamilies' => 'Motors dels navegadors',
- 'UserSettings_Browsers' => 'Navegadors',
- 'UserSettings_Plugins' => 'Connectors',
- 'UserSettings_Configurations' => 'Configuracions',
- 'UserSettings_OperatinsSystems' => 'Sistemes operatius',
- 'UserSettings_Resolutions' => 'Resolucions',
- 'UserSettings_WideScreen' => 'Pantalla panoràmica',
- 'UserSettings_WidgetResolutions' => 'Resoulucions',
- 'UserSettings_WidgetBrowsers' => 'Navegadors',
- 'UserSettings_WidgetPlugins' => 'Llistat de connectors',
- 'UserSettings_WidgetWidescreen' => 'Normal / panoràmica',
- 'UserSettings_WidgetBrowserFamilies' => 'Navegadors per motor',
- 'UserSettings_WidgetOperatingSystems' => 'Sistemes operatius',
- 'UserSettings_WidgetGlobalVisitors' => 'Configuracions globals dels visitants',
- 'UserSettings_SubmenuSettings' => 'Configuracions',
- 'UsersManager_ManageAccess' => 'Gestiona els permisos',
- 'UsersManager_Sites' => 'Llocs',
- 'UsersManager_AllWebsites' => 'Tots els llocs',
- 'UsersManager_ApplyToAllWebsites' => 'Aplica a tots els llocs',
- 'UsersManager_User' => 'Usuari',
- 'UsersManager_PrivNone' => 'Sense accés',
- 'UsersManager_PrivView' => 'Vista',
- 'UsersManager_PrivAdmin' => 'Administració',
- 'UsersManager_ChangeAllConfirm' => 'Realment voleu canviar els permisos de \'%s\' a tots els llocs web?',
- 'UsersManager_Login' => 'Nom d\'usuari',
- 'UsersManager_Password' => 'Contrasenya',
- 'UsersManager_Email' => 'Correu-e',
- 'UsersManager_Alias' => 'Àlies',
- 'UsersManager_Token' => 'token_auth',
- 'UsersManager_Edit' => 'Edita',
- 'UsersManager_AddUser' => 'Afegeix un usuari nou',
- 'UsersManager_MenuUsers' => 'Usuaris',
- 'UsersManager_DeleteConfirm_js' => 'Esteu segur que voleu eliminar l\'usuari %s?',
- 'UsersManager_ExceptionLoginExists' => 'L\'usuari \'%s\' ja existeix.',
- 'UsersManager_ExceptionEmailExists' => 'La direcció de correu-e \'%s\' ja està en un altre compte.',
- 'UsersManager_ExceptionInvalidLogin' => 'El nom d\'usuari només pot contenir lletres, números o els caràcters \'_\' o \'-\' o \'.\'',
- 'UsersManager_ExceptionInvalidPassword' => 'La contrasenya ha de tenir entre 6 i 26 caràcters.',
- 'UsersManager_ExceptionInvalidEmail' => 'La direcció de correu-e no té un format vàlid.',
- 'UsersManager_ExceptionDeleteDoesNotExist' => 'L\'usuari \'%s\' no existeix i, per tant, no es pot esborrar.',
- 'UsersManager_ExceptionAdminAnonymous' => 'No podeu donar permisos d\'administració a l\'usuari \'anonymous\' (anònim).',
- 'UsersManager_ExceptionEditAnonymous' => 'L\'usuari anònim no es pot editar o esborrar. El Piwik el fa servir per als usuaris que no han iniciat encara la sessió. Per exemple, podeu fer públiques les vostres estadístiques garantint el permís \'vista\' a l\'usuari \'anonymous\' (anònim).',
- 'UsersManager_ExceptionUserDoesNotExist' => 'L\'usuari \'%s\' no existeix.',
- 'UsersManager_ExceptionAccessValues' => 'El paràmetre permisos ha de tenir un dels següents valors: [ %s ]',
- 'VisitFrequency_Evolution' => 'Evolució del període',
- 'VisitFrequency_ReturnVisits' => 'Han tornat %s visites',
- 'VisitFrequency_ReturnActions' => 'Les visites que han tornat han fet %s accions',
- 'VisitFrequency_ReturnMaxActions' => 'Una visita que ha tornat ha fet un màxim de %s accions',
- 'VisitFrequency_ReturnTotalTime' => '%s de temps que han fet servir les visites que han tornat',
- 'VisitFrequency_ReturnBounces' => 'Una visita que ha tornat ha rebotat %s cops (ha abandonat el lloc després de veure només una pàgina)',
- 'VisitFrequency_WidgetOverview' => 'Resum de la freq&uuml;ència',
- 'VisitFrequency_WidgetGraphReturning' => 'Gràfic de les visites que han tornat',
- 'VisitFrequency_SubmenuFrequency' => 'Freq&uuml;ència',
- 'VisitTime_LocalTime' => 'Visites segons l\'hora local',
- 'VisitTime_ServerTime' => 'Visites segons l\'hora del servidor',
- 'VisitTime_WidgetLocalTime' => 'Visites segons l\'hora local',
- 'VisitTime_WidgetServerTime' => 'Visites segons l\'hora del servidor',
- 'VisitTime_SubmenuTimes' => 'Hores',
- 'VisitTime_NHour' => '%sh',
- 'VisitorInterest_VisitsPerDuration' => 'Visites segons la durada',
- 'VisitorInterest_VisitsPerNbOfPages' => 'Visites segons el nombre de pàgines',
- 'VisitorInterest_WidgetLengths' => 'Durada de les visites',
- 'VisitorInterest_WidgetPages' => 'Pàgines per visita',
- 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Freqüència i lleialtat',
- 'VisitorInterest_PlusXMin' => '%s min',
- 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
- 'VisitorInterest_OnePage' => '1 pàgina',
- 'VisitorInterest_NPages' => '%s pàgines',
- 'VisitorInterest_BetweenXYSeconds' => '%1s-%2ss',
- 'VisitsSummary_NbVisits' => '%s visites',
- 'VisitsSummary_NbUniqueVisitors' => '%s visitants únics',
- 'VisitsSummary_NbActions' => '%s accions (pàgines vistes)',
- 'VisitsSummary_TotalTime' => '%s de temps en total fet servir pels visitants',
- 'VisitsSummary_MaxNbActions' => 'Hi ha %s accions màximes en una visita',
- 'VisitsSummary_NbBounced' => '%s visitants han rebotat (han abandonat el lloc després de veure només una pàgina)',
- 'VisitsSummary_Evolution' => 'Evolució dels 30 darrers %ss',
- 'VisitsSummary_Report' => 'Informe',
- 'VisitsSummary_GenerateTime' => 'S\'han trigat %s segons en generar la pàgina',
- 'VisitsSummary_GenerateQueries' => 'S\'ha executat un total de %s consultes',
- 'VisitsSummary_WidgetLastVisits' => 'Gràfic de les darreres visites',
- 'VisitsSummary_WidgetVisits' => 'Resum de les visites',
- 'VisitsSummary_WidgetLastVisitors' => 'Gràfic dels darrers visitants únics',
- 'VisitsSummary_WidgetOverviewGraph' => 'Resum amb gràfic',
- 'VisitsSummary_SubmenuOverview' => 'Resum',
- 'General_Export' => 'Exporta',
- 'General_Visitors' => 'Visitants',
- 'General_NoDataForTagCloud' => 'No hi ha dades...',
- 'General_PiwikIsACollaborativeProject' => '%s El Piwik %s és un projecte col&middot;laboratiu que encara està en fase Beta. %s Si voleu ajudar, si us plau %s contacteu-nos!%s.',
- 'CorePluginsAdmin_PluginsManagement' => 'Gestina els connectors',
- 'CorePluginsAdmin_MainDescription' => 'Els connectors augmenten la funcionalitat del Piwik. Un cop hi ha un connector instal&middot;lat, podeu activar-lo i desactivar-lo aquí.',
- 'CorePluginsAdmin_Plugin' => 'Connector',
- 'CorePluginsAdmin_Version' => 'Versió',
- 'CorePluginsAdmin_Description' => 'Descripció',
- 'CorePluginsAdmin_Status' => 'Estat',
- 'CorePluginsAdmin_Action' => 'Acció',
- 'CorePluginsAdmin_PluginHomepage' => 'Pàgina web',
- 'CorePluginsAdmin_Active' => 'Actiu',
- 'CorePluginsAdmin_Inactive' => 'Inactiu',
- 'Actions_Actions' => 'Accions',
- 'Dashboard_Dashboard' => 'Tauler',
- 'Referers_Referers' => 'Referents',
- 'UsersManager_UsersManagement' => 'Gestiona els usuaris',
- 'UsersManager_UsersManagementMainDescription' => 'Creeu nous usuaris o actualitzeu els existents.
-Podeu configurar els seus permisos a dalt.',
- 'UsersManager_MainDescription' => 'Decidiu quin tipus d\'accés té cada usuari al Piwik. També podeu configurar tots els llocs web de cop.',
- 'SitesManager_WebsitesManagement' => 'Gestiona els llocs',
- 'SitesManager_MainDescription' => 'Els informes d\'anàlisi web necessiten llocs web! Afegiu, actualitzeu i esborreu-ne. Veieu també el codi JavaScript que heu d\'inserir a les pàgines',
- 'DBStats_DatabaseUsage' => 'Ús de la base de dades',
- 'DBStats_MainDescription' => 'El Piwik desa totes les anàlisis web la base de dades MySQL. Ara per ara, les taules del Piwik fan servir %s.',
- 'DBStats_Table' => 'Taula',
- 'DBStats_RowNumber' => 'Núm. fila',
- 'DBStats_DataSize' => 'Grandària de les dades',
- 'DBStats_IndexSize' => 'Grandària del l\'índex',
- 'General_Website' => 'Lloc web',
- 'CoreUpdater_UpdateTitle' => 'Actualització del Piwik',
- 'CoreUpdater_UpdateRequired' => 'Hi ha una actualització necessària',
- 'CoreUpdater_YourDatabaseIsOutOfDate' => 'La base de dades del Piwik és antiga i cal actualitzar-la abans de continuar.',
- 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'El Piwik s\'actualitzarà a la versió %s.',
- 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Aquests connectors s\'actualitzaran: %s.',
- 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'El procés d\'actualització pot durar una estona, tingueu paciència.',
- 'CoreUpdater_UpgradePiwik' => 'Actualitza el Piwik',
- 'CoreUpdater_HelpMessageContent' => 'Comproveu les %s PMF del Piwik (en anglès) %s, que intenten explicar els errors més comuns a l\'actualització. %s Pregunteu a l\'administrador del sistema, podria ajudar-vos amb l\'error, que sembla estar relacionat amb el servidor o la instal&middot;lació del MySQL.',
- 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Hi ha hagut un error crític durant el procés d\'actualització:',
- 'CoreUpdater_HelpMessageIntroductionWhenError' => 'El que hi ha a sobre és l\'error del nucli. Hauria d\'explicar la causa, però si necessiteu més ajuda, si us plau:',
- 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'La actualització s\'ha completat amb èxit, però hi ha hagut alguns problemes durant el procés. Si us plau, llegiu les descripcions que hi ha a sobre per a saber més detalls. Si voleu més informació:',
- 'CoreUpdater_UpgradeComplete' => 'S\'ha actualitzat amb èxit!',
- 'CoreUpdater_WarningMessages' => 'Avisos:',
- 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Hi ha hagut errors en l\'actualització dels connectors',
- 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'S\'han desactivat automàticament els connectors següents: %s',
- 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'El Piwik s\'ha actualitzat amb èxit!',
- 'CoreUpdater_ContinueToPiwik' => 'Vés cap al Piwik',
- 'Installation_DatabaseCreatedSuccess' => 'La base de dades %s s\'ha creat correctament!',
- 'Installation_ContinueToPiwik' => 'Vés cap al Piwik',
+<?php
+
+setlocale(LC_TIME, 'ca_ES.UTF-8');
+
+$translations = array(
+ 'General_Locale' => 'ca.UTF-8',
+ 'General_TranslatorName' => 'Isaac Sánchez Barrera',
+ 'General_TranslatorEmail' => 'isb1009@astronomipedia.es',
+ 'General_EnglishLanguageName' => 'Catalan',
+ 'General_OriginalLanguageName' => 'Català',
+ 'General_Unknown' => 'Desconegut',
+ 'General_Required' => '%s requerit',
+ 'General_Error' => 'Error',
+ 'General_Warning' => 'Avís',
+ 'General_BackToHomepage' => 'Torna a la pàgina principal de Piwik',
+ 'General_Yes' => 'Sí',
+ 'General_No' => 'No',
+ 'General_Delete' => 'Esborra',
+ 'General_Edit' => 'Edita',
+ 'General_Ok' => 'D\'acord',
+ 'General_Close' => 'Tanca',
+ 'General_Logout' => 'Surt',
+ 'General_Done' => 'Fet',
+ 'General_LoadingData' => 'Les dades s\'estan carregant&hellip;',
+ 'General_ErrorRequest' => 'Ups! Hi ha hagut un problema amb la sol&middot;licitud, torneu-ho a intentar.',
+ 'General_Next' => 'Seg&uuml;ent',
+ 'General_Previous' => 'Anterior',
+ 'General_Search' => 'Cerca',
+ 'General_Others' => 'Altres',
+ 'General_Table' => 'Taula',
+ 'General_Piechart' => 'Gràfic de sectors',
+ 'General_TagCloud' => 'Núvol d\'etiquetes',
+ 'General_VBarGraph' => 'Gràfic de barres',
+ 'General_Refresh' => 'Actualitza la pàgina',
+ 'General_ColumnNbUniqVisitors' => 'Visitants únics',
+ 'General_ColumnNbVisits' => 'Visites',
+ 'General_ColumnLabel' => 'Etiqueta',
+ 'General_Save' => 'Desa',
+ 'General_NoDataForGraph' => 'No hi ha dades...',
+ 'API_QuickDocumentation' => '<h2>Guia ràpida de l\'API</h2><p>Si no teniu dades per a avui, podeu <a href=\'misc/generateVisits.php\' target=\'_blank\'>generar-ne fent servir el Generador de visites</a>.</p><p><strong>Si voleu més informació, passeu-vos per la <a href=\'http://dev.piwik.org/trac/wiki/API\'>documentació oficial de l\'API (en anglès)</a> o les <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>referències de l\'API</a>.</strong></p><h2>Autenticació de l\'usuari</h2><p><strong>Si voleu sol&middot;licitar les dades amb un script, una tasca (crontab), etc.</strong>, necessiteu afegir el paràmetre <code><u>&token_auth=%s</u></code> per a poder invocar les URLs de l\'API que necessiten autenticació.</p><p>Aquest <tt>token_auth</tt> és tan secret com el vostre usuari i contrassenya, <strong>no l\'heu de donar a ningú!</strong></p>',
+ 'API_LoadedAPIs' => 'S\'ha carregat correctament un total de %s API',
+ 'Actions_SubmenuPages' => 'Pàgines',
+ 'Actions_SubmenuOutlinks' => 'Enlla&ccedil;os externs',
+ 'Actions_SubmenuDownloads' => 'Descàrregues',
+ 'Dashboard_AddWidget' => 'Afegeix un giny&hellip;',
+ 'Dashboard_DeleteWidgetConfirm' => 'Realment voleu esborrar aquest giny?',
+ 'Dashboard_SelectWidget' => 'Escolliu el giny que voleu afegir a la consola',
+ 'Dashboard_AddPreviewedWidget' => 'Afegeix el giny previsualitzat a la consola',
+ 'Dashboard_WidgetPreview' => 'Previsualització del giny',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Aquest giny ja es troba a la consola',
+ 'Dashboard_TitleClickToAdd_js' => 'Feu clic per a afegir-lo a la consola',
+ 'Dashboard_LoadingPreview_js' => 'S\'està carregant la previsualització&hellip;',
+ 'Dashboard_LoadingWidget_js' => 'S\'està carregant el giny&hellip;',
+ 'Dashboard_WidgetNotFound_js' => 'Aquest giny no s\'ha trobat',
+ 'CoreHome_NoPrivileges' => 'Heu iniciat la sessió fent servir l\'usuari \'%s\', però sembla que no teniu cap permís configurat al Piwik.<br />Demaneu a l\'administrador que us doni permisos de \'vista\' a algun lloc web.',
+ 'CoreHome_JavascriptDisabled' => 'És necessari tenir el JavaScript actiu si voleu fer servir el Piwik dins la vista estàndard.<br />Tot i això, sembla que teniu el JavaScript desactivat o el vostre navegador no el suporta.<br />Per a fer servir la vista estàndard, canvieu la configuració del vostre navegador i activeu el JavaScript. Llavors, %1storneu a accedir a la pàgina%2s.<br />',
+ 'CoreHome_TableNoData' => 'No hi ha cap dada per a aquesta taula.',
+ 'CoreHome_CategoryNoData' => 'No hi ha dades en aquesta categoria. Proveu d\'<em>incloure tota la població</em>.',
+ 'CoreHome_ShowJSCode' => 'Mostra el codi JavaScript necessari',
+ 'CoreHome_IncludeAllPopulation_js' => 'Inclou tota la població',
+ 'CoreHome_ExcludeLowPopulation_js' => 'Exclou la població baixa',
+ 'CoreHome_PageOf_js' => '%s de %s',
+ 'CoreHome_Loading_js' => 'Les dades estan carregant&hellip;',
+ 'CoreHome_LocalizedDateFormat' => '%A, %d de %B de %Y',
+ 'CoreHome_PeriodDay' => 'Dia',
+ 'CoreHome_PeriodWeek' => 'Setmana',
+ 'CoreHome_PeriodMonth' => 'Mes',
+ 'CoreHome_PeriodYear' => 'Any',
+ 'CoreHome_DaySu_js' => 'dg',
+ 'CoreHome_DayMo_js' => 'dl',
+ 'CoreHome_DayTu_js' => 'dt',
+ 'CoreHome_DayWe_js' => 'dc',
+ 'CoreHome_DayTh_js' => 'dj',
+ 'CoreHome_DayFr_js' => 'dv',
+ 'CoreHome_DaySa_js' => 'ds',
+ 'CoreHome_MonthJanuary_js' => 'Gener',
+ 'CoreHome_MonthFebruary_js' => 'Febrer',
+ 'CoreHome_MonthMarch_js' => 'Mar&ccedil;',
+ 'CoreHome_MonthApril_js' => 'Abril',
+ 'CoreHome_MonthMay_js' => 'Maig',
+ 'CoreHome_MonthJune_js' => 'Juny',
+ 'CoreHome_MonthJuly_js' => 'Juliol',
+ 'CoreHome_MonthAugust_js' => 'Agost',
+ 'CoreHome_MonthSeptember_js' => 'Setembre',
+ 'CoreHome_MonthOctober_js' => 'Octubre',
+ 'CoreHome_MonthNovember_js' => 'Novembre',
+ 'CoreHome_MonthDecember_js' => 'Desembre',
+ 'Installation_Installation' => 'Instal&middot;lació',
+ 'Installation_InstallationStatus' => 'Estat de la instal&middot;lació',
+ 'Installation_PercentDone' => '%s%% fet',
+ 'Installation_NoConfigFound' => 'No s\'ha trobat el fitxer de configuració del Piwik i esteu intentant accedir una pàgina del Piwik.<br /><strong>&nbsp;&nbsp;&raquo;Podeu <a href=\'index.php\'>instal&middot;lar el Piwik ara</a></strong>.<br /><small>Si heu instal·lat el Piwik abans i teniu algunes taules a la vostra base de dades, no us preocupeu; podeu continuar fent servir les mateixes taules i les dades existents es conservaran!</small>',
+ 'Installation_MysqlSetup' => 'Configuració de la base de dades MySQL',
+ 'Installation_MysqlErrorConnect' => 'Hi ha hagut un error en l\'intent de connexió amb la base de dades.',
+ 'Installation_JsTag' => 'Etiqueta JavaScript',
+ 'Installation_JsTagHelp' => '<p>Si voleu comptar tots els visitants, heu d\'inserir el codi JavaScript a totes les pàgines.</p><p>No és necessari que estiguin fetes en PHP, el Piwik funcionarà a tots els tipus de pàgines (siguin HTML, ASP, Perl o qualsevol altre).</p><p>Aquí teniu el codi que heu d\'inserir: (copieu-lo i aferreu-lo a totes les pàgines)</p>',
+ 'Installation_Congratulations' => 'Felicitats',
+ 'Installation_CongratulationsHelp' => '<p>Felicitats! La instal&middot;lació del Piwik ha finalitzat.</p><p>Assegureu-vos que heu inserit el codi JavaScript a totes les pàgines, i espereu els vostres primers visitants!</p>',
+ 'Installation_GoToPiwik' => 'Vés al Piwik',
+ 'Installation_SetupWebsite' => 'Configura un lloc',
+ 'Installation_SetupWebsiteError' => 'Hi ha hagut un problema en el moment d\'afegir el lloc.',
+ 'Installation_GeneralSetup' => 'Configuració general',
+ 'Installation_GeneralSetupSuccess' => 'La configuració general ha estat un èxit',
+ 'Installation_SystemCheck' => 'Comprovació del sistema',
+ 'Installation_SystemCheckPhp' => 'Versió del PHP',
+ 'Installation_SystemCheckPdo' => 'Extensió Pdo',
+ 'Installation_SystemCheckPdoMysql' => 'Extensió Pdo_Mysql',
+ 'Installation_SystemCheckPdoError' => 'Necessiteu activar les extensions PDO i PDO_MYSQL al vostre fitxer php.ini',
+ 'Installation_SystemCheckPdoHelp' => 'Si teniu un servidor Windows, podeu afegir les línies següents al vostre php.ini %s<br /><br />Si teniu un servidor Linux, podeu compilar el PHP amb les opcions següents %s<br /><br />Podeu trobar més informació al <a style="color:red" href="http://php.net/pdo"lloc web de PHP</a>.',
+ 'Installation_SystemCheckPhpXml' => 'Extensió PHP-XML',
+ 'Installation_SystemCheckWriteDirs' => 'Directoris amb permisos d\'escriptura',
+ 'Installation_SystemCheckWriteDirsHelp' => 'Per a arreglar aquest error al vostre sistema Linux, proveu d\'entrar les ordres següents',
+ 'Installation_SystemCheckMemoryLimit' => 'Límit de memòria',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'En un lloc web amb trànsit elevat, la creació de l\'arxiu pot necessitar més memòria de l\'acceptada actualment.<br />Feu una ullada al \'memory_limit\' del vostre fitxer php.ini si és necessari.',
+ 'Installation_SystemCheckGD' => 'GD &gt; 2.x (gràfics)',
+ 'Installation_SystemCheckGDHelp' => 'Els gràfics petits no funcionaran.',
+ 'Installation_SystemCheckTimeLimit' => 'El set_time_limit() està permès.',
+ 'Installation_SystemCheckTimeLimitHelp' => 'En un lloc web amb trànsit elevat, la creació de l\'arxiu pot necessitar més temps de l\'acceptada actualment.<br />Feu una ullada al \'max_execution_time\' del vostre fitxer php.ini si és necessari.',
+ 'Installation_SystemCheckMail' => 'La funció mail() està permesa',
+ 'Installation_SystemCheckError' => 'Hi ha hagut un error i s\'ha d\'arreglar abans de que pugueu continuar.',
+ 'Installation_SystemCheckWarning' => 'El Piwik funcionarà amb normalitat, però algunes funcions potser no estaran disponibles',
+ 'Installation_Tables' => 'S\'estan creant les taules&hellip;',
+ 'Installation_TablesWarning' => 'Algunes <span id="linkToggle">taules del Piwik</span> ja estan instal&middot;lades a la base de dades',
+ 'Installation_TablesFound' => 'Aquestes taules s\'han trobat a la base de dades:',
+ 'Installation_TablesWarningHelp' => 'Podeu escollir entre fer servir les taules existents de la base de dades o fer una instal&middot;lació neta per a esborrar les dades existents a la base de dades.',
+ 'Installation_TablesReuse' => 'Fes servir les taules existents',
+ 'Installation_TablesDelete' => 'Esborra les taules existents',
+ 'Installation_TablesDeletedSuccess' => 'Les taules del Piwik existents s\'han esborrat amb èxit.',
+ 'Installation_TablesCreatedSuccess' => 'Les taules s\'han creat amb èxit!',
+ 'Installation_TablesDeleteConfirm' => 'Realment voleu esborrar les taules del Piwik existents en aquesta base de dades?',
+ 'Installation_Welcome' => 'Benvingut/da!',
+ 'Installation_WelcomeHelp' => '<p>El Piwik és un programari d\'anàlisi web de codi obert que facilita la presa d\'informació dels vostres visitants.</p><p>Aquest procés està dividit en %s passos fàcils i trigarà uns 5 minuts.</p>',
+ 'Login_PluginDescription' => 'Pàgina d\'inici de sessió, dóna les credencials als usuaris',
+ 'Login_LoginPasswordNotCorrect' => 'L\'usuari o la contrasenya no són correctes',
+ 'Login_Login' => 'Nom d\'usuari',
+ 'Login_Password' => 'Contrasenya',
+ 'Login_LoginOrEmail' => 'Nom d\'usuari o correu-e',
+ 'Login_LogIn' => 'Inicia la sessió',
+ 'Login_Logout' => 'Surt',
+ 'Login_LostYourPassword' => 'Heu perdut la contrasenya?',
+ 'Login_RemindPassword' => 'Recorda la contrasenya',
+ 'Login_PasswordReminder' => 'Si us plau, inseriu el vostre nom d\'usuari o el vostre correu-e. Rebreu una contrasenya nova al vostre correu-e.',
+ 'Login_InvalidUsernameEmail' => 'Aquest usuari i/o direcció de correu-e és invàlid.',
+ 'Login_MailTopicPasswordRecovery' => 'Recuperació de la contrasenya',
+ 'Login_MailBodyPasswordRecovery' => 'Hola %1s! La vostra nova contrasenya és %2s<br />Ara ja podeu iniciar la sessió a %3s',
+ 'Login_PasswordSent' => 'La contrasenya s\'acaba d\'enviar. Reviseu el vostre correu-e',
+ 'Login_ContactAdmin' => 'Possiblement sigui perquè el vostre proveïdor d\'allotjament ha desactivat la funció mail().<br />Contacteu amb l\'administrador del lloc.',
+ 'Login_MailPasswordRecoveryBody' => 'Hola %1s, \n\n La nova contrasenya que teniu és: %2s \n\n Ja podeu iniciar la vostra sessió a %3s',
+ 'CorePluginsAdmin_Plugins' => 'Connectors',
+ 'CorePluginsAdmin_Activated' => 'Actiu',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Aquest connector no es pot desactivar',
+ 'CorePluginsAdmin_Deactivate' => 'Desactiva',
+ 'CorePluginsAdmin_Activate' => 'Activa',
+ 'CorePluginsAdmin_MenuPlugins' => 'Connectors',
+ 'Provider_WidgetProviders' => 'Proveïdors',
+ 'Provider_SubmenuLocationsProvider' => 'Localitzacions i proveïdors',
+ 'Referers_SearchEngines' => 'Cercadors',
+ 'Referers_Keywords' => 'Paraules clau',
+ 'Referers_DirectEntry' => 'Registre directe',
+ 'Referers_Websites' => 'Llocs web',
+ 'Referers_Newsletters' => 'Buttletins d\'informació',
+ 'Referers_Campaigns' => 'Campanyes',
+ 'Referers_Evolution' => 'Evolució durant el període',
+ 'Referers_Type' => 'Tipus de referent',
+ 'Referers_TypeDirectEntries' => 'Hi ha %s entrades directes',
+ 'Referers_TypeSearchEngines' => 'Hi ha %s visites provinents dels motors de cerca',
+ 'Referers_TypeWebsites' => 'Hi ha %s visites provinents d\'altres llocs',
+ 'Referers_TypeNewsletters' => 'Hi ha %s visites provinents de butlletins',
+ 'Referers_TypeCampaigns' => 'Hi ha %s visites provinents de campanyes',
+ 'Referers_Other' => 'Altres',
+ 'Referers_OtherDistinctSearchEngines' => 'Hi ha %s motors de cerca diferents',
+ 'Referers_OtherDistinctKeywords' => 'Hi ha %s paraules clau diferents',
+ 'Referers_OtherDistinctWebsites' => 'Hi ha %1s llocs web diferents (fent servir %2s URLs diferents)',
+ 'Referers_OtherDistinctCampaigns' => 'Hi ha %s campanyes diferents',
+ 'Referers_TagCloud' => 'Núvol d\'etiquetes',
+ 'Referers_SubmenuEvolution' => 'Evolució',
+ 'Referers_SubmenuSearchEngines' => 'Cercadors i paraules clau',
+ 'Referers_SubmenuWebsites' => 'Llocs web',
+ 'Referers_SubmenuCampaigns' => 'Campanyes',
+ 'Referers_WidgetKeywords' => 'Llistat de paraules clau',
+ 'Referers_WidgetCampaigns' => 'Llistat de campanyes',
+ 'Referers_WidgetExternalWebsites' => 'Llistat de llocs web externs',
+ 'Referers_WidgetSearchEngines' => 'Millors motors de cerca',
+ 'Referers_WidgetOverview' => 'Resum',
+ 'SitesManager_Sites' => 'Llocs',
+ 'SitesManager_JsCode' => 'Codi JavaScript',
+ 'SitesManager_JsCodeHelp' => 'Aquí teniu el codi JavaScript que heu d\'incloure a totes les pàgines',
+ 'SitesManager_ShowJsCode' => 'mostra el codi',
+ 'SitesManager_NoWebsites' => 'No teniu cap lloc que pugueu administrar',
+ 'SitesManager_AddSite' => 'Afegeix un lloc nou',
+ 'SitesManager_Id' => 'ID',
+ 'SitesManager_Name' => 'Nom',
+ 'SitesManager_Urls' => 'URLs',
+ 'SitesManager_MenuSites' => 'Llocs',
+ 'SitesManager_DeleteConfirm_js' => 'Realment voleu esborrar el lloc \'%s\'?',
+ 'SitesManager_ExceptionDeleteSite' => 'No és possible eliminar aquest lloc ja que és l\'únic configurat. Afegiu un altre lloc primer i, llavors, ja esborrareu aquest.',
+ 'SitesManager_ExceptionNoUrl' => 'Heu d\'especificar una URL com a mínim.',
+ 'SitesManager_ExceptionEmptyName' => 'El nom del lloc no pot estar buit.',
+ 'SitesManager_ExceptionInvalidUrl' => 'La URL \'%s\' no és vàlida.',
+ 'TranslationsAdmin_MenuTranslations' => 'Traduccions',
+ 'TranslationsAdmin_MenuLanguages' => 'Idiomes',
+ 'TranslationsAdmin_Plugin' => 'Connector',
+ 'TranslationsAdmin_Definition' => 'Definició',
+ 'TranslationsAdmin_DefaultString' => 'Original (anglès)',
+ 'TranslationsAdmin_TranslationString' => 'Traducció (idioma actual: %s)',
+ 'TranslationsAdmin_Translations' => 'Traduccions',
+ 'TranslationsAdmin_FixPermissions' => 'Si us plau, configureu bé els permisos dels fitxers',
+ 'TranslationsAdmin_AvailableLanguages' => 'Idiomes disponibles',
+ 'TranslationsAdmin_AddLanguage' => 'Afegeix un idioma',
+ 'TranslationsAdmin_LanguageCode' => 'Codi de l\'idioma',
+ 'TranslationsAdmin_Export' => 'Exporta un idioma',
+ 'TranslationsAdmin_Import' => 'Importa un idioma',
+ 'UserCountry_Country' => 'País',
+ 'UserCountry_Continent' => 'Continent',
+ 'UserCountry_DistinctCountries' => 'Hi ha %s pa&iuml;sos diferents',
+ 'UserCountry_SubmenuLocations' => 'Localització',
+ 'UserCountry_WidgetContinents' => 'Continents',
+ 'UserCountry_WidgetCountries' => 'Pa&iuml;sos',
+ 'UserCountry_country_ac' => 'Illes Ascensió',
+ 'UserCountry_country_ad' => 'Andorra',
+ 'UserCountry_country_ae' => 'Emirats Àrabs Units',
+ 'UserCountry_country_af' => 'Afganistan',
+ 'UserCountry_country_ag' => 'Antigua i Barbuda',
+ 'UserCountry_country_ai' => 'Anguilla',
+ 'UserCountry_country_al' => 'Albània',
+ 'UserCountry_country_am' => 'Armènia',
+ 'UserCountry_country_an' => 'Antilles Neerlandeses',
+ 'UserCountry_country_ao' => 'Angola',
+ 'UserCountry_country_aq' => 'Antàrtida',
+ 'UserCountry_country_ar' => 'Argentina',
+ 'UserCountry_country_as' => 'Samoa Nord-americana',
+ 'UserCountry_country_at' => 'Àustria',
+ 'UserCountry_country_au' => 'Austràlia',
+ 'UserCountry_country_aw' => 'Aruba',
+ 'UserCountry_country_az' => 'Azerbaidjan',
+ 'UserCountry_country_ba' => 'Bòsnia i Herzegovina',
+ 'UserCountry_country_bb' => 'Barbados',
+ 'UserCountry_country_bd' => 'Bangla Desh',
+ 'UserCountry_country_be' => 'Bèlgica',
+ 'UserCountry_country_bf' => 'Burkina Faso',
+ 'UserCountry_country_bg' => 'Bulgària',
+ 'UserCountry_country_bh' => 'Bahrain',
+ 'UserCountry_country_bi' => 'Burundi',
+ 'UserCountry_country_bj' => 'Benin',
+ 'UserCountry_country_bm' => 'Bermuda',
+ 'UserCountry_country_bn' => 'Brunei',
+ 'UserCountry_country_bo' => 'Bolívia',
+ 'UserCountry_country_br' => 'Brasil',
+ 'UserCountry_country_bs' => 'Bahames',
+ 'UserCountry_country_bt' => 'Bhutan',
+ 'UserCountry_country_bv' => 'Bouvet',
+ 'UserCountry_country_bw' => 'Botswana',
+ 'UserCountry_country_by' => 'Bielorússia',
+ 'UserCountry_country_bz' => 'Belize',
+ 'UserCountry_country_ca' => 'Canadà',
+ 'UserCountry_country_cc' => 'Illes Cocos',
+ 'UserCountry_country_cd' => 'República Democràtica del Congo',
+ 'UserCountry_country_cf' => 'República Centreafricana',
+ 'UserCountry_country_cg' => 'República del Congo',
+ 'UserCountry_country_ch' => 'Suïssa',
+ 'UserCountry_country_ci' => 'Costa d\'Ivori',
+ 'UserCountry_country_ck' => 'Illes Cook',
+ 'UserCountry_country_cl' => 'Xile',
+ 'UserCountry_country_cm' => 'Camerun',
+ 'UserCountry_country_cn' => 'Xina',
+ 'UserCountry_country_co' => 'Colòmbia',
+ 'UserCountry_country_cr' => 'Costa Rica',
+ 'UserCountry_country_cs' => 'Sèrbia i Montenegro',
+ 'UserCountry_country_cu' => 'Cuba',
+ 'UserCountry_country_cv' => 'Cap Verd',
+ 'UserCountry_country_cx' => 'Illa Christmas',
+ 'UserCountry_country_cy' => 'Xipre',
+ 'UserCountry_country_cz' => 'República Txeca',
+ 'UserCountry_country_de' => 'Alemanya',
+ 'UserCountry_country_dj' => 'Djibouti',
+ 'UserCountry_country_dk' => 'Dinamarca',
+ 'UserCountry_country_dm' => 'Dominica',
+ 'UserCountry_country_do' => 'República Dominicana',
+ 'UserCountry_country_dz' => 'Algèria',
+ 'UserCountry_country_ec' => 'Equador',
+ 'UserCountry_country_ee' => 'Estònia',
+ 'UserCountry_country_eg' => 'Egipte',
+ 'UserCountry_country_eh' => 'Sàhara Occidental',
+ 'UserCountry_country_er' => 'Eritrea',
+ 'UserCountry_country_es' => 'Espanya',
+ 'UserCountry_country_et' => 'Etiòpia',
+ 'UserCountry_country_fi' => 'Finlàndia',
+ 'UserCountry_country_fj' => 'Illes Fiji',
+ 'UserCountry_country_fk' => 'Illes Malvines',
+ 'UserCountry_country_fm' => 'Estats Federats de Micronèsia',
+ 'UserCountry_country_fo' => 'Illes Fèroe',
+ 'UserCountry_country_fr' => 'Fran&ccedil;a',
+ 'UserCountry_country_ga' => 'Gabon',
+ 'UserCountry_country_gd' => 'Grenada',
+ 'UserCountry_country_ge' => 'Geòrgia',
+ 'UserCountry_country_gf' => 'Guaiana Francesa',
+ 'UserCountry_country_gg' => 'Guernsey',
+ 'UserCountry_country_gh' => 'Ghana',
+ 'UserCountry_country_gi' => 'Gibraltar',
+ 'UserCountry_country_gl' => 'Grenlàndia',
+ 'UserCountry_country_gm' => 'Gàmbia',
+ 'UserCountry_country_gn' => 'Guinea',
+ 'UserCountry_country_gp' => 'Illa Guadalupe',
+ 'UserCountry_country_gq' => 'Guinea Ecuatorial',
+ 'UserCountry_country_gr' => 'Grècia',
+ 'UserCountry_country_gs' => 'Illes Geòrgia del Sud i Sandwich del Sud',
+ 'UserCountry_country_gt' => 'Guatemala',
+ 'UserCountry_country_gu' => 'Guam',
+ 'UserCountry_country_gw' => 'Guinea-Bissau',
+ 'UserCountry_country_gy' => 'Guyana',
+ 'UserCountry_country_hk' => 'Hong Kong',
+ 'UserCountry_country_hm' => 'Illes Heard i McDonald',
+ 'UserCountry_country_hn' => 'Hondures',
+ 'UserCountry_country_hr' => 'Croàcia',
+ 'UserCountry_country_ht' => 'Haití',
+ 'UserCountry_country_hu' => 'Hongria',
+ 'UserCountry_country_id' => 'Indonèsia',
+ 'UserCountry_country_ie' => 'Irlanda',
+ 'UserCountry_country_il' => 'Israel',
+ 'UserCountry_country_im' => 'Man (illa)',
+ 'UserCountry_country_in' => 'Índia',
+ 'UserCountry_country_io' => 'Territori Britànic de l\'Oceà Índic',
+ 'UserCountry_country_iq' => 'Iraq',
+ 'UserCountry_country_ir' => 'Iran',
+ 'UserCountry_country_is' => 'Islàndia',
+ 'UserCountry_country_it' => 'Itàlia',
+ 'UserCountry_country_je' => 'Jersey',
+ 'UserCountry_country_jm' => 'Jamaica',
+ 'UserCountry_country_jo' => 'Jordània',
+ 'UserCountry_country_jp' => 'Japó',
+ 'UserCountry_country_ke' => 'Kenya',
+ 'UserCountry_country_kg' => 'Kirguizistan',
+ 'UserCountry_country_kh' => 'Cambodja',
+ 'UserCountry_country_ki' => 'Kiribati',
+ 'UserCountry_country_km' => 'Comores',
+ 'UserCountry_country_kn' => 'Saint Kitts i Nevis',
+ 'UserCountry_country_kp' => 'Korea del Nord',
+ 'UserCountry_country_kr' => 'Corea del Sud',
+ 'UserCountry_country_kw' => 'Kuwait',
+ 'UserCountry_country_ky' => 'Illes Caiman',
+ 'UserCountry_country_kz' => 'Kazakhstan',
+ 'UserCountry_country_la' => 'Laos',
+ 'UserCountry_country_lb' => 'Líban',
+ 'UserCountry_country_lc' => 'Saint Lucia',
+ 'UserCountry_country_li' => 'Liechtenstein',
+ 'UserCountry_country_lk' => 'Sri Lanka',
+ 'UserCountry_country_lr' => 'Libèria',
+ 'UserCountry_country_ls' => 'Lesotho',
+ 'UserCountry_country_lt' => 'Lituània',
+ 'UserCountry_country_lu' => 'Luxemburg',
+ 'UserCountry_country_lv' => 'Letònia',
+ 'UserCountry_country_ly' => 'Líbia',
+ 'UserCountry_country_ma' => 'Marroc',
+ 'UserCountry_country_mc' => 'Mònaco',
+ 'UserCountry_country_md' => 'Moldàvia',
+ 'UserCountry_country_mg' => 'Madagascar',
+ 'UserCountry_country_mh' => 'Illes Marshall',
+ 'UserCountry_country_mk' => 'Macedònia',
+ 'UserCountry_country_ml' => 'Mañi',
+ 'UserCountry_country_mm' => 'Myanmar',
+ 'UserCountry_country_mn' => 'Mongòlia',
+ 'UserCountry_country_mo' => 'Macau',
+ 'UserCountry_country_mp' => 'Illes Mariannes Septentrionals',
+ 'UserCountry_country_mq' => 'Martinica',
+ 'UserCountry_country_mr' => 'Mauritània',
+ 'UserCountry_country_ms' => 'Montserrat',
+ 'UserCountry_country_mt' => 'Malta',
+ 'UserCountry_country_mu' => 'Maurici',
+ 'UserCountry_country_mv' => 'Maldives',
+ 'UserCountry_country_mw' => 'Malawi',
+ 'UserCountry_country_mx' => 'Mèxic',
+ 'UserCountry_country_my' => 'Malàisia',
+ 'UserCountry_country_mz' => 'Moçambic',
+ 'UserCountry_country_na' => 'Namíbia',
+ 'UserCountry_country_nc' => 'Nova Caledònia',
+ 'UserCountry_country_ne' => 'Níger',
+ 'UserCountry_country_nf' => 'Illa Norfolk',
+ 'UserCountry_country_ng' => 'Nigèria',
+ 'UserCountry_country_ni' => 'Nicaragua',
+ 'UserCountry_country_nl' => 'Pa&iuml;sos Baixos',
+ 'UserCountry_country_no' => 'Noruega',
+ 'UserCountry_country_np' => 'Nepal',
+ 'UserCountry_country_nr' => 'Nauru',
+ 'UserCountry_country_nu' => 'Niue',
+ 'UserCountry_country_nz' => 'Nova Zelanda',
+ 'UserCountry_country_om' => 'Oman',
+ 'UserCountry_country_pa' => 'Panamà',
+ 'UserCountry_country_pe' => 'Perú',
+ 'UserCountry_country_pf' => 'Polinèsia Francesa',
+ 'UserCountry_country_pg' => 'Papua Nova Guinea',
+ 'UserCountry_country_ph' => 'Filipines',
+ 'UserCountry_country_pk' => 'Pakistan',
+ 'UserCountry_country_pl' => 'Polònia',
+ 'UserCountry_country_pm' => 'Saint-Pierre i Miquelon',
+ 'UserCountry_country_pn' => 'Illes Pitcairn',
+ 'UserCountry_country_pr' => 'Puerto Rico',
+ 'UserCountry_country_ps' => 'Territori Palestí',
+ 'UserCountry_country_pt' => 'Portugal',
+ 'UserCountry_country_pw' => 'Palau',
+ 'UserCountry_country_py' => 'Paraguai',
+ 'UserCountry_country_qa' => 'Qatar',
+ 'UserCountry_country_re' => 'Illa de la Reunió',
+ 'UserCountry_country_ro' => 'Romania',
+ 'UserCountry_country_rw' => 'Rwanda',
+ 'UserCountry_country_sa' => 'Aràbia Saudita',
+ 'UserCountry_country_sb' => 'Illes Salomó',
+ 'UserCountry_country_sc' => 'Seychelles',
+ 'UserCountry_country_sd' => 'Sudan',
+ 'UserCountry_country_se' => 'Suècia',
+ 'UserCountry_country_sg' => 'Singapur',
+ 'UserCountry_country_sh' => 'Saint Helena',
+ 'UserCountry_country_si' => 'Eslovènia',
+ 'UserCountry_country_sj' => 'Svalbard',
+ 'UserCountry_country_sk' => 'Eslovàquia',
+ 'UserCountry_country_sl' => 'Sierra Leone',
+ 'UserCountry_country_sm' => 'San Marino',
+ 'UserCountry_country_sn' => 'Senegal',
+ 'UserCountry_country_so' => 'Somàlia',
+ 'UserCountry_country_sr' => 'Surinam',
+ 'UserCountry_country_st' => 'São Tomé i Príncipe',
+ 'UserCountry_country_su' => 'Antiga URSS',
+ 'UserCountry_country_sv' => 'El Salvador',
+ 'UserCountry_country_sy' => 'Síria',
+ 'UserCountry_country_sz' => 'Swazilàndia',
+ 'UserCountry_country_tc' => 'Illes Turks i Caicos',
+ 'UserCountry_country_td' => 'Txad',
+ 'UserCountry_country_tf' => 'Terres Australs i Antàrtiques Franceses',
+ 'UserCountry_country_tg' => 'Togo',
+ 'UserCountry_country_th' => 'Tailàndia',
+ 'UserCountry_country_tj' => 'Tadjikistan',
+ 'UserCountry_country_tk' => 'Tokelau',
+ 'UserCountry_country_tm' => 'Turkmenistan',
+ 'UserCountry_country_tn' => 'Tunísia',
+ 'UserCountry_country_to' => 'Tonga',
+ 'UserCountry_country_tp' => 'Timor Oriental',
+ 'UserCountry_country_tr' => 'Turquia',
+ 'UserCountry_country_tt' => 'Trinitat i Tobago',
+ 'UserCountry_country_tv' => 'Tuvalu',
+ 'UserCountry_country_tw' => 'Taiwan',
+ 'UserCountry_country_tz' => 'Tanzània',
+ 'UserCountry_country_ua' => 'Ucraïna',
+ 'UserCountry_country_ug' => 'Uganda',
+ 'UserCountry_country_uk' => 'Regne Unit',
+ 'UserCountry_country_gb' => 'Gran Bretanya',
+ 'UserCountry_country_um' => 'Illes Perifèriques Menors dels EUA',
+ 'UserCountry_country_us' => 'EUA',
+ 'UserCountry_country_uy' => 'Uruguai',
+ 'UserCountry_country_uz' => 'Uzbekistan',
+ 'UserCountry_country_va' => 'Ciutat del Vaticà',
+ 'UserCountry_country_vc' => 'Saint Vincent i les Grenadines',
+ 'UserCountry_country_ve' => 'Veneçuela',
+ 'UserCountry_country_vg' => 'Illes Verges Britàniques',
+ 'UserCountry_country_vi' => 'Illes Verges Americanes',
+ 'UserCountry_country_vn' => 'Vietnam',
+ 'UserCountry_country_vu' => 'Vanuatu',
+ 'UserCountry_country_wf' => 'Wallis i Futuna',
+ 'UserCountry_country_ws' => 'Samoa',
+ 'UserCountry_country_ye' => 'Iemen',
+ 'UserCountry_country_yt' => 'Mayotte',
+ 'UserCountry_country_yu' => 'Iugoslàvia',
+ 'UserCountry_country_za' => 'Sud-àfrica',
+ 'UserCountry_country_zm' => 'Zàmbia',
+ 'UserCountry_country_zr' => 'Zaire',
+ 'UserCountry_country_zw' => 'Zimbabwe',
+ 'UserCountry_continent_eur' => 'Europa',
+ 'UserCountry_continent_afr' => 'Àfrica',
+ 'UserCountry_continent_asi' => 'Àsia',
+ 'UserCountry_continent_ams' => 'Amèrica Central i del Sud',
+ 'UserCountry_continent_amn' => 'Amèrica del Nord',
+ 'UserCountry_continent_oce' => 'Oceania',
+ 'UserSettings_BrowserFamilies' => 'Motors dels navegadors',
+ 'UserSettings_Browsers' => 'Navegadors',
+ 'UserSettings_Plugins' => 'Connectors',
+ 'UserSettings_Configurations' => 'Configuracions',
+ 'UserSettings_OperatinsSystems' => 'Sistemes operatius',
+ 'UserSettings_Resolutions' => 'Resolucions',
+ 'UserSettings_WideScreen' => 'Pantalla panoràmica',
+ 'UserSettings_WidgetResolutions' => 'Resoulucions',
+ 'UserSettings_WidgetBrowsers' => 'Navegadors',
+ 'UserSettings_WidgetPlugins' => 'Llistat de connectors',
+ 'UserSettings_WidgetWidescreen' => 'Normal / panoràmica',
+ 'UserSettings_WidgetBrowserFamilies' => 'Navegadors per motor',
+ 'UserSettings_WidgetOperatingSystems' => 'Sistemes operatius',
+ 'UserSettings_WidgetGlobalVisitors' => 'Configuracions globals dels visitants',
+ 'UserSettings_SubmenuSettings' => 'Configuracions',
+ 'UsersManager_ManageAccess' => 'Gestiona els permisos',
+ 'UsersManager_Sites' => 'Llocs',
+ 'UsersManager_AllWebsites' => 'Tots els llocs',
+ 'UsersManager_ApplyToAllWebsites' => 'Aplica a tots els llocs',
+ 'UsersManager_User' => 'Usuari',
+ 'UsersManager_PrivNone' => 'Sense accés',
+ 'UsersManager_PrivView' => 'Vista',
+ 'UsersManager_PrivAdmin' => 'Administració',
+ 'UsersManager_ChangeAllConfirm' => 'Realment voleu canviar els permisos de \'%s\' a tots els llocs web?',
+ 'UsersManager_Login' => 'Nom d\'usuari',
+ 'UsersManager_Password' => 'Contrasenya',
+ 'UsersManager_Email' => 'Correu-e',
+ 'UsersManager_Alias' => 'Àlies',
+ 'UsersManager_Token' => 'token_auth',
+ 'UsersManager_Edit' => 'Edita',
+ 'UsersManager_AddUser' => 'Afegeix un usuari nou',
+ 'UsersManager_MenuUsers' => 'Usuaris',
+ 'UsersManager_DeleteConfirm_js' => 'Esteu segur que voleu eliminar l\'usuari %s?',
+ 'UsersManager_ExceptionLoginExists' => 'L\'usuari \'%s\' ja existeix.',
+ 'UsersManager_ExceptionEmailExists' => 'La direcció de correu-e \'%s\' ja està en un altre compte.',
+ 'UsersManager_ExceptionInvalidLogin' => 'El nom d\'usuari només pot contenir lletres, números o els caràcters \'_\' o \'-\' o \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'La contrasenya ha de tenir entre 6 i 26 caràcters.',
+ 'UsersManager_ExceptionInvalidEmail' => 'La direcció de correu-e no té un format vàlid.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'L\'usuari \'%s\' no existeix i, per tant, no es pot esborrar.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'No podeu donar permisos d\'administració a l\'usuari \'anonymous\' (anònim).',
+ 'UsersManager_ExceptionEditAnonymous' => 'L\'usuari anònim no es pot editar o esborrar. El Piwik el fa servir per als usuaris que no han iniciat encara la sessió. Per exemple, podeu fer públiques les vostres estadístiques garantint el permís \'vista\' a l\'usuari \'anonymous\' (anònim).',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'L\'usuari \'%s\' no existeix.',
+ 'UsersManager_ExceptionAccessValues' => 'El paràmetre permisos ha de tenir un dels següents valors: [ %s ]',
+ 'VisitFrequency_Evolution' => 'Evolució del període',
+ 'VisitFrequency_ReturnVisits' => 'Han tornat %s visites',
+ 'VisitFrequency_ReturnActions' => 'Les visites que han tornat han fet %s accions',
+ 'VisitFrequency_ReturnMaxActions' => 'Una visita que ha tornat ha fet un màxim de %s accions',
+ 'VisitFrequency_ReturnTotalTime' => '%s de temps que han fet servir les visites que han tornat',
+ 'VisitFrequency_ReturnBounces' => 'Una visita que ha tornat ha rebotat %s cops (ha abandonat el lloc després de veure només una pàgina)',
+ 'VisitFrequency_WidgetOverview' => 'Resum de la freq&uuml;ència',
+ 'VisitFrequency_WidgetGraphReturning' => 'Gràfic de les visites que han tornat',
+ 'VisitFrequency_SubmenuFrequency' => 'Freq&uuml;ència',
+ 'VisitTime_LocalTime' => 'Visites segons l\'hora local',
+ 'VisitTime_ServerTime' => 'Visites segons l\'hora del servidor',
+ 'VisitTime_WidgetLocalTime' => 'Visites segons l\'hora local',
+ 'VisitTime_WidgetServerTime' => 'Visites segons l\'hora del servidor',
+ 'VisitTime_SubmenuTimes' => 'Hores',
+ 'VisitTime_NHour' => '%sh',
+ 'VisitorInterest_VisitsPerDuration' => 'Visites segons la durada',
+ 'VisitorInterest_VisitsPerNbOfPages' => 'Visites segons el nombre de pàgines',
+ 'VisitorInterest_WidgetLengths' => 'Durada de les visites',
+ 'VisitorInterest_WidgetPages' => 'Pàgines per visita',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Freqüència i lleialtat',
+ 'VisitorInterest_PlusXMin' => '%s min',
+ 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
+ 'VisitorInterest_OnePage' => '1 pàgina',
+ 'VisitorInterest_NPages' => '%s pàgines',
+ 'VisitorInterest_BetweenXYSeconds' => '%1s-%2ss',
+ 'VisitsSummary_NbVisits' => '%s visites',
+ 'VisitsSummary_NbUniqueVisitors' => '%s visitants únics',
+ 'VisitsSummary_NbActions' => '%s accions (pàgines vistes)',
+ 'VisitsSummary_TotalTime' => '%s de temps en total fet servir pels visitants',
+ 'VisitsSummary_MaxNbActions' => 'Hi ha %s accions màximes en una visita',
+ 'VisitsSummary_NbBounced' => '%s visitants han rebotat (han abandonat el lloc després de veure només una pàgina)',
+ 'VisitsSummary_Evolution' => 'Evolució dels 30 darrers %ss',
+ 'VisitsSummary_Report' => 'Informe',
+ 'VisitsSummary_GenerateTime' => 'S\'han trigat %s segons en generar la pàgina',
+ 'VisitsSummary_GenerateQueries' => 'S\'ha executat un total de %s consultes',
+ 'VisitsSummary_WidgetLastVisits' => 'Gràfic de les darreres visites',
+ 'VisitsSummary_WidgetVisits' => 'Resum de les visites',
+ 'VisitsSummary_WidgetLastVisitors' => 'Gràfic dels darrers visitants únics',
+ 'VisitsSummary_WidgetOverviewGraph' => 'Resum amb gràfic',
+ 'VisitsSummary_SubmenuOverview' => 'Resum',
+ 'General_Export' => 'Exporta',
+ 'General_Visitors' => 'Visitants',
+ 'General_NoDataForTagCloud' => 'No hi ha dades...',
+ 'General_PiwikIsACollaborativeProject' => '%s El Piwik %s és un projecte col&middot;laboratiu que encara està en fase Beta. %s Si voleu ajudar, si us plau %s contacteu-nos!%s.',
+ 'CorePluginsAdmin_PluginsManagement' => 'Gestiona els connectors',
+ 'CorePluginsAdmin_MainDescription' => 'Els connectors augmenten la funcionalitat del Piwik. Un cop hi ha un connector instal&middot;lat, podeu activar-lo i desactivar-lo aquí.',
+ 'CorePluginsAdmin_Plugin' => 'Connector',
+ 'CorePluginsAdmin_Version' => 'Versió',
+ 'CorePluginsAdmin_Description' => 'Descripció',
+ 'CorePluginsAdmin_Status' => 'Estat',
+ 'CorePluginsAdmin_Action' => 'Acció',
+ 'CorePluginsAdmin_PluginHomepage' => 'Pàgina web',
+ 'CorePluginsAdmin_Active' => 'Actiu',
+ 'CorePluginsAdmin_Inactive' => 'Inactiu',
+ 'Actions_Actions' => 'Accions',
+ 'Dashboard_Dashboard' => 'Tauler',
+ 'Referers_Referers' => 'Referents',
+ 'UsersManager_UsersManagement' => 'Gestiona els usuaris',
+ 'UsersManager_UsersManagementMainDescription' => 'Creeu nous usuaris o actualitzeu els existents.
+Podeu configurar els seus permisos a dalt.',
+ 'UsersManager_MainDescription' => 'Decidiu quin tipus d\'accés té cada usuari al Piwik. També podeu configurar tots els llocs web de cop.',
+ 'SitesManager_WebsitesManagement' => 'Gestiona els llocs',
+ 'SitesManager_MainDescription' => 'Els informes d\'anàlisi web necessiten llocs web! Afegiu, actualitzeu i esborreu-ne. Veieu també el codi JavaScript que heu d\'inserir a les pàgines',
+ 'DBStats_DatabaseUsage' => 'Ús de la base de dades',
+ 'DBStats_MainDescription' => 'El Piwik desa totes les anàlisis web la base de dades MySQL. Ara per ara, les taules del Piwik fan servir %s.',
+ 'DBStats_Table' => 'Taula',
+ 'DBStats_RowNumber' => 'Núm. fila',
+ 'DBStats_DataSize' => 'Grandària de les dades',
+ 'DBStats_IndexSize' => 'Grandària del l\'índex',
+ 'General_Website' => 'Lloc web',
+ 'CoreUpdater_UpdateTitle' => 'Actualització del Piwik',
+ 'CoreUpdater_UpdateRequired' => 'Hi ha una actualització necessària',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'La base de dades del Piwik és antiga i cal actualitzar-la abans de continuar.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'El Piwik s\'actualitzarà a la versió %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Aquests connectors s\'actualitzaran: %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'El procés d\'actualització pot durar una estona, tingueu paciència.',
+ 'CoreUpdater_UpgradePiwik' => 'Actualitza el Piwik',
+ 'CoreUpdater_HelpMessageContent' => 'Comproveu les %s PMF del Piwik (en anglès) %s, que intenten explicar els errors més comuns a l\'actualització. %s Pregunteu a l\'administrador del sistema, podria ajudar-vos amb l\'error, que sembla estar relacionat amb el servidor o la instal&middot;lació del MySQL.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Hi ha hagut un error crític durant el procés d\'actualització:',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'El que hi ha a sobre és l\'error del nucli. Hauria d\'explicar la causa, però si necessiteu més ajuda, si us plau:',
+ 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'La actualització s\'ha completat amb èxit, però hi ha hagut alguns problemes durant el procés. Si us plau, llegiu les descripcions que hi ha a sobre per a saber més detalls. Si voleu més informació:',
+ 'CoreUpdater_UpgradeComplete' => 'S\'ha actualitzat amb èxit!',
+ 'CoreUpdater_WarningMessages' => 'Avisos:',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Hi ha hagut errors en l\'actualització dels connectors',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'S\'han desactivat automàticament els connectors següents: %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'El Piwik s\'ha actualitzat amb èxit!',
+ 'CoreUpdater_ContinueToPiwik' => 'Vés cap al Piwik',
+ 'Installation_DatabaseCreatedSuccess' => 'La base de dades %s s\'ha creat correctament!',
+ 'Installation_ContinueToPiwik' => 'Vés cap al Piwik',
+ 'General_HelloUser' => 'Hola, %s!',
+ 'General_OpenSourceWebAnalytics' => 'Anàlisi web de codi obert',
+ 'General_YourDashboard' => 'Tauler',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Ginys',
+ 'General_Settings' => 'Tauler de control',
+ 'General_GiveUsYourFeedback' => 'Què penseu del Piwik?',
+ 'General_ColumnActionsPerVisit' => 'Accions per visita',
+ 'General_ColumnAvgTimeOnSite' => 'Temps mitjà per visita',
+ 'General_ColumnBounceRate' => 'Raó de rebots',
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => 'Esteu veient la demo del %s; %sdescarregueu-vos%s la versió completa! Visiteu %s',
+ 'UserCountry_country_ru' => 'Rússia',
+ 'UserCountry_country_rs' => 'Sèrbia',
+ 'General_ColumnPageviews' => 'Visualitzacions de pàgina',
+ 'General_ColumnUniquePageviews' => 'Visualitzacions de pàgina úniques',
+ 'General_DisplayNormalTable' => 'Mostra una taula normal',
+ 'General_DisplayMoreData' => 'Mostra més dades',
); \ No newline at end of file
diff --git a/lang/en.php b/lang/en.php
index 88cd035eaf..377239770f 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -593,6 +593,7 @@ $translations = array(
'DBStats_RowNumber' => 'Row number',
'DBStats_DataSize' => 'Data size',
'DBStats_IndexSize' => 'Index size',
+ 'DBStats_TotalSize' => 'Total size',
'TranslationsAdmin_MenuTranslations' => 'Translations',
'TranslationsAdmin_MenuLanguages' => 'Languages',
'TranslationsAdmin_Plugin' => 'Plugin',
diff --git a/lang/fr.php b/lang/fr.php
index 952eaf865b..793008baf2 100644
--- a/lang/fr.php
+++ b/lang/fr.php
@@ -1,61 +1,91 @@
-<?php
+<?php
$translations = array(
'General_Locale' => 'fr_FR.UTF-8',
'General_TranslatorName' => 'Get surf!',
'General_TranslatorEmail' => 'admin@get-surf.com',
'General_EnglishLanguageName' => 'French',
- 'General_OriginalLanguageName' => 'Fran&ccedil;ais',
+ 'General_OriginalLanguageName' => 'Français',
+ 'General_HelloUser' => 'Bonjour, %s',
+ 'General_OpenSourceWebAnalytics' => 'Analyse web libre',
+ 'General_YourDashboard' => 'Votre tableau de bord',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Widgets',
+ 'General_Settings' => 'Paramètres',
+ 'General_GiveUsYourFeedback' => 'Envoyez-nous vos commentaires !',
'General_Unknown' => 'Inconnu',
'General_Required' => '%s requis',
'General_Error' => 'Erreur',
'General_Warning' => 'Attention',
- 'General_BackToHomepage' => 'Retour &agrave; la page d\'accueil Piwik',
+ 'General_BackToHomepage' => 'Retour à la page d\'accueil Piwik',
'General_Yes' => 'Oui',
'General_No' => 'Non',
'General_Delete' => 'Supprimer',
- 'General_Edit' => 'Editer',
+ 'General_Edit' => 'Éditer',
'General_Ok' => 'Ok',
'General_Close' => 'Fermer',
- 'General_Logout' => 'D&eacute;connexion',
+ 'General_Logout' => 'Déconnexion',
'General_Done' => 'Fait',
- 'General_LoadingData' => 'Chargement des donn&eacute;es...',
- 'General_ErrorRequest' => 'Oops&hellip; probl&egrave;me rencontr&eacute; durant la requ&ecirc;te, veuillez r&eacute;essayer.',
+ 'General_LoadingData' => 'Chargement des données...',
+ 'General_ErrorRequest' => 'Oups ! Problème rencontré durant la requête, veuillez réessayer.',
'General_Next' => 'Suivant',
- 'General_Previous' => 'Pr&eacute;c&eacute;dent',
+ 'General_Previous' => 'Précédent',
'General_Search' => 'Rechercher',
'General_Others' => 'Autres',
- 'General_Table' => 'Table',
- 'General_Piechart' => 'Camembert', //////
+ 'General_Table' => 'Tableau',
+ 'General_Piechart' => 'Pointe de tarte',
'General_TagCloud' => 'Nuage de tags',
'General_VBarGraph' => 'Histogramme vertical',
- 'General_Refresh' => 'Rafraichissez la page',
+ 'General_Export' => 'Exporter',
+ 'General_Refresh' => 'Rafraîchir la page',
+ 'General_Visitors' => 'Visiteurs',
'General_ColumnNbUniqVisitors' => 'Visiteurs uniques',
'General_ColumnNbVisits' => 'Visites',
'General_ColumnLabel' => 'Nom',
+ 'General_ColumnActionsPerVisit' => 'Actions par visite',
+ 'General_ColumnAvgTimeOnSite' => 'Temps moyen sur le site',
+ 'General_ColumnBounceRate' => 'Taux de rebond',
+ 'General_ColumnPageviews' => 'Vues',
+ 'General_ColumnUniquePageviews' => 'Vues uniques',
'General_Save' => 'Enregistrer',
- 'General_NoDataForGraph' => 'Aucune donnee pour ce graph',
+ 'General_Website' => 'Site :',
+ 'General_NoDataForGraph' => 'Aucunes données pour ce graphique',
+ 'General_NoDataForTagCloud' => 'Aucunes données pour ce nuage de tags.',
+ 'General_DisplayNormalTable' => 'Voir tableau normal',
+ 'General_DisplayMoreData' => 'Voir plus de données',
+ 'General_PiwikIsACollaborativeProject' => "%s Piwik %s est un projet collaboratif en version Beta. %s Si vous voulez aider, %s contactez nous%s !",
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => "Vous êtes dans la démo de %s; %stéléchargez%s la version complète ! Visitez %s.",
'CorePluginsAdmin_Plugins' => 'Plugins',
- 'CorePluginsAdmin_Activated' => 'Activ&eacute;',
- 'CorePluginsAdmin_ActivatedHelp' => 'Ce plugin ne peut &ecirc;tre d&eacute;sactiv&eacute;',
- 'CorePluginsAdmin_Deactivate' => 'D&eacute;sactiver',
+ 'CorePluginsAdmin_PluginsManagement' => 'Gestionnaire de plugins',
+ 'CorePluginsAdmin_MainDescription' => 'Les plugins étendent et ajoutent des fonctionnalités à Piwik. Une fois un plugin installé, vous pouvez l\'activer ou le désactiver ici.',
+ 'CorePluginsAdmin_Plugin' => 'Plugin',
+ 'CorePluginsAdmin_Version' => 'Version',
+ 'CorePluginsAdmin_Description' => 'Description',
+ 'CorePluginsAdmin_Status' => 'État',
+ 'CorePluginsAdmin_Action' => 'Action',
+ 'CorePluginsAdmin_PluginHomepage' => 'Page d\'accueil du plugin',
+ 'CorePluginsAdmin_Activated' => 'Activé',
+ 'CorePluginsAdmin_Active' => 'Actif',
+ 'CorePluginsAdmin_Inactive' => 'Inactif',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Ce plugin ne peut être désactivé',
+ 'CorePluginsAdmin_Deactivate' => 'Désactiver',
'CorePluginsAdmin_Activate' => 'Activer',
'CorePluginsAdmin_MenuPlugins' => 'Plugins',
- 'API_QuickDocumentation' => '<h2>Documentation rapide de l\'API</h2><p>Si vousn\'avez pas de donn&eacute;es pour ajourd\'hui vous pouvez d\'abord <a href=\'misc/generateVisits.php\' target=_blank>g&eacute;n&eacute;rer des donn&eacute;es</a> en utilisant le G&eacute;n&eacute;rateur de Visites.</p><p>Vous pouvez essayer les diff&eacute;rents formats disponibles pour chaque m&eacute;thode. Il est tr&egrave;s facile d\'extraire n\'importe quelle donn&eacute;e que vous voulez de Piwik!</p><p><b>Pour plus d\'informations visitez la <a href=\'http://dev.piwik.org/trac/wiki/API\'>Documentation officielle de l\'API</a> or the <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>R&eacute;f&eacute;rence API</a>.</b></P><h2>Identification</h2><p>Si vous voulez <b>utiliser les donn&eacute;es dans vos scripts, dans une crontab, etc. </b> vous devez ajouter le param&egrave;tre <code><u>&token_auth=%s</u></code> to the API calls URLs that require authentication.</p><p>Cette token_auth est aussi secr&egrave;tes que votre nom d\'utilisateur ou votre mot de passe, <b>ne la partagez pas!</p>',
- 'API_LoadedAPIs' => '%s API charg&eacute;es avec succ&egrave;s',
- 'CoreHome_NoPrivileges' => 'Vous &ecirc;tes connect&eacute; en tant que \'%s\' mais il semble que vous n\'ayez aucune permission dans Piwik.<br />Demandez &agrave; votre administrateur Piwik de vous accorder l\'acc&egrave;s type \'view\' &agrave; un site Internet.',
- 'CoreHome_JavascriptDisabled' => 'Javascript doit &ecirc;tre activ&eacute; dans votre navigateur pour pouvoir utiliser Piwik en mode standard.<br />Il semble que Javascript soit d&eacute;sactiv&eacute; ou qu\'il ne soit pas support&eacute; par votre navigateur.<br />Pour utiliser Piwik en mode standard activez JS via les options de votre navigateur et essayez &agrave; nouveau.<br />',
- 'CoreHome_TableNoData' => 'Aucune donn&eacute;e pour cette table.',
- 'CoreHome_CategoryNoData' => 'Aucune donn&eacute;e pour cette cat&eacute;gorie. Essayez en cliquant sur "Inclure toute la population".',
- 'CoreHome_ShowJSCode' => 'Afficher le tag javascript &agrave; ins&eacute;rer',
+ 'API_QuickDocumentation' => '<h2>Documentation rapide de l\'API</h2><p>Si vous n\'avez pas de données pour ajourd\'hui, vous pouvez d\'abord <a href=\'misc/generateVisits.php\' target=_blank>générer des données</a> en utilisant le Générateur de Visites.</p><p>Vous pouvez essayer les différents formats disponibles pour chaque méthode. Il est très facile d\'extraire n\'importe quelle donnée que vous voulez de Piwik!</p><p><b>Pour plus d\'informations visitez la <a href=\'http://dev.piwik.org/trac/wiki/API\'>Documentation officielle de l\'API</a> or the <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>Référence API</a>.</b></P><h2>Identification</h2><p>Si vous voulez <b>utiliser les données dans vos scripts, dans une crontab, etc. </b> vous devez ajouter le paramètre <code><u>&token_auth=%s</u></code> to the API calls URLs that require authentication.</p><p>Cette token_auth est aussi secrètes que votre nom d\'utilisateur ou votre mot de passe, <b>ne la partagez pas!</p>',
+ 'API_LoadedAPIs' => '%s API chargées avec succès',
+ 'CoreHome_NoPrivileges' => 'Vous êtes connecté en tant que \'%s\' mais il semble que vous n\'ayez aucune permission dans Piwik.<br />Demandez à votre administrateur Piwik de vous accorder l\'accès type \'view\' à un site Internet.',
+ 'CoreHome_JavascriptDisabled' => 'JavaScript doit être activé dans votre navigateur pour pouvoir utiliser Piwik en mode standard.<br />Il semble que JavaScript soit désactivé ou qu\'il ne soit pas supporté par votre navigateur.<br />Pour utiliser Piwik en mode standard activez JS via les options de votre navigateur et essayez à nouveau.<br />',
+ 'CoreHome_TableNoData' => 'Aucunes données pour ce tableau.',
+ 'CoreHome_CategoryNoData' => 'Aucune donnée pour cette catégorie. Essayez en cliquant sur "Inclure toute la population".',
+ 'CoreHome_ShowJSCode' => 'Afficher le tag JavaScript à insérer',
'CoreHome_IncludeAllPopulation_js' => 'Inclure toute la population',
'CoreHome_ExcludeLowPopulation_js' => 'Exclure les petites populations des statistiques',
- 'CoreHome_PageOf_js' => '%s of %s',
+ 'CoreHome_PageOf_js' => '%s de %s',
'CoreHome_Loading_js' => 'Chargement...',
'CoreHome_LocalizedDateFormat' => '%A %d %B %Y',
'CoreHome_PeriodDay' => 'Jour',
'CoreHome_PeriodWeek' => 'Semaine',
'CoreHome_PeriodMonth' => 'Mois',
- 'CoreHome_PeriodYear' => 'Ann&eacute;e',
+ 'CoreHome_PeriodYear' => 'Année',
'CoreHome_DaySu_js' => 'Di',
'CoreHome_DayMo_js' => 'Lu',
'CoreHome_DayTu_js' => 'Ma',
@@ -64,88 +94,108 @@ $translations = array(
'CoreHome_DayFr_js' => 'Ve',
'CoreHome_DaySa_js' => 'Sa',
'CoreHome_MonthJanuary_js' => 'Janvier',
- 'CoreHome_MonthFebruary_js' => 'F&eacute;vrier',
+ 'CoreHome_MonthFebruary_js' => 'Février',
'CoreHome_MonthMarch_js' => 'Mars',
'CoreHome_MonthApril_js' => 'Avril',
'CoreHome_MonthMay_js' => 'Mai',
'CoreHome_MonthJune_js' => 'Juin',
'CoreHome_MonthJuly_js' => 'Juillet',
- 'CoreHome_MonthAugust_js' => 'Ao&ucirc;t',
+ 'CoreHome_MonthAugust_js' => 'Août',
'CoreHome_MonthSeptember_js' => 'Septembre',
'CoreHome_MonthOctober_js' => 'Octobre',
'CoreHome_MonthNovember_js' => 'Novembre',
- 'CoreHome_MonthDecember_js' => 'D&eacute;cembre',
+ 'CoreHome_MonthDecember_js' => 'Décembre',
+ 'CoreUpdater_UpdateTitle' => 'Piwik &rsaquo; Mise à jour',
+ 'CoreUpdater_UpdateRequired' => 'Mise à jour requise',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Votre base de données est expirée et doit être mise à jour avant de pouvoir continuer.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'Piwik sera mis à jour à la version %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Les plugins suivants seront mis à jour : %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Le procédé de mise à jour peut être long, soyez patients.',
+ 'CoreUpdater_UpgradePiwik' => 'Mettez Piwik à jour',
+ 'CoreUpdater_HelpMessageContent' => 'Consultez la %s FAQ Piwik %s qui tente d\'expliquer les erreurs les plus communes lors des mises à jour. $s Demandez à votre administrateur système, il pourrait être capable de vous aider à corriger l\'erreur qui est fort probablement reliée à votre serveur ou configuration MySQL.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Erreur Critique pendant le procédé de mise à jour :',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'Ci-dessus est le message d\'erreur du noyau. Cela devrait expliquer la cause, mais si vous nécessitez d\'avantage d\'aide merci de :',
+'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'La mise à jour a été complétée avec succès. Cependant, des problèmes sont survenus. Lisez la description ci-dessus pour plus de détails. Pour d\'avantage d\'aide :',
+ 'CoreUpdater_UpgradeComplete' => 'Mise à jour complète !',
+ 'CoreUpdater_WarningMessages' => 'Messages d\'avertissement :',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Erreurs pendant les mises à jour de plugins :',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'Nous avons automatiquement désactivé les plugins suivants : %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik a été mis à jour avec succès !',
+ 'CoreUpdater_ContinueToPiwik' => 'Continuer vers Piwik',
+ 'Actions_Actions' => 'Actions',
'Actions_SubmenuPages' => 'Pages',
'Actions_SubmenuOutlinks' => 'Liens de sortie',
- 'Actions_SubmenuDownloads' => 'T&eacute;l&eacute;chargements',
+ 'Actions_SubmenuDownloads' => 'Téléchargements',
+ 'Dashboard_Dashboard' => 'Tableau de bord',
'Dashboard_AddWidget' => 'Ajouter un widget...',
- 'Dashboard_DeleteWidgetConfirm' => 'Etes vous s&ucirc;r de vouloir supprimer ce widget du tableau de bord?',
- 'Dashboard_SelectWidget' => 'S&eacute;lectionnez le widget &agrave; ajouter au tableau de bord',
- 'Dashboard_AddPreviewedWidget' => 'Ajouter le widget visualis&eacute; au tableau de bord',
- 'Dashboard_WidgetPreview' => 'Pr&eacute;visualisation du Widget',
- 'Dashboard_TitleWidgetInDashboard_js' => 'Widget d&eacute;j&agrave; pr&eacute;sent sur le tableau de bord',
+ 'Dashboard_DeleteWidgetConfirm' => 'Êtes-vous sûr de vouloir supprimer ce widget du tableau de bord?',
+ 'Dashboard_SelectWidget' => 'Sélectionnez le widget à ajouter au tableau de bord',
+ 'Dashboard_AddPreviewedWidget' => 'Ajouter le widget visualisé au tableau de bord',
+ 'Dashboard_WidgetPreview' => 'Prévisualisation du Widget',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Widget déjà présent sur le tableau de bord',
'Dashboard_TitleClickToAdd_js' => 'Cliquez pour ajouter au tableau de bord',
- 'Dashboard_LoadingPreview_js' => 'Chargement de la pr&eacute;visualisation, patientez svp...',
+ 'Dashboard_LoadingPreview_js' => 'Chargement de la prévisualisation, patientez svp...',
'Dashboard_LoadingWidget_js' => 'Chargement du widget, patientez svp...',
'Dashboard_WidgetNotFound_js' => 'Widget introuvable;',
+ 'Referers_Referers' => 'Référents',
'Referers_SearchEngines' => 'Moteurs de recherche',
- 'Referers_Keywords' => 'Mots cl&eacute;s',
- 'Referers_DirectEntry' => 'Entr&eacute;es directes',
+ 'Referers_Keywords' => 'Mots-clés',
+ 'Referers_DirectEntry' => 'Entrées directes',
'Referers_Websites' => 'Sites Internet',
- 'Referers_Newsletters' => 'Newsletters',
+ 'Referers_Newsletters' => 'Lettres d\'information',
'Referers_Campaigns' => 'Campagnes',
- 'Referers_Evolution' => 'Evolution sur la p&eacute;riode',
- 'Referers_Type' => 'Types d\'affluent',
- 'Referers_TypeDirectEntries' => '%s entr&eacute;es directes',
+ 'Referers_Evolution' => 'Évolution sur la période',
+ 'Referers_Type' => 'Types d\'affluents',
+ 'Referers_TypeDirectEntries' => '%s entrées directes',
'Referers_TypeSearchEngines' => '%s depuis des moteurs de recherche',
'Referers_TypeWebsites' => '%s depuis d\'autres sites Internet',
- 'Referers_TypeNewsletters' => '%s depuis des newsletters',
+ 'Referers_TypeNewsletters' => '%s depuis des lettres d\'information',
'Referers_TypeCampaigns' => '%s depuis des campagnes',
- 'Referers_Other' => 'Autre',
- 'Referers_OtherDistinctSearchEngines' => '%s moteurs de recherches diff&eacute;rents',
- 'Referers_OtherDistinctKeywords' => '%s mots cl&eacute;s diff&eacute;rents',
- 'Referers_OtherDistinctWebsites' => '%1s sites Internet diff&eacute;rents (utilisant %2s diff&eacute;rentes adresses)',
- 'Referers_OtherDistinctCampaigns' => '%s diff&eacute;rentes campagnes',
- 'Referers_TagCloud' => 'R&eacute;sultat de nuage de tags',
- 'Referers_SubmenuEvolution' => 'Evolution',
- 'Referers_SubmenuSearchEngines' => 'Moteurs de recherche et mots cl&eacute;s',
+ 'Referers_Other' => 'Autres',
+ 'Referers_OtherDistinctSearchEngines' => '%s moteurs de recherches différents',
+ 'Referers_OtherDistinctKeywords' => '%s mots-clés différents',
+ 'Referers_OtherDistinctWebsites' => '%1s sites Internet différents (utilisant %2s différentes adresses)',
+ 'Referers_OtherDistinctCampaigns' => '%s différentes campagnes',
+ 'Referers_TagCloud' => 'Résultat de nuage de tags',
+ 'Referers_SubmenuEvolution' => 'Évolution',
+ 'Referers_SubmenuSearchEngines' => 'Moteurs de recherche et mots-clés',
'Referers_SubmenuWebsites' => 'Sites Internet',
'Referers_SubmenuCampaigns' => 'Campagnes',
- 'Referers_WidgetKeywords' => 'Liste des mots cl&eacute;s',
+ 'Referers_WidgetKeywords' => 'Liste des mots-clés',
'Referers_WidgetCampaigns' => 'Liste des campagnes',
'Referers_WidgetExternalWebsites' => 'Liste des sites Internet externes',
'Referers_WidgetSearchEngines' => 'Meilleurs moteurs de recherche',
- 'Referers_WidgetOverview' => 'R&eacute;capitulatif',
+ 'Referers_WidgetOverview' => 'Récapitulatif',
'UserSettings_BrowserFamilies' => 'Familles de navigateurs',
'UserSettings_Browsers' => 'Navigateurs',
'UserSettings_Plugins' => 'Plugins',
'UserSettings_Configurations' => 'Configurations',
- 'UserSettings_OperatinsSystems' => 'Syst&egrave;me d\'exploitation',
- 'UserSettings_Resolutions' => 'R&eacute;solutions',
- 'UserSettings_WideScreen' => 'Largeur d\'&eacute;cran',
- 'UserSettings_WidgetResolutions' => 'R&eacute;solutions d\'&eacute;cran',
+ 'UserSettings_OperatinsSystems' => 'Système d\'exploitation',
+ 'UserSettings_Resolutions' => 'Résolutions',
+ 'UserSettings_WideScreen' => 'Largeur d\'écran',
+ 'UserSettings_WidgetResolutions' => 'Résolutions d\'écran',
'UserSettings_WidgetBrowsers' => 'Navigateurs du visiteur',
'UserSettings_WidgetPlugins' => 'Liste de Plugins',
- 'UserSettings_WidgetWidescreen' => 'Normal / Ecran large',
+ 'UserSettings_WidgetWidescreen' => 'Normal / Écran large',
'UserSettings_WidgetBrowserFamilies' => 'Navigateurs par famille',
- 'UserSettings_WidgetOperatingSystems' => 'Syst&egrave;mes d\exploitation',
+ 'UserSettings_WidgetOperatingSystems' => 'Systèmes d\'exploitation',
'UserSettings_WidgetGlobalVisitors' => 'Configuration globale des visiteurs',
- 'UserSettings_SubmenuSettings' => 'Param&egrave;tres',
+ 'UserSettings_SubmenuSettings' => 'Paramètres',
'UserCountry_Country' => 'Pays',
'UserCountry_Continent' => 'Continent',
- 'UserCountry_DistinctCountries' => '%s pays diff&eacute;rents',
- 'UserCountry_SubmenuLocations' => 'Provenances g&eacute;ographiques',
+ 'UserCountry_DistinctCountries' => '%s pays différents',
+ 'UserCountry_SubmenuLocations' => 'Provenances géographiques',
'UserCountry_WidgetContinents' => 'Continents des visiteurs',
'UserCountry_WidgetCountries' => 'Pays des visiteurs',
- 'UserCountry_country_ac' => 'Ascension (&icirc;le)',
+ 'UserCountry_country_ac' => 'Ascension (île)',
'UserCountry_country_ad' => 'Andorre',
- 'UserCountry_country_ae' => 'Emirats Arabes unis',
+ 'UserCountry_country_ae' => 'Émirats arabes unis',
'UserCountry_country_af' => 'Afghanistan',
'UserCountry_country_ag' => 'Antigua et Barbuda',
'UserCountry_country_ai' => 'Anguilla',
'UserCountry_country_al' => 'Albanie',
'UserCountry_country_am' => 'Armenie',
- 'UserCountry_country_an' => 'Antilles N&eacute;erlandaises',
+ 'UserCountry_country_an' => 'Antilles Néerlandaises',
'UserCountry_country_ao' => 'Angola',
'UserCountry_country_aq' => 'Antarctique',
'UserCountry_country_ar' => 'Argentine',
@@ -162,11 +212,11 @@ $translations = array(
'UserCountry_country_bg' => 'Bulgarie',
'UserCountry_country_bh' => 'Bahrein',
'UserCountry_country_bi' => 'Burundi',
- 'UserCountry_country_bj' => 'B&eacute;nin',
+ 'UserCountry_country_bj' => 'Bénin',
'UserCountry_country_bm' => 'Bermudes',
'UserCountry_country_bn' => 'Brunei',
'UserCountry_country_bo' => 'Bolivie',
- 'UserCountry_country_br' => 'Br&eacute;sil',
+ 'UserCountry_country_br' => 'Brésil',
'UserCountry_country_bs' => 'Bahamas',
'UserCountry_country_bt' => 'Bhutan',
'UserCountry_country_bv' => 'Ile Bouvet',
@@ -175,8 +225,8 @@ $translations = array(
'UserCountry_country_bz' => 'Belize',
'UserCountry_country_ca' => 'Canada',
'UserCountry_country_cc' => 'Iles des Cocos (Keeling)',
- 'UserCountry_country_cd' => 'Congo, R&eacute;publique d&eacute;mocratique du',
- 'UserCountry_country_cf' => 'R&eacute;publique d\'Afrique Centrale',
+ 'UserCountry_country_cd' => 'Congo, République démocratique du',
+ 'UserCountry_country_cf' => 'République d\'Afrique Centrale',
'UserCountry_country_cg' => 'Congo',
'UserCountry_country_ch' => 'Suisse',
'UserCountry_country_ci' => 'Cote D\'Ivoire',
@@ -191,18 +241,18 @@ $translations = array(
'UserCountry_country_cv' => 'Cap Vert',
'UserCountry_country_cx' => 'Christmas Island', //////
'UserCountry_country_cy' => 'Chypres',
- 'UserCountry_country_cz' => 'Republique Tch&egrave;que',
+ 'UserCountry_country_cz' => 'Republique Tchèque',
'UserCountry_country_de' => 'Allemagne',
'UserCountry_country_dj' => 'Djibouti',
'UserCountry_country_dk' => 'Danemark',
'UserCountry_country_dm' => 'Dominique',
'UserCountry_country_do' => 'Republique Dominicaine',
'UserCountry_country_dz' => 'Algerie',
- 'UserCountry_country_ec' => 'Equateur',
+ 'UserCountry_country_ec' => 'Équateur',
'UserCountry_country_ee' => 'Estonie',
- 'UserCountry_country_eg' => 'Egypte',
+ 'UserCountry_country_eg' => 'Égypte',
'UserCountry_country_eh' => 'Western Sahara', /////
- 'UserCountry_country_er' => 'Erythr&eacute;e',
+ 'UserCountry_country_er' => 'Erythrée',
'UserCountry_country_es' => 'Espagne',
'UserCountry_country_et' => 'Ethiopie',
'UserCountry_country_fi' => 'Finlande',
@@ -214,20 +264,20 @@ $translations = array(
'UserCountry_country_ga' => 'Gabon',
'UserCountry_country_gd' => 'Grenade',
'UserCountry_country_ge' => 'Georgie',
- 'UserCountry_country_gf' => 'Guyanne Fran&ccedil;aise',
+ 'UserCountry_country_gf' => 'Guyanne Française',
'UserCountry_country_gg' => 'Ile de Guernesey',
'UserCountry_country_gh' => 'Ghana',
'UserCountry_country_gi' => 'Gibraltar',
'UserCountry_country_gl' => 'Groenland',
'UserCountry_country_gm' => 'Gambie',
- 'UserCountry_country_gn' => 'Guin&eacute;e',
+ 'UserCountry_country_gn' => 'Guinée',
'UserCountry_country_gp' => 'Guadeloupe',
- 'UserCountry_country_gq' => 'Guin&eacute;e Equatoriale',
- 'UserCountry_country_gr' => 'Gr&egrave;ce',
+ 'UserCountry_country_gq' => 'Guinée Équatoriale',
+ 'UserCountry_country_gr' => 'Grèce',
'UserCountry_country_gs' => 'South Georgia and the South Sandwich Islands', /////
'UserCountry_country_gt' => 'Guatemala',
'UserCountry_country_gu' => 'Guam',
- 'UserCountry_country_gw' => 'Guin&eacute;e-Bissau',
+ 'UserCountry_country_gw' => 'Guinée-Bissau',
'UserCountry_country_gy' => 'Guyanne',
'UserCountry_country_hk' => 'Hong Kong',
'UserCountry_country_hm' => 'Iles heard et Mac Donald',
@@ -240,13 +290,13 @@ $translations = array(
'UserCountry_country_il' => 'Israel',
'UserCountry_country_im' => 'Iles de Man',
'UserCountry_country_in' => 'Inde',
- 'UserCountry_country_io' => 'Oc&eacute;an indien (Territoire Britanique)',
+ 'UserCountry_country_io' => 'Océan indien (Territoire Britanique)',
'UserCountry_country_iq' => 'Irak',
- 'UserCountry_country_ir' => 'Iran, R&eacute;publique Islamique de',
+ 'UserCountry_country_ir' => 'Iran, République Islamique de',
'UserCountry_country_is' => 'Islande',
'UserCountry_country_it' => 'Italie',
'UserCountry_country_je' => 'Jersey',
- 'UserCountry_country_jm' => 'Jama&iuml;que',
+ 'UserCountry_country_jm' => 'Jamaïque',
'UserCountry_country_jo' => 'Jordanie',
'UserCountry_country_jp' => 'Japon',
'UserCountry_country_ke' => 'Kenya',
@@ -255,8 +305,8 @@ $translations = array(
'UserCountry_country_ki' => 'Kiribati',
'UserCountry_country_km' => 'Comores',
'UserCountry_country_kn' => 'Saint Christophe Nieves Ang.',
- 'UserCountry_country_kp' => 'Cor&eacute;e du Nord',
- 'UserCountry_country_kr' => 'Cor&eacute;e du Sud',
+ 'UserCountry_country_kp' => 'Corée du Nord',
+ 'UserCountry_country_kr' => 'Corée du Sud',
'UserCountry_country_kw' => 'Koweit',
'UserCountry_country_ky' => 'Iles Caimans',
'UserCountry_country_kz' => 'Kazakhstan',
@@ -276,7 +326,7 @@ $translations = array(
'UserCountry_country_md' => 'Moldava',
'UserCountry_country_mg' => 'Madagascar',
'UserCountry_country_mh' => 'Iles Marshall',
- 'UserCountry_country_mk' => 'Mac&eacute;donie',
+ 'UserCountry_country_mk' => 'Macédonie',
'UserCountry_country_ml' => 'Mali',
'UserCountry_country_mm' => 'Myanmar',
'UserCountry_country_mn' => 'Mongolie',
@@ -293,22 +343,22 @@ $translations = array(
'UserCountry_country_my' => 'Malaisie',
'UserCountry_country_mz' => 'Mozambique',
'UserCountry_country_na' => 'Namibie',
- 'UserCountry_country_nc' => 'Nouvelle Cal&eacute;donie',
+ 'UserCountry_country_nc' => 'Nouvelle Calédonie',
'UserCountry_country_ne' => 'Niger',
'UserCountry_country_nf' => 'Ile Norfolk',
'UserCountry_country_ng' => 'Nigeria',
'UserCountry_country_ni' => 'Nicaragua',
'UserCountry_country_nl' => 'Pays-Bas',
- 'UserCountry_country_no' => 'Norv&egrave;ge',
- 'UserCountry_country_np' => 'N&eacute;pal',
+ 'UserCountry_country_no' => 'Norvège',
+ 'UserCountry_country_np' => 'Népal',
'UserCountry_country_nr' => 'Nauru',
'UserCountry_country_nu' => 'Nioue',
- 'UserCountry_country_nz' => 'Nouvelle Z&eacute;lande',
+ 'UserCountry_country_nz' => 'Nouvelle Zélande',
'UserCountry_country_om' => 'Oman',
'UserCountry_country_pa' => 'Panama',
- 'UserCountry_country_pe' => 'P&eacute;rou',
- 'UserCountry_country_pf' => 'Polyn&eacute;sie Fran&ccedil;aise',
- 'UserCountry_country_pg' => 'Papouasie Nouvelle Guin&eacute;e',
+ 'UserCountry_country_pe' => 'Pérou',
+ 'UserCountry_country_pf' => 'Polynésie Française',
+ 'UserCountry_country_pg' => 'Papouasie Nouvelle Guinée',
'UserCountry_country_ph' => 'Philippines',
'UserCountry_country_pk' => 'Pakistan',
'UserCountry_country_pl' => 'Pologne',
@@ -320,22 +370,24 @@ $translations = array(
'UserCountry_country_pw' => 'Palau',/////
'UserCountry_country_py' => 'Paraguay',
'UserCountry_country_qa' => 'Qatar',
- 'UserCountry_country_re' => 'La R&eacute;union',
+ 'UserCountry_country_re' => 'La Réunion',
'UserCountry_country_ro' => 'Roumanie',
+ 'UserCountry_country_ru' => 'Russia',
+ 'UserCountry_country_rs' => 'Serbia',
'UserCountry_country_rw' => 'Rwanda',
'UserCountry_country_sa' => 'Arabie Saoudite',
'UserCountry_country_sb' => 'Iles Solomon',
'UserCountry_country_sc' => 'Seychelles',
'UserCountry_country_sd' => 'Soudan',
- 'UserCountry_country_se' => 'Su&egrave;de',
+ 'UserCountry_country_se' => 'Suède',
'UserCountry_country_sg' => 'Singapour',
- 'UserCountry_country_sh' => 'Sainte H&eacute;l&egrave;ne',
+ 'UserCountry_country_sh' => 'Sainte Hélène',
'UserCountry_country_si' => 'Slovenie',
'UserCountry_country_sj' => 'Svalbard et Ile Jan Mayen',
'UserCountry_country_sk' => 'Slovaquie',
'UserCountry_country_sl' => 'Sierra Leone',
'UserCountry_country_sm' => 'Saint-Marin',
- 'UserCountry_country_sn' => 'S&eacute;n&eacute;gal',
+ 'UserCountry_country_sn' => 'Sénégal',
'UserCountry_country_so' => 'Somalie',
'UserCountry_country_sr' => 'Surinam',
'UserCountry_country_st' => 'Sao Tome et Principe',
@@ -347,7 +399,7 @@ $translations = array(
'UserCountry_country_td' => 'Tchad',
'UserCountry_country_tf' => 'French Southern Territories',////
'UserCountry_country_tg' => 'Togo',
- 'UserCountry_country_th' => 'Tha&icirc;lande',
+ 'UserCountry_country_th' => 'Thaïlande',
'UserCountry_country_tj' => 'Tajikistan',
'UserCountry_country_tk' => 'Tokelaou',
'UserCountry_country_tm' => 'Turkmenistan',
@@ -355,14 +407,14 @@ $translations = array(
'UserCountry_country_to' => 'Tonga',
'UserCountry_country_tp' => 'Timor Oriental',
'UserCountry_country_tr' => 'Turquie',
- 'UserCountry_country_tt' => 'Trinit&eacute; et Tobago ',
+ 'UserCountry_country_tt' => 'Trinité et Tobago ',
'UserCountry_country_tv' => 'Tuvalu',
- 'UserCountry_country_tw' => 'Ta&icirc;wan',
+ 'UserCountry_country_tw' => 'Taïwan',
'UserCountry_country_tz' => 'Tanzanie',
'UserCountry_country_ua' => 'Ukraine',
'UserCountry_country_ug' => 'Ouganda',
- 'UserCountry_country_uk' => 'Royaume Uni',
- 'UserCountry_country_gb' => 'Grande bretagne',
+ 'UserCountry_country_uk' => 'Royaume-Uni',
+ 'UserCountry_country_gb' => 'Grande-Bretagne',
'UserCountry_country_um' => 'United States Minor Outlying Islands', ////
'UserCountry_country_us' => 'Etats Unis',
'UserCountry_country_uy' => 'Uruguay',
@@ -386,44 +438,44 @@ $translations = array(
'UserCountry_continent_eur' => 'Europe',
'UserCountry_continent_afr' => 'Afrique',
'UserCountry_continent_asi' => 'Asie',
- 'UserCountry_continent_ams' => 'Am&eacute;rique du sud et centrale',
- 'UserCountry_continent_amn' => 'Am&eacute;rique du nord',
- 'UserCountry_continent_oce' => 'Oc&eacute;anie',
+ 'UserCountry_continent_ams' => 'Amérique du sud et centrale',
+ 'UserCountry_continent_amn' => 'Amérique du nord',
+ 'UserCountry_continent_oce' => 'Océanie',
'VisitsSummary_NbVisits' => '%s visites',
'VisitsSummary_NbUniqueVisitors' => '%s visiteurs uniques',
'VisitsSummary_NbActions' => '%s actions (pages vues)',
- 'VisitsSummary_TotalTime' => '%s temps total pass&eacute; par les visiteurs',
+ 'VisitsSummary_TotalTime' => '%s temps total passé par les visiteurs',
'VisitsSummary_MaxNbActions' => '%s actions maximums en une visite',
- 'VisitsSummary_NbBounced' => '%s visiteurs ont survol&eacute; (quitt&eacute; le site apr&egrave;s une page)',
- 'VisitsSummary_Evolution' => 'Evolution sur les 30 derniers %ss',
+ 'VisitsSummary_NbBounced' => '%s visiteurs ont survolé (quitté le site après une page)',
+ 'VisitsSummary_Evolution' => 'Évolution sur les 30 derniers %ss',
'VisitsSummary_Report' => 'Rapport',
- 'VisitsSummary_GenerateTime' => '%s secondes pour g&eacute;n&eacute;rer la page',
- 'VisitsSummary_GenerateQueries' => '%s requ&ecirc;tes ex&eacute;cut&eacute;es',
- 'VisitsSummary_WidgetLastVisits' => 'Graphique des derni&egrave;res visites',
- 'VisitsSummary_WidgetVisits' => 'R&eacute;capitulatif des visites',
+ 'VisitsSummary_GenerateTime' => '%s secondes pour générer la page',
+ 'VisitsSummary_GenerateQueries' => '%s requêtes exécutées',
+ 'VisitsSummary_WidgetLastVisits' => 'Graphique des dernières visites',
+ 'VisitsSummary_WidgetVisits' => 'Récapitulatif des visites',
'VisitsSummary_WidgetLastVisitors' => 'Graphique des derniers visiteurs uniques',
- 'VisitsSummary_WidgetOverviewGraph' => 'Graphique r&eacute;capitulatif',
- 'VisitsSummary_SubmenuOverview' => 'R&eacute;capitulatif',
- 'VisitFrequency_Evolution' => 'Evolution sur la p&eacute;riode',
+ 'VisitsSummary_WidgetOverviewGraph' => 'Graphique récapitulatif',
+ 'VisitsSummary_SubmenuOverview' => 'Récapitulatif',
+ 'VisitFrequency_Evolution' => 'Évolution sur la période',
'VisitFrequency_ReturnVisits' => '%s visites de visiteurs connus',
'VisitFrequency_ReturnActions' => '%s actions de visites de visiteurs connus',
'VisitFrequency_ReturnMaxActions' => '%s actions maximums par visite de visiteur connus',
- 'VisitFrequency_ReturnTotalTime' => '%s temps total pass&eacute; par des visiteurs connus',
- 'VisitFrequency_ReturnBounces' => '%s visiteurs connus ont survol&eacute; (quitt&eacute; le site apr&egrave;s une page)',
- 'VisitFrequency_WidgetOverview' => 'R&eacute;capitulatif de la Fr&eacute;quence',
+ 'VisitFrequency_ReturnTotalTime' => '%s temps total passé par des visiteurs connus',
+ 'VisitFrequency_ReturnBounces' => '%s visiteurs connus ont survolé (quitté le site après une page)',
+ 'VisitFrequency_WidgetOverview' => 'Récapitulatif de la Fréquence',
'VisitFrequency_WidgetGraphReturning' => 'Graphique de visites de visiteurs connus',
- 'VisitFrequency_SubmenuFrequency' => 'Fr&eacute;quence',
+ 'VisitFrequency_SubmenuFrequency' => 'Fréquence',
'VisitTime_LocalTime' => 'Visites par heure locale',
'VisitTime_ServerTime' => 'Visites par heure du serveur',
'VisitTime_WidgetLocalTime' => 'Visites par fuseau horaire local',
'VisitTime_WidgetServerTime' => 'Visites par fuseau horaire du serveur',
'VisitTime_SubmenuTimes' => 'Horaires',
'VisitTime_NHour' => '%sh',
- 'VisitorInterest_VisitsPerDuration' => 'Visites par dur&eacute;e de la visite',
+ 'VisitorInterest_VisitsPerDuration' => 'Visites par durée de la visite',
'VisitorInterest_VisitsPerNbOfPages' => 'Visites par nombre de pages',
- 'VisitorInterest_WidgetLengths' => 'Dur&eacute;e des visites',
+ 'VisitorInterest_WidgetLengths' => 'Durée des visites',
'VisitorInterest_WidgetPages' => 'Pages par visite',
- 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Fr&eacute;quence et Fid&eacute;lit&eacute;',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Fréquence et Fidélité',
'VisitorInterest_PlusXMin' => '%s min',
'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
'VisitorInterest_OnePage' => '1 page',
@@ -434,114 +486,130 @@ $translations = array(
'Login_Password' => 'Mot de passe',
'Login_LoginOrEmail' => 'Nom d\'utilisateur ou courriel',
'Login_LogIn' => 'Connexion',
- 'Login_Logout' => 'D&eacute;connexion',
- 'Login_LostYourPassword' => 'Mot de passe perdu?',
+ 'Login_Logout' => 'Déconnexion',
+ 'Login_LostYourPassword' => 'Mot de passe perdu ?',
'Login_RemindPassword' => 'Rappeler le mot de passe',
'Login_PasswordReminder' => 'Entrez un nom d\'utilisateur ou un courriel valide, vous recevrez votre nouveau mot de passe par courriel.',
'Login_InvalidUsernameEmail' => 'Nom d\'utilisateur et/ou courriel invalide.',
- 'Login_MailTopicPasswordRecovery' => 'R&eacute;cup&eacute;ration du mot de passe',
- 'Login_MailPasswordRecoveryBody' => 'Hi %1s, \n\n Votre nouveau mot de passe est: %2s \n\n Vous pouvez vous connecter maintenant ici: %3s',
- 'Login_PasswordSent' => 'Le mot de passe vient juste d\'&ecirc;tre envoy&eacute;. Veuillez v&eacute;rifier vos courriels.',
- 'Login_ContactAdmin' => 'Raison possible: Votre h&eacute;bergeur peut avoir d&eacute;sactiv&eacute; la fonction mail(). <br /> Veuillez contacter votre administrateur Piwik.',
- 'UsersManager_ManageAccess' => 'Gestion des acc&egrave;s utilisateurs',
+ 'Login_MailTopicPasswordRecovery' => 'Récupération du mot de passe',
+ 'Login_MailPasswordRecoveryBody' => 'Hi %1s, \n\n Votre nouveau mot de passe est : %2s \n\n Vous pouvez vous connecter maintenant ici : %3s',
+ 'Login_PasswordSent' => 'Le mot de passe vient juste d\'être envoyé. Veuillez vérifier vos courriels.',
+ 'Login_ContactAdmin' => 'Raison possible : Votre hébergeur peut avoir désactivé la fonction mail(). <br /> Veuillez contacter votre administrateur Piwik.',
+ 'UsersManager_UsersManagement' => 'Gestion des utilisateurs',
+ 'UsersManager_UsersManagementMainDescription' => 'Créez de nouveaux utilisateurs ou modifiez-les. Vous pourrez ensuite changez leurs permissions ci-dessus.',
+ 'UsersManager_ManageAccess' => 'Gestion des accès utilisateurs',
+ 'UsersManager_MainDescription' => 'Décidez quels utilisateurs ont accès à quels sites. Vous pouvez aussi changer les permissions de tous les sites d\'un seul coup.',
'UsersManager_Sites' => 'Sites',
'UsersManager_AllWebsites' => 'Tous les sites Internet',
- 'UsersManager_ApplyToAllWebsites' => 'Appliquer &agrave; tous les sites',
+ 'UsersManager_ApplyToAllWebsites' => 'Appliquer à tous les sites',
'UsersManager_User' => 'Utilisateur',
- 'UsersManager_PrivNone' => 'Pas d\'acc&egrave;s',
+ 'UsersManager_PrivNone' => 'Pas d\'accès',
'UsersManager_PrivView' => 'Consultation',
'UsersManager_PrivAdmin' => 'Administration',
- 'UsersManager_ChangeAllConfirm' => 'Etes vous s&ucirc;r de vouloir changer les permissions de \'%s\' sur tous les sites Internet?',
+ 'UsersManager_ChangeAllConfirm' => 'Êtes-vous sûr de vouloir changer les permissions de \'%s\' sur tous les sites Internet?',
'UsersManager_Login' => 'Nom d\'utilisateur',
'UsersManager_Password' => 'Mot de passe',
- 'UsersManager_Email' => 'Email',
+ 'UsersManager_Email' => 'Courriel',
'UsersManager_Alias' => 'Alias',
'UsersManager_Token' => 'token_auth',
- 'UsersManager_Edit' => 'Editer',
+ 'UsersManager_Edit' => 'Éditer',
'UsersManager_AddUser' => 'Ajouter un nouvel utilisateur',
'UsersManager_MenuUsers' => 'Utilisateurs',
- 'UsersManager_DeleteConfirm_js' => 'Etes vous s&ucirc;r de vouloir supprimer l\'utilisateur %s?',
- 'UsersManager_ExceptionLoginExists' => 'Le nom d\'utilisateur \'%s\' existe d&eacute;j&agrave;.',
- 'UsersManager_ExceptionEmailExists' => 'Un utilisateur avec l\'adresse courriel \'%s\' existe d&eacute;j&agrave;.',
- 'UsersManager_ExceptionInvalidLogin' => 'Le nom d\'utilisateur doit contenir uniquement des lettres, chiffres et les caract&egrave;res suivants \'_\' ou \'-\' ou \'.\'',
- 'UsersManager_ExceptionInvalidPassword' => 'Le mot de passe doit faire entre 6 et 26 caract&egrave;res.',
- 'UsersManager_ExceptionInvalidEmail' => 'L\'adresse email n\'est pas valide.',
- 'UsersManager_ExceptionDeleteDoesNotExist' => 'L\'utilisateur \'%s\' n\'existe pas, il n\'a pu &ecirc;tre supprim&eacute;.',
- 'UsersManager_ExceptionAdminAnonymous' => 'Vous ne pouvez pas autoriser l\'acc&egrave;s administrateur &agrave; l\'utilisateur Anonyme.',
- 'UsersManager_ExceptionEditAnonymous' => 'L\'utilisateur Anonyme ne peut &ecirc;tre &eacute;dit&eacute; ou supprim&eacute;. Il est utilis&eacute; pour identifier un utilisateur qui ne s\'est pas encor&eacute; connect&eacute;. Par exemple vous pouvez rendre vos statistiques publiques en accordant l\'acc&egrave;s \'vue\' &agrave; l\'utilisateur \'anonyme\'.',
- 'UsersManager_ExceptionUserDoesNotExist' => 'L\'utilisateur \'%s\' n\'existe pas.',
- 'UsersManager_ExceptionAccessValues' => 'Le param&egrave;tre access doit contenir une des valeurs suivantes : [ %s ]',
- 'SitesManager_Sites' => 'Sites',
- 'SitesManager_JsCode' => 'Code javascript',
- 'SitesManager_JsCodeHelp' => 'Ici se trouve le code javascript &agrave; inclure dans toutes vos pages',
- 'SitesManager_ShowJsCode' => 'afficher le code',
- 'SitesManager_NoWebsites' => 'Vous n\'avez aucun site Internet &agrave; administrer.',
+ 'UsersManager_DeleteConfirm_js' => 'Êtes-vous sûr de vouloir supprimer l\'utilisateur %s ?',
+ 'UsersManager_ExceptionLoginExists' => 'Le nom d\'utilisateur \'%s\' existe déjà.',
+ 'UsersManager_ExceptionEmailExists' => 'Un utilisateur avec l\'adresse courriel \'%s\' existe déjà.',
+ 'UsersManager_ExceptionInvalidLogin' => 'Le nom d\'utilisateur doit contenir uniquement des lettres, chiffres et les caractères suivants \'_\' ou \'-\' ou \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'Le mot de passe doit faire entre 6 et 26 caractères.',
+ 'UsersManager_ExceptionInvalidEmail' => 'L\'adresse courriel est invalide.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'L\'utilisateur \'%s\' est inexistant, il n\'a pu être supprimé.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'Vous ne pouvez pas autoriser l\'accès administrateur à l\'utilisateur Anonyme.',
+ 'UsersManager_ExceptionEditAnonymous' => 'L\'utilisateur Anonyme ne peut être édité ou supprimé. Il est utilisé pour identifier un utilisateur qui ne s\'est pas encoré connecté. Par exemple vous pouvez rendre vos statistiques publiques en accordant l\'accès \'vue\' à l\'utilisateur \'anonyme\'.',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'L\'utilisateur \'%s\' est inexistant.',
+ 'UsersManager_ExceptionAccessValues' => 'Le paramètre access doit contenir une des valeurs suivantes : [ %s ]',
+ 'SitesManager_Sites' => 'Sites ',
+ 'SitesManager_WebsitesManagement' => 'Gestion des sites',
+ 'SitesManager_MainDescription' => 'Piwik a besoin de sites pour générer des rapports ! Ajoutez, éditez et supprimez des sites, et voyez le code JavaScript à inclure dans vos pages.',
+ 'SitesManager_JsCode' => 'Code JavaScript',
+ 'SitesManager_JsCodeHelp' => 'Ici se trouve le code JavaScript à inclure dans toutes vos pages ',
+ 'SitesManager_ShowJsCode' => 'Afficher le code',
+ 'SitesManager_NoWebsites' => 'Vous n\'avez aucun site Internet à administrer.',
'SitesManager_AddSite' => 'Ajouter un site',
'SitesManager_Id' => 'Id',
'SitesManager_Name' => 'Nom',
'SitesManager_Urls' => 'URLs',
'SitesManager_MenuSites' => 'Sites',
- 'SitesManager_DeleteConfirm_js' => 'Etes vous s&ucirc;r de vouloir supprimer le site %s?',
- 'SitesManager_ExceptionDeleteSite' => 'Impossible de supprimer le site car c\'est le seul site enregistr&eacute; dans Piwik. Vous pouvez d\'abord en ajouter un nouveau, puis supprimez celui-ci.',
- 'SitesManager_ExceptionNoUrl' => 'Vous devez sp&eacute;cifier au moins une url pour le site.',
- 'SitesManager_ExceptionEmptyName' => 'Le nom du site ne peut &ecirc;tre vide.',
- 'SitesManager_ExceptionInvalidUrl' => 'L\'url \'%s\' n\'est pas valide.',
+ 'SitesManager_DeleteConfirm_js' => 'Êtes-vous sûr de vouloir supprimer le site %s?',
+ 'SitesManager_ExceptionDeleteSite' => 'Impossible de supprimer le site car c\'est le seul site enregistré dans Piwik. Vous pouvez d\'abord en ajouter un nouveau, puis supprimez celui-ci.',
+ 'SitesManager_ExceptionNoUrl' => 'Vous devez spécifier au moins une url pour le site.',
+ 'SitesManager_ExceptionEmptyName' => 'Le nom du site ne peut être vide.',
+ 'SitesManager_ExceptionInvalidUrl' => 'L\'url \'%s\' est invalide.',
'Installation_Installation' => 'Installation',
'Installation_InstallationStatus' => 'Statut de l\'installation',
'Installation_PercentDone' => '%s %% Fait',
- 'Installation_NoConfigFound' => 'Le fichier de configuration de Piwik ne peut &ecirc;tre trouv&eacute; et vous essayez d\'acc&eacute;der &agrave; une page de Piwik.<br> <b>&nbsp;&nbsp;&raquo; Vous pouvez <a href=\'index.php\'>installer Piwik maintenant</a></b><br><small>Si vous avez d&eacute;j&agrave; install&eacute; Piwik ne vous inqui&eacute;tez pas Piwik r&eacute;utilisera ces tables et leurs donn&eacute;es.</small>',
- 'Installation_MysqlSetup' => 'Configuration de la base de donn&eacute;es Mysql',
- 'Installation_MysqlErrorConnect' => 'Erreur durant la connexion &agrave; la base de donn&eacute;es Mysql',
- 'Installation_JsTag' => 'Tag Javascript',
- 'Installation_JsTagHelp' => '<p>Pour comptabiliser tous les visiteurs vous devez copier le tag sur toutes vos pages.</p><p>Vos pages n\'ont pas besoin d\'&ecirc;tre en PHP, Piwik fonctionne avec tout type de pages (HTML, ASP, Perl ou n\'importe quel autre langage).</p><p>Ici se trouve le code &agrave; ins&eacute;rer: (copiez/collez dans toutes vos pages) </p>',
- 'Installation_Congratulations' => 'F&eacute;licitations',
- 'Installation_CongratulationsHelp' => '<p>F&eacute;licictations! Votre installation de Piwik est termin&eacute;e.</p><p>Assurez vous que le code Javascript est pr&eacute;sent sur toutes vos pages et attendez vos premiers visiteurs!</p>',
- 'Installation_GoToPiwik' => 'Aller sur Piwik',
- 'Installation_SetupWebsite' => 'Param&egrave;trer un site',
- 'Installation_SetupWebsiteError' => 'Une erreur a &eacute;t&eacute; recontr&eacute;e pendant l\'ajout du site',
- 'Installation_GeneralSetup' => 'Param&egrave;tres g&eacute;n&eacute;raux',
- 'Installation_GeneralSetupSuccess' => 'Param&egrave;tres g&eacute;nraux configur&eacute;s avec succ&egrave;s',
- 'Installation_SystemCheck' => 'V&eacute;rification du syst&egrave;me',
+ 'Installation_NoConfigFound' => 'Le fichier de configuration de Piwik ne peut être trouvé et vous essayez d\'accéder à une page de Piwik.<br> <b>&nbsp;&nbsp;&raquo; Vous pouvez <a href=\'index.php\'>installer Piwik maintenant</a></b><br><small>Si vous avez déjà installé Piwik ne vous inquiétez pas Piwik réutilisera ces tables et leurs données.</small>',
+ 'Installation_MysqlSetup' => 'Configuration de la base de données MySQL',
+ 'Installation_MysqlErrorConnect' => 'Erreur durant la connexion à la base de données MySQL',
+ 'Installation_JsTag' => 'Tag JavaScript',
+ 'Installation_JsTagHelp' => '<p>Pour comptabiliser tous les visiteurs vous devez copier le tag sur toutes vos pages.</p><p>Vos pages n\'ont pas besoin d\'être en PHP, Piwik fonctionne avec tout type de pages (HTML, ASP, Perl ou n\'importe quel autre langage).</p><p>Ici se trouve le code à insérer : (copiez/collez dans toutes vos pages) </p>',
+ 'Installation_Congratulations' => 'Félicitations',
+ 'Installation_CongratulationsHelp' => '<p>Félicictations! Votre installation de Piwik est terminée.</p><p>Assurez vous que le code JavaScript est présent sur toutes vos pages et attendez vos premiers visiteurs!</p>',
+ 'Installation_ContinueToPiwik' => 'Continuer vers Piwik',
+ 'Installation_SetupWebsite' => 'Paramètrer un site',
+ 'Installation_SetupWebsiteError' => 'Une erreur a été recontrée pendant l\'ajout du site',
+ 'Installation_GeneralSetup' => 'Paramètres généraux',
+ 'Installation_GeneralSetupSuccess' => 'Paramètres génraux configurés avec succès',
+ 'Installation_SystemCheck' => 'Vérification du système',
'Installation_SystemCheckPhp' => 'Version PHP',
'Installation_SystemCheckPdo' => 'Extension Pdo',
'Installation_SystemCheckPdoMysql' => 'Extension Pdo_Mysql',
'Installation_SystemCheckPdoError' => 'Vous devez activer les extensions PDO et POD_MYSQL dans votre fichier de configuration php.ini.',
- 'Installation_SystemCheckPdoHelp' => 'Sur un serveur windows vous pouvez ajouter les lignes suivantes &agrave; votre php.ini %s <br /><br />Sur un serveur Linux vous pouvez compiler PHP avec les options suivantes %s Dans votre php.ini, ajoutez les lignes suivantes %s<br /><br />Plus d\'informations sur le <a style="color:red" href="http://php.net/pdo">Site de PHP</a>.',
- 'Installation_SystemCheckWriteDirs' => 'R&eacute;pertoires avec les droits d\'acc&egrave;s en &eacute;criture',
- 'Installation_SystemCheckWriteDirsHelp' => 'Pour fixer les erreurs sur votre syst&egrave;me Linux essayez de taper les commandes suivantes',
- 'Installation_SystemCheckMemoryLimit' => 'Limite m&eacute;moire',
- 'Installation_SystemCheckMemoryLimitHelp' => 'Sur un site &agrave; trafic important le processus d\'archivage peut prendre plus de m&eacute;moire que la limite actuelle autoris&eacute;e.<br />R&eacute;f&eacute;rez vous &agrave; la configuration memory_limit de votre php.ini si n&eacute;cessaire.',
+ 'Installation_SystemCheckPdoHelp' => 'Sur un serveur windows vous pouvez ajouter les lignes suivantes à votre php.ini %s <br /><br />Sur un serveur Linux vous pouvez compiler PHP avec les options suivantes %s Dans votre php.ini, ajoutez les lignes suivantes %s<br /><br />Plus d\'informations sur le <a style="color:red" href="http://php.net/pdo">Site de PHP</a>.',
+ 'Installation_SystemCheckWriteDirs' => 'Répertoires avec les droits d\'accès en écriture',
+ 'Installation_SystemCheckWriteDirsHelp' => 'Pour corriger les erreurs sur votre système Linux essayez de taper les commandes suivantes',
+ 'Installation_SystemCheckMemoryLimit' => 'Limite mémoire',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'Sur un site à trafic important le processus d\'archivage peut prendre plus de mémoire que la limite actuelle autorisée.<br />Référez vous à la configuration memory_limit de votre php.ini si nécessaire.',
'Installation_SystemCheckGD' => 'GD &gt; 2.x (graphiques)',
'Installation_SystemCheckGDHelp' => 'Les sparklines (petits graphs) ne fonctionneront pas.',
- 'Installation_SystemCheckTimeLimit' => 'set_time_limit() autoris&eacute;',
- 'Installation_SystemCheckTimeLimitHelp' => 'Sur un site &agrave; trafic important le processus d\'archivage peut prendre plus de temps qu\'il n\'est d&eacute;j&agrave; autoris&eacute;.<br /> R&eacute;f&eacute;rez vous &agrave; la configuration max_execution_time de votre php.ini si n&eacute;cessaire.',
- 'Installation_SystemCheckMail' => 'mail() autorist&eacute;',
- 'Installation_SystemCheckError' => 'Une erreur s\'est produite - elle doit &ecirc;tre fix&eacute;e avant de pouvoir continuer',
- 'Installation_SystemCheckWarning' => 'Piwik fonctionnera normalement mais certaines fonctionnalit&eacute;s seront manquantes',
- 'Installation_Tables' => 'Cr&eacute;ation des tables',
- 'Installation_TablesWarning' => 'Des <span id="linkToggle">tables Piwik</span> sont d&eacute;j&agrave; install&eacute;es dans la base de donn&eacute;es',
- 'Installation_TablesFound' => 'Les tables suivantes ont &eacute;t&eacute; trouv&eacute;es dans la base de donn&eacute;es',
- 'Installation_TablesWarningHelp' => 'Vous pouvez choisir de r&eacute;utiliser les tables de la base de donn&eacute;es existante ou s&eacute;lectionner une nouvelle installation pour effacer toutes les donn&eacute;es existantes dans la base de donn&eacute;es.',
- 'Installation_TablesReuse' => 'R&eacute;utiliser les tables existantes',
- 'Installation_TablesDelete' => 'Supprimer les tables d&eacute;tect&eacute;es',
- 'Installation_TablesDeletedSuccess' => 'Tables Piwik existantes supprim&eacute;es avec succ&egrave;s',
- 'Installation_TablesCreatedSuccess' => 'Tables cr&eacute;es avec succ&egrave;s!',
- 'Installation_TablesDeleteConfirm' => 'Etes vous s&ucirc;r de vouloir supprimer toutes les tables Piwik de la base de donn&eacute;es?',
+ 'Installation_SystemCheckTimeLimit' => 'set_time_limit() autorisé',
+ 'Installation_SystemCheckTimeLimitHelp' => 'Sur un site à trafic important le processus d\'archivage peut prendre plus de temps qu\'il n\'est déjà autorisé.<br /> Référez vous à la configuration max_execution_time de votre php.ini si nécessaire.',
+ 'Installation_SystemCheckMail' => 'mail() autoristé',
+ 'Installation_SystemCheckError' => 'Une erreur s\'est produite — elle doit être corrigée avant de pouvoir continuer',
+ 'Installation_SystemCheckWarning' => 'Piwik fonctionnera normalement mais certaines fonctionnalités seront manquantes',
+ 'Installation_Tables' => 'Création des tables',
+ 'Installation_TablesWarning' => 'Des <span id="linkToggle">tables Piwik</span> sont déjà installées dans la base de données',
+ 'Installation_TablesFound' => 'Les tables suivantes ont été trouvées dans la base de données',
+ 'Installation_TablesWarningHelp' => 'Vous pouvez choisir de réutiliser les tables de la base de données existante ou sélectionner une nouvelle installation pour effacer toutes les données existantes dans la base de données.',
+ 'Installation_TablesReuse' => 'Réutiliser les tables existantes',
+ 'Installation_TablesDelete' => 'Supprimer les tables détectées',
+ 'Installation_TablesDeletedSuccess' => 'Tables Piwik existantes supprimées avec succès',
+ 'Installation_TablesCreatedSuccess' => 'Tables crées avec succès!',
+ 'Installation_DatabaseCreatedSuccess' => 'Base de données %s crée avec succès !',
+ 'Installation_TablesDeleteConfirm' => 'Êtes-vous sûr de vouloir supprimer toutes les tables Piwik de la base de données?',
'Installation_Welcome' => 'Bienvenue!',
- 'Installation_WelcomeHelp' => '<p>Piwik est une application d\'analyse du web Open Source qui vous permet d\'obtenir facilement les informations que vous d&eacute;sirez sur vos visiteurs.</p> <p>Ce proc&eacute;d&eacute; est divis&eacute; en %s &eacute;tapes faciles et vous prendra 5 minutes environ.</p>',
- 'Provider_WidgetProviders' => 'Fournisseurs d\'acc&egrave;s &agrave; internet',
- 'Provider_SubmenuLocationsProvider' => 'Situation g&eacute;ographique et FAI',
+ 'Installation_WelcomeHelp' => '<p>Piwik est une application d\'analyse du web Open Source qui vous permet d\'obtenir facilement les informations que vous désirez sur vos visiteurs.</p> <p>Ce procédé est divisé en %s étapes faciles et vous prendra 5 minutes environ.</p>',
+ 'Provider_WidgetProviders' => 'Fournisseurs d\'accès à Internet',
+ 'Provider_SubmenuLocationsProvider' => 'Situation géographique et FAI',
+ 'DBStats_DatabaseUsage' => 'Utilisation de la base de données',
+ 'DBStats_MainDescription' => 'Piwil conserve toutes vos analyses web dans la base de données MySQL. Présentement, les tables utilisent %s.',
+ 'DBStats_Table' => 'Table',
+ 'DBStats_RowNumber' => 'Numéro de rangée',
+ 'DBStats_DataSize' => 'Taille des données',
+ 'DBStats_IndexSize' => 'Taille de l\'index',
'TranslationsAdmin_MenuTranslations' => 'Traductions',
'TranslationsAdmin_MenuLanguages' => 'Langues',
'TranslationsAdmin_Plugin' => 'Plugin',
- 'TranslationsAdmin_Definition' => 'D&eacute;finition',
- 'TranslationsAdmin_DefaultString' => 'Chaine par d&eacute;faut (English)',
- 'TranslationsAdmin_TranslationString' => 'Traduction (Langue actuelle: %s)',
+ 'TranslationsAdmin_Definition' => 'Définition',
+ 'TranslationsAdmin_DefaultString' => 'Chaine par défaut (English)',
+ 'TranslationsAdmin_TranslationString' => 'Traduction (Langue actuelle : %s)',
'TranslationsAdmin_Translations' => 'Traductions',
- 'TranslationsAdmin_FixPermissions' => 'Veuillez d&eacute;finir les propri&eacute;t&eacute;s des fichiers syst&egrave;mes',
+ 'TranslationsAdmin_FixPermissions' => 'Veuillez définir les propriétés des fichiers systèmes',
'TranslationsAdmin_AvailableLanguages' => 'Langues disponibles',
'TranslationsAdmin_AddLanguage' => 'Ajouter langue',
'TranslationsAdmin_LanguageCode' => 'Code langue',
'TranslationsAdmin_Export' => 'Exporter langue',
'TranslationsAdmin_Import' => 'Importer langue',
+ 'Widgetize_MainDescription' => 'Avez Piwik, vous pouvez exporter vos résultats d\'analyses sur votre blog, site, ou tableau de bord intranet, en un clic ! Si vous désirez que vos widgets soient visibles de tous, vous devez configurer la permission \'consultation\' de l\'utilisateur Anonyme dans la section %1sGestion des utilisateurs%2s.',
+ 'Widgetize_EmbedIframe' => '&rsaquo; Incorporer iframe',
+ 'Widgetize_EmbedFlash' => '&rsaquo; Incorporer Flash',
+ 'Widgetize_ExportAnywhere' => '&rsaquo; Exportez partout !',
); \ No newline at end of file
diff --git a/lang/no.php b/lang/no.php
new file mode 100644
index 0000000000..307363fae0
--- /dev/null
+++ b/lang/no.php
@@ -0,0 +1,615 @@
+<?php
+$translations = array(
+ 'General_Locale' => 'no_NO.UTF-8',
+ 'General_TranslatorName' => 'QTSystems',
+ 'General_TranslatorEmail' => 'post@qts.no',
+ 'General_EnglishLanguageName' => 'Norwegian',
+ 'General_OriginalLanguageName' => 'Norsk',
+ 'General_HelloUser' => 'Hallo, %s!',
+ 'General_OpenSourceWebAnalytics' => 'Open Source Web Statistikk',
+ 'General_YourDashboard' => 'Ditt kontrollpanel',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Widgets',
+ 'General_Settings' => 'Innstillinger',
+ 'General_GiveUsYourFeedback' => 'Gi oss tilbakemeldinger!',
+ 'General_Unknown' => 'Ukjent',
+ 'General_Required' => '%s påkrevd',
+ 'General_Error' => 'Feil',
+ 'General_Warning' => 'Advarsel',
+ 'General_BackToHomepage' => 'Tilbake til Piwik startside',
+ 'General_Yes' => 'Ja',
+ 'General_No' => 'Nei',
+ 'General_Delete' => 'Slett',
+ 'General_Edit' => 'Endre',
+ 'General_Ok' => 'Ok',
+ 'General_Close' => 'Lukk',
+ 'General_Logout' => 'Logg ut',
+ 'General_Done' => 'Ferdig',
+ 'General_LoadingData' => 'Laster data...',
+ 'General_ErrorRequest' => 'Oops&hellip; problem oppstod, vennligst prøv igjen.',
+ 'General_Next' => 'Neste',
+ 'General_Previous' => 'Forrige',
+ 'General_Search' => 'Søk',
+ 'General_Others' => 'Andre',
+ 'General_Table' => 'Tabell',
+ 'General_Piechart' => 'Kakediagram',
+ 'General_TagCloud' => 'Takk-sky',
+ 'General_VBarGraph' => 'Søylediagram',
+ 'General_Export' => 'Eksporter',
+ 'General_Refresh' => 'Last siden på nytt',
+ 'General_Visitors' => 'Besøkende',
+ 'General_ColumnNbUniqVisitors' => 'Unike besøkende',
+ 'General_ColumnNbVisits' => 'Besøk',
+ 'General_ColumnLabel' => 'Type',
+ 'General_ColumnActionsPerVisit' => 'Handlinger pr besøk',
+ 'General_ColumnAvgTimeOnSite' => 'Gjennomsnittstid på nettstedet',
+ 'General_ColumnBounceRate' => 'Bounce Rate',
+ 'General_ColumnPageviews' => 'Sidevisninger',
+ 'General_ColumnUniquePageviews' => 'Unike sidevisninger',
+ 'General_Save' => 'Lagre',
+ 'General_Website' => 'Side',
+ 'General_NoDataForGraph' => 'Ingen data for denne grafen',
+ 'General_NoDataForTagCloud' => 'Ingen data for denne tagg-skyen.',
+ 'General_DisplayNormalTable' => 'Vis normal tabell',
+ 'General_DisplayMoreData' => 'Vis mer informasjon',
+ 'General_PiwikIsACollaborativeProject' => '%s Piwik %s er et åpent prosjekt og fremdeles i Beta. %s Hvis du vil hjelpe, vennligst %s kontakt oss%s.',
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => 'Du bruker nå en demo av %s; %sdownload%s full fersjon! Se %s',
+ 'API_QuickDocumentation' => '<h2>API quick documentation</h2><p>If you don\'t have data for today you can first <a href=\'misc/generateVisits.php\' target=_blank>generate some data</a> using the Visits Generator script.</p><p>You can try the different formats available for every method. It is very easy to extract any data you want from piwik!</p><p><b>For more information have a look at the <a href=\'http://dev.piwik.org/trac/wiki/API\'>official API Documentation</a> or the <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>API Reference</a>.</b></P><h2>User authentication</h2><p>If you want to <b>request the data in your scripts, in a crontab, etc. </b> you need to add the parameter <code><u>&token_auth=%s</u></code> to the API calls URLs that require authentication.</p><p>This token_auth is as secret as your login and password, <b>do not share it!</p>',
+ 'API_LoadedAPIs' => 'Lastet %s API\'et.',
+ 'Actions_Actions' => 'Handlinger',
+ 'Actions_SubmenuPages' => 'Sider',
+ 'Actions_SubmenuOutlinks' => 'Utlinker',
+ 'Actions_SubmenuDownloads' => 'Nedlastinger',
+ 'CoreHome_NoPrivileges' => 'Du er logget inn som \'%s\' men det ser ikke ut som du har noen tilganger i Piwik.<br />Spør din Piwik administrator for å gi deg lesetilgang.',
+ 'CoreHome_JavascriptDisabled' => 'JavaSript må være aktivert for at du skal kunne bruke Piwik sin standardvisning. Det ser ut som JavaScript er enten deaktiver eller ikke støttet av din nettleser.<br />For å bruke standardvisning, aktiver JavaScript i innstillingene for din nettleser, og %1stry again%2s.<br />',
+ 'CoreHome_TableNoData' => 'Ingen data for denne tabellen.',
+ 'CoreHome_CategoryNoData' => 'Ingen data i denne kategorien. Prøv å "Inkluder hele populasjon".',
+ 'CoreHome_ShowJSCode' => 'Vis JavaScript-koden til å sette inn på din webside.',
+ 'CoreHome_IncludeAllPopulation_js' => 'Inkluder hele populasjon',
+ 'CoreHome_ExcludeLowPopulation_js' => 'Eksluder lav populasjon',
+ 'CoreHome_PageOf_js' => '%s av %s',
+ 'CoreHome_Loading_js' => 'Laster...',
+ 'CoreHome_LocalizedDateFormat' => '%A %d %B %Y',
+ 'CoreHome_PeriodDay' => 'Dag',
+ 'CoreHome_PeriodWeek' => 'Uke',
+ 'CoreHome_PeriodMonth' => 'Måned',
+ 'CoreHome_PeriodYear' => 'År',
+ 'CoreHome_DaySu_js' => 'Søn',
+ 'CoreHome_DayMo_js' => 'Man',
+ 'CoreHome_DayTu_js' => 'Tirs',
+ 'CoreHome_DayWe_js' => 'Ons',
+ 'CoreHome_DayTh_js' => 'Tors',
+ 'CoreHome_DayFr_js' => 'Fre',
+ 'CoreHome_DaySa_js' => 'Lør',
+ 'CoreHome_MonthJanuary_js' => 'Januar',
+ 'CoreHome_MonthFebruary_js' => 'Februar',
+ 'CoreHome_MonthMarch_js' => 'Mars',
+ 'CoreHome_MonthApril_js' => 'April',
+ 'CoreHome_MonthMay_js' => 'Mai',
+ 'CoreHome_MonthJune_js' => 'Juni',
+ 'CoreHome_MonthJuly_js' => 'Juli',
+ 'CoreHome_MonthAugust_js' => 'August',
+ 'CoreHome_MonthSeptember_js' => 'September',
+ 'CoreHome_MonthOctober_js' => 'Oktober',
+ 'CoreHome_MonthNovember_js' => 'November',
+ 'CoreHome_MonthDecember_js' => 'Desember',
+ 'CorePluginsAdmin_Plugins' => 'Plugins',
+ 'CorePluginsAdmin_PluginsManagement' => 'Plugins Administrasjon',
+ 'CorePluginsAdmin_MainDescription' => 'Plugins kan utvide eller begrense funksjonaliteten i Piwik. Når en plugin har blitt installert, kan du aktivere eller deaktivere den er.',
+ 'CorePluginsAdmin_Plugin' => 'Plugin',
+ 'CorePluginsAdmin_Version' => 'Versjon',
+ 'CorePluginsAdmin_Description' => 'Beskrivelse',
+ 'CorePluginsAdmin_Status' => 'Status',
+ 'CorePluginsAdmin_Action' => 'Handling',
+ 'CorePluginsAdmin_PluginHomepage' => 'Plugin',
+ 'CorePluginsAdmin_Activated' => 'Aktivert',
+ 'CorePluginsAdmin_Active' => 'Aktiv',
+ 'CorePluginsAdmin_Inactive' => 'Inaktiv',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Denne plugin\'en kan ikke bli deaktivert',
+ 'CorePluginsAdmin_Deactivate' => 'Deaktiver',
+ 'CorePluginsAdmin_Activate' => 'Aktiver',
+ 'CorePluginsAdmin_MenuPlugins' => 'Plugins',
+ 'CoreUpdater_UpdateTitle' => 'Piwik &rsaquo; Oppdatering',
+ 'CoreUpdater_UpdateRequired' => 'Oppgradering er påkrevd',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Din Piwik database er utdatert, og må oppgraderes før du kan fortsette.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'Piwik vil nå bli oppgradert til versjon %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Følgende plugins vil nå bli oppgrader: %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Oppgraderingen kan ta en stund, vennligst vær litt tålmodig.',
+ 'CoreUpdater_UpgradePiwik' => 'Oppgrader Piwik',
+ 'CoreUpdater_HelpMessageContent' => 'sjekk %s Piwik FAQ %s som prøver å forklare de mest vanlige feil om oppgraderinger. %s Spør din systemadministrator - vedkommende kan kanskje hjelpe deg med feilen som antakelig har sammenheng med din server eller MySQL-installasjon / oppsett.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Kritisk feil med oppgraderingen:',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'Over vises feilmeldingen. Den bør hjelpe deg med å forklare årsaken, men hvis du trenger mer hjelp, vennligst:',
+ 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'Oppgraderingen er fullført, men det var noen småproblemer under prossessen. Les detaljene over her for detaljer. For videre hjelp:',
+ 'CoreUpdater_UpgradeComplete' => 'Oppgradering fullført!',
+ 'CoreUpdater_WarningMessages' => 'Advarsler:',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Feil under plugin-opggradering:',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'Vi automatisk deaktivere følgende plugins: %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik ble korrekt oppgradert!',
+ 'CoreUpdater_ContinueToPiwik' => 'Fortsett til Piwik',
+ 'DBStats_DatabaseUsage' => 'Databasebruk',
+ 'DBStats_MainDescription' => 'Piwik lagrer alle din statistikk i MySQL-databasen. Akkurat nå bruker Piwik-tabellene %s.',
+ 'DBStats_Table' => 'Tabell',
+ 'DBStats_RowNumber' => 'Rad nummer',
+ 'DBStats_DataSize' => 'Datastørrelse',
+ 'DBStats_IndexSize' => 'Index størrelse',
+ 'Dashboard_Dashboard' => 'Kontrollpanel',
+ 'Dashboard_AddWidget' => 'Legg til en widget...',
+ 'Dashboard_DeleteWidgetConfirm' => 'Er du sikker på at du vil fjerne denne widget\'en fra ditt kontrollpanel?',
+ 'Dashboard_SelectWidget' => 'Velg hvilken widget som du vil legge til kontrollpanelet.',
+ 'Dashboard_AddPreviewedWidget' => 'Legg til forhåndsvist widget til kontrollpanelet.',
+ 'Dashboard_WidgetPreview' => 'Forhåndsvisning av widget',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Widget er allerede i kontrollpanelet',
+ 'Dashboard_TitleClickToAdd_js' => 'Klikk her for å legge til kontrollpanelet',
+ 'Dashboard_LoadingPreview_js' => 'Laster forhåndsvisning, vennligst vent...',
+ 'Dashboard_LoadingWidget_js' => 'Laster widget, vennligst vent...',
+ 'Dashboard_WidgetNotFound_js' => 'Finner ikke widget',
+ 'Installation_Installation' => 'Installasjon',
+ 'Installation_InstallationStatus' => 'Installasjonsstatus',
+ 'Installation_PercentDone' => '%s %% ferdig',
+ 'Installation_NoConfigFound' => 'Piwik-konfigurasjonsfil kunne ikke bli funnet og du prøver å få tilgang til Piwik. <br /><b>&nbsp;&nbsp;&raquo;Du kan <a href=\'index.php\'>installere Piwik nå</a></b><br /><small>Hvus du prøvde å installere Piwik tidligere, og har noen tabeller i databasen, gamle data blir liggende!</small>',
+ 'Installation_MysqlSetup' => 'MySQL database oppsett',
+ 'Installation_MysqlErrorConnect' => 'Feil ved tilkobling til databasen
+',
+ 'Installation_JsTag' => 'Javascript tag',
+ 'Installation_JsTagHelp' => '<p>For å telle alle besøkende, du må plasse JavaScript-koden på alle dine sider.</p><p>Dine sider trenger ikke være laget med PHP, Piwik vil virke på alle typer sider (uansett om det er HTML, ASP, Perl eler noe annet språk).</p><p>Her er koden du må sette inn: (kopier og lim på alle dine sider)</p>',
+ 'Installation_Congratulations' => 'Gratulerer',
+ 'Installation_CongratulationsHelp' => '<p>Gratulerer! Din Piwik installasjon er fullført.</p><p>Sørg for at JavaScript-koden er lagt inn på dine sider, og vent på dine første besøkende!</p>',
+ 'Installation_ContinueToPiwik' => 'Fortsett til Piwik',
+ 'Installation_SetupWebsite' => 'Legg til en webside',
+ 'Installation_SetupWebsiteError' => 'Det skjedde en feil ved tillegging av en webskde',
+ 'Installation_GeneralSetup' => 'Generelt oppsett',
+ 'Installation_GeneralSetupSuccess' => 'Generelt oppsett ble vellykket lagret
+',
+ 'Installation_SystemCheck' => 'Systemsjekk',
+ 'Installation_SystemCheckPhp' => 'PHP versjon',
+ 'Installation_SystemCheckPdo' => 'Pdo tillegg',
+ 'Installation_SystemCheckPdoMysql' => 'Pdo_Mysql tillegg',
+ 'Installation_SystemCheckPdoError' => 'Du trenger å aktivere PDO og PDO_MYSQL tillegg i din php.ini fil.',
+ 'Installation_SystemCheckPdoHelp' => 'På en Windows-server du kan legge til følgende linjer i din php-ini %s <br /><br />På en linux-server kan du kompilere php med følgende valg %s I din php.ini, legg til følgende linjer %s<br /><br />Mer informasjon finner du på <a style="color:red" href="http://php.net/pdo">PHP.net</a>.',
+ 'Installation_SystemCheckWriteDirs' => 'Kataloger med skrivetilgang',
+ 'Installation_SystemCheckWriteDirsHelp' => 'Forå fikse denne fielen på ditt linux-system, prøv å skriv inn følgende kommando(er)',
+ 'Installation_SystemCheckMemoryLimit' => 'Memory limit',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'På en høyt trafikkert webside, kan arkiveringsprossessen kreve mer minne enn det som nå er tillatt.<br />Se på memory_limit i din php.ini fil hvis nødvendig.',
+ 'Installation_SystemCheckGD' => 'GD &gt; 2.x (grafikk)',
+ 'Installation_SystemCheckGDHelp' => 'Mindre grafiske elementer vil ikke fungere som ønsket.',
+ 'Installation_SystemCheckTimeLimit' => 'set_time_limit() tilgjengelig',
+ 'Installation_SystemCheckTimeLimitHelp' => 'På en høyt trafikkert webside, kan arkiveringsprossessen kreve mer tid enn det som nå er tillatt.<br />Se på max_execution_time i din php.ini fil hvis nødvendig.
+',
+ 'Installation_SystemCheckMail' => 'mail() tilgjengelig',
+ 'Installation_SystemCheckError' => 'En feil oppstod - må fikses før du kan fortsette',
+ 'Installation_SystemCheckWarning' => 'Piwik vil virke normalt, men noen tjenester vil kanskje mangle',
+ 'Installation_Tables' => 'Oppretter tabellene',
+ 'Installation_TablesWarning' => 'Noen <span id="linkToggle">Piwik tabeller</span> er allerede installert i databasen',
+ 'Installation_TablesFound' => 'Følgende tabeller ble funnet i databasen',
+ 'Installation_TablesWarningHelp' => 'Enten velg å bruke de eksisterende tabellene eller velg en ren installasjon for å slette all eksisterende data i databasen.',
+ 'Installation_TablesReuse' => 'Bruk de eksisterende tabellene',
+ 'Installation_TablesDelete' => 'Slett de oppdagede tabellene',
+ 'Installation_TablesDeletedSuccess' => 'Eksisterende Piwik-tabeller ble vellykket slettet
+',
+ 'Installation_TablesCreatedSuccess' => 'Tabellene ble vellykket opprettet!',
+ 'Installation_DatabaseCreatedSuccess' => 'Databasen %s ble vellykket opprettet!',
+ 'Installation_TablesDeleteConfirm' => 'Er du sikker på at du vil slette alle Piwik-tabellene fra denne databasen?',
+ 'Installation_Welcome' => 'Velkommen!',
+ 'Installation_WelcomeHelp' => '<p>Piwik er en Open Source statistikk-programvare som gjør det enkelt å finne informasjonen du ønsker om dine besøkende.</p><p>Denne prossessen er delt opp i %s lette steg og vil ta ca 5 minutter.</p>',
+ 'Login_LoginPasswordNotCorrect' => 'Brukernavn og passord er ikke korrekt',
+ 'Login_Login' => 'Brukernavn',
+ 'Login_Password' => 'Passord',
+ 'Login_LoginOrEmail' => 'Login eller epost',
+ 'Login_LogIn' => 'Logg inn',
+ 'Login_Logout' => 'Logg ut',
+ 'Login_LostYourPassword' => 'Glemt passord?',
+ 'Login_RemindPassword' => 'Husk passord',
+ 'Login_PasswordReminder' => 'Vennligst skriv inn ditt brukernavn eller epost-adresse. Du vil få et nytt passord på epost.',
+ 'Login_InvalidUsernameEmail' => 'Feil brukernavn og/eller epost-adresse.',
+ 'Login_MailTopicPasswordRecovery' => 'Gjennoppretting av passord',
+ 'Login_MailPasswordRecoveryBody' => 'Hei %1s, \n\m Ditt nye passord er: %2s \n\n Du kan nå logge inn her: %3s',
+ 'Login_PasswordSent' => 'Passordet har nettopp blitt sendt. Sjekk din epost.',
+ 'Login_ContactAdmin' => 'Mulig grunn: din webhost har kanskje deaktivert mail()-funksjonen. <br />Kontakt din Piwik administrator.',
+ 'Provider_WidgetProviders' => 'Tilbydere',
+ 'Provider_SubmenuLocationsProvider' => 'Lokasjoner & tilbydere',
+ 'Referers_Referers' => 'Henvisninger',
+ 'Referers_SearchEngines' => 'Søkemotorer',
+ 'Referers_Keywords' => 'Nøkkelord',
+ 'Referers_DirectEntry' => 'Direkte treff',
+ 'Referers_Websites' => 'Websider',
+ 'Referers_Campaigns' => 'Kampanjer',
+ 'Referers_Evolution' => 'Evolusjon over perioden',
+ 'Referers_Type' => 'Type kilde',
+ 'Referers_TypeDirectEntries' => '%s direkte treff',
+ 'Referers_TypeSearchEngines' => '%s fra søkemotorer',
+ 'Referers_TypeWebsites' => '%s fra websider',
+ 'Referers_TypeCampaigns' => '%s fra kampanjer',
+ 'Referers_Other' => 'Andre',
+ 'Referers_OtherDistinctSearchEngines' => '%s bestemte søkemotorer',
+ 'Referers_OtherDistinctKeywords' => '%s bestemte nøkkelord',
+ 'Referers_OtherDistinctWebsites' => '%1s bestemte websider (bruker %2s bestemte URLs)',
+ 'Referers_OtherDistinctCampaigns' => '%s bestemte kampanjer',
+ 'Referers_TagCloud' => 'Taggsky',
+ 'Referers_SubmenuEvolution' => 'Evolusjon',
+ 'Referers_SubmenuSearchEngines' => 'Søkemotorer og nøkkelord',
+ 'Referers_SubmenuWebsites' => 'Websider',
+ 'Referers_SubmenuCampaigns' => 'Kampanjer',
+ 'Referers_WidgetKeywords' => 'Liste over nøkkelord',
+ 'Referers_WidgetCampaigns' => 'Liste over kampanjer',
+ 'Referers_WidgetExternalWebsites' => 'Liste over eksterne websider',
+ 'Referers_WidgetSearchEngines' => 'Beste søkemotorer',
+ 'Referers_WidgetOverview' => 'Oversikt',
+ 'SitesManager_Sites' => 'Websider',
+ 'SitesManager_WebsitesManagement' => 'Administrasjon av websider',
+ 'SitesManager_MainDescription' => 'Dine analyser trenger websider! Legg til, oppdater, slett websider, og vis koden som du skal legge inn på dine websider.',
+ 'SitesManager_JsCode' => 'JavaScript kode',
+ 'SitesManager_JsCodeHelp' => 'Her er JavaScript-koden som du skal legge inn på alle dine sider',
+ 'SitesManager_ShowJsCode' => 'vis kode',
+ 'SitesManager_NoWebsites' => 'Du har ingen websider å administrere',
+ 'SitesManager_AddSite' => 'Legg til en ny webside',
+ 'SitesManager_Id' => 'ID',
+ 'SitesManager_Name' => 'Navn',
+ 'SitesManager_Urls' => 'URLs',
+ 'SitesManager_MenuSites' => 'Websider',
+ 'SitesManager_DeleteConfirm_js' => 'Er du sikker på at du ønsker å slette følgende webside? %s
+',
+ 'SitesManager_ExceptionDeleteSite' => 'Det er ikke mulig å slette denne websiden, da den er den eneste registrerte webside. Legg til en ny webside, og så slett denne.',
+ 'SitesManager_ExceptionNoUrl' => 'Du må spesifisere minst 1 URL til websiden.',
+ 'SitesManager_ExceptionEmptyName' => 'Sidens navn kan ikke være tomt.',
+ 'SitesManager_ExceptionInvalidUrl' => 'URL\'en \'%s\' er ikke en gyldig URL.',
+ 'TranslationsAdmin_MenuTranslations' => 'Oversettelser',
+ 'TranslationsAdmin_MenuLanguages' => 'Språk',
+ 'TranslationsAdmin_Plugin' => 'Plugin',
+ 'TranslationsAdmin_Definition' => 'Definisjon',
+ 'TranslationsAdmin_DefaultString' => 'Standard (English)',
+ 'TranslationsAdmin_TranslationString' => 'Oversettelse (gjeldende språk: %s)',
+ 'TranslationsAdmin_Translations' => 'Oversettelser',
+ 'TranslationsAdmin_FixPermissions' => 'Vennligst fiks filsystem-rettighetene',
+ 'TranslationsAdmin_AvailableLanguages' => 'Tilgjengelige språk',
+ 'TranslationsAdmin_AddLanguage' => 'Legg til språk',
+ 'TranslationsAdmin_LanguageCode' => 'Språk-kode',
+ 'TranslationsAdmin_Export' => 'Eksporter språk',
+ 'TranslationsAdmin_Import' => 'Importer språk',
+ 'UserCountry_Country' => 'Land',
+ 'UserCountry_Continent' => 'Kontinent',
+ 'UserCountry_DistinctCountries' => '%s bestemte land',
+ 'UserCountry_SubmenuLocations' => 'Lokasjoner',
+ 'UserCountry_WidgetContinents' => 'Besøkendes kontinent',
+ 'UserCountry_WidgetCountries' => 'Besøkendes land',
+ 'UserCountry_country_ac' => 'Ascension Islands',
+ 'UserCountry_country_ad' => 'Andorra',
+ 'UserCountry_country_ae' => 'United Arab Emirates',
+ 'UserCountry_country_af' => 'Afghanistan',
+ 'UserCountry_country_ag' => 'Antigua and Barbuda',
+ 'UserCountry_country_ai' => 'Anguilla',
+ 'UserCountry_country_al' => 'Albania',
+ 'UserCountry_country_am' => 'Armenia',
+ 'UserCountry_country_an' => 'Netherlands Antilles',
+ 'UserCountry_country_ao' => 'Angola',
+ 'UserCountry_country_aq' => 'Antarctica',
+ 'UserCountry_country_ar' => 'Argentina',
+ 'UserCountry_country_as' => 'American Samoa',
+ 'UserCountry_country_at' => 'Østerrike',
+ 'UserCountry_country_au' => 'Australia',
+ 'UserCountry_country_aw' => 'Aruba',
+ 'UserCountry_country_az' => 'Aserbaijan',
+ 'UserCountry_country_ba' => 'Bosnia og Herzegovina',
+ 'UserCountry_country_bb' => 'Barbados',
+ 'UserCountry_country_bd' => 'Bangladesh',
+ 'UserCountry_country_be' => 'Belgia',
+ 'UserCountry_country_bf' => 'Burkina Faso',
+ 'UserCountry_country_bg' => 'Bulgaria',
+ 'UserCountry_country_bh' => 'Bahrain',
+ 'UserCountry_country_bi' => 'Burundi',
+ 'UserCountry_country_bj' => 'Benin',
+ 'UserCountry_country_bm' => 'Bermuda',
+ 'UserCountry_country_bn' => 'Bruneo',
+ 'UserCountry_country_bo' => 'Bolivia',
+ 'UserCountry_country_br' => 'Brasil',
+ 'UserCountry_country_bs' => 'Bahamas',
+ 'UserCountry_country_bt' => 'Bhutan',
+ 'UserCountry_country_bv' => 'Bouvet Island',
+ 'UserCountry_country_bw' => 'Botswana',
+ 'UserCountry_country_by' => 'Hvitrussland',
+ 'UserCountry_country_bz' => 'Belize',
+ 'UserCountry_country_ca' => 'Kanada',
+ 'UserCountry_country_cc' => 'Cocos (Keeling) Islands',
+ 'UserCountry_country_cd' => 'Congo, The Democratic Republic of the',
+ 'UserCountry_country_cf' => 'Central African Republic',
+ 'UserCountry_country_cg' => 'Kongo',
+ 'UserCountry_country_ch' => 'Sveits',
+ 'UserCountry_country_ci' => 'Cote D\'Ivoire',
+ 'UserCountry_country_ck' => 'Cook Islands',
+ 'UserCountry_country_cl' => 'Chile',
+ 'UserCountry_country_cm' => 'Kamerun',
+ 'UserCountry_country_cn' => 'Kina',
+ 'UserCountry_country_co' => 'Colombia',
+ 'UserCountry_country_cr' => 'Costa Rica',
+ 'UserCountry_country_cs' => 'Serbia Montenegro',
+ 'UserCountry_country_cu' => 'Cuba',
+ 'UserCountry_country_cv' => 'Cape Verde',
+ 'UserCountry_country_cx' => 'Christmas Island',
+ 'UserCountry_country_cy' => 'Kypros',
+ 'UserCountry_country_cz' => 'Tsjekkiske republikk',
+ 'UserCountry_country_de' => 'Tyskland',
+ 'UserCountry_country_dj' => 'Djibouti',
+ 'UserCountry_country_dk' => 'Danmark',
+ 'UserCountry_country_dm' => 'Dominica',
+ 'UserCountry_country_do' => 'Dominican Republic',
+ 'UserCountry_country_dz' => 'Algerie',
+ 'UserCountry_country_ec' => 'Ecuador',
+ 'UserCountry_country_ee' => 'Estonia',
+ 'UserCountry_country_eg' => 'Egypt',
+ 'UserCountry_country_eh' => 'Western Sahara',
+ 'UserCountry_country_er' => 'Eritrea',
+ 'UserCountry_country_es' => 'Spania',
+ 'UserCountry_country_et' => 'Ethiopia',
+ 'UserCountry_country_fi' => 'Finland',
+ 'UserCountry_country_fj' => 'Fiji',
+ 'UserCountry_country_fk' => 'Falkland Islands (Malvinas)',
+ 'UserCountry_country_fm' => 'Micronesia, Federated States of',
+ 'UserCountry_country_fo' => 'Faroe Islands',
+ 'UserCountry_country_fr' => 'Frankrike',
+ 'UserCountry_country_ga' => 'Gabon',
+ 'UserCountry_country_gd' => 'Grenada',
+ 'UserCountry_country_ge' => 'Georgia',
+ 'UserCountry_country_gf' => 'French Guyana',
+ 'UserCountry_country_gg' => 'Guernsey',
+ 'UserCountry_country_gh' => 'Ghana',
+ 'UserCountry_country_gi' => 'Gibraltar',
+ 'UserCountry_country_gl' => 'Grønland',
+ 'UserCountry_country_gm' => 'Gambia',
+ 'UserCountry_country_gn' => 'Guinea',
+ 'UserCountry_country_gp' => 'Guadeloupe',
+ 'UserCountry_country_gq' => 'Equatorial Guinea',
+ 'UserCountry_country_gr' => 'Hellas',
+ 'UserCountry_country_gs' => 'South Georgia and the South Sandwich Islands',
+ 'UserCountry_country_gt' => 'Guatemala',
+ 'UserCountry_country_gu' => 'Guam',
+ 'UserCountry_country_gw' => 'Guinea-Bissau',
+ 'UserCountry_country_gy' => 'Guyana',
+ 'UserCountry_country_hk' => 'Hong Kong',
+ 'UserCountry_country_hm' => 'Heard Island and McDonald Islands',
+ 'UserCountry_country_hn' => 'Honduras',
+ 'UserCountry_country_hr' => 'Kroatia',
+ 'UserCountry_country_ht' => 'Haiti',
+ 'UserCountry_country_hu' => 'Hungary',
+ 'UserCountry_country_id' => 'Indonesia',
+ 'UserCountry_country_ie' => 'Ireland',
+ 'UserCountry_country_il' => 'Israel',
+ 'UserCountry_country_im' => 'Man Island',
+ 'UserCountry_country_in' => 'India',
+ 'UserCountry_country_io' => 'British Indian Ocean Territory',
+ 'UserCountry_country_iq' => 'Iraq',
+ 'UserCountry_country_ir' => 'Iran',
+ 'UserCountry_country_is' => 'Island',
+ 'UserCountry_country_it' => 'Italia',
+ 'UserCountry_country_je' => 'Jersey',
+ 'UserCountry_country_jm' => 'Jamaica',
+ 'UserCountry_country_jo' => 'Jordan',
+ 'UserCountry_country_jp' => 'Japan',
+ 'UserCountry_country_ke' => 'Kenya',
+ 'UserCountry_country_kg' => 'Kyrgyzstan',
+ 'UserCountry_country_kh' => 'Cambodia',
+ 'UserCountry_country_ki' => 'Kiribati',
+ 'UserCountry_country_km' => 'Comoros',
+ 'UserCountry_country_kn' => 'Saint Kitts and Nevis',
+ 'UserCountry_country_kp' => 'Korea, Democratic People\'s Republic of',
+ 'UserCountry_country_kr' => 'Korea, Republic of',
+ 'UserCountry_country_kw' => 'Kuwait',
+ 'UserCountry_country_ky' => 'Cayman Islands',
+ 'UserCountry_country_kz' => 'Kazakhstan',
+ 'UserCountry_country_la' => 'Laos',
+ 'UserCountry_country_lb' => 'Libanon',
+ 'UserCountry_country_lc' => 'Saint Lucia',
+ 'UserCountry_country_li' => 'Liechtenstein',
+ 'UserCountry_country_lk' => 'Sri Lanka',
+ 'UserCountry_country_lr' => 'Liberia',
+ 'UserCountry_country_ls' => 'Lesotho',
+ 'UserCountry_country_lt' => 'Litauen',
+ 'UserCountry_country_lu' => 'Luxembourg',
+ 'UserCountry_country_lv' => 'Latvia',
+ 'UserCountry_country_ly' => 'Libya',
+ 'UserCountry_country_ma' => 'Marocco',
+ 'UserCountry_country_mc' => 'Monaco',
+ 'UserCountry_country_md' => 'Moldova, Republic of',
+ 'UserCountry_country_mg' => 'Madagaskar',
+ 'UserCountry_country_mh' => 'Marshall Islands',
+ 'UserCountry_country_mk' => 'Makedonia',
+ 'UserCountry_country_ml' => 'Mali',
+ 'UserCountry_country_mm' => 'Myanmar',
+ 'UserCountry_country_mn' => 'Mongolia',
+ 'UserCountry_country_mo' => 'Macau',
+ 'UserCountry_country_mp' => 'Northern Mariana Islands',
+ 'UserCountry_country_mq' => 'Martinique',
+ 'UserCountry_country_mr' => 'Mauritania',
+ 'UserCountry_country_ms' => 'Montserrat',
+ 'UserCountry_country_mt' => 'Malta',
+ 'UserCountry_country_mu' => 'Mauritius',
+ 'UserCountry_country_mv' => 'Maldivene',
+ 'UserCountry_country_mw' => 'Malawi',
+ 'UserCountry_country_mx' => 'Mexico',
+ 'UserCountry_country_my' => 'Malaysia',
+ 'UserCountry_country_mz' => 'Mozambique',
+ 'UserCountry_country_na' => 'Namibia',
+ 'UserCountry_country_nc' => 'New Caledonia',
+ 'UserCountry_country_ne' => 'Niger',
+ 'UserCountry_country_nf' => 'Norfolk Island',
+ 'UserCountry_country_ng' => 'Nigeria',
+ 'UserCountry_country_ni' => 'Nicaragua',
+ 'UserCountry_country_nl' => 'Nederland',
+ 'UserCountry_country_no' => 'Norge',
+ 'UserCountry_country_np' => 'Nepal',
+ 'UserCountry_country_nr' => 'Nauru',
+ 'UserCountry_country_nu' => 'Niue',
+ 'UserCountry_country_nz' => 'New Zealand',
+ 'UserCountry_country_om' => 'Oman',
+ 'UserCountry_country_pa' => 'Panama',
+ 'UserCountry_country_pe' => 'Peru',
+ 'UserCountry_country_pf' => 'French Polynesia',
+ 'UserCountry_country_pg' => 'Papua New Guinea',
+ 'UserCountry_country_ph' => 'Fillipinene',
+ 'UserCountry_country_pk' => 'Pakistan',
+ 'UserCountry_country_pl' => 'Polen',
+ 'UserCountry_country_pm' => 'Saint Pierre and Miquelon',
+ 'UserCountry_country_pn' => 'Pitcairn',
+ 'UserCountry_country_pr' => 'Puerto Rico',
+ 'UserCountry_country_ps' => 'Palestinian Territory',
+ 'UserCountry_country_pt' => 'Portugal',
+ 'UserCountry_country_pw' => 'Palau',
+ 'UserCountry_country_py' => 'Paraguay',
+ 'UserCountry_country_qa' => 'Qatar',
+ 'UserCountry_country_re' => 'Reunion Island',
+ 'UserCountry_country_ro' => 'Romania',
+ 'UserCountry_country_ru' => 'Russland',
+ 'UserCountry_country_rs' => 'Serbia',
+ 'UserCountry_country_rw' => 'Rwanda',
+ 'UserCountry_country_sa' => 'Saudi Arabia',
+ 'UserCountry_country_sb' => 'Solomon Islands',
+ 'UserCountry_country_sc' => 'Seychellene',
+ 'UserCountry_country_sd' => 'Sudan',
+ 'UserCountry_country_se' => 'Sverige',
+ 'UserCountry_country_sg' => 'Singapore',
+ 'UserCountry_country_sh' => 'Saint Helena',
+ 'UserCountry_country_si' => 'Slovenia',
+ 'UserCountry_country_sj' => 'Svalbard',
+ 'UserCountry_country_sk' => 'Slovakia',
+ 'UserCountry_country_sl' => 'Sierra Leone',
+ 'UserCountry_country_sm' => 'San Marino',
+ 'UserCountry_country_sn' => 'Senegal',
+ 'UserCountry_country_so' => 'Somalia',
+ 'UserCountry_country_sr' => 'Surinam',
+ 'UserCountry_country_st' => 'Sao Tome and Principe',
+ 'UserCountry_country_su' => 'Old U.S.S.R',
+ 'UserCountry_country_sv' => 'El Salvador',
+ 'UserCountry_country_sy' => 'Syrian Arab Republic',
+ 'UserCountry_country_sz' => 'Swaziland',
+ 'UserCountry_country_tc' => 'Turks and Caicos Islands',
+ 'UserCountry_country_td' => 'Chad',
+ 'UserCountry_country_tf' => 'French Southern Territories',
+ 'UserCountry_country_tg' => 'Togo',
+ 'UserCountry_country_th' => 'Thailand',
+ 'UserCountry_country_tj' => 'Tajikistan',
+ 'UserCountry_country_tk' => 'Tokelau',
+ 'UserCountry_country_tm' => 'Turkmenistan',
+ 'UserCountry_country_tn' => 'Tunisia',
+ 'UserCountry_country_to' => 'Tonga',
+ 'UserCountry_country_tp' => 'East Timor',
+ 'UserCountry_country_tr' => 'Tyrkia',
+ 'UserCountry_country_tt' => 'Trinidad and Tobago',
+ 'UserCountry_country_tv' => 'Tuvalu',
+ 'UserCountry_country_tw' => 'Taiwan',
+ 'UserCountry_country_tz' => 'Tanzania, United Republic of',
+ 'UserCountry_country_ua' => 'Ukraina',
+ 'UserCountry_country_ug' => 'Uganda',
+ 'UserCountry_country_uk' => 'England',
+ 'UserCountry_country_gb' => 'Storbrittania',
+ 'UserCountry_country_um' => 'United States Minor Outlying Islands',
+ 'UserCountry_country_us' => 'USA',
+ 'UserCountry_country_uy' => 'Uruguay',
+ 'UserCountry_country_uz' => 'Uzbekistan',
+ 'UserCountry_country_va' => 'Vatikanstaten',
+ 'UserCountry_country_vc' => 'Saint Vincent and the Grenadines',
+ 'UserCountry_country_ve' => 'Venezuela',
+ 'UserCountry_country_vg' => 'Virgin Islands, British',
+ 'UserCountry_country_vi' => 'Virgin Islands, U.S.',
+ 'UserCountry_country_vn' => 'Vietnam',
+ 'UserCountry_country_vu' => 'Vanuatu',
+ 'UserCountry_country_wf' => 'Wallis and Futuna',
+ 'UserCountry_country_ws' => 'Samoa',
+ 'UserCountry_country_ye' => 'Yemen',
+ 'UserCountry_country_yt' => 'Mayotte',
+ 'UserCountry_country_yu' => 'Jugoslavia',
+ 'UserCountry_country_za' => 'Sør Afrika',
+ 'UserCountry_country_zm' => 'Zambia',
+ 'UserCountry_country_zr' => 'Zaire',
+ 'UserCountry_country_zw' => 'Zimbabwe',
+ 'UserCountry_continent_eur' => 'Europa',
+ 'UserCountry_continent_afr' => 'Afrika',
+ 'UserCountry_continent_asi' => 'Asia',
+ 'UserCountry_continent_ams' => 'Sør- og Sentral-Ameria',
+ 'UserCountry_continent_amn' => 'Nord-Amerika',
+ 'UserCountry_continent_oce' => 'Australia',
+ 'UserSettings_BrowserFamilies' => 'Nettleserfamilier',
+ 'UserSettings_Browsers' => 'Nettlesere',
+ 'UserSettings_Plugins' => 'Plugins',
+ 'UserSettings_Configurations' => 'Innstillinger',
+ 'UserSettings_OperatinsSystems' => 'Operativsystemer',
+ 'UserSettings_Resolutions' => 'Oppløsninger',
+ 'UserSettings_WideScreen' => 'Widescreen',
+ 'UserSettings_WidgetResolutions' => 'Skjermoppløsninger',
+ 'UserSettings_WidgetBrowsers' => 'Besøkendes nettlesere',
+ 'UserSettings_WidgetPlugins' => 'Liste over plugins',
+ 'UserSettings_WidgetWidescreen' => 'Normal / Widescreen',
+ 'UserSettings_WidgetBrowserFamilies' => 'Nettlesere etter familie',
+ 'UserSettings_WidgetOperatingSystems' => 'Operativsystemer',
+ 'UserSettings_WidgetGlobalVisitors' => 'Besøkendes konfigurasjon',
+ 'UserSettings_SubmenuSettings' => 'Innstillinger',
+ 'UsersManager_UsersManagement' => 'Brukerkonfigurasjon',
+ 'UsersManager_UsersManagementMainDescription' => 'Opprett nye brukere eller oppdater eksisterende. Du kan etterpå endre dems tilganger.',
+ 'UsersManager_ManageAccess' => 'Konfigurer tilgang',
+ 'UsersManager_MainDescription' => 'Bestem hvilken bruker som har tilgang til Piwik på dine websider. Du kan også sette tilgange på alle dine websider på en gang.',
+ 'UsersManager_Sites' => 'Websider',
+ 'UsersManager_AllWebsites' => 'Alle websider',
+ 'UsersManager_ApplyToAllWebsites' => 'Legg til alle websider',
+ 'UsersManager_User' => 'Bruker',
+ 'UsersManager_PrivNone' => 'Ingen tilgang',
+ 'UsersManager_PrivView' => 'Vis',
+ 'UsersManager_PrivAdmin' => 'Admin',
+ 'UsersManager_ChangeAllConfirm' => 'Er du sikker på at du vil endre \'%s\' tilgang på alle websidene?',
+ 'UsersManager_Login' => 'Login',
+ 'UsersManager_Password' => 'Passord',
+ 'UsersManager_Email' => 'Epost',
+ 'UsersManager_Alias' => 'Alias',
+ 'UsersManager_Token' => 'token_auth',
+ 'UsersManager_Edit' => 'Endre',
+ 'UsersManager_AddUser' => 'Legg til ny bruker',
+ 'UsersManager_MenuUsers' => 'Brukere',
+ 'UsersManager_DeleteConfirm_js' => 'Er du sikker på at du vil slette %s?',
+ 'UsersManager_ExceptionLoginExists' => 'Login \'%s\' eksisterer allerede.',
+ 'UsersManager_ExceptionEmailExists' => 'Bruker med epost \'%s\' eksisterer allerede.',
+ 'UsersManager_ExceptionInvalidLogin' => 'Login kan kun inneholde bokstaver, tall og tegnene \'_\' eller \'-\' eller \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'Lengden på massord må være mellom 6 og 26 bokstaver.',
+ 'UsersManager_ExceptionInvalidEmail' => 'Epost-adressen er ikke i gyldig format.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'Bruker \'%s\' eksisterer ikke, og kan derfor ikke bli slettet.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'Du kan ikke gi administrator-tilgang til \'anonymous\'-bruker.',
+ 'UsersManager_ExceptionEditAnonymous' => 'Anonymous bruker kan ikke bli redigert eller slettet. Den blir brukt av Piwik for å definere en bruker som ikke har blitt logget inn ennå.',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'Bruker \'%s\' eksisterer ikke.',
+ 'UsersManager_ExceptionAccessValues' => 'Tilgangsparameteret må minst ha en av de følgende verdier: [ %s ]',
+ 'VisitFrequency_Evolution' => 'Evolusjon over perioden',
+ 'VisitFrequency_ReturnVisits' => '%s tilbakevendende besøk',
+ 'VisitFrequency_ReturnActions' => '%s handlinger av de tilbakevendende besøk',
+ 'VisitFrequency_ReturnMaxActions' => '%s maks handlinger av de tilbakevendende besøk',
+ 'VisitFrequency_ReturnTotalTime' => '%s total tid bruk av de tilbakevendende besøk',
+ 'VisitFrequency_ReturnBounces' => '%s ganger har en tilbakevendende besøk har gått videre til en annen webside / lukket nettleseren.',
+ 'VisitFrequency_WidgetOverview' => 'Frekvens-oversikt',
+ 'VisitFrequency_WidgetGraphReturning' => 'Graf for tilbakevendende besøk',
+ 'VisitFrequency_SubmenuFrequency' => 'Frekvens',
+ 'VisitTime_LocalTime' => 'Besøk pr lokaltid',
+ 'VisitTime_ServerTime' => 'Besøk pr servertid',
+ 'VisitTime_WidgetLocalTime' => 'Besøk etter lokaltid',
+ 'VisitTime_WidgetServerTime' => 'Besøk etter servertid',
+ 'VisitTime_SubmenuTimes' => 'Tider',
+ 'VisitTime_NHour' => '%st',
+ 'VisitorInterest_VisitsPerDuration' => 'Besøk pr besøkstid',
+ 'VisitorInterest_VisitsPerNbOfPages' => 'Besøk pr antall sider',
+ 'VisitorInterest_WidgetLengths' => 'Besøkslengde',
+ 'VisitorInterest_WidgetPages' => 'Sider pr besøk',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Frekvens og lojalitet',
+ 'VisitorInterest_PlusXMin' => '%s min',
+ 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
+ 'VisitorInterest_OnePage' => '1 side',
+ 'VisitorInterest_NPages' => '%s sider',
+ 'VisitorInterest_BetweenXYSeconds' => '%1s-%2ss',
+ 'VisitsSummary_NbVisits' => '%s besøk',
+ 'VisitsSummary_NbUniqueVisitors' => '%s unike besøkende',
+ 'VisitsSummary_NbActions' => '%s handlinger (sidevisninger)',
+ 'VisitsSummary_TotalTime' => '%s total tid brukt av besøkende',
+ 'VisitsSummary_MaxNbActions' => '%s maks handlinger i ett besøk',
+ 'VisitsSummary_NbBounced' => '%s har forlatt websiden etter en side',
+ 'VisitsSummary_Evolution' => 'Evolusjon de siste 30 %ss',
+ 'VisitsSummary_Report' => 'Rapport',
+ 'VisitsSummary_GenerateTime' => '%s sekuner for å generere denne siden',
+ 'VisitsSummary_GenerateQueries' => '%s spørringer kjørt',
+ 'VisitsSummary_WidgetLastVisits' => 'Sist besøkende grafikk
+',
+ 'VisitsSummary_WidgetVisits' => 'Besøksoversikt',
+ 'VisitsSummary_WidgetLastVisitors' => 'Siste unike beslkende',
+ 'VisitsSummary_WidgetOverviewGraph' => 'Oversikt med grafikk',
+ 'VisitsSummary_SubmenuOverview' => 'Oversikt',
+); \ No newline at end of file
diff --git a/lang/pt.php b/lang/pt.php
index 0d9e782a23..cac8f7a884 100644
--- a/lang/pt.php
+++ b/lang/pt.php
@@ -75,7 +75,7 @@ $translations = array(
'CoreHome_MonthSeptember_js' => 'Setembro',
'CoreHome_MonthOctober_js' => 'Outubro',
'CoreHome_MonthNovember_js' => 'Novembro',
- 'CoreHome_MonthDecemeber_js' => 'Dezembro',
+ 'CoreHome_MonthDecember_js' => 'Dezembro',
'Actions_SubmenuPages' => 'P&aacute;ginas',
'Actions_SubmenuOutlinks' => 'Links Externos',
'Actions_SubmenuDownloads' => 'Downloads',
diff --git a/lang/sk.php b/lang/sk.php
new file mode 100644
index 0000000000..bd90fc85c3
--- /dev/null
+++ b/lang/sk.php
@@ -0,0 +1,618 @@
+<?php
+
+setlocale(LC_TIME, 'sk_SK.UTF-8');
+
+$translations = array(
+ 'General_Locale' => 'sk_SK.UTF-8',
+ 'General_TranslatorName' => 'Zdenko Podobný',
+ 'General_TranslatorEmail' => 'zdenop@gmail.com',
+ 'General_EnglishLanguageName' => 'Slovak',
+ 'General_OriginalLanguageName' => 'Slovensky',
+ 'General_HelloUser' => 'Vitaj, %s!',
+ 'General_OpenSourceWebAnalytics' => 'Open Source Analýza Webu',
+ 'General_YourDashboard' => 'Riadiaci panel',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Miniaplikácie',
+ 'General_Settings' => 'Nastavenia',
+ 'General_GiveUsYourFeedback' => 'Spätná reakcia!',
+ 'General_Unknown' => 'Neznáme',
+ 'General_Required' => '%s požadované',
+ 'General_Error' => 'Chyba',
+ 'General_Warning' => 'Varovanie',
+ 'General_BackToHomepage' => 'Späť na domovskú stránku Piwik',
+ 'General_Yes' => 'Áno',
+ 'General_No' => 'Nie',
+ 'General_Delete' => 'Odstrániť',
+ 'General_Edit' => 'Upraviť',
+ 'General_Ok' => 'Ok',
+ 'General_Close' => 'Zatvoriť',
+ 'General_Logout' => 'Odhlásiť',
+ 'General_Done' => 'Hotovo',
+ 'General_LoadingData' => 'Načítavanie dát...',
+ 'General_ErrorRequest' => 'Oops&hellip; problém počas požiadavky, prosím skúste znova.',
+ 'General_Next' => 'Ďalej',
+ 'General_Previous' => 'Späť',
+ 'General_Search' => 'Hľadanie',
+ 'General_Others' => 'Ostatné',
+ 'General_Table' => 'Tabuľka',
+ 'General_Piechart' => 'Koláčový graf',
+ 'General_TagCloud' => 'Oblak značiek',
+ 'General_VBarGraph' => 'Vertikálny stĺpcový graf',
+ 'General_Export' => 'Export',
+ 'General_Refresh' => 'Aktualizovať stránku',
+ 'General_Visitors' => 'Návštevníci',
+ 'General_ColumnNbUniqVisitors' => 'Unikátny návštevníci',
+ 'General_ColumnNbVisits' => 'Návštevy',
+ 'General_ColumnLabel' => 'Popis',
+ 'General_ColumnActionsPerVisit' => 'Akcie počas návštevy',
+ 'General_ColumnAvgTimeOnSite' => 'Priem. doba na stránke',
+ 'General_ColumnBounceRate' => 'Miera odskokov',
+ 'General_ColumnPageviews' => 'Zobrazené stránky',
+ 'General_ColumnUniquePageviews' => 'Unikátne zobrazenia stránok',
+ 'General_Save' => 'Uložiť',
+ 'General_Website' => 'Webstránka',
+ 'General_NoDataForGraph' => 'Pre tento graf nie sú dáta',
+ 'General_NoDataForTagCloud' => 'Pre tento oblak nie sú dáta',
+ 'General_DisplayNormalTable' => 'Zobraziť bežnú tabuľku',
+ 'General_DisplayMoreData' => 'Zobraziť viac dát',
+ 'General_PiwikIsACollaborativeProject' => '%s Piwik %s je založený na spolupráci a je v beta štádiu. %s Ak chcete pomôcť, tak nás prosím %s kontaktujte!%s.',
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => 'Aktuálne prezeráte demo %s; %sdownload%s úplnej verzie! Pozrite si %s',
+ 'CorePluginsAdmin_Plugins' => 'Zásuvné moduly',
+ 'CorePluginsAdmin_PluginsManagement' => 'Správa modulov',
+ 'CorePluginsAdmin_MainDescription' => 'Moduly rozširujú funkcionalitu projektu Piwik. Po nainštalovaní modulu ho tu môžete aktivovať, alebo deaktivovať.',
+ 'CorePluginsAdmin_Plugin' => 'Modul',
+ 'CorePluginsAdmin_Version' => 'Verzia',
+ 'CorePluginsAdmin_Description' => 'Popis',
+ 'CorePluginsAdmin_Status' => 'Stav',
+ 'CorePluginsAdmin_Action' => 'Akcia',
+ 'CorePluginsAdmin_PluginHomepage' => 'Domovská stránka modulu',
+ 'CorePluginsAdmin_Activated' => 'Aktivovaný',
+ 'CorePluginsAdmin_Active' => 'Aktívny',
+ 'CorePluginsAdmin_Inactive' => 'Neaktívny',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Tento modul nie je možné deaktivovať',
+ 'CorePluginsAdmin_Deactivate' => 'Deaktivovať',
+ 'CorePluginsAdmin_Activate' => 'Aktivovať',
+ 'CorePluginsAdmin_MenuPlugins' => 'Moduly',
+ 'API_QuickDocumentation' => '<h2>API skrátená dokumentácia</h2><p>Pokiaľ ešte nemáte dáta pre dnešný deň, tak si najskôr nejaké <a href=\'misc/generateVisits.php\' target=_blank>vygenerujte</a> s použitím skriptu na generovanie návštevníkov.</p><p>Môžete vyskúšať rôzne formáty dostupné pre každú metódu. Je veľmi ľahké extrahovať ktorékoľvek dáta z piwik!</p><p><b>Viac informácií nájdete v <a href=\'http://dev.piwik.org/trac/wiki/API\'>oficiálnej API Dokumentácií</a> alebo v <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>API Referenčnej príručke</a>.</b></P><h2>Autentifikácia používateľov</h2><p>Ak chcete <b>požadovať dáta vo svojich skriptoch, cez crontab atď.,</b> budete potrebovať pridať parameter <code><u>&token_auth=%s</u></code> k volaniu API URL, ktorá vyžaduje autentifikáciu.</p><p>Parameter token_auth je tajný, rovnako ako vaše prihlasovacie údaje (login) a heslo, <b>nikomu ho neposkytnite!</p>',
+ 'API_LoadedAPIs' => 'Úspešne načítané %s API',
+ 'CoreHome_NoPrivileges' => 'Ste prihlásený ako \'%s\', ale zdá sa, že nemáte žiadne práva na nastavovanie Piwik.<br />Požiadajte svojho Piwik administrátora, aby vám dal prístup na prezeranie(\'view\') k webstránke.',
+ 'CoreHome_JavascriptDisabled' => 'JavaScript musí byť povolený, ak chcete používať Piwik v štandardnom zobrazení.<br />Akokoľvek — zdá sa že, JavaScript buď nie je povolený, alebo podporovaný vašim prehliadačom.<br />Pre štandardné zobrazenie povoľte JavaScript zmenou nastavení Vášho prehliadača, a potom %1sskúste znova%2s.<br />',
+ 'CoreHome_TableNoData' => 'Pre túto tabuľku nie sú dáta.',
+ 'CoreHome_CategoryNoData' => 'Pre túto kategóriu nie sú dáta. Skúste použiť „Vrátane celej populácie“.',
+ 'CoreHome_ShowJSCode' => 'Zobraziť javascript kód pre vloženie',
+ 'CoreHome_IncludeAllPopulation_js' => 'Vrátane celej populácie',
+ 'CoreHome_ExcludeLowPopulation_js' => 'Bez nízkej populácie',
+ 'CoreHome_PageOf_js' => '%s z %s',
+ 'CoreHome_Loading_js' => 'Načítavanie…',
+ 'CoreHome_LocalizedDateFormat' => '%A %d %B %Y',
+ 'CoreHome_PeriodDay' => 'Deň',
+ 'CoreHome_PeriodWeek' => 'týždeň',
+ 'CoreHome_PeriodMonth' => 'Mesiac',
+ 'CoreHome_PeriodYear' => 'Rok',
+ 'CoreHome_DaySu_js' => 'Ne',
+ 'CoreHome_DayMo_js' => 'Po',
+ 'CoreHome_DayTu_js' => 'Ut',
+ 'CoreHome_DayWe_js' => 'St',
+ 'CoreHome_DayTh_js' => 'Št',
+ 'CoreHome_DayFr_js' => 'Pi',
+ 'CoreHome_DaySa_js' => 'So',
+ 'CoreHome_MonthJanuary_js' => 'Január',
+ 'CoreHome_MonthFebruary_js' => 'Február',
+ 'CoreHome_MonthMarch_js' => 'Marec',
+ 'CoreHome_MonthApril_js' => 'Apríl',
+ 'CoreHome_MonthMay_js' => 'Máj',
+ 'CoreHome_MonthJune_js' => 'Jún',
+ 'CoreHome_MonthJuly_js' => 'Júl',
+ 'CoreHome_MonthAugust_js' => 'August',
+ 'CoreHome_MonthSeptember_js' => 'September',
+ 'CoreHome_MonthOctober_js' => 'Október',
+ 'CoreHome_MonthNovember_js' => 'November',
+ 'CoreHome_MonthDecember_js' => 'December',
+ 'CoreUpdater_UpdateTitle' => 'Piwik &rsaquo; Aktualizácia',
+ 'CoreUpdater_UpdateRequired' => 'Vyžaduje sa aktualizácia',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Vaša Piwik databáza je zastaralá a musí byť zaktualizovaná, aby ste mohli pokračovať ďalej.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'Piwik bude zaktualizovaný na verziu %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Nasledujúce moduly budú zaktualizované: %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Aktualizačný proces môžte chvíľu trvať, tak buďte prosím trpezlivý.',
+ 'CoreUpdater_UpgradePiwik' => 'Aktualizácia Piwik',
+ 'CoreUpdater_HelpMessageContent' => 'Pozrite si %s Piwik FAQ %s, kde sa pokúšame vysvetliť väčšinu bežných problémov počas aktualizácie. %s Požiadajte svojho systémového administrátora - mal by Vám vedieť pomôcť s chyba, ktoré sa s najväčšou pravdepodobnosťou týkajú Vášho servera alebo nastavenia MySQ.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Kritická chyba počas procesu aktualizácie:',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'Vyššie je uvedená hlavná chybová správa, ktorá by mala vysvetliť problém. Ak potrebujete ďalšiu pomoc, tak prosím:',
+ 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'Aktualizácie je úspešne ukončená, avšak sa počas nej vyskytli problémy. Prečítajte si nasledovné detaily. Ďalšiu pomoc nájdete na:',
+ 'CoreUpdater_UpgradeComplete' => 'Aktualizácia je ukončená!',
+ 'CoreUpdater_WarningMessages' => 'Varovania:',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Chyba počas aktualizovania modulov:',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'Automaticky sa deaktivovali tieto moduly: %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik bol úspešne zaktualizovaný!',
+ 'CoreUpdater_ContinueToPiwik' => 'Pokračovať do projektu Piwik',
+ 'Actions_Actions' => 'Akcie',
+ 'Actions_SubmenuPages' => 'Stránky',
+ 'Actions_SubmenuOutlinks' => 'Externé stránky',
+ 'Actions_SubmenuDownloads' => 'Sťahovania',
+ 'Dashboard_Dashboard' => 'Panel',
+ 'Dashboard_AddWidget' => 'Pridať miniaplikáciu…',
+ 'Dashboard_DeleteWidgetConfirm' => 'Ste si istý, že chcete odstrániť miniaplikáciu z panela?',
+ 'Dashboard_SelectWidget' => 'Vyberte miniaplikáciu, ktorá sa pridná na panel',
+ 'Dashboard_AddPreviewedWidget' => 'Pridať zobrazenú miniaplikáciu na panel',
+ 'Dashboard_WidgetPreview' => 'Náhľad miniaplikácie',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Miniaplikácia je už na panely',
+ 'Dashboard_TitleClickToAdd_js' => 'Kliknutím pridáte na panel',
+ 'Dashboard_LoadingPreview_js' => 'Načítavanie náhľadu, prosím čakajte…',
+ 'Dashboard_LoadingWidget_js' => 'Načítavanie miniaplikácie, prosím čakajte…',
+ 'Dashboard_WidgetNotFound_js' => 'Miniaplikácia nebola nájdená',
+ 'Referers_Referers' => 'Odkazy',
+ 'Referers_SearchEngines' => 'Vyhľadávače',
+ 'Referers_Keywords' => 'Kľúčové slová',
+ 'Referers_DirectEntry' => 'Priamy vstup',
+ 'Referers_Websites' => 'Webstránky',
+ 'Referers_Campaigns' => 'Kampane',
+ 'Referers_Evolution' => 'Vývoj za obdobie',
+ 'Referers_Type' => 'Typ odkazu',
+ 'Referers_TypeDirectEntries' => '%s priamych vstupov',
+ 'Referers_TypeSearchEngines' => '%s z vyhľadávačov',
+ 'Referers_TypeWebsites' => '%s zo stránok',
+ 'Referers_TypeCampaigns' => '%s z kampaní',
+ 'Referers_Other' => 'Iné',
+ 'Referers_OtherDistinctSearchEngines' => 'Počet vyhľadávačov: %s',
+ 'Referers_OtherDistinctKeywords' => 'Počet rôznych kľúčových slov: %s',
+ 'Referers_OtherDistinctWebsites' => 'Počet webstránok: %1s (počet rôznych url: %2s )',
+ 'Referers_OtherDistinctCampaigns' => 'Počet rôznych kampaní: %s',
+ 'Referers_TagCloud' => 'Výstup oblaku značiek',
+ 'Referers_SubmenuEvolution' => 'Vývoj',
+ 'Referers_SubmenuSearchEngines' => 'Vyhľadávače a kľúčové slová',
+ 'Referers_SubmenuWebsites' => 'Webstránky',
+ 'Referers_SubmenuCampaigns' => 'Kampane',
+ 'Referers_WidgetKeywords' => 'Zoznam kľúčových stránok',
+ 'Referers_WidgetCampaigns' => 'Zoznam Kampaní',
+ 'Referers_WidgetExternalWebsites' => 'Zoznam externých stránok',
+ 'Referers_WidgetSearchEngines' => 'Najlepšie vyhľadávače',
+ 'Referers_WidgetOverview' => 'Prehľad',
+ 'UserSettings_BrowserFamilies' => 'Rodina prehliadača',
+ 'UserSettings_Browsers' => 'Prehliadače',
+ 'UserSettings_Plugins' => 'Zásuvné moduly',
+ 'UserSettings_Configurations' => 'Konfigurácia',
+ 'UserSettings_OperatinsSystems' => 'Operačný systém',
+ 'UserSettings_Resolutions' => 'Rozlíšenie',
+ 'UserSettings_WideScreen' => 'Širokouhlá obrazovka',
+ 'UserSettings_WidgetResolutions' => 'Rozlíšenie obrazovky',
+ 'UserSettings_WidgetBrowsers' => 'Prehliadače návštevníkov',
+ 'UserSettings_WidgetPlugins' => 'Zoznam modulov',
+ 'UserSettings_WidgetWidescreen' => 'Bežný/Širokouhlý',
+ 'UserSettings_WidgetBrowserFamilies' => 'Prehliadače podľa rodiny',
+ 'UserSettings_WidgetOperatingSystems' => 'Operačné systémy',
+ 'UserSettings_WidgetGlobalVisitors' => 'Globálne konfigurácie návštevníkov',
+ 'UserSettings_SubmenuSettings' => 'Nastavenia',
+ 'UserCountry_Country' => 'Krajina',
+ 'UserCountry_Continent' => 'Kontinent',
+ 'UserCountry_DistinctCountries' => 'Počet rôznych krajín: %s',
+ 'UserCountry_SubmenuLocations' => 'Umiestnenie',
+ 'UserCountry_WidgetContinents' => 'Návštevníci z kontinentov',
+ 'UserCountry_WidgetCountries' => 'Návštevníci z krajín',
+ 'UserCountry_country_ac' => 'Ostrov Ascension',
+ 'UserCountry_country_ad' => 'Andora',
+ 'UserCountry_country_ae' => 'Spojené arabské emiráty',
+ 'UserCountry_country_af' => 'Afganistan',
+ 'UserCountry_country_ag' => 'Antigua a Barbuda',
+ 'UserCountry_country_ai' => 'Anguilla',
+ 'UserCountry_country_al' => 'Albánsko',
+ 'UserCountry_country_am' => 'Arménsko',
+ 'UserCountry_country_an' => 'Holandské Antily',
+ 'UserCountry_country_ao' => 'Angola',
+ 'UserCountry_country_aq' => 'Antarktída',
+ 'UserCountry_country_ar' => 'Argentína',
+ 'UserCountry_country_as' => 'Americká Samoa',
+ 'UserCountry_country_at' => 'Rakúsko',
+ 'UserCountry_country_au' => 'Austrália',
+ 'UserCountry_country_aw' => 'Aruba',
+ 'UserCountry_country_az' => 'Azerbajdžan',
+ 'UserCountry_country_ba' => 'Bosna a Hercegovina',
+ 'UserCountry_country_bb' => 'Barbados',
+ 'UserCountry_country_bd' => 'Bangladéš',
+ 'UserCountry_country_be' => 'Belgicko',
+ 'UserCountry_country_bf' => 'Burkina Faso',
+ 'UserCountry_country_bg' => 'Bulharsko',
+ 'UserCountry_country_bh' => 'Bahrajn',
+ 'UserCountry_country_bi' => 'Burundi',
+ 'UserCountry_country_bj' => 'Benin',
+ 'UserCountry_country_bm' => 'Bermudy',
+ 'UserCountry_country_bn' => 'Bruneo',
+ 'UserCountry_country_bo' => 'Bolívia',
+ 'UserCountry_country_br' => 'Brazília',
+ 'UserCountry_country_bs' => 'Bahamy',
+ 'UserCountry_country_bt' => 'Bhután',
+ 'UserCountry_country_bv' => 'Bouvetov ostrov',
+ 'UserCountry_country_bw' => 'Botswana',
+ 'UserCountry_country_by' => 'Bielorusko',
+ 'UserCountry_country_bz' => 'Belize',
+ 'UserCountry_country_ca' => 'Kanada',
+ 'UserCountry_country_cc' => 'Kokosové ostrovy',
+ 'UserCountry_country_cd' => 'Konžská demokratická republika (býv. Zair)',
+ 'UserCountry_country_cf' => 'Stredoafrická republika',
+ 'UserCountry_country_cg' => 'Kongo',
+ 'UserCountry_country_ch' => 'Švajčiarsko',
+ 'UserCountry_country_ci' => 'Pobrežie Slonoviny',
+ 'UserCountry_country_ck' => 'Cookove ostrovy
+',
+ 'UserCountry_country_cl' => 'Čile',
+ 'UserCountry_country_cm' => 'Kamerun',
+ 'UserCountry_country_cn' => 'Čína',
+ 'UserCountry_country_co' => 'Kolumbia',
+ 'UserCountry_country_cr' => 'Kostarika
+',
+ 'UserCountry_country_cs' => 'Srbsko-Čierna Hora
+',
+ 'UserCountry_country_cu' => 'Kuba',
+ 'UserCountry_country_cv' => 'Kapverdy',
+ 'UserCountry_country_cx' => 'Vianočný ostrov',
+ 'UserCountry_country_cy' => 'Cyprus',
+ 'UserCountry_country_cz' => 'Česká republika',
+ 'UserCountry_country_de' => 'Nemecko',
+ 'UserCountry_country_dj' => 'Džibutsko',
+ 'UserCountry_country_dk' => 'Dánsko',
+ 'UserCountry_country_dm' => 'Dominika',
+ 'UserCountry_country_do' => 'Dominikánska republika',
+ 'UserCountry_country_dz' => 'Alžírsko',
+ 'UserCountry_country_ec' => 'Ekvádor',
+ 'UserCountry_country_ee' => 'Estónsko',
+ 'UserCountry_country_eg' => 'Egypt',
+ 'UserCountry_country_eh' => 'Západná Sahara',
+ 'UserCountry_country_er' => 'Eritrea',
+ 'UserCountry_country_es' => 'Španielsko',
+ 'UserCountry_country_et' => 'Etiópia',
+ 'UserCountry_country_fi' => 'Fínsko',
+ 'UserCountry_country_fj' => 'Fidži',
+ 'UserCountry_country_fk' => 'Falklandy',
+ 'UserCountry_country_fm' => 'Mikronézske federatívne štáty',
+ 'UserCountry_country_fo' => 'Faerské ostrovy',
+ 'UserCountry_country_fr' => 'Francúzsko',
+ 'UserCountry_country_ga' => 'Gabon',
+ 'UserCountry_country_gd' => 'Grenada',
+ 'UserCountry_country_ge' => 'Gruzínsko',
+ 'UserCountry_country_gf' => 'Francúzska Guyana',
+ 'UserCountry_country_gg' => 'Guernsey',
+ 'UserCountry_country_gh' => 'Ghana',
+ 'UserCountry_country_gi' => 'Gibraltár',
+ 'UserCountry_country_gl' => 'Grónsko',
+ 'UserCountry_country_gm' => 'Gambia',
+ 'UserCountry_country_gn' => 'Guinea',
+ 'UserCountry_country_gp' => 'Guadeloupe',
+ 'UserCountry_country_gq' => 'Rovníková Guinea',
+ 'UserCountry_country_gr' => 'Grécko',
+ 'UserCountry_country_gs' => 'Južná Georgia a Južné Sandwichove ostrovy',
+ 'UserCountry_country_gt' => 'Guatemala',
+ 'UserCountry_country_gu' => 'Guam',
+ 'UserCountry_country_gw' => 'Guinea-Bissau',
+ 'UserCountry_country_gy' => 'Guyana',
+ 'UserCountry_country_hk' => 'Hong Kong',
+ 'UserCountry_country_hm' => 'Heardov ostrov',
+ 'UserCountry_country_hn' => 'Honduras',
+ 'UserCountry_country_hr' => 'Chorvátsko',
+ 'UserCountry_country_ht' => 'Haiti',
+ 'UserCountry_country_hu' => 'Maďarsko',
+ 'UserCountry_country_id' => 'Indonézia',
+ 'UserCountry_country_ie' => 'Írsko',
+ 'UserCountry_country_il' => 'Izrael',
+ 'UserCountry_country_im' => 'Man Island',
+ 'UserCountry_country_in' => 'India',
+ 'UserCountry_country_io' => 'Britské indickooceánske územie',
+ 'UserCountry_country_iq' => 'Irak',
+ 'UserCountry_country_ir' => 'Iránska islamská republika',
+ 'UserCountry_country_is' => 'Island
+',
+ 'UserCountry_country_it' => 'Taliansko',
+ 'UserCountry_country_je' => 'Jersey',
+ 'UserCountry_country_jm' => 'Jamajka',
+ 'UserCountry_country_jo' => 'Jordánsko
+',
+ 'UserCountry_country_jp' => 'Japonsko',
+ 'UserCountry_country_ke' => 'Keňa',
+ 'UserCountry_country_kg' => 'Kirgizsko',
+ 'UserCountry_country_kh' => 'Kambodža',
+ 'UserCountry_country_ki' => 'Kiribati',
+ 'UserCountry_country_km' => 'Komory',
+ 'UserCountry_country_kn' => 'Svätý Krištof a Nevis',
+ 'UserCountry_country_kp' => 'Kórejská ľudovodemokratická republika',
+ 'UserCountry_country_kr' => 'Kórejská republika',
+ 'UserCountry_country_kw' => 'Kuvajt',
+ 'UserCountry_country_ky' => 'Kajmanie ostrovy
+',
+ 'UserCountry_country_kz' => 'Kazachstan',
+ 'UserCountry_country_la' => 'Laos',
+ 'UserCountry_country_lb' => 'Libanon',
+ 'UserCountry_country_lc' => 'Svätá Lucia',
+ 'UserCountry_country_li' => 'Lichtenštajnsko',
+ 'UserCountry_country_lk' => 'Srí Lanka',
+ 'UserCountry_country_lr' => 'Libéria',
+ 'UserCountry_country_ls' => 'Lesotho',
+ 'UserCountry_country_lt' => 'Litva',
+ 'UserCountry_country_lu' => 'Luxembursko',
+ 'UserCountry_country_lv' => 'Lotyšsko',
+ 'UserCountry_country_ly' => 'Líbya',
+ 'UserCountry_country_ma' => 'Maroko',
+ 'UserCountry_country_mc' => 'Monako',
+ 'UserCountry_country_md' => 'Moldavská republika',
+ 'UserCountry_country_mg' => 'Madagaskar',
+ 'UserCountry_country_mh' => 'Marshallove ostrovy',
+ 'UserCountry_country_mk' => 'Macedónsko',
+ 'UserCountry_country_ml' => 'Mali',
+ 'UserCountry_country_mm' => 'Mjanmarsko',
+ 'UserCountry_country_mn' => 'Mongolsko',
+ 'UserCountry_country_mo' => 'Macau',
+ 'UserCountry_country_mp' => 'Severné Mariány',
+ 'UserCountry_country_mq' => 'Martinik',
+ 'UserCountry_country_mr' => 'Mauritánia',
+ 'UserCountry_country_ms' => 'Montserrat',
+ 'UserCountry_country_mt' => 'Malta',
+ 'UserCountry_country_mu' => 'Maurícius',
+ 'UserCountry_country_mv' => 'Maldivy',
+ 'UserCountry_country_mw' => 'Malawi',
+ 'UserCountry_country_mx' => 'Mexiko',
+ 'UserCountry_country_my' => 'Malajzia',
+ 'UserCountry_country_mz' => 'Mozambik',
+ 'UserCountry_country_na' => 'Namíbia',
+ 'UserCountry_country_nc' => 'Nová Kaledónia',
+ 'UserCountry_country_ne' => 'Niger',
+ 'UserCountry_country_nf' => 'Norfolk',
+ 'UserCountry_country_ng' => 'Nigéria',
+ 'UserCountry_country_ni' => 'Nikaragua',
+ 'UserCountry_country_nl' => 'Holandsko',
+ 'UserCountry_country_no' => 'Nórsko',
+ 'UserCountry_country_np' => 'Nepál',
+ 'UserCountry_country_nr' => 'Nauru',
+ 'UserCountry_country_nu' => 'Niue',
+ 'UserCountry_country_nz' => 'Nový Zéland',
+ 'UserCountry_country_om' => 'Oman',
+ 'UserCountry_country_pa' => 'Panama',
+ 'UserCountry_country_pe' => 'Peru',
+ 'UserCountry_country_pf' => 'Francúzska Polynézia',
+ 'UserCountry_country_pg' => 'Papua Nová Guinea',
+ 'UserCountry_country_ph' => 'Filipíny',
+ 'UserCountry_country_pk' => 'Pakistan',
+ 'UserCountry_country_pl' => 'Poľsko',
+ 'UserCountry_country_pm' => 'Saint Pierre a Miquelon',
+ 'UserCountry_country_pn' => 'Pitcairnove ostrovy',
+ 'UserCountry_country_pr' => 'Portoriko',
+ 'UserCountry_country_ps' => 'Palestína',
+ 'UserCountry_country_pt' => 'Portugalsko',
+ 'UserCountry_country_pw' => 'Palau',
+ 'UserCountry_country_py' => 'Paraguaj',
+ 'UserCountry_country_qa' => 'Katar',
+ 'UserCountry_country_re' => 'Réunion',
+ 'UserCountry_country_ro' => 'Rumunsko',
+ 'UserCountry_country_ru' => 'Rusko',
+ 'UserCountry_country_rs' => 'Srbsko',
+ 'UserCountry_country_rw' => 'Rwanda',
+ 'UserCountry_country_sa' => 'Saudská Arábia',
+ 'UserCountry_country_sb' => 'Šalamúnove ostrovy',
+ 'UserCountry_country_sc' => 'Seychely',
+ 'UserCountry_country_sd' => 'Sudán',
+ 'UserCountry_country_se' => 'Švédsko',
+ 'UserCountry_country_sg' => 'Singapur',
+ 'UserCountry_country_sh' => 'Svätá Helena',
+ 'UserCountry_country_si' => 'Slovinsko',
+ 'UserCountry_country_sj' => 'Svalbard Jan Mayen',
+ 'UserCountry_country_sk' => 'Slovensko',
+ 'UserCountry_country_sl' => 'Sierra Leone',
+ 'UserCountry_country_sm' => 'San Maríno',
+ 'UserCountry_country_sn' => 'Senegal',
+ 'UserCountry_country_so' => 'Somálsko',
+ 'UserCountry_country_sr' => 'Suriname',
+ 'UserCountry_country_st' => 'Svätý Tomáš a Princov ostrov',
+ 'UserCountry_country_su' => 'Bývalé ZSSR',
+ 'UserCountry_country_sv' => 'Salvádor',
+ 'UserCountry_country_sy' => 'Sýria',
+ 'UserCountry_country_sz' => 'Svazijsko',
+ 'UserCountry_country_tc' => 'Turks a Caicos',
+ 'UserCountry_country_td' => 'Čad',
+ 'UserCountry_country_tf' => 'Francúzske južné územia',
+ 'UserCountry_country_tg' => 'Togo',
+ 'UserCountry_country_th' => 'Thajsko',
+ 'UserCountry_country_tj' => 'Tadžikistan',
+ 'UserCountry_country_tk' => 'Tokelau',
+ 'UserCountry_country_tm' => 'Turkménsko',
+ 'UserCountry_country_tn' => 'Tunis',
+ 'UserCountry_country_to' => 'Tonga',
+ 'UserCountry_country_tp' => 'Východný Timor',
+ 'UserCountry_country_tr' => 'Turecko',
+ 'UserCountry_country_tt' => 'Trinidad a Tobago',
+ 'UserCountry_country_tv' => 'Tuvalu',
+ 'UserCountry_country_tw' => 'Taiwan',
+ 'UserCountry_country_tz' => 'Tanzánijská zjednotená republika',
+ 'UserCountry_country_ua' => 'Ukrajina',
+ 'UserCountry_country_ug' => 'Uganda',
+ 'UserCountry_country_uk' => 'Spojené Kráľovstvo',
+ 'UserCountry_country_gb' => 'Veľká Británia',
+ 'UserCountry_country_um' => 'Menšie odľahlé ostrovy USA',
+ 'UserCountry_country_us' => 'Spojené štáty',
+ 'UserCountry_country_uy' => 'Uruguaj',
+ 'UserCountry_country_uz' => 'Uzbekistan',
+ 'UserCountry_country_va' => 'Vatikán',
+ 'UserCountry_country_vc' => 'Svätý Vincent a Grenadíny',
+ 'UserCountry_country_ve' => 'Venezuela',
+ 'UserCountry_country_vg' => 'Britské Panenské ostrovy',
+ 'UserCountry_country_vi' => 'Americké panenské ostrovy',
+ 'UserCountry_country_vn' => 'Vietnam',
+ 'UserCountry_country_vu' => 'Vanuatu',
+ 'UserCountry_country_wf' => 'Wallis a Futuna',
+ 'UserCountry_country_ws' => 'Samoa',
+ 'UserCountry_country_ye' => 'Jemen',
+ 'UserCountry_country_yt' => 'Mayotte',
+ 'UserCountry_country_yu' => 'Juhoslávia',
+ 'UserCountry_country_za' => 'Južná Afrika',
+ 'UserCountry_country_zm' => 'Zambia',
+ 'UserCountry_country_zr' => 'Zair',
+ 'UserCountry_country_zw' => 'Zimbabwe',
+ 'UserCountry_continent_eur' => 'Európa',
+ 'UserCountry_continent_afr' => 'Afrika',
+ 'UserCountry_continent_asi' => 'Ázia',
+ 'UserCountry_continent_ams' => 'Stredná a Južná Amerika',
+ 'UserCountry_continent_amn' => 'Severná Amerika',
+ 'UserCountry_continent_oce' => 'Oceánia',
+ 'VisitsSummary_NbVisits' => 'Počet návštev: %s',
+ 'VisitsSummary_NbUniqueVisitors' => 'Počet unikátnych návštevníkov: %s',
+ 'VisitsSummary_NbActions' => 'Počet akcií (zobrazení stránok): %s',
+ 'VisitsSummary_TotalTime' => 'Celkový čas strávený návštevníkmi: %s',
+ 'VisitsSummary_MaxNbActions' => 'Max. akcií na jednu návštevu: %s',
+ 'VisitsSummary_NbBounced' => 'Počet odskočených návštevníkov: %s (odišli po zobrazení jednej strany)',
+ 'VisitsSummary_Evolution' => 'Vývoj za posledných 30 %ss',
+ 'VisitsSummary_Report' => 'Správa',
+ 'VisitsSummary_GenerateTime' => '%s sekúnd na vygenerovanie strany',
+ 'VisitsSummary_GenerateQueries' => 'spustené požiadavky: %s',
+ 'VisitsSummary_WidgetLastVisits' => 'Graf posledných návštev',
+ 'VisitsSummary_WidgetVisits' => 'Prehľad návštevníkov',
+ 'VisitsSummary_WidgetLastVisitors' => 'Graf posledných jedinečných návštevníkov',
+ 'VisitsSummary_WidgetOverviewGraph' => 'Prehľad s grafom',
+ 'VisitsSummary_SubmenuOverview' => 'Prehľad',
+ 'VisitFrequency_Evolution' => 'Vývoj za obdobie',
+ 'VisitFrequency_ReturnVisits' => 'počet vracajúcich sa: %s ',
+ 'VisitFrequency_ReturnActions' => 'počet akcií vracajúcich sa: %s',
+ 'VisitFrequency_ReturnMaxActions' => 'maximum akcií vracajúcich sa: %s',
+ 'VisitFrequency_ReturnTotalTime' => 'celkový čas strávený vracajúcimi sa návštevníkmi: %s ',
+ 'VisitFrequency_ReturnBounces' => 'počet odskočení (odídenie po zobrazení jednej stránky) vracajúcich sa: %s',
+ 'VisitFrequency_WidgetOverview' => 'Prehľad frekvencií',
+ 'VisitFrequency_WidgetGraphReturning' => 'Graf vracajúcich sa',
+ 'VisitFrequency_SubmenuFrequency' => 'Frekvencia',
+ 'VisitTime_LocalTime' => 'Návštevníci podľa lokálneho času',
+ 'VisitTime_ServerTime' => 'Návštevníci podľa serverového času',
+ 'VisitTime_WidgetLocalTime' => 'Návštevníci podľa lokálneho času',
+ 'VisitTime_WidgetServerTime' => 'Návštevníci podľa serverového času',
+ 'VisitTime_SubmenuTimes' => 'Časy',
+ 'VisitTime_NHour' => '%sh',
+ 'VisitorInterest_VisitsPerDuration' => 'Návštevy podľa dĺžky trvania návštevy',
+ 'VisitorInterest_VisitsPerNbOfPages' => 'Návštevy na počet stránok',
+ 'VisitorInterest_WidgetLengths' => 'Trvanie návštev',
+ 'VisitorInterest_WidgetPages' => 'Strany na návštevu',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Frekvencia & Lojalita',
+ 'VisitorInterest_PlusXMin' => '%s min',
+ 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
+ 'VisitorInterest_OnePage' => '1 stránka',
+ 'VisitorInterest_NPages' => '%s stránok',
+ 'VisitorInterest_BetweenXYSeconds' => '%1s-%2ss',
+ 'Login_LoginPasswordNotCorrect' => 'Meno používateľa a heslo nie sú správne',
+ 'Login_Login' => 'Meno používateľa',
+ 'Login_Password' => 'Heslo',
+ 'Login_LoginOrEmail' => 'Prihlasovací údaj (Login) alebo e-mail',
+ 'Login_LogIn' => 'Prihlásiť sa',
+ 'Login_Logout' => 'Odhlásiť sa',
+ 'Login_LostYourPassword' => 'Zabudli ste heslo?',
+ 'Login_RemindPassword' => 'Pripomenúť heslo',
+ 'Login_PasswordReminder' => 'Vložte prosím svoje meno používateľa alebo e-mailovú adresu. E-mailom Vám bude doručené nové heslo.',
+ 'Login_InvalidUsernameEmail' => 'Neplatné meno používateľa alebo e-mailová adresa',
+ 'Login_MailTopicPasswordRecovery' => 'Obnova hesla',
+ 'Login_MailPasswordRecoveryBody' => 'Ahoj %1s, \n\n Tvoje nové heslo je: %2s \n\n Teraz sa môžeš prihlásiť: %3s',
+ 'Login_PasswordSent' => 'Heslo bolo práve odoslané. Skontrolujte si e-mail.',
+ 'Login_ContactAdmin' => 'Možné dôvody: Váš server ma zakázanú funkciu mail().<br /> Skontaktujte svojho administrátora Piwik.',
+ 'UsersManager_UsersManagement' => 'Správa používateľov',
+ 'UsersManager_UsersManagementMainDescription' => 'Vytvorenie nových alebo aktualizácia existujúcich používateľov V sekcií vyššie im môžete nastaviť rozsah prístupov.',
+ 'UsersManager_ManageAccess' => 'Správa prístupov',
+ 'UsersManager_MainDescription' => 'Rozhodnite sa, ktorí používatelia budú môcť pristupovať k jednotlivým stránkam. Tiež im môžete umožniť prístup na všetky vaše stránky.',
+ 'UsersManager_Sites' => 'Webstránky',
+ 'UsersManager_AllWebsites' => 'Všetky webstránky',
+ 'UsersManager_ApplyToAllWebsites' => 'Použiť na všetky webstránky',
+ 'UsersManager_User' => 'Používatelia',
+ 'UsersManager_PrivNone' => 'Bez prístupu',
+ 'UsersManager_PrivView' => 'Prezeranie',
+ 'UsersManager_PrivAdmin' => 'Admin',
+ 'UsersManager_ChangeAllConfirm' => 'Ste si istý, že chcete zmeniť \'%s\' práva pre všetky webstránky?',
+ 'UsersManager_Login' => 'Používateľ',
+ 'UsersManager_Password' => 'Heslo',
+ 'UsersManager_Email' => 'E-mail',
+ 'UsersManager_Alias' => 'Alias',
+ 'UsersManager_Token' => 'token_auth',
+ 'UsersManager_Edit' => 'Upraviť',
+ 'UsersManager_AddUser' => 'Pridať nového používateľa',
+ 'UsersManager_MenuUsers' => 'Používatelia',
+ 'UsersManager_DeleteConfirm_js' => 'Ste si istý, že chcete odstrániť používateľa %s?',
+ 'UsersManager_ExceptionLoginExists' => 'Používateľ (login) \'%s\' už existuje.',
+ 'UsersManager_ExceptionEmailExists' => 'Používateľ s e-mailom \'%s\' už existuje.',
+ 'UsersManager_ExceptionInvalidLogin' => 'Používateľské meno (login) môže obsahovať iba písmen, číslice a znaky \'_\' alebo \'-\' alebo \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'Dĺžka hesla musí byť od 6 do 26 znakov.',
+ 'UsersManager_ExceptionInvalidEmail' => 'E-mailová adresa nemá platný formát.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'Používateľ \'%s\' neexistuje a preto nemôže byť odstránený.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'Nemôžete priradiť prístup \'admin\' pre používateľa \'anonymous\'.',
+ 'UsersManager_ExceptionEditAnonymous' => 'Anonymný používateľ nemôže byť odstránený alebo upravený. Piwik ho používa na definovanie používateľa, ktorý sa ešte prihlásil. Anonymného používateľa môžete použiť na zverejnenie svojich štatistík, a to priradeným mu práv na prezeranie.',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'Používateľ \'%s\' neexistuje.',
+ 'UsersManager_ExceptionAccessValues' => 'Parameter prístupu musí mať jednu z nasledujúcich hodnôt : [ %s ]',
+ 'SitesManager_Sites' => 'Stránky',
+ 'SitesManager_WebsitesManagement' => 'Správa webstránok',
+ 'SitesManager_MainDescription' => 'Váš report analýzy webu potrebuje webstránky! Tu si pridajte, aktualizujte, odstráňte webstránky alebo zobrazte Javascript kód pre vaše stránky.',
+ 'SitesManager_JsCode' => 'Javascript kód',
+ 'SitesManager_JsCodeHelp' => 'Tu je javascript kód, ktorý potrebujete vložiť do vašich stránok',
+ 'SitesManager_ShowJsCode' => 'Zobraziť kód',
+ 'SitesManager_NoWebsites' => 'Nemáte webstránky na administrovanie.',
+ 'SitesManager_AddSite' => 'Pridať novú stránku',
+ 'SitesManager_Id' => 'Id',
+ 'SitesManager_Name' => 'Názov',
+ 'SitesManager_Urls' => 'URL',
+ 'SitesManager_MenuSites' => 'Stránky',
+ 'SitesManager_DeleteConfirm_js' => 'Ste si istý, že chcete zmazať webstránku %s?',
+ 'SitesManager_ExceptionDeleteSite' => 'Nie je možné odstrániť webstránku, pretože je jediná registrovaná webstránka. Najskôr pridajte novú webstránka a potom môžete odstrániť túto.',
+ 'SitesManager_ExceptionNoUrl' => 'Musíte zadať aspoň jednu URL pre stránku.',
+ 'SitesManager_ExceptionEmptyName' => 'Názov stránok nemôže byť prázdny.',
+ 'SitesManager_ExceptionInvalidUrl' => 'Url \'%s\' nie je platná URL.',
+ 'Installation_Installation' => 'Inštalácia',
+ 'Installation_InstallationStatus' => 'Stav inštalácie',
+ 'Installation_PercentDone' => '%s %% Dokončené',
+ 'Installation_NoConfigFound' => 'Piwik konfiguračný súbor nie je možné nájsť a vy sa pokúšate pripojiť k Piwik stránke. <br /><b>&nbsp;&nbsp;&raquo; Môžete <a href=\'index.php\'>teraz nainštalovať Piwik</a></b><br /><small>Ak ste nainštalovali Piwik už skôr, a máte nejaké tabuľky s dátami v databáze, nemusíte sa báť, budete ich ďalej používať!</small>',
+ 'Installation_MysqlSetup' => 'Nastavenie Mysql databázy',
+ 'Installation_MysqlErrorConnect' => 'Vyskytla sa chyba počas testu pripojenia k Mysql databáze',
+ 'Installation_JsTag' => 'Javascript značka',
+ 'Installation_JsTagHelp' => '<p>Na spočítanie všetkých vašich návštevníkov musíte vložiť do svojich stránok javascript kód.</p><p>Vaše stránky nemusia byť vytvorené v PHP, Piwik bude fungovať na všetkých typoch stránok (či už to bude HTML, ASP, Perl alebo iný jazyk).</p><p>Tu je kód, ktorý musíte použiť: (skopírujte a vložte ho do svojich stránok)</p>',
+ 'Installation_Congratulations' => 'Blahoželanie',
+ 'Installation_CongratulationsHelp' => '<p>Blahoželáme Vám! Inštalácia Piwik je dokončená.</p><p>Uistite sa, že Váš javascript kód je vložený od Vašich stránok a počkajte si na prvých návštevníkov!</p>',
+ 'Installation_ContinueToPiwik' => 'Pokračovať do Piwik',
+ 'Installation_SetupWebsite' => 'Nastavenie webstránky',
+ 'Installation_SetupWebsiteError' => 'Vyskytla sa chyba pridávaní webstránky',
+ 'Installation_GeneralSetup' => 'Všeobecné nastavenia',
+ 'Installation_GeneralSetupSuccess' => 'Všeobecné nastavenia boli úspešne nastavené.',
+ 'Installation_SystemCheck' => 'Kontrola systému',
+ 'Installation_SystemCheckPhp' => 'PHP verzia',
+ 'Installation_SystemCheckPdo' => 'Pdo rozšírenie',
+ 'Installation_SystemCheckPdoMysql' => 'Pdo_Mysql rozšírenie',
+ 'Installation_SystemCheckPdoError' => 'Musíte povoliť PDO a PDO_MYSQL rozšírenie vo svojom php.ini súbore.',
+ 'Installation_SystemCheckPdoHelp' => 'Na Windows servery môžete pridať nasledovné riadky do svojho php.ini %s <br /><br />Na Linux servery môžete skompilovať php s nasledujúcimi voľbami %s Do svojom php.ini pridajte nasledovné riadky %s<br /><br />Viac informácií nájdete na <a style="color:red" href="http://php.net/pdo">stránkach PHP</a>.',
+ 'Installation_SystemCheckWriteDirs' => 'Priečinky s prístupom na zápis',
+ 'Installation_SystemCheckWriteDirsHelp' => 'Na vyriešenie problém v Linuxe skúste napísať nasledovné príkazy',
+ 'Installation_SystemCheckMemoryLimit' => 'Pamäťový limit',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'Na webstránkach s vysokou premávkou archivačný proces bude vyžadovať viac pamäte, než je to aktuálne povolené.<br /> Pozrite si direktívu memory_limit vo vašom php.ini súbore, ak je to potrebné.',
+ 'Installation_SystemCheckGD' => 'GD &gt; 2.x (grafika)',
+ 'Installation_SystemCheckGDHelp' => '„Sparklines“ (malé grafy) nebudú fungovať.',
+ 'Installation_SystemCheckTimeLimit' => 'set_time_limit() je povolené',
+ 'Installation_SystemCheckTimeLimitHelp' => 'Na webstránkach s vysokou premávkou bude spúšťanie archivačného procesu trvať dlhšie, než je to aktuálne povolené.<br /> Pozrite si direktívu max_execution_time vo vašom php.ini súbore, ak je to potrebné.',
+ 'Installation_SystemCheckMail' => 'mail() je povolené',
+ 'Installation_SystemCheckError' => 'Vyskytla sa chyba - musíte ju vyriešiť, inak nie je možné pokračovať',
+ 'Installation_SystemCheckWarning' => 'Piwik bude fungovať normálne, ale niektoré vlastnosti budú chýbať.',
+ 'Installation_Tables' => 'Vytváranie tabuliek',
+ 'Installation_TablesWarning' => 'Niektoré <span id="linkToggle">Piwik tabuľky</span> už existujú v databáze',
+ 'Installation_TablesFound' => 'Nasledujúce tabuľky boli nájdené.',
+ 'Installation_TablesWarningHelp' => 'Vyberte si použitie už existujúcich tabuliek alebo výber čistej inštalácie s vymazaním všetkých existujúcich dát v databáze.',
+ 'Installation_TablesReuse' => 'Znovu použiť existujúce tabuľky',
+ 'Installation_TablesDelete' => 'zmazanie delegovaných tabuliek',
+ 'Installation_TablesDeletedSuccess' => 'Existujúce Piwik tabuľky boli úspešne zmazané',
+ 'Installation_TablesCreatedSuccess' => 'Tabuľky boli úspešne vytvorené!',
+ 'Installation_DatabaseCreatedSuccess' => 'Vytvorenie databázy %s prebehlo úspešne!',
+ 'Installation_TablesDeleteConfirm' => 'Ste si istý, že chcete zmazať všetky Piwik tabuľky v databáze?',
+ 'Installation_Welcome' => 'Vitajte!',
+ 'Installation_WelcomeHelp' => '<p>Piwik je open source projekt analýzy webstránok, ktorý zjednodušuje získavanie informácií o Vašich návštevníkoch.</p><p>Tento proces je rozdelený do %s jednoduchých krokov a bude trvať asi 5 minút.</p>',
+ 'Provider_WidgetProviders' => 'Poskytovatelia',
+ 'Provider_SubmenuLocationsProvider' => 'Umiestnenie & poskytovateľ',
+ 'DBStats_DatabaseUsage' => 'Využitie databázy',
+ 'DBStats_MainDescription' => 'Piwik ukladá všetky vaše web analýzy do Mysql databázy. Aktuálne Piwik tabuľky používajú %s.',
+ 'DBStats_Table' => 'Tabuľka',
+ 'DBStats_RowNumber' => 'Počet riadkov',
+ 'DBStats_DataSize' => 'Veľkosť dát',
+ 'DBStats_IndexSize' => 'Veľkosť indexu',
+ 'TranslationsAdmin_MenuTranslations' => 'Preklady',
+ 'TranslationsAdmin_MenuLanguages' => 'Jazyky',
+ 'TranslationsAdmin_Plugin' => 'Modul',
+ 'TranslationsAdmin_Definition' => 'Definícia',
+ 'TranslationsAdmin_DefaultString' => 'Štandardný reťazec (Anglicky)',
+ 'TranslationsAdmin_TranslationString' => 'Preklad (aktuálny jazyk: %s)',
+ 'TranslationsAdmin_Translations' => 'Preklady',
+ 'TranslationsAdmin_FixPermissions' => 'Prosím vyriešte problém s nastavením prístupu v súborovom systéme',
+ 'TranslationsAdmin_AvailableLanguages' => 'Dostupné jazyky',
+ 'TranslationsAdmin_AddLanguage' => 'Pridať jazyk',
+ 'TranslationsAdmin_LanguageCode' => 'Kód jazyka',
+ 'TranslationsAdmin_Export' => 'Exportovať jazyk',
+ 'TranslationsAdmin_Import' => 'Importovať jazyk',
+); \ No newline at end of file
diff --git a/lang/sr.php b/lang/sr.php
new file mode 100644
index 0000000000..a9b2f16101
--- /dev/null
+++ b/lang/sr.php
@@ -0,0 +1,615 @@
+<?php
+
+setlocale(LC_TIME, 'sr_RS.UTF-8');
+
+$translations = array(
+ 'General_Locale' => 'sr_RS.UTF-8',
+ 'General_TranslatorName' => 'Petar Benke',
+ 'General_TranslatorEmail' => 'petar@benke.co.uk',
+ 'General_EnglishLanguageName' => 'Serbian',
+ 'General_OriginalLanguageName' => 'Srpski',
+ 'General_Unknown' => 'Nepoznato',
+ 'General_Required' => '%s potrebno',
+ 'General_Error' => 'Greška',
+ 'General_Warning' => 'Upozorenje',
+ 'General_BackToHomepage' => 'Natrag na Piwik početnu stranu',
+ 'General_Yes' => 'Da',
+ 'General_No' => 'Ne',
+ 'General_Delete' => 'Brisanje',
+ 'General_Edit' => 'Izmena',
+ 'General_Ok' => 'Potvrda',
+ 'General_Close' => 'Zatvori',
+ 'General_Logout' => 'Odjava',
+ 'General_Done' => 'Izvršeno',
+ 'General_LoadingData' => 'Učitavanje podataka...',
+ 'General_ErrorRequest' => 'Ups&hellip; problem s zahtevom, pokušajte ponovo',
+ 'General_Next' => 'Sledeća',
+ 'General_Previous' => 'Prethodna',
+ 'General_Search' => 'Pretraga',
+ 'General_Others' => 'Ostalo',
+ 'General_Table' => 'Tabela',
+ 'General_Piechart' => 'Pita',
+ 'General_TagCloud' => 'Oblak tagova',
+ 'General_VBarGraph' => 'Stubičasti dijagram',
+ 'General_Export' => 'Izvoz',
+ 'General_Refresh' => 'Osvežavanje prikaza',
+ 'General_Visitors' => 'Posetioci',
+ 'General_ColumnNbUniqVisitors' => 'Broj jedinstvenih posetilaca',
+ 'General_ColumnNbVisits' => 'Poseta',
+ 'General_ColumnLabel' => 'Kategorija',
+ 'General_ColumnActionsPerVisit' => 'Akcije po poseti',
+ 'General_ColumnAvgTimeOnSite' => 'Prosečno provedeno vreme',
+ 'General_ColumnBounceRate' => 'Bounce stopa',
+ 'General_Save' => 'Snimanje',
+ 'General_Website' => 'Sajt',
+ 'General_NoDataForGraph' => 'Nema podataka za ovaj grafikon',
+ 'General_NoDataForTagCloud' => 'Nema podataka za ovaj oblak tagova',
+ 'General_PiwikIsACollaborativeProject' => '%s Piwik %s je projekat koji se još uvek nalazi u fazi razvoja. %s Ukoliko želite da date svoj doprinos molimo vas da nas %s kontaktirate%s.',
+ 'Dashboard_Dashboard' => 'Konzola',
+ 'Dashboard_AddWidget' => 'Dodavanje elementa...',
+ 'Dashboard_DeleteWidgetConfirm' => 'Da li ste sigurni da želite da uklonite ovaj element sa Konzole?',
+ 'Dashboard_SelectWidget' => 'Izaberite element koji želite da dodate na Konzolu',
+ 'Dashboard_AddPreviewedWidget' => 'Dodavanje prikazanog elementa na Konzolu',
+ 'Dashboard_WidgetPreview' => 'Prikaz elementa',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Element se već nalazi na Konzoli',
+ 'Dashboard_TitleClickToAdd_js' => 'Kliknite kako biste dodali element na Konzolu',
+ 'Dashboard_LoadingPreview_js' => 'Učitavanje prikaza, molimo sačekajte...',
+ 'Dashboard_LoadingWidget_js' => 'Učitavanje elementa, molimo sačekajte...',
+ 'Dashboard_WidgetNotFound_js' => 'Element nije nađen',
+ 'Login_LoginPasswordNotCorrect' => 'Korisničko ime i lozinka ne odgovaraju',
+ 'Login_Login' => 'Korisničko ime',
+ 'Login_Password' => 'Lozinka',
+ 'Login_LoginOrEmail' => 'Korisničko ime ili elektronska adresa',
+ 'Login_LogIn' => 'Prijavljivanje',
+ 'Login_Logout' => 'Odjavljivanje',
+ 'Login_LostYourPassword' => 'Zaboravili ste lozinku?',
+ 'Login_RemindPassword' => 'Podsetnik za lozinku',
+ 'Login_PasswordReminder' => 'Molimo vas da upišete vaše korisničko ime ili elektronsku adresu. Novu lozinku ćete dobiti elektronskom poštom.',
+ 'Login_InvalidUsernameEmail' => 'Pogrešno korisničko ime i/ili elektronska adresa',
+ 'Login_MailTopicPasswordRecovery' => 'Oporavak lozinke',
+ 'Login_MailPasswordRecoveryBody' => 'Pozdrav %1s \n\n Vaša nova lozinka je: %2s \n\n Sada se možete prijaviti na: %3s',
+ 'Login_PasswordSent' => 'Lozinka vam je poslata. Proverite vašu elektronsku poštu.',
+ 'Login_ContactAdmin' => 'Mogući razlog: vaš hosting partner je možda onemogućio mail() funkciju. <br />Molimo vas da kontaktirate vašeg Piwik administratora.',
+ 'VisitsSummary_NbVisits' => 'Broj poseta: %s',
+ 'VisitsSummary_NbUniqueVisitors' => 'Broj jedinstvenih posetilaca: %s',
+ 'VisitsSummary_NbActions' => 'Broj akcija (prikaza stranica): %s',
+ 'VisitsSummary_TotalTime' => 'Ukupno provedeno vreme posetilaca: %s',
+ 'VisitsSummary_MaxNbActions' => 'Maksimum akcija u jednoj poseti: %s',
+ 'VisitsSummary_NbBounced' => 'Broj posetilaca koji su odmah napustili sajt: %s',
+ 'VisitsSummary_Evolution' => '30 %s trend',
+ 'VisitsSummary_Report' => 'Izveštaj',
+ 'VisitsSummary_GenerateTime' => 'Vreme generisanja izveštaja u sekundama: %s',
+ 'VisitsSummary_GenerateQueries' => 'Izvršeno upita: %s',
+ 'VisitsSummary_WidgetLastVisits' => 'Grafikon najskorijih poseta',
+ 'VisitsSummary_WidgetVisits' => 'Pregled poseta',
+ 'VisitsSummary_WidgetLastVisitors' => 'Grafikon najskorijih jedinstvenih posetilaca',
+ 'VisitsSummary_WidgetOverviewGraph' => 'Pregled sa grafikonom',
+ 'VisitsSummary_SubmenuOverview' => 'Pregled',
+ 'VisitorInterest_VisitsPerDuration' => 'Broj poseta po dužini zadržavanja',
+ 'VisitorInterest_VisitsPerNbOfPages' => 'Broj poseta po broju stranica',
+ 'VisitorInterest_WidgetLengths' => 'Dužine poseta',
+ 'VisitorInterest_WidgetPages' => 'Broj stranica po poseti',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Učestalost i odanost',
+ 'VisitorInterest_PlusXMin' => '%s min',
+ 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
+ 'VisitorInterest_OnePage' => '1 stranica',
+ 'VisitorInterest_NPages' => '%s stranica',
+ 'VisitorInterest_BetweenXYSeconds' => '%1s-%2s sek',
+ 'VisitTime_LocalTime' => 'Broj poseta po lokalnom vremenu',
+ 'VisitTime_ServerTime' => 'Broj poseta po serverskom vremenu',
+ 'VisitTime_WidgetLocalTime' => 'Broj poseta po lokalnom vremenu',
+ 'VisitTime_WidgetServerTime' => 'Broj poseta po serverskom vremenu',
+ 'VisitTime_SubmenuTimes' => 'Vreme',
+ 'VisitTime_NHour' => '%s',
+ 'VisitFrequency_Evolution' => 'Trend za period',
+ 'VisitFrequency_ReturnVisits' => 'Broj ponovnih poseta: %s',
+ 'VisitFrequency_ReturnActions' => 'Broj akcija od strane ponovnih poseta: %s',
+ 'VisitFrequency_ReturnMaxActions' => 'Maksimum akcija od strane ponovnih poseta: %s',
+ 'VisitFrequency_ReturnTotalTime' => 'Ukupno provedeno vreme od strane ponovnih poseta: %s',
+ 'VisitFrequency_ReturnBounces' => 'Broj ponovnih posetilaca koji su odmah napustili sajt: %s',
+ 'VisitFrequency_WidgetOverview' => 'Pregled učestalosti',
+ 'VisitFrequency_WidgetGraphReturning' => 'Grafikon ponovnih poseta',
+ 'VisitFrequency_SubmenuFrequency' => 'Učestalost',
+ 'UsersManager_UsersManagement' => 'Upravljanje korisnicima',
+ 'UsersManager_UsersManagementMainDescription' => 'Dodavanje novih i obrada postojećih korisničkih naloga. Dodeljivanje privilegija.',
+ 'UsersManager_ManageAccess' => 'Kontrola pristupa',
+ 'UsersManager_MainDescription' => 'Određivanje koji korisnici imaju Piwik pristup sajtovima.',
+ 'UsersManager_Sites' => 'Sajtovi',
+ 'UsersManager_AllWebsites' => 'Svi sajtovi',
+ 'UsersManager_ApplyToAllWebsites' => 'Primeni na sve sajtove',
+ 'UsersManager_User' => 'Korisnik',
+ 'UsersManager_PrivNone' => 'Nema pristup',
+ 'UsersManager_PrivView' => 'Prikaz',
+ 'UsersManager_PrivAdmin' => 'Administracija',
+ 'UsersManager_ChangeAllConfirm' => 'Da li ste sigurni da želite da izmenite \'%s\' privilegije na svim sajtovima?',
+ 'UsersManager_Login' => 'Korisničko ime',
+ 'UsersManager_Password' => 'Lozinka',
+ 'UsersManager_Email' => 'Elektronska adresa',
+ 'UsersManager_Alias' => 'Alias',
+ 'UsersManager_Token' => 'Token',
+ 'UsersManager_Edit' => 'Izmena',
+ 'UsersManager_AddUser' => 'Dodavanje novog korisnika',
+ 'UsersManager_MenuUsers' => 'Korisnici',
+ 'UsersManager_DeleteConfirm_js' => 'Da li ste sigurni da želite da obrišete korisnika %s?',
+ 'UsersManager_ExceptionLoginExists' => 'Korisničko ime \'%s\' već postoji.',
+ 'UsersManager_ExceptionEmailExists' => 'Korisnik sa elektronskom adresom \'%s\' već postoji.',
+ 'UsersManager_ExceptionInvalidLogin' => 'Korisničko ime se može sastojati samo od slova, brojeva i znakova \'_\', \'-\' i \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'Dužina lozinke mora biti između 6 i 26 znakova.',
+ 'UsersManager_ExceptionInvalidEmail' => 'Elektronska adresa nije validna.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'Korisnik \'%s\' ne postoji pa stoga ni ne može biti obrisan.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'Ne možete dozvoliti \'admin\' privilegije anonimnom korisniku.',
+ 'UsersManager_ExceptionEditAnonymous' => 'Podaci o anonimnom korisniku ne mogu biti menjani ili obrisani. Anonimni korisnik služi da bi Piwik mogao da razlikuje korisnika koji se još nije prijavio na sistem. Primera radi, svoju statistiku možete učiniti javnom tako što ćete anonimnom korisniku dozvoliti \'prikaz\' pristup.',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'Korisnik \'%s\' ne postoji.',
+ 'UsersManager_ExceptionAccessValues' => 'Parametar pristupa mora da ima jednu od sledećih vrednosti: [ %s ]',
+ 'UserSettings_BrowserFamilies' => 'Klase Internet čitača',
+ 'UserSettings_Browsers' => 'Internet čitači',
+ 'UserSettings_Plugins' => 'Instalirani dodaci Internet čitača',
+ 'UserSettings_Configurations' => 'Globalne karakteristike',
+ 'UserSettings_OperatinsSystems' => 'Operativni sistemi',
+ 'UserSettings_Resolutions' => 'Ekranske rezolucije',
+ 'UserSettings_WideScreen' => 'Odnos stranica ekrana',
+ 'UserSettings_WidgetResolutions' => 'Ekranske rezolucije',
+ 'UserSettings_WidgetBrowsers' => 'Korisnički Internet čitači',
+ 'UserSettings_WidgetPlugins' => 'Lista dodataka Internet čitača',
+ 'UserSettings_WidgetWidescreen' => 'Nromalan/široki ekran',
+ 'UserSettings_WidgetBrowserFamilies' => 'Internet čitači po klasama',
+ 'UserSettings_WidgetOperatingSystems' => 'Operativni sistemi',
+ 'UserSettings_WidgetGlobalVisitors' => 'Globalne karakteristike korisnika',
+ 'UserSettings_SubmenuSettings' => 'Postavke',
+ 'UserCountry_Country' => 'Država',
+ 'UserCountry_Continent' => 'Kontinent',
+ 'UserCountry_DistinctCountries' => 'Broj različitih država: %s',
+ 'UserCountry_SubmenuLocations' => 'Lokacije',
+ 'UserCountry_WidgetContinents' => 'Kontinenti posetilaca',
+ 'UserCountry_WidgetCountries' => 'Države posetilaca',
+ 'UserCountry_country_ac' => 'Ascension Ostrva',
+ 'UserCountry_country_ad' => 'Andora',
+ 'UserCountry_country_ae' => 'Ujedinjeni Arapski Emirati',
+ 'UserCountry_country_af' => 'Avganistan',
+ 'UserCountry_country_ag' => 'Antigva i Barbuda',
+ 'UserCountry_country_ai' => 'Angvila',
+ 'UserCountry_country_al' => 'Albanija',
+ 'UserCountry_country_am' => 'Jermenija',
+ 'UserCountry_country_an' => 'Holandski Antili',
+ 'UserCountry_country_ao' => 'Angola',
+ 'UserCountry_country_aq' => 'Antarktik',
+ 'UserCountry_country_ar' => 'Argentina',
+ 'UserCountry_country_as' => 'Američka Samoa',
+ 'UserCountry_country_at' => 'Austrija',
+ 'UserCountry_country_au' => 'Australija',
+ 'UserCountry_country_aw' => 'Aruba',
+ 'UserCountry_country_az' => 'Azerbejdžan',
+ 'UserCountry_country_ba' => 'Bosna i Hercegovina',
+ 'UserCountry_country_bb' => 'Barbados',
+ 'UserCountry_country_bd' => 'Bangladeš',
+ 'UserCountry_country_be' => 'Belgija',
+ 'UserCountry_country_bf' => 'Burkina Faso',
+ 'UserCountry_country_bg' => 'Bugarska',
+ 'UserCountry_country_bh' => 'Bahrein',
+ 'UserCountry_country_bi' => 'Burundi',
+ 'UserCountry_country_bj' => 'Benin',
+ 'UserCountry_country_bm' => 'Bermuda',
+ 'UserCountry_country_bn' => 'Bruneji',
+ 'UserCountry_country_bo' => 'Bolivija',
+ 'UserCountry_country_br' => 'Brazil',
+ 'UserCountry_country_bs' => 'Bahami',
+ 'UserCountry_country_bt' => 'Butan',
+ 'UserCountry_country_bv' => 'Buve Ostrva',
+ 'UserCountry_country_bw' => 'Bocvana',
+ 'UserCountry_country_by' => 'Belorusija',
+ 'UserCountry_country_bz' => 'Belize',
+ 'UserCountry_country_ca' => 'Kanada',
+ 'UserCountry_country_cc' => 'Kokos (Kiling) Ostrva',
+ 'UserCountry_country_cd' => 'Kongo, Demokratska Republika',
+ 'UserCountry_country_cf' => 'Centralnoafrička Republika',
+ 'UserCountry_country_cg' => 'Kongo',
+ 'UserCountry_country_ch' => 'Švajcarska',
+ 'UserCountry_country_ci' => 'Obala Slonovače',
+ 'UserCountry_country_ck' => 'Kukova Ostrva',
+ 'UserCountry_country_cl' => 'Čile',
+ 'UserCountry_country_cm' => 'Kamerun',
+ 'UserCountry_country_cn' => 'Kina',
+ 'UserCountry_country_co' => 'Kolumbija',
+ 'UserCountry_country_cr' => 'Kosta Rika',
+ 'UserCountry_country_cs' => 'Srbija i Crna Gora',
+ 'UserCountry_country_cu' => 'Kuba',
+ 'UserCountry_country_cv' => 'Zelenortska Ostrva',
+ 'UserCountry_country_cx' => 'Božićna Ostrva',
+ 'UserCountry_country_cy' => 'Kipar',
+ 'UserCountry_country_cz' => 'Češka Republika',
+ 'UserCountry_country_de' => 'Nemačka',
+ 'UserCountry_country_dj' => 'Džibuti',
+ 'UserCountry_country_dk' => 'Danska',
+ 'UserCountry_country_dm' => 'Dominika',
+ 'UserCountry_country_do' => 'Dominikanska Republika',
+ 'UserCountry_country_dz' => 'Alžir',
+ 'UserCountry_country_ec' => 'Ekvador',
+ 'UserCountry_country_ee' => 'Estonija',
+ 'UserCountry_country_eg' => 'Egipat',
+ 'UserCountry_country_eh' => 'Zapadna Sahara',
+ 'UserCountry_country_er' => 'Eritreja',
+ 'UserCountry_country_es' => 'Španija',
+ 'UserCountry_country_et' => 'Etiopija',
+ 'UserCountry_country_fi' => 'Finska',
+ 'UserCountry_country_fj' => 'Fidži',
+ 'UserCountry_country_fk' => 'Foklandska Ostrva (Malvini)',
+ 'UserCountry_country_fm' => 'Mikronezija',
+ 'UserCountry_country_fo' => 'Farska Ostrva',
+ 'UserCountry_country_fr' => 'Francuska',
+ 'UserCountry_country_ga' => 'Gabon',
+ 'UserCountry_country_gd' => 'Grenada',
+ 'UserCountry_country_ge' => 'Gruzija',
+ 'UserCountry_country_gf' => 'Francuska Gvajana',
+ 'UserCountry_country_gg' => 'Gernsi',
+ 'UserCountry_country_gh' => 'Gana',
+ 'UserCountry_country_gi' => 'Gibraltar',
+ 'UserCountry_country_gl' => 'Grenland',
+ 'UserCountry_country_gm' => 'Gambija',
+ 'UserCountry_country_gn' => 'Gvineja',
+ 'UserCountry_country_gp' => 'Gvadelupe',
+ 'UserCountry_country_gq' => 'Ekvatorijalna Gvineja',
+ 'UserCountry_country_gr' => 'Grčka',
+ 'UserCountry_country_gs' => 'Južna Gruzija i Južnosendvička Ostrva',
+ 'UserCountry_country_gt' => 'Gvatemala',
+ 'UserCountry_country_gu' => 'Guam',
+ 'UserCountry_country_gw' => 'Gvineja Bisao',
+ 'UserCountry_country_gy' => 'Gvajana',
+ 'UserCountry_country_hk' => 'Hong Kong',
+ 'UserCountry_country_hm' => 'Herd i Mekdonaldova Ostrva',
+ 'UserCountry_country_hn' => 'Honduras',
+ 'UserCountry_country_hr' => 'Hrvatska',
+ 'UserCountry_country_ht' => 'Haiti',
+ 'UserCountry_country_hu' => 'Mađarska',
+ 'UserCountry_country_id' => 'Indonezija',
+ 'UserCountry_country_ie' => 'Irska',
+ 'UserCountry_country_il' => 'Izrael',
+ 'UserCountry_country_im' => 'Ostrvo Man',
+ 'UserCountry_country_in' => 'Indija',
+ 'UserCountry_country_io' => 'Britanska teritorija Indijskog Okeana',
+ 'UserCountry_country_iq' => 'Irak',
+ 'UserCountry_country_ir' => 'Iran',
+ 'UserCountry_country_is' => 'Island',
+ 'UserCountry_country_it' => 'Italija',
+ 'UserCountry_country_je' => 'Džerzi',
+ 'UserCountry_country_jm' => 'Jamajka',
+ 'UserCountry_country_jo' => 'Jordan',
+ 'UserCountry_country_jp' => 'Japan',
+ 'UserCountry_country_ke' => 'Kenija',
+ 'UserCountry_country_kg' => 'Kirgistan',
+ 'UserCountry_country_kh' => 'Kambodža',
+ 'UserCountry_country_ki' => 'Kiribati',
+ 'UserCountry_country_km' => 'Komorska Ostrva',
+ 'UserCountry_country_kn' => 'Sent Kits i Nevis',
+ 'UserCountry_country_kp' => 'Koreja, Demokratska Narodna Republika',
+ 'UserCountry_country_kr' => 'Koreja, Republika',
+ 'UserCountry_country_kw' => 'Kuvajt',
+ 'UserCountry_country_ky' => 'Kajmanska Ostrva',
+ 'UserCountry_country_kz' => 'Kazahstan',
+ 'UserCountry_country_la' => 'Laos',
+ 'UserCountry_country_lb' => 'Liban',
+ 'UserCountry_country_lc' => 'Sent Lucia',
+ 'UserCountry_country_li' => 'Lihtenštajn',
+ 'UserCountry_country_lk' => 'Šri Lanka',
+ 'UserCountry_country_lr' => 'Liberija',
+ 'UserCountry_country_ls' => 'Lesoto',
+ 'UserCountry_country_lt' => 'Litvanija',
+ 'UserCountry_country_lu' => 'Luksemburg',
+ 'UserCountry_country_lv' => 'Letonija',
+ 'UserCountry_country_ly' => 'Libija',
+ 'UserCountry_country_ma' => 'Maroko',
+ 'UserCountry_country_mc' => 'Monako',
+ 'UserCountry_country_md' => 'Moldavija',
+ 'UserCountry_country_mg' => 'Madagaskar',
+ 'UserCountry_country_mh' => 'Maršalska Ostrva',
+ 'UserCountry_country_mk' => 'Makedonija',
+ 'UserCountry_country_ml' => 'Mali',
+ 'UserCountry_country_mm' => 'Mianmar',
+ 'UserCountry_country_mn' => 'Mongolija',
+ 'UserCountry_country_mo' => 'Makao',
+ 'UserCountry_country_mp' => 'Severna Mariana Ostrva',
+ 'UserCountry_country_mq' => 'Martinik',
+ 'UserCountry_country_mr' => 'Mauritanija',
+ 'UserCountry_country_ms' => 'Monserat',
+ 'UserCountry_country_mt' => 'Malta',
+ 'UserCountry_country_mu' => 'Mauricijus',
+ 'UserCountry_country_mv' => 'Maldivi',
+ 'UserCountry_country_mw' => 'Malavi',
+ 'UserCountry_country_mx' => 'Meksiko',
+ 'UserCountry_country_my' => 'Malezija',
+ 'UserCountry_country_mz' => 'Mozambik',
+ 'UserCountry_country_na' => 'Namibija',
+ 'UserCountry_country_nc' => 'Nova Kaledonija',
+ 'UserCountry_country_ne' => 'Niger',
+ 'UserCountry_country_nf' => 'Norfolk Ostrva',
+ 'UserCountry_country_ng' => 'Nigerija',
+ 'UserCountry_country_ni' => 'Nikaragva',
+ 'UserCountry_country_nl' => 'Holandija',
+ 'UserCountry_country_no' => 'Norveška',
+ 'UserCountry_country_np' => 'Nepal',
+ 'UserCountry_country_nr' => 'Nauru',
+ 'UserCountry_country_nu' => 'Niui',
+ 'UserCountry_country_nz' => 'Novi Zeland',
+ 'UserCountry_country_om' => 'Oman',
+ 'UserCountry_country_pa' => 'Panama',
+ 'UserCountry_country_pe' => 'Peru',
+ 'UserCountry_country_pf' => 'Francuska Polinezija',
+ 'UserCountry_country_pg' => 'Papua Nova Gvineja',
+ 'UserCountry_country_ph' => 'Filipini',
+ 'UserCountry_country_pk' => 'Pakistan',
+ 'UserCountry_country_pl' => 'Poljska',
+ 'UserCountry_country_pm' => 'Sent Pjer i Mikelon',
+ 'UserCountry_country_pn' => 'Pitkern',
+ 'UserCountry_country_pr' => 'Porto Riko',
+ 'UserCountry_country_ps' => 'Palestina',
+ 'UserCountry_country_pt' => 'Portugalija',
+ 'UserCountry_country_pw' => 'Palau',
+ 'UserCountry_country_py' => 'Paragvaj',
+ 'UserCountry_country_qa' => 'Katar',
+ 'UserCountry_country_re' => 'Reunion Ostrva',
+ 'UserCountry_country_ro' => 'Rumunija',
+ 'UserCountry_country_ru' => 'Rusija',
+ 'UserCountry_country_rs' => 'Srbija',
+ 'UserCountry_country_rw' => 'Ruanda',
+ 'UserCountry_country_sa' => 'Saudijska Arabija',
+ 'UserCountry_country_sb' => 'Solomonova Ostrva',
+ 'UserCountry_country_sc' => 'Sejšeli',
+ 'UserCountry_country_sd' => 'Sudan',
+ 'UserCountry_country_se' => 'Švedska',
+ 'UserCountry_country_sg' => 'Singapur',
+ 'UserCountry_country_sh' => 'Sent Helena',
+ 'UserCountry_country_si' => 'Slovenija',
+ 'UserCountry_country_sj' => 'Svalbard',
+ 'UserCountry_country_sk' => 'Slovačka',
+ 'UserCountry_country_sl' => 'Siera Leone',
+ 'UserCountry_country_sm' => 'San Marino',
+ 'UserCountry_country_sn' => 'Senegal',
+ 'UserCountry_country_so' => 'Somalija',
+ 'UserCountry_country_sr' => 'Surinam',
+ 'UserCountry_country_st' => 'Sao Tome i Prinčipe',
+ 'UserCountry_country_su' => 'Sovjetski Savez',
+ 'UserCountry_country_sv' => 'El Salvador',
+ 'UserCountry_country_sy' => 'Sirija',
+ 'UserCountry_country_sz' => 'Svazilend',
+ 'UserCountry_country_tc' => 'Turkova Ostrva',
+ 'UserCountry_country_td' => 'Čad',
+ 'UserCountry_country_tf' => 'Francuske Južne Teritorije',
+ 'UserCountry_country_tg' => 'Togo',
+ 'UserCountry_country_th' => 'Tajland',
+ 'UserCountry_country_tj' => 'Tadžikistan',
+ 'UserCountry_country_tk' => 'Tokelau',
+ 'UserCountry_country_tm' => 'Turkmenistan',
+ 'UserCountry_country_tn' => 'Tunis',
+ 'UserCountry_country_to' => 'Tonga',
+ 'UserCountry_country_tp' => 'Istočni Timor',
+ 'UserCountry_country_tr' => 'Turska',
+ 'UserCountry_country_tt' => 'Trinidad i Tobago',
+ 'UserCountry_country_tv' => 'Tuvalu',
+ 'UserCountry_country_tw' => 'Tajvan',
+ 'UserCountry_country_tz' => 'Tanzanija',
+ 'UserCountry_country_ua' => 'Ukrajina',
+ 'UserCountry_country_ug' => 'Uganda',
+ 'UserCountry_country_uk' => 'Ujedinjeno Kraljevstvo',
+ 'UserCountry_country_gb' => 'Velika Britanija',
+ 'UserCountry_country_um' => 'Američka Prekomorska Ostrva',
+ 'UserCountry_country_us' => 'Sjedinjene Američke Države',
+ 'UserCountry_country_uy' => 'Urugvaj',
+ 'UserCountry_country_uz' => 'Uzbekistan',
+ 'UserCountry_country_va' => 'Vatikan',
+ 'UserCountry_country_vc' => 'Sent Vinsent i Grenadini',
+ 'UserCountry_country_ve' => 'Venecuela',
+ 'UserCountry_country_vg' => 'Britanska Devičanska Ostrva',
+ 'UserCountry_country_vi' => 'Američka Devičanska Ostrva',
+ 'UserCountry_country_vn' => 'Vijetnam',
+ 'UserCountry_country_vu' => 'Vanuatu',
+ 'UserCountry_country_wf' => 'Valis i Futuna',
+ 'UserCountry_country_ws' => 'Samoa',
+ 'UserCountry_country_ye' => 'Jemen',
+ 'UserCountry_country_yt' => 'Majoti',
+ 'UserCountry_country_yu' => 'Jugoslavija',
+ 'UserCountry_country_za' => 'Južnoafrička Republika',
+ 'UserCountry_country_zm' => 'Zambija',
+ 'UserCountry_country_zr' => 'Zair',
+ 'UserCountry_country_zw' => 'Zimbabve',
+ 'UserCountry_continent_eur' => 'Evropa',
+ 'UserCountry_continent_afr' => 'Afrika',
+ 'UserCountry_continent_asi' => 'Azija',
+ 'UserCountry_continent_ams' => 'Centralna i Južna Amerika',
+ 'UserCountry_continent_amn' => 'Severna Amerika',
+ 'UserCountry_continent_oce' => 'Okeanija',
+ 'TranslationsAdmin_MenuTranslations' => 'Prevodi',
+ 'TranslationsAdmin_MenuLanguages' => 'Jezici',
+ 'TranslationsAdmin_Plugin' => 'Dodatak',
+ 'TranslationsAdmin_Definition' => 'Definicija',
+ 'TranslationsAdmin_DefaultString' => 'Engleski',
+ 'TranslationsAdmin_TranslationString' => 'Prevod (jezik: %s)',
+ 'TranslationsAdmin_Translations' => 'Prevodi',
+ 'TranslationsAdmin_FixPermissions' => 'Molimo vas da proverite dozvole nad datotekama',
+ 'TranslationsAdmin_AvailableLanguages' => 'Raspoloživi jezici',
+ 'TranslationsAdmin_AddLanguage' => 'Dodavanje jezika',
+ 'TranslationsAdmin_LanguageCode' => 'Oznaka jezika',
+ 'TranslationsAdmin_Export' => 'Snimanje jezika',
+ 'TranslationsAdmin_Import' => 'Učitavanje jezika',
+ 'SitesManager_Sites' => 'Sajtovi',
+ 'SitesManager_WebsitesManagement' => 'Upravljanje sajtovima',
+ 'SitesManager_MainDescription' => 'Potrebni su vam sajtovi da biste mogli da pratite izveštaje. Dodavanje, obrada i uklanjanje sajtova kao i generisanje JavaScript koda koji je potrebno postaviti na vaše stranice.',
+ 'SitesManager_JsCode' => 'JavaScript kod',
+ 'SitesManager_JsCodeHelp' => 'Ovo je JavaScript kod koji je potrebno postaviti na sve vaše stranice',
+ 'SitesManager_ShowJsCode' => 'prikaži kod',
+ 'SitesManager_NoWebsites' => 'Nemate nijedan sajt za obradu',
+ 'SitesManager_AddSite' => 'Dodavanje novog sajta',
+ 'SitesManager_Id' => 'ID',
+ 'SitesManager_Name' => 'Naziv',
+ 'SitesManager_Urls' => 'URL-ovi',
+ 'SitesManager_MenuSites' => 'Sajtovi',
+ 'SitesManager_DeleteConfirm_js' => 'Da li ste sigurni da želite da uklonite sajt %s?',
+ 'SitesManager_ExceptionDeleteSite' => 'Nije moguće obrisati ovaj sajt pošto je to jedini prijavljeni sajt. Najpre dodajte novi sajt pa tek onda obrišite ovaj.',
+ 'SitesManager_ExceptionNoUrl' => 'Morate navesti barem jedan URL po sajtu.',
+ 'SitesManager_ExceptionEmptyName' => 'Naziv sajta ne može biti izostavljen.',
+ 'SitesManager_ExceptionInvalidUrl' => 'URL \'%s\' nije validan.',
+ 'Provider_WidgetProviders' => 'Provajderi',
+ 'Provider_SubmenuLocationsProvider' => 'Lokacije i provajderi',
+ 'DBStats_DatabaseUsage' => 'Iskorišćenost baze podataka',
+ 'DBStats_MainDescription' => 'Piwik smešta sve vaše analitičke podatke u MySQL bazu. Trenutno Piwik tabele zauzimaju %s.',
+ 'DBStats_Table' => 'Tabela',
+ 'DBStats_RowNumber' => 'Broj zapisa',
+ 'DBStats_DataSize' => 'Količina podataka',
+ 'DBStats_IndexSize' => 'Veličina indeksa',
+ 'CoreHome_NoPrivileges' => 'Prijavili ste se na sistem kao korisnik \'%s\' ali izgleda da nemate nikakve privilegije dodeljene.<br />Zatražite od Piwik administratora da vam omogući barem \'prikaz\' pristup sajtu.',
+ 'CoreHome_JavascriptDisabled' => 'Da biste mogli da koristite Piwik morate biti u stanju da izvršavate JavaScript kod.<br />Međutim, kod vas ili je JavaScript isključen ili ga vaš Internet čitač ne podržava.<br />Da biste nastavili dalje, uključite JavaScript izmenom podešavanja vašeg Internt čitača i %1spokušajte ponovo%2s.<br />',
+ 'CoreHome_TableNoData' => 'Nema podataka za ovu tabelu.',
+ 'CoreHome_CategoryNoData' => 'Nema podataka u ovoj kategoriji. Pokušajte sa "Uključi celu populaciju".',
+ 'CoreHome_ShowJSCode' => 'Prikaži JavaScript kod koji treba da se ubaci',
+ 'CoreHome_IncludeAllPopulation_js' => 'Uključi celu populaciju',
+ 'CoreHome_ExcludeLowPopulation_js' => 'Zanemari nisku populaciju',
+ 'CoreHome_PageOf_js' => '%s od %s',
+ 'CoreHome_Loading_js' => 'Učitavanje podataka...',
+ 'CoreHome_LocalizedDateFormat' => '%A %d %B %Y',
+ 'CoreHome_PeriodDay' => 'Dan',
+ 'CoreHome_PeriodWeek' => 'Sedmica',
+ 'CoreHome_PeriodMonth' => 'Mesec',
+ 'CoreHome_PeriodYear' => 'Godina',
+ 'CoreHome_DaySu_js' => 'Ned',
+ 'CoreHome_DayMo_js' => 'Pon',
+ 'CoreHome_DayTu_js' => 'Uto',
+ 'CoreHome_DayWe_js' => 'Sre',
+ 'CoreHome_DayTh_js' => 'Čet',
+ 'CoreHome_DayFr_js' => 'Pet',
+ 'CoreHome_DaySa_js' => 'Sub',
+ 'CoreHome_MonthJanuary_js' => 'Januar',
+ 'CoreHome_MonthFebruary_js' => 'Februar',
+ 'CoreHome_MonthMarch_js' => 'Mart',
+ 'CoreHome_MonthApril_js' => 'April',
+ 'CoreHome_MonthMay_js' => 'Maj',
+ 'CoreHome_MonthJune_js' => 'Jun',
+ 'CoreHome_MonthJuly_js' => 'Jul',
+ 'CoreHome_MonthAugust_js' => 'Avgust',
+ 'CoreHome_MonthSeptember_js' => 'Septembar',
+ 'CoreHome_MonthOctober_js' => 'Oktobar',
+ 'CoreHome_MonthNovember_js' => 'Novembar',
+ 'CoreHome_MonthDecember_js' => 'Decembar',
+ 'Actions_Actions' => 'Akcije',
+ 'Actions_SubmenuPages' => 'Stranice',
+ 'Actions_SubmenuOutlinks' => 'Izlazni linkovi',
+ 'Actions_SubmenuDownloads' => 'Preuzimanja',
+ 'API_QuickDocumentation' => '<h2>API ukratko</h2><p>Ukoliko nemate podatke za danas, najpre ih možete <a href=\'misc/generateVisits.php\' target=_blank>generisati</a> pomoću Visits Generator skripta.</p><p>Možete isprobati različite formate koji su vam na raspolaganju za svaki metod. Veoma je lako izvući iz Piwik bilo kakve podatke koji vam trebaju!</p><p><b>Za više informacija pogledajte <a href=\'http://dev.piwik.org/trac/wiki/API\'>zvaničnu API dokumentaciju</a> ili <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>API referenc-listu</a>.</b></P><h2>Identifikacija korisnika</h2><p>Ukoliko želite da <b>pošaljete zahtev za podacima iz vaših skriptova, crontab-a i slično</b>, onda morate da dodate parametar <code><u>&token_auth=%s</u></code> u URL-ove sa API pozivima koji zahtevaju identifikaciju.</p><p>token_auth je poverljiva informacija, baš poput vaše lozinke stoga <b>nemojte ga obelodanjivati!</p>',
+ 'API_LoadedAPIs' => 'Uspešno učitano API-ja: %s',
+ 'CorePluginsAdmin_Plugins' => 'Dodaci',
+ 'CorePluginsAdmin_PluginsManagement' => 'Upravljanje dodacima',
+ 'CorePluginsAdmin_MainDescription' => 'Dodaci proširuju funkcionalnost Piwik-a. Jednom instaliran dodatak se ovde može aktivirati ili deaktivirati.',
+ 'CorePluginsAdmin_Plugin' => 'Dodatak',
+ 'CorePluginsAdmin_Version' => 'Verzija',
+ 'CorePluginsAdmin_Description' => 'Opis',
+ 'CorePluginsAdmin_Status' => 'Status',
+ 'CorePluginsAdmin_Action' => 'Akcija',
+ 'CorePluginsAdmin_PluginHomepage' => 'Matična strana dodatka',
+ 'CorePluginsAdmin_Activated' => 'Aktiviran',
+ 'CorePluginsAdmin_Active' => 'Aktivan',
+ 'CorePluginsAdmin_Inactive' => 'Neaktivan',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Ovaj dodatak ne može biti deaktiviran',
+ 'CorePluginsAdmin_Deactivate' => 'Deaktivirati',
+ 'CorePluginsAdmin_Activate' => 'Aktivirati',
+ 'CorePluginsAdmin_MenuPlugins' => 'Dodaci',
+ 'CoreUpdater_UpdateTitle' => 'Nadogradnja',
+ 'CoreUpdater_UpdateRequired' => 'Nadogradnja je neophodna',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Piwik baza podataka je zastarela i mora biti nadograđena pre nego što nastavite.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'Piwik će biti nadograđen na verziju %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'Sledeći dodaci će biti nadograđeni: %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Proces nadogradnje može potrajati stoga budite strpljivi.',
+ 'CoreUpdater_UpgradePiwik' => 'Piwik nadogradnja',
+ 'CoreUpdater_HelpMessageContent' => 'Pogledajte %s Piwik pitanja i odgovore %s koja objašnjavaju najčešće greške prilikom nadogradnje. %s Kontaktirajte vašeg sistemskog administratora - možda je u mogućnosti da vam pomogne oko grešaka koje su najverovatnije u domenu podešavanja servera ili MySQL-a.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Kritične greške nastale tokom procesa nadogradnje:',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'Ovo gore je sama srž poruke o grešci. Ona bi trebalo da objasni uzrok a u slučaju da vam je potrebna dalja pomoć:',
+ 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'Proces nadogradnje je uspešno okončan, međutim, imamo i spornih momenata nastalih tokom procesa. Molimo vas da pročitate njihove opise zarad detalja. U slučaju da vam je potrebna dalja pomoć:',
+ 'CoreUpdater_UpgradeComplete' => 'Nadogradnja okončana!',
+ 'CoreUpdater_WarningMessages' => 'Poruka upozorenja:',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Greška tokom nadogradnje dodatka:',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'Automatski smo deaktivirali sledeće dodatke: %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik je uspešno nadograđen!',
+ 'CoreUpdater_ContinueToPiwik' => 'Nastavite rad sa Piwik-om.',
+ 'Installation_Installation' => 'Instalacija',
+ 'Installation_InstallationStatus' => 'Status instalacije',
+ 'Installation_PercentDone' => '%s %% urađeno',
+ 'Installation_NoConfigFound' => 'Piwik datoteka sa podešavanjima nije nađena u momentu dok vi pokušavate da pristupite Piwik stranici.<br /><b>&nbsp;&nbsp;&raquo; Kliknite ovde kako biste <a href=\'index.php\'>instalirali Piwik</a></b><br /><small>Ukoliko ste već ranije instalirali Piwik i imate neke tabele u bazi podataka, bez brige: možete nastaviti da ih koristite i zadržite postojeće podatke!</small>',
+ 'Installation_MysqlSetup' => 'Podešavanje MySQL baze podataka',
+ 'Installation_MysqlErrorConnect' => 'Greška prilikom pokušaja povezivanja na MySQL bazu podataka',
+ 'Installation_JsTag' => 'JavaScript tag',
+ 'Installation_JsTagHelp' => '<p>Da biste prikupili podatke o svim posetama vašeg sajta morate ubaciti JavaScript kod na sve stranice.</p><p>Stranice ne moraju biti pisane u jeziku PHP, Piwik će raditi sa svim vrstama stranica bez obzira da li su one pisane u HTML, ASP, Perl ili nekom drugom jeziku.</p><p>Ovo je JavaScript kod koji morate ubaciti (iskopirajte i ubacite ga na sve stranice vašeg sajta): </p>',
+ 'Installation_Congratulations' => 'Sve čestitke!',
+ 'Installation_CongratulationsHelp' => '<p>Čestitamo! Piwik instalacija je završena.</p><p>Postarajte se da je JavaScript kod ubačen na sve stranice sajta i sačekajte vaše prve posetioce!</p>',
+ 'Installation_ContinueToPiwik' => 'Nastavite sa korišćenjem Piwik-a',
+ 'Installation_SetupWebsite' => 'Podešavanje sajta',
+ 'Installation_SetupWebsiteError' => 'Došlo je do greške prilikom dodavanja sajta',
+ 'Installation_GeneralSetup' => 'Opšta podešavanja',
+ 'Installation_GeneralSetupSuccess' => 'Opšta podešavanja su uspešno izvršena',
+ 'Installation_SystemCheck' => 'Provera sistema',
+ 'Installation_SystemCheckPhp' => 'Verzija PHP-a',
+ 'Installation_SystemCheckPdo' => 'PDO dodatak',
+ 'Installation_SystemCheckPdoMysql' => 'PDO_MYSQL dodatak',
+ 'Installation_SystemCheckPdoError' => 'Morate uključiti PDO i PDO_MYSQL dodatke u php.ini datoteci',
+ 'Installation_SystemCheckPdoHelp' => 'Na Windows serveru možete dodati sledeće linije u php.ini datoteku %s <br /><br />Na Linux serveru možete kompajlirati PHP sa sledećom opcijom %s U php.ini datoteku dodajte sledeće linije %s<br /><br />Više informacija možete naći na <a style="color:red" href="http://php.net/pdo">PHP stranici</a>.',
+ 'Installation_SystemCheckWriteDirs' => 'Diektorijumi sa pristupom pisanja',
+ 'Installation_SystemCheckWriteDirsHelp' => 'Da biste ispravili ovu grešku na Linux serveru, ukucajte sledeće komande:',
+ 'Installation_SystemCheckMemoryLimit' => 'Memorijsko ograničenje',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'Na sajtovima sa visokim saobraćajem proces arhiviranja podataka može zahtevati više memorije nego što je to trenutno dozvoljeno.<br />Promenite vrednost parametra memory_limit u php.ini datoteci ukoliko je to neophodno.',
+ 'Installation_SystemCheckGD' => 'GD &gt; 2.x (grafika)',
+ 'Installation_SystemCheckGDHelp' => 'Iskrice (mali grafikoni) neće raditi',
+ 'Installation_SystemCheckTimeLimit' => 'set_time_limit() dozvoljen',
+ 'Installation_SystemCheckTimeLimitHelp' => 'Na sajtovima sa visokim saobraćajem proces arhiviranja podataka može zahtevati više vremena nego što je to trenutno dozvoljeno.<br />Promenite vrednost parametra max_execution_time u php.ini datoteci ukoliko je to neophodno.',
+ 'Installation_SystemCheckMail' => 'mail() dozvoljen',
+ 'Installation_SystemCheckError' => 'Došlo je do greške koja mora biti ispravljena pre nego što nastavimo',
+ 'Installation_SystemCheckWarning' => 'Piwik će raditi normalno ali neke funkcije neće biti dostupne',
+ 'Installation_Tables' => 'Kreiranje tabela',
+ 'Installation_TablesWarning' => 'Neke <span id="linkToggle">Piwik tabele</span> se već nalaze u bazi podataka',
+ 'Installation_TablesFound' => 'Sledeće tabele su zatečene u bazi podataka',
+ 'Installation_TablesWarningHelp' => 'Ili izaberite opciju da nastavite sa korišćenjem postojećih tabela ili opciju čiste instalacije čime ćete obrisati postojeće podatke iz baze podataka.',
+ 'Installation_TablesReuse' => 'Nastavak korišćenja postojećih tabela',
+ 'Installation_TablesDelete' => 'Brisanje zatečenih tabela',
+ 'Installation_TablesDeletedSuccess' => 'Zatečene Piwik tabele su uspešno obrisane',
+ 'Installation_TablesCreatedSuccess' => 'Tabele su uspešno kreirane!',
+ 'Installation_DatabaseCreatedSuccess' => 'Baza podataka %s je uspešno kreirana!',
+ 'Installation_TablesDeleteConfirm' => 'Da li ste zaista sigurni da želite da obrišete sve Piwik tabele iz ove baze podataka?',
+ 'Installation_Welcome' => 'Dobrodošli!',
+ 'Installation_WelcomeHelp' => '<p>Piwik je alat otvorenog koda za analizu saobraćaja na sajtovima koji vam na lak način pruža željene informacije o vašim posetiocima.</p><p>Proces instalacije je podeljen na %s jednostavnih koraka i zahteva svega 5 minuta vašeg vremena.</p>',
+ 'Referers_Referers' => 'Reference',
+ 'Referers_SearchEngines' => 'Pretraživači',
+ 'Referers_Keywords' => 'Ključne reči',
+ 'Referers_DirectEntry' => 'Direktni ulasci',
+ 'Referers_Websites' => 'Sajtovi',
+ 'Referers_Partners' => 'Partneri',
+ 'Referers_Newsletters' => 'Elektronske novine',
+ 'Referers_Campaigns' => 'Kampanje',
+ 'Referers_Evolution' => 'Trend kroz period',
+ 'Referers_Type' => 'Tip reference',
+ 'Referers_TypeDirectEntries' => 'Direktnih ulazaka: %s',
+ 'Referers_TypeSearchEngines' => 'Preko pretraživača: %s',
+ 'Referers_TypePartners' => 'Preko partnera: %s',
+ 'Referers_TypeWebsites' => 'Preko sajtova: %s',
+ 'Referers_TypeNewsletters' => 'Putem elektronskih novina: %s',
+ 'Referers_TypeCampaigns' => 'Kroz kampanje: %s',
+ 'Referers_Other' => 'Ostalo',
+ 'Referers_OtherDistinctSearchEngines' => 'Različitih pretraživača: %s',
+ 'Referers_OtherDistinctKeywords' => 'Različitih ključnih reči: %s',
+ 'Referers_OtherDistinctWebsites' => 'Različitih sajtova: %1s (različitih URL-ova: %2s)',
+ 'Referers_OtherDistinctPartners' => 'Različitih partnera: %1s (različitih URL-ova: %2s)',
+ 'Referers_OtherDistinctCampaigns' => 'Različitih kampanja: %s',
+ 'Referers_TagCloud' => 'Oblak tagova',
+ 'Referers_SubmenuEvolution' => 'Trend',
+ 'Referers_SubmenuSearchEngines' => 'Pretraživači i ključne reči',
+ 'Referers_SubmenuWebsites' => 'Sajtovi',
+ 'Referers_SubmenuCampaigns' => 'Kampanje',
+ 'Referers_SubmenuPartners' => 'Partneri',
+ 'Referers_WidgetKeywords' => 'Spisak ključnih reči',
+ 'Referers_WidgetPartners' => 'Spisak partnera',
+ 'Referers_WidgetCampaigns' => 'Spisak kampanja',
+ 'Referers_WidgetExternalWebsites' => 'Spisak eksternih sajtova',
+ 'Referers_WidgetSearchEngines' => 'Najbolji pretraživači',
+ 'Referers_WidgetOverview' => 'Pregled',
+ 'General_HelloUser' => 'Pozdrav %s!',
+ 'General_OpenSourceWebAnalytics' => 'Alat otvorenog koda za analizu saobraćaja na sajtovima',
+ 'General_YourDashboard' => 'Konzola',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Elementi',
+ 'General_Settings' => 'Podešavanja',
+ 'General_GiveUsYourFeedback' => 'Recite nam šta mislite!',
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => 'Trenutno koristite demo verziju %s; %spreuzmite%s punu verziju! Posetite %s',
+); \ No newline at end of file
diff --git a/lang/sv.php b/lang/sv.php
new file mode 100644
index 0000000000..49666aa556
--- /dev/null
+++ b/lang/sv.php
@@ -0,0 +1,609 @@
+<?php
+$translations = array(
+ 'General_Locale' => 'sv_SE.UTF-8',
+ 'General_TranslatorName' => 'Fredrik &Aring;str&ouml;m',
+ 'General_TranslatorEmail' => 'fredrik@lagun.se',
+ 'General_EnglishLanguageName' => 'Swedish',
+ 'General_OriginalLanguageName' => 'Svenska',
+ 'General_HelloUser' => 'Hej %s!',
+ 'General_OpenSourceWebAnalytics' => 'Webbanalys med &ouml;ppen k&auml;llkod',
+ 'General_YourDashboard' => 'Din instrumentpanel',
+ 'General_API' => 'API',
+ 'General_Widgets' => 'Widgets',
+ 'General_Settings' => 'Inst&auml;llningar',
+ 'General_GiveUsYourFeedback' => 'Ge oss din &aring;sikt',
+ 'General_Unknown' => 'Ok&auml;nt',
+ 'General_Required' => '%s kr&auml;vs',
+ 'General_Error' => 'Fel',
+ 'General_Warning' => 'Varning',
+ 'General_BackToHomepage' => 'Tillbaka till Piwik\'s hemsida',
+ 'General_Yes' => 'Ja',
+ 'General_No' => 'Nej',
+ 'General_Delete' => 'Ta bort',
+ 'General_Edit' => '&Auml;ndra',
+ 'General_Ok' => 'Ok',
+ 'General_Close' => 'St&auml;ng',
+ 'General_Logout' => 'Logga ut',
+ 'General_Done' => 'Klar',
+ 'General_LoadingData' => 'Laddar data...',
+ 'General_ErrorRequest' => 'Oops&hellip; ett problem p&aring;tr&auml;ffades under f&ouml;rfr&aring;gningen, var v&auml;nlig f&ouml;rs&ouml;k igen.',
+ 'General_Next' => 'N&auml;sta',
+ 'General_Previous' => 'F&ouml;reg&aring;ende',
+ 'General_Search' => 'S&ouml;k',
+ 'General_Others' => 'Andra',
+ 'General_Table' => 'Tabell',
+ 'General_Piechart' => 'Cirkeldiagram',
+ 'General_TagCloud' => 'Taggmoln',
+ 'General_VBarGraph' => 'Stapeldiagram',
+ 'General_Export' => 'Exportera',
+ 'General_Refresh' => 'Uppdatera sidan',
+ 'General_Visitors' => 'Bes&ouml;kare',
+ 'General_ColumnNbUniqVisitors' => 'Unika bes&ouml;kare',
+ 'General_ColumnNbVisits' => 'Bes&ouml;k',
+ 'General_ColumnLabel' => 'Etikett',
+ 'General_ColumnActionsPerVisit' => 'H&auml;ndelser per bes&ouml;k',
+ 'General_ColumnAvgTimeOnSite' => 'Tid p&aring; webbplats',
+ 'General_ColumnBounceRate' => 'Avvisningsfrekvens',
+ 'General_ColumnPageviews' => 'Sidvisningar',
+ 'General_ColumnUniquePageviews' => 'Unika sidvisningar',
+ 'General_Save' => 'Spara',
+ 'General_Website' => 'Webbplats',
+ 'General_NoDataForGraph' => 'Ingen data f&ouml;r den h&auml;r grafen',
+ 'General_NoDataForTagCloud' => 'Ingen data f&ouml;r taggmolnet',
+ 'General_DisplayNormalTable' => 'Visa normal tabell',
+ 'General_DisplayMoreData' => 'Visa mer data',
+ 'General_PiwikIsACollaborativeProject' => '%s Piwik %s &auml;r ett samarbetsprojekt och fortfarande beta. %s Om du vill hj&auml;lpa till, v&auml;nligen %s kontakta oss!%s.',
+ 'General_YouAreCurrentlyViewingDemoOfPiwik' => 'Du ser just nu ett demo av %s; %sladda ner%s den fullst&auml;ndiga versionen! Kolla in %s',
+ 'Actions_Actions' => 'H&auml;ndelser',
+ 'Actions_SubmenuPages' => 'Sidor',
+ 'Actions_SubmenuOutlinks' => 'Utg&aring;ngssidor',
+ 'Actions_SubmenuDownloads' => 'Nedladdningar',
+ 'API_QuickDocumentation' => '<h2>Snabbdokumentation f&ouml;r API</h2><p> Om du inte har data f&ouml;r \'i dag\' kan du f&ouml;rst <a href=\'misc/generateVisits.php\' target=_blank> generera lite data</a> med bes&ouml;ksgeneratorn.</p><p>Du kan prova olika format som finns tillg&auml;ngliga f&ouml;r varje metod. Det &auml;r mycket enkelt att extrahera den data du vill ha fr&aring;n piwik!</p><p><b>F&ouml;r mer information, ta en titt p&aring; den <a href=\'http://dev.piwik.org/trac/wiki/API\'>officiell API-dokumentationen</a> eller <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>API Referensen</a>.</b></p><h2>Anv&auml;ndarverifiering</h2><p>Om du tex vill <b>k&ouml;ra ditt skript i en crontab, eller liknande,</b> m&aring;ste du l&auml;gga till parametern <code><u>&token_auth=%s</u></code> till API-beg&auml;ran som kr&auml;ver autentisering.</p><p>Detta token_auth &auml;r lika hemligt som inloggning och l&ouml;senord, <b>sprid aldrig det!</ p>',
+ 'API_LoadedAPIs' => '%s APIs laddades utan problem',
+ 'CoreHome_NoPrivileges' => 'Du &auml;r inloggad som \'%s\' men det ser inte ut som att du har n&aring;gra r&auml;ttigheter inst&auml;llda i Piwik.<br />Be din Piwik-admin att ge dig r&auml;ttigheten att visa en webbplats.',
+ 'CoreHome_JavascriptDisabled' => 'JavaScript m&aring;ste vara till&aring;tet f&ouml;r att kunna anv&auml;nda Piwik i standardl&auml;ge.<br />Det ser ut som att JavaScript antingen &auml;r avaktiverat eller inte st&ouml;ds av din webbl&auml;sare.<br /> F&ouml;r att anv&auml;nda standardl&auml;get, aktivera JavaScript i din webbl&auml;sare och g&ouml;r ett %s1nytt f&ouml;rs&ouml;k%s2.<br />',
+ 'CoreHome_TableNoData' => 'Ingen data f&ouml;r den h&auml;r tabellen',
+ 'CoreHome_CategoryNoData' => 'Ingen data i den h&auml;r kategorin. F&ouml;rs&ouml;k att "visa all data"',
+ 'CoreHome_ShowJSCode' => 'Visa javascript-koden att l&auml;gga till p&aring; webbplatsen',
+ 'CoreHome_IncludeAllPopulation_js' => 'Visa all data',
+ 'CoreHome_ExcludeLowPopulation_js' => 'D&ouml;lj enstaka data',
+ 'CoreHome_PageOf_js' => '%s av %s',
+ 'CoreHome_Loading_js' => 'Laddar...',
+ 'CoreHome_LocalizedDateFormat' => '%A %d %B %Y',
+ 'CoreHome_PeriodDay' => 'Dag',
+ 'CoreHome_PeriodWeek' => 'Vecka',
+ 'CoreHome_PeriodMonth' => 'M&aring;nad',
+ 'CoreHome_PeriodYear' => '&Aring;r',
+ 'CoreHome_DaySu_js' => 'S&ouml;n',
+ 'CoreHome_DayMo_js' => 'M&aring;n',
+ 'CoreHome_DayTu_js' => 'Tis',
+ 'CoreHome_DayWe_js' => 'Ons',
+ 'CoreHome_DayTh_js' => 'Tor',
+ 'CoreHome_DayFr_js' => 'Fre',
+ 'CoreHome_DaySa_js' => 'L&ouml;r',
+ 'CoreHome_MonthJanuary_js' => 'Januari',
+ 'CoreHome_MonthFebruary_js' => 'Februari',
+ 'CoreHome_MonthMarch_js' => 'Mars',
+ 'CoreHome_MonthApril_js' => 'April',
+ 'CoreHome_MonthMay_js' => 'Maj',
+ 'CoreHome_MonthJune_js' => 'Juni',
+ 'CoreHome_MonthJuly_js' => 'Juli',
+ 'CoreHome_MonthAugust_js' => 'Augusti',
+ 'CoreHome_MonthSeptember_js' => 'September',
+ 'CoreHome_MonthOctober_js' => 'Oktober',
+ 'CoreHome_MonthNovember_js' => 'November',
+ 'CoreHome_MonthDecember_js' => 'December',
+ 'CorePluginsAdmin_Plugins' => 'Till&auml;gg',
+ 'CorePluginsAdmin_PluginsManagement' => 'Till&auml;ggshantering',
+ 'CorePluginsAdmin_MainDescription' => 'Till&auml;gg ut&ouml;kar Piwik\'s funktioner. N&auml;r ett till&auml;gg &auml;r installerat kan du aktivera eller avaktivera det h&auml;r.',
+ 'CorePluginsAdmin_Plugin' => 'Till&auml;gg',
+ 'CorePluginsAdmin_Version' => 'Version',
+ 'CorePluginsAdmin_Description' => 'Beskrivning',
+ 'CorePluginsAdmin_Status' => 'Status',
+ 'CorePluginsAdmin_Action' => '&Aring;tg&auml;rd',
+ 'CorePluginsAdmin_PluginHomepage' => 'Till&auml;ggets hemsida',
+ 'CorePluginsAdmin_Activated' => 'Aktiverat',
+ 'CorePluginsAdmin_Active' => 'Aktiv',
+ 'CorePluginsAdmin_Inactive' => 'Inaktivt',
+ 'CorePluginsAdmin_ActivatedHelp' => 'Till&auml;gget kan inte avaktiveras',
+ 'CorePluginsAdmin_Deactivate' => 'Avaktivera',
+ 'CorePluginsAdmin_Activate' => 'Aktivera',
+ 'CorePluginsAdmin_MenuPlugins' => 'Till&auml;gg',
+ 'CoreUpdater_UpdateTitle' => 'Piwik &rsaquo; uppdatering',
+ 'CoreUpdater_UpdateRequired' => 'Uppgradering kr&auml;vs',
+ 'CoreUpdater_YourDatabaseIsOutOfDate' => 'Din Piwik-databas &auml;r utdaterad och m&aring;ste uppgraderas innan du kan forts&auml;tta.',
+ 'CoreUpdater_PiwikWillBeUpgradedToVersionX' => 'Piwik kommer uppgraderas till version %s.',
+ 'CoreUpdater_TheFollowingPluginsWillBeUpgradedX' => 'F&ouml;ljande till&auml;gg kommer att uppgraderas: %s.',
+ 'CoreUpdater_TheUpgradeProcessMayTakeAWhilePleaseBePatient' => 'Uppgraderingsprocessen kan ta ett tag, var v&auml;nlig v&auml;nta.',
+ 'CoreUpdater_UpgradePiwik' => 'Uppgradera Piwik',
+ 'CoreUpdater_HelpMessageContent' => 'Titta i %s Piwik FAQ %s som har tagit upp dom vanligaste felen under uppgraderingar. %s Fr&aring;ga din systemadministrat&ouml;r - som kanske kan hj&auml;lpa dig med problemen som troligast &auml;r relaterade till dina server eller MySQL-inst&auml;llningar.',
+ 'CoreUpdater_CriticalErrorDuringTheUpgradeProcess' => 'Kritiskt fel under uppgraderingsprocessen:',
+ 'CoreUpdater_HelpMessageIntroductionWhenError' => 'H&auml;r ovanf&ouml;r visas felmeddelandet. Det borde hj&auml;lpa dig att f&ouml;rklara felorsaken. Om du beh&ouml;ver ytterligare hj&auml;lp, v&auml;nligen:',
+ 'CoreUpdater_HelpMessageIntroductionWhenWarning' => 'Uppgraderingen slutf&ouml;rdes men p&aring;tr&auml;ffade n&aring;gra problem. L&auml;s beskrivningen h&auml;r ovanf&ouml;r f&ouml;r detaljer om problemen. Om du beh&ouml;ver ytterligare hj&auml;lp, v&auml;nligen:',
+ 'CoreUpdater_UpgradeComplete' => 'Uppgraderingen slutf&ouml;rd!',
+ 'CoreUpdater_WarningMessages' => 'Varningsmeddelanden:',
+ 'CoreUpdater_ErrorDuringPluginsUpdates' => 'Fel under till&auml;ggsupdatering:',
+ 'CoreUpdater_WeAutomaticallyDeactivatedTheFollowingPlugins' => 'F&ouml;ljande till&auml;gg har avaktiverats automatiskt: %s',
+ 'CoreUpdater_PiwikHasBeenSuccessfullyUpgraded' => 'Piwik har uppgraderats utan problem!',
+ 'CoreUpdater_ContinueToPiwik' => 'Forts&auml;tt till Piwik',
+ 'Dashboard_Dashboard' => 'Instrumentpanel',
+ 'Dashboard_AddWidget' => 'L&auml;gg till en widget...',
+ 'Dashboard_DeleteWidgetConfirm' => 'Vill du verkligen ta bort den h&auml;r widgeten fr&aring;n instrumentpanelen?',
+ 'Dashboard_SelectWidget' => 'V&auml;lj widget att l&auml;gga till i instrumentpanelen',
+ 'Dashboard_AddPreviewedWidget' => 'L&auml;gg till f&ouml;rhandsgranskad widget i instrumentpanelen',
+ 'Dashboard_WidgetPreview' => 'F&ouml;rhandsgranska widget',
+ 'Dashboard_TitleWidgetInDashboard_js' => 'Widgeten finns redan i instrumentpanelen',
+ 'Dashboard_TitleClickToAdd_js' => 'Klicka f&ouml;r att l&auml;gga till instrumentpanelen',
+ 'Dashboard_LoadingPreview_js' => 'Laddar f&ouml;rhandsgranskning, v&auml;nligen v&auml;nta...',
+ 'Dashboard_LoadingWidget_js' => 'Laddar widget, v&auml;nligen v&auml;nta...',
+ 'Dashboard_WidgetNotFound_js' => 'Widgeten hittades inte',
+ 'DBStats_DatabaseUsage' => 'Databasanv&auml;ndning',
+ 'DBStats_MainDescription' => 'Piwik lagrar alla dina analyser i en MySQL-databas. F&ouml;r n&auml;rvarande anv&auml;nder Piwik %s.',
+ 'DBStats_Table' => 'Tabell',
+ 'DBStats_RowNumber' => 'Antal rader',
+ 'DBStats_DataSize' => 'Datam&auml;ngd',
+ 'DBStats_IndexSize' => 'Indexstorlek',
+ 'Installation_Installation' => 'Installation',
+ 'Installation_InstallationStatus' => 'Installationsstatus',
+ 'Installation_PercentDone' => '%s %% Klart',
+ 'Installation_NoConfigFound' => 'Du f&ouml;rs&ouml;ker visa en Piwiksida utan att n&aring;gon konfigurationsfil hittades.<br /><b>&nbsp;&nbsp;&raquo; Du kan <a href=\'index.php\'>installera Piwik nu</a></b><br /><small>Om du har installerat Piwik f&ouml;rut och har analyser lagrade i databasen, oroa dig inte, du kan &aring;teranv&auml;nda samma analyser och beh&aring;lla befintlig data!</small>',
+ 'Installation_MysqlSetup' => 'Mysql databasinst&auml;llning',
+ 'Installation_MysqlErrorConnect' => 'Fel vid anslutning till MySQL databasen',
+ 'Installation_JsTag' => 'Javascript kod',
+ 'Installation_JsTagHelp' => '<p>F&ouml;r att r&auml;kna alla bes&ouml;k m&aring;ste du l&auml;gga till Javascript-koden p&aring; alla dina sidor.</p><p>Dina sidor beh&ouml;ver inte vara gjorda med PHP, Piwik fungerar p&aring; alla typer av sidor (oavsett om det &auml;r HTML, ASP, Perl eller n&aring;got annat spr&aring;k).</p><p>H&auml;r &auml;r koden du m&aring;ste l&auml;gga till: (kopiera och klistra in p&aring; alla dina sidor)</p>',
+ 'Installation_Congratulations' => 'Grattis',
+ 'Installation_CongratulationsHelp' => '<p>Grattis! Din installation av Piwik &auml;r klar.</p><p>Kontrollera att din javascript-kod finns p&aring; alla dina sidor, inv&auml;nta sedan p&aring; dina f&ouml;rsta bes&ouml;kare!',
+ 'Installation_ContinueToPiwik' => 'Forts&auml;tt till Piwik',
+ 'Installation_SetupWebsite' => 'L&auml;gg till en webbplats',
+ 'Installation_SetupWebsiteError' => 'Ett fel p&aring;tr&auml;ffades n&auml;r webbplatsen skulle l&auml;ggas till',
+ 'Installation_GeneralSetup' => 'Allm&auml;nna inst&auml;llningar',
+ 'Installation_GeneralSetupSuccess' => 'Allm&auml;nna inst&auml;llningar slutf&ouml;rdes utan problbem',
+ 'Installation_SystemCheck' => 'Systemkontroll',
+ 'Installation_SystemCheckPhp' => 'PHP-version',
+ 'Installation_SystemCheckPdo' => 'Pdo-till&auml;gg',
+ 'Installation_SystemCheckPdoMysql' => 'Pdo_Mysql-till&auml;gg',
+ 'Installation_SystemCheckPdoError' => 'Du m&aring;ste aktivera PDO och PDO_MYSQL-till&auml;ggen i din php.ini-fil.',
+ 'Installation_SystemCheckPdoHelp' => 'P&aring; windows-servrar kan du l&auml;gga till f&ouml;ljande rader i din php.ini %s<br /><br />P&aring; en linux-server kan du kompilera php med f&ouml;ljande val %s L&auml;gg till f&ouml;ljande rader i din php.ini %s<br /><br />Mer informations finns p&aring; <a style="color:red" href="http://php.net/pdo">PHP\'s webbplats</a>.',
+ 'Installation_SystemCheckWriteDirs' => 'Mappar med skrivbeh&ouml;righet',
+ 'Installation_SystemCheckWriteDirsHelp' => 'F&ouml;r att fixa det h&auml;r problemet p&aring; ditt Linuxsystem, f&ouml;rs&ouml;k att skriva f&ouml;ljande kommando(n)',
+ 'Installation_SystemCheckMemoryLimit' => 'Minnesgr&auml;ns',
+ 'Installation_SystemCheckMemoryLimitHelp' => 'P&aring; sidor med mycket trafik kan arkiveringsprocessen kr&auml;va mer minne &auml;n det som till&aring;ts just nu.<br />Se &ouml;ver direktivet memory_limit i din php.ini om det beh&ouml;vs.',
+ 'Installation_SystemCheckGD' => 'GD &gt; 2.x (grafik)',
+ 'Installation_SystemCheckGDHelp' => 'Sparklines (sm&aring; diagram) kommer inte att fungera',
+ 'Installation_SystemCheckTimeLimit' => 'set_time_limit() till&aring;ts',
+ 'Installation_SystemCheckTimeLimitHelp' => 'P&aring; sidor med mycket trafik kan arkiveringsprocessen kr&auml;va mer tid &auml;n vad som till&aring;ts just nu.<br />Se &ouml;ver direktivet max_execution_time i din php.ini om det beh&ouml;vs.',
+ 'Installation_SystemCheckMail' => 'mail() till&aring;ts',
+ 'Installation_SystemCheckError' => 'Ett fel p&aring;tr&auml;ffades - det m&aring;ste r&auml;ttas till innan du kan forts&auml;tta',
+ 'Installation_SystemCheckWarning' => 'Piwik kommer fungera men vissa funktioner kan saknas',
+ 'Installation_Tables' => 'Skapar tabeller',
+ 'Installation_TablesWarning' => 'N&aring;gra <span id="linkToggle">Piwik-tabeller</span> finns redan i databasen',
+ 'Installation_TablesFound' => 'F&ouml;ljande tabeller hittades i databasen',
+ 'Installation_TablesWarningHelp' => 'V&auml;lj att antingen &aring;teranv&auml;nda befintliga tabeller i databasen eller v&auml;lj en ren installation f&ouml;r att radera all befintlig data.',
+ 'Installation_TablesReuse' => '&Aring;teranv&auml;nd befintlig tabeller',
+ 'Installation_TablesDelete' => 'Radera befintliga tabeller',
+ 'Installation_TablesDeletedSuccess' => 'Befintliga Piwik-tabeller raderades utan problem',
+ 'Installation_TablesCreatedSuccess' => 'Tabeller skapades utan problem!',
+ 'Installation_DatabaseCreatedSuccess' => 'Databasen %s skapades utan problem!',
+ 'Installation_TablesDeleteConfirm' => '&Auml;r du s&auml;ker p&aring; att du vill radera alla Piwik\'s tabeller i databasen?',
+ 'Installation_Welcome' => 'V&auml;lkommen!',
+ 'Installation_WelcomeHelp' => '<p>Piwik &auml;r en open source programvara f&ouml;r webbplatsanalys som g&ouml;r det enkelt att samla in information om dina bes&ouml;kare.</p><p>Den &auml;r processen &auml;r uppdelad i %s enkla steg och kommer ta ca 5 minuter.</p>',
+ 'Login_LoginPasswordNotCorrect' => 'Anv&auml;ndarnamn och l&ouml;senord &auml;r felaktigt',
+ 'Login_Login' => 'Anv&auml;ndarnamn',
+ 'Login_Password' => 'L&ouml;senord',
+ 'Login_LoginOrEmail' => 'Anv&auml;ndarnamn eller e-post',
+ 'Login_LogIn' => 'Logga in',
+ 'Login_Logout' => 'Logga ut',
+ 'Login_LostYourPassword' => 'F&ouml;rlorat ditt l&ouml;senord?',
+ 'Login_RemindPassword' => 'P&aring;minn l&ouml;senord',
+ 'Login_PasswordReminder' => 'V&auml;nligen fyll i ditt anv&auml;ndarnamn eller din e-postadress. Du kommer att f&aring; ett nytt l&ouml;senord skickat via e-post.',
+ 'Login_InvalidUsernameEmail' => 'Felaktigt anv&auml;ndarnamn och/eller e-postadress',
+ 'Login_MailTopicPasswordRecovery' => '&Aring;terst&auml;ll l&ouml;senord',
+ 'Login_MailPasswordRecoveryBody' => 'Hej %1s, \n\n Ditt nya l&ouml;senord &auml;r: %2s \n\n Nu kan du logga in p&aring;: %3s',
+ 'Login_PasswordSent' => 'L&ouml;senordet har skickats. Kontrollera din e-post.',
+ 'Login_ContactAdmin' => 'M&ouml;jlig orsak: din v&auml;rd kan ha avaktiverat mail() funktionen. <br />Var v&auml;nlig kontakta din Piwik-administrat&ouml;r',
+ 'Provider_WidgetProviders' => 'Operat&ouml;r',
+ 'Provider_SubmenuLocationsProvider' => 'Lokalisering och operat&ouml;r',
+ 'Referers_Referers' => 'Trafikk&auml;llor',
+ 'Referers_SearchEngines' => 'S&ouml;kmotorer',
+ 'Referers_Keywords' => 'S&ouml;kord',
+ 'Referers_DirectEntry' => 'Direkt trafik',
+ 'Referers_Websites' => 'Webbplatser',
+ 'Referers_Campaigns' => 'Kampanjer',
+ 'Referers_Evolution' => 'Utveckling under perioden',
+ 'Referers_Type' => 'H&auml;nvisningstyp',
+ 'Referers_TypeDirectEntries' => '%s direkta bes&ouml;k',
+ 'Referers_TypeSearchEngines' => '%s fr&aring;n s&ouml;kmotorer',
+ 'Referers_TypeWebsites' => '%s fr&aring;n webbplatser',
+ 'Referers_TypeCampaigns' => '%s fr&aring;n kampanjer',
+ 'Referers_Other' => 'Annat',
+ 'Referers_OtherDistinctSearchEngines' => '%s s&ouml;kmotor',
+ 'Referers_OtherDistinctKeywords' => '%s s&ouml;kord',
+ 'Referers_OtherDistinctWebsites' => '%1s webbplatser (anv&auml;nder %2s URLer)',
+ 'Referers_OtherDistinctCampaigns' => '%s kampanjer',
+ 'Referers_TagCloud' => 'Taggmoln',
+ 'Referers_SubmenuEvolution' => 'Utveckling',
+ 'Referers_SubmenuSearchEngines' => 'S&ouml;kmotorer och s&ouml;kord',
+ 'Referers_SubmenuWebsites' => 'Webbplatser',
+ 'Referers_SubmenuCampaigns' => 'Kampanjer',
+ 'Referers_WidgetKeywords' => 'Popul&auml;ra s&ouml;kord',
+ 'Referers_WidgetCampaigns' => 'Lista &ouml;ver kampanjer',
+ 'Referers_WidgetExternalWebsites' => 'Lista &ouml;ver externa webbplatser',
+ 'Referers_WidgetSearchEngines' => 'B&auml;sta s&ouml;kmotorerna',
+ 'Referers_WidgetOverview' => '&ouml;versikt',
+ 'SitesManager_Sites' => 'Webbplatser',
+ 'SitesManager_WebsitesManagement' => 'Webbplatser',
+ 'SitesManager_MainDescription' => 'Dina analyser beh&ouml;ver webbplatser! L&auml;gg till, uppdatera, radera webbplatser och visa Javascript-kod att l&auml;gga till p&aring; dina sidor.',
+ 'SitesManager_JsCode' => 'Javascript-kod',
+ 'SitesManager_JsCodeHelp' => 'H&auml;r &auml;r javascript-koden som ska l&auml;ggas in p&aring; alla dina sidor',
+ 'SitesManager_ShowJsCode' => 'Visa kod',
+ 'SitesManager_NoWebsites' => 'Do har inga webbplatser att administrera',
+ 'SitesManager_AddSite' => 'L&auml;gg till webbplats',
+ 'SitesManager_Id' => 'Id',
+ 'SitesManager_Name' => 'Namn',
+ 'SitesManager_Urls' => 'URLer',
+ 'SitesManager_MenuSites' => 'Webbplatser',
+ 'SitesManager_DeleteConfirm_js' => '&Auml;r du s&auml;ker p&aring; att du vill radera webbplatsen %s?',
+ 'SitesManager_ExceptionDeleteSite' => 'Det g&aring;r inte att radera den h&auml;r webbplatsen eftersom det &auml;r den enda registrerade. L&auml;gg till en ny webbplats f&ouml;rst, radera d&auml;refter den h&auml;r.',
+ 'SitesManager_ExceptionNoUrl' => 'Du m&aring;ste ange minst en URL f&ouml;r webbplatsen',
+ 'SitesManager_ExceptionEmptyName' => 'Webbplatsen m&aring;ste ha ett namn',
+ 'SitesManager_ExceptionInvalidUrl' => '\'%s\' &auml;r inte en giltig URL.',
+ 'TranslationsAdmin_MenuTranslations' => '&ouml;vers&auml;ttningar',
+ 'TranslationsAdmin_MenuLanguages' => 'Spr&aring;k',
+ 'TranslationsAdmin_Plugin' => 'Till&auml;gg',
+ 'TranslationsAdmin_Definition' => 'Definition',
+ 'TranslationsAdmin_DefaultString' => 'Standardstr&auml;ng (Engelska)',
+ 'TranslationsAdmin_TranslationString' => '&ouml;vers&auml;ttningsstr&auml;ng (nuvarande spr&aring;k: %s)',
+ 'TranslationsAdmin_Translations' => '&ouml;vers&auml;ttningar',
+ 'TranslationsAdmin_FixPermissions' => 'Var v&auml;nlig att r&auml;tta till filsystemets r&auml;ttigheter',
+ 'TranslationsAdmin_AvailableLanguages' => 'Tillg&auml;ngliga spr&aring;k',
+ 'TranslationsAdmin_AddLanguage' => 'L&auml;gg till spr&aring;k',
+ 'TranslationsAdmin_LanguageCode' => 'Spr&aring;kkod',
+ 'TranslationsAdmin_Export' => 'Exportera spr&aring;k',
+ 'TranslationsAdmin_Import' => 'Importera spr&aring;k',
+ 'UserCountry_Country' => 'Land',
+ 'UserCountry_Continent' => 'Kontinent',
+ 'UserCountry_DistinctCountries' => '%s kontinenter',
+ 'UserCountry_SubmenuLocations' => 'Platser',
+ 'UserCountry_WidgetContinents' => 'Bes&ouml;karkontinenter',
+ 'UserCountry_WidgetCountries' => 'Bes&ouml;karl&auml;nder',
+ 'UserCountry_country_ac' => 'Ascension',
+ 'UserCountry_country_ad' => 'Andorra',
+ 'UserCountry_country_ae' => 'F&ouml;renade arabemiraten',
+ 'UserCountry_country_af' => 'Afghanistan',
+ 'UserCountry_country_ag' => 'Antigua och Barbuda',
+ 'UserCountry_country_ai' => 'Anguilla',
+ 'UserCountry_country_al' => 'Albanien',
+ 'UserCountry_country_am' => 'Armenien',
+ 'UserCountry_country_an' => 'Nederl&auml;ndska Antillerna',
+ 'UserCountry_country_ao' => 'Angola',
+ 'UserCountry_country_aq' => 'Antarktis',
+ 'UserCountry_country_ar' => 'Argentina',
+ 'UserCountry_country_as' => 'Amerikanska Samoa',
+ 'UserCountry_country_at' => '&ouml;sterrike',
+ 'UserCountry_country_au' => 'Australien',
+ 'UserCountry_country_aw' => 'Aruba',
+ 'UserCountry_country_az' => 'Azerbajdzjan',
+ 'UserCountry_country_ba' => 'Bosnien och Hercegovina',
+ 'UserCountry_country_bb' => 'Barbados',
+ 'UserCountry_country_bd' => 'Bangladesh',
+ 'UserCountry_country_be' => 'Belgien',
+ 'UserCountry_country_bf' => 'Burkina Faso',
+ 'UserCountry_country_bg' => 'Bulgarien',
+ 'UserCountry_country_bh' => 'Bahrain',
+ 'UserCountry_country_bi' => 'Burundi',
+ 'UserCountry_country_bj' => 'Benin',
+ 'UserCountry_country_bm' => 'Bermuda',
+ 'UserCountry_country_bn' => 'Brunei',
+ 'UserCountry_country_bo' => 'Bolivia',
+ 'UserCountry_country_br' => 'Brasilien',
+ 'UserCountry_country_bs' => 'Bahamas',
+ 'UserCountry_country_bt' => 'Bhutan',
+ 'UserCountry_country_bv' => 'Bouvet&ouml;n',
+ 'UserCountry_country_bw' => 'Botswana',
+ 'UserCountry_country_by' => 'Vitryssland',
+ 'UserCountry_country_bz' => 'Belize',
+ 'UserCountry_country_ca' => 'Kanada',
+ 'UserCountry_country_cc' => 'Kokos&ouml;arna',
+ 'UserCountry_country_cd' => 'Kongo-Kinshasa',
+ 'UserCountry_country_cf' => 'Centralafrikanska republiken',
+ 'UserCountry_country_cg' => 'Republiken Kongo',
+ 'UserCountry_country_ch' => 'Schweiz',
+ 'UserCountry_country_ci' => 'Elfenbenskusten',
+ 'UserCountry_country_ck' => 'Cook&ouml;arna',
+ 'UserCountry_country_cl' => 'Chile',
+ 'UserCountry_country_cm' => 'Kamerun',
+ 'UserCountry_country_cn' => 'Kina',
+ 'UserCountry_country_co' => 'Colombia',
+ 'UserCountry_country_cr' => 'Costa Rica',
+ 'UserCountry_country_cs' => 'Serbien och Montenegro',
+ 'UserCountry_country_cu' => 'Kuba',
+ 'UserCountry_country_cv' => 'Kap Verde',
+ 'UserCountry_country_cx' => 'Jul&ouml;n',
+ 'UserCountry_country_cy' => 'Cypern',
+ 'UserCountry_country_cz' => 'Tjeckien',
+ 'UserCountry_country_de' => 'Tyskland',
+ 'UserCountry_country_dj' => 'Djibouti',
+ 'UserCountry_country_dk' => 'Danmark',
+ 'UserCountry_country_dm' => 'Dominica',
+ 'UserCountry_country_do' => 'Dominikanska republiken',
+ 'UserCountry_country_dz' => 'Algeriet',
+ 'UserCountry_country_ec' => 'Ecuador',
+ 'UserCountry_country_ee' => 'Estland',
+ 'UserCountry_country_eg' => 'Egypten',
+ 'UserCountry_country_eh' => 'V&auml;stsahara',
+ 'UserCountry_country_er' => 'Eritrea',
+ 'UserCountry_country_es' => 'Spanien',
+ 'UserCountry_country_et' => 'Etiopien',
+ 'UserCountry_country_fi' => 'Finland',
+ 'UserCountry_country_fj' => 'Fiji',
+ 'UserCountry_country_fk' => 'Falklands&ouml;arna',
+ 'UserCountry_country_fm' => 'Mikronesiens federerade stater',
+ 'UserCountry_country_fo' => 'F&auml;r&ouml;arna',
+ 'UserCountry_country_fr' => 'Frankrike',
+ 'UserCountry_country_ga' => 'Gabon',
+ 'UserCountry_country_gd' => 'Grenada',
+ 'UserCountry_country_ge' => 'Georgien',
+ 'UserCountry_country_gf' => 'Franska Guyana',
+ 'UserCountry_country_gg' => 'Guernsey',
+ 'UserCountry_country_gh' => 'Ghana',
+ 'UserCountry_country_gi' => 'Gibraltar',
+ 'UserCountry_country_gl' => 'Gr&ouml;nland',
+ 'UserCountry_country_gm' => 'Gambia',
+ 'UserCountry_country_gn' => 'Guinea',
+ 'UserCountry_country_gp' => 'Guadeloupe',
+ 'UserCountry_country_gq' => 'Ekvatorialguinea',
+ 'UserCountry_country_gr' => 'Grekland',
+ 'UserCountry_country_gs' => 'Sydgeorgien',
+ 'UserCountry_country_gt' => 'Guatemala',
+ 'UserCountry_country_gu' => 'Guam',
+ 'UserCountry_country_gw' => 'Guinea-Bissau',
+ 'UserCountry_country_gy' => 'Guyana',
+ 'UserCountry_country_hk' => 'Hong Kong',
+ 'UserCountry_country_hm' => 'Heard- och McDonalds&ouml;arna',
+ 'UserCountry_country_hn' => 'Honduras',
+ 'UserCountry_country_hr' => 'Kroatien',
+ 'UserCountry_country_ht' => 'Haiti',
+ 'UserCountry_country_hu' => 'Ungern',
+ 'UserCountry_country_id' => 'Indonesien',
+ 'UserCountry_country_ie' => 'Irland',
+ 'UserCountry_country_il' => 'Israel',
+ 'UserCountry_country_im' => 'Isle of Man',
+ 'UserCountry_country_in' => 'Indien',
+ 'UserCountry_country_io' => 'Brittiska territoriet i Indiska oceanen',
+ 'UserCountry_country_iq' => 'Irak',
+ 'UserCountry_country_ir' => 'Iran',
+ 'UserCountry_country_is' => 'Island',
+ 'UserCountry_country_it' => 'Italien',
+ 'UserCountry_country_je' => 'Jersey',
+ 'UserCountry_country_jm' => 'Jamaica',
+ 'UserCountry_country_jo' => 'Jordanien',
+ 'UserCountry_country_jp' => 'Japan',
+ 'UserCountry_country_ke' => 'Kenya',
+ 'UserCountry_country_kg' => 'Kirgizistan',
+ 'UserCountry_country_kh' => 'Kambodja',
+ 'UserCountry_country_ki' => 'Kiribati',
+ 'UserCountry_country_km' => 'Komorerna',
+ 'UserCountry_country_kn' => 'Saint Christopher och Nevis',
+ 'UserCountry_country_kp' => 'Nordkorea',
+ 'UserCountry_country_kr' => 'Sydkorea',
+ 'UserCountry_country_kw' => 'Kuwait',
+ 'UserCountry_country_ky' => 'Cayman&ouml;arna',
+ 'UserCountry_country_kz' => 'Kazakstan',
+ 'UserCountry_country_la' => 'Laos',
+ 'UserCountry_country_lb' => 'Libanon',
+ 'UserCountry_country_lc' => 'Saint Lucia',
+ 'UserCountry_country_li' => 'Liechtenstein',
+ 'UserCountry_country_lk' => 'Sri Lanka',
+ 'UserCountry_country_lr' => 'Liberia',
+ 'UserCountry_country_ls' => 'Lesotho',
+ 'UserCountry_country_lt' => 'Litauen',
+ 'UserCountry_country_lu' => 'Luxemburg',
+ 'UserCountry_country_lv' => 'Lettland',
+ 'UserCountry_country_ly' => 'Libyen',
+ 'UserCountry_country_ma' => 'Marocko',
+ 'UserCountry_country_mc' => 'Monaco',
+ 'UserCountry_country_md' => 'Moldavien',
+ 'UserCountry_country_mg' => 'Madagaskar',
+ 'UserCountry_country_mh' => 'Marshall&ouml;arna',
+ 'UserCountry_country_mk' => 'Makedonien',
+ 'UserCountry_country_ml' => 'Mali',
+ 'UserCountry_country_mm' => 'Myanmar',
+ 'UserCountry_country_mn' => 'Mongoliet',
+ 'UserCountry_country_mo' => 'Macao',
+ 'UserCountry_country_mp' => 'Nordmarianerna',
+ 'UserCountry_country_mq' => 'Martinique',
+ 'UserCountry_country_mr' => 'Mauretanien',
+ 'UserCountry_country_ms' => 'Montserrat',
+ 'UserCountry_country_mt' => 'Malta',
+ 'UserCountry_country_mu' => 'Mauritius',
+ 'UserCountry_country_mv' => 'Maldiverna',
+ 'UserCountry_country_mw' => 'Malawi',
+ 'UserCountry_country_mx' => 'Mexiko',
+ 'UserCountry_country_my' => 'Malaysia',
+ 'UserCountry_country_mz' => 'Moçambique',
+ 'UserCountry_country_na' => 'Namibia',
+ 'UserCountry_country_nc' => 'Nya Kaledonien',
+ 'UserCountry_country_ne' => 'Niger',
+ 'UserCountry_country_nf' => 'Norfolk&ouml;n',
+ 'UserCountry_country_ng' => 'Nigeria',
+ 'UserCountry_country_ni' => 'Nicaragua',
+ 'UserCountry_country_nl' => 'Nederl&auml;nderna',
+ 'UserCountry_country_no' => 'Norge',
+ 'UserCountry_country_np' => 'Nepal',
+ 'UserCountry_country_nr' => 'Nauru',
+ 'UserCountry_country_nu' => 'Niue',
+ 'UserCountry_country_nz' => 'Nya Zeeland',
+ 'UserCountry_country_om' => 'Oman',
+ 'UserCountry_country_pa' => 'Panama',
+ 'UserCountry_country_pe' => 'Peru',
+ 'UserCountry_country_pf' => 'Franska Polynesien',
+ 'UserCountry_country_pg' => 'Papua Nya Guinea',
+ 'UserCountry_country_ph' => 'Filippinerna',
+ 'UserCountry_country_pk' => 'Pakistan',
+ 'UserCountry_country_pl' => 'Polen',
+ 'UserCountry_country_pm' => 'Saint-Pierre och Miquelon',
+ 'UserCountry_country_pn' => 'Pitcairn&ouml;arna',
+ 'UserCountry_country_pr' => 'Puerto Rico',
+ 'UserCountry_country_ps' => 'Palestina',
+ 'UserCountry_country_pt' => 'Portugal',
+ 'UserCountry_country_pw' => 'Palau',
+ 'UserCountry_country_py' => 'Paraguay',
+ 'UserCountry_country_qa' => 'Qatar',
+ 'UserCountry_country_re' => 'Réunion',
+ 'UserCountry_country_ro' => 'Rum&auml;nien',
+ 'UserCountry_country_ru' => 'Ryssland',
+ 'UserCountry_country_rs' => 'Serbien',
+ 'UserCountry_country_rw' => 'Rwanda',
+ 'UserCountry_country_sa' => 'Saudiarabien',
+ 'UserCountry_country_sb' => 'Salomon&ouml;arna',
+ 'UserCountry_country_sc' => 'Seychellerna',
+ 'UserCountry_country_sd' => 'Sudan',
+ 'UserCountry_country_se' => 'Sverige',
+ 'UserCountry_country_sg' => 'Singapore',
+ 'UserCountry_country_sh' => 'Sankt Helena',
+ 'UserCountry_country_si' => 'Slovenien',
+ 'UserCountry_country_sj' => 'Svalbard',
+ 'UserCountry_country_sk' => 'Slovakien',
+ 'UserCountry_country_sl' => 'Sierra Leone',
+ 'UserCountry_country_sm' => 'San Marino',
+ 'UserCountry_country_sn' => 'Senegal',
+ 'UserCountry_country_so' => 'Somalia',
+ 'UserCountry_country_sr' => 'Surinam',
+ 'UserCountry_country_st' => 'São Tomé och Príncipe',
+ 'UserCountry_country_su' => 'Sovjetunionen',
+ 'UserCountry_country_sv' => 'El Salvador',
+ 'UserCountry_country_sy' => 'Syrien',
+ 'UserCountry_country_sz' => 'Swaziland',
+ 'UserCountry_country_tc' => 'Turks- och Caicos&ouml;arna',
+ 'UserCountry_country_td' => 'Tchad',
+ 'UserCountry_country_tf' => 'Franska sydterritorierna',
+ 'UserCountry_country_tg' => 'Togo',
+ 'UserCountry_country_th' => 'Thailand',
+ 'UserCountry_country_tj' => 'Tadzjikistan',
+ 'UserCountry_country_tk' => 'Tokelau&ouml;arna',
+ 'UserCountry_country_tm' => 'Turkmenistan',
+ 'UserCountry_country_tn' => 'Tunisien',
+ 'UserCountry_country_to' => 'Tonga',
+ 'UserCountry_country_tp' => '&ouml;sttimor',
+ 'UserCountry_country_tr' => 'Turkiet',
+ 'UserCountry_country_tt' => 'Trinidad och Tobago',
+ 'UserCountry_country_tv' => 'Tuvalu',
+ 'UserCountry_country_tw' => 'Taiwan',
+ 'UserCountry_country_tz' => 'Tanzania',
+ 'UserCountry_country_ua' => 'Ukraina',
+ 'UserCountry_country_ug' => 'Uganda',
+ 'UserCountry_country_uk' => 'Storbritannien',
+ 'UserCountry_country_gb' => 'Storbritannien',
+ 'UserCountry_country_um' => 'F&ouml;renta staternas avl&auml;gset bel&auml;gna &ouml;ar',
+ 'UserCountry_country_us' => 'USA',
+ 'UserCountry_country_uy' => 'Uruguay',
+ 'UserCountry_country_uz' => 'Uzbekistan',
+ 'UserCountry_country_va' => 'Vatikanstaten',
+ 'UserCountry_country_vc' => 'Saint Vincent och Grenadinerna',
+ 'UserCountry_country_ve' => 'Venezuela',
+ 'UserCountry_country_vg' => 'Brittiska Jungfru&ouml;arna',
+ 'UserCountry_country_vi' => 'Amerikanska Jungfru&ouml;arna',
+ 'UserCountry_country_vn' => 'Vietnam',
+ 'UserCountry_country_vu' => 'Vanuatu',
+ 'UserCountry_country_wf' => 'Wallis- och Futuna&ouml;arna',
+ 'UserCountry_country_ws' => 'Samoa',
+ 'UserCountry_country_ye' => 'Jemen',
+ 'UserCountry_country_yt' => 'Mayotte',
+ 'UserCountry_country_yu' => 'Jugoslavien',
+ 'UserCountry_country_za' => 'Sydafrika',
+ 'UserCountry_country_zm' => 'Zambia',
+ 'UserCountry_country_zr' => 'Zaire',
+ 'UserCountry_country_zw' => 'Zimbabwe',
+ 'UserCountry_continent_eur' => 'Europeiska unionen',
+ 'UserCountry_continent_afr' => 'Afrika',
+ 'UserCountry_continent_asi' => 'Asien',
+ 'UserCountry_continent_ams' => 'Syd- och Centralamerika',
+ 'UserCountry_continent_amn' => 'Nordamerika',
+ 'UserCountry_continent_oce' => 'Oceanien',
+ 'UserSettings_BrowserFamilies' => 'Webbl&auml;sarfamiljer',
+ 'UserSettings_Browsers' => 'Webbl&auml;sare',
+ 'UserSettings_Plugins' => 'Till&auml;gg',
+ 'UserSettings_Configurations' => 'Konfigurationer',
+ 'UserSettings_OperatinsSystems' => 'Operativsystem',
+ 'UserSettings_Resolutions' => 'Sk&auml;rmuppl&ouml;sning',
+ 'UserSettings_WideScreen' => 'Wide Screen',
+ 'UserSettings_WidgetResolutions' => 'Sk&auml;rmuppl&ouml;sning',
+ 'UserSettings_WidgetBrowsers' => 'Webbl&auml;sare',
+ 'UserSettings_WidgetPlugins' => 'Lista med till&auml;gg',
+ 'UserSettings_WidgetWidescreen' => 'Normal / Widescreen',
+ 'UserSettings_WidgetBrowserFamilies' => 'Webbl&auml;sare efter familj',
+ 'UserSettings_WidgetOperatingSystems' => 'Operativsystem',
+ 'UserSettings_WidgetGlobalVisitors' => 'Konfigurationer',
+ 'UserSettings_SubmenuSettings' => 'Inst&auml;llningar',
+ 'UsersManager_UsersManagement' => 'Anv&auml;ndarhantering',
+ 'UsersManager_UsersManagementMainDescription' => 'Skapa nya eller redigera befintliga anv&auml;ndare. D&auml;refter kan du st&auml;lla in deras r&auml;ttigheter h&auml;r ovanf&ouml;r.',
+ 'UsersManager_ManageAccess' => 'Hantera r&auml;ttigheter',
+ 'UsersManager_MainDescription' => 'Best&auml;m vilka anv&auml;ndare som ska ha tillg&aring;ng till analyserna p&aring; din webbplats. Du kan ocks&aring; st&auml;lla in r&auml;ttigheterna f&ouml;r alla webbplatser p&aring; en g&aring;ng.',
+ 'UsersManager_Sites' => 'Webbplatser',
+ 'UsersManager_AllWebsites' => 'Alla webbplatser',
+ 'UsersManager_ApplyToAllWebsites' => 'Verkst&auml;ll p&aring; alla webbplatser',
+ 'UsersManager_User' => 'Anv&auml;ndare',
+ 'UsersManager_PrivNone' => 'Ingen beh&ouml;righet',
+ 'UsersManager_PrivView' => 'Visa',
+ 'UsersManager_PrivAdmin' => 'Admin',
+ 'UsersManager_ChangeAllConfirm' => '&Auml;r du s&auml;ker p&aring; att du vill &auml;ndra r&auml;ttigheterna f&ouml;r \'%s\' p&aring; alla webbplatser?',
+ 'UsersManager_Login' => 'Anv&auml;ndarnamn',
+ 'UsersManager_Password' => 'L&ouml;senord',
+ 'UsersManager_Email' => 'E-post',
+ 'UsersManager_Alias' => 'Alias',
+ 'UsersManager_Token' => 'token_auth',
+ 'UsersManager_Edit' => '&Auml;ndra',
+ 'UsersManager_AddUser' => 'L&auml;gg till en ny anv&auml;ndare',
+ 'UsersManager_MenuUsers' => 'Anv&auml;ndare',
+ 'UsersManager_DeleteConfirm_js' => '&Auml;r du s&auml;ker p&aring; att du vill radera \'%s\'?',
+ 'UsersManager_ExceptionLoginExists' => 'Anv&auml;ndarnamnet \'%s\' finns redan.',
+ 'UsersManager_ExceptionEmailExists' => 'En anv&auml;ndare med e-postadressen \'%s\' finns redan.',
+ 'UsersManager_ExceptionInvalidLogin' => 'Anv&auml;ndarnamnet f&aring;r endast best&aring; av bokst&auml;ver, siffror eller tecknen \'_\' eller \'-\' eller \'.\'',
+ 'UsersManager_ExceptionInvalidPassword' => 'L&ouml;senordet m&aring;ste ha en l&auml;ngd mellan 6 och 26 tecken.',
+ 'UsersManager_ExceptionInvalidEmail' => 'E-postadressen har inget giltigt format.',
+ 'UsersManager_ExceptionDeleteDoesNotExist' => 'Anv&auml;ndaren \'%s\' finns inte och kan d&auml;rf&ouml;r inte raderas.',
+ 'UsersManager_ExceptionAdminAnonymous' => 'Du kan inte ge anv&auml;ndaren \'anonymous\' administrat&ouml;rsr&auml;ttigheter.',
+ 'UsersManager_ExceptionEditAnonymous' => 'Den anonyma anv&auml;ndare kan inte redigeras eller tas bort. Den anv&auml;nds av Piwik f&ouml;r att definiera en anv&auml;ndare som inte har loggat in &auml;nnu. Till exempel kan du g&ouml;ra din statistik tillg&auml;nglig f&ouml;r allm&auml;nheten genom att ge \'anonymous\' r&auml;ttigheten \'visa\'.',
+ 'UsersManager_ExceptionUserDoesNotExist' => 'Anv&auml;ndaren \'%s\' finns inte.',
+ 'UsersManager_ExceptionAccessValues' => 'Parametern m&aring;ste ha en av f&ouml;ljande v&auml;rden: [ %s ]',
+ 'VisitFrequency_Evolution' => 'Utveckling &ouml;ver perioden',
+ 'VisitFrequency_ReturnVisits' => '%s &aring;terkommande bes&ouml;k',
+ 'VisitFrequency_ReturnActions' => '%s h&auml;ndelser av dom &aring;terkommande bes&ouml;ken',
+ 'VisitFrequency_ReturnMaxActions' => '%s h&auml;ndelser som mest i ett &aring;terkommande bes&ouml;k',
+ 'VisitFrequency_ReturnTotalTime' => '%s har spenderats av dom &aring;terkommande bes&ouml;ken',
+ 'VisitFrequency_ReturnBounces' => '%s g&aring;nger som en &aring;terkommande bes&ouml;kare har studsat (l&auml;mnat sidan efter en sidvisning)',
+ 'VisitFrequency_WidgetOverview' => 'Frekvens&ouml;versikt',
+ 'VisitFrequency_WidgetGraphReturning' => 'Diagram f&ouml;r &aring;terkommande bes&ouml;k',
+ 'VisitFrequency_SubmenuFrequency' => 'Frekvens',
+ 'VisitorInterest_VisitsPerDuration' => 'Tid per bes&ouml;k',
+ 'VisitorInterest_VisitsPerNbOfPages' => 'Sidvisningar per bes&ouml;k',
+ 'VisitorInterest_WidgetLengths' => 'Bes&ouml;ksl&auml;ngd',
+ 'VisitorInterest_WidgetPages' => 'Sidvisningar per bes&ouml;k',
+ 'VisitorInterest_SubmenuFrequencyLoyalty' => 'Frekvens och lojalitet',
+ 'VisitorInterest_PlusXMin' => '%s min',
+ 'VisitorInterest_BetweenXYMinutes' => '%1s-%2s min',
+ 'VisitorInterest_OnePage' => '1 sida',
+ 'VisitorInterest_NPages' => '%s sidor',
+ 'VisitorInterest_BetweenXYSeconds' => '%1s-%2ss',
+ 'VisitsSummary_NbVisits' => '%s bes&ouml;k',
+ 'VisitsSummary_NbUniqueVisitors' => '%s unika bes&ouml;kare',
+ 'VisitsSummary_NbActions' => '%s h&auml;ndelser (sidvisningar)',
+ 'VisitsSummary_TotalTime' => '%s har spenderats av bes&ouml;karna',
+ 'VisitsSummary_MaxNbActions' => '%s h&auml;ndelser som mest i ett bes&ouml;k',
+ 'VisitsSummary_NbBounced' => '%s bes&ouml;kare har studsat (l&auml;mnat sidan efter en sidvisning)',
+ 'VisitsSummary_Evolution' => 'Utveckling dom senaste 30 %sarna',
+ 'VisitsSummary_Report' => 'Rapport',
+ 'VisitsSummary_GenerateTime' => 'Sidan genererades p&aring; %s sekunder',
+ 'VisitsSummary_GenerateQueries' => '%s fr&aring;gor skickade',
+ 'VisitsSummary_WidgetLastVisits' => 'Senaste bes&ouml;ken',
+ 'VisitsSummary_WidgetVisits' => 'Bes&ouml;ks&ouml;versikt',
+ 'VisitsSummary_WidgetLastVisitors' => 'Senaste unika bes&ouml;ken',
+ 'VisitsSummary_WidgetOverviewGraph' => '&ouml;versikt med diagram',
+ 'VisitsSummary_SubmenuOverview' => '&ouml;versikt',
+ 'VisitTime_LocalTime' => 'Bes&ouml;k efter lokal tid',
+ 'VisitTime_ServerTime' => 'Bes&ouml;k efter servertid',
+ 'VisitTime_WidgetLocalTime' => 'Bes&ouml;k efter lokal tid',
+ 'VisitTime_WidgetServerTime' => 'Bes&ouml;k efter servertid',
+ 'VisitTime_SubmenuTimes' => 'Tider',
+ 'VisitTime_NHour' => '%sh',
+); \ No newline at end of file
diff --git a/lang/tw.php b/lang/tw.php
index 12373884fd..b814a4f11e 100644
--- a/lang/tw.php
+++ b/lang/tw.php
@@ -12,7 +12,7 @@ $translations = array(
'General_Widgets' => '器件',
'General_Settings' => '設定值',
'General_GiveUsYourFeedback' => '給我們反饋意見!',
- 'General_Unknown' => '未知的',
+ 'General_Unknown' => '不明的',
'General_Required' => '%s 個請求數',
'General_Error' => '錯誤',
'General_Warning' => '警告',
@@ -44,10 +44,14 @@ $translations = array(
'General_ColumnActionsPerVisit' => '各個造訪的活動數',
'General_ColumnAvgTimeOnSite' => '在網站上停留的平均時間',
'General_ColumnBounceRate' => '單頁造訪率',
+ 'General_ColumnPageviews' => '頁面瀏覽數',
+ 'General_ColumnUniquePageviews' => '絕對獨一頁面瀏覽數',
'General_Save' => '儲存',
'General_Website' => '網站',
'General_NoDataForGraph' => '無資料提供此繪圖',
'General_NoDataForTagCloud' => '無資料提供此標籤雲!',
+ 'General_DisplayNormalTable' => '顯示標準表格',
+ 'General_DisplayMoreData' => '顯示更多資料',
'General_PiwikIsACollaborativeProject' => "%s Piwik %s 是一個協同專案,並且現在仍處於 Beta 測試階段! %s 假如您想提供協助,請 %s 聯絡我們 %s!",
'General_YouAreCurrentlyViewingDemoOfPiwik' => "您目前正在檢視 %s 的展示;如有需要可 %s下載%s 完整版! 拜訪 %s",
'CorePluginsAdmin_Plugins' => '外掛',
@@ -59,9 +63,9 @@ $translations = array(
'CorePluginsAdmin_Status' => '狀態',
'CorePluginsAdmin_Action' => '動作',
'CorePluginsAdmin_PluginHomepage' => '外掛首頁',
- 'CorePluginsAdmin_Activated' => '已活動的',
- 'CorePluginsAdmin_Active' => '活動的',
- 'CorePluginsAdmin_Inactive' => '非活動的',
+ 'CorePluginsAdmin_Activated' => '已作用中',
+ 'CorePluginsAdmin_Active' => '作用中',
+ 'CorePluginsAdmin_Inactive' => '非作用中',
'CorePluginsAdmin_ActivatedHelp' => '此外掛無法被停用',
'CorePluginsAdmin_Deactivate' => '停用',
'CorePluginsAdmin_Activate' => '啟用',
@@ -138,14 +142,12 @@ $translations = array(
'Referers_Keywords' => '關鍵字',
'Referers_DirectEntry' => '直接連結項目',
'Referers_Websites' => '網站',
- 'Referers_Newsletters' => '電子快訊',
'Referers_Campaigns' => '廣告活動',
- 'Referers_Evolution' => '此段統計週期的發展趨勢',
+ 'Referers_Evolution' => '此統計期的發展趨勢',
'Referers_Type' => '轉介媒體類型',
'Referers_TypeDirectEntries' => '%s 個來自直接連結項目',
'Referers_TypeSearchEngines' => '%s 個來自搜尋引擎',
'Referers_TypeWebsites' => '%s 個來自網站',
- 'Referers_TypeNewsletters' => '%s 個來自電子快訊',
'Referers_TypeCampaigns' => '%s 個來自廣告活動',
'Referers_Other' => '其他的',
'Referers_OtherDistinctSearchEngines' => '%s 個不同的搜尋引擎',
@@ -452,7 +454,7 @@ $translations = array(
'VisitsSummary_WidgetLastVisitors' => '最近絕對獨一訪客繪圖',
'VisitsSummary_WidgetOverviewGraph' => '概觀繪圖',
'VisitsSummary_SubmenuOverview' => '概觀',
- 'VisitFrequency_Evolution' => '此段統計週期的發展趨勢',
+ 'VisitFrequency_Evolution' => '此統計期的發展趨勢',
'VisitFrequency_ReturnVisits' => '%s 個重返造訪數',
'VisitFrequency_ReturnActions' => '%s 個活動數由重返造訪所產生',
'VisitFrequency_ReturnMaxActions' => '%s 個由單一重返造訪所產生的最大活動數',
@@ -595,7 +597,7 @@ $translations = array(
'TranslationsAdmin_MenuLanguages' => '語系',
'TranslationsAdmin_Plugin' => '外掛程式',
'TranslationsAdmin_Definition' => '定義',
- 'TranslationsAdmin_DefaultString' => '預設字串 (English)',
+ 'TranslationsAdmin_DefaultString' => '預設字串 (英語)',
'TranslationsAdmin_TranslationString' => '翻譯字串 (目前的語系: %s)',
'TranslationsAdmin_Translations' => '翻譯',
'TranslationsAdmin_FixPermissions' => '請修正檔案系統權限',
diff --git a/misc/TODO b/misc/TODO
index f6db576935..41ed27986f 100644
--- a/misc/TODO
+++ b/misc/TODO
@@ -1,20 +1,47 @@
-Following up show all columns new UI element
-====
-$("td img", domElem).attr("src") is undefined
-[Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
-datatable.js (line 907)
-$("td img", domElem).attr("src") is undefined
-[Break on this error] var plusDetected = $('td img', domElem).attr('src').indexOf('plus') >= 0;
-when clicking MINUS on actions
-- icons disappear when showing all columns for browsers
-- exclude low population doesn't work for providers
+Before Alpha
+------------
+
+3h - small bugs report in robotrock, new search engines, etc.
+1h - release
+
+To fix
+======
+- <idsubdatatable>1</idsubdatatable> shouldnt be in api response
+- when used with visitsGenerator, in dowloads export XML, full_url and url is 0
+- post 29 There seems not to be a way to export the pages information widget.
+ I wanted to download the entry pages to see where my visitors entered my site from,
+ but there is no option to do so.
- ADD forward of non true show_values to forward when specified from URL to ajax
- disable show icon in some iframes and/or dashboard
-- do proper CSS factoring
- clarify 'false' '0' values etc. //convert all JS datatable footer parameter values to '1' or '0'
-- check state of javascript footer (should not have safe_decode and filter_add_columns blah)
-- set custom truncation limit per datatable type (simple VS allColumns, and subtable) ->bug display subtable icon is cut (see truncation limit)
-- Blog post!
+- cron should return errors when token doesn't have any website
+
+Bugs
+====
+- actions for year seems to not load (memory issue?)
+- all graphic showing data evolution are labelled with the text &quot;nb_uniq_visitors&quot;
+ no matter if youre watching last visits graph, global visits graph or any other.
+ Its happening in every graph under Visitors subpages and in the Dashboard.
+- In Referers-&gt;Evolution page, in addition, I think its melting titles because I read
+ in spanish &quot;Entrada directa nb_uniq_visitors&quot; for the first graph,
+ &quot;Paginas web nb_uniq_visitors&quot; for the second and so on.
+- exclude all population doesn't work for actions
+
+Reports improvements
+====================
+- add new column "overall visits with conversion"
+- add visits with conversion sparkline in VisitsSummary overview
+- add link under widgets to report (optional display)
+- link under goal conversion to full goal reports (optional display)
+- think of ways to show entry / exit pages and bounce rate.
+- show unique visitors when available, otherwise show nb_visits by default
+- bounce count should be bounce rate
+- idem in 222 times that a returning visit has bounced (left the site after one page)
+- show new vs returning more clearly in UI
+- see also #421
+- add "days since last visit"
+- add "visit count until conversion"
+- add best search engines, keywords, campaigns, websites in referers overview
Test page
==========
@@ -25,63 +52,41 @@ Test page
- without footer
- without all columns icon
-UI fixes + adjustements
-====
-- keep referers logs lines used for XSXS referer injection attack
-- write test to make sure deployement don't include logger in file/db/etc
-- write test to check disabled db plugin default
-- show total size in MB in db plugin
-- search inside datatable doesnt really work eg. "web analytics" restore regex search
-- bounce count should be bounce rate
-- idem in 222 times that a returning visit has bounced (left the site after one page)
-- show new vs returning more clearly in UI
-- calendar CSS on API page
-- WRONG::: 147 sites Internet différents (utilisant 147 différentes adresses)
-- see also #421
-
-check phpmyvisites piwik analytics sur delicious
-check analytics books
-
high priority features
====
-- tester clickheat http://www.labsmedia.com/clickheat/piwik-clickheat.tar.gz + add FAQ
-- sync update + email install
- Goal tracking
+- tester clickheat http://www.labsmedia.com/clickheat/piwik-clickheat.tar.gz + add FAQ
+- sync update + email install + automatic update
- Live!
- simple MultiSites report plugin.
- new JS tagging API
- Exclude webmaster
- Loyalty (Most people visited: 1 times) and Recency (Most people last visited: X days ago)
+ http://en.wikipedia.org/wiki/RFM
+
+User Interface improvements
+===========================
+- add icon calendar http://developer.yahoo.com/ypatterns/pattern.php?pattern=calendar#Solution
+- something is wrong in JS calendar when year selected
-UI elements:
-====
-- add link under widgets to report (optional display)
-- link under goal conversion to full goal reports (optional display)
-- think of ways to show entry / exit pages and bounce rate.
-- show unique visitors when available, otherwise show nb_visits by default
-
-website
+piwik.org
====
- 404 more useful
-- provide changelog + rss feed for new versions
+- fix Piwik changelog
- www.piwik.org/demo/ is 404
-Bugs
-- add icon calendar http://developer.yahoo.com/ypatterns/pattern.php?pattern=calendar#Solution
-- something is wrong in JS calendar when year selected
-- I had to chmod 777 tmp/ to pass install
-all graphic showing data evolution are labelled with the text &quot;nb_uniq_visitors&quot; no matter if youre watching last visits graph, global visits graph or any other. Its happening in every graph under Visitors subpages and in the Dashboard.
-In Referers-&gt;Evolution page, in addition, I think its melting titles because I read in spanish &quot;Entrada directa nb_uniq_visitors&quot; for the first graph, &quot;Paginas web nb_uniq_visitors&quot; for the second and so on.
-
-To clean
+Code improvements
+=================
- plugins should listen to user delete/ site delete and delete their own user/site related data
- why widgetize inherits Piwik_Widgetize_Controller
-- PLUGINS HAVE THEIR OWN TESTS
+- plugins could have their own tests, read automatically from the test suite
Documentation
+=============
- postEvent smarty doc is not clear, + feature we're not using (filter but what we need is simply way to print out html in templates from plugins)
Live! plugin
+============
- api propre
- html
- jquery spy
diff --git a/misc/generateVisits.php b/misc/generateVisits.php
index f8984199e8..38774e0d00 100644
--- a/misc/generateVisits.php
+++ b/misc/generateVisits.php
@@ -3,10 +3,10 @@
* The script can be used to generate huge number of visits and actions
* for a given number of days.
*/
-$minVisitors = 500;
-$maxVisitors = 1000;
+$minVisitors = 200;
+$maxVisitors = 200;
$nbActions = 3;
-$daysToCompute = 1;
+$daysToCompute = 10;
//-----------------------------------------------------------------------------
error_reporting(E_ALL|E_NOTICE);
@@ -46,6 +46,7 @@ require_once "Tracker/Action.php";
require_once "Tracker/Db.php";
require_once "Tracker/Visit.php";
require_once "Tracker/Generator.php";
+require_once "Tracker/GoalManager.php";
//Piwik_PluginsManager::getInstance()->unloadPlugins();
@@ -73,6 +74,7 @@ while($startTime <= time())
$visitors = rand($minVisitors, $maxVisitors);
$actions = $nbActions;
$generator->setTimestampToUse($startTime);
+
$nbActionsTotalThisDay = $generator->generate($visitors, $actions);
$actionsPerVisit = round($nbActionsTotalThisDay / $visitors);
print("Generated $visitors unique visitors and $actionsPerVisit actions per visit for the ".date("Y-m-d", $startTime)."<br>\n");
diff --git a/misc/iframeWidget.htm b/misc/iframeWidget.htm
index 66c7decef9..ee070bb8f5 100644
--- a/misc/iframeWidget.htm
+++ b/misc/iframeWidget.htm
@@ -1,6 +1,6 @@
-<html>
+<html>
<body>
-<h3 style="color:#143974">Embedding the Piwik Country widget in an Iframe</h3>
-<div id="widgetIframe"><iframe width="500" height="350" src="http://piwik.org/demo/index.php?module=Widgetize&action=iframe&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry&idSite=1&period=day&date=yesterday&disableLink=1" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>
-
+<h3 style="color:#143974">Embedding the Piwik Country widget in an Iframe</h3>
+<div id="widgetIframe"><iframe width="500" height="350" src="http://piwik.org/demo/index.php?module=Widgetize&action=iframe&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry&idSite=1&period=day&date=yesterday&disableLink=1" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>
+
</body></html> \ No newline at end of file
diff --git a/misc/iframeWidget_localhost.htm b/misc/iframeWidget_localhost.htm
new file mode 100644
index 0000000000..e45598f34a
--- /dev/null
+++ b/misc/iframeWidget_localhost.htm
@@ -0,0 +1,7 @@
+<html>
+<body>
+<h3 style="color:#143974">Embedding the Piwik Country widget in an Iframe</h3>
+<div id="widgetIframe"><iframe width="500" height="350"
+src="http://localhost/trunk/index.php?module=Widgetize&action=iframe&moduleToWidgetize=UserCountry&actionToWidgetize=getCountry&idSite=1&period=day&date=2008-11-17&disableLink=1" scrolling="no" frameborder="0" marginheight="0" marginwidth="0"></iframe></div>
+
+</body></html> \ No newline at end of file
diff --git a/misc/testJavascriptTracker/index.php b/misc/testJavascriptTracker/index.php
index 8361e50375..1de9ff8de3 100644
--- a/misc/testJavascriptTracker/index.php
+++ b/misc/testJavascriptTracker/index.php
@@ -52,4 +52,4 @@ piwik_log(piwik_action_name, piwik_idsite,piwik_url);
</script><object>
<noscript><p>Web analytics <img src="<?php echo $urlPiwik; ?>/piwik.php" style="border:0" alt="piwik"/></p>
</noscript></object></a>
-<!-- /Piwik --> \ No newline at end of file
+<!-- /Piwik -->
diff --git a/piwik.php b/piwik.php
index 413ef7d147..94186c952c 100644
--- a/piwik.php
+++ b/piwik.php
@@ -8,7 +8,7 @@
*/
error_reporting(E_ALL|E_NOTICE);
-define('PIWIK_INCLUDE_PATH', '.');
+define('PIWIK_INCLUDE_PATH', dirname(__FILE__));
@ignore_user_abort(true);
set_include_path(PIWIK_INCLUDE_PATH
@@ -25,6 +25,7 @@ require_once "Tracker/Action.php";
require_once "Cookie.php";
require_once "Tracker/Db.php";
require_once "Tracker/Visit.php";
+require_once "Tracker/GoalManager.php";
$GLOBALS['DEBUGPIWIK'] = false;
diff --git a/plugins/API/Controller.php b/plugins/API/Controller.php
index 60602f585e..8eb442cca1 100644
--- a/plugins/API/Controller.php
+++ b/plugins/API/Controller.php
@@ -10,7 +10,7 @@
*/
require_once "API/Request.php";
-
+require_once "API/DocumentationGenerator.php";
/**
*
@@ -26,36 +26,19 @@ class Piwik_API_Controller extends Piwik_Controller
public function listAllMethods()
{
- $this->init();
- echo Piwik_API_Proxy::getInstance()->getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = Piwik_Common::getRequestVar('prefixUrl', '') );
+ $ApiDocumentation = new Piwik_API_DocumentationGenerator();
+ echo $ApiDocumentation->getAllInterfaceString( $outputExampleUrls = true, $prefixUrls = Piwik_Common::getRequestVar('prefixUrl', '') );
}
public function listAllAPI()
{
$view = new Piwik_View("API/templates/listAllAPI.tpl");
$this->setGeneralVariablesView($view);
- $view->countLoadedAPI = $this->init();
- $view->list_api_methods_with_links = Piwik_API_Proxy::getInstance()->getAllInterfaceString();
- echo $view->render();
- }
-
- protected function init()
- {
- $plugins = Piwik_PluginsManager::getInstance()->getLoadedPluginsName();
- $loaded = 0;
- foreach( $plugins as $plugin )
- {
- $plugin = Piwik::unprefixClass($plugin);
-
- try {
- Piwik_API_Proxy::getInstance()->registerClass($plugin);
- $loaded++;
- }
- catch(Exception $e){
- }
- }
- return $loaded;
+ $ApiDocumentation = new Piwik_API_DocumentationGenerator();
+ $view->countLoadedAPI = Piwik_API_Proxy::getInstance()->getCountRegisteredClasses();
+ $view->list_api_methods_with_links = $ApiDocumentation->getAllInterfaceString();
+ echo $view->render();
}
}
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index 42996b7a53..57c3afa6fe 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -18,7 +18,7 @@ require_once "Actions.php";
*
* @package Piwik_Actions
*/
-class Piwik_Actions_API extends Piwik_Apiable
+class Piwik_Actions_API
{
static private $instance = null;
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index 40e167bd38..50e1d04345 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -1,21 +1,21 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_Actions
- */
-
-/**
- *
- * @package Piwik_Actions
- */
-class Piwik_Actions extends Piwik_Plugin
-{
- static protected $actionCategoryDelimiter = null;
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_Actions
+ */
+
+/**
+ *
+ * @package Piwik_Actions
+ */
+class Piwik_Actions extends Piwik_Plugin
+{
+ static protected $actionCategoryDelimiter = null;
static protected $limitLevelSubCategory = 10;
public function getInformation()
@@ -41,309 +41,310 @@ class Piwik_Actions extends Piwik_Plugin
);
return $hooks;
}
-
- public function __construct()
+
+ public function __construct()
+ {
+ $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter);
+ }
+
+ public function setCategoryDelimiter($delimiter)
{
- $this->setCategoryDelimiter( Zend_Registry::get('config')->General->action_category_delimiter);
- }
-
- public function setCategoryDelimiter($delimiter)
- {
- self::$actionCategoryDelimiter = $delimiter;
- }
-
+ self::$actionCategoryDelimiter = $delimiter;
+ }
+
function addWidgets()
{
Piwik_AddWidget( 'Actions', 'getActions', Piwik_Translate('Actions_SubmenuPages'));
Piwik_AddWidget( 'Actions', 'getDownloads', Piwik_Translate('Actions_SubmenuDownloads'));
Piwik_AddWidget( 'Actions', 'getOutlinks', Piwik_Translate('Actions_SubmenuOutlinks'));
}
-
- function addMenus()
- {
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
- Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
- }
-
- function archivePeriod( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- $dataTableToSum = array(
- 'Actions_actions',
- 'Actions_downloads',
- 'Actions_outlink',
- );
+
+ function addMenus()
+ {
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuPages', array('module' => 'Actions', 'action' => 'getActions'));
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuOutlinks', array('module' => 'Actions', 'action' => 'getOutlinks'));
+ Piwik_AddMenu('Actions_Actions', 'Actions_SubmenuDownloads', array('module' => 'Actions', 'action' => 'getDownloads'));
+ }
+
+ function archivePeriod( $notification )
+ {
+ $archiveProcessing = $notification->getNotificationObject();
+
+ $dataTableToSum = array(
+ 'Actions_actions',
+ 'Actions_downloads',
+ 'Actions_outlink',
+ );
$maximumRowsInDataTableLevelZero = 200;
- $maximumRowsInSubDataTable = 50;
- $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- }
-
- /**
- * Compute all the actions along with their hierarchies.
- *
- * For each action we process the "interest statistics" :
- * visits, unique visitors, bouce count, sum visit length.
- *
- *
- */
- public function archiveDay( $notification )
- {
- $archiveProcessing = $notification->getNotificationObject();
-
- require_once "Tracker/Action.php";
-
- $this->actionsTablesByType = array(
- Piwik_Tracker_Action::TYPE_ACTION => array(),
- Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
- Piwik_Tracker_Action::TYPE_OUTLINK => array(),
- );
-
- // This row is used in the case where an action is know as an exit_action
- // but this action was not properly recorded when it was hit in the first place
- // so we add this fake row information to make sure there is a nb_hits, etc. column for every action
- $this->defaultRow = new Piwik_DataTable_Row(array(
- Piwik_DataTable_Row::COLUMNS => array(
- 'nb_visits' => 1,
- 'nb_uniq_visitors' => 1,
- 'nb_hits' => 1,
- )));
-
- /*
- * Actions global information
- */
- $query = "SELECT name,
- type,
- count(distinct t1.idvisit) as nb_visits,
- count(distinct visitor_idcookie) as nb_uniq_visitors,
- count(*) as nb_hits
- FROM (".$archiveProcessing->logTable." as t1
- LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
- LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ $maximumRowsInSubDataTable = 50;
+ $archiveProcessing->archiveDataTable($dataTableToSum, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
+ }
+
+ /**
+ * Compute all the actions along with their hierarchies.
+ *
+ * For each action we process the "interest statistics" :
+ * visits, unique visitors, bouce count, sum visit length.
+ *
+ *
+ */
+ public function archiveDay( $notification )
+ {
+ $archiveProcessing = $notification->getNotificationObject();
+
+ require_once "Tracker/Action.php";
+
+ $this->actionsTablesByType = array(
+ Piwik_Tracker_Action::TYPE_ACTION => array(),
+ Piwik_Tracker_Action::TYPE_DOWNLOAD => array(),
+ Piwik_Tracker_Action::TYPE_OUTLINK => array(),
+ );
+
+ // This row is used in the case where an action is know as an exit_action
+ // but this action was not properly recorded when it was hit in the first place
+ // so we add this fake row information to make sure there is a nb_hits, etc. column for every action
+ $this->defaultRow = new Piwik_DataTable_Row(array(
+ Piwik_DataTable_Row::COLUMNS => array(
+ 'nb_visits' => 1,
+ 'nb_uniq_visitors' => 1,
+ 'nb_hits' => 1,
+ )));
+
+ /*
+ * Actions global information
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct t1.idvisit) as nb_visits,
+ count(distinct visitor_idcookie) as nb_uniq_visitors,
+ count(*) as nb_hits
+ FROM (".$archiveProcessing->logTable." as t1
+ LEFT JOIN ".$archiveProcessing->logVisitActionTable." as t2 USING (idvisit))
+ LEFT JOIN ".$archiveProcessing->logActionTable." as t3 USING (idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY t3.idaction
- ORDER BY nb_hits DESC";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Entry actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as entry_nb_unique_visitor,
- count(*) as entry_nb_visits,
- sum(visit_total_actions) as entry_nb_actions,
- sum(visit_total_time) as entry_sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ ORDER BY nb_hits DESC";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+
+ /*
+ * Entry actions
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct visitor_idcookie) as entry_nb_unique_visitor,
+ count(*) as entry_nb_visits,
+ sum(visit_total_actions) as entry_nb_actions,
+ sum(visit_total_time) as entry_sum_visit_length,
+ sum(case visit_total_actions when 1 then 1 else 0 end) as entry_bounce_count
+ FROM ".$archiveProcessing->logTable."
+ JOIN ".$archiveProcessing->logActionTable." ON (visit_entry_idaction = idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY visit_entry_idaction
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
-
- /*
- * Exit actions
- */
- $query = "SELECT name,
- type,
- count(distinct visitor_idcookie) as exit_nb_unique_visitor,
- count(*) as exit_nb_visits,
- sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count
-
- FROM ".$archiveProcessing->logTable."
- JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction)
- WHERE visit_server_date = ?
- AND idsite = ?
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+
+ /*
+ * Exit actions
+ */
+ $query = "SELECT name,
+ type,
+ count(distinct visitor_idcookie) as exit_nb_unique_visitor,
+ count(*) as exit_nb_visits,
+ sum(case visit_total_actions when 1 then 1 else 0 end) as exit_bounce_count
+
+ FROM ".$archiveProcessing->logTable."
+ JOIN ".$archiveProcessing->logActionTable." ON (visit_exit_idaction = idaction)
+ WHERE visit_server_date = ?
+ AND idsite = ?
GROUP BY visit_exit_idaction
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
-
- /*
- * Time per action
- */
- $query = "SELECT name,
- type,
- sum(time_spent_ref_action) as sum_time_spent
- FROM (".$archiveProcessing->logTable." log_visit
- JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
- JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)
- WHERE visit_server_date = ?
- AND idsite = ?
- GROUP BY idaction_ref
- ";
- $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
-
- $modified = $this->updateActionsTableWithRowQuery($query);
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
- $maximumRowsInDataTableLevelZero = 200;
- $maximumRowsInSubDataTable = 50;
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s);
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s);
-
- $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
- $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s);
+ /*
+ * Time per action
+ */
+ $query = "SELECT name,
+ type,
+ sum(time_spent_ref_action) as sum_time_spent
+ FROM (".$archiveProcessing->logTable." log_visit
+ JOIN ".$archiveProcessing->logVisitActionTable." log_link_visit_action USING (idvisit))
+ JOIN ".$archiveProcessing->logActionTable." log_action ON (log_action.idaction = log_link_visit_action.idaction_ref)
+ WHERE visit_server_date = ?
+ AND idsite = ?
+ GROUP BY idaction_ref
+ ";
+ $query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
+ $modified = $this->updateActionsTableWithRowQuery($query);
+
+ $this->archiveDayRecordInDatabase();
+ }
+
+ protected function archiveDayRecordInDatabase()
+ {
+ $maximumRowsInDataTableLevelZero = 1000;
+ $maximumRowsInSubDataTable = 200;
+
+ $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_ACTION]);
+ $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_actions', $s);
+
+ $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_DOWNLOAD]);
+ $s = $dataTable->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_downloads', $s);
- unset($this->actionsTablesByType);
- }
-
- static public function splitUrl($url)
- {
- $matches = $split_arr = array();
- $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE);
- if( $n )
- {
- $host = substr($url, 0, $matches[1][1]);
- $split_arr = array($host, $url);
- }
- else
- {
- $split_arr = array($url);
- }
- return $split_arr;
- }
-
- static public function getActionCategoryFromName($name)
- {
- $isUrl = false;
- // case the name is an URL we dont clean the name the same way
- if(Piwik_Common::isLookLikeUrl($name)
- || preg_match('#^mailto:#',$name))
- {
- $split = self::splitUrl($name);
- $isUrl = true;
- }
- else
+ $dataTable = Piwik_ArchiveProcessing_Day::generateDataTable($this->actionsTablesByType[Piwik_Tracker_Action::TYPE_OUTLINK]);
+ $s = $dataTable->getSerialized( $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable );
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('Actions_outlink', $s);
+
+ unset($this->actionsTablesByType);
+ }
+
+ static public function splitUrl($url)
+ {
+ $matches = $split_arr = array();
+ $n = preg_match("#://[^/]+(/)#",$url, $matches, PREG_OFFSET_CAPTURE);
+ if( $n )
+ {
+ $host = substr($url, 0, $matches[1][1]);
+ $split_arr = array($host, $url);
+ }
+ else
+ {
+ $split_arr = array($url);
+ }
+ return $split_arr;
+ }
+
+ static public function getActionCategoryFromName($name)
+ {
+ $isUrl = false;
+ // case the name is an URL we dont clean the name the same way
+ if(Piwik_Common::isLookLikeUrl($name)
+ || preg_match('#^mailto:#',$name))
+ {
+ $split = self::splitUrl($name);
+ $isUrl = true;
+ }
+ else
{
if(empty(self::$actionCategoryDelimiter))
{
$split = array($name);
}
else
- {
+ {
$split = explode(self::$actionCategoryDelimiter, $name, self::$limitLevelSubCategory);
- }
- }
- return array( $isUrl, $split);
- }
-
-
- protected function updateActionsTableWithRowQuery($query)
- {
- $rowsProcessed = 0;
-
- while( $row = $query->fetch() )
- {
- // split the actions by category
- $returned = $this->getActionCategoryFromName($row['name']);
- $aActions = $returned[1];
- $isUrl = $returned[0];
-
- // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.)
- $currentTable =& $this->actionsTablesByType[$row['type']];
-
- // go to the level of the subcategory
- $end = count($aActions)-1;
- for($level = 0 ; $level < $end; $level++)
- {
- $actionCategory = $aActions[$level];
- $currentTable =& $currentTable[$actionCategory];
- }
- $actionName = $aActions[$end];
-
- // create a new element in the array for the page
- // we are careful to prefix the pageName with some value so that if a page has the same name
- // as a category we don't overwrite or do other silly things
-
- // if the page name is not a URL we add a / before
- if( !$isUrl )
- {
- // we know that the concatenation of a space and the name of the action
- // will always be unique as all the action names have been trimmed before reaching this point
- $actionName = '/' . $actionName;
- }
- else
- {
- $actionName = ' ' . $actionName;
- }
-
- // currentTable is now the array element corresponding the the action
- // at this point we may be for example at the 4th level of depth in the hierarchy
- $currentTable =& $currentTable[$actionName];
-
- // add the row to the matching sub category subtable
- if(!($currentTable instanceof Piwik_DataTable_Row))
- {
- $currentTable = new Piwik_DataTable_Row(
- array( Piwik_DataTable_Row::COLUMNS =>
- array( 'label' => (string)$actionName,
- 'full_url' => (string)$row['name'],
- )
- )
- );
- }
-
- foreach($row as $name => $value)
- {
- // we don't add this information as itnot pertinent
- // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
- // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
- if($name != 'name' && $name != 'type')
- {
- // in some very rare case, we actually have twice the same action name with 2 different idaction
- // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
- // and in between the two the other visitor comes.
- // here we handle the case where there is already a row for this action name, if this is the case we add the value
- if(($alreadyValue = $currentTable->getColumn($name)) !== false)
- {
- $currentTable->setColumn($name, $alreadyValue+$value);
- }
- else
- {
- $currentTable->addColumn($name, $value);
- }
- }
- }
-
- // if the exit_action was not recorded properly in the log_link_visit_action
- // there would be an error message when getting the nb_hits column
- // we must fake the record and add the columns
- if($currentTable->getColumn('nb_hits') === false)
- {
- // to test this code: delete the entries in log_link_action_visit for
- // a given exit_idaction
- foreach($this->defaultRow->getColumns() as $name => $value)
- {
- $currentTable->addColumn($name, $value);
- }
- }
- // simple count
- $rowsProcessed++;
- }
-
- // just to make sure php copies the last $currentTable in the $parentTable array
- $currentTable =& $this->actionsTablesByType;
-
- return $rowsProcessed;
- }
-}
-
+ }
+ }
+ return array( $isUrl, $split);
+ }
+
+
+ protected function updateActionsTableWithRowQuery($query)
+ {
+ $rowsProcessed = 0;
+
+ while( $row = $query->fetch() )
+ {
+ // split the actions by category
+ $returned = $this->getActionCategoryFromName($row['name']);
+ $aActions = $returned[1];
+ $isUrl = $returned[0];
+
+ // we work on the root table of the given TYPE (either ACTION or DOWNLOAD or OUTLINK etc.)
+ $currentTable =& $this->actionsTablesByType[$row['type']];
+
+ // go to the level of the subcategory
+ $end = count($aActions)-1;
+ for($level = 0 ; $level < $end; $level++)
+ {
+ $actionCategory = $aActions[$level];
+ $currentTable =& $currentTable[$actionCategory];
+ }
+ $actionName = $aActions[$end];
+
+ // create a new element in the array for the page
+ // we are careful to prefix the pageName with some value so that if a page has the same name
+ // as a category we don't overwrite or do other silly things
+
+ // if the page name is not a URL we add a / before
+ if( !$isUrl )
+ {
+ // we know that the concatenation of a space and the name of the action
+ // will always be unique as all the action names have been trimmed before reaching this point
+ $actionName = '/' . $actionName;
+ }
+ else
+ {
+ $actionName = ' ' . $actionName;
+ }
+
+ // currentTable is now the array element corresponding the the action
+ // at this point we may be for example at the 4th level of depth in the hierarchy
+ $currentTable =& $currentTable[$actionName];
+
+ // add the row to the matching sub category subtable
+ if(!($currentTable instanceof Piwik_DataTable_Row))
+ {
+ $currentTable = new Piwik_DataTable_Row(
+ array( Piwik_DataTable_Row::COLUMNS =>
+ array( 'label' => (string)$actionName,
+ 'full_url' => (string)$row['name'],
+ )
+ )
+ );
+ }
+
+ foreach($row as $name => $value)
+ {
+ // we don't add this information as itnot pertinent
+ // name is already set as the label // and it has been cleaned from the categories and extracted from the initial string
+ // type is used to partition the different actions type in different table. Adding the info to the row would be a duplicate.
+ if($name != 'name' && $name != 'type')
+ {
+ // in some very rare case, we actually have twice the same action name with 2 different idaction
+ // this happens when 2 visitors visit the same new page at the same time, there is a SELECT and an INSERT for each new page,
+ // and in between the two the other visitor comes.
+ // here we handle the case where there is already a row for this action name, if this is the case we add the value
+ if(($alreadyValue = $currentTable->getColumn($name)) !== false)
+ {
+ $currentTable->setColumn($name, $alreadyValue+$value);
+ }
+ else
+ {
+ $currentTable->addColumn($name, $value);
+ }
+ }
+ }
+
+ // if the exit_action was not recorded properly in the log_link_visit_action
+ // there would be an error message when getting the nb_hits column
+ // we must fake the record and add the columns
+ if($currentTable->getColumn('nb_hits') === false)
+ {
+ // to test this code: delete the entries in log_link_action_visit for
+ // a given exit_idaction
+ foreach($this->defaultRow->getColumns() as $name => $value)
+ {
+ $currentTable->addColumn($name, $value);
+ }
+ }
+ // simple count
+ $rowsProcessed++;
+ }
+
+ // just to make sure php copies the last $currentTable in the $parentTable array
+ $currentTable =& $this->actionsTablesByType;
+
+ return $rowsProcessed;
+ }
+}
+
diff --git a/plugins/Actions/Controller.php b/plugins/Actions/Controller.php
index 4957756f3c..20e160f927 100644
--- a/plugins/Actions/Controller.php
+++ b/plugins/Actions/Controller.php
@@ -45,7 +45,6 @@ class Piwik_Actions_Controller extends Piwik_Controller
__FUNCTION__,
'Actions.getActions',
'getActionsSubDataTable' );
-
return $this->renderView($view, $fetch);
}
@@ -117,8 +116,6 @@ class Piwik_Actions_Controller extends Piwik_Controller
$currentMethod,
$methodToCall,
$subMethod );
- $view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews'));
- $view->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnUniquePageviews'));
$view->setTemplate('CoreHome/templates/datatable_actions.tpl');
if(Piwik_Common::getRequestVar('idSubtable', -1) != -1)
@@ -132,25 +129,24 @@ class Piwik_Actions_Controller extends Piwik_Controller
$view->setTemplate('CoreHome/templates/datatable_actions_recursive.tpl');
}
$view->disableSort();
-
- $view->setSortedColumn( 'nb_hits', 'desc' );
-
$view->disableOffsetInformation();
+ $view->setLimit( 100 );
$view->setColumnsToDisplay( array('label','nb_uniq_visitors','nb_hits') );
- $view->setLimit( 100 );
+ $view->setSortedColumn( 'nb_uniq_visitors', 'desc' );
+ $view->setColumnTranslation('nb_hits', Piwik_Translate('General_ColumnPageviews'));
+ $view->setColumnTranslation('nb_uniq_visitors', Piwik_Translate('General_ColumnUniquePageviews'));
+
// computing minimum value to exclude
require_once "VisitsSummary/Controller.php";
$visitsInfo = Piwik_VisitsSummary_Controller::getVisitsSummary();
$nbActions = $visitsInfo->getColumn('nb_actions');
$nbActionsLowPopulationThreshold = floor(0.02 * $nbActions); // 2 percent of the total number of actions
-
// we remove 1 to make sure some actions/downloads are displayed in the case we have a very few of them
// and each of them has 1 or 2 hits...
$nbActionsLowPopulationThreshold = min($visitsInfo->getColumn('max_actions')-1, $nbActionsLowPopulationThreshold-1);
- $view->setExcludeLowPopulation( $nbActionsLowPopulationThreshold, 'nb_hits' );
-
+ $view->setExcludeLowPopulation( 'nb_hits', $nbActionsLowPopulationThreshold );
$view->main();
// we need to rewrite the phpArray so it contains all the recursive arrays
diff --git a/plugins/CoreAdminHome/templates/header.tpl b/plugins/CoreAdminHome/templates/header.tpl
index 8ed9472766..55762dccb3 100644
--- a/plugins/CoreAdminHome/templates/header.tpl
+++ b/plugins/CoreAdminHome/templates/header.tpl
@@ -18,6 +18,7 @@
<link rel="stylesheet" type="text/css" href="themes/default/common.css" />
<link rel="stylesheet" type="text/css" href="plugins/CoreAdminHome/templates/styles.css" />
+<link rel="stylesheet" type="text/css" href="libs/jquery/jquery-calendar.css" />
<link rel="shortcut icon" href="plugins/CoreHome/templates/images/favicon.ico">
diff --git a/plugins/CoreAdminHome/templates/styles.css b/plugins/CoreAdminHome/templates/styles.css
index 6bf24d65b4..758e61f7b8 100644
--- a/plugins/CoreAdminHome/templates/styles.css
+++ b/plugins/CoreAdminHome/templates/styles.css
@@ -14,16 +14,6 @@ a {
color: black;
}
-#ajaxError {
- color: red;
- text-align: center;
- font-weight: bold;
- width: 550px;
- border: 3px solid red;
- margin: 10px;
- padding: 10px;
-}
-
table.admin {
font-size: 0.9em;
font-family: Arial, Helvetica, verdana sans-serif;
diff --git a/plugins/CoreHome/Controller.php b/plugins/CoreHome/Controller.php
index 713bba8e19..185cdfb2c2 100644
--- a/plugins/CoreHome/Controller.php
+++ b/plugins/CoreHome/Controller.php
@@ -1,56 +1,67 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id: Controller.php 561 2008-07-21 00:00:35Z matt $
- *
- * @package Piwik_CoreHome
- *
- */
-
-require_once "API/Request.php";
-require_once "ViewDataTable.php";
-
-/**
- * @package Piwik_CoreHome
- */
-class Piwik_CoreHome_Controller extends Piwik_Controller
-{
- function getDefaultAction()
- {
- return 'redirectToIndex';
- }
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id: Controller.php 561 2008-07-21 00:00:35Z matt $
+ *
+ * @package Piwik_CoreHome
+ *
+ */
+
+require_once "API/Request.php";
+require_once "ViewDataTable.php";
+
+/**
+ * @package Piwik_CoreHome
+ */
+class Piwik_CoreHome_Controller extends Piwik_Controller
+{
+ function getDefaultAction()
+ {
+ return 'redirectToIndex';
+ }
+
+ function redirectToIndex()
+ {
+ // redirect to Login only for anonymous user
+ if((bool)Zend_Registry::get('config')->General->default_module_login == true
+ && Piwik::getCurrentUserLogin() == 'anonymous')
+ {
+ return Piwik_FrontController::dispatch('Login', false);
+ }
+ parent::redirectToIndex('CoreHome', 'index');
+ }
- protected function setGeneralVariablesView($view)
- {
- parent::setGeneralVariablesView($view);
- $view->menu = Piwik_GetMenu();
- }
+ protected function setGeneralVariablesView($view)
+ {
+ parent::setGeneralVariablesView($view);
+ $view->menu = Piwik_GetMenu();
+ }
- public function showInContext()
- {
- $controllerName = Piwik_Common::getRequestVar('moduleToLoad');
- $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index');
-
- $view = $this->getDefaultIndexView();
- $view->basicHtmlView = true;
- $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName );
- echo $view->render();
- }
-
- protected function getDefaultIndexView()
- {
- $view = new Piwik_View('CoreHome/templates/index.tpl');
- $this->setGeneralVariablesView($view);
+ public function showInContext()
+ {
+ $controllerName = Piwik_Common::getRequestVar('moduleToLoad');
+ $actionName = Piwik_Common::getRequestVar('actionToLoad', 'index');
+
+ $view = $this->getDefaultIndexView();
+ $view->basicHtmlView = true;
+ $view->content = Piwik_FrontController::getInstance()->fetchDispatch( $controllerName, $actionName );
+ echo $view->render();
+ }
+
+ protected function getDefaultIndexView()
+ {
+ $view = new Piwik_View('CoreHome/templates/index.tpl');
+ $this->setGeneralVariablesView($view);
$view->content = '';
- return $view;
+ return $view;
+ }
+
+ public function index()
+ {
+ $view = $this->getDefaultIndexView();
+ echo $view->render();
}
-
- public function index()
- {
- $view = $this->getDefaultIndexView();
- echo $view->render();
- }
-}
+}
diff --git a/plugins/CoreHome/templates/calendar.js b/plugins/CoreHome/templates/calendar.js
index 8a5b20ef1b..db71c42fe8 100644
--- a/plugins/CoreHome/templates/calendar.js
+++ b/plugins/CoreHome/templates/calendar.js
@@ -166,7 +166,7 @@ $(document).ready(function(){
_pk_translate('CoreHome_MonthSeptember'),
_pk_translate('CoreHome_MonthOctober'),
_pk_translate('CoreHome_MonthNovember'),
- _pk_translate('CoreHome_MonthDecemeber')]
+ _pk_translate('CoreHome_MonthDecember')]
},
currentDate);
diff --git a/plugins/CoreHome/templates/cloud.tpl b/plugins/CoreHome/templates/cloud.tpl
index 8989e48a85..b3c208ccc0 100644
--- a/plugins/CoreHome/templates/cloud.tpl
+++ b/plugins/CoreHome/templates/cloud.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
{literal}
<style>
diff --git a/plugins/CoreHome/templates/datatable.css b/plugins/CoreHome/templates/datatable.css
index 364e24cd69..5a3c3577a7 100644
--- a/plugins/CoreHome/templates/datatable.css
+++ b/plugins/CoreHome/templates/datatable.css
@@ -303,20 +303,6 @@ table thead div {
padding: 0.5em;
}
-#tooltip h3 {
- margin:0;
- padding:0;
-}
-#tooltip {
- position: absolute;
- z-index: 3000;
- border: 1px solid #111;
- background-color: #eee;
- opacity: 0.85;
- font-size: 0.7em;
- padding:7px;
-}
-
/* Actions table */
table.dataTableActions tr td.labelodd {
background-image: none;
diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js
index c8b7c26079..b24a8f1254 100644
--- a/plugins/CoreHome/templates/datatable.js
+++ b/plugins/CoreHome/templates/datatable.js
@@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
-// Data Table
+// DataTable
//-----------------------------------------------------------------------------
//A list of all our DataTables
//Test if the object have already been initialized (multiple includes)
@@ -63,8 +63,7 @@ dataTable.prototype =
'filter_pattern',
'filter_column_recursive',
'filter_pattern_recursive',
- 'filter_excludelowpop',
- 'filter_excludelowpop_value',
+ 'enable_filter_excludelowpop',
'filter_offset',
'filter_limit',
'filter_sort_column',
@@ -216,7 +215,6 @@ dataTable.prototype =
handleSort: function(domElem)
{
var self = this;
-
if( self.param.enable_sort )
{
$('.sortable', domElem).click(
@@ -255,19 +253,19 @@ dataTable.prototype =
.each(
function()
{
- if(typeof self.param.filter_excludelowpop == 'undefined')
+ if(typeof self.param.enable_filter_excludelowpop == 'undefined')
{
- self.param.filter_excludelowpop = 0;
+ self.param.enable_filter_excludelowpop = 0;
}
- if(Number(self.param.filter_excludelowpop) != 0)
+ if(Number(self.param.enable_filter_excludelowpop) != 0)
{
string = _pk_translate('CoreHome_IncludeAllPopulation');
- self.param.filter_excludelowpop = 1;
+ self.param.enable_filter_excludelowpop = 1;
}
else
{
string = _pk_translate('CoreHome_ExcludeLowPopulation');
- self.param.filter_excludelowpop = 0;
+ self.param.enable_filter_excludelowpop = 0;
}
$(this).html(string);
}
@@ -276,7 +274,7 @@ dataTable.prototype =
.click(
function()
{
- self.param.filter_excludelowpop = 1 - self.param.filter_excludelowpop;
+ self.param.enable_filter_excludelowpop = 1 - self.param.enable_filter_excludelowpop;
self.param.filter_offset = 0;
self.reloadAjaxDataTable(true, callbackSuccess);
}
@@ -484,6 +482,19 @@ dataTable.prototype =
}
);
+ $('#tableGoals', domElem)
+ .show()
+ .click(
+ function(){
+ // we only reset the limit filter, in case switch to table view from cloud view where limit is custom set to 30
+ // this value is stored in config file General->dataTable_default_limit but this is more an edge case so ok to set it to 10
+ delete self.param.filter_limit;
+ delete self.param.enable_filter_excludelowpop;
+ self.param.viewDataTable = 'tableGoals';
+ self.reloadAjaxDataTable();
+ }
+ );
+
$('#tableAllColumnsSwitch', domElem)
.show()
.click(
@@ -492,6 +503,11 @@ dataTable.prototype =
// this value is stored in config file General->dataTable_default_limit but this is more an edge case so ok to set it to 10
delete self.param.filter_limit;
self.param.viewDataTable = self.param.viewDataTable == 'table' ? 'tableAllColumns' : 'table';
+ // when switching to display simple table, do not exclude low pop by default
+ if(self.param.viewDataTable == 'table')
+ {
+ self.param.enable_filter_excludelowpop = 0;
+ }
self.reloadAjaxDataTable();
}
);
@@ -505,12 +521,17 @@ dataTable.prototype =
var method = $(this).attr('methodToCall');
var filter_limit = $(this).attr('filter_limit');
+ var param_date = self.param.date;
+ var date = $(this).attr('date');
+ if(typeof date != 'undefined') {
+ param_date = date;
+ }
var str = '?module=API'
+'&method='+method
+'&format='+format
+'&idSite='+self.param.idSite
+'&period='+self.param.period
- +'&date='+self.param.date
+ +'&date='+param_date
+'&token_auth='+piwik.token_auth;
if( filter_limit )
{
@@ -580,7 +601,7 @@ dataTable.prototype =
var urlToLink = $(urlLinkDom).html();
$(urlLinkDom).remove();
- var truncationOffsetBecauseImageIsPrepend = -2;
+ var truncationOffsetBecauseImageIsPrepend = -2; //website subtable needs -9.
self.truncate( $(this), truncationOffsetBecauseImageIsPrepend );
if( urlToLink.match("javascript:") )
@@ -649,7 +670,7 @@ dataTable.prototype =
var filtersToRestore = self.resetAllFilters();
self.param.idSubtable = idSubTable;
- self.param.action = self.param.actionToLoadTheSubTable;
+ self.param.action = self.param.controllerActionCalledWhenRequestSubTable;
self.reloadAjaxDataTable(false);
self.param.action = savedActionVariable;
@@ -862,7 +883,7 @@ actionDataTable.prototype =
delete self.param.filter_pattern;
self.param.idSubtable = idSubTable;
- self.param.action = self.param.actionToLoadTheSubTable;
+ self.param.action = self.param.controllerActionCalledWhenRequestSubTable;
self.reloadAjaxDataTable(false, function(resp){self.actionsSubDataTableLoaded(resp)});
self.param.action = savedActionVariable;
diff --git a/plugins/CoreHome/templates/datatable.tpl b/plugins/CoreHome/templates/datatable.tpl
index 49e233f82e..55291ee9ea 100644
--- a/plugins/CoreHome/templates/datatable.tpl
+++ b/plugins/CoreHome/templates/datatable.tpl
@@ -1,12 +1,12 @@
-<div id="{$id}">
- <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
+<div id="{$properties.uniqueId}">
+ <div class="{if isset($javascriptVariablesToSet.idSubtable)&& $javascriptVariablesToSet.idSubtable!=0}sub{/if}{if $javascriptVariablesToSet.viewDataTable=='tableAllColumns'}dataTableAllColumnsWrapper{elseif $javascriptVariablesToSet.viewDataTable=='tableGoals'}dataTableAllColumnsWrapper{else}dataTableWrapper{/if}">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
{if count($arrayDataTable) == 0}
<div id="emptyDatatable">{'CoreHome_TableNoData'|translate}</div>
{else}
- <a name="{$id}"></a>
+ <a name="{$properties.uniqueId}"></a>
<table cellspacing="0" class="dataTable">
<thead>
<tr>
@@ -18,11 +18,11 @@
<tbody>
{foreach from=$arrayDataTable item=row}
- <tr {if $row.idsubdatatable}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
+ <tr {if $row.idsubdatatable && $javascriptVariablesToSet.controllerActionCalledWhenRequestSubTable != null}class="subDataTable" id="{$row.idsubdatatable}"{/if}>
{foreach from=$dataTableColumns item=column}
<td>
{if !$row.idsubdatatable && $column.name=='label' && isset($row.metadata.url)}<span id="urlLink">{$row.metadata.url}</span>{/if}
-{if $column.name=='label' && isset($row.metadata.logo)}<img {if isset($row.metadata.logoWidth)}width="{$row.metadata.logoWidth}"{/if} {if isset($row.metadata.logoHeight)}height="{$row.metadata.logoHeight}"{/if} src="{$row.metadata.logo}" />{/if}
+{if $column.name=='label'}{logoHtml metadata=$row.metadata alt=$row.columns.label}{/if}
{* sometimes all columns are not set in the datatable, we assume the value 0 *}
{if isset($row.columns[$column.name])}{$row.columns[$column.name]}{else}0{/if}
</td>
diff --git a/plugins/CoreHome/templates/datatable_actions.tpl b/plugins/CoreHome/templates/datatable_actions.tpl
index 94341cddff..c2dbe1868f 100644
--- a/plugins/CoreHome/templates/datatable_actions.tpl
+++ b/plugins/CoreHome/templates/datatable_actions.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_js.tpl b/plugins/CoreHome/templates/datatable_actions_js.tpl
index 5bf5ed2bca..568fe83d7b 100644
--- a/plugins/CoreHome/templates/datatable_actions_js.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_js.tpl
@@ -1,12 +1,12 @@
<script type="text/javascript" defer="defer">
$(document).ready(function(){literal}{{/literal}
- actionDataTables['{$id}'] = new actionDataTable();
- actionDataTables['{$id}'].param = {literal}{{/literal}
+ actionDataTables['{$properties.uniqueId}'] = new actionDataTable();
+ actionDataTables['{$properties.uniqueId}'].param = {literal}{{/literal}
{foreach from=$javascriptVariablesToSet key=name item=value name=loop}
{$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if}
{/foreach}
{literal}};{/literal}
- actionDataTables['{$id}'].init('{$id}');
+ actionDataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}');
{literal}}{/literal});
</script>
diff --git a/plugins/CoreHome/templates/datatable_actions_recursive.tpl b/plugins/CoreHome/templates/datatable_actions_recursive.tpl
index bcec62eb2c..01a22255ed 100644
--- a/plugins/CoreHome/templates/datatable_actions_recursive.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_recursive.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="dataTableActionsWrapper">
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
diff --git a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
index 39e103f691..1cfe58edc9 100644
--- a/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
+++ b/plugins/CoreHome/templates/datatable_actions_subdatable.tpl
@@ -1,4 +1,4 @@
-<tr id="{$id}"></tr>
+<tr id="{$properties.uniqueId}"></tr>
{if isset($arrayDataTable.result) and $arrayDataTable.result == 'error'}
{$arrayDataTable.message}
{else}
diff --git a/plugins/CoreHome/templates/datatable_footer.tpl b/plugins/CoreHome/templates/datatable_footer.tpl
index 355fbe2a3e..1d92fbcad5 100644
--- a/plugins/CoreHome/templates/datatable_footer.tpl
+++ b/plugins/CoreHome/templates/datatable_footer.tpl
@@ -23,10 +23,11 @@
<span id="exportToFormat" style="display:none;padding-left:4px;">
<img width="16" height="16" src="{$piwikUrl}themes/default/images/export.png" title="{'General_Export'|translate}" />
<span id="linksExportToFormat" style="display:none;">
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="CSV" filter_limit="100">CSV</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="XML" filter_limit="100">XML</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="JSON" filter_limit="100">Json</a> |
- <a target="_blank" class="exportToFormat" methodToCall="{$method}" format="PHP" filter_limit="100">Php</a>
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="CSV" filter_limit="100">CSV</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="XML" filter_limit="100">XML</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="JSON" filter_limit="100">Json</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="PHP" filter_limit="100">Php</a> |
+ <a target="_blank" class="exportToFormat" methodToCall="{$properties.apiMethodToRequestDataTable}" format="RSS" filter_limit="100" date="last10"><img border="0" src="{$piwikUrl}themes/default/images/feed.png"></a>
</span>
<a class="viewDataTable" format="cloud"><img width="16" height="16" src="{$piwikUrl}themes/default/images/tagcloud.png" title="{'General_TagCloud'|translate}" /></a>
<a class="viewDataTable" format="graphVerticalBar"><img width="16" height="16" src="{$piwikUrl}themes/default/images/chart_bar.png" title="{'General_VBarGraph'|translate}" /></a>
@@ -44,6 +45,13 @@
{/if}
</span>
{/if}
+ {if $properties.show_goals}
+ <span id="tableGoals" style="display:none;float:right;padding-right:4px;">
+ {if $javascriptVariablesToSet.viewDataTable != 'tableGoals'}
+ <img title="View Goals" src="{$piwikUrl}themes/default/images/goal.png" />
+ {/if}
+ </span>
+ {/if}
</span>
</div>
{/if}
diff --git a/plugins/CoreHome/templates/datatable_js.tpl b/plugins/CoreHome/templates/datatable_js.tpl
index c3e5c9e5c3..acae875cf4 100644
--- a/plugins/CoreHome/templates/datatable_js.tpl
+++ b/plugins/CoreHome/templates/datatable_js.tpl
@@ -1,13 +1,13 @@
<script type="text/javascript" defer="defer">
$(document).ready(function(){literal}{{/literal}
- dataTables['{$id}'] = new dataTable();
- dataTables['{$id}'].param = {literal}{{/literal}
+ dataTables['{$properties.uniqueId}'] = new dataTable();
+ dataTables['{$properties.uniqueId}'].param = {literal}{{/literal}
{foreach from=$javascriptVariablesToSet key=name item=value name=loop}
{$name}: '{$value}'{if !$smarty.foreach.loop.last},{/if}
{/foreach}
{literal}};{/literal}
- dataTables['{$id}'].init('{$id}');
+ dataTables['{$properties.uniqueId}'].init('{$properties.uniqueId}');
{literal}}{/literal});
</script>
diff --git a/plugins/CoreHome/templates/graph.tpl b/plugins/CoreHome/templates/graph.tpl
index 74e6df6e1f..4e2bd9cda4 100644
--- a/plugins/CoreHome/templates/graph.tpl
+++ b/plugins/CoreHome/templates/graph.tpl
@@ -1,4 +1,4 @@
-<div id="{$id}">
+<div id="{$properties.uniqueId}">
<div class="{if $graphType=='evolution'}dataTableGraphEvolutionWrapper{else}dataTableGraphWrapper{/if}">
{$jsInvocationTag}
diff --git a/plugins/DBStats/API.php b/plugins/DBStats/API.php
index b041b9a227..5c26a6700e 100644
--- a/plugins/DBStats/API.php
+++ b/plugins/DBStats/API.php
@@ -13,7 +13,7 @@
*
* @package Piwik_DBStats_API
*/
-class Piwik_DBStats_API extends Piwik_Apiable
+class Piwik_DBStats_API
{
static private $instance = null;
static public function getInstance()
@@ -44,23 +44,6 @@ class Piwik_DBStats_API extends Piwik_Apiable
return $status;
}
- static private function get_size($size)
- {
- $bytes = array('','K','M','G','T');
- foreach($bytes as $val)
- {
- if($size > 1024)
- {
- $size = $size / 1024;
- }
- else
- {
- break;
- }
- }
- return round($size, 1)." ".$val;
- }
-
static public function getTableStatus($table, $field = '')
{
Piwik::checkUserIsSuperUser();
@@ -80,30 +63,31 @@ class Piwik_DBStats_API extends Piwik_Apiable
static public function getAllTablesStatus()
{
- Piwik::isUserIsSuperUser();
+ Piwik::checkUserIsSuperUser();
$db = Zend_Registry::get('db');
// http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html
$tablesPiwik = Piwik::getTablesInstalled();
$total = array('Name' => 'Total', 'Data_length' => 0, 'Index_length' => 0, 'Rows' => 0);
- foreach($tablesPiwik as $table)
+ $table = array();
+ foreach($tablesPiwik as $tableName)
{
- $t = self::getTableStatus($table);
+ $t = self::getTableStatus($tableName);
$total['Data_length'] += $t['Data_length'];
$total['Index_length'] += $t['Index_length'];
$total['Rows'] += $t['Rows'];
- $t['Total_length'] = self::get_size($t['Index_length']+$t['Data_length']);
- $t['Data_length'] = self::get_size($t['Data_length']);
- $t['Index_length'] = self::get_size($t['Index_length']);
- $t['Rows'] = self::get_size($t['Rows']);
- $tables[] = $t;
+ $t['Total_length'] = Piwik::getPrettySizeFromBytes($t['Index_length']+$t['Data_length']);
+ $t['Data_length'] = Piwik::getPrettySizeFromBytes($t['Data_length']);
+ $t['Index_length'] = Piwik::getPrettySizeFromBytes($t['Index_length']);
+ $t['Rows'] = Piwik::getPrettySizeFromBytes($t['Rows']);
+ $table[] = $t;
}
- $total['Total_length'] = self::get_size($total['Data_length']+$total['Index_length']);
- $total['Data_length'] = self::get_size($total['Data_length']);
- $total['Index_length'] = self::get_size($total['Index_length']);
- $total['TotalRows'] = self::get_size($total['Rows']);
- $tables['Total'] = $total;
+ $total['Total_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']+$total['Index_length']);
+ $total['Data_length'] = Piwik::getPrettySizeFromBytes($total['Data_length']);
+ $total['Index_length'] = Piwik::getPrettySizeFromBytes($total['Index_length']);
+ $total['TotalRows'] = Piwik::getPrettySizeFromBytes($total['Rows']);
+ $table['Total'] = $total;
- return $tables;
+ return $table;
}
}
diff --git a/plugins/DBStats/templates/DBStats.tpl b/plugins/DBStats/templates/DBStats.tpl
index 27f0769dcd..e82e095683 100644
--- a/plugins/DBStats/templates/DBStats.tpl
+++ b/plugins/DBStats/templates/DBStats.tpl
@@ -13,10 +13,11 @@
<th>{'DBStats_RowNumber'|translate}</th>
<th>{'DBStats_DataSize'|translate}</th>
<th>{'DBStats_IndexSize'|translate}</th>
+ <th>{'DBStats_TotalSize'|translate}</th>
</thead>
<tbody id="tables">
{foreach from=$tablesStatus key=index item=table}
- <tr {if $table.Name == 'Total'}class="active"{/if}>
+ <tr {if $table.Name == 'Total'}class="active" style="font-weight:bold;"{/if}>
<td>
{$table.Name}
</td>
@@ -29,6 +30,9 @@
<td>
{$table.Index_length}b
</td>
+ <td>
+ {$table.Total_length}b
+ </td>
</tr>
{/foreach}
</tbody>
diff --git a/plugins/ExampleAPI/API.php b/plugins/ExampleAPI/API.php
index 8a6d19af96..ca052d42aa 100644
--- a/plugins/ExampleAPI/API.php
+++ b/plugins/ExampleAPI/API.php
@@ -20,7 +20,7 @@
*
* @package Piwik_ExamplePlugin
*/
-class Piwik_ExampleAPI_API extends Piwik_Apiable
+class Piwik_ExampleAPI_API
{
static private $instance = null;
static public function getInstance()
@@ -35,6 +35,7 @@ class Piwik_ExampleAPI_API extends Piwik_Apiable
public function getPiwikVersion()
{
+ Piwik::checkUserHasSomeViewAccess();
return Piwik_Version::VERSION;
}
diff --git a/plugins/ExamplePlugin/ExamplePlugin.php b/plugins/ExamplePlugin/ExamplePlugin.php
index 106a6cdbb8..a2cc37bf15 100644
--- a/plugins/ExamplePlugin/ExamplePlugin.php
+++ b/plugins/ExamplePlugin/ExamplePlugin.php
@@ -21,6 +21,24 @@ class Piwik_ExamplePlugin extends Piwik_Plugin
'version' => '0.1',
);
}
+
+ public function getListHooksRegistered()
+ {
+ return array(
+// 'Controller.renderView' => 'addUniqueVisitorsColumnToGivenReport',
+ );
+ }
+
+ function addUniqueVisitorsColumnToGivenReport($notification)
+ {
+ $view = $notification->getNotificationInfo();
+ $view = $view['view'];
+ if($view->getCurrentControllerName() == 'Referers'
+ && $view->getCurrentControllerAction() == 'getWebsites')
+ {
+ $view->addColumnToDisplay('nb_uniq_visitors');
+ }
+ }
}
// we register the widgets so they appear in the "Add a new widget" window in the dashboard
diff --git a/plugins/Goals/API.php b/plugins/Goals/API.php
new file mode 100644
index 0000000000..5b1b849f01
--- /dev/null
+++ b/plugins/Goals/API.php
@@ -0,0 +1,227 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_VisitsSummary
+ */
+
+/**
+ * @package Piwik_Goals
+ */
+class Piwik_Goals_API
+{
+ static private $instance = null;
+ static public function getInstance()
+ {
+ if (self::$instance == null)
+ {
+ $c = __CLASS__;
+ self::$instance = new $c();
+ }
+ return self::$instance;
+ }
+
+ static public function getGoals( $idSite )
+ {
+ $goals = Zend_Registry::get('db')->fetchAll("SELECT *
+ FROM ".Piwik_Common::prefixTable('goal')."
+ WHERE idsite = ?
+ AND deleted = 0", $idSite);
+ $cleanedGoals = array();
+ foreach($goals as &$goal)
+ {
+ unset($goal['idsite']);
+ $cleanedGoals[$goal['idgoal']] = $goal;
+ }
+ return $cleanedGoals;
+ }
+
+ public function addGoal( $idSite, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue )
+ {
+ Piwik::checkUserHasAdminAccess($idSite);
+ // save in db
+ $db = Zend_Registry::get('db');
+ $idGoal = $db->fetchOne("SELECT max(idgoal) + 1
+ FROM ".Piwik::prefixTable('goal')."
+ WHERE idsite = ?", $idSite);
+ if($idGoal == false)
+ {
+ $idGoal = 1;
+ }
+ self::checkPatternIsValid($patternType, $pattern);
+ $name = self::checkName($name);
+ $pattern = self::checkPattern($pattern);
+ $db->insert(Piwik::prefixTable('goal'),
+ array(
+ 'idsite' => $idSite,
+ 'idgoal' => $idGoal,
+ 'name' => $name,
+ 'match_attribute' => $matchAttribute,
+ 'pattern' => $pattern,
+ 'pattern_type' => $patternType,
+ 'case_sensitive' => $caseSensitive,
+ 'revenue' => $revenue,
+ 'deleted' => 0,
+ ));
+ Piwik_Common::regenerateCacheWebsiteAttributes($idSite);
+ return $idGoal;
+ }
+
+ public function updateGoal( $idSite, $idGoal, $name, $matchAttribute, $pattern, $patternType, $caseSensitive, $revenue )
+ {
+ Piwik::checkUserHasAdminAccess($idSite);
+ $name = self::checkName($name);
+ $pattern = self::checkPattern($pattern);
+ self::checkPatternIsValid($patternType, $pattern);
+ Zend_Registry::get('db')->update( Piwik::prefixTable('goal'),
+ array(
+ 'name' => $name,
+ 'match_attribute' => $matchAttribute,
+ 'pattern' => $pattern,
+ 'pattern_type' => $patternType,
+ 'case_sensitive' => $caseSensitive,
+ 'revenue' => $revenue,
+ ),
+ "idsite = '$idSite' AND idgoal = '$idGoal'"
+ );
+ Piwik_Common::regenerateCacheWebsiteAttributes($idSite);
+ }
+
+ private function checkPatternIsValid($patternType, $pattern)
+ {
+ if($patternType == 'exact'
+ && substr($pattern, 0, 4) != 'http')
+ {
+ throw new Exception("If you choose 'exact match', the matching string must be a
+ URL starting with http:// or https://. For example, 'http://www.yourwebsite.com/newsletter/subscribed.html'.");
+ }
+ }
+
+ private function checkName($name)
+ {
+ return urldecode($name);
+ }
+
+ private function checkPattern($pattern)
+ {
+ return urldecode($pattern);
+ }
+
+ public function deleteGoal( $idSite, $idGoal )
+ {
+ Piwik::checkUserHasAdminAccess($idSite);
+ Zend_Registry::get('db')->query("UPDATE ".Piwik::prefixTable('goal')."
+ SET deleted = 1
+ WHERE idsite = ?
+ AND idgoal = ?",
+ array($idSite, $idGoal));
+ $db->query("DELETE FROM ".Piwik::prefixTable("log_conversion")." WHERE idgoal = ?", $idGoal);
+ Piwik_Common::regenerateCacheWebsiteAttributes($idSite);
+ }
+
+// public function getConversionsReturningVisitors( $idSite, $period, $date, $idGoal = false )
+// {
+//
+// }
+//
+// public function getConversionsNewVisitors( $idSite, $period, $date, $idGoal = false )
+// {
+//
+// }
+
+ // TODO
+ public function getConversionRateReturningVisitors( $idSite, $period, $date, $idGoal = false )
+ {
+ // visits converted for returning for all goals = call Frequency API
+ if($idGoal === false)
+ {
+ $request = new Piwik_API_Request("method=VisitFrequency.getConvertedVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
+ $nbVisitsConvertedReturningVisitors = $request->process();
+ }
+ // visits converted for returning = nb conversion for this goal
+ else
+ {
+ $nbVisitsConvertedReturningVisitors = $this->getNumeric($idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal, 1));
+ }
+ // all returning visits
+ $request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
+ $nbVisitsReturning = $request->process();
+// echo $nbVisitsConvertedReturningVisitors;
+// echo "<br>". $nbVisitsReturning;exit;
+ return $this->getPercentage($nbVisitsConvertedReturningVisitors, $nbVisitsReturning);
+ }
+
+ public function getConversionRateNewVisitors( $idSite, $period, $date, $idGoal = false )
+ {
+ // new visits converted for all goals = nb visits converted - nb visits converted for returning
+ if($idGoal == false)
+ {
+ $request = new Piwik_API_Request("method=VisitsSummary.getVisitsConverted&idSite=$idSite&period=$period&date=$date&format=original");
+ $convertedVisits = $request->process();
+ $request = new Piwik_API_Request("method=VisitFrequency.getConvertedVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
+ $convertedReturningVisits = $request->process();
+ $convertedNewVisits = $convertedVisits - $convertedReturningVisits;
+ }
+ // new visits converted for a given goal = nb conversion for this goal for new visits
+ else
+ {
+ $convertedNewVisits = $this->getNumeric($idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal, 0));
+ }
+ // all new visits = all visits - all returning visits
+ $request = new Piwik_API_Request("method=VisitFrequency.getVisitsReturning&idSite=$idSite&period=$period&date=$date&format=original");
+ $nbVisitsReturning = $request->process();
+ $request = new Piwik_API_Request("method=VisitsSummary.getVisits&idSite=$idSite&period=$period&date=$date&format=original");
+ $nbVisits = $request->process();
+ $newVisits = $nbVisits - $nbVisitsReturning;
+ return $this->getPercentage($convertedNewVisits, $newVisits);
+ }
+
+ protected function getPercentage($a, $b)
+ {
+ if($b == 0)
+ {
+ return 0;
+ }
+ return round(100 * $a / $b, Piwik_Goals::ROUNDING_PRECISION);
+ }
+
+ public function get( $idSite, $period, $date, $idGoal = false )
+ {
+ Piwik::checkUserHasViewAccess( $idSite );
+ $archive = Piwik_Archive::build($idSite, $period, $date );
+ $toFetch = array( Piwik_Goals::getRecordName('nb_conversions', $idGoal),
+ Piwik_Goals::getRecordName('conversion_rate', $idGoal),
+ Piwik_Goals::getRecordName('revenue', $idGoal),
+ );
+ $dataTable = $archive->getDataTableFromNumeric($toFetch);
+ return $dataTable;
+ }
+
+ protected static function getNumeric( $idSite, $period, $date, $toFetch )
+ {
+ Piwik::checkUserHasViewAccess( $idSite );
+ $archive = Piwik_Archive::build($idSite, $period, $date );
+ $dataTable = $archive->getNumeric($toFetch);
+ return $dataTable;
+ }
+
+ public function getConversions( $idSite, $period, $date, $idGoal = false )
+ {
+ return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('nb_conversions', $idGoal));
+ }
+
+ public function getConversionRate( $idSite, $period, $date, $idGoal = false )
+ {
+ return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('conversion_rate', $idGoal));
+ }
+
+ public function getRevenue( $idSite, $period, $date, $idGoal = false )
+ {
+ return self::getNumeric( $idSite, $period, $date, Piwik_Goals::getRecordName('revenue', $idGoal));
+ }
+
+}
diff --git a/plugins/Goals/Controller.php b/plugins/Goals/Controller.php
new file mode 100644
index 0000000000..935d616258
--- /dev/null
+++ b/plugins/Goals/Controller.php
@@ -0,0 +1,150 @@
+<?php
+require_once "Goals/API.php";
+
+class Piwik_Goals_Controller extends Piwik_Controller
+{
+ const CONVERSION_RATE_PRECISION = 1;
+ function goalReport()
+ {
+ $idGoal = Piwik_Common::getRequestVar('idGoal', null, 'int');
+ $idSite = Piwik_Common::getRequestVar('idSite');
+ $goals = Piwik_Goals_API::getGoals($idSite);
+ if(!isset($goals[$idGoal]))
+ {
+ throw new Exception("idgoal $idGoal not valid.");
+ }
+ $goalDefinition = $goals[$idGoal];
+
+ $view = new Piwik_View('Goals/templates/single_goal.tpl');
+ $view->currency = Piwik::getCurrency();
+ $goal = $this->getMetricsForGoal($idGoal);
+ foreach($goal as $name => $value)
+ {
+ $view->$name = $value;
+ }
+ $view->name = $goalDefinition['name'];
+ $view->title = $goalDefinition['name'] . ' - Conversions';
+ $view->graphEvolution = $this->getLastNbConversionsGraph(true);
+ $view->nameGraphEvolution = 'GoalsgetLastNbConversionsGraph'; // must be the function name used above
+
+ $columnNbConversions = 'goal_'.$idGoal.'_nb_conversions';
+ $columnConversionRate = 'goal_'.$idGoal.'_conversion_rate';
+
+ $topSegmentsToLoad = array(
+ 'country' => 'UserCountry.getCountry',
+ 'keyword' => 'Referers.getKeywords',
+ 'website' => 'Referers.getWebsites',
+ );
+
+ $topSegments = array();
+ foreach($topSegmentsToLoad as $segmentName => $apiMethod)
+ {
+ $request = new Piwik_API_Request("method=$apiMethod
+ &format=original
+ &filter_update_columns_when_show_all_goals=1
+ &filter_sort_order=desc
+ &filter_sort_column=$columnNbConversions
+ &filter_limit=3");
+ $datatable = $request->process();
+ $topSegment = array();
+ foreach($datatable->getRows() as $row)
+ {
+ $topSegment[] = array (
+ 'name' => $row->getColumn('label'),
+ 'nb_conversions' => $row->getColumn($columnNbConversions),
+ 'conversion_rate' => $row->getColumn($columnConversionRate),
+ 'metadata' => $row->getMetadata(),
+ );
+ }
+ $topSegments[$segmentName] = $topSegment;
+// echo $datatable;
+ }
+
+ $request = new Piwik_API_Request("method=Goals.getConversionRateReturningVisitors&format=original");
+ $view->conversion_rate_returning = round( $request->process(), self::CONVERSION_RATE_PRECISION );
+ $request = new Piwik_API_Request("method=Goals.getConversionRateNewVisitors&format=original");
+ $view->conversion_rate_new = round( $request->process(), self::CONVERSION_RATE_PRECISION );
+
+ $view->topSegments = $topSegments;
+ echo $view->render();
+ //todo next: nice legends for graphs
+ }
+
+ protected function getMetricsForGoal($goalId)
+ {
+ $request = new Piwik_API_Request("method=Goals.get&format=original&idGoal=$goalId");
+ $datatable = $request->process();
+ return array (
+ 'id' => $goalId,
+ 'nb_conversions' => $datatable->getRowFromLabel(Piwik_Goals::getRecordName('nb_conversions', $goalId))->getColumn('value'),
+ 'conversion_rate' => round($datatable->getRowFromLabel(Piwik_Goals::getRecordName('conversion_rate', $goalId))->getColumn('value'), 1),
+ 'revenue' => $datatable->getRowFromLabel(Piwik_Goals::getRecordName('revenue', $goalId))->getColumn('value'),
+ 'urlSparklineConversions' => $this->getUrlSparkline('getLastNbConversionsGraph', $goalId) . "&idGoal=".$goalId,
+ 'urlSparklineConversionRate' => $this->getUrlSparkline('getLastConversionRateGraph', $goalId) . "&idGoal=".$goalId,
+ 'urlSparklineRevenue' => $this->getUrlSparkline('getLastRevenueGraph', $goalId) . "&idGoal=".$goalId,
+ );
+ }
+
+ function index()
+ {
+ $view = new Piwik_View('Goals/templates/overview.tpl');
+ $view->currency = Piwik::getCurrency();
+
+ $view->title = 'All goals - evolution';
+ $view->graphEvolution = $this->getLastNbConversionsGraph(true);
+ $view->nameGraphEvolution = 'GoalsgetLastNbConversionsGraph'; // must be the function name used above
+
+ // sparkline for the historical data of the above values
+ $view->urlSparklineConversions = $this->getUrlSparkline('getLastNbConversionsGraph');
+ $view->urlSparklineConversionRate = $this->getUrlSparkline('getLastConversionRateGraph');
+ $view->urlSparklineRevenue = $this->getUrlSparkline('getLastRevenueGraph');
+
+ $request = new Piwik_API_Request("method=Goals.get&format=original");
+ $datatable = $request->process();
+ $view->nb_conversions = $datatable->getRowFromLabel('Goal_nb_conversions')->getColumn('value');
+ $view->conversion_rate = $datatable->getRowFromLabel('Goal_conversion_rate')->getColumn('value');
+ $view->revenue = $datatable->getRowFromLabel('Goal_revenue')->getColumn('value');
+
+ $goalMetrics = array();
+
+ $idSite = Piwik_Common::getRequestVar('idSite');
+ $goals = Piwik_Goals_API::getGoals($idSite);
+ foreach($goals as $idGoal => $goal)
+ {
+ $goalMetrics[$idGoal] = $this->getMetricsForGoal($idGoal);
+ $goalMetrics[$idGoal]['name'] = $goal['name'];
+ }
+
+ $view->goalMetrics = $goalMetrics;
+ $view->goals = $goals;
+ $view->goalsJSON = json_encode($goals);
+ $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite);
+ echo $view->render();
+ }
+
+ function addNewGoal()
+ {
+ $view = new Piwik_View('Goals/templates/add_new_goal.tpl');
+ $idSite = Piwik_Common::getRequestVar('idSite');
+ $view->userCanEditGoals = Piwik::isUserHasAdminAccess($idSite);
+ $view->currency = Piwik::getCurrency();
+ $view->onlyShowAddNewGoal = true;
+ echo $view->render();
+ }
+
+ function getLastNbConversionsGraph( $fetch = false )
+ {
+ $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversions');
+ return $this->renderView($view, $fetch);
+ }
+ function getLastConversionRateGraph( $fetch = false )
+ {
+ $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getConversionRate');
+ return $this->renderView($view, $fetch);
+ }
+ function getLastRevenueGraph( $fetch = false )
+ {
+ $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, 'Goals.getRevenue');
+ return $this->renderView($view, $fetch);
+ }
+}
diff --git a/plugins/Goals/Goals.php b/plugins/Goals/Goals.php
new file mode 100644
index 0000000000..550f0e7288
--- /dev/null
+++ b/plugins/Goals/Goals.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_Referers
+ */
+
+require_once "core/Tracker/GoalManager.php";
+
+/**
+ * @package Piwik_Referers
+ */
+class Piwik_Goals extends Piwik_Plugin
+{
+ const ROUNDING_PRECISION = 2;
+
+ public function getInformation()
+ {
+ $info = array(
+ 'name' => '(ALPHA) Goal Tracking',
+ 'description' => 'Create Goals and see reports about your goal conversions: evolution over time, revenue per visit, conversions per referer, per keyword, etc.',
+ 'author' => 'Piwik',
+ 'homepage' => 'http://piwik.org/',
+ 'version' => '0.1',
+ 'TrackerPlugin' => true
+ );
+
+ return $info;
+ }
+
+ function getListHooksRegistered()
+ {
+ $hooks = array(
+ 'Common.fetchWebsiteAttributes' => 'fetchGoalsFromDb',
+ 'ArchiveProcessing_Day.compute' => 'archiveDay',
+ 'ArchiveProcessing_Period.compute' => 'archivePeriod',
+ 'WidgetsList.add' => 'addWidgets',
+ 'Menu.add' => 'addMenus',
+ );
+ return $hooks;
+ }
+
+ function fetchGoalsFromDb($notification)
+ {
+ require_once "Goals/API.php";
+ $info = $notification->getNotificationInfo();
+ $idsite = $info['idsite'];
+
+ // add the 'goal' entry in the website array
+ $array =& $notification->getNotificationObject();
+ $array['goals'] = Piwik_Goals_API::getGoals($idsite);
+ }
+
+ function addWidgets()
+ {
+// Piwik_AddWidget( 'Referers', 'getKeywords', Piwik_Translate('Referers_WidgetKeywords'));
+ }
+
+ function addMenus()
+ {
+ $goals = Piwik_Tracker_GoalManager::getGoalDefinitions(Piwik_Common::getRequestVar('idSite'));
+ if(count($goals)==0)
+ {
+ Piwik_AddMenu('Goals', 'Add a new Goal', array('module' => 'Goals', 'action' => 'addNewGoal'));
+ }
+ else
+ {
+ Piwik_AddMenu('Goals', 'Overview', array('module' => 'Goals'));
+ foreach($goals as $goal)
+ {
+ Piwik_AddMenu('Goals', str_replace('%', '%%', $goal['name']), array('module' => 'Goals', 'action' => 'goalReport', 'idGoal' => $goal['idgoal']));
+ }
+ }
+ }
+
+ /**
+ * @param string $recordName 'nb_conversions'
+ * @param int $idGoal idGoal to return the metrics for, or false to return overall
+ * @param int $visitorReturning 0 for new visitors, 1 for returning visitors, false for all
+ * @return unknown
+ */
+ static public function getRecordName($recordName, $idGoal = false, $visitorReturning = false)
+ {
+ $idGoalStr = $returningStr = '';
+ if($idGoal !== false)
+ {
+ $idGoalStr = $idGoal . "_";
+ }
+ if($visitorReturning !== false)
+ {
+ $returningStr = 'visitor_returning_' . $visitorReturning . '_';
+ }
+ return 'Goal_' . $returningStr . $idGoalStr . $recordName;
+ }
+
+ function archivePeriod($notification )
+ {
+ /**
+ * @var Piwik_ArchiveProcessing_Period
+ */
+ $archiveProcessing = $notification->getNotificationObject();
+
+ $metricsToSum = array( 'nb_conversions', 'revenue');
+ $goalIdsToSum = Piwik_Tracker_GoalManager::getGoalIds($archiveProcessing->idsite);
+
+ $fieldsToSum = array();
+ foreach($metricsToSum as $metricName)
+ {
+ foreach($goalIdsToSum as $goalId)
+ {
+ $fieldsToSum[] = self::getRecordName($metricName, $goalId);
+ $fieldsToSum[] = self::getRecordName($metricName, $goalId, 0);
+ $fieldsToSum[] = self::getRecordName($metricName, $goalId, 1);
+ }
+ $fieldsToSum[] = self::getRecordName($metricName);
+ }
+ $records = $archiveProcessing->archiveNumericValuesSum($fieldsToSum);
+
+ // also recording conversion_rate for each goal
+ foreach($goalIdsToSum as $goalId)
+ {
+ $nb_conversions = $records[self::getRecordName('nb_conversions', $goalId)]->value;
+ $conversion_rate = $this->getConversionRate($nb_conversions, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_Numeric(self::getRecordName('conversion_rate', $goalId), $conversion_rate);
+ }
+
+ // global conversion rate
+ $nb_conversions = $records[self::getRecordName('nb_conversions')]->value;
+ $conversion_rate = $this->getConversionRate($nb_conversions, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_Numeric(self::getRecordName('conversion_rate'), $conversion_rate);
+
+ }
+
+ function archiveDay( $notification )
+ {
+ /**
+ * @var Piwik_ArchiveProcessing_Day
+ */
+ $archiveProcessing = $notification->getNotificationObject();
+
+ // by processing visitor_returning segment, we can also simply sum and get stats for all goals.
+ $query = $archiveProcessing->queryConversionsBySegment('visitor_returning');
+
+ $nb_conversions = $revenue = 0;
+ $goals = $goalsByVisitorReturning = array();
+ while($row = $query->fetch() )
+ {
+ $goalsByVisitorReturning[$row['idgoal']][$row['visitor_returning']] = $archiveProcessing->getGoalRowFromQueryRow($row);
+
+ if(!isset($goals[$row['idgoal']])) $goals[$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats($row, $goals[$row['idgoal']]);
+
+ $revenue += $row['revenue'];
+ $nb_conversions += $row['nb_conversions'];
+ }
+
+ // Stats by goal, for all visitors
+ foreach($goals as $idgoal => $values)
+ {
+ foreach($values as $metricId => $value)
+ {
+ $metricName = Piwik_Archive::$mappingFromIdToNameGoal[$metricId];
+ $recordName = self::getRecordName($metricName, $idgoal);
+ $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value);
+ }
+ $conversion_rate = $this->getConversionRate($values[Piwik_Archive::INDEX_GOAL_NB_CONVERSIONS], $archiveProcessing);
+ $recordName = self::getRecordName('conversion_rate', $idgoal);
+ $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $conversion_rate);
+ }
+
+ // Stats by goal, for visitor returning / non returning
+ foreach($goalsByVisitorReturning as $idgoal => $values)
+ {
+ foreach($values as $visitor_returning => $goalValues)
+ {
+ foreach($goalValues as $metricId => $value)
+ {
+ $metricName = Piwik_Archive::$mappingFromIdToNameGoal[$metricId];
+ $recordName = self::getRecordName($metricName, $idgoal, $visitor_returning);
+ $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value);
+// echo $record . "<br>";
+ }
+ }
+ }
+
+ // Stats for all goals
+ $totalAllGoals = array(
+ self::getRecordName('conversion_rate') => round(100 * $archiveProcessing->getNumberOfVisitsConverted() / $archiveProcessing->getNumberOfVisits(), self::ROUNDING_PRECISION),
+ self::getRecordName('nb_conversions') => $nb_conversions,
+ self::getRecordName('revenue') => $revenue,
+ );
+ foreach($totalAllGoals as $recordName => $value)
+ {
+ $record = new Piwik_ArchiveProcessing_Record_Numeric($recordName, $value);
+ }
+ }
+
+ function getConversionRate($count, $archiveProcessing)
+ {
+ return round(100 * $count / $archiveProcessing->getNumberOfVisits(), self::ROUNDING_PRECISION);
+ }
+}
diff --git a/plugins/Goals/templates/GoalForm.js b/plugins/Goals/templates/GoalForm.js
new file mode 100644
index 0000000000..4345bc8958
--- /dev/null
+++ b/plugins/Goals/templates/GoalForm.js
@@ -0,0 +1,124 @@
+
+function showAddNewGoal()
+{
+ $("#GoalForm").show();
+ $("#EditGoals").hide();
+ $.scrollTo("#AddEditGoals", 400);
+ return false;
+}
+
+function showEditGoals()
+{
+ $("#EditGoals").show();
+ $("#GoalForm").hide();
+ $.scrollTo("#AddEditGoals", 400);
+ return false;
+}
+
+// init the goal form with existing goal value, if any
+function initGoalForm(goalMethodAPI, submitText, goalName, matchAttribute, pattern, patternType, caseSensitive, revenue, goalId)
+{
+ $('#goal_name').val(goalName);
+ $('input[@name=match_attribute][value='+matchAttribute+']').attr('checked', true);
+ $('#match_attribute_name').html(mappingMatchTypeName[matchAttribute]);
+ $('#examples_pattern').html(mappingMatchTypeExamples[matchAttribute]);
+ $('option[value='+patternType+']').attr('selected', true);
+ $('input[name=pattern]').val(pattern);
+ $('#case_sensitive').attr('checked', caseSensitive);
+ $('input[name=revenue]').val(revenue);
+ $('input[name=methodGoalAPI]').val(goalMethodAPI);
+ $('#goal_submit').val(submitText);
+ if(goalId != undefined) {
+ $('input[name=goalIdUpdate]').val(goalId);
+ }
+}
+
+function initAndShowAddGoalForm()
+{
+ initGoalForm('Goals.addGoal', 'Add Goal', '', 'url', '', 'contains', false, '0');
+ return showAddNewGoal();
+}
+function bindGoalForm()
+{
+ $('input[@name=match_attribute]').click( function() {
+ var matchTypeId = $(this).attr('value');
+ $('#match_attribute_name').html(mappingMatchTypeName[matchTypeId]);
+ $('#examples_pattern').html(mappingMatchTypeExamples[matchTypeId]);
+ });
+
+ $('#goal_submit').click( function() {
+ // prepare ajax query to API to add goal
+ ajaxRequestAddGoal = getAjaxAddGoal();
+ $.ajax( ajaxRequestAddGoal );
+ return false;
+ });
+
+ $('a[name=linkAddNewGoal]').click( function(){
+ initAndShowAddGoalForm();
+ } );
+}
+
+function bindListGoalEdit()
+{
+ $('a[name=linkEditGoal]').click( function() {
+ var goalId = $(this).attr('id');
+ var goal = piwik.goals[goalId];
+ initGoalForm("Goals.updateGoal", "Update Goal", goal.name, goal.match_attribute, goal.pattern, goal.pattern_type, (goal.case_sensitive=='0' ? false : true), goal.revenue, goalId);
+ showAddNewGoal();
+ return false;
+ });
+
+ $('a[name=linkDeleteGoal]').click( function() {
+ var goalId = $(this).attr('id');
+ var goalName = 'test goal';//piwik.goals[goalId][name]
+ if(confirm(sprintf('Are you sure you want to delete the Goal %s?','"'+goalName+'"')))
+ {
+ $.ajax( getAjaxDeleteGoal( goalId ) );
+ return false;
+ }
+ });
+
+ $('a[name=linkEditGoals]').click( function(){
+ return showEditGoals();
+ } );
+}
+function getAjaxDeleteGoal(idGoal)
+{
+ var ajaxRequest = getStandardAjaxConf();
+ toggleAjaxLoading();
+
+ var parameters = new Object;
+ parameters.idSite = piwik.idSite;
+ parameters.idGoal = idGoal;
+ parameters.method = 'Goals.deleteGoal';
+ parameters.module = 'API';
+ parameters.format = 'json';
+ parameters.token_auth = piwik.token_auth;
+ ajaxRequest.data = parameters;
+ return ajaxRequest;
+}
+
+function getAjaxAddGoal()
+{
+ var ajaxRequest = getStandardAjaxConf();
+ toggleAjaxLoading();
+
+ var parameters = new Object;
+
+ parameters.idSite = piwik.idSite;
+ parameters.name = encodeURIComponent( $('#goal_name').val() );
+ parameters.matchAttribute = $('input[name=match_attribute][checked]').val();
+ parameters.patternType = $('[name=pattern_type]').val();
+ parameters.pattern = encodeURIComponent( $('input[name=pattern]').val() );
+ parameters.caseSensitive = $('#case_sensitive').attr('checked') == true ? 1: 0;
+ parameters.revenue = $('input[name=revenue]').val();
+
+ parameters.idGoal = $('input[name=goalIdUpdate]').val();
+ parameters.method = $('input[name=methodGoalAPI]').val();
+ parameters.module = 'API';
+ parameters.format = 'json';
+ parameters.token_auth = piwik.token_auth;
+
+ ajaxRequest.data = parameters;
+ return ajaxRequest;
+} \ No newline at end of file
diff --git a/plugins/Goals/templates/add_edit_goal.tpl b/plugins/Goals/templates/add_edit_goal.tpl
new file mode 100644
index 0000000000..2ca55ca102
--- /dev/null
+++ b/plugins/Goals/templates/add_edit_goal.tpl
@@ -0,0 +1,49 @@
+
+<div id="AddEditGoals">
+{if isset($onlyShowAddNewGoal)}
+ <h2>Add a new Goal</h2>
+{else}
+ <h2><a onclick='' name="linkAddNewGoal">+ Add a new Goal</a>
+ or <a onclick='' name="linkEditGoals">Edit</a> existing Goals</h2>
+{/if}
+
+ <div>
+ <div id="ajaxError" style="display:none"></div>
+ <div id="ajaxLoading" style="display:none"><div id="loadingPiwik"><img src="themes/default/images/loading-blue.gif" alt="" /> {'General_LoadingData'|translate}</div></div>
+ </div>
+
+{if !isset($onlyShowAddNewGoal)}
+ {include file="Goals/templates/list_goal_edit.tpl"}
+{/if}
+ {include file="Goals/templates/form_add_goal.tpl"}
+
+ <a id='bottom'></a>
+</div>
+
+{literal}
+<script type="text/javascript" src="plugins/Goals/templates/GoalForm.js"></script>
+<script language="javascript">
+
+var mappingMatchTypeName = {
+ "url": "URL",
+ "file": "filename",
+ "external_website": "external website URL"
+};
+var mappingMatchTypeExamples = {
+ "url": "eg. contains 'checkout/confirmation'<br>eg. is exactly 'http://example.com/thank-you.html'<br>eg. matches the expression '[.*]\\\/demo\\\/[.*]'",
+ "file": "eg. contains 'files/brochure.pdf'<br>eg. is exactly 'http://example.com/files/brochure.pdf'<br>eg. matches the expression '[.*]\\\.zip'",
+ "external_website": "eg. contains 'amazon.com'<br>eg. is exactly 'http://mypartner.com/landing.html'<br>eg. matches the expression 'http://www.amazon.com\\\/[.*]\\\/yourAffiliateId'"
+};
+
+bindGoalForm();
+
+{/literal}
+
+{if !isset($onlyShowAddNewGoal)}
+piwik.goals = {$goalsJSON};
+bindListGoalEdit();
+{else}
+initAndShowAddGoalForm();
+{/if}
+
+</script>
diff --git a/plugins/Goals/templates/add_new_goal.tpl b/plugins/Goals/templates/add_new_goal.tpl
new file mode 100644
index 0000000000..05a7f66e8d
--- /dev/null
+++ b/plugins/Goals/templates/add_new_goal.tpl
@@ -0,0 +1,8 @@
+
+{if $userCanEditGoals}
+ {include file=Goals/templates/add_edit_goal.tpl}
+{else}
+Only an Administrator or the Super User can add Goals for a given website.
+Please ask your Piwik administrator to set up a Goal for your website.
+<br>Tracking Goals are a great tool to help you maximize your website performance!
+{/if}
diff --git a/plugins/Goals/templates/form_add_goal.tpl b/plugins/Goals/templates/form_add_goal.tpl
new file mode 100644
index 0000000000..95c4f6d3d9
--- /dev/null
+++ b/plugins/Goals/templates/form_add_goal.tpl
@@ -0,0 +1,67 @@
+{literal}
+<style>
+.goalInlineHelp{
+color:#9B9B9B;
+}
+</style>
+{/literal}
+<span id='GoalForm' style="display:none;">
+<form>
+ <table class="tableForm">
+ <tr>
+ <td>Goal Name </td>
+ <td><input type="text" name="name" value="" id="goal_name" /></td>
+ </tr>
+ <tr>
+ <td>Goal is triggered when visitors:</td>
+ <td>
+ <input type="radio" id="match_attribute_url" value="url" name="match_attribute"/>
+ <label for="match_attribute_url">Visit a given URL (page or group of pages)</label>
+ <br>
+ <input type="radio" id="match_attribute_file" value="file" name="match_attribute"/>
+ <label for="match_attribute_file">Download a file</label>
+ <br>
+ <input type="radio" id="match_attribute_external_website" value="external_website" name="match_attribute"/>
+ <label for="match_attribute_external_website">Click on a Link to an external website </label>
+ </td>
+ </tr>
+ <tr>
+ <td>where the <span id="match_attribute_name"></span></td>
+ <td>
+ <select name="pattern_type">
+ <option value="contains">contains</option>
+ <option value="exact">is exactly</option>
+ <option value="regex">matches the expression</option>
+ </select>
+
+ <input type="text" name="pattern" value=""/>
+ <br>
+ <div id="examples_pattern" class="goalInlineHelp"></div>
+ <br>
+ <span style="float:right">
+ (optional) <input type="checkbox" id="case_sensitive"/>
+ <label for="case_sensitive">Case sensitive match</label>
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>(optional) Goal default value is </td>
+ <td>{$currency} <input type="text" name="revenue" size="1" value="0"/>
+ <div class="goalInlineHelp">
+ For example, a Contact Form submitted by a visitor <br>
+ may be worth $10 on average. Piwik will help you understand <br>
+ how well your visitors segments are performing.</div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" style="border:0">
+ <div class="submit">
+ <input type="hidden" name="methodGoalAPI" value="">
+ <input type="hidden" name="goalIdUpdate" value="">
+ <input type="submit" value="Add Goal" name="submit" id="goal_submit" class="submit" />
+ </div>
+ </td>
+ </tr>
+ </table>
+</form>
+</span> \ No newline at end of file
diff --git a/plugins/Goals/templates/list_goal_edit.tpl b/plugins/Goals/templates/list_goal_edit.tpl
new file mode 100644
index 0000000000..081497cade
--- /dev/null
+++ b/plugins/Goals/templates/list_goal_edit.tpl
@@ -0,0 +1,22 @@
+<span id='EditGoals' style="display:none;">
+ <table class="tableForm">
+ <thead style="font-weight:bold">
+ <td>Id</td>
+ <td>Goal Name</td>
+ <td>Goal is Triggered when</td>
+ <td>Revenue</td>
+ <td>Edit</td>
+ <td>Delete</td>
+ </thead>
+ {foreach from=$goals item=goal}
+ <tr>
+ <td>{$goal.idgoal}</td>
+ <td>{$goal.name}</td>
+ <td>{$goal.match_attribute} <br>Pattern {$goal.pattern_type}: {$goal.pattern}</b></td>
+ <td>{if $goal.revenue==0}-{else}{$currency}{$goal.revenue}{/if}</td>
+ <td><a href='#' name="linkEditGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/edit.png' border=0> Edit</a></td>
+ <td><a href='#' name="linkDeleteGoal" id="{$goal.idgoal}"><img src='plugins/UsersManager/images/remove.png' border=0> Delete</a></td>
+ </tr>
+ {/foreach}
+ </table>
+</span> \ No newline at end of file
diff --git a/plugins/Goals/templates/list_top_segment.tpl b/plugins/Goals/templates/list_top_segment.tpl
new file mode 100644
index 0000000000..6dbe69813f
--- /dev/null
+++ b/plugins/Goals/templates/list_top_segment.tpl
@@ -0,0 +1,5 @@
+
+{foreach from=$topSegment item=element name=topGoalElements}
+<span class='goalTopElement' title='<b>{$element.nb_conversions}</b> conversions, <b>{$element.conversion_rate}%</b> conversion rate'>
+{$element.name}</span>{logoHtml metadata=$element.metadata alt=$element.name}{if $smarty.foreach.topGoalElements.iteration == $smarty.foreach.topGoalElements.total-1} and {elseif $smarty.foreach.topGoalElements.iteration < $smarty.foreach.topGoalElements.total-1}, {else}{/if}
+{/foreach} {* (<a href=''>more</a>) *}
diff --git a/plugins/Goals/templates/overview.tpl b/plugins/Goals/templates/overview.tpl
new file mode 100644
index 0000000000..04bf1af90d
--- /dev/null
+++ b/plugins/Goals/templates/overview.tpl
@@ -0,0 +1,27 @@
+
+{include file="Goals/templates/title_and_evolution_graph.tpl"}
+
+{foreach from=$goalMetrics item=goal}
+{assign var=nb_conversions value=$goal.nb_conversions}
+{assign var=conversion_rate value=$goal.conversion_rate}
+<h2 style="padding-top: 30px;">{$goal.name} (goal)</h3>
+<table width=700px>
+ <tr><td>
+ <p>{sparkline src=$goal.urlSparklineConversions}<span>
+ {'%s conversions'|translate:"<strong>$nb_conversions</strong>"}</span></p>
+ </td><td>
+ <p>{sparkline src=$goal.urlSparklineConversionRate}<span>
+ {'%s conversion rate'|translate:"<strong>$conversion_rate%</strong>"}</span></p>
+ </td><td>
+ {* (<a href=''>more</a>) *}
+ </td></tr>
+</table>
+
+{/foreach}
+
+{if $userCanEditGoals}
+ <hr style="margin:30px 0px">
+ {include file=Goals/templates/add_edit_goal.tpl}
+{/if}
+
+{include file="Goals/templates/release_notes.tpl} \ No newline at end of file
diff --git a/plugins/Goals/templates/release_notes.tpl b/plugins/Goals/templates/release_notes.tpl
new file mode 100644
index 0000000000..dce9ec63b2
--- /dev/null
+++ b/plugins/Goals/templates/release_notes.tpl
@@ -0,0 +1,20 @@
+<hr>
+<b>About the Goal Tracking Plugin</b><br>
+<pre>
+The Goal Tracking Plugin is in alpha release. There is more coming soon!
+- The Goal Report page will display conversion table by search engines, country, keyword, campaign, etc.
+- The Goal Overview page will link to a Goal Report page with a "(more)" link that will ajax reload the page
+- Goals could be triggered using javascript event, with custom revenue
+- internationalization of all strings
+- provide documentation, screenshots, blog post + add screenshot and inline help in "Add a New Goal"
+- provide widgets for the dashboard, general goal overview, and one widget for each goal. With: graph evolution, sparklines. Widget with top segments for each goal.
+
+Known bugs
+- The Goal total nb conversions should be sum of all goal conversions (wrong number when deleting a Goal)
+- After adding goal, the window should refresh to the goal report page, and not to the dashboard
+- Outlink trailing slash is automatically deleted from the URL, there would be a problem when trying to exact match a URL with trailing slash
+- All graph labelling are not correct (always printing nb_uniq_visitors even when showing conversion or conversion_rate) see <a href='http://dev.piwik.org/trac/ticket/322'>#322</a>
+
+Give us Feedback!
+If you find any other bug, or if you have suggestions, please send us a message using the "Give us feedback" link at the top of the Piwik pages.
+</pre> \ No newline at end of file
diff --git a/plugins/Goals/templates/single_goal.tpl b/plugins/Goals/templates/single_goal.tpl
new file mode 100644
index 0000000000..b605c17490
--- /dev/null
+++ b/plugins/Goals/templates/single_goal.tpl
@@ -0,0 +1,37 @@
+{include file="Goals/templates/title_and_evolution_graph.tpl"}
+
+{if $nb_conversions > 0}
+ <h2>Conversions Overview</h2>
+ <ul class="ulGoalTopElements">
+ <li>Your best converting countries are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.country}</li>
+ {if count($topSegments.keyword)>0}<li>Your top converting keywords are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.keyword}</li>{/if}
+ {if count($topSegments.website)>0}<li>Your best converting websites referers are: {include file='Goals/templates/list_top_segment.tpl' topSegment=$topSegments.website}</li>{/if}
+ <li>Returning visitors conversion rate is <b>{$conversion_rate_returning}%</b>, New Visitors conversion rate is <b>{$conversion_rate_new}%</b></li>
+ </ul>
+{/if}
+
+
+{literal}
+<style>
+ul.ulGoalTopElements {
+ list-style-type:circle;
+ margin-left:30px;
+}
+.ulGoalTopElements a {
+ text-decoration:none;
+ color:#0033CC;
+ border-bottom:1px dotted #0033CC;
+ line-height:2em;
+}
+.goalTopElement {
+ border-bottom:1px dotted;
+}
+</style>
+<script>
+$(document).ready( function() {
+ $('.goalTopElement')
+ .Tooltip()
+ ;
+ });
+</script>
+{/literal} \ No newline at end of file
diff --git a/plugins/Goals/templates/title_and_evolution_graph.tpl b/plugins/Goals/templates/title_and_evolution_graph.tpl
new file mode 100644
index 0000000000..0b1b8d2c7b
--- /dev/null
+++ b/plugins/Goals/templates/title_and_evolution_graph.tpl
@@ -0,0 +1,20 @@
+<script type="text/javascript" src="plugins/CoreHome/templates/sparkline.js"></script>
+
+<a name="evolutionGraph" graphId="{$nameGraphEvolution}"></a>
+<h2>{$title}</h2>
+{$graphEvolution}
+
+<table>
+ <tr><td>
+ <p>{sparkline src=$urlSparklineConversions}<span>
+ {'%s conversions'|translate:"<strong>$nb_conversions</strong>"}</span></p>
+ {if $revenue != 0 }
+ <p>{sparkline src=$urlSparklineRevenue}<span>
+ {'%s overall revenue'|translate:"<strong>$currency$revenue</strong>"}</span></p>
+ {/if}
+ </td><td valign="top">
+ <p>{sparkline src=$urlSparklineConversionRate}<span>
+ {'%s overall conversion rate (visits with a completed goal)'|translate:"<strong>$conversion_rate%</strong>"}</span></p>
+ </td></tr>
+</table>
+
diff --git a/plugins/Installation/Controller.php b/plugins/Installation/Controller.php
index f843263eb9..1bee5cdbbf 100644
--- a/plugins/Installation/Controller.php
+++ b/plugins/Installation/Controller.php
@@ -1,135 +1,135 @@
-<?php
-/**
- * Piwik - Open source web analytics
- *
- * @link http://piwik.org
- * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
- * @version $Id$
- *
- * @package Piwik_Installation
- */
-
-require_once "Installation/View.php";
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_Installation_Controller extends Piwik_Controller
-{
- // public so plugins can add/delete installation steps
- public $steps = array(
- 'welcome',
- 'systemCheck',
- 'databaseSetup',
- 'tablesCreation',
- 'generalSetup',
- 'firstWebsiteSetup',
- 'displayJavascriptCode',
- 'finished'
- );
-
- protected $pathView = 'Installation/templates/';
-
- public function __construct()
- {
- if(!isset($_SESSION['currentStepDone']))
- {
- $_SESSION['currentStepDone'] = '';
- }
-
- Piwik_PostEvent('InstallationController.construct', $this);
- }
-
- public function getInstallationSteps()
- {
- return $this->steps;
- }
-
- function getDefaultAction()
- {
- return $this->steps[0];
- }
-
- function welcome()
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @package Piwik_Installation
+ */
+
+require_once "Installation/View.php";
+
+/**
+ *
+ * @package Piwik_Installation
+ */
+class Piwik_Installation_Controller extends Piwik_Controller
+{
+ // public so plugins can add/delete installation steps
+ public $steps = array(
+ 'welcome',
+ 'systemCheck',
+ 'databaseSetup',
+ 'tablesCreation',
+ 'generalSetup',
+ 'firstWebsiteSetup',
+ 'displayJavascriptCode',
+ 'finished'
+ );
+
+ protected $pathView = 'Installation/templates/';
+
+ public function __construct()
+ {
+ if(!isset($_SESSION['currentStepDone']))
+ {
+ $_SESSION['currentStepDone'] = '';
+ }
+
+ Piwik_PostEvent('InstallationController.construct', $this);
+ }
+
+ public function getInstallationSteps()
+ {
+ return $this->steps;
+ }
+
+ function getDefaultAction()
+ {
+ return $this->steps[0];
+ }
+
+ function welcome()
{
require_once "Login/Controller.php";
Piwik_Login_Controller::clearSession();
-
- $view = new Piwik_Install_View(
- $this->pathView . 'welcome.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->skipThisStep( __FUNCTION__ );
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function systemCheck()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'systemCheck.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->infos = $this->getSystemInformation();
- $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
-
- $view->showNextStep = !$view->problemWithSomeDirectories
- && $view->infos['phpVersion_ok']
- && $view->infos['pdo_ok']
- && $view->infos['pdo_mysql_ok']
-
- ;
- $_SESSION['currentStepDone'] = __FUNCTION__;
-
- echo $view->render();
- }
-
-
- function databaseSetup()
- {
- // case the user hits the back button
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
-
- $view = new Piwik_Install_View(
- $this->pathView . 'databaseSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- $view->showNextStep = false;
- require_once "FormDatabaseSetup.php";
- $form = new Piwik_Installation_FormDatabaseSetup;
-
- if($form->validate())
- {
- $dbInfos = array(
- 'host' => $form->getSubmitValue('host'),
- 'username' => $form->getSubmitValue('username'),
- 'password' => $form->getSubmitValue('password'),
- 'dbname' => $form->getSubmitValue('dbname'),
- 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
- 'adapter' => Zend_Registry::get('config')->database->adapter,
- 'port' => Zend_Registry::get('config')->database->port,
- );
-
- $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"';
-
- if(($portIndex = strpos($dbInfos['host'],':')) !== false)
- {
- $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
- $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
- }
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'welcome.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->skipThisStep( __FUNCTION__ );
+ $view->showNextStep = true;
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ function systemCheck()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'systemCheck.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $view->infos = $this->getSystemInformation();
+ $view->problemWithSomeDirectories = (false !== array_search(false, $view->infos['directories']));
+
+ $view->showNextStep = !$view->problemWithSomeDirectories
+ && $view->infos['phpVersion_ok']
+ && $view->infos['pdo_ok']
+ && $view->infos['pdo_mysql_ok']
+
+ ;
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+
+ echo $view->render();
+ }
+
+
+ function databaseSetup()
+ {
+ // case the user hits the back button
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'databaseSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ $view->showNextStep = false;
+ require_once "FormDatabaseSetup.php";
+ $form = new Piwik_Installation_FormDatabaseSetup;
+
+ if($form->validate())
+ {
+ $dbInfos = array(
+ 'host' => $form->getSubmitValue('host'),
+ 'username' => $form->getSubmitValue('username'),
+ 'password' => $form->getSubmitValue('password'),
+ 'dbname' => $form->getSubmitValue('dbname'),
+ 'tables_prefix' => $form->getSubmitValue('tables_prefix'),
+ 'adapter' => Zend_Registry::get('config')->database->adapter,
+ 'port' => Zend_Registry::get('config')->database->port,
+ );
+
+ $dbInfos['password'] = '"'.htmlspecialchars($form->getSubmitValue('password')).'"';
+
+ if(($portIndex = strpos($dbInfos['host'],':')) !== false)
+ {
+ $dbInfos['port'] = substr($dbInfos['host'], $portIndex + 1 );
+ $dbInfos['host'] = substr($dbInfos['host'], 0, $portIndex);
+ }
try{
try {
@@ -152,64 +152,64 @@ class Piwik_Installation_Controller extends Piwik_Controller
{
throw new Exception(vsprintf("Your MySQL version is %s but Piwik requires at least %s.", array($mysqlVersion, $minimumMysqlVersion)));
}
-
+
$_SESSION['db_infos'] = $dbInfos;
- $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
- }
- $view->addForm($form);
-
- $view->infos = $this->getSystemInformation();
-
- echo $view->render();
- }
-
- function tablesCreation()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'tablesCreation.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->createDbFromSessionInformation();
-
- if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
- {
- Piwik::dropTables();
- $view->existingTablesDeleted = true;
-
- // when the user decides to drop the tables then we dont skip the next steps anymore
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
- }
-
- $tablesInstalled = Piwik::getTablesInstalled();
- $tablesToInstall = Piwik::getTablesNames();
-
- if(count($tablesInstalled) > 0)
- {
- $view->someTablesInstalled = true;
- $view->tablesInstalled = implode(", ", $tablesInstalled);
-
- // when the user reuses the same tables we skip the website creation step
- $_SESSION['skipThisStep']['firstWebsiteSetup'] = true;
- $_SESSION['skipThisStep']['displayJavascriptCode'] = true;
- }
- else
- {
- Piwik::createTables();
- Piwik::createAnonymousUser();
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+ }
+ $view->addForm($form);
+
+ $view->infos = $this->getSystemInformation();
+
+ echo $view->render();
+ }
+
+ function tablesCreation()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'tablesCreation.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+ $this->createDbFromSessionInformation();
+
+ if(Piwik_Common::getRequestVar('deleteTables', 0, 'int') == 1)
+ {
+ Piwik::dropTables();
+ $view->existingTablesDeleted = true;
+
+ // when the user decides to drop the tables then we dont skip the next steps anymore
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = false;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = false;
+ }
+
+ $tablesInstalled = Piwik::getTablesInstalled();
+ $tablesToInstall = Piwik::getTablesNames();
+
+ if(count($tablesInstalled) > 0)
+ {
+ $view->someTablesInstalled = true;
+ $view->tablesInstalled = implode(", ", $tablesInstalled);
+
+ // when the user reuses the same tables we skip the website creation step
+ $_SESSION['skipThisStep']['firstWebsiteSetup'] = true;
+ $_SESSION['skipThisStep']['displayJavascriptCode'] = true;
+ }
+ else
+ {
+ Piwik::createTables();
+ Piwik::createAnonymousUser();
require_once "Version.php";
- require_once "Updater.php";
+ require_once "Updater.php";
$updater = new Piwik_Updater();
- $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
- $view->tablesCreated = true;
- $view->showNextStep = true;
- }
+ $updater->recordComponentSuccessfullyUpdated('core', Piwik_Version::VERSION);
+ $view->tablesCreated = true;
+ $view->showNextStep = true;
+ }
if(isset($_SESSION['databaseCreated'])
&& $_SESSION['databaseCreated'] === true)
@@ -218,294 +218,294 @@ class Piwik_Installation_Controller extends Piwik_Controller
$view->databaseCreated = true;
$_SESSION['databaseCreated'] = null;
}
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- function generalSetup()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'generalSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormGeneralSetup.php";
- $form = new Piwik_Installation_FormGeneralSetup;
-
- if($form->validate())
- {
- $superUserInfos = array(
- 'login' => $form->getSubmitValue('login'),
- 'password' => md5( $form->getSubmitValue('password') ),
- 'email' => $form->getSubmitValue('email'),
- );
-
- $_SESSION['superuser_infos'] = $superUserInfos;
- $this->redirectToNextStep( __FUNCTION__ );
- }
- $view->addForm($form);
-
- echo $view->render();
- }
-
- public function firstWebsiteSetup()
- {
-
- $view = new Piwik_Install_View(
- $this->pathView . 'firstWebsiteSetup.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- require_once "FormFirstWebsiteSetup.php";
- $form = new Piwik_Installation_FormFirstWebsiteSetup;
-
- if( !isset($_SESSION['generalSetupSuccessMessage']))
- {
- $view->displayGeneralSetupSuccess = true;
- $_SESSION['generalSetupSuccessMessage'] = true;
- }
-
- if($form->validate())
- {
- // we setup the superuser login & password in the config that will be checked by the
- // API authentication process
- Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos'];
-
- $name = urlencode($form->getSubmitValue('siteName'));
- $url = urlencode($form->getSubmitValue('url'));
-
- $this->initObjectsToCallAPI();
-
- require_once "API/Request.php";
- $request = new Piwik_API_Request("
- method=SitesManager.addSite
- &siteName=$name
- &urls=$url
- &format=original
- ");
-
- try {
- $result = $request->process();
- $_SESSION['site_idSite'] = $result;
- $_SESSION['site_name'] = $name;
- $_SESSION['site_url'] = $url;
-
- $this->redirectToNextStep( __FUNCTION__ );
- } catch(Exception $e) {
- $view->errorMessage = $e->getMessage();
- }
-
- }
- $view->addForm($form);
- echo $view->render();
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ function generalSetup()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'generalSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ require_once "FormGeneralSetup.php";
+ $form = new Piwik_Installation_FormGeneralSetup;
+
+ if($form->validate())
+ {
+ $superUserInfos = array(
+ 'login' => $form->getSubmitValue('login'),
+ 'password' => md5( $form->getSubmitValue('password') ),
+ 'email' => $form->getSubmitValue('email'),
+ );
+
+ $_SESSION['superuser_infos'] = $superUserInfos;
+ $this->redirectToNextStep( __FUNCTION__ );
+ }
+ $view->addForm($form);
+
+ echo $view->render();
}
-
- public function displayJavascriptCode()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'displayJavascriptCode.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
-
- if( !isset($_SESSION['firstWebsiteSetupSuccessMessage']))
- {
- $view->displayfirstWebsiteSetupSuccess = true;
- $_SESSION['firstWebsiteSetupSuccessMessage'] = true;
- }
-
-
- $view->websiteName = urldecode($_SESSION['site_name']);
-
- $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName());
-
- $view->javascriptTag = $jsTag;
- $view->showNextStep = true;
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- echo $view->render();
- }
-
- public function finished()
- {
- $view = new Piwik_Install_View(
- $this->pathView . 'finished.tpl',
- $this->getInstallationSteps(),
- __FUNCTION__
- );
- $this->checkPreviousStepIsValid( __FUNCTION__ );
- $this->skipThisStep( __FUNCTION__ );
- $this->writeConfigFileFromSession();
-
- $_SESSION['currentStepDone'] = __FUNCTION__;
- $view->showNextStep = false;
-
- setcookie(session_name(), session_id(), 1, '/');
- @session_destroy();
- echo $view->render();
- }
-
- protected function initObjectsToCallAPI()
- {
- // connect to the database using the DB infos currently in the session
- $this->createDbFromSessionInformation();
-
- // create the fake access to grant super user privilege
- Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser);
-
- // we need to create the logs otherwise the API request throws an exception
- Piwik::createLogObject();
- }
-
- protected function writeConfigFileFromSession()
+
+ public function firstWebsiteSetup()
+ {
+
+ $view = new Piwik_Install_View(
+ $this->pathView . 'firstWebsiteSetup.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ require_once "FormFirstWebsiteSetup.php";
+ $form = new Piwik_Installation_FormFirstWebsiteSetup;
+
+ if( !isset($_SESSION['generalSetupSuccessMessage']))
+ {
+ $view->displayGeneralSetupSuccess = true;
+ $_SESSION['generalSetupSuccessMessage'] = true;
+ }
+
+ if($form->validate())
+ {
+ // we setup the superuser login & password in the config that will be checked by the
+ // API authentication process
+ Zend_Registry::get('config')->superuser = $_SESSION['superuser_infos'];
+
+ $name = urlencode($form->getSubmitValue('siteName'));
+ $url = urlencode($form->getSubmitValue('url'));
+
+ $this->initObjectsToCallAPI();
+
+ require_once "API/Request.php";
+ $request = new Piwik_API_Request("
+ method=SitesManager.addSite
+ &siteName=$name
+ &urls=$url
+ &format=original
+ ");
+
+ try {
+ $result = $request->process();
+ $_SESSION['site_idSite'] = $result;
+ $_SESSION['site_name'] = $name;
+ $_SESSION['site_url'] = $url;
+
+ $this->redirectToNextStep( __FUNCTION__ );
+ } catch(Exception $e) {
+ $view->errorMessage = $e->getMessage();
+ }
+
+ }
+ $view->addForm($form);
+ echo $view->render();
+ }
+
+ public function displayJavascriptCode()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'displayJavascriptCode.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+
+ if( !isset($_SESSION['firstWebsiteSetupSuccessMessage']))
+ {
+ $view->displayfirstWebsiteSetupSuccess = true;
+ $_SESSION['firstWebsiteSetupSuccessMessage'] = true;
+ }
+
+
+ $view->websiteName = urldecode($_SESSION['site_name']);
+
+ $jsTag = Piwik::getJavascriptCode($_SESSION['site_idSite'], Piwik_Url::getCurrentUrlWithoutFileName());
+
+ $view->javascriptTag = $jsTag;
+ $view->showNextStep = true;
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ echo $view->render();
+ }
+
+ public function finished()
+ {
+ $view = new Piwik_Install_View(
+ $this->pathView . 'finished.tpl',
+ $this->getInstallationSteps(),
+ __FUNCTION__
+ );
+ $this->checkPreviousStepIsValid( __FUNCTION__ );
+ $this->skipThisStep( __FUNCTION__ );
+ $this->writeConfigFileFromSession();
+
+ $_SESSION['currentStepDone'] = __FUNCTION__;
+ $view->showNextStep = false;
+
+ setcookie(session_name(), session_id(), 1, '/');
+ @session_destroy();
+ echo $view->render();
+ }
+
+ protected function initObjectsToCallAPI()
+ {
+ // connect to the database using the DB infos currently in the session
+ $this->createDbFromSessionInformation();
+
+ // create the fake access to grant super user privilege
+ Zend_Registry::set('access', new Piwik_FakeAccess_SetSuperUser);
+
+ // we need to create the logs otherwise the API request throws an exception
+ Piwik::createLogObject();
+ }
+
+ protected function writeConfigFileFromSession()
{
if(!isset($_SESSION['superuser_infos'])
|| !isset($_SESSION['db_infos']))
{
return;
- }
- $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
- $configFile .= "; file automatically generated during the piwik installation process\n";
-
- // super user information
- $configFile .= "[superuser]\n";
- foreach( $_SESSION['superuser_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
- $configFile .= "\n";
-
- // database information
- $configFile .= "[database]\n";
- foreach($_SESSION['db_infos'] as $key => $value)
- {
- $configFile .= "$key = $value\n";
- }
-
- file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile);
- }
- /**
- * The previous step is valid if it is either
- * - any step before (OK to go back)
- * - the current step (case when validating a form)
- */
- function checkPreviousStepIsValid( $currentStep )
+ }
+ $configFile = "; <?php exit; ?> DO NOT REMOVE THIS LINE\n";
+ $configFile .= "; file automatically generated during the piwik installation process\n";
+
+ // super user information
+ $configFile .= "[superuser]\n";
+ foreach( $_SESSION['superuser_infos'] as $key => $value)
+ {
+ $configFile .= "$key = $value\n";
+ }
+ $configFile .= "\n";
+
+ // database information
+ $configFile .= "[database]\n";
+ foreach($_SESSION['db_infos'] as $key => $value)
+ {
+ $configFile .= "$key = $value\n";
+ }
+
+ file_put_contents(Piwik_Config::getDefaultUserConfigPath(), $configFile);
+ }
+ /**
+ * The previous step is valid if it is either
+ * - any step before (OK to go back)
+ * - the current step (case when validating a form)
+ */
+ function checkPreviousStepIsValid( $currentStep )
{
if(empty($_SESSION['currentStepDone']))
{
return;
- }
- // the currentStep
- $currentStepId = array_search($currentStep, $this->steps);
-
- // the step before
- $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps);
+ }
+ // the currentStep
+ $currentStepId = array_search($currentStep, $this->steps);
+
+ // the step before
+ $previousStepId = array_search($_SESSION['currentStepDone'], $this->steps);
- // not OK if currentStepId > previous+1
- if( $currentStepId > $previousStepId + 1 )
- {
- $message = "Error: it seems you try to skip a step of the Installation process,
- or your cookies are disabled.
- <br /><b>Make sure your cookies are enabled</b> and go back
- <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'>
- to the first page of the installation</a>.";
- Piwik::exitWithErrorMessage( $message );
- }
- }
-
- protected function redirectToNextStep($currentStep)
- {
- $_SESSION['currentStepDone'] = $currentStep;
- $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)];
- Piwik::redirectToModule('Installation' , $nextStep);
- }
-
- protected function createDbFromSessionInformation()
- {
- $dbInfos = $_SESSION['db_infos'];
-
- Zend_Registry::get('config')->database = $dbInfos;
- Piwik::createDatabaseObject($dbInfos);
- }
-
- protected function getSystemInformation()
- {
- $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version;
- $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
-
- $infos = array();
-
- $infos['directories'] = Piwik::checkDirectoriesWritable();
- $infos['phpVersion_minimum'] = $minimumPhpVersion;
- $infos['phpVersion'] = phpversion();
- $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1;
-
- $extensions = @get_loaded_extensions();
-
- $infos['pdo_ok'] = false;
- if (in_array('PDO', $extensions))
- {
- $infos['pdo_ok'] = true;
- }
-
- $infos['pdo_mysql_ok'] = false;
- if (in_array('pdo_mysql', $extensions))
- {
- $infos['pdo_mysql_ok'] = true;
- }
-
- $infos['gd_ok'] = false;
- if (in_array('gd', $extensions))
- {
- $gdInfo = gd_info();
- $infos['gd_version'] = $gdInfo['GD Version'];
- ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion);
- if($gdVersion[0] >= 2)
- {
- $infos['gd_ok'] = true;
- }
- }
-
- $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']);
- $infos['serverOs'] = @php_uname();
- $infos['serverTime'] = date('H:i:s');
-
- $infos['setTimeLimit_ok'] = false;
- if(function_exists( 'set_time_limit'))
- {
- $infos['setTimeLimit_ok'] = true;
- }
-
- $infos['mail_ok'] = false;
- if(function_exists('mail'))
- {
- $infos['mail_ok'] = true;
- }
-
- $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
- $infos['memoryMinimum'] = $minimumMemoryLimit;
-
- $infos['memory_ok'] = true;
- // on windows the ini_get is not working?
- $infos['memoryCurrent'] = '?M';
-
- $raised = Piwik::raiseMemoryLimitIfNecessary();
- if( $memoryValue = Piwik::getMemoryLimitValue() )
- {
- $infos['memoryCurrent'] = $memoryValue."M";
- $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
- }
-
- return $infos;
+ // not OK if currentStepId > previous+1
+ if( $currentStepId > $previousStepId + 1 )
+ {
+ $message = "Error: it seems you try to skip a step of the Installation process,
+ or your cookies are disabled.
+ <br /><b>Make sure your cookies are enabled</b> and go back
+ <a href='".Piwik_Url::getCurrentUrlWithoutFileName()."'>
+ to the first page of the installation</a>.";
+ Piwik::exitWithErrorMessage( $message );
+ }
+ }
+
+ protected function redirectToNextStep($currentStep)
+ {
+ $_SESSION['currentStepDone'] = $currentStep;
+ $nextStep = $this->steps[1 + array_search($currentStep, $this->steps)];
+ Piwik::redirectToModule('Installation' , $nextStep);
+ }
+
+ protected function createDbFromSessionInformation()
+ {
+ $dbInfos = $_SESSION['db_infos'];
+
+ Zend_Registry::get('config')->database = $dbInfos;
+ Piwik::createDatabaseObject($dbInfos);
+ }
+
+ protected function getSystemInformation()
+ {
+ $minimumPhpVersion = Zend_Registry::get('config')->General->minimum_php_version;
+ $minimumMemoryLimit = Zend_Registry::get('config')->General->minimum_memory_limit;
+
+ $infos = array();
+
+ $infos['directories'] = Piwik::checkDirectoriesWritable();
+ $infos['phpVersion_minimum'] = $minimumPhpVersion;
+ $infos['phpVersion'] = phpversion();
+ $infos['phpVersion_ok'] = version_compare( $minimumPhpVersion, $infos['phpVersion']) === -1;
+
+ $extensions = @get_loaded_extensions();
+
+ $infos['pdo_ok'] = false;
+ if (in_array('PDO', $extensions))
+ {
+ $infos['pdo_ok'] = true;
+ }
+
+ $infos['pdo_mysql_ok'] = false;
+ if (in_array('pdo_mysql', $extensions))
+ {
+ $infos['pdo_mysql_ok'] = true;
+ }
+
+ $infos['gd_ok'] = false;
+ if (in_array('gd', $extensions))
+ {
+ $gdInfo = gd_info();
+ $infos['gd_version'] = $gdInfo['GD Version'];
+ ereg ("([0-9]{1})", $gdInfo['GD Version'], $gdVersion);
+ if($gdVersion[0] >= 2)
+ {
+ $infos['gd_ok'] = true;
+ }
+ }
+
+ $infos['serverVersion'] = addslashes($_SERVER['SERVER_SOFTWARE']);
+ $infos['serverOs'] = @php_uname();
+ $infos['serverTime'] = date('H:i:s');
+
+ $infos['setTimeLimit_ok'] = false;
+ if(function_exists( 'set_time_limit'))
+ {
+ $infos['setTimeLimit_ok'] = true;
+ }
+
+ $infos['mail_ok'] = false;
+ if(function_exists('mail'))
+ {
+ $infos['mail_ok'] = true;
+ }
+
+ $infos['registerGlobals_ok'] = ini_get('register_globals') == 0;
+ $infos['memoryMinimum'] = $minimumMemoryLimit;
+
+ $infos['memory_ok'] = true;
+ // on windows the ini_get is not working?
+ $infos['memoryCurrent'] = '?M';
+
+ $raised = Piwik::raiseMemoryLimitIfNecessary();
+ if( $memoryValue = Piwik::getMemoryLimitValue() )
+ {
+ $infos['memoryCurrent'] = $memoryValue."M";
+ $infos['memory_ok'] = $memoryValue >= $minimumMemoryLimit;
+ }
+
+ return $infos;
}
@@ -516,18 +516,18 @@ class Piwik_Installation_Controller extends Piwik_Controller
{
$this->redirectToNextStep($step);
}
- }
-}
-
-
-/**
- *
- * @package Piwik_Installation
- */
-class Piwik_FakeAccess_SetSuperUser {
- function checkUserIsSuperUser()
- {
- return true;
- }
- function loadAccess() {}
-}
+ }
+}
+
+
+/**
+ *
+ * @package Piwik_Installation
+ */
+class Piwik_FakeAccess_SetSuperUser {
+ function checkUserIsSuperUser()
+ {
+ return true;
+ }
+ function loadAccess() {}
+}
diff --git a/plugins/Installation/templates/firstWebsiteSetup.tpl b/plugins/Installation/templates/firstWebsiteSetup.tpl
index ca83f4ccd8..3c0446bc3c 100644
--- a/plugins/Installation/templates/firstWebsiteSetup.tpl
+++ b/plugins/Installation/templates/firstWebsiteSetup.tpl
@@ -9,8 +9,6 @@
<h1>{'Installation_SetupWebsite'|translate}</h1>
-
-
{if isset($errorMessage)}
<div class="error">
<img src="themes/default/images/error_medium.png">
@@ -20,7 +18,6 @@
</div>
{/if}
-
{if isset($form_data)}
{include file=default/genericForm.tpl}
{/if}
diff --git a/plugins/LanguagesManager/API.php b/plugins/LanguagesManager/API.php
index 20411a7021..edb5d1aa7b 100644
--- a/plugins/LanguagesManager/API.php
+++ b/plugins/LanguagesManager/API.php
@@ -2,7 +2,7 @@
/**
* @package Piwik_LanguagesManager
*/
-class Piwik_LanguagesManager_API extends Piwik_Apiable
+class Piwik_LanguagesManager_API
{
static private $instance = null;
static public function getInstance()
diff --git a/plugins/Live/API.php b/plugins/Live/API.php
new file mode 100644
index 0000000000..3ff93c223a
--- /dev/null
+++ b/plugins/Live/API.php
@@ -0,0 +1,143 @@
+<?php
+require_once "Live/Visitor.php";
+
+class Piwik_Live_API
+{
+ static private $instance = null;
+
+ /*
+ * @return Piwik_Live_API
+ */
+ static public function getInstance()
+ {
+ if (self::$instance == null)
+ {
+ $c = __CLASS__;
+ self::$instance = new $c();
+ }
+ return self::$instance;
+ }
+
+ /*
+ * @return Piwik_DataTable
+ */
+ public function getLastVisitForVisitor( $visitorId, $idSite = null )
+ {
+ return $this->getLastVisitsForVisitor($visitorId, $idSite, 1);
+ }
+
+ /*
+ * @return Piwik_DataTable
+ */
+ public function getLastVisitsForVisitor( $visitorId, $idSite, $limit = 10 )
+ {
+ if(is_null($idSite))
+ {
+ Piwik::checkUserIsSuperUser();
+ }
+ else
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+ }
+ $visitorDetails = self::loadLastVisitorDetailsFromDatabase($visitorId, $idSite, $limit);
+ $table = self::getCleanedVisitorsFromDetails($visitorDetails);
+ return $table;
+ }
+
+ /*
+ * @return Piwik_DataTable
+ */
+ public function getLastVisits( $idSite = false, $limit = 10, $minIdVisit = false )
+ {
+ if(is_null($idSite))
+ {
+ Piwik::checkUserIsSuperUser();
+ }
+ else
+ {
+ Piwik::checkUserHasViewAccess($idSite);
+ }
+ $visitorDetails = self::loadLastVisitorDetailsFromDatabase(null, $idSite, $limit, $minIdVisit);
+ $table = self::getCleanedVisitorsFromDetails($visitorDetails);
+ return $table;
+ }
+
+ /*
+ * @return Piwik_DataTable
+ */
+ static private function getCleanedVisitorsFromDetails($visitorDetails)
+ {
+ $table = new Piwik_DataTable();
+ foreach($visitorDetails as $visitorDetail)
+ {
+ self::cleanVisitorDetails($visitorDetail);
+ $visitor = new Piwik_Live_Visitor($visitorDetail);
+ $visitorDetailsArray = $visitor->getAllVisitorDetails();
+ $dateTimeVisit = Piwik_Date::factory($visitorDetailsArray['firstActionTimestamp']);
+ $visitorDetailsArray['serverDatePretty'] = $dateTimeVisit->getLocalized('%a %d %b');
+ $visitorDetailsArray['serverTimePretty'] = $dateTimeVisit->getLocalized('%X');
+ $table->addRowFromArray( array(Piwik_DataTable_Row::COLUMNS => $visitorDetailsArray));
+ }
+ return $table;
+ }
+
+ /*
+ * @return array
+ */
+ private function loadLastVisitorDetailsFromDatabase($visitorId = null, $idSite = null, $limit = null, $minIdVisit = false )
+ {
+ $where = $whereBind = array();
+
+ if(!is_null($idSite))
+ {
+ $where[] = " idsite = ? ";
+ $whereBind[] = $idSite;
+ }
+
+ if(!is_null($visitorId))
+ {
+ $where[] = " visitor_idcookie = ? ";
+ $whereBind[] = $visitorId;
+ }
+
+ if(!$minIdVisit)
+ {
+ $where[] = " idvisit > ? ";
+ $whereBind[] = $minIdVisit;
+ }
+
+ $sqlWhere = "";
+ if(count($where) > 0)
+ {
+ $sqlWhere = " WHERE " . join(' AND ', $where);
+ }
+
+ $sql = "SELECT *
+ FROM " . Piwik::prefixTable('log_visit') . "
+ $sqlWhere
+ ORDER BY idvisit DESC
+ LIMIT $limit";
+
+ return Piwik_FetchAll($sql, $whereBind);
+ }
+
+ /*
+ * @return void
+ */
+ static private function cleanVisitorDetails( &$visitorDetails )
+ {
+ $toUnset = array('config_md5config');
+ if(!Piwik::isUserIsSuperUser())
+ {
+ $toUnset[] = 'visitor_idcookie';
+ $toUnset[] = 'location_ip';
+ }
+ foreach($toUnset as $keyName)
+ {
+ if(isset($visitorDetails[$keyName]))
+ {
+ unset($visitorDetails[$keyName]);
+ }
+ }
+ }
+}
diff --git a/plugins/Live/Controller.php b/plugins/Live/Controller.php
new file mode 100644
index 0000000000..aeb13829d9
--- /dev/null
+++ b/plugins/Live/Controller.php
@@ -0,0 +1,37 @@
+<?php
+require_once 'Live/API.php';
+
+Piwik_AddWidget('Live', 'widget', 'Live Visitors!');
+
+class Piwik_Live_Controller extends Piwik_Controller
+{
+ function widget()
+ {
+ echo "Live Visitors!";
+ }
+
+ function getLastVisits($fetch = false)
+ {
+ $idSite = Piwik_Common::getRequestVar('idSite', null, 'int');
+ $limit = 10;
+ $api = new Piwik_API_Request("method=Live.getLastVisits&idSite=$idSite&limit=$limit&format=php&serialize=0&disable_generic_filters=1");
+
+ $view = new Piwik_View('Live/templates/lastVisits.tpl');
+ $view->visitors = $api->process();
+ $rendered = $view->render($fetch);
+
+ if($fetch)
+ {
+ return $rendered;
+ }
+ echo $rendered;
+ }
+
+ function index()
+ {
+ $view = new Piwik_View('Live/templates/index.tpl');
+ $this->setGeneralVariablesView($view);
+ $view->visitors = $this->getLastVisits($fetch = true);
+ echo $view->render();
+ }
+}
diff --git a/plugins/Live/Live.php b/plugins/Live/Live.php
new file mode 100644
index 0000000000..d6432bf447
--- /dev/null
+++ b/plugins/Live/Live.php
@@ -0,0 +1,14 @@
+<?php
+class Piwik_Live extends Piwik_Plugin
+{
+ public function getInformation()
+ {
+ return array(
+ 'name' => 'Live Visitors',
+ 'description' => 'Live Visitors!',
+ 'author' => 'Piwik',
+ 'homepage' => 'http://piwik.org/',
+ 'version' => '0.1',
+ );
+ }
+}
diff --git a/plugins/Live/Visitor.php b/plugins/Live/Visitor.php
new file mode 100644
index 0000000000..0145641a69
--- /dev/null
+++ b/plugins/Live/Visitor.php
@@ -0,0 +1,262 @@
+<?php
+//TODO add api to get actions name/count/first/last/etc
+require_once "Referers/functions.php";
+require_once "UserCountry/functions.php";
+require_once "UserSettings/functions.php";
+require_once "Provider/functions.php";
+
+class Piwik_Live_Visitor
+{
+ function __construct($visitorRawData)
+ {
+ $this->details = $visitorRawData;
+ }
+
+ function getAllVisitorDetails()
+ {
+ return array(
+ 'ip' => $this->getIp(),
+ 'idVisit' => $this->getIdVisit(),
+ 'countActions' => $this->getNumberOfActions(),
+ 'isVisitorReturning' => $this->isVisitorReturning(),
+ 'country' => $this->getCountryName(),
+ 'countryFlag' => $this->getCountryFlag(),
+ 'continent' => $this->getContinent(),
+ 'provider' => $this->getProvider(),
+ 'providerUrl' => $this->getProviderUrl(),
+ 'idSite' => $this->getIdSite(),
+ 'serverDate' => $this->getServerDate(),
+ 'visitLength' => $this->getVisitLength(),
+ 'visitLengthPretty' => $this->getVisitLengthPretty(),
+ 'firstActionTimestamp' => $this->getTimestampFirstAction(),
+ 'lastActionTimestamp' => $this->getTimestampLastAction(),
+
+ 'refererType' => $this->getRefererType(),
+ 'refererName' => $this->getRefererTypeName(),
+ 'keywords' => $this->getKeywords(),
+ 'refererUrl' => $this->getRefererUrl(),
+ 'refererName' => $this->getRefererName(),
+ 'searchEngineUrl' => $this->getSearchEngineUrl(),
+ 'searchEngineIcon' => $this->getSearchEngineIcon(),
+
+ 'operatingSystem' => $this->getOperatingSystem(),
+ 'operatingSystemShortName' => $this->getOperatingSystemShortName(),
+ 'operatingSystemIcon' => $this->getOperatingSystemIcon(),
+ 'browserFamily' => $this->getBrowserFamily(),
+ 'browserFamilyDescription' => $this->getBrowserFamilyDescription(),
+ 'browser' => $this->getBrowser(),
+ 'browserIcon' => $this->getBrowserIcon(),
+ 'screen' => $this->getScreenType(),
+ 'resolution' => $this->getResolution(),
+ 'screenIcon' => $this->getScreenTypeIcon(),
+ 'plugins' => $this->getPlugins(),
+ );
+ }
+
+ function getServerDate()
+ {
+ return $this->details['visit_server_date'];
+ }
+
+ function getIp()
+ {
+ if(isset($this->details['location_ip']))
+ {
+ return long2ip($this->details['location_ip']);
+ }
+ return false;
+ }
+
+ function getIdVisit()
+ {
+ return $this->details['idvisit'];
+ }
+
+ function getIdSite()
+ {
+ return $this->details['idsite'];
+ }
+
+ function getNumberOfActions()
+ {
+ return $this->details['visit_total_actions'];
+ }
+
+ function getVisitLength()
+ {
+ return $this->details['visit_total_time'];
+ }
+
+ function getVisitLengthPretty()
+ {
+ return Piwik::getPrettyTimeFromSeconds($this->details['visit_total_time']);
+ }
+
+ function isVisitorReturning()
+ {
+ return $this->details['visitor_returning'];
+ }
+
+ function getTimestampFirstAction()
+ {
+ return strtotime($this->details['visit_first_action_time']);
+ }
+
+ function getTimestampLastAction()
+ {
+ return strtotime($this->details['visit_last_action_time']);
+ }
+
+ function getCountryName()
+ {
+ return Piwik_CountryTranslate($this->details['location_country']);
+ }
+
+ function getCountryFlag()
+ {
+ return Piwik_getFlagFromCode($this->details['location_country']);
+ }
+
+ function getContinent()
+ {
+ return Piwik_ContinentTranslate($this->details['location_continent']);
+ }
+
+ function getRefererType()
+ {
+ $map = array(
+ Piwik_Common::REFERER_TYPE_SEARCH_ENGINE => 'searchEngine',
+ Piwik_Common::REFERER_TYPE_WEBSITE => 'website',
+ Piwik_Common::REFERER_TYPE_DIRECT_ENTRY => 'directEntry',
+ Piwik_Common::REFERER_TYPE_CAMPAIGN => 'campaign',
+ );
+ if(isset($map[$this->details['referer_type']]))
+ {
+ return $map[$this->details['referer_type']];
+ }
+ return $map[Piwik_Common::REFERER_TYPE_DIRECT_ENTRY];
+ }
+
+ function getRefererTypeName()
+ {
+ return Piwik_getRefererTypeLabel($this->details['referer_type']);
+ }
+
+ function getKeywords()
+ {
+ return $this->details['referer_keyword'];
+ }
+
+ function getRefererUrl()
+ {
+ return $this->details['referer_url'];
+ }
+
+ function getRefererName()
+ {
+ return $this->details['referer_name'];
+ }
+
+ function getSearchEngineUrl()
+ {
+ if($this->getRefererType() == 'searchEngine'
+ && !empty($this->details['referer_name']))
+ {
+ return Piwik_getSearchEngineUrlFromName($this->details['referer_name']);
+ }
+ return null;
+ }
+
+ function getSearchEngineIcon()
+ {
+ $searchEngine = $this->getSearchEngineUrl();
+ if( !is_null($searchEngine) )
+ {
+ return Piwik_getSearchEngineLogoFromName($searchEngine);
+ }
+ return null;
+ }
+
+ function getPlugins()
+ {
+ $plugins = array(
+ 'config_pdf',
+ 'config_flash',
+ 'config_java',
+ 'config_director',
+ 'config_quicktime',
+ 'config_realplayer',
+ 'config_windowsmedia'
+ );
+ $return = array();
+ foreach($plugins as $plugin)
+ {
+ if($this->details[$plugin] == 1)
+ {
+ $pluginShortName = substr($plugin, 7);
+ $return[] = $pluginShortName;
+ }
+ }
+ return implode(", ", $return);
+ }
+
+ function getOperatingSystem()
+ {
+ return Piwik_getOSLabel($this->details['config_os']);
+ }
+
+ function getOperatingSystemShortName()
+ {
+ return Piwik_getOSShortLabel($this->details['config_os']);
+ }
+
+ function getOperatingSystemIcon()
+ {
+ return Piwik_getOSLogo($this->details['config_os']);
+ }
+
+ function getBrowserFamilyDescription()
+ {
+ return Piwik_getBrowserTypeLabel($this->getBrowserFamily());
+ }
+
+ function getBrowserFamily()
+ {
+ return Piwik_getBrowserFamily($this->details['config_browser_name']);
+ }
+
+ function getBrowser()
+ {
+ return Piwik_getBrowserLabel($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
+ }
+
+ function getBrowserIcon()
+ {
+ return Piwik_getBrowsersLogo($this->details['config_browser_name'] . ";" . $this->details['config_browser_version']);
+ }
+
+ function getScreenType()
+ {
+ return Piwik_getScreenTypeFromResolution($this->details['config_resolution']);
+ }
+
+ function getResolution()
+ {
+ return $this->details['config_resolution'];
+ }
+
+ function getScreenTypeIcon()
+ {
+ return Piwik_getScreensLogo($this->getScreenType());
+ }
+
+ function getProvider()
+ {
+ return Piwik_getHostnameName($this->details['location_provider']);
+ }
+
+ function getProviderUrl()
+ {
+ return Piwik_getHostnameUrl($this->details['location_provider']);
+ }
+}
diff --git a/plugins/Live/templates/images/pause.gif b/plugins/Live/templates/images/pause.gif
new file mode 100644
index 0000000000..5954f9f545
--- /dev/null
+++ b/plugins/Live/templates/images/pause.gif
Binary files differ
diff --git a/plugins/Live/templates/images/pause_disabled.gif b/plugins/Live/templates/images/pause_disabled.gif
new file mode 100644
index 0000000000..98b79f7402
--- /dev/null
+++ b/plugins/Live/templates/images/pause_disabled.gif
Binary files differ
diff --git a/plugins/Live/templates/images/play.gif b/plugins/Live/templates/images/play.gif
new file mode 100644
index 0000000000..87eded433b
--- /dev/null
+++ b/plugins/Live/templates/images/play.gif
Binary files differ
diff --git a/plugins/Live/templates/images/play_disabled.gif b/plugins/Live/templates/images/play_disabled.gif
new file mode 100644
index 0000000000..ef69513d69
--- /dev/null
+++ b/plugins/Live/templates/images/play_disabled.gif
Binary files differ
diff --git a/plugins/Live/templates/images/returningVisitor.gif b/plugins/Live/templates/images/returningVisitor.gif
new file mode 100644
index 0000000000..bc71867e55
--- /dev/null
+++ b/plugins/Live/templates/images/returningVisitor.gif
Binary files differ
diff --git a/plugins/Live/templates/index.tpl b/plugins/Live/templates/index.tpl
new file mode 100644
index 0000000000..a30eef0739
--- /dev/null
+++ b/plugins/Live/templates/index.tpl
@@ -0,0 +1,83 @@
+{assign var=showSitesSelection value=true}
+{assign var=showPeriodSelection value=false}
+{include file="CoreAdminHome/templates/header.tpl"}
+
+<h1> Plugin Development version </h1>
+
+{literal}
+<script type="text/javascript" src="plugins/Live/templates/scripts/spy.js"></script>
+
+<script type="text/javascript" charset="utf-8">
+ $(document).ready(function() {
+ $('#visits').spy({ limit: 10, 'fadeInSpeed': '1400', ajax: 'index.php?module=Live&idSite=1&action=getLastVisits', timeout: 5000, customParameterName: 'minIdVisit', customParameterValueCallback: lastIdVisit, fadeInSpeed: 1400 });
+ });
+
+ function lastIdVisit()
+ {
+ return $('#visits > div:lt(2) .idvisit').html();
+ }
+ var pauseImage = "plugins/Live/templates/images/pause.gif";
+ var pauseDisabledImage = "plugins/Live/templates/images/pause_disabled.gif";
+ var playImage = "plugins/Live/templates/images/play.gif";
+ var playDisabledImage = "plugins/Live/templates/images/play_disabled.gif";
+
+ function onClickPause()
+ {
+ $('#pauseImage').attr('src', pauseImage);
+ $('#playImage').attr('src', playDisabledImage);
+ return pauseSpy();
+ }
+ function onClickPlay()
+ {
+ $('#playImage').attr('src', playImage);
+ $('#pauseImage').attr('src', pauseDisabledImage);
+ return playSpy();
+ }
+
+</script>
+
+<style>
+#visits {
+ text-align:left;
+}
+#visits .datetime, #visits .country, #visits .referer, #visits .settings, #visits .returning {
+ float:left;
+ margin-right:10px;
+ overflow:hidden;
+ padding-left:1px;
+ max-width:700px;
+}
+#visits .datetime {
+ width:110px;
+}
+#visits .country {
+ width:30px;
+}
+#visits .referer {
+ width:200px;
+}
+#visits .settings {
+ width:100px;
+}
+#visits .returning {
+ width:30px;
+}
+#visits .visit {
+ border-bottom:1px solid #C1DAD7;
+ background-color:#F9FAFA;
+ padding:10px;
+ line-height:24px;
+ height:40px;
+}
+#visits .alt {
+ background-color:#FFFFFF;
+}
+</style>
+{/literal}
+
+{$visitors}
+
+<div>
+ <a href="#?" onclick="onClickPause();"><img id="pauseImage" border="0" src="plugins/Live/templates/images/pause_disabled.gif"></a>
+ <a href="#?" onclick="onClickPlay();"><img id="playImage" border="0" src="plugins/Live/templates/images/play.gif"></a>
+</div>
diff --git a/plugins/Live/templates/lastVisits.tpl b/plugins/Live/templates/lastVisits.tpl
new file mode 100644
index 0000000000..ac515f2d63
--- /dev/null
+++ b/plugins/Live/templates/lastVisits.tpl
@@ -0,0 +1,15 @@
+<div id="visits">
+{foreach from=$visitors item=visitor}
+ <div class="visit{if $visitor.idVisit % 2} alt{/if}">
+ <div style="display:none" class="idvisit">{$visitor.idVisit}</div>
+ <div class="datetime">{$visitor.serverDatePretty}<br/>{$visitor.serverTimePretty}</div>
+ <div class="country"><img src="{$visitor.countryFlag}" title="{$visitor.country}, Provider {$visitor.provider}"></div>
+ <div class="referer">{if $visitor.refererType != 'directEntry'}from <a href="{$visitor.refererUrl}">{$visitor.refererName}</a> {if !empty($visitor.keywords)}"{$visitor.keywords}"{/if}{/if}</div>
+ <div class="settings">
+ <img src="{$visitor.browserIcon}" title="{$visitor.browser} with plugins {$visitor.plugins} enabled">
+ <img src="{$visitor.operatingSystemIcon}" title="{$visitor.operatingSystem}, {$visitor.resolution}">
+ </div>
+ <div class="returning">{if $visitor.isVisitorReturning}<img src="plugins/Live/templates/images/returningVisitor.gif" title="Returning Visitor">{/if}</div>
+ </div>
+{/foreach}
+</div>
diff --git a/plugins/Live/templates/scripts/spy.js b/plugins/Live/templates/scripts/spy.js
new file mode 100644
index 0000000000..ac296ab02f
--- /dev/null
+++ b/plugins/Live/templates/scripts/spy.js
@@ -0,0 +1,139 @@
+/*
+ jQuery Plugin spy (leftlogic.com/info/articles/jquery_spy2)
+ (c) 2006 Remy Sharp (leftlogic.com)
+ $Id$
+*/
+var spyRunning = 1;
+
+$.fn.spy = function(settings) {
+ var spy = this;
+ spy.epoch = new Date(1970, 0, 1);
+ spy.last = '';
+ spy.parsing = 0;
+ spy.waitTimer = 0;
+ spy.json = null;
+
+ if (!settings.ajax) {
+ alert("An AJAX/AJAH URL must be set for the spy to work.");
+ return;
+ }
+
+ spy.attachHolder = function() {
+ // not mad on this, but the only way to parse HTML collections
+ if (o.method == 'html')
+ $('body').append('<div style="display: none!important;" id="_spyTmp"></div>');
+ }
+
+ // returns true for 'no dupe', and false for 'dupe found'
+ // latest = is latest ajax return value (raw)
+ // last = is previous ajax return value (raw)
+ // note that comparing latest and last if they're JSON objects
+ // always returns false, so you need to implement it manually.
+ spy.isDupe = function(latest, last) {
+ if ((last.constructor == Object) && (o.method == 'html'))
+ return (latest.html() == last.html());
+ else if (last.constructor == String)
+ return (latest == last);
+ else
+ return 0;
+ }
+
+ spy.parse = function(e, r) {
+ spy.parsing = 1; // flag to stop pull via ajax
+ if (o.method == 'html') {
+ $('div#_spyTmp').html(r); // add contents to hidden div
+ } else if (o.method == 'json') {
+ eval('spy.json = ' + r); // convert text to json
+ }
+
+ if ((o.method == 'json' && spy.json.constructor == Array) || o.method == 'html') {
+ if (spy.parseItem(e)) {
+ spy.waitTimer = window.setInterval(function() {
+ if (spyRunning) {
+ if (!spy.parseItem(e)) {
+ spy.parsing = 0;
+ clearInterval(spy.waitTimer);
+ }
+ }
+ }, o.pushTimeout);
+ } else {
+ spy.parsing = 0;
+ }
+ } else if (o.method == 'json') { // we just have 1
+ eval('spy.json = ' + r)
+ spy.addItem(e, spy.json);
+ spy.parsing = 0;
+ }
+ }
+
+ // returns true if there's more to parse
+ spy.parseItem = function(e) {
+ if (o.method == 'html') {
+ // note: pre jq-1.0 doesn't return the object
+ var i = $('div#_spyTmp').find('div:first').remove();
+ if (i.size() > 0) {
+ i.hide();
+ spy.addItem(e, i);
+ }
+ return ($('div#_spyTmp').find('div').size() != 0);
+ } else {
+ if (spy.json.length) {
+ var i = spy.json.shift();
+ spy.addItem(e, i);
+ }
+
+ return (spy.json.length != 0);
+ }
+ }
+
+ spy.addItem = function(e, i) {
+ if (! o.isDupe.call(this, i, spy.last)) {
+ spy.last = i; // note i is a pointer - so when it gets modified, so does spy.last
+ $('#' + e.id + ' > div:gt(' + (o.limit - 1) + ')').remove();
+ o.push.call(e, i);
+ $('#' + e.id + ' > div:first').fadeIn(o.fadeInSpeed);
+ }
+ }
+
+ spy.push = function(r) {
+ $('#' + this.id).prepend(r);
+ }
+
+ var o = {
+ limit: (settings.limit || 10),
+ ajax: settings.ajax,
+ timeout: (settings.timeout || 3000),
+ pushTimeout: (settings.pushTimeout || settings.timeout || 3000),
+ method: (settings.method || 'html').toLowerCase(),
+ push: (settings.push || spy.push),
+ fadeInSpeed: (settings.fadeInSpeed || 'slow'), // 1400 = crawl
+ customParameterName: settings.customParameterName,
+ customParameterValueCallback: settings.customParameterValueCallback,
+ isDupe: (settings.isDupe || spy.isDupe),
+ };
+
+ spy.attachHolder();
+
+ return this.each(function() {
+ var e = this;
+ var lr = ''; // last ajax return
+ var parameters = new Object;
+ spy.ajaxTimer = window.setInterval(function() {
+ if (spyRunning && (!spy.parsing)) {
+ var customParameterValue = o.customParameterValueCallback.call();
+ parameters[o.customParameterName] = customParameterValue;
+ $.get(o.ajax, parameters, function(r) {
+ spy.parse(e, r);
+ });
+ }
+ }, o.timeout);
+ });
+};
+
+function pauseSpy() {
+ spyRunning = 0; return false;
+}
+
+function playSpy() {
+ spyRunning = 1; return false;
+}
diff --git a/plugins/Login/Controller.php b/plugins/Login/Controller.php
index fbee6a38e0..54557e9563 100644
--- a/plugins/Login/Controller.php
+++ b/plugins/Login/Controller.php
@@ -100,70 +100,97 @@ class Piwik_Login_Controller extends Piwik_Controller
if($form->validate())
{
$loginMail = $form->getSubmitValue('form_login');
- Piwik::setUserIsSuperUser();
-
- $user = null;
-
- if( Piwik_UsersManager_API::userExists($loginMail) )
- {
- $user = Piwik_UsersManager_API::getUser($loginMail);
- }
- else if( Piwik_UsersManager_API::userEmailExists($loginMail) )
- {
- $user = Piwik_UsersManager_API::getUserByEmail($loginMail);
- }
+ $this->lostPasswordFormValidated($loginMail, $urlToRedirect);
+ return;
+ }
+ $view = new Piwik_View('Login/templates/lostPassword.tpl');
+ $view->AccessErrorString = $messageNoAccess;
+ // make navigation login form -> reset password -> login form remember your first url
+ $view->urlToRedirect = $urlToRedirect;
+ $view->linkTitle = Piwik::getRandomTitle();
+ $view->addForm( $form );
+ $view->subTemplate = 'genericForm.tpl';
+ echo $view->render();
+ }
+
+ protected function lostPasswordFormValidated($loginMail, $urlToRedirect)
+ {
+ Piwik::setUserIsSuperUser();
+ $user = null;
+ $isSuperUser = false;
+
+ if( $loginMail == Zend_Registry::get('config')->superuser->email
+ || $loginMail == Zend_Registry::get('config')->superuser->login )
+ {
+ $isSuperUser = true;
+ $user = array(
+ 'login' => Zend_Registry::get('config')->superuser->login,
+ 'email' => Zend_Registry::get('config')->superuser->email);
+ }
+ else if( Piwik_UsersManager_API::userExists($loginMail) )
+ {
+ $user = Piwik_UsersManager_API::getUser($loginMail);
+ }
+ else if( Piwik_UsersManager_API::userEmailExists($loginMail) )
+ {
+ $user = Piwik_UsersManager_API::getUserByEmail($loginMail);
+ }
- if( $user === null )
+ if( $user === null )
+ {
+ $messageNoAccess = Piwik_Translate('Login_InvalidUsernameEmail');
+ }
+ else
+ {
+ $view = new Piwik_View('Login/templates/passwordsent.tpl');
+
+ $login = $user['login'];
+ $email = $user['email'];
+ $randomPassword = Piwik_Common::getRandomString(8);
+
+ if($isSuperUser)
{
- $messageNoAccess = Piwik_Translate('Login_InvalidUsernameEmail');
+ $user['password'] = md5($randomPassword);
+ Zend_Registry::get('config')->superuser = $user;
}
else
{
- $view = new Piwik_View('Login/templates/passwordsent.tpl');
-
- $login = $user['login'];
- $email = $user['email'];
- $randomPassword = Piwik_Common::getRandomString(8);
Piwik_UsersManager_API::updateUser($login, $randomPassword);
+ }
- // send email with new password
- try
- {
- $mail = new Piwik_Mail();
- $mail->addTo($email, $login);
- $mail->setSubject(Piwik_Translate('Login_MailTopicPasswordRecovery'));
- $mail->setBodyText(sprintf(Piwik_Translate('Login_MailPasswordRecoveryBody'),
- $login, $randomPassword, Piwik_Url::getCurrentUrlWithoutQueryString()));
+ // send email with new password
+ try
+ {
+ $mail = new Piwik_Mail();
+ $mail->addTo($email, $login);
+ $mail->setSubject(Piwik_Translate('Login_MailTopicPasswordRecovery'));
+ $mail->setBodyText(
+ str_replace(
+ '\n',
+ "\n",
+ sprintf(Piwik_Translate('Login_MailPasswordRecoveryBody'), $login, $randomPassword, Piwik_Url::getCurrentUrlWithoutQueryString())
+ )
+ );
- $host = $_SERVER['HTTP_HOST'];
- if(strlen($host) == 0)
- {
- $host = 'piwik.org';
- }
- $mail->setFrom('password-recovery@'.$host, 'Piwik');
- @$mail->send();
- }
- catch(Exception $e)
+ $host = $_SERVER['HTTP_HOST'];
+ if(strlen($host) == 0)
{
- $view->ErrorString = $e->getMessage();
+ $host = 'piwik.org';
}
-
- $view->linkTitle = Piwik::getRandomTitle();
- $view->urlToRedirect = $urlToRedirect;
- echo $view->render();
- return;
+ $mail->setFrom('password-recovery@'.$host, 'Piwik');
+ @$mail->send();
+ }
+ catch(Exception $e)
+ {
+ $view->ErrorString = $e->getMessage();
}
+
+ $view->linkTitle = Piwik::getRandomTitle();
+ $view->urlToRedirect = $urlToRedirect;
+ echo $view->render();
}
- $view = new Piwik_View('Login/templates/lostPassword.tpl');
- $view->AccessErrorString = $messageNoAccess;
- // make navigation login form -> reset password -> login form remember your first url
- $view->urlToRedirect = $urlToRedirect;
- $view->linkTitle = Piwik::getRandomTitle();
- $view->addForm( $form );
- $view->subTemplate = 'genericForm.tpl';
- echo $view->render();
}
-
+
static public function clearSession()
{
$authCookieName = 'piwik-auth';
diff --git a/plugins/Login/templates/login.tpl b/plugins/Login/templates/login.tpl
index 4b3ef37de9..0484425181 100644
--- a/plugins/Login/templates/login.tpl
+++ b/plugins/Login/templates/login.tpl
@@ -35,7 +35,7 @@
<p id="nav">
-<a href="?module=Login&amp;action=lostPassword&amp;form_url={$urlToRedirect}" title="{'Login_LostYourPassword'|translate}">{'Login_LostYourPassword'|translate}</a>
+<a href="?module=Login&amp;action=lostPassword&amp;form_url={$urlToRedirect|escape:url}" title="{'Login_LostYourPassword'|translate}">{'Login_LostYourPassword'|translate}</a>
</p>
</div>
diff --git a/plugins/Provider/API.php b/plugins/Provider/API.php
index 7f7c83f569..074ca64994 100644
--- a/plugins/Provider/API.php
+++ b/plugins/Provider/API.php
@@ -14,7 +14,7 @@ require_once "Provider/functions.php";
*
* @package Piwik_Provider
*/
-class Piwik_Provider_API extends Piwik_Apiable
+class Piwik_Provider_API
{
static private $instance = null;
@@ -38,18 +38,5 @@ class Piwik_Provider_API extends Piwik_Apiable
$dataTable->queueFilter('Piwik_DataTable_Filter_ReplaceColumnNames');
return $dataTable;
}
-
- /**
- * Example of getting a RAW BLOB
- *
- * @return blob
- */
- public function getProviderBlob( $idSite, $period, $date )
- {
- Piwik::checkUserHasViewAccess( $idSite );
- $archive = Piwik_Archive::build($idSite, $period, $date );
- $dataTable = $archive->getBlob('Provider_hostnameExt');
- return $dataTable;
- }
}
diff --git a/plugins/Provider/Controller.php b/plugins/Provider/Controller.php
index cc08f0b3e9..90d9674cc3 100644
--- a/plugins/Provider/Controller.php
+++ b/plugins/Provider/Controller.php
@@ -1,6 +1,4 @@
<?php
-require_once "ViewDataTable.php";
-
class Piwik_Provider_Controller extends Piwik_Controller
{
/**
@@ -9,12 +7,10 @@ class Piwik_Provider_Controller extends Piwik_Controller
function getProvider($fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( 'Provider', __FUNCTION__, "Provider.getProvider" );
-
+ $view->init( $this->pluginName, __FUNCTION__, "Provider.getProvider" );
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
$view->setLimit( 5 );
-
return $this->renderView($view, $fetch);
}
diff --git a/plugins/Provider/Provider.php b/plugins/Provider/Provider.php
index a819797c31..0de4d5b8f8 100644
--- a/plugins/Provider/Provider.php
+++ b/plugins/Provider/Provider.php
@@ -97,7 +97,8 @@ class Piwik_Provider extends Piwik_Plugin
$recordName = 'Provider_hostnameExt';
$labelSQL = "location_provider";
- $tableProvider = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByProvider = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableProvider = $archiveProcessing->getDataTableFromArray($interestByProvider);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableProvider->getSerialized());
}
diff --git a/plugins/Referers/API.php b/plugins/Referers/API.php
index 8a5b8b5bca..ab60cc8c83 100644
--- a/plugins/Referers/API.php
+++ b/plugins/Referers/API.php
@@ -15,7 +15,7 @@ require_once "Referers/functions.php";
*
* @package Piwik_Referers
*/
-class Piwik_Referers_API extends Piwik_Apiable
+class Piwik_Referers_API
{
static private $instance = null;
static public function getInstance()
@@ -56,10 +56,10 @@ class Piwik_Referers_API extends Piwik_Apiable
$dataTable->queueFilter('Piwik_DataTable_Filter_ColumnCallbackReplace', array('label', 'Piwik_getRefererTypeLabel'));
return $dataTable;
}
-
+
function getKeywords($idSite, $period, $date, $expanded = false)
{
- $dataTable = $this->getDataTable('Referers_searchEngineByKeyword',$idSite, $period, $date, $expanded);
+ $dataTable = $this->getDataTable('Referers_searchEngineByKeyword', $idSite, $period, $date, $expanded);
return $dataTable;
}
diff --git a/plugins/Referers/Controller.php b/plugins/Referers/Controller.php
index c76d596b19..c064e8b83e 100644
--- a/plugins/Referers/Controller.php
+++ b/plugins/Referers/Controller.php
@@ -1,10 +1,9 @@
<?php
-require_once "ViewDataTable.php";
class Piwik_Referers_Controller extends Piwik_Controller
{
function index()
{
- $view = new Piwik_View('Referers/index.tpl');
+ $view = new Piwik_View('Referers/templates/index.tpl');
$view->graphEvolutionReferers = $this->getLastDirectEntryGraph(true);
$view->nameGraphEvolutionReferers = 'ReferersgetLastDirectEntryGraph'; // must be the function name used above
@@ -40,25 +39,24 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getSearchEnginesAndKeywords()
{
- $view = new Piwik_View('Referers/searchEngines_Keywords.tpl');
+ $view = new Piwik_View('Referers/templates/searchEngines_Keywords.tpl');
$view->searchEngines = $this->getSearchEngines(true) ;
$view->keywords = $this->getKeywords(true);
echo $view->render();
}
- /**
- * Referers
- */
+
function getRefererType( $fetch = false)
{
$view = Piwik_ViewDataTable::factory('cloud');
$view->init( $this->pluginName,
- 'getRefererType',
+ __FUNCTION__,
'Referers.getRefererType'
);
$view->disableSearchBox();
$view->disableOffsetInformation();
$view->disableExcludeLowPopulation();
$view->doNotShowFooter();
+ $view->enableShowGoals();
$view->setColumnsToDisplay( array('label','nb_uniq_visitors', 'nb_visits') );
@@ -68,21 +66,21 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getKeywords( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
-
- $view->init( $this->pluginName, 'getKeywords',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywords',
'getSearchEnginesFromKeywordId'
);
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_visits') );
-
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
return $this->renderView($view, $fetch);
}
function getSearchEnginesFromKeywordId( $fetch = false )
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getSearchEnginesFromKeywordId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getSearchEnginesFromKeywordId'
);
$view->disableSearchBox();
@@ -96,34 +94,36 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getSearchEngines( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getSearchEngines',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getSearchEngines',
'getKeywordsFromSearchEngineId'
);
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
$view->setColumnsToDisplay( array('label','nb_visits') );
return $this->renderView($view, $fetch);
}
- public function getSearchEnginesEvolution($fetch = false)
- {
- $view = Piwik_ViewDataTable::factory('graphEvolution');
- $view->init( 'Referers', __FUNCTION__, 'Referers.getSearchEngines' );
-
- $view->setColumnsToDisplay( 'nb_uniq_visitors' );
- $view->setExactPattern( array('Google','Yahoo!'), 'label');
- //$view->setExactPattern( array('Google'), 'label');
-
- return $this->renderView($view, $fetch);
- }
+ public function getSearchEnginesEvolution($fetch = false)
+ {
+ $view = Piwik_ViewDataTable::factory('graphEvolution');
+ $view->init( $this->pluginName, __FUNCTION__, 'Referers.getSearchEngines' );
+
+ $view->setColumnsToDisplay( 'nb_uniq_visitors' );
+ $view->setExactPattern( array('Google','Yahoo!'), 'label');
+ //$view->setExactPattern( array('Google'), 'label');
+
+ return $this->renderView($view, $fetch);
+ }
function getKeywordsFromSearchEngineId( $fetch = false )
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getKeywordsFromSearchEngineId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywordsFromSearchEngineId'
);
$view->disableSearchBox();
@@ -136,20 +136,23 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getWebsites( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getWebsites',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getWebsites',
'getUrlsFromWebsiteId'
);
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_visits') );
$view->setLimit(10);
+ $view->enableShowGoals();
+ $view->disableSubTableWhenShowGoals();
+
return $this->renderView($view, $fetch);
}
function getCampaigns( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getCampaigns',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getCampaigns',
'getKeywordsFromCampaignId'
);
@@ -157,16 +160,15 @@ class Piwik_Referers_Controller extends Piwik_Controller
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
$view->setLimit( 5 );
-
+ $view->enableShowGoals();
$view->setColumnsToDisplay( array('label','nb_visits') );
-
return $this->renderView($view, $fetch);
}
function getKeywordsFromCampaignId( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getKeywordsFromCampaignId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getKeywordsFromCampaignId'
);
@@ -180,7 +182,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
function getUrlsFromWebsiteId( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( $this->pluginName, 'getUrlsFromWebsiteId',
+ $view->init( $this->pluginName, __FUNCTION__,
'Referers.getUrlsFromWebsiteId'
);
$view->disableSearchBox();
@@ -189,7 +191,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
return $this->renderView($view, $fetch);
}
- function getReferersType()
+ protected function getReferersVisitorsByType()
{
// we disable the queued filters because here we want to get the visits coming from search engines
// if the filters were applied we would have to look up for a label looking like "Search Engines"
@@ -198,13 +200,7 @@ class Piwik_Referers_Controller extends Piwik_Controller
&format=original
&disable_queued_filters=1";
$request = new Piwik_API_Request($requestString);
- return $request->process();
- }
-
- protected function getReferersVisitorsByType()
- {
- // this is raw data (no filters applied, on purpose) so we select the data using the magic integers ID
- $dataTableReferersType = $this->getReferersType(true);
+ $dataTableReferersType = $request->process();
$nameToColumnId = array(
'visitorsFromSearchEngines' => Piwik_Common::REFERER_TYPE_SEARCH_ENGINE,
diff --git a/plugins/Referers/Referers.php b/plugins/Referers/Referers.php
index fe23422512..339a75f73f 100644
--- a/plugins/Referers/Referers.php
+++ b/plugins/Referers/Referers.php
@@ -122,10 +122,22 @@ class Piwik_Referers extends Piwik_Plugin
);
}
}
-
+
+
public function archiveDay( $notification )
{
+ /**
+ * @var Piwik_ArchiveProcessing_Day
+ */
$archiveProcessing = $notification->getNotificationObject();
+
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$query = "SELECT referer_type,
referer_name,
referer_keyword,
@@ -135,7 +147,8 @@ class Piwik_Referers extends Piwik_Plugin
sum(visit_total_actions) as nb_actions,
max(visit_total_actions) as max_actions,
sum(visit_total_time) as sum_visit_length,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted
FROM ".$archiveProcessing->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -143,111 +156,164 @@ class Piwik_Referers extends Piwik_Plugin
ORDER BY nb_visits DESC";
$query = $archiveProcessing->db->query($query, array( $archiveProcessing->strDateStart, $archiveProcessing->idsite ));
- $interestBySearchEngine =
- $interestByKeyword =
- $keywordBySearchEngine =
- $searchEngineByKeyword =
- $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] =
- $urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE] =
- $keywordByCampaign =
- $interestByCampaign =
- $interestByType =
- $distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE] = array();
+ $this->interestBySearchEngine =
+ $this->interestByKeyword =
+ $this->interestBySearchEngineAndKeyword =
+ $this->interestByKeywordAndSearchEngine =
+ $this->interestByWebsite =
+ $this->interestByWebsiteAndUrl =
+ $this->interestByCampaignAndKeyword =
+ $this->interestByCampaign =
+ $this->interestByType =
+ $this->distinctUrls = array();
- while($rowBefore = $query->fetch() )
+ while($row = $query->fetch() )
{
- $row = array(
- Piwik_Archive::INDEX_NB_UNIQ_VISITORS => $rowBefore['nb_uniq_visitors'],
- Piwik_Archive::INDEX_NB_VISITS => $rowBefore['nb_visits'],
- Piwik_Archive::INDEX_NB_ACTIONS => $rowBefore['nb_actions'],
- Piwik_Archive::INDEX_MAX_ACTIONS => $rowBefore['max_actions'],
- Piwik_Archive::INDEX_SUM_VISIT_LENGTH => $rowBefore['sum_visit_length'],
- Piwik_Archive::INDEX_BOUNCE_COUNT => $rowBefore['bounce_count'],
- 'referer_type' => $rowBefore['referer_type'],
- 'referer_name' => $rowBefore['referer_name'],
- 'referer_keyword' => $rowBefore['referer_keyword'],
- 'referer_url' => $rowBefore['referer_url'],
- );
-
- switch($row['referer_type'])
+ if(empty($row['referer_type']))
{
- case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
-
- if(!isset($interestBySearchEngine[$row['referer_name']])) $interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- if(!isset($interestByKeyword[$row['referer_keyword']])) $interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- if(!isset($keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']])) $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- if(!isset($searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']])) $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
-
- $archiveProcessing->updateInterestStats( $row, $interestBySearchEngine[$row['referer_name']]);
- $archiveProcessing->updateInterestStats( $row, $interestByKeyword[$row['referer_keyword']]);
- $archiveProcessing->updateInterestStats( $row, $keywordBySearchEngine[$row['referer_name']][$row['referer_keyword']]);
- $archiveProcessing->updateInterestStats( $row, $searchEngineByKeyword[$row['referer_keyword']][$row['referer_name']]);
- break;
-
- case Piwik_Common::REFERER_TYPE_WEBSITE:
+ $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
+ }
+ else
+ {
+ switch($row['referer_type'])
+ {
+ case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
- if(!isset($interestByWebsite[$row['referer_type']][$row['referer_name']])) $interestByWebsite[$row['referer_type']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $interestByWebsite[$row['referer_type']][$row['referer_name']]);
+ if(!isset($this->interestBySearchEngine[$row['referer_name']])) $this->interestBySearchEngine[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestByKeyword[$row['referer_keyword']])) $this->interestByKeyword[$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ if(!isset($this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']])) $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- if(!isset($urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']])) $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $urlByWebsite[$row['referer_type']][$row['referer_name']][$row['referer_url']]);
-
- if(!isset($distinctUrls[$row['referer_type']][$row['referer_url']]))
- {
- $distinctUrls[$row['referer_type']][$row['referer_url']] = true;
- }
+ $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngine[$row['referer_name']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestByKeyword[$row['referer_keyword']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestBySearchEngineAndKeyword[$row['referer_name']][$row['referer_keyword']]);
+ $archiveProcessing->updateInterestStats( $row, $this->interestByKeywordAndSearchEngine[$row['referer_keyword']][$row['referer_name']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_WEBSITE:
+
+ if(!isset($this->interestByWebsite[$row['referer_name']])) $this->interestByWebsite[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByWebsite[$row['referer_name']]);
+
+ if(!isset($this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']])) $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByWebsiteAndUrl[$row['referer_name']][$row['referer_url']]);
- break;
+ if(!isset($this->distinctUrls[$row['referer_url']]))
+ {
+ $this->distinctUrls[$row['referer_url']] = true;
+ }
+
+ break;
+
+ case Piwik_Common::REFERER_TYPE_CAMPAIGN:
+ if(!empty($row['referer_keyword']))
+ {
+ if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']]);
+ }
+ if(!isset($this->interestByCampaign[$row['referer_name']])) $this->interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats( $row, $this->interestByCampaign[$row['referer_name']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_DIRECT_ENTRY:
+ // direct entry are aggregated below in $this->interestByType array
+ break;
+
+ default:
+ throw new Exception("Non expected referer_type = " . $row['referer_type']);
+ break;
+ }
+ }
+ if(!isset($this->interestByType[$row['referer_type']] )) $this->interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow();
+ $archiveProcessing->updateInterestStats($row, $this->interestByType[$row['referer_type']]);
+ }
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySegment("referer_type,referer_name,referer_keyword");
+ while($row = $query->fetch() )
+ {
+ if(empty($row['referer_type']))
+ {
+ $row['referer_type'] = Piwik_Common::REFERER_TYPE_DIRECT_ENTRY;
+ }
+ else
+ {
+ switch($row['referer_type'])
+ {
+ case Piwik_Common::REFERER_TYPE_SEARCH_ENGINE:
+ if(!isset($this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ if(!isset($this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+
+ $archiveProcessing->updateGoalStats( $row, $this->interestBySearchEngine[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ $archiveProcessing->updateGoalStats( $row, $this->interestByKeyword[$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_WEBSITE:
+ if(!isset($this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByWebsite[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
+
+ case Piwik_Common::REFERER_TYPE_CAMPAIGN:
+ if(!empty($row['referer_keyword']))
+ {
+ if(!isset($this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByCampaignAndKeyword[$row['referer_name']][$row['referer_keyword']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ }
+ if(!isset($this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats( $row, $this->interestByCampaign[$row['referer_name']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ break;
- case Piwik_Common::REFERER_TYPE_CAMPAIGN:
- if(!empty($row['referer_keyword']))
- {
- if(!isset($keywordByCampaign[$row['referer_name']][$row['referer_keyword']])) $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $keywordByCampaign[$row['referer_name']][$row['referer_keyword']]);
- }
- if(!isset($interestByCampaign[$row['referer_name']])) $interestByCampaign[$row['referer_name']]= $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats( $row, $interestByCampaign[$row['referer_name']]);
- break;
+ default:
+ throw new Exception("Non expected referer_type = " . $row['referer_type']);
+ break;
+ }
}
- if(!isset($interestByType[$row['referer_type']] )) $interestByType[$row['referer_type']] = $archiveProcessing->getNewInterestRow();
- $archiveProcessing->updateInterestStats($row, $interestByType[$row['referer_type']]);
+ if(!isset($this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] )) $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats($row, $this->interestByType[$row['referer_type']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
}
-
- $numberOfDistinctSearchEngines = count($keywordBySearchEngine);
- $numberOfDistinctKeywords = count($searchEngineByKeyword);
-
- $numberOfDistinctCampaigns = count($interestByCampaign);
- $numberOfDistinctWebsites = count($interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE]);
- $numberOfDistinctWebsitesUrls = count($distinctUrls[Piwik_Common::REFERER_TYPE_WEBSITE]);
-
+
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByType);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestBySearchEngine);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByKeyword);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByWebsite);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByCampaign);
+ $archiveProcessing->enrichConversionsByLabelArrayHasTwoLevels($this->interestByCampaignAndKeyword);
+ }
+
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
$numericRecords = array(
- 'Referers_distinctSearchEngines' => $numberOfDistinctSearchEngines,
- 'Referers_distinctKeywords' => $numberOfDistinctKeywords,
- 'Referers_distinctCampaigns' => $numberOfDistinctCampaigns,
- 'Referers_distinctWebsites' => $numberOfDistinctWebsites,
- 'Referers_distinctWebsitesUrls' => $numberOfDistinctWebsitesUrls,
+ 'Referers_distinctSearchEngines' => count($this->interestBySearchEngineAndKeyword),
+ 'Referers_distinctKeywords' => count($this->interestByKeywordAndSearchEngine),
+ 'Referers_distinctCampaigns' => count($this->interestByCampaign),
+ 'Referers_distinctWebsites' => count($this->interestByWebsite),
+ 'Referers_distinctWebsitesUrls' => count($this->distinctUrls),
);
+
foreach($numericRecords as $name => $value)
{
$record = new Piwik_ArchiveProcessing_Record_Numeric($name, $value);
}
- $data = $archiveProcessing->getDataTableSerialized($interestByType);
+ $data = $archiveProcessing->getDataTableSerialized($this->interestByType);
$record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_type', $data);
$maximumRowsInDataTableLevelZero = 500;
$maximumRowsInSubDataTable = 50;
- $data = $archiveProcessing->getDataTablesSerialized($keywordBySearchEngine, $interestBySearchEngine, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordBySearchEngine', $data);
-
- $data = $archiveProcessing->getDataTablesSerialized($searchEngineByKeyword, $interestByKeyword, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_searchEngineByKeyword', $data);
-
- $data = $archiveProcessing->getDataTablesSerialized($keywordByCampaign, $interestByCampaign, $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_keywordByCampaign', $data);
+ $blobRecords = array(
+ 'Referers_keywordBySearchEngine' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestBySearchEngineAndKeyword, $this->interestBySearchEngine),
+ 'Referers_searchEngineByKeyword' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByKeywordAndSearchEngine, $this->interestByKeyword),
+ 'Referers_keywordByCampaign' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByCampaignAndKeyword, $this->interestByCampaign),
+ 'Referers_urlByWebsite' => $archiveProcessing->getDataTableWithSubtablesFromArraysIndexedByLabel($this->interestByWebsiteAndUrl, $this->interestByWebsite),
+ );
- $data = $archiveProcessing->getDataTablesSerialized($urlByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $interestByWebsite[Piwik_Common::REFERER_TYPE_WEBSITE], $maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray('Referers_urlByWebsite', $data);
+ foreach($blobRecords as $recordName => $table )
+ {
+ $dataToRecord = $table->getSerialized($maximumRowsInDataTableLevelZero, $maximumRowsInSubDataTable);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $dataToRecord);
+ }
}
}
diff --git a/plugins/Referers/functions.php b/plugins/Referers/functions.php
index 9df808e0b1..735e7865e1 100644
--- a/plugins/Referers/functions.php
+++ b/plugins/Referers/functions.php
@@ -63,4 +63,5 @@ function Piwik_getRefererTypeLabel($label)
break;
}
return Piwik_Translate($indexTranslation);
-} \ No newline at end of file
+}
+
diff --git a/plugins/Referers/index.tpl b/plugins/Referers/templates/index.tpl
index df1995c81e..df1995c81e 100644
--- a/plugins/Referers/index.tpl
+++ b/plugins/Referers/templates/index.tpl
diff --git a/plugins/Referers/searchEngines_Keywords.tpl b/plugins/Referers/templates/searchEngines_Keywords.tpl
index a664aefb50..a664aefb50 100644
--- a/plugins/Referers/searchEngines_Keywords.tpl
+++ b/plugins/Referers/templates/searchEngines_Keywords.tpl
diff --git a/plugins/SitesManager/API.php b/plugins/SitesManager/API.php
index cfd4e8b0c7..6ff1ff9a8b 100755
--- a/plugins/SitesManager/API.php
+++ b/plugins/SitesManager/API.php
@@ -13,7 +13,7 @@
*
* @package Piwik_SitesManager
*/
-class Piwik_SitesManager_API extends Piwik_Apiable
+class Piwik_SitesManager_API
{
static private $instance = null;
static public function getInstance()
@@ -26,8 +26,6 @@ class Piwik_SitesManager_API extends Piwik_Apiable
return self::$instance;
}
- static public $methodsNotToPublish = array();
-
/**
* Returns the javascript tag for the given idSite.
* This tag must be included on every page to be tracked by Piwik
diff --git a/plugins/SitesManager/templates/SitesManager.js b/plugins/SitesManager/templates/SitesManager.js
index df6b3ed9f1..8ebfedd3b3 100644
--- a/plugins/SitesManager/templates/SitesManager.js
+++ b/plugins/SitesManager/templates/SitesManager.js
@@ -1,15 +1,3 @@
-
-function getEncoded(siteName)
-{
- // compatible with old browsers but wouldnt work for UTF8 strings
- if (encodeURIComponent) {
- siteName = encodeURIComponent(siteName);
- } else {
- siteName = escape(siteName);
- }
- return siteName;
-}
-
function getDeleteSiteAJAX( idSite )
{
var ajaxRequest = getStandardAjaxConf();
@@ -41,7 +29,7 @@ function getAddSiteAJAX( row )
request += '&module=API';
request += '&format=json';
request += '&method=SitesManager.addSite';
- siteName = getEncoded(siteName);
+ siteName = encodeURIComponent(siteName);
request += '&siteName='+siteName;
$.each(urls, function (key,value){ request+= '&urls[]='+escape(value);} );
request += '&token_auth=' + piwik.token_auth;
@@ -64,7 +52,7 @@ function getUpdateSiteAJAX( row )
request += '&module=API';
request += '&format=json';
request += '&method=SitesManager.updateSite';
- siteName = getEncoded(siteName);
+ siteName = encodeURIComponent(siteName);
request += '&siteName='+siteName;
request += '&idSite='+idSite;
$.each(urls, function (key,value){ if(value.length>1) request+= '&urls[]='+value;} );
diff --git a/plugins/UserCountry/API.php b/plugins/UserCountry/API.php
index 404dc0cbc4..6c6f00c857 100644
--- a/plugins/UserCountry/API.php
+++ b/plugins/UserCountry/API.php
@@ -15,7 +15,7 @@ require_once "UserCountry/functions.php";
*
* @package Piwik_UserCountry
*/
-class Piwik_UserCountry_API extends Piwik_Apiable
+class Piwik_UserCountry_API
{
static private $instance = null;
static public function getInstance()
diff --git a/plugins/UserCountry/Controller.php b/plugins/UserCountry/Controller.php
index 29e7f56b07..a2395620f8 100644
--- a/plugins/UserCountry/Controller.php
+++ b/plugins/UserCountry/Controller.php
@@ -19,39 +19,41 @@ class Piwik_UserCountry_Controller extends Piwik_Controller
function getCountry( $fetch = false)
{
$view = Piwik_ViewDataTable::factory();
- $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getCountry" );
+ $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getCountry" );
$view->disableExcludeLowPopulation();
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
$view->disableSearchBox();
$view->setLimit( 5 );
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
- function getNumberOfDistinctCountries( $fetch = false)
- {
- return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries');
- }
-
- function getLastDistinctCountriesGraph( $fetch = false )
- {
- $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries");
- return $this->renderView($view, $fetch);
- }
-
function getContinent( $fetch = false)
{
$view = Piwik_ViewDataTable::factory( 'graphVerticalBar' );
- $view->init( 'UserCountry', __FUNCTION__, "UserCountry.getContinent" );
+ $view->init( $this->pluginName, __FUNCTION__, "UserCountry.getContinent" );
$view->disableExcludeLowPopulation();
$view->disableSearchBox();
$view->disableOffsetInformation();
$view->disableSort();
$view->setColumnsToDisplay( array('label','nb_uniq_visitors') );
$view->setSortedColumn( 1 );
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
+
+ function getNumberOfDistinctCountries( $fetch = false)
+ {
+ return $this->getNumericValue('UserCountry.getNumberOfDistinctCountries');
+ }
+
+ function getLastDistinctCountriesGraph( $fetch = false )
+ {
+ $view = $this->getLastUnitGraph('UserCountry',__FUNCTION__, "UserCountry.getNumberOfDistinctCountries");
+ return $this->renderView($view, $fetch);
+ }
}
diff --git a/plugins/UserCountry/UserCountry.php b/plugins/UserCountry/UserCountry.php
index bd69f64067..93a052ca1e 100644
--- a/plugins/UserCountry/UserCountry.php
+++ b/plugins/UserCountry/UserCountry.php
@@ -68,17 +68,42 @@ class Piwik_UserCountry extends Piwik_Plugin
function archiveDay($notification)
{
$archiveProcessing = $notification->getNotificationObject();
-
- $recordName = 'UserCountry_country';
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$labelSQL = "location_country";
- $tableCountry = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount());
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableCountry->getSerialized());
-
- $recordName = 'UserCountry_continent';
+ $this->interestByCountry = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+
$labelSQL = "location_continent";
- $tableContinent = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableContinent->getSerialized());
+ $this->interestByContinent = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySegment("location_continent,location_country");
+ while($row = $query->fetch() )
+ {
+ if(!isset($this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ if(!isset($this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']])) $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getNewGoalRow();
+ $archiveProcessing->updateGoalStats($row, $this->interestByCountry[$row['location_country']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ $archiveProcessing->updateGoalStats($row, $this->interestByContinent[$row['location_continent']][Piwik_Archive::INDEX_GOALS][$row['idgoal']]);
+ }
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByCountry);
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByContinent);
+ }
+
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
+ $tableCountry = $archiveProcessing->getDataTableFromArray($this->interestByCountry);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_country', $tableCountry->getSerialized());
+ $record = new Piwik_ArchiveProcessing_Record_Numeric('UserCountry_distinctCountries', $tableCountry->getRowsCount());
+
+ $tableContinent = $archiveProcessing->getDataTableFromArray($this->interestByContinent);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('UserCountry_continent', $tableContinent->getSerialized());
}
}
diff --git a/plugins/UserSettings/API.php b/plugins/UserSettings/API.php
index c31f941ced..d283c83870 100644
--- a/plugins/UserSettings/API.php
+++ b/plugins/UserSettings/API.php
@@ -16,7 +16,7 @@ require_once "UserSettings/functions.php";
/**
* @package Piwik_UserSettings
*/
-class Piwik_UserSettings_API extends Piwik_Apiable
+class Piwik_UserSettings_API
{
static private $instance = null;
static public function getInstance()
diff --git a/plugins/UserSettings/UserSettings.php b/plugins/UserSettings/UserSettings.php
index 6b0895145f..b56ed2d8b2 100644
--- a/plugins/UserSettings/UserSettings.php
+++ b/plugins/UserSettings/UserSettings.php
@@ -30,8 +30,8 @@ class Piwik_UserSettings extends Piwik_Plugin
// source: http://en.wikipedia.org/wiki/List_of_web_browsers
static public $browserType = array(
"ie" => array("IE"),
- "gecko" => array("NS", "PX", "FF", "FB", "CA", "CH", "GA", "KM", "MO", "SM"),
- "khtml" => array("SF", "KO", "OW"),
+ "gecko" => array("NS", "PX", "FF", "FB", "CA", "GA", "KM", "MO", "SM"),
+ "khtml" => array("SF", "KO", "OW", "CH"),
"opera" => array("OP")
);
@@ -78,17 +78,20 @@ class Piwik_UserSettings extends Piwik_Plugin
$recordName = 'UserSettings_configuration';
$labelSQL = "CONCAT(config_os, ';', config_browser_name, ';', config_resolution)";
- $tableConfiguration = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByConfiguration = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableConfiguration = $archiveProcessing->getDataTableFromArray($interestByConfiguration);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableConfiguration->getSerialized());
$recordName = 'UserSettings_os';
$labelSQL = "config_os";
- $tableOs = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByOs = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableOs = $archiveProcessing->getDataTableFromArray($interestByOs);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableOs->getSerialized());
$recordName = 'UserSettings_browser';
$labelSQL = "CONCAT(config_browser_name, ';', config_browser_version)";
- $tableBrowser = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByBrowser = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableBrowser = $archiveProcessing->getDataTableFromArray($interestByBrowser);
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableBrowser->getSerialized());
$recordName = 'UserSettings_browserType';
@@ -97,7 +100,8 @@ class Piwik_UserSettings extends Piwik_Plugin
$recordName = 'UserSettings_resolution';
$labelSQL = "config_resolution";
- $tableResolution = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
+ $interestByResolution = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ $tableResolution = $archiveProcessing->getDataTableFromArray($interestByResolution);
$filter = new Piwik_DataTable_Filter_ColumnCallbackDeleteRow($tableResolution, 'label', 'Piwik_UserSettings_keepStrlenGreater');
$record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableResolution->getSerialized());
diff --git a/plugins/UsersManager/API.php b/plugins/UsersManager/API.php
index 46024d1295..235562c11c 100755
--- a/plugins/UsersManager/API.php
+++ b/plugins/UsersManager/API.php
@@ -13,7 +13,7 @@
*
* @package Piwik_UsersManager
*/
-class Piwik_UsersManager_API extends Piwik_Apiable
+class Piwik_UsersManager_API
{
static private $instance = null;
static public function getInstance()
@@ -26,8 +26,6 @@ class Piwik_UsersManager_API extends Piwik_Apiable
return self::$instance;
}
- static public $methodsNotToPublish = array();
-
/**
* Returns the list of all the users
*
diff --git a/plugins/UsersManager/templates/UsersManager.js b/plugins/UsersManager/templates/UsersManager.js
index a4e772ab97..966ea73ea5 100644
--- a/plugins/UsersManager/templates/UsersManager.js
+++ b/plugins/UsersManager/templates/UsersManager.js
@@ -185,7 +185,7 @@ $(document).ready( function() {
.toggle()
.parent()
.prepend( $('<img src="plugins/UsersManager/images/ok.png" class="updateuser">')
- .click( function(){ $.ajax( getUpdateUserAJAX( $('tr#'+idRow) ) ); } )
+ .click( function(){ $.ajax( getUpdateUserAJAX( $('tr#'+idRow) ) ); } )
);
});
diff --git a/plugins/VisitFrequency/API.php b/plugins/VisitFrequency/API.php
index c1e92bcc01..70e6010a02 100644
--- a/plugins/VisitFrequency/API.php
+++ b/plugins/VisitFrequency/API.php
@@ -13,7 +13,7 @@
*
* @package Piwik_VisitFrequency
*/
-class Piwik_VisitFrequency_API extends Piwik_Apiable
+class Piwik_VisitFrequency_API
{
static private $instance = null;
static public function getInstance()
@@ -36,6 +36,7 @@ class Piwik_VisitFrequency_API extends Piwik_Apiable
'max_actions_returning',
'sum_visit_length_returning',
'bounce_count_returning',
+ 'nb_visits_converted_returning',
);
$dataTable = $archive->getDataTableFromNumeric($toFetch);
return $dataTable;
@@ -73,4 +74,9 @@ class Piwik_VisitFrequency_API extends Piwik_Apiable
{
return $this->getNumeric( $idSite, $period, $date, 'bounce_count_returning');
}
+
+ public function getConvertedVisitsReturning( $idSite, $period, $date )
+ {
+ return $this->getNumeric( $idSite, $period, $date, 'nb_visits_converted_returning');
+ }
}
diff --git a/plugins/VisitFrequency/Controller.php b/plugins/VisitFrequency/Controller.php
index c3ce1a01bb..366ed17ab4 100644
--- a/plugins/VisitFrequency/Controller.php
+++ b/plugins/VisitFrequency/Controller.php
@@ -37,8 +37,7 @@ class Piwik_VisitFrequency_Controller extends Piwik_Controller
protected function getSummary()
{
- $requestString = "method=VisitFrequency.getSummary
- &format=original";
+ $requestString = "method=VisitFrequency.getSummary&format=original";
$request = new Piwik_API_Request($requestString);
return $request->process();
}
diff --git a/plugins/VisitFrequency/VisitFrequency.php b/plugins/VisitFrequency/VisitFrequency.php
index 94aa1329d9..68bb7fb02a 100644
--- a/plugins/VisitFrequency/VisitFrequency.php
+++ b/plugins/VisitFrequency/VisitFrequency.php
@@ -58,6 +58,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin
'nb_actions_returning',
'sum_visit_length_returning',
'bounce_count_returning',
+ 'nb_visits_converted_returning',
);
$archiveProcessing->archiveNumericValuesSum($numericToSum);
$archiveProcessing->archiveNumericValuesMax('max_actions_returning');
@@ -72,7 +73,8 @@ class Piwik_VisitFrequency extends Piwik_Plugin
sum(visit_total_actions) as nb_actions_returning,
max(visit_total_actions) as max_actions_returning,
sum(visit_total_time) as sum_visit_length_returning,
- sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning
+ sum(case visit_total_actions when 1 then 1 else 0 end) as bounce_count_returning,
+ sum(case visit_goal_converted when 1 then 1 else 0 end) as nb_visits_converted_returning
FROM ".$archiveProcessing->logTable."
WHERE visit_server_date = ?
AND idsite = ?
@@ -87,6 +89,7 @@ class Piwik_VisitFrequency extends Piwik_Plugin
$row['max_actions_returning'] = 0;
$row['sum_visit_length_returning'] = 0;
$row['bounce_count_returning'] = 0;
+ $row['nb_visits_converted_returning'] = 0;
}
foreach($row as $name => $value)
diff --git a/plugins/VisitTime/API.php b/plugins/VisitTime/API.php
index 86fe3d6224..47dc678216 100644
--- a/plugins/VisitTime/API.php
+++ b/plugins/VisitTime/API.php
@@ -14,7 +14,7 @@
*
* @package Piwik_VisitTime
*/
-class Piwik_VisitTime_API extends Piwik_Apiable
+class Piwik_VisitTime_API
{
static private $instance = null;
static public function getInstance()
diff --git a/plugins/VisitTime/Controller.php b/plugins/VisitTime/Controller.php
index d08458a706..923c406a1e 100644
--- a/plugins/VisitTime/Controller.php
+++ b/plugins/VisitTime/Controller.php
@@ -23,6 +23,7 @@ class Piwik_VisitTime_Controller extends Piwik_Controller
$view->disableSearchBox();
$view->disableExcludeLowPopulation();
$view->disableOffsetInformation();
+ $view->enableShowGoals();
return $this->renderView($view, $fetch);
}
diff --git a/plugins/VisitTime/VisitTime.php b/plugins/VisitTime/VisitTime.php
index 0160b838c4..9ee7f006d9 100644
--- a/plugins/VisitTime/VisitTime.php
+++ b/plugins/VisitTime/VisitTime.php
@@ -52,41 +52,58 @@ class Piwik_VisitTime extends Piwik_Plugin
function archivePeriod( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
-
$dataTableToSum = array(
'VisitTime_localTime',
'VisitTime_serverTime',
);
-
$archiveProcessing->archiveDataTable($dataTableToSum);
}
public function archiveDay( $notification )
{
$archiveProcessing = $notification->getNotificationObject();
-
- $this->archiveProcessing = $archiveProcessing;
-
- $recordName = 'VisitTime_localTime';
+ $this->archiveDayAggregateVisits($archiveProcessing);
+ $this->archiveDayAggregateGoals($archiveProcessing);
+ $this->archiveDayRecordInDatabase($archiveProcessing);
+ }
+
+ protected function archiveDayAggregateVisits($archiveProcessing)
+ {
$labelSQL = "HOUR(visitor_localtime)";
- $tableLocalTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $this->makeSureAllHoursAreSet($tableLocalTime);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableLocalTime->getSerialized());
+ $this->interestByLocalTime = $archiveProcessing->getArrayInterestForLabel($labelSQL);
- $recordName = 'VisitTime_serverTime';
$labelSQL = "HOUR(visit_first_action_time)";
- $tableServerTime = $archiveProcessing->getDataTableInterestForLabel($labelSQL);
- $this->makeSureAllHoursAreSet($tableServerTime);
- $record = new Piwik_ArchiveProcessing_Record_BlobArray($recordName, $tableServerTime->getSerialized());
+ $this->interestByServerTime = $archiveProcessing->getArrayInterestForLabel($labelSQL);
+ }
+
+ protected function archiveDayAggregateGoals($archiveProcessing)
+ {
+ $query = $archiveProcessing->queryConversionsBySingleSegment("HOUR(server_time)");
+ while($row = $query->fetch())
+ {
+ $this->interestByServerTime[$row['label']][Piwik_Archive::INDEX_GOALS][$row['idgoal']] = $archiveProcessing->getGoalRowFromQueryRow($row);
+ }
+ $archiveProcessing->enrichConversionsByLabelArray($this->interestByServerTime);
}
- private function makeSureAllHoursAreSet($table)
+ protected function archiveDayRecordInDatabase($archiveProcessing)
+ {
+ $tableLocalTime = $archiveProcessing->getDataTableFromArray($this->interestByLocalTime);
+ $this->makeSureAllHoursAreSet($tableLocalTime, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_localTime', $tableLocalTime->getSerialized());
+
+ $tableServerTime = $archiveProcessing->getDataTableFromArray($this->interestByServerTime);
+ $this->makeSureAllHoursAreSet($tableServerTime, $archiveProcessing);
+ $record = new Piwik_ArchiveProcessing_Record_BlobArray('VisitTime_serverTime', $tableServerTime->getSerialized());
+ }
+
+ private function makeSureAllHoursAreSet($table, $archiveProcessing)
{
for($i=0;$i<=23;$i++)
{
if($table->getRowFromLabel($i) === false)
{
- $row = $this->archiveProcessing->getNewInterestRowLabeled($i);
+ $row = $archiveProcessing->getNewInterestRowLabeled($i);
$table->addRow( $row );
}
}
diff --git a/plugins/VisitorInterest/API.php b/plugins/VisitorInterest/API.php
index fc2af110ff..2903c3eabf 100644
--- a/plugins/VisitorInterest/API.php
+++ b/plugins/VisitorInterest/API.php
@@ -14,7 +14,7 @@
*
* @package Piwik_VisitorInterest
*/
-class Piwik_VisitorInterest_API extends Piwik_Apiable
+class Piwik_VisitorInterest_API
{
static private $instance = null;
static public function getInstance()
diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php
index 72df24bfbf..ed9a75df7c 100644
--- a/plugins/VisitsSummary/API.php
+++ b/plugins/VisitsSummary/API.php
@@ -12,7 +12,7 @@
/**
* @package Piwik_VisitsSummary
*/
-class Piwik_VisitsSummary_API extends Piwik_Apiable
+class Piwik_VisitsSummary_API
{
static private $instance = null;
static public function getInstance()
@@ -36,6 +36,7 @@ class Piwik_VisitsSummary_API extends Piwik_Apiable
'nb_actions',
'sum_visit_length',
'bounce_count',
+ 'nb_visits_converted',
);
$dataTable = $archive->getDataTableFromNumeric($toFetch);
return $dataTable;
@@ -83,4 +84,9 @@ class Piwik_VisitsSummary_API extends Piwik_Apiable
{
return self::getNumeric( $idSite, $period, $date, 'bounce_count');
}
+
+ public function getVisitsConverted( $idSite, $period, $date )
+ {
+ return self::getNumeric( $idSite, $period, $date, 'nb_visits_converted');
+ }
}
diff --git a/tests/build-canoo.xml b/tests/build-canoo.xml
new file mode 100644
index 0000000000..72f8dc7c2c
--- /dev/null
+++ b/tests/build-canoo.xml
@@ -0,0 +1,15 @@
+<project name="canoo" default="webtest" basedir=".">
+
+ <property file="webtest/config/webtest.properties"/>
+ <echo>${wt.home}</echo>
+ <import file="${wt.home}/webtest.xml" optional="true" description="Import all functionalities for a full build"/>
+
+ <property name="wt.testInWork" value="webtest/test_suite"/>
+ <property name="wt.config.resultfile" value="webtestResults.xml"/>
+ <property name="wt.config.resultpath" location="results"/>
+ <property name="wt.config.summary" value="true"/>
+ <property name="wt.config.showhtmlparseroutput" value="true"/>
+
+ <target name="webtest" depends="wt.full"/>
+
+</project> \ No newline at end of file
diff --git a/tests/build.sample.properties b/tests/build.sample.properties
index 20794460b0..df34f0b3cf 100644
--- a/tests/build.sample.properties
+++ b/tests/build.sample.properties
@@ -15,3 +15,8 @@ database.test.port=3306
database.test.username=username
database.test.password=password
database.test.name=dbname_test
+
+phpdocumentor.home=/usr/local/PhpDocumentor
+phpdocumentor.report.dir=./phpdocumentor-report
+
+schemaspy.report.dir=./schemaspy-report
diff --git a/tests/build.xml b/tests/build.xml
index 9b5630fe27..17a272be24 100644
--- a/tests/build.xml
+++ b/tests/build.xml
@@ -1,9 +1,11 @@
<project name="piwik" default="all" basedir=".">
<property file="build.properties" />
+ <property file="defaults.properties" />
<target name="clean">
<delete dir="${basedir}/../build" />
+ <delete dir="${basedir}/results" />
</target>
<target name="prepare-build-filesystem" depends="clean">
@@ -23,6 +25,16 @@
<include name="*" />
</fileset>
</copy>
+ <mkdir dir="${basedir}/../build/tmp/templates_c"/>
+ <mkdir dir="${basedir}/../build/tmp/cache"/>
+ <chmod perm="a+rw">
+ <dirset dir="${basedir}/../build">
+ <include name="config" />
+ <include name="tmp" />
+ <include name="tmp/templates_c" />
+ <include name="tmp/cache" />
+ </dirset>
+ </chmod>
</target>
<target name="process-build-resources" depends="prepare-build-filesystem">
@@ -39,9 +51,71 @@
<arg value="all_tests.php" />
</exec>
</target>
+
+ <target name="phpdoc">
+
+ <echo>phpDocumentor started</echo>
+
+ <delete dir="${basedir}/build/phpdocumentor-report"/>
+ <mkdir dir="${basedir}/build/phpdocumentor-report"/>
+ <exec executable="${php.executable}" dir="${basedir}/../build" failonerror="true" failifexecutionfails="true">
+ <arg value="${phpdocumentor.home}/phpDocumentor/phpdoc.inc" />
+ <arg value="--useconfig"/>
+ <arg path="${basedir}/../misc/phpdoc-config.ini"/>
+ </exec>
+
+ <copy todir="${phpdocumentor.report.dir}" overwrite="true" failonerror="true" verbose="true">
+ <fileset dir="${basedir}/../build/documentation"/>
+ </copy>
+
+ <echo>phpDocumentor finished</echo>
+
+ </target>
+
+ <target name="webtest">
+ <delete file="${basedir}/../build/config/config.ini.php"/>
+ <ant antfile="${basedir}/build-canoo.xml"/>
+ </target>
+
+ <target name="schemaspy">
+
+ <echo>SchemaSpy started</echo>
+
+ <delete dir="${basedir}/build/schemaspy-report"/>
+ <mkdir dir="${basedir}/build/schemaspy-report"/>
+
+ <echo message="Generating schema for MySql" />
+ <java jar="${basedir}/lib/java/schemaSpy_3.1.1.jar" fork="true" failonerror="true" maxmemory="256m" dir="${basedir}">
+ <arg value="-t"/>
+ <arg value="mysql"/>
+ <arg value="-host"/>
+ <arg value="${database.main.host}:${database.main.port}"/>
+ <arg value="-db"/>
+ <arg value="${database.main.name}"/>
+ <arg value="-cp"/>
+ <arg path="${basedir}/lib/java/mysql-connector-java-5.1.7.jar"/>
+ <arg value="-u"/>
+ <arg value="${database.main.username}"/>
+ <arg value="-o"/>
+ <arg path="${basedir}/build/schemaspy-report"/>
+ <arg value="-p"/>
+ <arg value="${database.main.password}"/>
+ </java>
+
+ <copy todir="${schemaspy.report.dir}" overwrite="true" failonerror="true" verbose="true">
+ <fileset dir="${basedir}/build/schemaspy-report"/>
+ </copy>
+
+ <echo>SchemaSpy finished</echo>
+
+ </target>
+
<target name="all">
<antcall target="test"/>
+ <antcall target="webtest"/>
+ <antcall target="phpdoc"/>
+ <antcall target="schemaspy"/>
</target>
</project> \ No newline at end of file
diff --git a/tests/config_test.php b/tests/config_test.php
index 676d4e4d6b..4b8d6b85f3 100755
--- a/tests/config_test.php
+++ b/tests/config_test.php
@@ -72,7 +72,6 @@ require_once 'Zend/Db/Table.php';
require_once 'FrontController.php';
require_once 'Config.php';
require_once 'Timer.php';
-require_once 'API/APIable.php';
require_once 'Access.php';
require_once 'Log.php';
require_once 'core/Piwik.php';
diff --git a/tests/core/DataTable.test.php b/tests/core/DataTable.test.php
index f54315e412..092fb7e7d3 100644
--- a/tests/core/DataTable.test.php
+++ b/tests/core/DataTable.test.php
@@ -255,7 +255,8 @@ class Test_Piwik_DataTable extends UnitTestCase
'test_float3'=> 1.5,
'test_stringint'=> "145",
"test" => 'string fake',
- 'super'=>array('this column has an array value, amazing')
+ 'super'=>array('this column has an array string that will be 0 when algorithm sums the value'),
+ 'integerArrayToSum'=>array( 1 => 1, 2 => 10.0, 3 => array(1 => 2, 2 => 3)),
);
$metadata = array('logo'=> 'piwik.png',
'super'=>array('this column has an array value, amazing'));
@@ -271,23 +272,22 @@ class Test_Piwik_DataTable extends UnitTestCase
'test_float2'=> 14.5,
'test_stringint'=> "5",
0925824 => 'toto',
- 'super'=>array('this column has geagaean array value, amazing'));
+ 'super'=>array('this column has geagaean array value, amazing'),
+ 'integerArrayToSum'=>array( 1 => 5, 2 => 5.5, 3 => array(2 => 4)),
+ );
$finalRow = new Piwik_DataTable_Row( array(Piwik_DataTable_Row::COLUMNS => $columns2));
-
$finalRow->sumRow($row1);
-
-
$columnsWanted = array('test_int'=> 150,
'test_float'=> 150.0,
'test_float2'=> 14.5,
'test_float3'=> 1.5,
- 'test_stringint'=> "150", //add also strings!!
- 'super'=>array('this column has geagaean array value, amazing'),
+ 'test_stringint'=> 150, //add also strings!!
+ 'super'=>array(0),
+ 'test' => 0,
+ 'integerArrayToSum' => array( 1 => 6, 2 => 15.5, 3 => array(1 => 2, 2 => 7)),
0925824 => 'toto',
);
-
$rowWanted = new Piwik_DataTable_Row( array(Piwik_DataTable_Row::COLUMNS => $columnsWanted));
-
$this->assertTrue( Piwik_DataTable_Row::isEqual($rowWanted, $finalRow));
}
diff --git a/tests/core/DataTable/Renderer.test.php b/tests/core/DataTable/Renderer.test.php
index 28721ec5cd..182eec74b9 100644
--- a/tests/core/DataTable/Renderer.test.php
+++ b/tests/core/DataTable/Renderer.test.php
@@ -50,7 +50,7 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
$subtable =
$array = array (
- array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Google&copy;', 'nb_uniq_visitors' => 11, 'nb_visits' => 11, 'nb_actions' => 17, 'max_actions' => '5', 'sum_visit_length' => 517, 'bounce_count' => 9),
+ array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Google&copy;', 'goals' => array('idgoal=1' => array('revenue'=> 5.5, 'nb_conversions' => 10)), 'nb_uniq_visitors' => 11, 'nb_visits' => 11, 'nb_actions' => 17, 'max_actions' => '5', 'sum_visit_length' => 517, 'bounce_count' => 9),
Piwik_DataTable_Row::METADATA => array('url' => 'http://www.google.com', 'logo' => './plugins/Referers/images/searchEngines/www.google.com.png'),
),
array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Yahoo!', 'nb_uniq_visitors' => 15, 'nb_visits' => 151, 'nb_actions' => 147, 'max_actions' => '50', 'sum_visit_length' => 517, 'bounce_count' => 90),
@@ -107,6 +107,12 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
<result>
<row>
<label>Google©</label>
+ <goals>
+ <row idgoal=\'1\'>
+ <revenue>5.5</revenue>
+ <nb_conversions>10</nb_conversions>
+ </row>
+ </goals>
<nb_uniq_visitors>11</nb_uniq_visitors>
<nb_visits>11</nb_visits>
<nb_actions>17</nb_actions>
@@ -190,9 +196,9 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase
$dataTable = $this->getDataTableTest();
$render = new Piwik_DataTable_Renderer_Csv($dataTable);
$render->convertToUnicode = false;
- $expected = 'label,nb_uniq_visitors,nb_visits,nb_actions,max_actions,sum_visit_length,bounce_count,metadata_url,metadata_logo
-Google©,11,11,17,5,517,9,http://www.google.com,./plugins/Referers/images/searchEngines/www.google.com.png
-Yahoo!,15,151,147,50,517,90,http://www.yahoo.com,./plugins/Referers/images/searchEngines/www.yahoo.com.png';
+ $expected = 'label,goals_idgoal=1_revenue,goals_idgoal=1_nb_conversions,nb_uniq_visitors,nb_visits,nb_actions,max_actions,sum_visit_length,bounce_count,metadata_url,metadata_logo
+Google©,5.5,10,11,11,17,5,517,9,http://www.google.com,./plugins/Referers/images/searchEngines/www.google.com.png
+Yahoo!,,,15,151,147,50,517,90,http://www.yahoo.com,./plugins/Referers/images/searchEngines/www.yahoo.com.png';
$this->assertEqual( $expected,$render->render());
}
@@ -243,7 +249,7 @@ bounce_count,44';
{
$dataTable = $this->getDataTableTest();
$render = new Piwik_DataTable_Renderer_Json($dataTable, true);
- $expected = '[{"label":"Google&copy;","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":0,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
+ $expected = '[{"label":"Google&copy;","goals":{"idgoal=1":{"revenue":5.5,"nb_conversions":10}},"nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":0,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]';
$rendered = $render->render();
$this->assertEqual( $expected,$rendered);
@@ -289,6 +295,12 @@ bounce_count,44';
0 =>
array (
'label' => 'Google&copy;',
+ 'goals' => array(
+ 'idgoal=1' => array(
+ 'revenue' => 5.5,
+ 'nb_conversions' => 10,
+ ),
+ ),
'nb_uniq_visitors' => 11,
'nb_visits' => 11,
'nb_actions' => 17,
diff --git a/tests/core/PHP_Related.test.php b/tests/core/PHP_Related.test.php
index ae6f25ef98..99c8ee092b 100644
--- a/tests/core/PHP_Related.test.php
+++ b/tests/core/PHP_Related.test.php
@@ -24,6 +24,51 @@ class Test_PHP_Related extends UnitTestCase
{
}
+ // conclusion:
+ // - it's ok to have big holes in your array index values
+ // - obvious: it's not ok to index array by strings when you can do magic and index with int
+ function oldtest_memoryUsageArrayIncreasingIndexOrJumps()
+ {
+ ini_set('memory_limit','200M');
+ Piwik::createConfigObject();
+ Piwik::createLogObject();
+ //test array[0] array[1] array[2]
+ //VS
+ // test array[0] array[100] array[200]
+ // same memory usage? hash
+ echo "start ". __FUNCTION__ . "<br>";
+ Piwik::printMemoryUsage();
+ $timer = new Piwik_Timer();
+ $testId = 2;
+ if($testId == 1)
+ {
+ echo "start incrementing index<br>";
+ $array = array();
+ for($i = 0; $i<1000000;$i++) {
+ $array[$i] = 1;
+ }
+ }
+ elseif($testId == 2)
+ {
+ echo "start indexing by strings<br>";
+ $array = array();
+ for($i = 0; $i<1000000;$i++) {
+ $array[$i."_".$i] = 1;
+ }
+ }
+ elseif($testId == 3)
+ {
+ echo "start jumping index<br>";
+ for($i = 0; $i<1000000;$i++) {
+ $array[$i*100] = 1;
+ }
+ }
+ echo $timer . "<br>";
+ echo "size serialized:". Piwik::getPrettySizeFromBytes(strlen(serialize($array))). "<br>";
+ Piwik::printMemoryUsage();
+ echo "end ". __FUNCTION__ . "<br>";
+ }
+
function test_versionTrailingZero()
{
$this->assertTrue(version_compare('0.1','0.01') == 0);
@@ -75,9 +120,7 @@ class Test_PHP_Related extends UnitTestCase
public function test_staticAttr()
{
// use this trick to read the static attribute of the class
- // $class::$methodsNotToPublish doesn't work
$vars = get_class_vars("test_staticAttr");
-
$this->assertEqual( $vars['a'], 'testa' );
}
diff --git a/tests/core/Piwik.test.php b/tests/core/Piwik.test.php
index f3313e7a81..6f53b1dcb3 100644
--- a/tests/core/Piwik.test.php
+++ b/tests/core/Piwik.test.php
@@ -29,17 +29,18 @@ class Test_Piwik extends UnitTestCase
(float)-1, (float)0 , (float)1, (float)1.5, (float)-1.5, (float)21111, (float)89898, (float)99999999999, (float)-4565656,
(int)-1, (int)0 , (int)1, (int)1.5, (int)-1.5, (int)21111, (int)89898, (int)99999999999, (int)-4565656,
'-1', '0' , '1', '1.5', '-1.5', '21111', '89898', '99999999999', '-4565656',
+ '1e3','0x123', "-1e-2",
);
foreach($valid as $toTest)
{
- $this->assertTrue(Piwik::isNumeric($toTest), $toTest." not valid!");
+ $this->assertTrue(Piwik::isNumeric($toTest), $toTest." not valid but should!");
}
}
public function test_isNumericNotValid()
{
$notvalid = array(
- '-1.0.0', '1e3','1,2', '0x123', '--1', '-.', "-1e-2", '- 1', '1-',
+ '-1.0.0', '1,2', '--1', '-.', '- 1', '1-',
);
foreach($notvalid as $toTest)
{
diff --git a/tests/core/ReleaseCheckList.test.php b/tests/core/ReleaseCheckList.test.php
index 2272cadaee..329a329376 100644
--- a/tests/core/ReleaseCheckList.test.php
+++ b/tests/core/ReleaseCheckList.test.php
@@ -27,13 +27,38 @@ class Test_Piwik_ReleaseCheckList extends UnitTestCase
$this->checkEqual(array('General' => 'default_language'), 'en');
$this->checkEqual(array('Tracker' => 'record_statistics'), '1');
$this->checkEqual(array('Tracker' => 'visit_standard_length'), '1800');
+ $this->checkEqual(array('log' => 'logger_message'), array('screen'));
+ $this->checkEqual(array('log' => 'logger_exception'), array('screen'));
+ $this->checkEqual(array('log' => 'logger_error'), array('screen'));
+ $this->checkEqual(array('log' => 'logger_api_call'), null);
}
private function checkEqual($key, $valueExpected)
{
$section = key($key);
$optionName = current($key);
- $value = $this->globalConfig[$section][$optionName];
+ $value = null;
+ if(isset($this->globalConfig[$section][$optionName]))
+ {
+ $value = $this->globalConfig[$section][$optionName];
+ }
$this->assertEqual($value, $valueExpected, "$section -> $optionName was '$value', expected '$valueExpected'");
}
+
+ public function test_checkThatGivenPluginsAreDisabledByDefault()
+ {
+ $pluginsShouldBeDisabled = array(
+ 'DBStats',
+ 'Goals',
+ 'Live',
+ );
+ foreach($pluginsShouldBeDisabled as $pluginName)
+ {
+ if(in_array($pluginName, $this->globalConfig['Plugins']['Plugins']))
+ {
+ throw new Exception("Plugin $pluginName is enabled by default but shouldn't.");
+ }
+ }
+
+ }
}
diff --git a/tests/datasets/referer-xss.txt b/tests/datasets/referer-xss.txt
new file mode 100644
index 0000000000..b396c04813
--- /dev/null
+++ b/tests/datasets/referer-xss.txt
@@ -0,0 +1,7 @@
+INSERT INTO `piwik_log_visit` (`idvisit`, `idsite`, `visitor_localtime`, `visitor_idcookie`, `visitor_returning`, `visit_first_action_time`, `visit_last_action_time`, `visit_server_date`, `visit_exit_idaction`, `visit_entry_idaction`, `visit_total_actions`, `visit_total_time`, `visit_goal_converted`, `referer_type`, `referer_name`, `referer_url`, `referer_keyword`, `config_md5config`, `config_os`, `config_browser_name`, `config_browser_version`, `config_resolution`, `config_pdf`, `config_flash`, `config_java`, `config_director`, `config_quicktime`, `config_realplayer`, `config_windowsmedia`, `config_cookie`, `location_ip`, `location_browser_lang`, `location_country`, `location_continent`, `location_provider`) VALUES
+(5, 1, '14:38:01', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 15:48:40', '2008-11-14 15:48:40', '2008-11-14', 2, 2, 1, 10, '', 2, 'Google', 'http://www.google.co.uk/search?hl=en&amp;q=%3Cscript%3Ealert(%27test%27);%3C/script%3E', '%3cscript%3ealert(%27test%27);%3c/script%3e', '231ea91c00491cb5e6484f00c274b037', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 0, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(15, 1, '18:03:29', 'fff3699b375db5e7cea33a58454cb8a0', 0, '2008-11-14 18:04:39', '2008-11-14 18:04:39', '2008-11-14', 2, 2, 1, 10, '', 3, 'htmlentities', 'http://example.com/&quot;&lt;script&gt;alert(''test'');&lt;/script&gt;', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(16, 1, '19:51:00', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 19:51:00', '2008-11-14 19:51:00', '2008-11-14', 5, 5, 1, 10, '', 3, 'example1.com', 'http://example.com/%22%3E%3Cscript%3Ealert(%27yo%27)%3C%2Fscript%3E', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(17, 1, '10:25:48', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 10:25:48', '2008-11-14 10:25:48', '2008-11-14', 5, 5, 1, 10, '', 3, 'urlencode', 'http://example3.com/test%3cscript%3ealert(%27test%27);%3c/script%3e', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(21, 1, '12:35:41', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-14 12:35:41', '2008-11-14 13:27:14', '2008-11-14', 5, 2, 26, 3093, '', 3, 'example2.com', 'http://example.com/&quot;&gt;&lt;script&gt;alert(''hi'')&lt;/script&gt;', '', '00b29dee0697cb1eeb1931d04813f5f1', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 1, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip'),
+(53615, 1, '14:38:01', 'fb9af1315358d20049619db26b6f1ff9', 1, '2008-11-24 14:04:42', '2008-11-24 14:21:20', '2008-11-24', 2, 2, 3, 998, '', 3, 'localhost&lt;script&gt;alert(''test'')&lt;', 'http://localhost&lt;script&gt;alert(''test'')&lt;/script&gt;/test&lt;script&gt;alert(''test'')&lt;/script&gt;', '', '231ea91c00491cb5e6484f00c274b037', 'WXP', 'FF', '3.0', '1440x900', 1, 1, 0, 0, 0, 0, 1, 1, 2130706433, 'en-gb,fr;q=0.8,ja;q=', 'uk', 'eur', 'Ip');
diff --git a/tests/defaults.properties b/tests/defaults.properties
new file mode 100644
index 0000000000..ddf763f802
--- /dev/null
+++ b/tests/defaults.properties
@@ -0,0 +1,2 @@
+phpdocumentor.report.dir=./phpdocumentor-report
+schemaspy.report.dir=./schemaspy-report
diff --git a/tests/lib/java/mysql-connector-java-5.1.7.jar b/tests/lib/java/mysql-connector-java-5.1.7.jar
new file mode 100644
index 0000000000..ebfe06861a
--- /dev/null
+++ b/tests/lib/java/mysql-connector-java-5.1.7.jar
Binary files differ
diff --git a/tests/lib/java/schemaSpy_3.1.1.jar b/tests/lib/java/schemaSpy_3.1.1.jar
new file mode 100644
index 0000000000..0fb672c67b
--- /dev/null
+++ b/tests/lib/java/schemaSpy_3.1.1.jar
Binary files differ
diff --git a/tests/webtest/config/webtest.example.properties b/tests/webtest/config/webtest.example.properties
new file mode 100644
index 0000000000..470688723c
--- /dev/null
+++ b/tests/webtest/config/webtest.example.properties
@@ -0,0 +1,44 @@
+################################################
+# Test suite configuration file
+################################################
+
+### WebTests config
+wt.home=/usr/local/canoo
+wt.config.host=127.0.0.1
+wt.config.port=80
+wt.config.protocol=http
+wt.config.basepath=/piwik
+
+wt.config.failOnError=true
+wt.config.haltOnError=true
+wt.config.haltOnFailure=true
+wt.config.enableJS=true
+wt.config.throwExceptionOnScriptError=true
+wt.config.browser=Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12
+wt.config.verifyLinks=true
+wt.config.verifyImages=true
+wt.config.headless=false
+#wt.openResultFile.skip=true
+
+## General settings
+testcase.dir=./testcases
+
+# patterns for each level
+testcase.level0.pattern=*.xml
+testcase.level1.pattern=*.xml
+testcase.level2.pattern=*.xml
+testcase.level3.pattern=*.xml
+screens=manual_results
+
+## To turn on/off specific level of tests just uncomment/comment appropriate line below
+test.level0=true
+test.level1=true
+#test.level2=true
+#test.level3=true
+
+## db settings
+db.username=username
+db.password=password
+db.port=3306
+db.name=piwik
+db.host=127.0.0.1
diff --git a/tests/webtest/test_suite.xml b/tests/webtest/test_suite.xml
new file mode 100644
index 0000000000..e2d86279f5
--- /dev/null
+++ b/tests/webtest/test_suite.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Piwik" default="Level3" basedir=".">
+
+ <target name="setup">
+ <mkdir dir="${screens}" />
+ </target>
+
+ <target name="Level0" if="test.level0" depends="setup">
+ <echo>Starting smoke tests...</echo>
+ <subant failonerror="${wt.config.failOnError}" inheritall="true">
+ <fileset dir="${testcase.dir}/level0" includes="${testcase.level0.pattern}"/>
+ </subant>
+ <echo>##################################</echo>
+ <echo># 0 level smoke tests - FINISHED!#</echo>
+ <echo>##################################</echo>
+ </target>
+
+ <target name="Level1" if="test.level1" depends="Level0">
+ <echo>Starting setup tests...</echo>
+ <subant failonerror="${wt.config.failOnError}" inheritall="true">
+ <fileset dir="${testcase.dir}/level1" includes="${testcase.level1.pattern}"/>
+ </subant>
+ <echo>#################################</echo>
+ <echo># 1st level tests - FINISHED! #</echo>
+ <echo>#################################</echo>
+ </target>
+
+ <target name="Level2" if="test.level2" depends="Level1">
+ <echo>Starting setup tests...</echo>
+ <subant failonerror="${wt.config.failOnError}" inheritall="true">
+ <fileset dir="${testcase.dir}/level2" includes="${testcase.level2.pattern}"/>
+ </subant>
+ <echo>###################################</echo>
+ <echo># 2nd level test - FINISHED! #</echo>
+ <echo>###################################</echo>
+ </target>
+
+ <target name="Level3" if="test.level3" depends="Level2">
+ <echo>Starting UI tests - 3rd level...</echo>
+ <echo>+-----------------------------------------+</echo>
+ <echo>| WARNING! 3rd Level tests are optional |</echo>
+ <echo>| and could fail without BUILD FAILED! |</echo>
+ <echo>+-----------------------------------------+</echo>
+ <subant failonerror="${wt.config.failOnError}" inheritall="true">
+ <fileset dir="${testcase.dir}/level3" includes="${testcase.level3.pattern}"/>
+ </subant>
+ <echo>3rd level smoke tests finished - check for potential errors!</echo>
+ </target>
+
+</project>
diff --git a/tests/webtest/testcases/level0/test.piwik.index.xml b/tests/webtest/testcases/level0/test.piwik.index.xml
new file mode 100644
index 0000000000..0752307202
--- /dev/null
+++ b/tests/webtest/testcases/level0/test.piwik.index.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE project [
+ <!ENTITY time SYSTEM "../modules/time.xml">
+ <!ENTITY checkForErrors SYSTEM "../modules/errors.xml">
+ <!ENTITY verifyLinksAndImages SYSTEM "../modules/common_pages.xml">
+ <!ENTITY raquo "&#187;">
+ <!ENTITY rsaquo "&#8250;" >
+]>
+
+<project name="Smoke test level0 - deploy test" basedir="." default="webtest">
+ &time;
+ <target name="webtest">
+ <webtest name="install index">
+ <steps>
+
+ <echo>Piwik install - dbsetup: db.name: ${db.name}</echo>
+ <sql
+ driver="com.mysql.jdbc.Driver"
+ url="jdbc:mysql://${db.host}:${db.port}/"
+ userid="${db.username}"
+ password="${db.password}"
+ >
+ <classpath>
+ <pathelement location="${basedir}/../lib/java/mysql-connector-java-5.1.7.jar" />
+ </classpath>
+ <transaction>
+ DROP DATABASE IF EXISTS ${db.name};
+ </transaction>
+ <transaction>
+ CREATE DATABASE IF NOT EXISTS ${db.name};
+ </transaction>
+ </sql>
+
+ <invoke description="get account index" url="/" />
+
+ <!-- 1. welcome -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Welcome!" />
+ <verifyText description="check page text" text="This process is split up into 8 easy steps and will take around 5 minutes" />
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <clickLink description="click 'Next'" label="Next &raquo;" />
+
+ <!-- 2. systemCheck -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="System check" />
+ <verifyText description="check page text" text="Optional" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <not description="check if system check passed">
+ <verifyXPath description="looking for error image" xpath="//img[@src='themes/default/images/error.png']"/>
+ </not>
+
+ <verifyXPath description="looking for ok image" xpath="//img[@src='themes/default/images/ok.png']"/>
+
+ <clickLink description="click 'Next'" label="Next &raquo;" />
+
+ <!-- 3. databaseSetup -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Mysql database setup" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <setInputField description="set database host (and port)" name="host" value="${db.host}:${db.port}" />
+ <setInputField description="set database username" name="username" value="${db.username}" />
+ <setInputField description="set database password" name="password" value="${db.password}" />
+ <setInputField description="set database name" name="dbname" value="${db.name}" />
+ <setInputField description="set database port" name="tables_prefix" value="canoo_" />
+
+ <clickButton description="click 'Go!' button" label="Go!"/>
+
+ <!-- 4. tablesCreation -->
+
+ <not description="check if no error">
+ <verifyXPath description="looking for error image" xpath="//img[@src='themes/default/images/error_medium.png']"/>
+ </not>
+
+ <not description="check if no warning">
+ <verifyXPath description="looking for warning image" xpath="//img[@src='themes/default/images/warning_medium.png']"/>
+ </not>
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Tables created with success!" />
+ <verifyXPath description="looking for success image" xpath="//img[@src='themes/default/images/success_medium.png']"/>
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <clickLink description="click 'Next'" label="Next &raquo;" />
+
+ <!-- 5. generalSetup -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="General Setup" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <setInputField description="set Piwik login" name="login" value="piwik_login" />
+ <setInputField description="set Piwik password" name="password" value="piwik_password" />
+ <setInputField description="set repeated Piwik password" name="password_bis" value="piwik_password" />
+ <setInputField description="set Piwik email" name="email" value="nobody@piwik.org" />
+
+ <clickButton description="click 'Go!' button" label="Go!"/>
+
+ <!-- 6. firstWebsiteSetup -->
+
+ <not description="check if no error">
+ <verifyXPath description="looking for error image" xpath="//img[@src='themes/default/images/error_medium.png']"/>
+ </not>
+
+ <not description="check if no warning">
+ <verifyXPath description="looking for warning image" xpath="//img[@src='themes/default/images/warning_medium.png']"/>
+ </not>
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Setup a website" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <setInputField description="set Piwik site name" name="siteName" value="Dummy Site Name" />
+ <setInputField description="set Piwik URL" name="url" value="${wt.config.protocol}://${wt.config.host}:${wt.config.port}${wt.config.basepath}" />
+
+ <clickButton description="click 'Go!' button" label="Go!"/>
+
+ <!-- 7. displayJavascriptCode -->
+
+ <not description="check if no error">
+ <verifyXPath description="looking for error image" xpath="//img[@src='themes/default/images/error_medium.png']"/>
+ </not>
+
+ <not description="check if no warning">
+ <verifyXPath description="looking for warning image" xpath="//img[@src='themes/default/images/warning_medium.png']"/>
+ </not>
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Javascript tag" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <clickLink description="click 'Next'" label="Next &raquo;" />
+
+ <!-- 8. finished -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &raquo; Installation" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Congratulations" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <clickLink description="click 'Continue to Piwik'" label="Continue to Piwik &raquo;" />
+
+ <!-- logging in -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &rsaquo; Login" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Lost your password?" />
+
+ &checkForErrors;
+ &verifyLinksAndImages;
+
+ <setInputField description="set Piwik login" htmlId="form_login" value="piwik_login" />
+ <setInputField description="set Piwik password" htmlId="form_password" value="piwik_password" />
+ <clickButton description="click 'Sign in' button" label="Sign in"/>
+
+ <!-- logged in -->
+
+ <verifyTitle description="check the title is parsed correctly" text="Piwik &rsaquo; Web Analytics Reports" />
+ <verifyText description="check page text" text="Piwik" />
+ <verifyText description="check page text" text="Your Dashboard" />
+ <verifyText description="check page text" text="Hello" />
+
+ </steps>
+ </webtest>
+ </target>
+</project>
diff --git a/tests/webtest/testcases/modules/common_pages.xml b/tests/webtest/testcases/modules/common_pages.xml
new file mode 100644
index 0000000000..7ef4e4cbcb
--- /dev/null
+++ b/tests/webtest/testcases/modules/common_pages.xml
@@ -0,0 +1,8 @@
+ <enableJavaScript description="Disable JS verification for external resources" enable="false" />
+ <ifStep description="production tests" test="${wt.config.verifyLinks}">
+ <verifyLinks />
+ </ifStep>
+ <ifStep description="production tests" test="${wt.config.verifyImages}">
+ <verifyImages />
+ </ifStep>
+ <enableJavaScript description="Turn back JS verification for further testing" enable="true" /> \ No newline at end of file
diff --git a/tests/webtest/testcases/modules/errors.xml b/tests/webtest/testcases/modules/errors.xml
new file mode 100644
index 0000000000..b348cb3a4d
--- /dev/null
+++ b/tests/webtest/testcases/modules/errors.xml
@@ -0,0 +1,6 @@
+<not description="There should be no errors and no notices on output page">
+ <verifyText description="Check errors" text="error:" />
+ <verifyText description="Check errors" text="Fatal error" />
+ <verifyText description="Check notices" text="Notice" />
+ <verifyText description="Check warnings" text="Warning" />
+</not> \ No newline at end of file
diff --git a/tests/webtest/testcases/modules/time.xml b/tests/webtest/testcases/modules/time.xml
new file mode 100644
index 0000000000..7374446eab
--- /dev/null
+++ b/tests/webtest/testcases/modules/time.xml
@@ -0,0 +1,15 @@
+ <tstamp>
+ <format property="today.plus.one" pattern="yyyy-MM-dd"
+ offset="1" unit="day" />
+ </tstamp>
+ <tstamp>
+ <format property="today.plus.three" pattern="yyyy-MM-dd"
+ offset="3" unit="day" />
+ </tstamp>
+ <tstamp>
+ <format property="unique" pattern="yyMMddHHmmssS" />
+ </tstamp>
+ <tstamp>
+ <format property="today.minus.two" pattern="yyyy-MM-dd"
+ offset="-2" unit="day" />
+ </tstamp> \ No newline at end of file
diff --git a/themes/default/common.css b/themes/default/common.css
index 353a9ab503..d2123e4753 100644
--- a/themes/default/common.css
+++ b/themes/default/common.css
@@ -45,6 +45,8 @@ body {
}
a {
color: #0F1B2E;
+ text-decoration:underline;
+ cursor:pointer;
}
#loadingPiwik {
@@ -135,3 +137,60 @@ a {
color: #000000;
margin-bottom: 0px;
}
+#tooltip h3 {
+ font-weight:none;
+ font-size:1em;
+ color:#162540;
+ margin:0;
+ padding:0;
+}
+#tooltip {
+ position: absolute;
+ z-index: 3000;
+ border: 1px solid #111;
+ padding:7px;
+ background-color:#F5F7FF;
+ opacity:0.95;
+}
+
+
+.tableForm {
+ cellspacing:0;
+}
+.tableForm td {
+ border-color:#FFFFFF rgb(198, 205, 216) rgb(198, 205, 216) rgb(198, 205, 216) ;
+ border-style:solid;
+ padding:0.5em 0.5em 0.5em 0.8em;
+ border-width:10px 1px 1px 1px;
+ color:#203276;
+}
+.tableForm input {
+ font-size:1.1em;
+ border-color:#CCCCCC rgb(153, 153, 153) rgb(153, 153, 153) rgb(204, 204, 204);
+ border-width:1px;
+ color:#3A2B16;
+ padding:0.15em;
+}
+.tableForm .submit {
+ text-align:center;
+}
+.submit input{
+ margin-top:15px;
+ background:transparent url(./images/background-submit.png) repeat scroll 0%;
+ font-size:1.4em;
+ border-color:#CCCCCC rgb(153, 153, 153) rgb(153, 153, 153) rgb(204, 204, 204);
+ border-style:double;
+ border-width:3px;
+ color:#333333;
+ padding:0.15em;
+}
+
+#ajaxError {
+ color: red;
+ text-align: center;
+ font-weight: bold;
+ width: 550px;
+ border: 3px solid red;
+ margin: 10px;
+ padding: 10px;
+} \ No newline at end of file
diff --git a/themes/default/common.js b/themes/default/common.js
index 04753a8a0a..d0d2611c7c 100644
--- a/themes/default/common.js
+++ b/themes/default/common.js
@@ -1,4 +1,3 @@
-
function findSWFGraph(name) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[name];
diff --git a/themes/default/genericForm.tpl b/themes/default/genericForm.tpl
index bad53cea86..1084e7fce5 100755
--- a/themes/default/genericForm.tpl
+++ b/themes/default/genericForm.tpl
@@ -51,4 +51,4 @@
{$form_data.submit.html}
</div>
-</form> \ No newline at end of file
+</form>
diff --git a/themes/default/images/feed.png b/themes/default/images/feed.png
new file mode 100644
index 0000000000..315c4f4fa6
--- /dev/null
+++ b/themes/default/images/feed.png
Binary files differ
diff --git a/themes/default/images/goal.png b/themes/default/images/goal.png
new file mode 100644
index 0000000000..e4bc611f87
--- /dev/null
+++ b/themes/default/images/goal.png
Binary files differ