Update translations
This commit is contained in:
parent
310fbcdb07
commit
48b354abf4
425
iwla.pot
425
iwla.pot
|
@ -1,425 +0,0 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2016-04-12 08:34+CEST\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: ENCODING\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
|
||||
|
||||
#: display.py:32
|
||||
msgid "April"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32
|
||||
msgid "February"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32
|
||||
msgid "January"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32
|
||||
msgid "July"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32
|
||||
msgid "March"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32 iwla.py:472
|
||||
msgid "June"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:32 iwla.py:472
|
||||
msgid "May"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:33
|
||||
msgid "August"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:33
|
||||
msgid "December"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:33
|
||||
msgid "November"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:33
|
||||
msgid "October"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:33
|
||||
msgid "September"
|
||||
msgstr ""
|
||||
|
||||
#: display.py:195
|
||||
msgid "Ratio"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:413
|
||||
msgid "Statistics"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 iwla.py:474
|
||||
msgid "Not viewed Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 iwla.py:474
|
||||
msgid "Visits"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76 plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153 plugins/display/top_downloads.py:97
|
||||
#: plugins/display/top_visitors.py:72 plugins/display/track_users.py:113
|
||||
msgid "Hits"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76 plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153 plugins/display/top_visitors.py:72
|
||||
#: plugins/display/track_users.py:77 plugins/display/track_users.py:113
|
||||
msgid "Pages"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 iwla.py:474 plugins/display/all_visits.py:70
|
||||
#: plugins/display/hours_stats.py:73 plugins/display/hours_stats.py:83
|
||||
#: plugins/display/top_visitors.py:72
|
||||
msgid "Bandwidth"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 plugins/display/hours_stats.py:71
|
||||
msgid "By day"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:421 plugins/display/hours_stats.py:73
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:458
|
||||
msgid "Average"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:463 iwla.py:508
|
||||
msgid "Total"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Apr"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Aug"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Dec"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Feb"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Jan"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Jul"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Mar"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Nov"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Oct"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:472
|
||||
msgid "Sep"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:473
|
||||
msgid "Summary"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:474
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:474 iwla.py:486 plugins/display/feeds.py:99
|
||||
#: plugins/display/ip_to_geo.py:109 plugins/display/operating_systems.py:90
|
||||
#: plugins/display/track_users.py:108
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:474 plugins/display/ip_to_geo.py:96
|
||||
#: plugins/display/ip_to_geo.py:114
|
||||
msgid "Visitors"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:522
|
||||
msgid "Statistics for"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:529
|
||||
msgid "Last update"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:533
|
||||
msgid "Time analysis"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:535
|
||||
msgid "hours"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:536
|
||||
msgid "minutes"
|
||||
msgstr ""
|
||||
|
||||
#: iwla.py:536
|
||||
msgid "seconds"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/all_visits.py:70 plugins/display/feeds.py:76
|
||||
#: plugins/display/ip_to_geo.py:64 plugins/display/top_visitors.py:72
|
||||
#: plugins/display/track_users.py:113
|
||||
msgid "Host"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/all_visits.py:70 plugins/display/top_visitors.py:72
|
||||
msgid "Last seen"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/all_visits.py:92
|
||||
msgid "All visits"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/all_visits.py:93 plugins/display/top_visitors.py:72
|
||||
msgid "Top visitors"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:79
|
||||
msgid "Browsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:79 plugins/display/browsers.py:113
|
||||
msgid "Browser"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:79 plugins/display/browsers.py:113
|
||||
#: plugins/display/operating_systems.py:78
|
||||
#: plugins/display/operating_systems.py:95 plugins/display/top_hits.py:71
|
||||
#: plugins/display/top_hits.py:97 plugins/display/top_pages.py:71
|
||||
#: plugins/display/top_pages.py:96
|
||||
msgid "Entrance"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:98 plugins/display/browsers.py:128
|
||||
#: plugins/display/referers.py:110 plugins/display/referers.py:125
|
||||
#: plugins/display/referers.py:140 plugins/display/referers.py:163
|
||||
#: plugins/display/referers.py:174 plugins/display/referers.py:185
|
||||
#: plugins/display/referers.py:222 plugins/display/top_downloads.py:83
|
||||
#: plugins/display/top_downloads.py:103 plugins/display/top_hits.py:82
|
||||
#: plugins/display/top_hits.py:103 plugins/display/top_pages.py:82
|
||||
#: plugins/display/top_pages.py:102 plugins/display/top_visitors.py:92
|
||||
msgid "Others"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:105
|
||||
msgid "Top Browsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:107
|
||||
msgid "All Browsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/browsers.py:123
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/feeds.py:70
|
||||
msgid "All Feeds parsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/feeds.py:76
|
||||
msgid "All feeds parsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/feeds.py:92
|
||||
msgid "Merged feeds parsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/feeds.py:97
|
||||
msgid "Feeds parsers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/feeds.py:104
|
||||
msgid "Found"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Fri"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Mon"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Sat"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Sun"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Thu"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Tue"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Wed"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:81
|
||||
msgid "By Hours"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/hours_stats.py:83
|
||||
msgid "Hours"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/ip_to_geo.py:96
|
||||
msgid "Country"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/ip_to_geo.py:96 plugins/display/ip_to_geo.py:107
|
||||
#: plugins/display/ip_to_geo.py:114
|
||||
msgid "Countries"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/operating_systems.py:78
|
||||
#: plugins/display/operating_systems.py:88
|
||||
msgid "Operating Systems"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/operating_systems.py:78
|
||||
#: plugins/display/operating_systems.py:95
|
||||
msgid "Operating System"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:95
|
||||
msgid "Connexion from"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:95 plugins/display/referers.py:153
|
||||
msgid "Origin"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:99 plugins/display/referers.py:156
|
||||
msgid "Search Engine"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:114 plugins/display/referers.py:167
|
||||
msgid "External URL"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:129 plugins/display/referers.py:178
|
||||
msgid "External URL (robot)"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:147
|
||||
msgid "Top Referers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:149
|
||||
msgid "All Referers"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:193
|
||||
msgid "All Key Phrases"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:200 plugins/display/referers.py:216
|
||||
msgid "Key phrase"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:200 plugins/display/referers.py:216
|
||||
msgid "Search"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:200 plugins/display/referers_diff.py:56
|
||||
msgid "Key phrases"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:210
|
||||
msgid "Top key phrases"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/referers.py:212
|
||||
msgid "All key phrases"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_downloads.py:71
|
||||
msgid "Hit"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:91
|
||||
#: plugins/display/top_downloads_diff.py:56
|
||||
msgid "All Downloads"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:97
|
||||
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:97
|
||||
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:96
|
||||
msgid "URI"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_downloads.py:89
|
||||
msgid "Top Downloads"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:91
|
||||
msgid "All Hits"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:90
|
||||
msgid "All Pages"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/top_pages.py:88
|
||||
msgid "Top Pages"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/track_users.py:77 plugins/display/track_users.py:106
|
||||
msgid "Tracked users"
|
||||
msgstr ""
|
||||
|
||||
#: plugins/display/track_users.py:77 plugins/display/track_users.py:113
|
||||
msgid "Last Access"
|
||||
msgstr ""
|
||||
|
Binary file not shown.
|
@ -5,16 +5,17 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: iwla\n"
|
||||
"POT-Creation-Date: 2016-04-12 08:34+CEST\n"
|
||||
"PO-Revision-Date: 2016-04-12 08:39+0100\n"
|
||||
"POT-Creation-Date: 2022-11-04 20:18+0100\n"
|
||||
"PO-Revision-Date: 2022-11-04 20:33+0100\n"
|
||||
"Last-Translator: Soutadé <soutade@gmail.com>\n"
|
||||
"Language-Team: iwla\n"
|
||||
"Language: fr_FR\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Generated-By: pygettext.py 1.5\n"
|
||||
"X-Generator: Poedit 1.6.10\n"
|
||||
"X-Generator: Poedit 3.1.1\n"
|
||||
"X-Poedit-SourceCharset: UTF-8\n"
|
||||
|
||||
#: display.py:32
|
||||
|
@ -37,13 +38,11 @@ msgstr "Juillet"
|
|||
msgid "March"
|
||||
msgstr "Mars"
|
||||
|
||||
#: display.py:32
|
||||
#: iwla.py:472
|
||||
#: display.py:32 iwla.py:503
|
||||
msgid "June"
|
||||
msgstr "Juin"
|
||||
|
||||
#: display.py:32
|
||||
#: iwla.py:472
|
||||
#: display.py:32 iwla.py:503
|
||||
msgid "May"
|
||||
msgstr "Mai"
|
||||
|
||||
|
@ -67,177 +66,152 @@ msgstr "Octobre"
|
|||
msgid "September"
|
||||
msgstr "Septembre"
|
||||
|
||||
#: display.py:195
|
||||
#: display.py:196
|
||||
msgid "Ratio"
|
||||
msgstr "Pourcentage"
|
||||
|
||||
#: iwla.py:413
|
||||
#: iwla.py:446
|
||||
msgid "Statistics"
|
||||
msgstr "Statistiques"
|
||||
|
||||
#: iwla.py:421
|
||||
#: iwla.py:474
|
||||
#: iwla.py:454 iwla.py:505
|
||||
msgid "Not viewed Bandwidth"
|
||||
msgstr "Traffic non vu"
|
||||
|
||||
#: iwla.py:421
|
||||
#: iwla.py:474
|
||||
#: iwla.py:454 iwla.py:505
|
||||
msgid "Visits"
|
||||
msgstr "Visites"
|
||||
|
||||
#: iwla.py:421
|
||||
#: iwla.py:474
|
||||
#: plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76
|
||||
#: plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83
|
||||
#: plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153
|
||||
#: plugins/display/top_downloads.py:97
|
||||
#: plugins/display/top_visitors.py:72
|
||||
#: plugins/display/track_users.py:113
|
||||
msgid "Hits"
|
||||
msgstr "Hits"
|
||||
|
||||
#: iwla.py:421
|
||||
#: iwla.py:474
|
||||
#: plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76
|
||||
#: plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83
|
||||
#: plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153
|
||||
#: plugins/display/top_visitors.py:72
|
||||
#: plugins/display/track_users.py:77
|
||||
#: plugins/display/track_users.py:113
|
||||
#: iwla.py:454 iwla.py:505 plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76 plugins/display/filter_users.py:77
|
||||
#: plugins/display/filter_users.py:113 plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83 plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153 plugins/display/top_visitors.py:72
|
||||
msgid "Pages"
|
||||
msgstr "Pages"
|
||||
|
||||
#: iwla.py:421
|
||||
#: iwla.py:474
|
||||
#: plugins/display/all_visits.py:70
|
||||
#: plugins/display/hours_stats.py:73
|
||||
#: plugins/display/hours_stats.py:83
|
||||
#: iwla.py:454 iwla.py:505 plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76 plugins/display/filter_users.py:113
|
||||
#: plugins/display/hours_stats.py:73 plugins/display/hours_stats.py:83
|
||||
#: plugins/display/referers.py:95 plugins/display/referers.py:153
|
||||
#: plugins/display/top_downloads.py:97 plugins/display/top_visitors.py:72
|
||||
msgid "Hits"
|
||||
msgstr "Hits"
|
||||
|
||||
#: iwla.py:454 iwla.py:505 plugins/display/all_visits.py:70
|
||||
#: plugins/display/hours_stats.py:73 plugins/display/hours_stats.py:83
|
||||
#: plugins/display/robot_bandwidth.py:81 plugins/display/robot_bandwidth.py:106
|
||||
#: plugins/display/top_visitors.py:72
|
||||
msgid "Bandwidth"
|
||||
msgstr "Bande passante"
|
||||
|
||||
#: iwla.py:421
|
||||
#: plugins/display/hours_stats.py:71
|
||||
#: iwla.py:454 plugins/display/hours_stats.py:71
|
||||
msgid "By day"
|
||||
msgstr "Par jour"
|
||||
|
||||
#: iwla.py:421
|
||||
#: plugins/display/hours_stats.py:73
|
||||
#: iwla.py:454 plugins/display/hours_stats.py:73
|
||||
msgid "Day"
|
||||
msgstr "Jour"
|
||||
|
||||
#: iwla.py:458
|
||||
#: iwla.py:493
|
||||
msgid "Average"
|
||||
msgstr "Moyenne"
|
||||
|
||||
#: iwla.py:463
|
||||
#: iwla.py:508
|
||||
#: iwla.py:496 iwla.py:541
|
||||
msgid "Total"
|
||||
msgstr "Total"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Apr"
|
||||
msgstr "Avr"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Aug"
|
||||
msgstr "Août"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Dec"
|
||||
msgstr "Déc"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Feb"
|
||||
msgstr "Fév"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Jan"
|
||||
msgstr "Jan"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Jul"
|
||||
msgstr "Jui"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Mar"
|
||||
msgstr "Mars"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Nov"
|
||||
msgstr "Nov"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Oct"
|
||||
msgstr "Oct"
|
||||
|
||||
#: iwla.py:472
|
||||
#: iwla.py:503
|
||||
msgid "Sep"
|
||||
msgstr "Sep"
|
||||
|
||||
#: iwla.py:473
|
||||
#: iwla.py:504
|
||||
msgid "Summary"
|
||||
msgstr "Résumé"
|
||||
|
||||
#: iwla.py:474
|
||||
#: iwla.py:505
|
||||
msgid "Month"
|
||||
msgstr "Mois"
|
||||
|
||||
#: iwla.py:474
|
||||
#: iwla.py:486
|
||||
#: plugins/display/feeds.py:99
|
||||
#: plugins/display/ip_to_geo.py:109
|
||||
#: iwla.py:505 iwla.py:517 plugins/display/feeds.py:101
|
||||
#: plugins/display/filter_users.py:108 plugins/display/ip_to_geo.py:109
|
||||
#: plugins/display/operating_systems.py:90
|
||||
#: plugins/display/track_users.py:108
|
||||
msgid "Details"
|
||||
msgstr "Détails"
|
||||
|
||||
#: iwla.py:474
|
||||
#: plugins/display/ip_to_geo.py:96
|
||||
#: plugins/display/ip_to_geo.py:114
|
||||
#: iwla.py:505 plugins/display/ip_to_geo.py:96 plugins/display/ip_to_geo.py:114
|
||||
msgid "Visitors"
|
||||
msgstr "Visiteurs"
|
||||
|
||||
#: iwla.py:522
|
||||
#: iwla.py:553
|
||||
msgid "Statistics for"
|
||||
msgstr "Statistiques pour"
|
||||
|
||||
#: iwla.py:529
|
||||
#: iwla.py:560
|
||||
msgid "Last update"
|
||||
msgstr "Dernière mise à jour"
|
||||
|
||||
#: iwla.py:533
|
||||
#: iwla.py:564
|
||||
msgid "Time analysis"
|
||||
msgstr "Durée de l'analyse"
|
||||
|
||||
#: iwla.py:535
|
||||
#: iwla.py:566
|
||||
msgid "hours"
|
||||
msgstr "heures "
|
||||
msgstr "heures"
|
||||
|
||||
#: iwla.py:536
|
||||
#: iwla.py:567
|
||||
msgid "minutes"
|
||||
msgstr "minutes"
|
||||
|
||||
#: iwla.py:536
|
||||
#: iwla.py:567
|
||||
msgid "seconds"
|
||||
msgstr "secondes"
|
||||
|
||||
#: plugins/display/all_visits.py:70
|
||||
#: plugins/display/feeds.py:76
|
||||
#: plugins/display/ip_to_geo.py:64
|
||||
#: plugins/display/all_visits.py:70 plugins/display/feeds.py:76
|
||||
#: plugins/display/filter_users.py:113 plugins/display/ip_to_geo.py:64
|
||||
#: plugins/display/robot_bandwidth.py:81 plugins/display/robot_bandwidth.py:106
|
||||
#: plugins/display/top_visitors.py:72
|
||||
#: plugins/display/track_users.py:113
|
||||
msgid "Host"
|
||||
msgstr "Hôte"
|
||||
|
||||
#: plugins/display/all_visits.py:70
|
||||
#: plugins/display/top_visitors.py:72
|
||||
#: plugins/display/all_visits.py:70 plugins/display/robot_bandwidth.py:81
|
||||
#: plugins/display/robot_bandwidth.py:106 plugins/display/top_visitors.py:72
|
||||
msgid "Last seen"
|
||||
msgstr "Dernière visite"
|
||||
|
||||
|
@ -245,8 +219,7 @@ msgstr "Dernière visite"
|
|||
msgid "All visits"
|
||||
msgstr "Toutes les visites"
|
||||
|
||||
#: plugins/display/all_visits.py:93
|
||||
#: plugins/display/top_visitors.py:72
|
||||
#: plugins/display/all_visits.py:93 plugins/display/top_visitors.py:72
|
||||
msgid "Top visitors"
|
||||
msgstr "Top visiteurs"
|
||||
|
||||
|
@ -254,50 +227,39 @@ msgstr "Top visiteurs"
|
|||
msgid "Browsers"
|
||||
msgstr "Navigateurs"
|
||||
|
||||
#: plugins/display/browsers.py:79
|
||||
#: plugins/display/browsers.py:113
|
||||
#: plugins/display/browsers.py:79 plugins/display/browsers.py:114
|
||||
msgid "Browser"
|
||||
msgstr "Navigateur"
|
||||
|
||||
#: plugins/display/browsers.py:79
|
||||
#: plugins/display/browsers.py:113
|
||||
#: plugins/display/browsers.py:79 plugins/display/browsers.py:114
|
||||
#: plugins/display/operating_systems.py:78
|
||||
#: plugins/display/operating_systems.py:95
|
||||
#: plugins/display/top_hits.py:71
|
||||
#: plugins/display/top_hits.py:97
|
||||
#: plugins/display/top_pages.py:71
|
||||
#: plugins/display/operating_systems.py:95 plugins/display/top_hits.py:71
|
||||
#: plugins/display/top_hits.py:97 plugins/display/top_pages.py:71
|
||||
#: plugins/display/top_pages.py:96
|
||||
msgid "Entrance"
|
||||
msgstr "Entrées"
|
||||
|
||||
#: plugins/display/browsers.py:98
|
||||
#: plugins/display/browsers.py:128
|
||||
#: plugins/display/referers.py:110
|
||||
#: plugins/display/referers.py:125
|
||||
#: plugins/display/referers.py:140
|
||||
#: plugins/display/referers.py:163
|
||||
#: plugins/display/referers.py:174
|
||||
#: plugins/display/referers.py:185
|
||||
#: plugins/display/referers.py:222
|
||||
#: plugins/display/top_downloads.py:83
|
||||
#: plugins/display/top_downloads.py:103
|
||||
#: plugins/display/top_hits.py:82
|
||||
#: plugins/display/top_hits.py:103
|
||||
#: plugins/display/top_pages.py:82
|
||||
#: plugins/display/top_pages.py:102
|
||||
#: plugins/display/browsers.py:99 plugins/display/browsers.py:130
|
||||
#: plugins/display/filter_users.py:123 plugins/display/referers.py:110
|
||||
#: plugins/display/referers.py:125 plugins/display/referers.py:140
|
||||
#: plugins/display/referers.py:163 plugins/display/referers.py:174
|
||||
#: plugins/display/referers.py:185 plugins/display/referers.py:222
|
||||
#: plugins/display/top_downloads.py:83 plugins/display/top_downloads.py:103
|
||||
#: plugins/display/top_hits.py:82 plugins/display/top_hits.py:103
|
||||
#: plugins/display/top_pages.py:82 plugins/display/top_pages.py:102
|
||||
#: plugins/display/top_visitors.py:92
|
||||
msgid "Others"
|
||||
msgstr "Autres"
|
||||
|
||||
#: plugins/display/browsers.py:105
|
||||
#: plugins/display/browsers.py:106
|
||||
msgid "Top Browsers"
|
||||
msgstr "Top Navigateurs"
|
||||
|
||||
#: plugins/display/browsers.py:107
|
||||
#: plugins/display/browsers.py:108
|
||||
msgid "All Browsers"
|
||||
msgstr "Tous les navigateurs"
|
||||
|
||||
#: plugins/display/browsers.py:123
|
||||
#: plugins/display/browsers.py:125 plugins/display/filter_users.py:80
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnu"
|
||||
|
||||
|
@ -309,18 +271,30 @@ msgstr "Tous les agrégateurs"
|
|||
msgid "All feeds parsers"
|
||||
msgstr "Tous les agrégateurs"
|
||||
|
||||
#: plugins/display/feeds.py:92
|
||||
#: plugins/display/feeds.py:94
|
||||
msgid "Merged feeds parsers"
|
||||
msgstr "Agrégateurs fusionnés"
|
||||
|
||||
#: plugins/display/feeds.py:97
|
||||
#: plugins/display/feeds.py:99
|
||||
msgid "Feeds parsers"
|
||||
msgstr "Agrégateurs"
|
||||
|
||||
#: plugins/display/feeds.py:104
|
||||
#: plugins/display/feeds.py:106
|
||||
msgid "Found"
|
||||
msgstr "Trouvé"
|
||||
|
||||
#: plugins/display/filter_users.py:77
|
||||
msgid "User Agent"
|
||||
msgstr "Navigateur"
|
||||
|
||||
#: plugins/display/filter_users.py:77 plugins/display/filter_users.py:106
|
||||
msgid "Filtered users"
|
||||
msgstr "Utilisateurs filtrés"
|
||||
|
||||
#: plugins/display/filter_users.py:77 plugins/display/filter_users.py:113
|
||||
msgid "Last Access"
|
||||
msgstr "Dernière visite"
|
||||
|
||||
#: plugins/display/hours_stats.py:72
|
||||
msgid "Fri"
|
||||
msgstr "Jeu"
|
||||
|
@ -361,8 +335,7 @@ msgstr "Heures"
|
|||
msgid "Country"
|
||||
msgstr "Pays"
|
||||
|
||||
#: plugins/display/ip_to_geo.py:96
|
||||
#: plugins/display/ip_to_geo.py:107
|
||||
#: plugins/display/ip_to_geo.py:96 plugins/display/ip_to_geo.py:107
|
||||
#: plugins/display/ip_to_geo.py:114
|
||||
msgid "Countries"
|
||||
msgstr "Pays"
|
||||
|
@ -381,23 +354,19 @@ msgstr "Système d'exploitation"
|
|||
msgid "Connexion from"
|
||||
msgstr "Connexion depuis"
|
||||
|
||||
#: plugins/display/referers.py:95
|
||||
#: plugins/display/referers.py:153
|
||||
#: plugins/display/referers.py:95 plugins/display/referers.py:153
|
||||
msgid "Origin"
|
||||
msgstr "Origine"
|
||||
|
||||
#: plugins/display/referers.py:99
|
||||
#: plugins/display/referers.py:156
|
||||
#: plugins/display/referers.py:99 plugins/display/referers.py:156
|
||||
msgid "Search Engine"
|
||||
msgstr "Moteur de recherche"
|
||||
|
||||
#: plugins/display/referers.py:114
|
||||
#: plugins/display/referers.py:167
|
||||
#: plugins/display/referers.py:114 plugins/display/referers.py:167
|
||||
msgid "External URL"
|
||||
msgstr "URL externe"
|
||||
|
||||
#: plugins/display/referers.py:129
|
||||
#: plugins/display/referers.py:178
|
||||
#: plugins/display/referers.py:129 plugins/display/referers.py:178
|
||||
msgid "External URL (robot)"
|
||||
msgstr "URL externe (robot)"
|
||||
|
||||
|
@ -413,18 +382,15 @@ msgstr "Toutes les origines"
|
|||
msgid "All Key Phrases"
|
||||
msgstr "Toutes les phrases clé"
|
||||
|
||||
#: plugins/display/referers.py:200
|
||||
#: plugins/display/referers.py:216
|
||||
#: plugins/display/referers.py:200 plugins/display/referers.py:216
|
||||
msgid "Key phrase"
|
||||
msgstr "Phrase clé"
|
||||
|
||||
#: plugins/display/referers.py:200
|
||||
#: plugins/display/referers.py:216
|
||||
#: plugins/display/referers.py:200 plugins/display/referers.py:216
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: plugins/display/referers.py:200
|
||||
#: plugins/display/referers_diff.py:56
|
||||
#: plugins/display/referers.py:200 plugins/display/referers_diff.py:56
|
||||
msgid "Key phrases"
|
||||
msgstr "Phrases clé"
|
||||
|
||||
|
@ -436,22 +402,26 @@ msgstr "Top phrases clé"
|
|||
msgid "All key phrases"
|
||||
msgstr "Toutes les phrases clé"
|
||||
|
||||
#: plugins/display/robot_bandwidth.py:99
|
||||
msgid "Robots bandwidth"
|
||||
msgstr "Bande passante robots"
|
||||
|
||||
#: plugins/display/robot_bandwidth.py:101
|
||||
msgid "All robots bandwidth"
|
||||
msgstr "Bande passante tous les robots"
|
||||
|
||||
#: plugins/display/top_downloads.py:71
|
||||
msgid "Hit"
|
||||
msgstr "Hit"
|
||||
|
||||
#: plugins/display/top_downloads.py:71
|
||||
#: plugins/display/top_downloads.py:91
|
||||
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:91
|
||||
#: plugins/display/top_downloads_diff.py:56
|
||||
msgid "All Downloads"
|
||||
msgstr "Tous les téléchargements"
|
||||
|
||||
#: plugins/display/top_downloads.py:71
|
||||
#: plugins/display/top_downloads.py:97
|
||||
#: plugins/display/top_hits.py:71
|
||||
#: plugins/display/top_hits.py:97
|
||||
#: plugins/display/top_pages.py:71
|
||||
#: plugins/display/top_pages.py:96
|
||||
#: plugins/display/top_downloads.py:71 plugins/display/top_downloads.py:97
|
||||
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:97
|
||||
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:96
|
||||
msgid "URI"
|
||||
msgstr "URI"
|
||||
|
||||
|
@ -459,13 +429,12 @@ msgstr "URI"
|
|||
msgid "Top Downloads"
|
||||
msgstr "Top Téléchargements"
|
||||
|
||||
#: plugins/display/top_hits.py:71
|
||||
#: plugins/display/top_hits.py:91
|
||||
#: plugins/display/top_hits.py:71 plugins/display/top_hits.py:91
|
||||
msgid "All Hits"
|
||||
msgstr "Tous les hits"
|
||||
|
||||
#: plugins/display/top_pages.py:71
|
||||
#: plugins/display/top_pages.py:90
|
||||
#: plugins/display/top_pages.py:71 plugins/display/top_pages.py:90
|
||||
#: plugins/display/top_pages_diff.py:56
|
||||
msgid "All Pages"
|
||||
msgstr "Toutes les pages"
|
||||
|
||||
|
@ -473,16 +442,6 @@ msgstr "Toutes les pages"
|
|||
msgid "Top Pages"
|
||||
msgstr "Top Pages"
|
||||
|
||||
#: plugins/display/track_users.py:77
|
||||
#: plugins/display/track_users.py:106
|
||||
msgid "Tracked users"
|
||||
msgstr "Utilisateurs traqués"
|
||||
|
||||
#: plugins/display/track_users.py:77
|
||||
#: plugins/display/track_users.py:113
|
||||
msgid "Last Access"
|
||||
msgstr "Dernière visite"
|
||||
|
||||
#~ msgid "IP"
|
||||
#~ msgstr "IP"
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
pygettext -a -d iwla -o iwla.pot -k gettext *.py plugins/pre_analysis/*.py plugins/post_analysis/*.py plugins/display/*.py
|
||||
./tools/pygettext.py -a -d iwla -o iwla.pot -k gettext *.py plugins/pre_analysis/*.py plugins/post_analysis/*.py plugins/display/*.py
|
||||
# Synchronize with new generated iwla.pot at root
|
||||
find locales -name '*.po' -exec poedit \{\} \;
|
||||
|
|
684
tools/pygettext.py
Executable file
684
tools/pygettext.py
Executable file
|
@ -0,0 +1,684 @@
|
|||
#! /usr/bin/env python3
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
# Originally written by Barry Warsaw <barry@python.org>
|
||||
#
|
||||
# Minimally patched to make it even more xgettext compatible
|
||||
# by Peter Funk <pf@artcom-gmbh.de>
|
||||
#
|
||||
# 2002-11-22 Jürgen Hermann <jh@web.de>
|
||||
# Added checks that _() only contains string literals, and
|
||||
# command line args are resolved to module lists, i.e. you
|
||||
# can now pass a filename, a module or package name, or a
|
||||
# directory (including globbing chars, important for Win32).
|
||||
# Made docstring fit in 80 chars wide displays using pydoc.
|
||||
#
|
||||
|
||||
# for selftesting
|
||||
try:
|
||||
import fintl
|
||||
_ = fintl.gettext
|
||||
except ImportError:
|
||||
_ = lambda s: s
|
||||
|
||||
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
|
||||
|
||||
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
|
||||
internationalization of C programs. Most of these tools are independent of
|
||||
the programming language and can be used from within Python programs.
|
||||
Martin von Loewis' work[1] helps considerably in this regard.
|
||||
|
||||
There's one problem though; xgettext is the program that scans source code
|
||||
looking for message strings, but it groks only C (or C++). Python
|
||||
introduces a few wrinkles, such as dual quoting characters, triple quoted
|
||||
strings, and raw strings. xgettext understands none of this.
|
||||
|
||||
Enter pygettext, which uses Python's standard tokenize module to scan
|
||||
Python source code, generating .pot files identical to what GNU xgettext[2]
|
||||
generates for C and C++ code. From there, the standard GNU tools can be
|
||||
used.
|
||||
|
||||
A word about marking Python strings as candidates for translation. GNU
|
||||
xgettext recognizes the following keywords: gettext, dgettext, dcgettext,
|
||||
and gettext_noop. But those can be a lot of text to include all over your
|
||||
code. C and C++ have a trick: they use the C preprocessor. Most
|
||||
internationalized C source includes a #define for gettext() to _() so that
|
||||
what has to be written in the source is much less. Thus these are both
|
||||
translatable strings:
|
||||
|
||||
gettext("Translatable String")
|
||||
_("Translatable String")
|
||||
|
||||
Python of course has no preprocessor so this doesn't work so well. Thus,
|
||||
pygettext searches only for _() by default, but see the -k/--keyword flag
|
||||
below for how to augment this.
|
||||
|
||||
[1] https://www.python.org/workshops/1997-10/proceedings/loewis.html
|
||||
[2] https://www.gnu.org/software/gettext/gettext.html
|
||||
|
||||
NOTE: pygettext attempts to be option and feature compatible with GNU
|
||||
xgettext where ever possible. However some options are still missing or are
|
||||
not fully implemented. Also, xgettext's use of command line switches with
|
||||
option arguments is broken, and in these cases, pygettext just defines
|
||||
additional switches.
|
||||
|
||||
Usage: pygettext [options] inputfile ...
|
||||
|
||||
Options:
|
||||
|
||||
-a
|
||||
--extract-all
|
||||
Extract all strings.
|
||||
|
||||
-d name
|
||||
--default-domain=name
|
||||
Rename the default output file from messages.pot to name.pot.
|
||||
|
||||
-E
|
||||
--escape
|
||||
Replace non-ASCII characters with octal escape sequences.
|
||||
|
||||
-D
|
||||
--docstrings
|
||||
Extract module, class, method, and function docstrings. These do
|
||||
not need to be wrapped in _() markers, and in fact cannot be for
|
||||
Python to consider them docstrings. (See also the -X option).
|
||||
|
||||
-h
|
||||
--help
|
||||
Print this help message and exit.
|
||||
|
||||
-k word
|
||||
--keyword=word
|
||||
Keywords to look for in addition to the default set, which are:
|
||||
%(DEFAULTKEYWORDS)s
|
||||
|
||||
You can have multiple -k flags on the command line.
|
||||
|
||||
-K
|
||||
--no-default-keywords
|
||||
Disable the default set of keywords (see above). Any keywords
|
||||
explicitly added with the -k/--keyword option are still recognized.
|
||||
|
||||
--no-location
|
||||
Do not write filename/lineno location comments.
|
||||
|
||||
-n
|
||||
--add-location
|
||||
Write filename/lineno location comments indicating where each
|
||||
extracted string is found in the source. These lines appear before
|
||||
each msgid. The style of comments is controlled by the -S/--style
|
||||
option. This is the default.
|
||||
|
||||
-o filename
|
||||
--output=filename
|
||||
Rename the default output file from messages.pot to filename. If
|
||||
filename is `-' then the output is sent to standard out.
|
||||
|
||||
-p dir
|
||||
--output-dir=dir
|
||||
Output files will be placed in directory dir.
|
||||
|
||||
-S stylename
|
||||
--style stylename
|
||||
Specify which style to use for location comments. Two styles are
|
||||
supported:
|
||||
|
||||
Solaris # File: filename, line: line-number
|
||||
GNU #: filename:line
|
||||
|
||||
The style name is case insensitive. GNU style is the default.
|
||||
|
||||
-v
|
||||
--verbose
|
||||
Print the names of the files being processed.
|
||||
|
||||
-V
|
||||
--version
|
||||
Print the version of pygettext and exit.
|
||||
|
||||
-w columns
|
||||
--width=columns
|
||||
Set width of output to columns.
|
||||
|
||||
-x filename
|
||||
--exclude-file=filename
|
||||
Specify a file that contains a list of strings that are not be
|
||||
extracted from the input files. Each string to be excluded must
|
||||
appear on a line by itself in the file.
|
||||
|
||||
-X filename
|
||||
--no-docstrings=filename
|
||||
Specify a file that contains a list of files (one per line) that
|
||||
should not have their docstrings extracted. This is only useful in
|
||||
conjunction with the -D option above.
|
||||
|
||||
If `inputfile' is -, standard input is read.
|
||||
""")
|
||||
|
||||
import os
|
||||
import importlib.machinery
|
||||
import importlib.util
|
||||
import sys
|
||||
import glob
|
||||
import time
|
||||
import getopt
|
||||
import ast
|
||||
import token
|
||||
import tokenize
|
||||
|
||||
__version__ = '1.5'
|
||||
|
||||
default_keywords = ['_']
|
||||
DEFAULTKEYWORDS = ', '.join(default_keywords)
|
||||
|
||||
EMPTYSTRING = ''
|
||||
|
||||
|
||||
|
||||
# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's
|
||||
# there.
|
||||
pot_header = _('''\
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR ORGANIZATION
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\\n"
|
||||
"POT-Creation-Date: %(time)s\\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\\n"
|
||||
"MIME-Version: 1.0\\n"
|
||||
"Content-Type: text/plain; charset=%(charset)s\\n"
|
||||
"Content-Transfer-Encoding: %(encoding)s\\n"
|
||||
"Generated-By: pygettext.py %(version)s\\n"
|
||||
|
||||
''')
|
||||
|
||||
|
||||
def usage(code, msg=''):
|
||||
print(__doc__ % globals(), file=sys.stderr)
|
||||
if msg:
|
||||
print(msg, file=sys.stderr)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
|
||||
def make_escapes(pass_nonascii):
|
||||
global escapes, escape
|
||||
if pass_nonascii:
|
||||
# Allow non-ascii characters to pass through so that e.g. 'msgid
|
||||
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
|
||||
# escape any character outside the 32..126 range.
|
||||
mod = 128
|
||||
escape = escape_ascii
|
||||
else:
|
||||
mod = 256
|
||||
escape = escape_nonascii
|
||||
escapes = [r"\%03o" % i for i in range(mod)]
|
||||
for i in range(32, 127):
|
||||
escapes[i] = chr(i)
|
||||
escapes[ord('\\')] = r'\\'
|
||||
escapes[ord('\t')] = r'\t'
|
||||
escapes[ord('\r')] = r'\r'
|
||||
escapes[ord('\n')] = r'\n'
|
||||
escapes[ord('\"')] = r'\"'
|
||||
|
||||
|
||||
def escape_ascii(s, encoding):
|
||||
return ''.join(escapes[ord(c)] if ord(c) < 128 else c for c in s)
|
||||
|
||||
def escape_nonascii(s, encoding):
|
||||
return ''.join(escapes[b] for b in s.encode(encoding))
|
||||
|
||||
|
||||
def is_literal_string(s):
|
||||
return s[0] in '\'"' or (s[0] in 'rRuU' and s[1] in '\'"')
|
||||
|
||||
|
||||
def safe_eval(s):
|
||||
# unwrap quotes, safely
|
||||
return eval(s, {'__builtins__':{}}, {})
|
||||
|
||||
|
||||
def normalize(s, encoding):
|
||||
# This converts the various Python string types into a format that is
|
||||
# appropriate for .po files, namely much closer to C style.
|
||||
lines = s.split('\n')
|
||||
if len(lines) == 1:
|
||||
s = '"' + escape(s, encoding) + '"'
|
||||
else:
|
||||
if not lines[-1]:
|
||||
del lines[-1]
|
||||
lines[-1] = lines[-1] + '\n'
|
||||
for i in range(len(lines)):
|
||||
lines[i] = escape(lines[i], encoding)
|
||||
lineterm = '\\n"\n"'
|
||||
s = '""\n"' + lineterm.join(lines) + '"'
|
||||
return s
|
||||
|
||||
|
||||
def containsAny(str, set):
|
||||
"""Check whether 'str' contains ANY of the chars in 'set'"""
|
||||
return 1 in [c in str for c in set]
|
||||
|
||||
|
||||
def getFilesForName(name):
|
||||
"""Get a list of module files for a filename, a module or package name,
|
||||
or a directory.
|
||||
"""
|
||||
if not os.path.exists(name):
|
||||
# check for glob chars
|
||||
if containsAny(name, "*?[]"):
|
||||
files = glob.glob(name)
|
||||
list = []
|
||||
for file in files:
|
||||
list.extend(getFilesForName(file))
|
||||
return list
|
||||
|
||||
# try to find module or package
|
||||
try:
|
||||
spec = importlib.util.find_spec(name)
|
||||
name = spec.origin
|
||||
except ImportError:
|
||||
name = None
|
||||
if not name:
|
||||
return []
|
||||
|
||||
if os.path.isdir(name):
|
||||
# find all python files in directory
|
||||
list = []
|
||||
# get extension for python source files
|
||||
_py_ext = importlib.machinery.SOURCE_SUFFIXES[0]
|
||||
for root, dirs, files in os.walk(name):
|
||||
# don't recurse into CVS directories
|
||||
if 'CVS' in dirs:
|
||||
dirs.remove('CVS')
|
||||
# add all *.py files to list
|
||||
list.extend(
|
||||
[os.path.join(root, file) for file in files
|
||||
if os.path.splitext(file)[1] == _py_ext]
|
||||
)
|
||||
return list
|
||||
elif os.path.exists(name):
|
||||
# a single file
|
||||
return [name]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class TokenEater:
|
||||
def __init__(self, options):
|
||||
self.__options = options
|
||||
self.__messages = {}
|
||||
self.__state = self.__waiting
|
||||
self.__data = []
|
||||
self.__lineno = -1
|
||||
self.__freshmodule = 1
|
||||
self.__curfile = None
|
||||
self.__enclosurecount = 0
|
||||
|
||||
def __call__(self, ttype, tstring, stup, etup, line):
|
||||
# dispatch
|
||||
## import token
|
||||
## print('ttype:', token.tok_name[ttype], 'tstring:', tstring,
|
||||
## file=sys.stderr)
|
||||
self.__state(ttype, tstring, stup[0])
|
||||
|
||||
def __waiting(self, ttype, tstring, lineno):
|
||||
opts = self.__options
|
||||
# Do docstring extractions, if enabled
|
||||
if opts.docstrings and not opts.nodocstrings.get(self.__curfile):
|
||||
# module docstring?
|
||||
if self.__freshmodule:
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__freshmodule = 0
|
||||
return
|
||||
if ttype in (tokenize.COMMENT, tokenize.NL, tokenize.ENCODING):
|
||||
return
|
||||
self.__freshmodule = 0
|
||||
# class or func/method docstring?
|
||||
if ttype == tokenize.NAME and tstring in ('class', 'def'):
|
||||
self.__state = self.__suiteseen
|
||||
return
|
||||
if ttype == tokenize.NAME and tstring in opts.keywords:
|
||||
self.__state = self.__keywordseen
|
||||
return
|
||||
if ttype == tokenize.STRING:
|
||||
maybe_fstring = ast.parse(tstring, mode='eval').body
|
||||
if not isinstance(maybe_fstring, ast.JoinedStr):
|
||||
return
|
||||
for value in filter(lambda node: isinstance(node, ast.FormattedValue),
|
||||
maybe_fstring.values):
|
||||
for call in filter(lambda node: isinstance(node, ast.Call),
|
||||
ast.walk(value)):
|
||||
func = call.func
|
||||
if isinstance(func, ast.Name):
|
||||
func_name = func.id
|
||||
elif isinstance(func, ast.Attribute):
|
||||
func_name = func.attr
|
||||
else:
|
||||
continue
|
||||
|
||||
if func_name not in opts.keywords:
|
||||
continue
|
||||
if len(call.args) != 1:
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected amount of'
|
||||
' positional arguments in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
if call.keywords:
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected keyword arguments'
|
||||
' in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
arg = call.args[0]
|
||||
if not isinstance(arg, ast.Constant):
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected argument type'
|
||||
' in gettext call: %(source_segment)s'
|
||||
) % {
|
||||
'source_segment': ast.get_source_segment(tstring, call) or tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': lineno
|
||||
}, file=sys.stderr)
|
||||
continue
|
||||
if isinstance(arg.value, str):
|
||||
self.__addentry(arg.value, lineno)
|
||||
|
||||
def __suiteseen(self, ttype, tstring, lineno):
|
||||
# skip over any enclosure pairs until we see the colon
|
||||
if ttype == tokenize.OP:
|
||||
if tstring == ':' and self.__enclosurecount == 0:
|
||||
# we see a colon and we're not in an enclosure: end of def
|
||||
self.__state = self.__suitedocstring
|
||||
elif tstring in '([{':
|
||||
self.__enclosurecount += 1
|
||||
elif tstring in ')]}':
|
||||
self.__enclosurecount -= 1
|
||||
|
||||
def __suitedocstring(self, ttype, tstring, lineno):
|
||||
# ignore any intervening noise
|
||||
if ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__addentry(safe_eval(tstring), lineno, isdocstring=1)
|
||||
self.__state = self.__waiting
|
||||
elif ttype not in (tokenize.NEWLINE, tokenize.INDENT,
|
||||
tokenize.COMMENT):
|
||||
# there was no class docstring
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __keywordseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == '(':
|
||||
self.__data = []
|
||||
self.__lineno = lineno
|
||||
self.__state = self.__openseen
|
||||
else:
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __openseen(self, ttype, tstring, lineno):
|
||||
if ttype == tokenize.OP and tstring == ')':
|
||||
# We've seen the last of the translatable strings. Record the
|
||||
# line number of the first line of the strings and update the list
|
||||
# of messages seen. Reset state for the next batch. If there
|
||||
# were no strings inside _(), then just ignore this entry.
|
||||
if self.__data:
|
||||
self.__addentry(EMPTYSTRING.join(self.__data))
|
||||
self.__state = self.__waiting
|
||||
elif ttype == tokenize.STRING and is_literal_string(tstring):
|
||||
self.__data.append(safe_eval(tstring))
|
||||
elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT,
|
||||
token.NEWLINE, tokenize.NL]:
|
||||
# warn if we see anything else than STRING or whitespace
|
||||
print(_(
|
||||
'*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"'
|
||||
) % {
|
||||
'token': tstring,
|
||||
'file': self.__curfile,
|
||||
'lineno': self.__lineno
|
||||
}, file=sys.stderr)
|
||||
self.__state = self.__waiting
|
||||
|
||||
def __addentry(self, msg, lineno=None, isdocstring=0):
|
||||
if lineno is None:
|
||||
lineno = self.__lineno
|
||||
if not msg in self.__options.toexclude:
|
||||
entry = (self.__curfile, lineno)
|
||||
self.__messages.setdefault(msg, {})[entry] = isdocstring
|
||||
|
||||
def set_filename(self, filename):
|
||||
self.__curfile = filename
|
||||
self.__freshmodule = 1
|
||||
|
||||
def write(self, fp):
|
||||
options = self.__options
|
||||
timestamp = time.strftime('%Y-%m-%d %H:%M%z')
|
||||
encoding = fp.encoding if fp.encoding else 'UTF-8'
|
||||
print(pot_header % {'time': timestamp, 'version': __version__,
|
||||
'charset': encoding,
|
||||
'encoding': '8bit'}, file=fp)
|
||||
# Sort the entries. First sort each particular entry's keys, then
|
||||
# sort all the entries by their first item.
|
||||
reverse = {}
|
||||
for k, v in self.__messages.items():
|
||||
keys = sorted(v.keys())
|
||||
reverse.setdefault(tuple(keys), []).append((k, v))
|
||||
rkeys = sorted(reverse.keys())
|
||||
for rkey in rkeys:
|
||||
rentries = reverse[rkey]
|
||||
rentries.sort()
|
||||
for k, v in rentries:
|
||||
# If the entry was gleaned out of a docstring, then add a
|
||||
# comment stating so. This is to aid translators who may wish
|
||||
# to skip translating some unimportant docstrings.
|
||||
isdocstring = any(v.values())
|
||||
# k is the message string, v is a dictionary-set of (filename,
|
||||
# lineno) tuples. We want to sort the entries in v first by
|
||||
# file name and then by line number.
|
||||
v = sorted(v.keys())
|
||||
if not options.writelocations:
|
||||
pass
|
||||
# location comments are different b/w Solaris and GNU:
|
||||
elif options.locationstyle == options.SOLARIS:
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
print(_(
|
||||
'# File: %(filename)s, line: %(lineno)d') % d, file=fp)
|
||||
elif options.locationstyle == options.GNU:
|
||||
# fit as many locations on one line, as long as the
|
||||
# resulting line length doesn't exceed 'options.width'
|
||||
locline = '#:'
|
||||
for filename, lineno in v:
|
||||
d = {'filename': filename, 'lineno': lineno}
|
||||
s = _(' %(filename)s:%(lineno)d') % d
|
||||
if len(locline) + len(s) <= options.width:
|
||||
locline = locline + s
|
||||
else:
|
||||
print(locline, file=fp)
|
||||
locline = "#:" + s
|
||||
if len(locline) > 2:
|
||||
print(locline, file=fp)
|
||||
if isdocstring:
|
||||
print('#, docstring', file=fp)
|
||||
print('msgid', normalize(k, encoding), file=fp)
|
||||
print('msgstr ""\n', file=fp)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
global default_keywords
|
||||
try:
|
||||
opts, args = getopt.getopt(
|
||||
sys.argv[1:],
|
||||
'ad:DEhk:Kno:p:S:Vvw:x:X:',
|
||||
['extract-all', 'default-domain=', 'escape', 'help',
|
||||
'keyword=', 'no-default-keywords',
|
||||
'add-location', 'no-location', 'output=', 'output-dir=',
|
||||
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
|
||||
'docstrings', 'no-docstrings',
|
||||
])
|
||||
except getopt.error as msg:
|
||||
usage(1, msg)
|
||||
|
||||
# for holding option values
|
||||
class Options:
|
||||
# constants
|
||||
GNU = 1
|
||||
SOLARIS = 2
|
||||
# defaults
|
||||
extractall = 0 # FIXME: currently this option has no effect at all.
|
||||
escape = 0
|
||||
keywords = []
|
||||
outpath = ''
|
||||
outfile = 'messages.pot'
|
||||
writelocations = 1
|
||||
locationstyle = GNU
|
||||
verbose = 0
|
||||
width = 78
|
||||
excludefilename = ''
|
||||
docstrings = 0
|
||||
nodocstrings = {}
|
||||
|
||||
options = Options()
|
||||
locations = {'gnu' : options.GNU,
|
||||
'solaris' : options.SOLARIS,
|
||||
}
|
||||
|
||||
# parse options
|
||||
for opt, arg in opts:
|
||||
if opt in ('-h', '--help'):
|
||||
usage(0)
|
||||
elif opt in ('-a', '--extract-all'):
|
||||
options.extractall = 1
|
||||
elif opt in ('-d', '--default-domain'):
|
||||
options.outfile = arg + '.pot'
|
||||
elif opt in ('-E', '--escape'):
|
||||
options.escape = 1
|
||||
elif opt in ('-D', '--docstrings'):
|
||||
options.docstrings = 1
|
||||
elif opt in ('-k', '--keyword'):
|
||||
options.keywords.append(arg)
|
||||
elif opt in ('-K', '--no-default-keywords'):
|
||||
default_keywords = []
|
||||
elif opt in ('-n', '--add-location'):
|
||||
options.writelocations = 1
|
||||
elif opt in ('--no-location',):
|
||||
options.writelocations = 0
|
||||
elif opt in ('-S', '--style'):
|
||||
options.locationstyle = locations.get(arg.lower())
|
||||
if options.locationstyle is None:
|
||||
usage(1, _('Invalid value for --style: %s') % arg)
|
||||
elif opt in ('-o', '--output'):
|
||||
options.outfile = arg
|
||||
elif opt in ('-p', '--output-dir'):
|
||||
options.outpath = arg
|
||||
elif opt in ('-v', '--verbose'):
|
||||
options.verbose = 1
|
||||
elif opt in ('-V', '--version'):
|
||||
print(_('pygettext.py (xgettext for Python) %s') % __version__)
|
||||
sys.exit(0)
|
||||
elif opt in ('-w', '--width'):
|
||||
try:
|
||||
options.width = int(arg)
|
||||
except ValueError:
|
||||
usage(1, _('--width argument must be an integer: %s') % arg)
|
||||
elif opt in ('-x', '--exclude-file'):
|
||||
options.excludefilename = arg
|
||||
elif opt in ('-X', '--no-docstrings'):
|
||||
fp = open(arg)
|
||||
try:
|
||||
while 1:
|
||||
line = fp.readline()
|
||||
if not line:
|
||||
break
|
||||
options.nodocstrings[line[:-1]] = 1
|
||||
finally:
|
||||
fp.close()
|
||||
|
||||
# calculate escapes
|
||||
make_escapes(not options.escape)
|
||||
|
||||
# calculate all keywords
|
||||
options.keywords.extend(default_keywords)
|
||||
|
||||
# initialize list of strings to exclude
|
||||
if options.excludefilename:
|
||||
try:
|
||||
with open(options.excludefilename) as fp:
|
||||
options.toexclude = fp.readlines()
|
||||
except IOError:
|
||||
print(_(
|
||||
"Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
else:
|
||||
options.toexclude = []
|
||||
|
||||
# resolve args to module lists
|
||||
expanded = []
|
||||
for arg in args:
|
||||
if arg == '-':
|
||||
expanded.append(arg)
|
||||
else:
|
||||
expanded.extend(getFilesForName(arg))
|
||||
args = expanded
|
||||
|
||||
# slurp through all the files
|
||||
eater = TokenEater(options)
|
||||
for filename in args:
|
||||
if filename == '-':
|
||||
if options.verbose:
|
||||
print(_('Reading standard input'))
|
||||
fp = sys.stdin.buffer
|
||||
closep = 0
|
||||
else:
|
||||
if options.verbose:
|
||||
print(_('Working on %s') % filename)
|
||||
fp = open(filename, 'rb')
|
||||
closep = 1
|
||||
try:
|
||||
eater.set_filename(filename)
|
||||
try:
|
||||
tokens = tokenize.tokenize(fp.readline)
|
||||
for _token in tokens:
|
||||
eater(*_token)
|
||||
except tokenize.TokenError as e:
|
||||
print('%s: %s, line %d, column %d' % (
|
||||
e.args[0], filename, e.args[1][0], e.args[1][1]),
|
||||
file=sys.stderr)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
# write the output
|
||||
if options.outfile == '-':
|
||||
fp = sys.stdout
|
||||
closep = 0
|
||||
else:
|
||||
if options.outpath:
|
||||
options.outfile = os.path.join(options.outpath, options.outfile)
|
||||
fp = open(options.outfile, 'w')
|
||||
closep = 1
|
||||
try:
|
||||
eater.write(fp)
|
||||
finally:
|
||||
if closep:
|
||||
fp.close()
|
||||
|
||||
|
||||
if __name__ == ' |