From 4c849ec351a0ea27b3b4bb43a54bf119f20dfe34 Mon Sep 17 00:00:00 2001 From: Griatch Date: Thu, 14 Jun 2012 02:43:35 +0200 Subject: [PATCH] Cleaned and updated the i18n strings for various server-core system. Removed i18n for all strings that are only visible on stdout or in logs. Still missing i18n on certain specific things such as model field help and attribute warnings. Updated Swedish translation to match. --- game/manage.py | 6 +- locale/sv/LC_MESSAGES/django.mo | Bin 8440 -> 7463 bytes locale/sv/LC_MESSAGES/django.po | 1019 +++++++-------------------- src/commands/cmdhandler.py | 16 +- src/commands/cmdparser.py | 12 +- src/commands/cmdset.py | 5 +- src/commands/cmdsethandler.py | 24 +- src/comms/admin.py | 34 +- src/comms/imc2.py | 179 ++--- src/comms/imc2lib/imc2_ansi.py | 18 +- src/comms/imc2lib/imc2_listeners.py | 4 +- src/comms/imc2lib/imc2_packets.py | 426 +++++------ src/comms/imc2lib/imc2_trackers.py | 20 +- src/comms/irc.py | 90 +-- src/comms/managers.py | 140 ++-- src/comms/rss.py | 80 +-- src/locks/lockhandler.py | 19 +- src/scripts/scripthandler.py | 9 +- src/scripts/scripts.py | 14 +- src/server/initial_setup.py | 30 +- src/server/models.py | 5 +- src/server/portal.py | 7 +- src/server/server.py | 8 +- src/server/ssh.py | 9 +- src/server/ssl.py | 22 +- src/utils/batchprocessors.py | 142 ++-- 26 files changed, 918 insertions(+), 1420 deletions(-) diff --git a/game/manage.py b/game/manage.py index fc6c87a3cf..5d115b722d 100755 --- a/game/manage.py +++ b/game/manage.py @@ -124,8 +124,6 @@ SECRET_KEY = '%s' # Test the import of the settings file #------------------------------------------------------------ try: - # i18n - from django.utils.translation import ugettext as _ from game import settings except Exception: import traceback @@ -157,11 +155,11 @@ if __name__ == "__main__": # checks if the settings file was created this run if _CREATED_SETTINGS: - print _(""" + print """ Edit your new settings.py file as needed, then run 'python manage syncdb' and follow the prompts to create the database and your superuser account. - """) + """ sys.exit() # run the standard django manager, if dependencies match diff --git a/locale/sv/LC_MESSAGES/django.mo b/locale/sv/LC_MESSAGES/django.mo index 7c07e2f8deece621a3383fd413b4601c2cee0a8d..8dd1ea2f92a004f807e35a0ee0358d2597a9c596 100644 GIT binary patch literal 7463 zcmb`LYit}>6~`}+QsVM{77FF2#dw!yC$>}i*d!&clQbrF5)vm+kf^SA?(R-@c4nD7 zW5-lH%0og3^#iC-(IUPiqKFS5K16~qNVO0`0>l>(;sXdI1QLP|AdnCU_?K zyzjbEsn>w71&@LOxCj>DtH5to?LP!x$osFs=Yf9!Uj+UUly(0J9su7!r~TlAAWNvn zz}vtl!QJ4u!PkSo1aAfZ4ju$=*`?Ggzz4xsgE9C@@S|V=ehw6Qz5~j*pMl50zk>7N z5jOWG@B%3FJPykGUj@&B-vAL&?Yc=RQO(Oi4Za4Had(5$;Jd&Zzz>2V@5jKmfR{ko z-}k{8a2K0j2Is&A_#sfnf4O@90VwkS1(b19D7ytd03wPiKtxv`0r!HR0uO=T0%hI5 zfiD5y$UoV~9`HE04-|cW7?ky%1ZDiw;2Xg|f-eJK_EM$Z4DJSH-$z0I)CvCG0=^H_ z;0HiNR8N4?|0(be@CTsu`zsiLuVzw_`!I;f)JYJksds~SgYN~?=P31A@C5JA!w9nO z=?dQizMS_p@O5Ag9t9r-kAXi1#lE+qG-=-l$~r5cta}dRPZ|Enz6WiSr`*m;tezSU?er@S50eCy#=RuL@9Eb?Yfj5Ak1V!FQ!3KC4d^`9H z@GkI82>VX(9JmL33Y3072JZp?0m^)LqdeK)GAMR?9KeGC-4eI7gpehC!){1z1XZiEyf&t8yEstdBTdIXgAFMwi)r$Jfwd!Y3D87Oh! z&!DVxGfEJ??E&|K?*wU5kAR~8FM=}uN1*8Emlgg7yqEXigV1e!X`W?xcTx#~-N;{ooQst>zC@dL3HuA&ZeV=}L! zmw+Ox>|1=S%`G|={qE7g0@`Ym?`u)7MKYi}MFs_Z?ZcNfMd1t{(JasX@$xWu$*MEs{`OG5GZ2 ze=?RSdsZ#>ZD-)u)uJK4p(rt(JX*K9$Btat#c5}qi_(OLRI`^&Z8FQ4bsMO~*qY4A zSG|y9kF_GVdXWt=e>xnRBrGM5oEP4#nc5T~@IntY8b1j`Yi`Z$%t>c{*h)#_`${m(iUgP{3HIr6m|D*RP85FN5mtv(S@^_7!*5)dSsm2NHc^fC62D#Pg|cz>#cQS zddo`wp(MqOW(c%R!y>jLllPmho@=LK+S*H%%;Y*6j?ygG<(N`os%B4Uag1IvU072*_N%N8<(8*`8h%Q{fylajbC@v8edA4e{||3Oi24W|Ilh zku1j^jRFOrpq8WITB?@Q&Oi)``_P!12p%UGA&ucqqur$6q(>i$4I?)+ zISdwiN;v3S9N?;M%wakmJmVn=Qo0e_Zr*ZHXm#4HW{324ILbG#UW36z(KmPsuJG1SvnN{xU|SR#Ge^40q?z30`-ipHWpfF8+ljpT97@u zO*C<#^tDY+T0qw%NG$xZs*D zCttT)awQE}O^>68$RHu74z${gMsd{f+z!;rrd}xZsZOK`LEPqnI+?_qdT|(@vANS7 zlX%*O&_m{&gK(Xc6QRSwMUOH{t=Tx;2%fRsF|qG(+P2Vgrwp)( z&4~*GZ#vFHA8-|Wgk57%81msor85P3Y$?=cvUl^Q-zB*$47Ne zH=31zFaSv*K%mZ8f)ac64i~u=lq0r}OlM&8os9!axRKUYX5U|MB#(O)p5)ykMt`P2 z4@oYXo+z$7naT|YYE>8^p`8E2BF>``u3GvNL|g4cEB?;n{rdK~$p?h=uA)b=>DYc6 zhjegW6@faN43cyssZnT@BZfLVBEH%3^r76Oh)ou62I^d7 zH#8wYLZEtAKSe6C88+$3J>5vNs23$oCmbF+(hT(=$v~J&$n6_ZBPmGa55{rmGs$M& z=kyAEU*BuZ5-BHvNe-$`K`b1~w38G^BpDxhWkdK-%JMVnd>SQadm8l-Ez0&eP ztrgdc!q)vo&$U+5w%*v-2yB_01f6s^b?W45YmqZj;!5i|L$7eR_Uh zdv5NI+4>aan^jkJAZ>?q~ak1g3XzK^ENW!o_&?_Gf z^@belviN;;PI?8KY^_=|Z0j={oIH-Mla{ugT3K2-GTGx?Fgvwa5~n43TwCWPxqIPT zl2h9g@aXk-B>F)lbWhAFbQE^HHy5qb%}&2kKnl^*OS~D za!YD$7^>6Z|1G~haK=bxhn;$GyQ1-blVq>h1le?0Xg1>p#B-ADGlMKzA1B#cm&vlv zZ(ZDxXD@GE?3Eiwk{?~p=~bl^osQRI3Y*M8twdU1}R5~@saWxsdUS0 zo89_g*NZr`{aBKB-H*uN1N98^T{AO(*6GyN$CEHK>H(XiL$`Ig%+p(tu_sL8Q+BEh zzfT$Gw<+A}q03$z^*BrECaJqrUvBSlOq9q|mvb$VA>%kk4icL%6#fPJsEx_z-5|5; z906q_PpWrzH1euv2GlE(B|YhXMT11zc(XH*xqJ@4b6gi8;xrq#9;ZgKrRhHC@31Ep|gVcnoe5-&~EjYO`l(5);AT4dm!fWjJ+)wMxn)G<3$+iL@}&bc8G z0^?0ca#eZIa_cbP8x3-wrkS(GYy3FZ=3ndyE5yBD|B6|o#nu*RRqrQ45-igOGhgreO6bp;RN z89pwO;TdLowhp_v)Yc~uL23&l@iymN8@TFZ*t%S$eDiXo8g?jYKA9Ci&ukNa)#x>H zyzA5&W?gCxp~$sM4WyRFaiKB5NsJE^;=rwKwT3S>b~fv4RU6W8DHNaa5o63+Y<(*Ph8Ho8Fyey<^YVS$oFVp4lvk;;rtw z-LC2CTfKFw>}inT1(EO&2_f;sB7`y{0uMY8GExLWf_?ym5JEx-ULph!yzmtv9wJ4+ z@7!C}-Q$@-BU;n`cX!=7_uO;-=d0$MAA0AnDqb)1{t@2q{Vt^r!S8%Ge|T-bOR2x& zw;k}e`To>i^fE-C(eZNva3hskq0t+HS<)GN-=fUp*-v&jmuYjV@ zpMW0%|FOFMU*Ju?e+PUwc=&zT0{k4f4895e6!?oErd59jHo$L!-w(d~1HoP&0Wpc% z0WqmM0$%~Y03urb1}OUcF8Fcq>mdKsKkx@p>RX`b|Bep^d%PdieD8qQz|U2`{|@+# zcPRC@;9uhJUq*?qbNvfA>o)l04=ME%;FrMz@b^FszUzmB9i9O<_`U@`1%45H4*X3} z?ETl^D)=wptKd^C`bqHfp#1(eD0caCP}cuDDE3(5i~N2OjKMd+4){mlHu!Du0{H4j zlv)Q%Q2g;*;49#tf~czAgY$kC)Zk~pw?XmuKZB^G{sR;{KY{bb{!fCkZvzzjUIRs+ z8=(08=fEETe;pJ#Ujv8WA6DNREE4{#gKhA6Q1}po;_p8IMc+RLMb3YM9|fO4dGXsS zDE@v46uVvlgXqb&To&``a^`$^v7hx#Qpk{9mt_LI+ISK;3C@`ab!3p#m!ej1d#@G;&i zyv26nzo&VBiua4W#cvWzV(*uEi~r>%{E%28JUpjxnfI;mS1m1RUR!yd4%MH1!nYZ=P ziOG$Qc$cn>(sZJWvrOkEa+!6ypXEqOTqj6aZ|XO)QjfAz6YEJ<=6YdUZBl2>L|j|% zhyqcedyzAKxlRh*je0|kK(7pE>ak0~-a1X}P#2l3>F3$V@5t6^Y*5gzzR(m!XS*RX zE;)7LwBL|BSDbd`c$_&jLsZwS>TZbw;ml4OF`#SLdmot7#GH966?xP%Ubm>r!Q}4T zxGa^A>^aV}ZfZuW@`Y1j%xHiWE5$B0^-f<*p$Dd@Hqn{IDK-{EZ+>Ru+STjFhg(NS zJJ+rr9`9Y>ys^9GZx|(mlR}?F>{DxnHFY`G@vX=XGJTe3NWhma8yS5TO|Wa&D=#f( zJ5BNem+4W|J4q}D#(qI)m*vpoq?Q|wR75a_HGFdh8BF5(#qk@Nm~}CHl$zNk8ey_U(3C z^r_qe*JYt_+uSB*q7dZhU->F3i)@6%o)73c&TP1ALF^zJndfRv+p@v!Xf!6U8iZtd zdv!tQY-}v&mv9*5(Wu!GeXbg7@>=t4eQ>xT+K;0o7mZnfn#Wt$HeTJ`+N=rW^#0^J z!nh#Z0_w`JKo#c+}SujxPJX;<~VaZafKtM1~$vRgpGKV*w)CzFkg7+F!4AE3FQGX zjn@hB>R6BvJTLH^1UDH;T73BCtesItsNzp6{28QK7ZbT& zo=60EC(Kq7s!^Ge6Hg**N!I5sXWd&=3#S|VX*3}qKDO?|WH%Xg$%t7tYK9wpDGD@~ zErYk}Ezyh|B_$&yLycFR*m<=MjEZyPvWrVa`T7SUjbDTd&ZPYr^^!bpjqx#sDa%qP z8~EBMd+*)&tUfU*8M6-TMr=+^3IY1mA=@+L;&f6ezL%ZKO`&vR*l=f8oZ&x8qz$B6 zt}G+Q+p6hS*svmAnmJ!kEM|gza$n#ZOAd@HA&;c%q)5aCrXZ91at52na5;?}`9Ri| z8i+9t!7!4lOaNUm1Kx zaeB>6_9ZZVA?%)3AV8$Okhe|jgi0&>xD zdJY>AjgV(9Ndmyvda~r@6GImuSuoJ-xyvUJ1-O84#bj)HSShp}-I8WTEjL2&tBt+= z&;)sFEH@I{&zkfl{v2u}j^)j_dO2Sr$`Q7y@tF`lVG#;l?_c(T2 z?M?KCk2j~TWpo-7Q?ylGYqMNBTu&#@YYa&j@aXHVUT|P~(x%js4~+D*D#YF8%=VK3 zy{nbJM{G{#(A8Cbe3}B}n(9bW9RF@W9#Umn-LONOomps)+ijt4N`Fa~5PGOLXb|H} z8h79CkrYRCT2&J99;bmKYl_dRLddPljciOx4Bb~R8`$J$q)z27BAEaGfxNre)wI=F zPR1e~Ngcbi-0Q7e?6%(ga3uN{41ZT&)P?Luq)(|UcabMceUuC1@Fv9Ki_xme_(>pt;( zShq_KZ5`#2b!miOI{GSYWOS?pQNuSs{GSTSqmZJ0C&feDi zaO>^0CHNp7Z5@%HI$Bz;=f)``z>88zDOSa$8%I}KFU;48e$=1VmhELS1$6Wa-K1FB zPs=F|TPK&@m;#=#4Ov9x#^;y>E5GJ-wN>fCjF>ul0+B6vyxK@v+cS(tay)I7q$ORKi z9gJ|Jm&SCtSrQ<*?xzz(5PS2XR@>>_0Wm>PV%>swTVL_Z$bxCwjfV9Zj8`X}-m(1T z1#4dZ6iL9 z)+%%9qP?xX!I;DnEERSgPVeP95hwW35koOaxuHy$h#f}a>!OzKZE(sS1&xZNL7Iz5 zqhVj9_@C&mIF0vqI=v@ns)l7ba9uu!`ScF;mn@c#qI4$S(@&&e4L?IBD9$RpEVfV5 zThn{>5SjZS5_M}kDz7AUg!zcuG(o2AgmHC&FR;-Y6#3J87O&>3S`6TCnK z$;oV@^lqHqOKs>jL}ZYi=bRMK!%nHOby zL)z5&L@BIi2tg?{9TQ`8cwTrtoy|-DFKJzGP4Ce55=+A{OJ)}Oi(~xuRS7w*Cn+x~ zmuak3?JSyB1LhFE$e?iFaM{XBiUMvM&XYwwRk|Su^va3AxfDX-+(5Z?+l6`&G|SP!d6;P#$E{n zBs|(Cz8`t4=`xB9-Pe4)#790D_?ZA;lk=k-{TQv9KbH4tJ!3-fHf`!`$ZSc*#KbaW z=CVu38V`u8N6i*VZD5)Y5z!SxRdT{32Z@%4i@Q$+9rENO_in3-J3^Rn?7W&X3Adq) znVvk=DpuGy%42d#Bu5io)dCnVAx`5ELdfGrCIpe``^hk%U4bdWHl8X9yL@hi;fMZl zKr3w4R+7qm$|2`bWL!aMTCMn4kCJ}26zTO3VYYM}(? z#?CNxlB|WpX(j}rnY7|&+G83vF9e#wCydP#Npv{C%`Em5V^y8mtN%rwmDc&I+Y*!f#2TIl1s1n6o6G?bDhhDwF`{>|@ z(*?PnY~ahOV&Er^HB}j)ltOYcOT@!P&L-h|%@TbX^jgaM@3< z(msT3f{Pz#H=adE;gU*(>8Q6-)-f<8Ns=~h>Ps#NfiLM<{17_7dZKGV1a{j46S{ z^Koqc=mqpcVZouX%uHrc{1MGL)7t&hu5^FCCrcw~z^Y8wlA(84R5S0U&%4rgR`odK zaU3y3PyTPA?v@elThP}%zaq66+IlZv%pggdCx5~dZWM+D^U56BR&`6`M}>(zI`d=j yLdeQ?97~I3X7li4r;+e%{JuOQ(?NLDFFB>|lEi(B)3LsUF7, YEAR. +# Griatch , 2012. # msgid "" msgstr "" -"Project-Id-Version: 0.1\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-02-19 10:36+0100\n" -"PO-Revision-Date: 2012-02-19 10:45+0100\n" +"Project-Id-Version: Evennia Beta\n" +"Report-Msgid-Bugs-To: www.evennia.com\n" +"POT-Creation-Date: 2012-06-13 23:11+0200\n" +"PO-Revision-Date: 2012-06-14 02:40+0100\n" "Last-Translator: Griatch \n" -"Language-Team: Griatch \n" +"Language-Team: Swedish <>\n" "Language: \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" -"X-Poedit-Language: Swedish\n" -"X-Poedit-Country: Sweden\n" -"X-Poedit-SourceCharset: utf-8\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: game/manage.py:116 +#: src/commands/cmdhandler.py:201 +#, python-format +msgid "Command '%s' is not available." +msgstr "Kommandot '%s' är inte tillgängligt." + +#: src/commands/cmdhandler.py:204 +#, python-format +msgid " Maybe you meant %s?" +msgstr "Menade du kanske %s?" + +#: src/commands/cmdhandler.py:204 +msgid "or" +msgstr "eller" + +#: src/commands/cmdhandler.py:206 +msgid " Type \"help\" for help." +msgstr "Skriv \"help\" för hjälp." + +#: src/commands/cmdhandler.py:212 +msgid "There where multiple matches." +msgstr "Det fanns många träffar." + +#: src/commands/cmdparser.py:144 +#, python-format +msgid "Could not find '%s'." +msgstr "Kunde inte hitta '%s'." + +#: src/commands/cmdparser.py:160 +msgid "location" +msgstr "plats" + +#: src/commands/cmdparser.py:161 +msgid " (carried)" +msgstr "(buren)" + +#: src/commands/cmdparser.py:240 +msgid " (channel)" +msgstr "(kanal)" + +#: src/commands/cmdparser.py:244 +#, python-format +msgid " (exit to %s)" +msgstr "(utgång till %s)" + +#: src/commands/cmdsethandler.py:115 +#, python-format +msgid "Error loading cmdset: Couldn't import module '%s'." +msgstr "Fel medan cmdset laddades: Kunde inte importera modulen '%s'." + +#: src/commands/cmdsethandler.py:119 +#, python-format +msgid "Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s." +msgstr "Fel medan cmdset laddades: Ingen cmdset-klass med namn '%(classname)s' i %(modulepath)s." + +#: src/commands/cmdsethandler.py:123 +#, python-format +msgid "Compile/Run error when loading cmdset '%s'. Error was logged." +msgstr "Kompilerings/Körningsfel när cmdset '%s' laddades. Felet skrevs i loggen." + +#: src/commands/cmdsethandler.py:199 +#, python-format +msgid "custom %(mergetype)s on cmdset '%(merged_on)s'" +msgstr "särskild %(mergetype)s på cmdset '%(merged_on)s'" + +#: src/commands/cmdsethandler.py:201 +#, python-format +msgid " : %(current)s" +msgstr ": %(current)s" + +#: src/commands/cmdsethandler.py:207 +#, python-format +msgid " <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s" +msgstr " <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s" + +#: src/commands/cmdsethandler.py:281 +#: src/commands/cmdsethandler.py:313 +msgid "Only CmdSets can be added to the cmdsethandler!" +msgstr "Bara CmdSets can läggas till cmdsethandler!" + +#: src/comms/imc2.py:66 +msgid "Send an IMC2 is-alive packet" +msgstr "Skicka ett IMC2-is-alive paket" + +#: src/comms/imc2.py:82 +msgid "Send an IMC2 keepalive-request packet" +msgstr "Skicka ett IMC2 keepalive-request paket" + +#: src/comms/imc2.py:99 +msgid "Check IMC2 list for inactive games" +msgstr "Genomsök IMC2-listan efter inaktiva spel" + +#: src/comms/imc2.py:120 +msgid "Re-sync IMC2 network channel list" +msgstr "Återsynca nätverkslistan över IMC2 kanaler" + +#: src/comms/imc2.py:204 +msgid "IMC2 server rejected connection." +msgstr "IMC2 server avvisade uppkopplingen." + +#: src/comms/imc2.py:213 +msgid "IMC2: Autosetup response found." +msgstr "IMC2: Autosetup-svar hittat." + +#: src/comms/imc2.py:220 +#, python-format +msgid "Successfully authenticated to the '%s' network." +msgstr "Identifierade sig framgångsrikt till nätverket '%s'." + +#: src/comms/imc2.py:260 +#, python-format +msgid "{c%(sender)s@%(origin)s{n {wpages (over IMC):{n %(msg)s" +msgstr "{c%(sender)s@%(origin)s{n {wskickar (over IMC):{n %(msg)s" + +#: src/comms/imc2.py:371 +#, python-format +msgid "Connection failed: %s" +msgstr "Uppkopplingen misslyckades: %s" + +#: src/comms/imc2.py:376 +#, python-format +msgid "Connection lost: %s" +msgstr "Uppkopplingen förlorades: %s" + +#: src/comms/imc2.py:413 +#, python-format +msgid "Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" +msgstr "Kan inte sammankoppla IMC2<->Evennia: Evennia-kanalen '%s' gick inte att hitta." + +#: src/comms/irc.py:51 +#, python-format +msgid "joined %s." +msgstr "lyssnar till %s." + +#: src/comms/irc.py:66 +msgid "Unknown" +msgstr "Okänd" + +#: src/comms/irc.py:97 +msgid "Connection closed." +msgstr "Uppkopplingen stängdes." + +#: src/comms/irc.py:99 +#, python-format +msgid "Lost connection %(key)s. Reason: '%(reason)s'. Reconnecting." +msgstr "Förlorade uppkopplingen %(key)s. Anledning: '%(reason)s'. Försöker igen." + +#: src/comms/irc.py:102 +#, python-format +msgid "Could not connect %(key)s Reason: '%(reason)s'" +msgstr "Kunde inte koppla upp %(key)s Reason: '%(reason)s'" + +#: src/comms/irc.py:122 +#, python-format +msgid "Cannot attach IRC<->Evennia: Evennia Channel '%s' not found" +msgstr "Kan inte sammankoppla IRC<->Evennia: Evennia-kanalen '%s' gick inte att hitta" + +#: src/comms/imc2lib/imc2_listeners.py:20 +#, python-format +msgid "Whois reply from %(origin)s: %(msg)s" +msgstr "Whois-svar från %(origin)s: %(msg)s" + +#: src/locks/lockhandler.py:221 +#, python-format +msgid "Lock: function '%s' is not available." +msgstr "Lås: funktionen '%s' kunde inte hittas." + +#: src/locks/lockhandler.py:234 +#, python-format +msgid "Lock: definition '%s' has syntax errors." +msgstr "Lås: definitionen '%s' har syntaktiska fel." + +#: src/locks/lockhandler.py:238 +#, python-format +msgid "Lock: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " +msgstr "Lås: låstypen '%(access_type)s' ändrade sig från '%(source)s' till '%(goal)s'" + +#: src/locks/lockhandler.py:272 +#, python-format +msgid "Lock: '%s' contains no colon (:)." +msgstr "Lås: '%s' innehåller inget kolon (:)." + +#: src/locks/lockhandler.py:276 +#, python-format +msgid "Lock: '%s' has no access_type (left-side of colon is empty)." +msgstr "Lås: '%s' saknar låstyp (ingenting till vänster om kolonet)." + +#: src/locks/lockhandler.py:279 +#, python-format +msgid "Lock: '%s' has mismatched parentheses." +msgstr "Lås: '%s' has ickematchande parenteser." + +#: src/locks/lockhandler.py:282 +#, python-format +msgid "Lock: '%s' has no valid lock functions." +msgstr "Lås: '%s' innehåller inga acceptabla låsfunktioner." + +#: src/scripts/scripthandler.py:43 #, python-format msgid "" "\n" -"\n" -" Error: Couldn't import the file 'settings.py' in the directory \n" -" containing %(file)r. There are usually two reasons for this: \n" -" 1) You moved your settings.py elsewhere. In that case move it back or \n" -" create a link to it from this folder. \n" -" 2) The settings module is where it's supposed to be, but contains errors.\n" -" Review the traceback above to resolve the problem, then try again. \n" -" 3) If you get errors on finding DJANGO_SETTINGS_MODULE you might have \n" -" set up django wrong in some way. If you run a virtual machine, it might be worth\n" -" to restart it to see if this resolves the issue. Evennia should not require you \n" -" to define any environment variables manually. \n" -" " +" '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s" msgstr "" "\n" -"\n" -" Fel: Kunde inte importera filen 'settings.py' från den hårddiskplats som\n" -" innehåller %(file)r. Detta beror vanligtvis på en av två anledningar: \n" -" 1) Du har flyttat settings.py någon annanstans. Flytta tillbaka filen eller länka \n" -" den hit.\n" -" 2) settings.py är där den ska vara men innehåller fel. Läs felmeddelandet ovan\n" -" och fixa till problemet. \n" -" 3) Om du ser ett felmeddelande som nämner DJANGO_SETTINGS_MODULE så \n" -" är django felkonfigurerat på något vis. Om du kör i en virtuell maskin så kan det\n" -" vara värt att starta om för att se om detta löser problemet. Evennia kräver normalt\n" -" inte att du definierar några miljövariabler manuellt. \n" -" " +" '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repetitioner): %(desc)s" -#: game/manage.py:140 -msgid "" -"\n" -" Edit your new settings.py file as needed, then run\n" -" 'python manage syncdb' and follow the prompts to\n" -" create the database and your superuser account.\n" -" " -msgstr "" -"\n" -" Modifiera din nya settings.py fil som du önskar, kör\n" -" sedan 'python manage.py syncdb' och följ instruktionerna\n" -" för att skapa databasen och ditt superuser-konto.\n" -" " +#: src/scripts/scripts.py:70 +#, python-format +msgid "Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'." +msgstr "Script %(key)s(#%(dbid)i) av typ '%(cname)s': at_repeat() fel '%(err)s'." -#: src/server/amp.py:109 -msgid " Portal lost connection to Server." -msgstr "Portalen förlorade sin koppling till terminalen. " +#: src/scripts/scripts.py:397 +msgid "This is an empty placeholder script." +msgstr "Detta är ett tomt platshållar-script." -#: src/server/amp.py:218 +#: src/scripts/scripts.py:404 +msgid "Checks sessions so they are live." +msgstr "Kollar sessioner så att de är aktiva." + +#: src/scripts/scripts.py:419 +msgid "Validates all scripts regularly." +msgstr "Validerar alla script regelbundet." + +#: src/scripts/scripts.py:433 +msgid "Updates the channel handler" +msgstr "Uppdaterar kanalhanteraren" + +#: src/scripts/scripts.py:447 +msgid "Clears the Attribute Cache" +msgstr "Nollställer Attribut-cachen" + +#: src/server/amp.py:394 msgid " ... Server restarted." -msgstr "... Servern startades om. " +msgstr "... Servern startades om." -#: src/server/amp.py:227 -#, python-format -msgid "AMP Error for %(info)s: %(e)s" -msgstr "AMP-fel: %(info)s: %(e)s" - -#: src/server/amp.py:366 -#: src/server/amp.py:428 -#, python-format -msgid "operation %(op)s not recognized." -msgstr "kommando av typ %(op)s kunde inte kännas igen." - -#: src/server/initial_setup.py:37 -msgid " Creating objects (Player #1 and Limbo room) ..." -msgstr "Skapar objekt (Spelare #1 och Limbo) ..." - -#: src/server/initial_setup.py:62 -msgid "#1 could not be created. Check the Player/Character typeclass for bugs." -msgstr "#1 kunde inte skapas. Kolla efter fel i typklassen för Player/Character. " - -#: src/server/initial_setup.py:65 +#: src/server/initial_setup.py:61 msgid "This is User #1." msgstr "Detta är användare #1." -#: src/server/initial_setup.py:73 +#: src/server/initial_setup.py:69 msgid "Limbo" msgstr "Limbo" -#: src/server/initial_setup.py:96 -msgid " Creating default channels ..." -msgstr "Skapar standardkanaler ..." - -#: src/server/initial_setup.py:119 -msgid " Importing MUX help database (devel reference only) ..." -msgstr "Importerar MUX:s hjälpdatabas (enbart för utvecklare)..." - -#: src/server/initial_setup.py:123 -#, python-format -msgid " Moving imported help db to help category '%(default)s'." -msgstr "Flyttar de importerade hjälpfileran till hjälpkategorin '%(default)s'." - -#: src/server/initial_setup.py:134 -msgid " Creating and starting global scripts ..." -msgstr "Skapar och startar globala skript ..." - -#: src/server/initial_setup.py:143 -msgid " Error creating system scripts." -msgstr "Fel under skapandet av System-skript." - -#: src/server/initial_setup.py:152 -msgid " Starting in-game time ..." -msgstr "Startar spelets tid ..." - -#: src/server/initial_setup.py:171 -msgid " ADMIN_MEDIA_ROOT already exists. Ignored." -msgstr "ADMIN_MEDIA_ROOT existerar redan. Ignorerar." - -#: src/server/initial_setup.py:174 -msgid " Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode)." -msgstr "Admin-media-filer kopierades till ADMIN_MEDIA_ROOT (Windows-läge)" - -#: src/server/initial_setup.py:179 -msgid " Admin-media symlinked to ADMIN_MEDIA_ROOT." -msgstr "Admin-media länkades till ADMIN_MEDIA_ROOT." - -#: src/server/initial_setup.py:181 -msgid " Admin-media files should be copied manually to ADMIN_MEDIA_ROOT." -msgstr "Admin-media-filer bör kopieras manuellt till ADMIN_MEDIA_ROOT." - -#: src/server/initial_setup.py:194 -msgid " Running at_initial_setup() hook." -msgstr "Kör kroken at_initial_setup()." - -#: src/server/models.py:88 -#, python-format -msgid "ServerConfig cannot store db objects! (%s)" -msgstr "ServerConfig kan inte lagra databas-objekt! (%s)" - -#: src/server/portal.py:106 -#, python-format -msgid " %(servername)s Portal (%(version)s) started." -msgstr " %(servername)s Portal (%(version)s) startades." - -#: src/server/portal.py:138 -#, python-format -msgid "writing mode=%(mode)s to %(portal_restart)s" -msgstr "writing mode = %(mode)s till %(portal_restart)s" - -#: src/server/server.py:137 -msgid " Server started for the first time. Setting defaults." -msgstr "Servern startades för första gången. Sätter standardvärden." - -#: src/server/server.py:145 -#, python-format -msgid " Resuming initial setup from step %(last)s." -msgstr "Startar om uppstarten från steg nummer %(last)s." - -#: src/server/server.py:165 -#, fuzzy, python-format -msgid " %(servername)s Server (%(version)s) started." -msgstr " %(servername)s Portal (%(version)s) startades." - -#: src/server/serversession.py:109 +#: src/server/serversession.py:108 #, python-format msgid "Logged in: %(self)s" -msgstr "%(self)s loggade in. " +msgstr "Loggade in: %(self)s" -#: src/server/sessionhandler.py:204 +#: src/server/sessionhandler.py:189 +msgid "You have been disconnected." +msgstr "Du har blivit frånkopplad." + +#: src/server/sessionhandler.py:202 msgid "Logged in from elsewhere. Disconnecting." -msgstr "Inloggad från någon annanstans. Kopplas ifrån." +msgstr "Inloggad från någon annanstans ifrån. Kopplas ifrån." -#: src/server/sessionhandler.py:220 +#: src/server/sessionhandler.py:222 msgid "Idle timeout exceeded, disconnecting." -msgstr "Passivitetstimer överskriden. Kopplas ifrån." - -#: src/server/ssh.py:298 -msgid " Generating SSH RSA keypair ..." -msgstr "Genererar SSH RSA-nyckerlpar. " - -#: src/server/ssh.py:343 -#, python-format -msgid "" -" getKeyPair error: %(e)s\n" -" WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead." -msgstr "" -"getKeyPair-fel: %(e)s\n" -"VARNING: Evennia kunde inte auomatiskt generera SSH-nyckelparet. Använder standardnycklar istället." - -#: src/server/ssh.py:344 -#, python-format -msgid " If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools." -msgstr "Om detta fel består, skapa game/%(pub)s och game/%(priv)s själv med hjälp av tredjepartsverktyg. " - -#: src/server/ssl.py:11 -msgid " SSL_ENABLED requires PyOpenSSL." -msgstr "För att använde SSL_ENABLED måste PyOpenSSL vara installerat. " - -#: src/server/ssl.py:36 -msgid " Creating SSL key and certificate ... " -msgstr "Skapar SSL-nyckel och certifikat ..." - -#: src/server/ssl.py:45 -#, python-format -msgid "" -"rsaKey error: %(e)s\n" -" WARNING: Evennia could not auto-generate SSL private key." -msgstr "" -"rsaKey fel: %(e)s\n" -"VARNING: Evennia kunde inte automatiskt generera den privata SSL-nyckeln. " - -#: src/server/ssl.py:46 -#, python-format -msgid "If this error persists, create game/%(keyfile)s yourself using third-party tools." -msgstr "Om detta fel består, skapa game/%(keyfile)s själv med hjälp av tredjepartsverktyg. " - -#: src/server/ssl.py:59 -#, python-format -msgid " Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s." -msgstr "Evennia's SSL-rutiner kunde inte automatiskt skapa SSL-certifikatet game/%(cert)s." - -#: src/server/ssl.py:60 -#, python-format -msgid " A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid" -msgstr "En privat nyckel 'ssl.key' har redan skapats. Skapa %(cert)s manuellt med hjälp av kommandona för ditt operativsystem." - -#: src/server/ssl.py:61 -msgid " for your operating system." -msgstr "för ditt operativsystem." - -#: src/server/ssl.py:62 -msgid " Example (linux, using the openssl program): " -msgstr "Exempel för Linux, med openssl:" +msgstr "Timeout. Kopplar ur." #: src/web/templates/admin/base_site.html:4 msgid "Evennia site admin" -msgstr "Evennia webside-admin" +msgstr "Evennia site admin" #: src/web/templates/admin/base_site.html:7 msgid "Evennia database administration" -msgstr "Evennia databas-administration" +msgstr "Evennia databasadministration" #: src/web/templates/admin/index.html:29 #: src/web/templates/admin/index.html:73 #: src/web/templates/admin/index.html:117 #, python-format msgid "Models available in the %(name)s application." -msgstr "Modeller tillgängliga i %(name)s." +msgstr "Modeller tillgängliga i %(name)s applikation." #: src/web/templates/admin/index.html:30 #: src/web/templates/admin/index.html:74 @@ -282,15 +314,15 @@ msgstr "Ändra" #: src/web/templates/admin/index.html:149 msgid "You don't have permission to edit anything." -msgstr "Du har inte tillstånd att ändra någonting." +msgstr "Du har inte rättigheter att ändra någonting." #: src/web/templates/admin/index.html:157 msgid "Recent Actions" -msgstr "Senaste Handlingar" +msgstr "Senaste Aktiviteter" #: src/web/templates/admin/index.html:158 msgid "My Actions" -msgstr "Mina Handlingar" +msgstr "Mina Aktiviteter" #: src/web/templates/admin/index.html:162 msgid "None yet." @@ -302,11 +334,11 @@ msgstr "Okänt innehåll" #: src/web/templates/admin/players/add_form.html:6 msgid "First, enter a username and password. Then you'll be able to edit more Player options." -msgstr "Mata först in ett användarnamn och lösenord. Sedan kommer du att kunna ändra fler Spelarinställningar." +msgstr "Först, ange ett användarnamn och lösenord. Då kommer du att kunna modifiera fler Player-inställningar." #: src/web/templates/admin/players/add_form.html:8 msgid "Enter a username and password." -msgstr "Mata in ett användarnamn och lösenord." +msgstr "Ange ett användarnamn och lösenord." #: src/web/templates/admin/players/change_form.html:20 #: src/web/templates/admin/players/change_list.html:42 @@ -320,14 +352,14 @@ msgstr "Historia" #: src/web/templates/admin/players/change_form.html:32 #: src/web/templates/admin/players/stacked.html:9 msgid "View on site" -msgstr "Se på Websida" +msgstr "Inspektera på sida" #: src/web/templates/admin/players/change_form.html:43 #: src/web/templates/admin/players/change_list.html:73 msgid "Please correct the error below." msgid_plural "Please correct the errors below." msgstr[0] "Vänligen korrigera felet nedan." -msgstr[1] "Vänligen korrigera felen nedan." +msgstr[1] "Vänligen korrigera felet nedan.\t\t\t\t" #: src/web/templates/admin/players/change_list.html:64 #, python-format @@ -341,552 +373,9 @@ msgstr "Filtrera" #: src/web/templates/admin/players/stacked.html:67 #, python-format msgid "Add another %(verbose_name)s" -msgstr "Lägg till ett annat %(verbose_name)s" +msgstr "Lägg till ännu ett %(verbose_name)s" #: src/web/templates/admin/players/stacked.html:70 msgid "Remove" msgstr "Ta bort" -#~ msgid "" -#~ "\n" -#~ " (version %s) \n" -#~ "\n" -#~ "This program launches Evennia with various options. You can access all\n" -#~ "this functionality directly from the command line; for example option\n" -#~ "five (restart server) would be \"evennia.py restart server\". Use\n" -#~ "\"evennia.py -h\" for command line options.\n" -#~ "\n" -#~ "Evennia consists of two separate programs that both must be running\n" -#~ "for the game to work as it should:\n" -#~ "\n" -#~ "Portal - the connection to the outside world (via telnet, web, ssh\n" -#~ " etc). This is normally running as a daemon and don't need to\n" -#~ " be reloaded unless you are debugging a new connection\n" -#~ " protocol. As long as this is running, players won't loose\n" -#~ " their connection to your game. Only one instance of Portal\n" -#~ " will be started, more will be ignored.\n" -#~ "Server - the game server itself. This will often need to be reloaded\n" -#~ " as you develop your game. The Portal will auto-connect to the\n" -#~ " Server whenever the Server activates. We will also make sure\n" -#~ " to automatically restart this whenever it is shut down (from\n" -#~ " here or from inside the game or via task manager etc). Only\n" -#~ " one instance of Server will be started, more will be ignored.\n" -#~ "\n" -#~ "In a production environment you will want to run with the default\n" -#~ "option (1), which runs as much as possible as a background\n" -#~ "process. When developing your game it is however convenient to\n" -#~ "directly see tracebacks on standard output, so starting with options\n" -#~ "2-4 may be a good bet. As you make changes to your code, reload the\n" -#~ "server (option 5) to make it available to users.\n" -#~ "\n" -#~ "Reload and stop is not well supported in Windows. If you have issues, " -#~ "log\n" -#~ "into the game to stop or restart the server instead. \n" -#~ msgstr "" -#~ "\n" -#~ " (version %s) \n" -#~ "\n" -#~ "Detta program startar Evennia med olika funktionalitet. Du kan se alla\n" -#~ "functioner direkt från kommandoraden; t.ex så motsvarar val nummer 5\n" -#~ "(starta om servern) kommandot \"evennia.py restart server\" Använd \n" -#~ "\"evennia.py -h för att lista alla möjliga kommandon. \n" -#~ "\n" -#~ "Evennia består av tvp separata program som båda måste vara igång\n" -#~ "för att servern ska fungera:\n" -#~ "\n" -#~ "Portal - Kopplingen till omvärlden (via telnet, web, ssh etc). Portalen\n" -#~ " körs vanligen som en \"demon\" och behöver inte startas om\n" -#~ " såtillvida du inte debuggar ett nytt nätverksprotokoll. Så " -#~ "länge\n" -#~ " Portalen kör så kommer inte spelare att förlora kontakten med\n" -#~ " spelet. Bara en instans av Portalen kan starts p¨ en gång, " -#~ "ytterligare\n" -#~ " instanser kommer att ignoreras\n" -#~ "Server - Spelservern själv. Denna kan ofta behöva starts om medan\n" -#~ " du utvecklar ditt spel. Portalen kommer att automatiskt ansluta\n" -#~ " till Servern så fort denna startar. Servern startar också " -#~ "automatiskt\n" -#~ " om så fort den stängs ner (innfrån spelet eller via " -#~ "operativsystemet).\n" -#~ " Bara en instans av Server kan vara igång samtidigt. \n" -#~ "\n" -#~ "När servern är öppen för allmänheten är det lämpligt att använda val (1)\n" -#~ "som innebär att så mycket som möjligt jörs i bakgrunden.\n" -#~ " När man utvecklar sitt spel är det dock bekvämt att direkt se " -#~ "felmeddanden\n" -#~ "i terminalen. För detta är val 2-4 bra val. Starta om servern när ny kod " -#~ "är\n" -#~ "på plats genom att använda val (5).\n" -#~ "\n" -#~ "Omstart och stopp fungerar inte så bra i Windows. Om du har problem, \n" -#~ "loggin in i spelet och starta om innifrån istället.\n" - -#~ msgid "" -#~ "\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| Welcome to the Evennia " -#~ "launcher! |\n" -#~ "| " -#~ "|\n" -#~ "| Pick an option below. Use 'h' to get " -#~ "help. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starting (will not restart already running processes) " -#~ "-----------------+\n" -#~ "| " -#~ "|\n" -#~ "| 1) (default): Start Server and Portal. Portal starts in daemon " -#~ "mode.|\n" -#~ "| All output is to " -#~ "logfiles. |\n" -#~ "| 2) (game debug): Start Server and Portal. Portal starts in daemon " -#~ "mode.|\n" -#~ "| Server outputs to stdout instead of " -#~ "logfile. |\n" -#~ "| 3) (portal debug): Start Server and Portal. Portal starts in non-" -#~ "daemon |\n" -#~ "| mode (can be reloaded) and logs to " -#~ "stdout. |\n" -#~ "| 4) (full debug): Start Server and Portal. Portal starts in non-" -#~ "daemon |\n" -#~ "| mode (can be reloaded). Both log to " -#~ "stdout. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Restarting (must first be started) " -#~ "------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 5) Reload the " -#~ "Server |\n" -#~ "| 6) Reload the Portal (only works in non-daemon mode. If " -#~ "running |\n" -#~ "| in daemon mode, Portal needs to be restarted manually (option " -#~ "1-4)) |\n" -#~ "| " -#~ "|\n" -#~ "+--- Stopping (must first be started) " -#~ "--------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 7) Stopping both Portal and Server. Server will not " -#~ "restart. |\n" -#~ "| 8) Stopping only Server. Server will not " -#~ "restart. |\n" -#~ "| 9) Stopping only " -#~ "Portal. |\n" -#~ "| " -#~ "|\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| h) " -#~ "Help |\n" -#~ "| q) " -#~ "Quit |\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ msgstr "" -#~ "\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| Välkommen till " -#~ "Evennia! |\n" -#~ "| " -#~ "|\n" -#~ "| Välj nedan. Ge '-h' för att få " -#~ "hjälp. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starta (kommer inte att starta om existerande processer)-------------" -#~ "+\n" -#~ "| " -#~ "|\n" -#~ "| 1) (förvalt): Start Server och Portal. Portalen startar som demon|" -#~ "n| Alla meddelanden till " -#~ "loggfiler |\n" -#~ "| 2) (spelutveckling): Starta Server och Portal. Portalen startar " -#~ "som .|\n" -#~ "| demon. Server meddelar till " -#~ "terminal. |\n" -#~ "| 3) (portal debug): StartaServer and Portal. Portal startar " -#~ "som |\n" -#~ "| icke-" -#~ "demon. |\n" -#~ "| 4) (full debug): StartaServer and Portal. Båda startar " -#~ "som |\n" -#~ "| icke-demon. Båda meddear till " -#~ "terminal. |\n" -#~ "| " -#~ "|\n" -#~ "+--- Starta om (måste först vara " -#~ "startad)-----------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 5) Starta om " -#~ "Server |\n" -#~ "| 6) Starta om Portalen (funkar bara som icke-demon). Om man " -#~ "kör |\n" -#~ "| som demon så måste Portalen startas om manuellt (val " -#~ "1-4) |\n" -#~ "| " -#~ "|\n" -#~ "+--- Stopp (måste först vara startad) " -#~ "--------------------------------------+\n" -#~ "| " -#~ "|\n" -#~ "| 7) Stoppa både Portal och Server. Server startar inte " -#~ "om. |\n" -#~ "| 8) Stoppa bara Server. Server kommer inte att starta " -#~ "om. |\n" -#~ "| 9) Stoppa bara " -#~ "Portalen. |\n" -#~ "| " -#~ "|\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" -#~ "| h) " -#~ "Hjälp |\n" -#~ "| q) " -#~ "Avsluta |\n" -#~ "+---------------------------------------------------------------------------" -#~ "+\n" - -#~ msgid " No settings.py file found. launching manage.py ..." -#~ msgstr " Filen \"settings.py\" hittades inte. Startar manage.py ..." - -#~ msgid "" -#~ "\n" -#~ " ... A new settings file was created. Edit this file to configure\n" -#~ " Evennia as desired by copy&pasting options from\n" -#~ " src/settings_default.py.\n" -#~ "\n" -#~ " You should then also create/configure the database using\n" -#~ "\n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " Make sure to create a new admin user when prompted -- this will be\n" -#~ " user #1 in-game. If you use django-south, you'll see mentions of\n" -#~ " migrating things in the above run. You then also have to run\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " If you use default sqlite3 database, you will find a file\n" -#~ " evennia.db appearing. This is the database file. Just delete this\n" -#~ " and repeat the above manage.py steps to start with a fresh\n" -#~ " database.\n" -#~ "\n" -#~ " When you are set up, run evennia.py again to start the server." -#~ msgstr "" -#~ "\n" -#~ " ... En ny settings-fil har skapats. Modifiera denna fil för att " -#~ "konfigurera\n" -#~ " Evennia som önskas genom att klippa och klistra från originalet i \n" -#~ " src/settings_default.py.\n" -#~ "\n" -#~ " Du bör sedan återskapa databasen med\n" -#~ "\n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " Se till att skapa ett nytt admin-lösenord när så tillfrågas - detta " -#~ "används\n" -#~ " för användare #1 i spelet. Om nu använder django-south kommer du \n" -#~ " se ett omnämnande om migrationer efter de ovanstående kommandona.\n" -#~ " Du måste då köra: \n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " Om du använder sqlite3-databasen kommer du att hitta en fil\n" -#~ " evennia.db i game/. Detta är databas-filen. Radera denna fil \n" -#~ " och upprepa de ovannämnda stegen för att starta om med en \n" -#~ " ny, tom databas. \n" -#~ "\n" -#~ " När allt är klart, kör evennia.py igen rör att starta servern." - -#~ msgid "" -#~ "\n" -#~ " Your database does not seem to be set up correctly.\n" -#~ "\n" -#~ " Please run:\n" -#~ " \n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " (make sure to create an admin user when prompted). If you use\n" -#~ " pyhon-south you will get mentions of migrating in the above\n" -#~ " run. You then need to also run\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " When you have a database set up, rerun evennia.py.\n" -#~ " " -#~ msgstr "" -#~ "\n" -#~ " Din databas verkar inte korrekt konfigurerad.\n" -#~ "\n" -#~ " Vänligen kör:\n" -#~ " \n" -#~ " python manage.py syncdb\n" -#~ "\n" -#~ " (Se till att skapa ett administrationskonto när det tillfrågas.\n" -#~ " Om du använder pyhon-south kommer du att se omnämnande om \n" -#~ " Se till att då också köra\n" -#~ "\n" -#~ " python manage.py migrate\n" -#~ "\n" -#~ " När databasen fungeran, kör evennia.py igen.\n" -#~ " " - -#~ msgid "" -#~ "\n" -#~ " ERROR: Unable to import win32api, which Twisted requires to run.\n" -#~ " You may download it from:\n" -#~ "\n" -#~ " http://sourceforge.net/projects/pywin32\n" -#~ " or\n" -#~ " http://starship.python.net/crew/mhammond/win32/Downloads.html" -#~ msgstr "" -#~ "\n" -#~ " FEL: Kunde inte importera win32api. Twisted behöver detta. \n" -#~ " Ladda ner från:\n" -#~ "\n" -#~ " http://sourceforge.net/projects/pywin32\n" -#~ " eller\n" -#~ " http://starship.python.net/crew/mhammond/win32/Downloads.html" - -#~ msgid "" -#~ "\n" -#~ " INFO: Since you are running Windows, a file 'twistd.bat' was\n" -#~ " created for you. This is a simple batch file that tries to call\n" -#~ " the twisted executable. Evennia determined this to be:\n" -#~ "\n" -#~ " %{twistd_path}s\n" -#~ "\n" -#~ " If you run into errors at startup you might need to edit\n" -#~ " twistd.bat to point to the actual location of the Twisted\n" -#~ " executable (usually called twistd.py) on your machine.\n" -#~ "\n" -#~ " This procedure is only done once. Run evennia.py again when you\n" -#~ " are ready to start the server.\n" -#~ " " -#~ msgstr "" -#~ "\n" -#~ " INFO: Efersom du kör Windows har en fil 'twistd.bat' skapats\n" -#~ " Detta är en enkel batch-file som försöker anropa twisted:s\n" -#~ " exeutiva fil. Evennia bedömde att detta är:\n" -#~ "\n" -#~ " %{twistd_path}s\n" -#~ "\n" -#~ " Om du stöter på fel under starten så kanske du behöver \n" -#~ " modifiera twistd.dat så att den hittar Twisted:s binärfil (vanligen\n" -#~ " kallad twistd.py) just på din dator.\n" -#~ "\n" -#~ " Denna procedur behöver bara göras en gång. Kör evennia.py\n" -#~ " igen när du är redo att starta servern.\n" -#~ " " - -#~ msgid "Windows requires Python 2.7 or higher for this operation." -#~ msgstr "Windows kräver Python 2.7 för att utföra detta. " - -#~ msgid "" -#~ "Process %(pid)s could not be signalled. The PID file '%(pidfile)s' seems " -#~ "stale. Try removing it." -#~ msgstr "" -#~ "Processen %(pid)s kunde inte signaleras. PID-filen '%(pidfile)s' verkar " -#~ "vara ur synk. Ta bort den manuellt." - -#~ msgid " option > " -#~ msgstr "val >" - -#~ msgid "press to continue ..." -#~ msgstr "tryck för att fortsätta ..." - -#~ msgid "Not a valid option." -#~ msgstr "Inte ett lämpligt val." - -#~ msgid "The %s does not seem to be running." -#~ msgstr "%s verkar inte köra. " - -#~ msgid "" -#~ "This operation is not supported under Windows. Log into the game to " -#~ "restart/reload the server." -#~ msgstr "Detta stöds inte under Windows. Logga in för att starta om servern." - -#~ msgid "Server reloaded." -#~ msgstr "Servern startades om." - -#~ msgid "This operation is not supported under Windows." -#~ msgstr "Detta stöds inte under Windows." - -#~ msgid "Portal reloaded (or stopped if in daemon mode)." -#~ msgstr "Portalen startades om (eller stoppades, om den körde some demon)" - -#~ msgid "Stopped Portal." -#~ msgstr "Stoppade Portalen." - -#~ msgid "Stopped Server." -#~ msgstr "Stoppade Portalen." - -#~ msgid "" -#~ "Restarting from command line is not supported under Windows. Log into the " -#~ "game to restart." -#~ msgstr "" -#~ "Att starta om från kommandoraden stöds inte under Windows. Logga in för " -#~ "att starta om. " - -#~ msgid "" -#~ "Note: Portal usually don't need to be reloaded unless you are debugging " -#~ "in interactive mode." -#~ msgstr "" -#~ "Obs: Portalen behöver oftast inte startas om såtillvida man inte håller " -#~ "på att debugga portalen. " - -#~ msgid "" -#~ "If Portal was running in default Daemon mode, it cannot be restarted. In " -#~ "that case you have " -#~ msgstr "" -#~ "Om Portalen kördes som en demon så kan den inte startas om. I såfall " -#~ "måste du" - -#~ msgid "to restart it manually with 'evennia.py start portal'" -#~ msgstr "starta om den manuellt med 'evennia.py start portal'" - -#~ msgid "Portal reloaded (or stopped, if it was in daemon mode)." -#~ msgstr "Portalen startades om (eller stoppades om den kördes som demon)" - -#~ msgid "Server reload." -#~ msgstr "Serven laddades om." - -#~ msgid "Server stopped." -#~ msgstr "Servern stoppades." - -#~ msgid "Portal stopped." -#~ msgstr "Portalen stoppades." - -#~ msgid "" -#~ "This is the main Evennia launcher. It handles the Portal and Server, the " -#~ "two services making up Evennia. Default is to operate on both services. " -#~ "Use --interactive together with start to launch services as " -#~ "'interactive'. Note that when launching 'all' services with the --" -#~ "interactive flag, both services will be started, but only Server will " -#~ "actually be started in interactive mode. This is simply because this is " -#~ "the most commonly useful state. To activate interactive mode also for " -#~ "Portal, launch the two services explicitly as two separate calls to this " -#~ "program. You can also use the menu." -#~ msgstr "" -#~ "Detta är Evennias huvudprogram. Det hanterar Portalen och Servern, de två " -#~ "program so utgör Evennia. Normal verkar alla kommandon på båda " -#~ "programmen. Använd --interactive tillsammans med start för att starta " -#~ "interaktiva lägen. Notera att normalt startar bara Servern i interaktivt " -#~ "läge eftersom detta är det oftast använda läget. För att aktivera " -#~ "interaktivt läge även för Portalen så måste man starta programmen var för " -#~ "sig. Man kan också använde menyn. " - -#~ msgid "" -#~ "Start given processes in interactive mode (log to stdout, don't start as " -#~ "a daemon)." -#~ msgstr "" -#~ "Starta den angivna processen i interaktivt läge (alla meddelanden till " -#~ "terminalen, starta inte som demon)" - -#~ msgid "mode should be none or one of 'menu', 'start', 'reload' or 'stop'." -#~ msgstr "" -#~ "'mode' (om den anges) måste antingen vara 'menu', 'start', 'reload' eller " -#~ "'stop'." - -#~ msgid "service should be none or 'server', 'portal' or 'all'." -#~ msgstr "" -#~ "'service' (om den anges) måste antingen vara 'server', 'portal' eller " -#~ "'all'." - -#~ msgid "No settings.py file found. Run evennia.py to create it." -#~ msgstr "" -#~ "Ingen settings.py-fil kunde hittas. Kör evennia.py för att skapa den. " - -#~ msgid "" -#~ "Twisted binary for Windows is not ready to use. Please run evennia.py." -#~ msgstr "" -#~ "Twisted:s Windows-binärfil är inte klar att användas. Vänligen kör " -#~ "evennia.py först. " - -#~ msgid "Server process error: %(e)s" -#~ msgstr "Server: Process-fel: %(e)s" - -#~ msgid "Portal process error: %(e)s" -#~ msgstr "Portal: Process-fel: %(e)s" - -#~ msgid "Evennia Server stopped. Restarting ..." -#~ msgstr "Evennia:s Serverprocess stoppades. Startar om ..." - -#~ msgid "Evennia Portal stopped in interactive mode. Restarting ..." -#~ msgstr "" -#~ "Evennia:s Portal-process stoppades i interaktivt läge. Startar om ..." - -#~ msgid "" -#~ "This runner should normally *not* be called directly - it is called " -#~ "automatically from the evennia.py main program. It manages the Evennia " -#~ "game server and portal processes an hosts a threaded loop to restart the " -#~ "Server whenever it is stopped (this constitues Evennia's reload " -#~ "mechanism)." -#~ msgstr "" -#~ "Detta program bör normalt *inte* anropas direkt - det startas automatiskt " -#~ "från evennia.py. Programmet styr Evennia:s Server- och Portal-processer " -#~ "med hj'lp av en trådbaserad loop som gör att Servern kan startas om. " - -#~ msgid "Do not start Server process" -#~ msgstr "Starta inte Server-processen." - -#~ msgid "Do not start Portal process" -#~ msgstr "Starta inte Portal-processen" - -#~ msgid "output server log to stdout instead of logfile" -#~ msgstr "Avge Server-data till stdout istället för till en logfil" - -#~ msgid "output portal log to stdout. Does not make portal a daemon." -#~ msgstr "Avge Portal-data till stdout. Starta inte som demon." - -#~ msgid "" -#~ "\n" -#~ "Evennia Server is already running as process %(pid)s. Not restarted." -#~ msgstr "" -#~ "\n" -#~ " Evennias Server-process kör redan som %(pid)s. Behöver inte startas. " - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Server (output to stdout)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Server-process (meddelanden till terminalen)." - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Server (output to server logfile)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Server (meddelanden till logfil)." - -#~ msgid "" -#~ "\n" -#~ "Evennia Portal is already running as process %(pid)s. Not restarted." -#~ msgstr "" -#~ "\n" -#~ "Evennias portal kör redan som %(pid)s. Behöver inte startas." - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Portal in non-Daemon mode (output to stdout)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Portal-process som icke-demon (meddelanden till " -#~ "terminalen)" - -#~ msgid "" -#~ "\n" -#~ "Starting Evennia Portal in Daemon mode (output to portal logfile)." -#~ msgstr "" -#~ "\n" -#~ "Startar Evennias Portal-process som en demon (meddelanden till logfil)." diff --git a/src/commands/cmdhandler.py b/src/commands/cmdhandler.py index aaebe95312..dd5f8f95f6 100644 --- a/src/commands/cmdhandler.py +++ b/src/commands/cmdhandler.py @@ -45,6 +45,8 @@ from src.commands.cmdset import CmdSet from src.commands.cmdparser import at_multimatch_cmd from src.utils.utils import string_suggestions +from django.utils.translation import ugettext as _ + __all__ = ("cmdhandler",) # This decides which command parser is to be used. @@ -196,18 +198,18 @@ def cmdhandler(caller, raw_string, testing=False): if syscmd: sysarg = raw_string else: - sysarg = "Command '%s' is not available." % raw_string + sysarg = _("Command '%s' is not available.") % raw_string suggestions = string_suggestions(raw_string, cmdset.get_all_cmd_keys_and_aliases(caller), cutoff=0.7, maxnum=3) if suggestions: - sysarg += " Maybe you meant %s?" % utils.list_to_string(suggestions, 'or', addquote=True) + sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True) else: - sysarg += " Type \"help\" for help." + sysarg += _(" Type \"help\" for help.") raise ExecSystemCommand(syscmd, sysarg) if len(matches) > 1: # We have a multiple-match syscmd = yield cmdset.get(CMD_MULTIMATCH) - sysarg = "There where multiple matches." + sysarg = _("There where multiple matches.") if syscmd: syscmd.matches = matches else: @@ -301,19 +303,19 @@ def cmdhandler(caller, raw_string, testing=False): string += "If logging out/in doesn't solve the problem, try to " string += "contact the server admin through some other means " string += "for assistance." - caller.msg(string) + caller.msg(_(string)) logger.log_errmsg("No cmdsets found: %s" % caller) except Exception: # We should not end up here. If we do, it's a programming bug. string = "%s\nAbove traceback is from an untrapped error." string += " Please file a bug report." - logger.log_trace(string) + logger.log_trace(_(string)) caller.msg(string % format_exc()) except Exception: # This catches exceptions in cmdhandler exceptions themselves string = "%s\nAbove traceback is from a Command handler bug." string += " Please contact an admin and/or file a bug report." - logger.log_trace(string) + logger.log_trace(_(string)) caller.msg(string % format_exc()) diff --git a/src/commands/cmdparser.py b/src/commands/cmdparser.py index 0d97ce283f..2a7cd7659d 100644 --- a/src/commands/cmdparser.py +++ b/src/commands/cmdparser.py @@ -6,6 +6,7 @@ return a CommandCandidates object. """ from src.utils.logger import log_trace +from django.utils.translation import ugettext as _ def cmdparser(raw_string, cmdset, caller, match_index=None): """ @@ -140,7 +141,7 @@ def at_search_result(msg_obj, ostring, results, global_search=False): string = "" if not results: # no results. - string = "Could not find '%s'." % ostring + string = _("Could not find '%s'." % ostring) results = None elif len(results) > 1: @@ -152,11 +153,12 @@ def at_search_result(msg_obj, ostring, results, global_search=False): string += "More than one match for '%s'" % ostring string += " (please narrow target):" + string = _(string) for num, result in enumerate(results): invtext = "" dbreftext = "" - if hasattr(result, "location") and result.location == msg_obj: - invtext = " (carried)" + if hasattr(result, _("location")) and result.location == msg_obj: + invtext = _(" (carried)") if show_dbref: dbreftext = "(#%i)" % result.dbid string += "\n %i-%s%s%s" % (num+1, result.name, @@ -235,11 +237,11 @@ def at_multimatch_cmd(caller, matches): is_channel = hasattr(cmd, "is_channel") and cmd.is_channel if is_channel: - is_channel = " (channel)" + is_channel = _(" (channel)") else: is_channel = "" if cmd.is_exit and cmd.destination: - is_exit = " (exit to %s)" % cmd.destination + is_exit = _(" (exit to %s)") % cmd.destination else: is_exit = "" diff --git a/src/commands/cmdset.py b/src/commands/cmdset.py index 614315d93d..a6da8e0be4 100644 --- a/src/commands/cmdset.py +++ b/src/commands/cmdset.py @@ -15,6 +15,7 @@ together to create interesting in-game effects. """ import copy +from django.utils.translation import ugettext as _ from src.utils.utils import inherits_from, is_iter __all__ = ("CmdSet",) @@ -303,9 +304,9 @@ class CmdSet(object): try: cmd = self._instantiate(cmd) except RuntimeError, e: - string = "Adding cmdset %s to %s lead to an infinite loop. When adding a cmdset to another, " + string = "Adding cmdset %(cmd)s to %(class)s lead to an infinite loop. When adding a cmdset to another, " string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain." - raise RuntimeError(string % (cmd, self.__class__)) + raise RuntimeError(_(string) % {"cmd":cmd, "class":self.__class__}) cmds = cmd.commands elif is_iter(cmd): cmds = [self._instantiate(c) for c in cmd] diff --git a/src/commands/cmdsethandler.py b/src/commands/cmdsethandler.py index 6f58e3021f..8608b6bdd4 100644 --- a/src/commands/cmdsethandler.py +++ b/src/commands/cmdsethandler.py @@ -67,6 +67,8 @@ import traceback from src.utils import logger, utils from src.commands.cmdset import CmdSet from src.server.models import ServerConfig + +from django.utils.translation import ugettext as _ __all__ = ("import_cmdset", "CmdSetHandler") _CACHED_CMDSETS = {} @@ -110,15 +112,15 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): return cmdsetclass except ImportError: - errstring = "Error loading cmdset: Couldn't import module '%s'." + errstring = _("Error loading cmdset: Couldn't import module '%s'.") errstring = errstring % modulepath raise except KeyError: - errstring = "Error in loading cmdset: No cmdset class '%s' in %s." - errstring = errstring % (classname, modulepath) + errstring = _("Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s.") + errstring = errstring % {"classname":classname, "modulepath":modulepath} raise except Exception: - errstring = "Compile/Run error when loading cmdset '%s'. Error was logged." + errstring = _("Compile/Run error when loading cmdset '%s'. Error was logged.") errstring = errstring % (python_path) raise except Exception: @@ -194,15 +196,17 @@ class CmdSetHandler(object): mergetype = self.mergetype_stack[-1] if mergetype != self.current.mergetype: merged_on = self.cmdset_stack[-2].key - mergetype = "custom %s on cmdset '%s'" % (mergetype, merged_on) + mergetype = _("custom %(mergetype)s on cmdset '%(merged_on)s'") % {"mergetype":mergetype, "merged_on":merged_on} if mergelist: - string += " : %s" % ("+".join(mergelist), mergetype, self.current.priority, self.current) + string += _(" : %(current)s") % \ + {"mergelist": "+".join(mergelist), "mergetype":mergetype, "prio":self.current.priority, "current":self.current} else: permstring = "non-perm" if self.current.permanent: permstring = "perm" - string += " <%s (%s, prio %i, %s)>: %s" % (self.current.key, mergetype, self.current.priority, permstring, - ", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key))) + string += _(" <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s") % \ + {"key":self.current.key, "mergetype":mergetype, "prio":self.current.priority, "permstring":permstring, + "keylost":", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key))} return string.strip() def _import_cmdset(self, cmdset_path, emit_to_obj=None): @@ -274,7 +278,7 @@ class CmdSetHandler(object): """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): - raise Exception("Only CmdSets can be added to the cmdsethandler!") + raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. @@ -306,7 +310,7 @@ class CmdSetHandler(object): """ if callable(cmdset): if not utils.inherits_from(cmdset, CmdSet): - raise Exception("Only CmdSets can be added to the cmdsethandler!") + raise Exception(_("Only CmdSets can be added to the cmdsethandler!")) cmdset = cmdset(self.obj) elif isinstance(cmdset, basestring): # this is (maybe) a python path. Try to import from cache. diff --git a/src/comms/admin.py b/src/comms/admin.py index 4ce9886978..e207fb2660 100644 --- a/src/comms/admin.py +++ b/src/comms/admin.py @@ -1,20 +1,20 @@ # -# This sets up how models are displayed -# in the web admin interface. +# This sets up how models are displayed +# in the web admin interface. # from django.contrib import admin from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChannelConnection -class MsgAdmin(admin.ModelAdmin): - list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage') +class MsgAdmin(admin.ModelAdmin): + list_display = ('id', 'db_date_sent', 'db_sender', 'db_receivers', 'db_channels', 'db_message', 'db_lock_storage') list_display_links = ("id",) ordering = ["db_date_sent", 'db_sender', 'db_receivers', 'db_channels'] #readonly_fields = ['db_message', 'db_sender', 'db_receivers', 'db_channels'] search_fields = ['id', '^db_date_sent', '^db_message'] - save_as = True - save_on_top = True - list_select_related = True + save_as = True + save_on_top = True + list_select_related = True #admin.site.register(Msg, MsgAdmin) class PlayerChannelConnectionInline(admin.TabularInline): @@ -41,12 +41,12 @@ class ChannelAdmin(admin.ModelAdmin): list_display_links = ("id", 'db_key') ordering = ["db_key"] search_fields = ['id', 'db_key', 'db_aliases'] - save_as = True - save_on_top = True - list_select_related = True + save_as = True + save_on_top = True + list_select_related = True fieldsets = ( (None, {'fields':(('db_key', 'db_aliases', 'db_desc'),'db_lock_storage', 'db_keep_log')}), - ) + ) admin.site.register(Channel, ChannelAdmin) @@ -55,9 +55,9 @@ admin.site.register(Channel, ChannelAdmin) # list_display_links = ("db_player", 'db_channel') # ordering = ["db_channel"] # search_fields = ['db_channel', 'db_player'] -# save_as = True -# save_on_top = True -# list_select_related = True +# save_as = True +# save_on_top = True +# list_select_related = True # admin.site.register(PlayerChannelConnection, PlayerChannelConnectionAdmin) # class ExternalChannelConnectionAdmin(admin.ModelAdmin): @@ -65,8 +65,8 @@ admin.site.register(Channel, ChannelAdmin) # list_display_links = ("db_channel", 'db_external_key', 'db_external_config') # ordering = ["db_channel"] # search_fields = ['db_channel', 'db_external_key'] -# save_as = True -# save_on_top = True -# list_select_related = True +# save_as = True +# save_on_top = True +# list_select_related = True # admin.site.register(ExternalChannelConnection, ExternalChannelConnectionAdmin) diff --git a/src/comms/imc2.py b/src/comms/imc2.py index 1b46b62731..1f04c0502e 100644 --- a/src/comms/imc2.py +++ b/src/comms/imc2.py @@ -16,6 +16,8 @@ from src.comms.imc2lib import imc2_packets as pck from src.comms.imc2lib.imc2_trackers import IMC2MudList, IMC2ChanList from src.comms.imc2lib.imc2_listeners import handle_whois_reply +from django.utils.translation import ugettext as _ + # IMC2 network setup IMC2_MUDNAME = settings.SERVERNAME IMC2_NETWORK = settings.IMC2_NETWORK @@ -26,8 +28,8 @@ IMC2_SERVER_PWD = settings.IMC2_SERVER_PWD # channel to send info to INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) # all linked channel connections -IMC2_CLIENT = None -# IMC2 debug mode +IMC2_CLIENT = None +# IMC2 debug mode IMC2_DEBUG = False # Use this instance to keep track of the other games on the network. IMC2_MUDLIST = IMC2MudList() @@ -41,7 +43,7 @@ IMC2_CHANLIST = IMC2ChanList() def msg_info(message): """ Send info to default info channel - """ + """ try: INFOCHANNEL[0].msg(message) message = '[%s][IMC2]: %s' % (INFOCHANNEL[0].key, message) @@ -49,7 +51,7 @@ def msg_info(message): logger.log_infomsg("MUDinfo (imc2): %s" % message) # -# Regular scripts +# Regular scripts # class Send_IsAlive(Script): @@ -61,8 +63,8 @@ class Send_IsAlive(Script): def at_script_creation(self): self.key = 'IMC2_Send_IsAlive' self.interval = 900 - self.desc = "Send an IMC2 is-alive packet" - self.persistent = True + self.desc = _("Send an IMC2 is-alive packet") + self.persistent = True def at_repeat(self): IMC2_CLIENT.send_packet(pck.IMC2PacketIsAlive()) def is_valid(self): @@ -77,9 +79,9 @@ class Send_Keepalive_Request(Script): def at_script_creation(self): self.key = "IMC2_Send_Keepalive_Request" self.interval = 3500 - self.desc = "Send an IMC2 keepalive-request packet" - self.persistent = True - def at_repeat(self): + self.desc = _("Send an IMC2 keepalive-request packet") + self.persistent = True + def at_repeat(self): IMC2_CLIENT.channel.send_packet(pck.IMC2PacketKeepAliveRequest()) def is_valid(self): "Is only valid as long as there are channels to update" @@ -94,8 +96,8 @@ class Prune_Inactive_Muds(Script): def at_script_creation(self): self.key = "IMC2_Prune_Inactive_Muds" self.interval = 1800 - self.desc = "Check IMC2 list for inactive games" - self.persistent = True + self.desc = _("Check IMC2 list for inactive games") + self.persistent = True self.inactive_threshold = 3599 def at_repeat(self): for name, mudinfo in IMC2_MUDLIST.mud_list.items(): @@ -104,7 +106,7 @@ class Prune_Inactive_Muds(Script): def is_valid(self): "Is only valid as long as there are channels to update" return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_")) - + class Sync_Server_Channel_List(Script): """ Re-syncs the network's channel list. This will @@ -114,11 +116,11 @@ class Sync_Server_Channel_List(Script): """ def at_script_creation(self): self.key = "IMC2_Sync_Server_Channel_List" - self.interval = 24 * 3600 # once every day - self.desc = "Re-sync IMC2 network channel list" - self.persistent = True + self.interval = 24 * 3600 # once every day + self.desc = _("Re-sync IMC2 network channel list") + self.persistent = True def at_repeat(self): - checked_networks = [] + checked_networks = [] network = IMC2_CLIENT.factory.network if not network in checked_networks: channel.send_packet(pkg.IMC2PacketIceRefresh()) @@ -126,7 +128,7 @@ class Sync_Server_Channel_List(Script): def is_valid(self): return any(service for service in SESSIONS.server.services if service.name.startswith("imc2_")) # -# IMC2 protocol +# IMC2 protocol # class IMC2Protocol(telnet.StatefulTelnetProtocol): @@ -143,7 +145,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): self.network_name = None self.sequence = None - + def connectionMade(self): """ Triggered after connecting to the IMC2 network. @@ -153,19 +155,19 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): logger.log_infomsg("IMC2: Connected to network server.") logger.log_infomsg("IMC2: Sending authentication packet.") self.send_packet(pck.IMC2PacketAuthPlaintext()) - + def connectionLost(self, reason=None): """ - This is executed when the connection is lost for - whatever reason. + This is executed when the connection is lost for + whatever reason. """ try: service = SESSIONS.server.services.getServiceNamed("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) except Exception: - return + return if service.running: service.stopService() - + def send_packet(self, packet): """ Given a sub-class of IMC2Packet, assemble the packet and send it @@ -182,14 +184,14 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): logger.log_infomsg("IMC2: SENT> %s" % packet_str) logger.log_infomsg(str(packet)) self.sendLine(packet_str) - + def _parse_auth_response(self, line): """ Parses the IMC2 network authentication packet. """ if self.auth_type == "plaintext": - # Plain text passwords. - # SERVER Sends: PW version= + # Plain text passwords. + # SERVER Sends: PW version= if IMC2_DEBUG: logger.log_infomsg("IMC2: AUTH< %s" % line) @@ -199,26 +201,26 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): autosetup_present = line_split[0] == 'autosetup' if "reject" in line_split: - auth_message = "IMC2 server rejected connection." + auth_message = _("IMC2 server rejected connection.") logger.log_infomsg(auth_message) msg_info(auth_message) - return - + return + if pw_present: self.server_name = line_split[1] self.network_name = line_split[4] elif autosetup_present: - logger.log_infomsg("IMC2: Autosetup response found.") + logger.log_infomsg(_("IMC2: Autosetup response found.")) self.server_name = line_split[1] - self.network_name = line_split[3] + self.network_name = line_split[3] self.is_authenticated = True self.sequence = int(time()) - + # Log to stdout and notify over MUDInfo. - auth_message = "Successfully authenticated to the '%s' network." % self.factory.network + auth_message = _("Successfully authenticated to the '%s' network.") % self.factory.network logger.log_infomsg('IMC2: %s' % auth_message) msg_info(auth_message) - + # Ask to see what other MUDs are connected. self.send_packet(pck.IMC2PacketKeepAliveRequest()) # IMC2 protocol states that KeepAliveRequests should be followed @@ -226,7 +228,7 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): self.send_packet(pck.IMC2PacketIsAlive()) # Get a listing of channels. self.send_packet(pck.IMC2PacketIceRefresh()) - + def _msg_evennia(self, packet): """ Handle the sending of packet data to Evennia channel @@ -235,34 +237,35 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): conn_name = packet.optional_data.get('channel', None) # If the packet lacks the 'echo' key, don't bother with it. - if not conn_name or not packet.optional_data.get('echo', None): - return + if not conn_name or not packet.optional_data.get('echo', None): + return imc2_channel = conn_name.split(':', 1)[1] # Look for matching IMC2 channel maps mapping to this imc2 channel. conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_") conns = [conn for conn in conns if imc2_channel in conn.db_external_config.split(",")] if not conns: - # we are not listening to this imc2 channel. - return - + # we are not listening to this imc2 channel. + return + # Format the message to send to local channel(s). for conn in conns: - message = '[%s] %s@%s: %s' % (conn.channel.key, packet.sender, packet.origin, packet.optional_data.get('text')) + message = '[%s] %s@%s: %s' % (conn.channel.key, packet.sender, packet.origin, packet.optional_data.get('text')) conn.to_channel(message) - + def _format_tell(self, packet): """ - Handle tells over IMC2 by formatting the text properly + Handle tells over IMC2 by formatting the text properly """ - return "{c%s@%s{n {wpages (over IMC):{n %s" % (packet.sender, packet.origin, - packet.optional_data.get('text', 'ERROR: No text provided.')) + return _("{c%(sender)s@%(origin)s{n {wpages (over IMC):{n %(msg)s") % {"sender":packet.sender, + "origin":packet.origin, + "msg":packet.optional_data.get('text', 'ERROR: No text provided.')} def lineReceived(self, line): """ Triggered when text is received from the IMC2 network. Figures out what to do with the packet. - IMC2 -> Evennia + IMC2 -> Evennia """ line = line.strip() @@ -271,18 +274,18 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): else: if IMC2_DEBUG and not 'is-alive' in line: # if IMC2_DEBUG mode is on, print the contents of the packet - # to stdout. + # to stdout. logger.log_infomsg("IMC2: RECV> %s" % line) - + # Parse the packet and encapsulate it for easy access packet = pck.IMC2Packet(self.factory.mudname, packet_str=line) - + if IMC2_DEBUG and packet.packet_type not in ('is-alive', 'keepalive-request'): # Print the parsed packet's __str__ representation. # is-alive and keepalive-requests happen pretty frequently. # Don't bore us with them in stdout. logger.log_infomsg(str(packet)) - + # Figure out what kind of packet we're dealing with and hand it # off to the correct handler. @@ -305,9 +308,9 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): elif packet.packet_type == 'tell': player = search.players(packet.target) if not player: - return + return player[0].msg(self._format_tell(packet)) - + def msg_imc2(self, message, from_obj=None, packet_type="imcbroadcast", data=None): """ Called by Evennia to send a message through the imc2 connection @@ -319,33 +322,33 @@ class IMC2Protocol(telnet.StatefulTelnetProtocol): from_name = from_obj else: from_name = self.factory.mudname - + if packet_type == "imcbroadcast": - if type(data) == dict: - conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_", - db_channel=data.get("channel", "Unknown")) + if type(data) == dict: + conns = ExternalChannelConnection.objects.filter(db_external_key__startswith="imc2_", + db_channel=data.get("channel", "Unknown")) if not conns: return # we remove the extra channel info since imc2 supplies this anyway if ":" in message: header, message = [part.strip() for part in message.split(":", 1)] - # send the packet + # send the packet imc2_channel = conns[0].db_external_config.split(',')[0] # only send to the first channel self.send_packet(pck.IMC2PacketIceMsgBroadcasted(self.factory.servername, imc2_channel, from_name, message)) elif packet_type == "imctell": - # send a tell + # send a tell if type(data) == dict: target = data.get("target", "Unknown") destination = data.get("destination", "Unknown") self.send_packet(pck.IMC2PacketTell(from_name, target, destination, message)) - + elif packet_type == "imcwhois": - # send a whois request + # send a whois request if type(data) == dict: target = data.get("target", "Unknown") self.send_packet(pck.IMC2PacketWhois(from_obj.id, target)) - + class IMC2Factory(protocol.ClientFactory): """ Creates instances of the IMC2Protocol. Should really only ever @@ -353,24 +356,24 @@ class IMC2Factory(protocol.ClientFactory): """ protocol = IMC2Protocol - def __init__(self, network, port, mudname, client_pwd, server_pwd): + def __init__(self, network, port, mudname, client_pwd, server_pwd): self.pretty_key = "%s:%s(%s)" % (network, port, mudname) self.network = network sname, host = network.split(".", 1) self.servername = sname.strip() - self.port = port + self.port = port self.mudname = mudname self.protocol_version = '2' self.client_pwd = client_pwd - self.server_pwd = server_pwd + self.server_pwd = server_pwd - def clientConnectionFailed(self, connector, reason): - message = 'Connection failed: %s' % reason.getErrorMessage() + def clientConnectionFailed(self, connector, reason): + message = _('Connection failed: %s') % reason.getErrorMessage() msg_info(message) logger.log_errmsg('IMC2: %s' % message) def clientConnectionLost(self, connector, reason): - message = 'Connection lost: %s' % reason.getErrorMessage() + message = _('Connection lost: %s') % reason.getErrorMessage() msg_info(message) logger.log_errmsg('IMC2: %s' % message) @@ -386,10 +389,10 @@ def start_scripts(validate=False): Start all the needed scripts """ - if validate: + if validate: from src.scripts.models import ScriptDB ScriptDB.objects.validate() - return + return if not search.scripts("IMC2_Send_IsAlive"): create.create_script(Send_IsAlive) if not search.scripts("IMC2_Send_Keepalive_Request"): @@ -397,7 +400,7 @@ def start_scripts(validate=False): if not search.scripts("IMC2_Prune_Inactive_Muds"): create.create_script(Prune_Inactive_Muds) if not search.scripts("IMC2_Sync_Server_Channel_List"): - create.create_script(Sync_Server_Channel_List) + create.create_script(Sync_Server_Channel_List) def create_connection(channel, imc2_channel): """ @@ -407,61 +410,61 @@ def create_connection(channel, imc2_channel): if not type(channel) == Channel: new_channel = Channel.objects.filter(db_key=channel) if not new_channel: - logger.log_errmsg("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found" % channel) + logger.log_errmsg(_("Cannot attach IMC2<->Evennia: Evennia Channel '%s' not found") % channel) return False channel = new_channel[0] key = build_connection_key(channel, imc2_channel) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - # this evennia channel is already connected to imc. Check if imc2_channel is different. + # this evennia channel is already connected to imc. Check if imc2_channel is different. # connection already exists. We try to only connect a new channel - old_config = old_conns[0].db_external_config.split(",") + old_config = old_conns[0].db_external_config.split(",") if imc2_channel in old_config: return False # we already listen to this channel else: # We add a new imc2_channel to listen to old_config.append(imc2_channel) old_conns[0].db_external_config = ",".join(old_config) - old_conns[0].save() + old_conns[0].save() return True else: # no old connection found; create a new one. config = imc2_channel - # how the evennia channel will be able to contact this protocol in reverse + # how the evennia channel will be able to contact this protocol in reverse send_code = "from src.comms.imc2 import IMC2_CLIENT\n" send_code += "data={'channel':from_channel}\n" send_code += "IMC2_CLIENT.msg_imc2(message, from_obj=from_obj, data=data)\n" - conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, - db_external_config=config) - conn.save() - return True + conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, + db_external_config=config) + conn.save() + return True def delete_connection(channel, imc2_channel): "Destroy a connection" if hasattr(channel, "key"): channel = channel.key key = build_connection_key(channel, imc2_channel) - + try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except ExternalChannelConnection.DoesNotExist: - return False - conn.delete() - return True + return False + conn.delete() + return True def connect_to_imc2(): - "Create the imc instance and connect to the IMC2 network." + "Create the imc instance and connect to the IMC2 network." - # connect - imc = internet.TCPClient(IMC2_NETWORK, int(IMC2_PORT), IMC2Factory(IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME, + # connect + imc = internet.TCPClient(IMC2_NETWORK, int(IMC2_PORT), IMC2Factory(IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME, IMC2_CLIENT_PWD, IMC2_SERVER_PWD)) - imc.setName("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) + imc.setName("imc2_%s:%s(%s)" % (IMC2_NETWORK, IMC2_PORT, IMC2_MUDNAME)) SESSIONS.server.services.addService(imc) def connect_all(): """ - Activates the imc2 system. Called by the server if IMC2_ENABLED=True. + Activates the imc2 system. Called by the server if IMC2_ENABLED=True. """ connect_to_imc2() start_scripts() diff --git a/src/comms/imc2lib/imc2_ansi.py b/src/comms/imc2lib/imc2_ansi.py index d561e9329d..25fe055bea 100644 --- a/src/comms/imc2lib/imc2_ansi.py +++ b/src/comms/imc2lib/imc2_ansi.py @@ -1,6 +1,6 @@ """ ANSI parser - this adds colour to text according to -special markup strings. +special markup strings. This is a IMC2 complacent version. """ @@ -14,9 +14,9 @@ class IMCANSIParser(ansi.ANSIParser): """ def __init__(self): normal = ansi.ANSI_NORMAL - hilite = ansi.ANSI_HILITE + hilite = ansi.ANSI_HILITE self.ansi_map = [ - (r'~Z', normal), # Random + (r'~Z', normal), # Random (r'~x', normal + ansi.ANSI_BLACK), # Black (r'~D', hilite + ansi.ANSI_BLACK), # Dark Grey (r'~z', hilite + ansi.ANSI_BLACK), @@ -25,21 +25,21 @@ class IMCANSIParser(ansi.ANSIParser): (r'~g', normal + ansi.ANSI_GREEN), # Dark Green (r'~G', hilite + ansi.ANSI_GREEN), # Green (r'~p', normal + ansi.ANSI_MAGENTA), # Dark magenta - (r'~m', normal + ansi.ANSI_MAGENTA), + (r'~m', normal + ansi.ANSI_MAGENTA), (r'~M', hilite + ansi.ANSI_MAGENTA), # Magenta (r'~P', hilite + ansi.ANSI_MAGENTA), (r'~c', normal + ansi.ANSI_CYAN), # Cyan (r'~y', normal + ansi.ANSI_YELLOW), # Dark Yellow (brown) - (r'~Y', hilite + ansi.ANSI_YELLOW), # Yellow + (r'~Y', hilite + ansi.ANSI_YELLOW), # Yellow (r'~b', normal + ansi.ANSI_BLUE), # Dark Blue (r'~B', hilite + ansi.ANSI_BLUE), # Blue - (r'~C', hilite + ansi.ANSI_BLUE), + (r'~C', hilite + ansi.ANSI_BLUE), (r'~r', normal + ansi.ANSI_RED), # Dark Red - (r'~R', hilite + ansi.ANSI_RED), # Red + (r'~R', hilite + ansi.ANSI_RED), # Red ## Formatting (r'~L', hilite), # Bold/hilite - (r'~!', normal), # reset + (r'~!', normal), # reset (r'\\r', normal), (r'\\n', ansi.ANSI_RETURN), ] @@ -51,7 +51,7 @@ class IMCANSIParser(ansi.ANSIParser): ANSI_PARSER = IMCANSIParser() - + def parse_ansi(string, strip_ansi=False, parser=ANSI_PARSER): """ Shortcut to use the IMC2 ANSI parser. diff --git a/src/comms/imc2lib/imc2_listeners.py b/src/comms/imc2lib/imc2_listeners.py index 88dec66500..bef1b4ae04 100644 --- a/src/comms/imc2lib/imc2_listeners.py +++ b/src/comms/imc2lib/imc2_listeners.py @@ -5,6 +5,8 @@ This module handles some of the -reply packets like whois-reply. from src.objects.models import ObjectDB from src.comms.imc2lib import imc2_ansi +from django.utils.translation import ugettext as _ + def handle_whois_reply(packet): """ When the player sends an imcwhois request, the outgoing @@ -15,7 +17,7 @@ def handle_whois_reply(packet): try: pobject = ObjectDB.objects.get(id=packet.target) response_text = imc2_ansi.parse_ansi(packet.optional_data.get('text', 'Unknown')) - string = 'Whois reply from %s: %s' % (packet.origin, response_text) + string = _('Whois reply from %(origin)s: %(msg)s') % {"origin":packet.origin, "msg":response_text} pobject.msg(string.strip()) except ObjectDB.DoesNotExist: # No match found for whois sender. Ignore it. diff --git a/src/comms/imc2lib/imc2_packets.py b/src/comms/imc2lib/imc2_packets.py index 9f51f06a74..b427f14a6c 100644 --- a/src/comms/imc2lib/imc2_packets.py +++ b/src/comms/imc2lib/imc2_packets.py @@ -4,7 +4,7 @@ http://www.mudbytes.net/index.php?a=articles&s=imc2_protocol """ import shlex -from django.conf import settings +from django.conf import settings class Lexxer(shlex.shlex): """ @@ -28,7 +28,7 @@ class IMC2Packet(object): Optionally, parse a packet and load it up. """ # The following fields are all according to the basic packet format of: - # @ @ + # @ @ self.sender = None if not mudname: mudname = settings.SERVERNAME @@ -42,13 +42,13 @@ class IMC2Packet(object): self.optional_data = {} # Reference to the IMC2Protocol object doing the sending. self.imc2_protocol = None - + if packet_str: # The lexxer handles the double quotes correctly, unlike just # splitting. Spaces throw things off, so shlex handles it # gracefully, ala POSIX shell-style parsing. lex = Lexxer(packet_str) - + # Token counter. counter = 0 for token in lex: @@ -90,7 +90,7 @@ class IMC2Packet(object): pass # Increment and continue to the next token (if applicable) counter += 1 - + def __str__(self): retval = """ --IMC2 package (%s) @@ -101,15 +101,15 @@ class IMC2Packet(object): Type: %s Target: %s Dest.: %s - Data: - %s + Data: + %s ------------------------""" % (self.packet_type, self.sender, self.origin, self.sequence, self.route, self.packet_type, self.target, self.destination, "\n ".join(["%s: %s" % items for items in self.optional_data.items()])) return retval.strip() - + def _get_optional_data_string(self): """ Generates the optional data string to tack on to the end of the packet. @@ -126,7 +126,7 @@ class IMC2Packet(object): return data_string.strip() else: return '' - + def _get_sender_name(self): """ Calculates the sender name to be sent with the packet. @@ -139,9 +139,9 @@ class IMC2Packet(object): elif type(self.sender) in [type(u""),type(str())]: #this is used by e.g. IRC where no user object is present. return self.sender.strip().replace(' ', '_') - elif self.sender: + elif self.sender: # Player object. - name = self.sender.get_name(fullname=False, show_dbref=False, + name = self.sender.get_name(fullname=False, show_dbref=False, show_flags=False, no_ansi=True) # IMC2 does not allow for spaces. @@ -149,12 +149,12 @@ class IMC2Packet(object): else: # None value. Do something or other. return 'Unknown' - + def assemble(self, mudname=None, client_pwd=None, server_pwd=None): """ Assembles the packet and returns the ready-to-send string. - Note that the arguments are not used, they are there for - consistency across all packets. + Note that the arguments are not used, they are there for + consistency across all packets. """ self.sequence = self.imc2_protocol.sequence packet = "%s@%s %s %s %s %s@%s %s\n" % ( @@ -167,29 +167,29 @@ class IMC2Packet(object): self.destination, self._get_optional_data_string()) return packet.strip() - + class IMC2PacketAuthPlaintext(object): """ IMC2 plain-text authentication packet. Auth packets are strangely formatted, so this does not sub-class IMC2Packet. The SHA and plain text auth packets are the two only non-conformers. - - CLIENT Sends: + + CLIENT Sends: PW version= autosetup (SHA256) - + Optional Arguments( required if using the specified authentication method: - (SHA256) The literal string: SHA256. This is sent to notify the server - that the MUD is SHA256-Enabled. All future logins from this - client will be expected in SHA256-AUTH format if the server - supports it. - """ + (SHA256) The literal string: SHA256. This is sent to notify the server + that the MUD is SHA256-Enabled. All future logins from this + client will be expected in SHA256-AUTH format if the server + supports it. + """ def assemble(self, mudname=None, client_pwd=None, server_pwd=None): """ This is one of two strange packets, just assemble the packet manually and go. """ return 'PW %s %s version=2 autosetup %s\n' %(mudname, client_pwd, server_pwd) - + class IMC2PacketKeepAliveRequest(IMC2Packet): """ Description: @@ -197,15 +197,15 @@ class IMC2PacketKeepAliveRequest(IMC2Packet): This packet is usually followed by the sending MUD's own is-alive packet. It is used in the filling of a client's MUD list, thus any MUD that doesn't respond with an is-alive isn't marked as online on the sending MUD's mudlist. - + Data: (none) - + Example of a received keepalive-request: *@YourMUD 1234567890 YourMUD!Hub1 keepalive-request *@* - + Example of a sent keepalive-request: - *@YourMUD 1234567890 YourMUD keepalive-request *@* + *@YourMUD 1234567890 YourMUD keepalive-request *@* """ def __init__(self): super(IMC2PacketKeepAliveRequest, self).__init__() @@ -213,40 +213,40 @@ class IMC2PacketKeepAliveRequest(IMC2Packet): self.packet_type = 'keepalive-request' self.target = '*' self.destination = '*' - + class IMC2PacketIsAlive(IMC2Packet): """ Description: - This packet is the reply to a keepalive-request packet. It is responsible + This packet is the reply to a keepalive-request packet. It is responsible for filling a client's mudlist with the information about other MUDs on the network. - + Data: - versionid= + versionid= Where is the text version ID of the client. ("IMC2 4.5 MUD-Net") - - url= + + url= Where is the proper URL of the client. (http://www.domain.com) - - host= + + host= Where is the telnet address of the MUD. (telnet://domain.com) - - port= + + port= Where is the telnet port of the MUD. - + (These data fields are not sent by the MUD, they are added by the server.) - networkname= + networkname= Where is the network name that the MUD/server is on. ("MyNetwork") - + sha256= - This is an optional tag that denotes the SHA-256 capabilities of a + This is an optional tag that denotes the SHA-256 capabilities of a MUD or server. - + Example of a received is-alive: *@SomeMUD 1234567890 SomeMUD!Hub2 is-alive *@YourMUD versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" networkname="MyNetwork" sha256=1 host=domain.com port=5500 - + Example of a sent is-alive: - *@YourMUD 1234567890 YourMUD is-alive *@* versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" host=domain.com port=5500 + *@YourMUD 1234567890 YourMUD is-alive *@* versionid="IMC2 4.5 MUD-Net" url="http://www.domain.com" host=domain.com port=5500 """ def __init__(self): super(IMC2PacketIsAlive, self).__init__() @@ -258,19 +258,19 @@ class IMC2PacketIsAlive(IMC2Packet): 'url': '"http://www.evennia.com"', 'host': 'test.com', 'port': '5555'} - + class IMC2PacketIceRefresh(IMC2Packet): """ Description: - This packet is sent by the MUD to request data about the channels on the - network. Servers with channels reply with an ice-update packet for each + This packet is sent by the MUD to request data about the channels on the + network. Servers with channels reply with an ice-update packet for each channel they control. The usual target for this packet is IMC@$. - + Data: (none) - + Example: - *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$ + *@YourMUD 1234567890 YourMUD!Hub1 ice-refresh IMC@$ """ def __init__(self): super(IMC2PacketIceRefresh, self).__init__() @@ -284,40 +284,40 @@ class IMC2PacketIceUpdate(IMC2Packet): Description: A server returns this packet with the data of a channel when prompted with an ice-refresh request. - + Data: - channel= + channel= The channel's network name in the format of ServerName:ChannelName - - owner= + + owner= The Name@MUD of the channel's owner - - operators= + + operators= A space-seperated list of the Channel's operators, in the format of Person@MUD - + policy= The policy is either "open" or "private" with no quotes. - + invited= - The space-seperated list of invited User@MUDs, only valid for a + The space-seperated list of invited User@MUDs, only valid for a "private" channel. - + excluded= - The space-seperated list of banned User@MUDs, only valid for "open" + The space-seperated list of banned User@MUDs, only valid for "open" channels. - - level= The default level of the channel: Admin, Imp, Imm, + + level= The default level of the channel: Admin, Imp, Imm, Mort, or None - + localname= The suggested local name of the channel. - + Examples: - + Open Policy: ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:ichat owner=Imm@SomeMUD operators=Other@SomeMUD policy=open excluded="Flamer@badMUD Jerk@dirtyMUD" level=Imm localname=ichat - + Private Policy: - ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:secretchat owner=Imm@SomeMUD operators=Other@SomeMUD policy=private invited="SpecialDude@OtherMUD CoolDude@WeirdMUD" level=Mort localname=schat + ICE@Hub1 1234567890 Hub1!Hub2 ice-update *@YourMUD channel=Hub1:secretchat owner=Imm@SomeMUD operators=Other@SomeMUD policy=private invited="SpecialDude@OtherMUD CoolDude@WeirdMUD" level=Mort localname=schat """ pass @@ -328,29 +328,29 @@ class IMC2PacketIceMsgRelayed(IMC2Packet): ice-msg-p packet, are used with private policy channels. The 'r' stands for 'relay'. All incoming channel messages are from ICE@, where is the server hosting the channel. - + Data: - realfrom= + realfrom= The User@MUD the message came from. - - channel= + + channel= The Server:Channel the message is intended to be displayed on. - - text= + + text= The message text. - - emote= - An integer value designating emotes. 0 for no emote, 1 for an emote, + + emote= + An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + Examples: ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="Aha! I got it!" emote=0 - + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text=Ahh emote=0 - + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="grins evilly." emote=1 - - ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="You@YourMUD grins evilly!" emote=2 + + ICE@Hub1 1234567890 Hub1!Hub2 ice-msg-r *@YourMUD realfrom=You@YourMUD channel=hub1:secret text="You@YourMUD grins evilly!" emote=2 """ pass @@ -360,27 +360,27 @@ class IMC2PacketIceMsgPrivate(IMC2Packet): This packet is sent when a player sends a message to a private channel. This packet should never be seen as incoming to a client. The target of this packet should be IMC@ of the server hosting the channel. - + Data: - channel= + channel= The Server:Channel the message is intended to be displayed on. - + text= The message text. - + emote= An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + echo= Tells the server to echo the message back to the sending MUD. This is only seen on out-going messages. - + Examples: You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="Ahh! I got it!" emote=0 echo=1 You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text=Ahh! emote=0 echo=1 You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="grins evilly." emote=1 echo=1 - You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="You@YourMUD grins evilly." emote=2 echo=1 + You@YourMUD 1234567890 YourMUD ice-msg-p IMC@Hub1 channel=Hub1:secret text="You@YourMUD grins evilly." emote=2 echo=1 """ pass @@ -392,34 +392,34 @@ class IMC2PacketIceMsgBroadcasted(IMC2Packet): as it was sent by the originating MUD. The server that hosts the channel sends the packet back to the originating MUD as an 'echo' by removing the "echo=1" and attaching the "sender=Person@MUD" data field. - + Data: channel= The Server:Channel the message is intended to be displayed on. - + text= The message text. - + emote= - An integer value designating emotes. 0 for no emote, 1 for an emote, + An integer value designating emotes. 0 for no emote, 1 for an emote, and 2 for a social. - + *echo= This stays on broadcasted messages. It tells the channel's server to relay an echo back. - + *sender= The hosting server replaces "echo=1" with this when sending the echo back to the originating MUD. - - Examples: + + Examples: (See above for emote/social examples as they are pretty much the same) - + Return Echo Packet: You-YourMUD@Hub1 1234567890 Hub1 ice-msg-b *@YourMUD text=Hi! channel=Hub1:ichat sender=You@YourMUD emote=0 - + Broadcasted Packet: - You@YourMUD 1234567890 YourMUD!Hub1 ice-msg-b *@* channel=Hub1:ichat text=Hi! emote=0 echo=1 + You@YourMUD 1234567890 YourMUD!Hub1 ice-msg-b *@* channel=Hub1:ichat text=Hi! emote=0 echo=1 """ def __init__(self, server, channel, pobject, message): """ @@ -445,27 +445,27 @@ class IMC2PacketUserCache(IMC2Packet): Sent by a MUD with a new IMC2-able player or when a player's gender changes, this packet contains only the gender for data. The packet's origination should be the Player@MUD. - + Data: gender= 0 is male, 1 is female, 2 is anything else such as neuter. Will be referred to as "it". - + Example: - Dude@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache *@* gender=0 + Dude@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache *@* gender=0 """ pass class IMC2PacketUserCacheRequest(IMC2Packet): """ Description: - The MUD sends this packet out when making a request for the user-cache + The MUD sends this packet out when making a request for the user-cache information of the user included in the data part of the packet. - + Data: user= The Person@MUD whose data the MUD is seeking. - + Example: - *@YourMUD 1234567890 YourMUD user-cache-request *@SomeMUD user=Dude@SomeMUD + *@YourMUD 1234567890 YourMUD user-cache-request *@SomeMUD user=Dude@SomeMUD """ pass @@ -474,16 +474,16 @@ class IMC2PacketUserCacheReply(IMC2Packet): Description: A reply to the user-cache-request packet. It contains the user and gender for the user. - + Data: user= The Person@MUD whose data the MUD requested. - + gender= The gender of the Person@MUD in the 'user' field. - + Example: - *@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache-reply *@YourMUD user=Dude@SomeMUD gender=0 + *@someMUD 1234567890 SomeMUD!Hub2!Hub1 user-cache-reply *@YourMUD user=Dude@SomeMUD gender=0 """ pass @@ -492,18 +492,18 @@ class IMC2PacketTell(IMC2Packet): Description: This packet is used to communicate private messages between users on MUDs across the network. - + Data: text= Message text isreply= Two settings: 1 denotes a reply, 2 denotes a tell social. - + Example: - + Originating: You@YourMUD 1234567890 YourMUD tell Dude@SomeMUD text="Having fun?" - + Reply from Dude: - Dude@SomeMUD 1234567890 SomeMUD!Hub1 tell You@YourMUD text="Yeah, this is cool!" isreply=1 + Dude@SomeMUD 1234567890 SomeMUD!Hub1 tell You@YourMUD text="Yeah, this is cool!" isreply=1 """ def __init__(self, pobject, target, destination, message): super(IMC2PacketTell, self).__init__() @@ -511,94 +511,94 @@ class IMC2PacketTell(IMC2Packet): self.packet_type = "tell" self.target = target self.destination = destination - self.optional_data = {"text": message, + self.optional_data = {"text": message, "isreply":None} - + def assemble(self, mudname=None, client_pwd=None, server_pwd=None): self.sequence = self.imc2_protocol.sequence #self.route = "%s!%s" % (self.origin, self.imc2_protocol.factory.servername.capitalize()) - return '''"%s@%s %s %s tell %s@%s text="%s"''' % (self.sender, self.origin, self.sequence, - self.route, self.target, self.destination, + return '''"%s@%s %s %s tell %s@%s text="%s"''' % (self.sender, self.origin, self.sequence, + self.route, self.target, self.destination, self.optional_data.get("text","NO TEXT GIVEN")) - + class IMC2PacketEmote(IMC2Packet): """ Description: This packet seems to be sent by servers when notifying the network of a new channel or the destruction of a channel. - + Data: - channel= - Unsure of what this means. The channel seen in both creation and + channel= + Unsure of what this means. The channel seen in both creation and destruction packets is 15. - + level= I am assuming this is the permission level of the sender. In both creation and destruction messages, this is -1. - + text= This is the message to be sent to the users. - + Examples: - ICE@Hub1 1234567890 Hub1 emote *@* channel=15 level=-1 text="the channel called hub1:test has been destroyed by You@YourMUD." + ICE@Hub1 1234567890 Hub1 emote *@* channel=15 level=-1 text="the channel called hub1:test has been destroyed by You@YourMUD." """ pass class IMC2PacketRemoteAdmin(IMC2Packet): """ Description: - This packet is used in remote server administration. Please note that - SHA-256 Support is *required* for a client to use this feature. The command - can vary, in fact this very packet is highly dependant on the server it's - being directed to. In most cases, sending the 'list' command will have a + This packet is used in remote server administration. Please note that + SHA-256 Support is *required* for a client to use this feature. The command + can vary, in fact this very packet is highly dependant on the server it's + being directed to. In most cases, sending the 'list' command will have a remote-admin enabled server send you the list of commands it will accept. - + Data: - command= + command= The command being sent to the server for processing. - - data= + + data= Data associated with the command. This is not always required. - - hash= - The SHA-256 hash that is verified by the server. This hash is generated in + + hash= + The SHA-256 hash that is verified by the server. This hash is generated in the same manner as an authentication packet. - + Example: - You@YourMUD 1234567890 YourMUD remote-admin IMC@Hub1 command=list hash= + You@YourMUD 1234567890 YourMUD remote-admin IMC@Hub1 command=list hash= """ pass class IMC2PacketIceCmd(IMC2Packet): """ Description: - Used for remote channel administration. In most cases, one must be listed - as a channel creator on the target server in order to do much with this + Used for remote channel administration. In most cases, one must be listed + as a channel creator on the target server in order to do much with this packet. Other cases include channel operators. - + Data: - channel= + channel= The target server:channel for the command. - - command= + + command= The command to be processed. - - data= + + data= Data associated with the command. This is not always required. - + Example: - You@YourMUD 1234567890 YourMUD ice-cmd IMC@hub1 channel=hub1:ichat command=list + You@YourMUD 1234567890 YourMUD ice-cmd IMC@hub1 channel=hub1:ichat command=list """ pass class IMC2PacketDestroy(IMC2Packet): """ Description: - Sent by a server to indicate the destruction of a channel it hosted. + Sent by a server to indicate the destruction of a channel it hosted. The mud should remove this channel from its local configuration. - + Data: - channel= The server:channel being destroyed. + channel= The server:channel being destroyed. """ pass @@ -606,39 +606,39 @@ class IMC2PacketWho(IMC2Packet): """ Description: A seemingly mutli-purpose information-requesting packet. The istats - packet currently only works on servers, or at least that's the case on - MUD-Net servers. The 'finger' type takes a player name in addition to the + packet currently only works on servers, or at least that's the case on + MUD-Net servers. The 'finger' type takes a player name in addition to the type name. - - Example: "finger Dude". The 'who' and 'info' types take no argument. - The MUD is responsible for building the reply text sent in the who-reply + + Example: "finger Dude". The 'who' and 'info' types take no argument. + The MUD is responsible for building the reply text sent in the who-reply packet. - + Data: type= Types: who, info, "finger ", istats (server only) - + Example: - Dude@SomeMUD 1234567890 SomeMUD!Hub1 who *@YourMUD type=who + Dude@SomeMUD 1234567890 SomeMUD!Hub1 who *@YourMUD type=who """ pass class IMC2PacketWhoReply(IMC2Packet): """ Description: - The multi-purpose reply to the multi-purpose information-requesting 'who' - packet. The MUD is responsible for building the return data, including the - format of it. The mud can use the permission level sent in the original who + The multi-purpose reply to the multi-purpose information-requesting 'who' + packet. The MUD is responsible for building the return data, including the + format of it. The mud can use the permission level sent in the original who packet to filter the output. The example below is the MUD-Net format. - + Data: text= The formatted reply to a 'who' packet. - + Additional Notes: - The example below is for the who list packet. The same construction would + The example below is for the who list packet. The same construction would go into formatting the other types of who packets. - + Example: - *@YourMUD 1234567890 YourMUD who-reply Dude@SomeMUD text="\n\r~R-=< ~WPlayers on YourMUD ~R>=-\n\r ~Y-=< ~Wtelnet://yourmud.domain.com:1234 ~Y>=-\n\r\n\r~B--------------------------------=< ~WPlayers ~B>=---------------------------------\n\r\n\r ~BPlayer ~z<--->~G Mortal the Toy\n\r\n\r~R-------------------------------=< ~WImmortals ~R>=--------------------------------\n\r\n\r ~YStaff ~z<--->~G You the Immortal\n\r\n\r~Y<~W2 Players~Y> ~Y<~WHomepage: http://www.yourmud.com~Y> <~W 2 Max Since Reboot~Y>\n\r~Y<~W3 logins since last reboot on Tue Feb 24, 2004 6:55:59 PM EST~Y>" + *@YourMUD 1234567890 YourMUD who-reply Dude@SomeMUD text="\n\r~R-=< ~WPlayers on YourMUD ~R>=-\n\r ~Y-=< ~Wtelnet://yourmud.domain.com:1234 ~Y>=-\n\r\n\r~B--------------------------------=< ~WPlayers ~B>=---------------------------------\n\r\n\r ~BPlayer ~z<--->~G Mortal the Toy\n\r\n\r~R-------------------------------=< ~WImmortals ~R>=--------------------------------\n\r\n\r ~YStaff ~z<--->~G You the Immortal\n\r\n\r~Y<~W2 Players~Y> ~Y<~WHomepage: http://www.yourmud.com~Y> <~W 2 Max Since Reboot~Y>\n\r~Y<~W3 logins since last reboot on Tue Feb 24, 2004 6:55:59 PM EST~Y>" """ pass @@ -646,12 +646,12 @@ class IMC2PacketWhois(IMC2Packet): """ Description: Sends a request to the network for the location of the specified player. - + Data: level= The permission level of the person making the request. - + Example: - You@YourMUD 1234567890 YourMUD whois dude@* level=5 + You@YourMUD 1234567890 YourMUD whois dude@* level=5 """ def __init__(self, pobject_id, whois_target): super(IMC2PacketWhois, self).__init__() @@ -664,98 +664,98 @@ class IMC2PacketWhois(IMC2Packet): class IMC2PacketWhoisReply(IMC2Packet): """ Description: - The reply to a whois packet. The MUD is responsible for building and formatting - the text sent back to the requesting player, and can use the permission level + The reply to a whois packet. The MUD is responsible for building and formatting + the text sent back to the requesting player, and can use the permission level sent in the original whois packet to filter or block the response. - + Data: text= The whois text. - + Example: - *@SomeMUD 1234567890 SomeMUD!Hub1 whois-reply You@YourMUD text="~RIMC Locate: ~YDude@SomeMUD: ~cOnline.\n\r" + *@SomeMUD 1234567890 SomeMUD!Hub1 whois-reply You@YourMUD text="~RIMC Locate: ~YDude@SomeMUD: ~cOnline.\n\r" """ pass class IMC2PacketBeep(IMC2Packet): """ Description: - Sends out a beep packet to the Player@MUD. The client receiving this should + Sends out a beep packet to the Player@MUD. The client receiving this should then send a bell-character to the target player to 'beep' them. - + Example: - You@YourMUD 1234567890 YourMUD beep dude@somemud + You@YourMUD 1234567890 YourMUD beep dude@somemud """ pass class IMC2PacketIceChanWho(IMC2Packet): """ Description: - Sends a request to the specified MUD or * to list all the users listening + Sends a request to the specified MUD or * to list all the users listening to the specified channel. - + Data: - level= + level= Sender's permission level. - - channel= + + channel= The server:chan name of the channel. - - lname= + + lname= The localname of the channel. - + Example: - You@YourMUD 1234567890 YourMUD ice-chan-who somemud level=5 channel=Hub1:ichat lname=ichat + You@YourMUD 1234567890 YourMUD ice-chan-who somemud level=5 channel=Hub1:ichat lname=ichat """ pass class IMC2PacketIceChanWhoReply(IMC2Packet): """ Description: - This is the reply packet for an ice-chan-who. The MUD is responsible for - creating and formatting the list sent back in the 'list' field. The - permission level sent in the original ice-chan-who packet can be used to + This is the reply packet for an ice-chan-who. The MUD is responsible for + creating and formatting the list sent back in the 'list' field. The + permission level sent in the original ice-chan-who packet can be used to filter or block the response. - + Data: - channel= + channel= The server:chan of the requested channel. - - list= + + list= The formatted list of local listeners for that MUD. - + Example: - *@SomeMUD 1234567890 SomeMUD!Hub1 ice-chan-whoreply You@YourMUD channel=Hub1:ichat list="The following people are listening to ichat on SomeMUD:\n\r\n\rDude\n\r" + *@SomeMUD 1234567890 SomeMUD!Hub1 ice-chan-whoreply You@YourMUD channel=Hub1:ichat list="The following people are listening to ichat on SomeMUD:\n\r\n\rDude\n\r" """ pass class IMC2PacketLaston(IMC2Packet): """ Description: - This packet queries the server the mud is connected to to find out when a + This packet queries the server the mud is connected to to find out when a specified user was last seen by the network on a public channel. - + Data: - username= The user, user@mud, or "all" being queried. Responses + username= The user, user@mud, or "all" being queried. Responses to this packet will be sent by the server in the form of a series of tells. - - Example: User@MUD 1234567890 MUD imc-laston SERVER username=somenamehere + + Example: User@MUD 1234567890 MUD imc-laston SERVER username=somenamehere """ pass class IMC2PacketCloseNotify(IMC2Packet): """ Description: - This packet alerts the network when a server or MUD has disconnected. The - server hosting the server or MUD is responsible for sending this packet - out across the network. Clients need only process the packet to remove the + This packet alerts the network when a server or MUD has disconnected. The + server hosting the server or MUD is responsible for sending this packet + out across the network. Clients need only process the packet to remove the disconnected MUD from their MUD list (or mark it as Disconnected). - + Data: - host= + host= The MUD or server that has disconnected from the network. - + Example: - *@Hub2 1234567890 Hub2!Hub1 close-notify *@* host=DisconnMUD + *@Hub2 1234567890 Hub2!Hub1 close-notify *@* host=DisconnMUD """ pass @@ -763,4 +763,4 @@ if __name__ == "__main__": packstr = "Kayle@MW 1234567 MW!Server02!Server01 ice-msg-b *@* channel=Server01:ichat text=\"*they're going woot\" emote=0 echo=1" packstr = "*@Lythelian 1234567 Lythelian!Server01 is-alive *@* versionid=\"Tim's LPC IMC2 client 30-Jan-05 / Dead Souls integrated\" networkname=Mudbytes url=http://dead-souls.net host=70.32.76.142 port=6666 sha256=0" print IMC2Packet(packstr) - + diff --git a/src/comms/imc2lib/imc2_trackers.py b/src/comms/imc2lib/imc2_trackers.py index f2ce2bf45c..f38d1fdfd7 100644 --- a/src/comms/imc2lib/imc2_trackers.py +++ b/src/comms/imc2lib/imc2_trackers.py @@ -2,7 +2,7 @@ Certain periodic packets are sent by connected MUDs (is-alive, user-cache, etc). The IMC2 protocol assumes that each connected MUD will capture these and populate/maintain their own lists of other servers connected. This module -contains stuff like this. +contains stuff like this. """ from time import time @@ -20,7 +20,7 @@ class IMC2Mud(object): self.sha256 = packet.optional_data.get('sha256', None) # This is used to determine when a Mud has fallen into inactive status. self.last_updated = time() - + class IMC2MudList(object): """ Keeps track of other MUDs connected to the IMC network. @@ -28,7 +28,7 @@ class IMC2MudList(object): def __init__(self): # Mud list is stored in a dict, key being the IMC Mud name. self.mud_list = {} - + def get_mud_list(self): """ Returns a sorted list of connected Muds. @@ -36,7 +36,7 @@ class IMC2MudList(object): muds = self.mud_list.items() muds.sort() return [value for key, value in muds] - + def update_mud_from_packet(self, packet): """ This grabs relevant info from the packet and stuffs it in the @@ -44,7 +44,7 @@ class IMC2MudList(object): """ mud = IMC2Mud(packet) self.mud_list[mud.name] = mud - + def remove_mud_from_packet(self, packet): """ Removes a mud from the Mud list when given a packet. @@ -55,7 +55,7 @@ class IMC2MudList(object): except KeyError: # No matching entry, no big deal. pass - + class IMC2Channel(object): """ Stores information about channels available on the network. @@ -67,7 +67,7 @@ class IMC2Channel(object): self.owner = packet.optional_data.get('owner', None) self.policy = packet.optional_data.get('policy', None) self.last_updated = time() - + class IMC2ChanList(object): """ Keeps track of other MUDs connected to the IMC network. @@ -75,7 +75,7 @@ class IMC2ChanList(object): def __init__(self): # Chan list is stored in a dict, key being the IMC Mud name. self.chan_list = {} - + def get_channel_list(self): """ Returns a sorted list of cached channels. @@ -83,7 +83,7 @@ class IMC2ChanList(object): channels = self.chan_list.items() channels.sort() return [value for key, value in channels] - + def update_channel_from_packet(self, packet): """ This grabs relevant info from the packet and stuffs it in the @@ -91,7 +91,7 @@ class IMC2ChanList(object): """ channel = IMC2Channel(packet) self.chan_list[channel.name] = channel - + def remove_channel_from_packet(self, packet): """ Removes a channel from the Channel list when given a packet. diff --git a/src/comms/irc.py b/src/comms/irc.py index f66798b8e7..f61ddae70d 100644 --- a/src/comms/irc.py +++ b/src/comms/irc.py @@ -11,6 +11,8 @@ from src.comms.models import ExternalChannelConnection, Channel from src.utils import logger, utils from src.server.sessionhandler import SESSIONS +from django.utils.translation import ugettext as _ + INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) IRC_CHANNELS = [] @@ -27,77 +29,77 @@ def msg_info(message): class IRC_Bot(irc.IRCClient): """ This defines an IRC bot that connects to an IRC channel - and relays data to and from an evennia game. + and relays data to and from an evennia game. """ - + def _get_nickname(self): "required for correct nickname setting" return self.factory.nickname nickname = property(_get_nickname) - - def signedOn(self): + + def signedOn(self): # This is the first point the protocol is instantiated. # add this protocol instance to the global list so we - # can access it later to send data. + # can access it later to send data. global IRC_CHANNELS self.join(self.factory.channel) - IRC_CHANNELS.append(self) + IRC_CHANNELS.append(self) #msg_info("Client connecting to %s.'" % (self.factory.channel)) - + def joined(self, channel): - msg = "joined %s." % self.factory.pretty_key + msg = _("joined %s.") % self.factory.pretty_key msg_info(msg) logger.log_infomsg(msg) def privmsg(self, user, irc_channel, msg): - "Someone has written something in irc channel. Echo it to the evennia channel" - #find irc->evennia channel mappings + "Someone has written something in irc channel. Echo it to the evennia channel" + #find irc->evennia channel mappings conns = ExternalChannelConnection.objects.filter(db_external_key=self.factory.key) if not conns: - return - #format message: + return + #format message: user = user.split("!")[0] if user: user.strip() else: - user = "Unknown" + user = _("Unknown") msg = "[%s] %s@%s: %s" % (self.factory.evennia_channel, user, irc_channel, msg.strip()) - #logger.log_infomsg("channel connection. + This will create a new IRC<->channel connection. """ if not type(channel) == Channel: new_channel = Channel.objects.filter(db_key=channel) if not new_channel: - logger.log_errmsg("Cannot attach IRC<->Evennia: Evennia Channel '%s' not found" % channel) + logger.log_errmsg(_("Cannot attach IRC<->Evennia: Evennia Channel '%s' not found") % channel) return False channel = new_channel[0] key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - return False + return False config = "%s|%s|%s|%s" % (irc_network, irc_port, irc_channel, irc_bot_nick) # how the channel will be able to contact this protocol - send_code = "from src.comms.irc import IRC_CHANNELS\n" + send_code = "from src.comms.irc import IRC_CHANNELS\n" send_code += "matched_ircs = [irc for irc in IRC_CHANNELS if irc.factory.key == '%s']\n" % key send_code += "[irc.msg_irc(message, from_obj=from_obj) for irc in matched_ircs]\n" - conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, - db_external_config=config) + conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_send_code=send_code, + db_external_config=config) conn.save() - # connect + # connect connect_to_irc(conn) - return True + return True def delete_connection(channel, irc_network, irc_port, irc_channel, irc_bot_nick): "Destroy a connection" if hasattr(channel, 'key'): channel = channel.key - key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) + key = build_connection_key(channel, irc_network, irc_port, irc_channel, irc_bot_nick) service_key = build_service_key(key) try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except Exception: - return False - conn.delete() + return False + conn.delete() try: service = SESSIONS.server.services.getServiceNamed(service_key) except Exception: - return True - if service.running: + return True + if service.running: SESSIONS.server.services.removeService(service) - return True + return True def connect_to_irc(connection): - "Create the bot instance and connect to the IRC network and channel." + "Create the bot instance and connect to the IRC network and channel." # get config key = utils.to_str(connection.external_key) service_key = build_service_key(key) irc_network, irc_port, irc_channel, irc_bot_nick = [utils.to_str(conf) for conf in connection.external_config.split('|')] - # connect - bot = internet.TCPClient(irc_network, int(irc_port), IRCbotFactory(key, irc_channel, irc_network, irc_port, irc_bot_nick, + # connect + bot = internet.TCPClient(irc_network, int(irc_port), IRCbotFactory(key, irc_channel, irc_network, irc_port, irc_bot_nick, connection.channel.key)) bot.setName(service_key) SESSIONS.server.services.addService(bot) def connect_all(): """ - Activate all irc bots. + Activate all irc bots. """ for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith='irc_'): connect_to_irc(connection) - + diff --git a/src/comms/managers.py b/src/comms/managers.py index 955c172a08..411bcdc4dc 100644 --- a/src/comms/managers.py +++ b/src/comms/managers.py @@ -1,5 +1,5 @@ """ -These managers handles the +These managers handles the """ import itertools @@ -18,7 +18,7 @@ def to_object(inp, objtype='player'): Locates the object related to the given playername or channel key. If input was already the correct object, return it. - inp - the input object/string + inp - the input object/string objtype - 'player' or 'channel' """ from src.players.models import PlayerDB @@ -30,43 +30,43 @@ def to_object(inp, objtype='player'): else: umatch = PlayerDB.objects.filter(user__username__iexact=inp) if umatch: - return umatch[0] + return umatch[0] elif objtype == 'external': from src.comms.models import ExternalChannelConnection if type (inp) == ExternalChannelConnection: return inp umatch = ExternalChannelConnection.objects.filter(db_key=inp) if umatch: - return umatch[0] + return umatch[0] else: # have to import this way to avoid circular imports - from src.comms.models import Channel - #= ContentType.objects.get(app_label="comms", + from src.comms.models import Channel + #= ContentType.objects.get(app_label="comms", # model="channel").model_class() if type(inp) == Channel: return inp cmatch = Channel.objects.filter(db_key__iexact=inp) if cmatch: return cmatch[0] - return None - + return None + # # Msg manager # class MsgManager(models.Manager): """ - This MsgManager implements methods for searching + This MsgManager implements methods for searching and manipulating Messages directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - A Message represents one unit of communication, be it over a + A Message represents one unit of communication, be it over a Channel or via some form of in-game mail system. Like an e-mail, it always has a sender and can have any number of receivers (some - of which may be Channels). - + of which may be Channels). + Evennia-specific: get_message_by_id get_messages_by_sender @@ -75,22 +75,22 @@ class MsgManager(models.Manager): text_search message_search (equivalent to ev.search_messages) """ - + def get_message_by_id(self, idnum): - "Retrieve message by its id." + "Retrieve message by its id." try: idnum = int(idnum) return self.get(id=id) except Exception: return None - + def get_messages_by_sender(self, player): """ Get all messages sent by one player """ - player = to_object(player, objtype='player') + player = to_object(player, objtype='player') if not player: - return None + return None return self.filter(db_sender=player).exclude(db_hide_from_sender=True) def get_messages_by_receiver(self, receiver): @@ -99,7 +99,7 @@ class MsgManager(models.Manager): """ receiver = to_object(receiver) if not receiver: - return None + return None return [msg for msg in self.all() if receiver in msg.receivers and receiver not in msg.hide_from_receivers] @@ -110,30 +110,30 @@ class MsgManager(models.Manager): """ channel = to_object(channel, objtype='channel') if not channel: - return None + return None return [msg for msg in self.all() - if channel in msg.channels + if channel in msg.channels and channel not in msg.hide_from_channels] - #TODO add search limited by send_times + #TODO add search limited by send_times def text_search(self, searchstring, filterdict=None): """ Returns all messages that contain the matching search string. To avoid too many results, and also since this can be a very computing- heavy operation, it's recommended to be filtered - by at least channel or sender/receiver. + by at least channel or sender/receiver. searchstring - string to search for filterdict - {'channels':[list], 'senders':[list], 'receivers':[list]} lists can contain either the name/keys of the - objects or the actual objects to filter by. - """ + objects or the actual objects to filter by. + """ if filterdict: - # obtain valid objects for all filters + # obtain valid objects for all filters channels = [chan for chan in [to_object(chan, objtype='channel') for chan in filterdict.get('channels',[])] @@ -141,23 +141,23 @@ class MsgManager(models.Manager): senders = [sender for sender in [to_object(sender) for sender in filterdict.get('senders',[])] - if sender] + if sender] receivers = [receiver for receiver in [to_object(receiver) for receiver in filterdict.get('receivers',[])] if receiver] - # filter the messages lazily using the filter objects + # filter the messages lazily using the filter objects msgs = [] for sender in senders: msgs = list(sender.message_set.filter( - db_message__icontains=searchstring)) + db_message__icontains=searchstring)) for receiver in receivers: rec_msgs = receiver.message_set.filter( db_message__icontains=searchstring) if msgs: msgs = [msg for msg in rec_msgs if msg in msgs] else: - msgs = rec_msgs + msgs = rec_msgs for channel in channels: chan_msgs = list(channel.message_set.filter( db_message__icontains=searchstring)) @@ -168,21 +168,21 @@ class MsgManager(models.Manager): return list(set(msgs)) return list(self.all().filter(db_message__icontains=searchstring)) - def message_search(self, sender=None, receiver=None, channel=None, freetext=None, dbref=None): + def message_search(self, sender=None, receiver=None, channel=None, freetext=None, dbref=None): """ - Search the message database for particular messages. At least one - of the arguments must be given to do a search. + Search the message database for particular messages. At least one + of the arguments must be given to do a search. sender - get messages sent by a particular player receiver - get messages received by a certain player or players channel - get messages sent to a particular channel or channels - freetext - Search for a text string in a message. + freetext - Search for a text string in a message. NOTE: This can potentially be slow, so make sure to supply - one of the other arguments to limit the search. - dbref - (int) the exact database id of the message. This will override + one of the other arguments to limit the search. + dbref - (int) the exact database id of the message. This will override all other search crieteria since it's unique and always gives a list with only one match. - """ + """ if dbref: return self.filter(id=dbref) if freetext: @@ -199,12 +199,12 @@ class MsgManager(models.Manager): msgs = [] if sender: msgs = self.get_messages_by_sender(sender) - if receiver: + if receiver: rec_msgs = self.get_messages_by_receiver(receiver) if msgs: msgs = [msg for msg in rec_msgs if msg in msgs] else: - msgs = rec_msgs + msgs = rec_msgs if channel: chan_msgs = self.get_messaqge_by_channel(channel) if msgs: @@ -212,20 +212,20 @@ class MsgManager(models.Manager): else: msgs = chan_msgs return msgs - + # # Channel manager # class ChannelManager(models.Manager): """ - This ChannelManager implements methods for searching + This ChannelManager implements methods for searching and manipulating Channels directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - A Channel is an in-game venue for communication. It's + A Channel is an in-game venue for communication. It's essentially representation of a re-sender: Users sends Messages to the Channel, and the Channel re-sends those messages to all users subscribed to the Channel. @@ -248,9 +248,9 @@ class ChannelManager(models.Manager): def get_channel(self, channelkey): """ Return the channel object if given its key. - Also searches its aliases. + Also searches its aliases. """ - # first check the channel key + # first check the channel key channels = self.filter(db_key__iexact=channelkey) if not channels: # also check aliases @@ -258,23 +258,23 @@ class ChannelManager(models.Manager): if channelkey in channel.aliases] if channels: return channels[0] - return None + return None def del_channel(self, channelkey): """ Delete channel matching channelkey. - Also cleans up channelhandler. + Also cleans up channelhandler. """ channels = self.filter(db_key__iexact=channelkey) if not channels: # no aliases allowed for deletion. - return False + return False for channel in channels: - channel.delete() + channel.delete() from src.comms.channelhandler import CHANNELHANDLER CHANNELHANDLER.update() - return None - + return None + def get_all_connections(self, channel): """ Return the connections of all players listening @@ -282,9 +282,9 @@ class ChannelManager(models.Manager): """ # import here to avoid circular imports #from src.comms.models import PlayerChannelConnection - PlayerChannelConnection = ContentType.objects.get(app_label="comms", + PlayerChannelConnection = ContentType.objects.get(app_label="comms", model="playerchannelconnection").model_class() - ExternalChannelConnection = ContentType.objects.get(app_label="comms", + ExternalChannelConnection = ContentType.objects.get(app_label="comms", model="externalchannelconnection").model_class() return itertools.chain(PlayerChannelConnection.objects.get_all_connections(channel), ExternalChannelConnection.objects.get_all_connections(channel)) @@ -297,10 +297,10 @@ class ChannelManager(models.Manager): """ channels = [] try: - # try an id match first + # try an id match first dbref = int(ostring.strip('#')) channels = self.filter(id=dbref) - except Exception: + except Exception: pass if not channels: # no id match. Search on the key. @@ -308,17 +308,17 @@ class ChannelManager(models.Manager): if not channels: # still no match. Search by alias. channels = [channel for channel in self.all() if ostring.lower in [a.lower for a in channel.aliases]] - return channels + return channels # # PlayerChannelConnection manager # class PlayerChannelConnectionManager(models.Manager): """ - This PlayerChannelConnectionManager implements methods for searching + This PlayerChannelConnectionManager implements methods for searching and manipulating PlayerChannelConnections directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. A PlayerChannelConnection defines a user's subscription to an in-game @@ -333,7 +333,7 @@ class PlayerChannelConnectionManager(models.Manager): break_connection """ - + def get_all_player_connections(self, player): "Get all connections that the given player has." player = to_object(player) @@ -346,18 +346,18 @@ class PlayerChannelConnectionManager(models.Manager): if player and channel: return self.filter(db_player=player).filter(db_channel=channel).count() > 0 return False - + def get_all_connections(self, channel): """ Get all connections for a channel """ channel = to_object(channel, objtype='channel') return self.filter(db_channel=channel) - + def create_connection(self, player, channel): """ Connect a player to a channel. player and channel - can be actual objects or keystrings. + can be actual objects or keystrings. """ player = to_object(player) channel = to_object(channel, objtype='channel') @@ -379,13 +379,13 @@ class PlayerChannelConnectionManager(models.Manager): class ExternalChannelConnectionManager(models.Manager): """ - This ExternalChannelConnectionManager implements methods for searching + This ExternalChannelConnectionManager implements methods for searching and manipulating HelpEntries directly from the database. - These methods will all return database objects + These methods will all return database objects (or QuerySets) directly. - An ExternalChannelConnetion describes the connection between an in-game + An ExternalChannelConnetion describes the connection between an in-game channel and some external source, such as an IRC or IMC channel. Evennia-specific: @@ -394,9 +394,9 @@ class ExternalChannelConnectionManager(models.Manager): get_all_connections create_connection break_connection - + """ - + def get_all_external_connections(self, external): "Get all connections that the given as external." external = to_object(external, objtype='external') @@ -409,18 +409,18 @@ class ExternalChannelConnectionManager(models.Manager): if external and channel: return self.filter(db_external_key=external).filter(db_channel=channel).count() > 0 return False - + def get_all_connections(self, channel): """ Get all connections for a channel """ channel = to_object(channel, objtype='channel') return self.filter(db_channel=channel) - + def create_connection(self, external, channel, config=""): """ Connect a external to a channel. external and channel - can be actual objects or keystrings. + can be actual objects or keystrings. """ channel = to_object(channel, objtype='channel') if not channel: diff --git a/src/comms/rss.py b/src/comms/rss.py index 2a4e638c07..dbfec7a65a 100644 --- a/src/comms/rss.py +++ b/src/comms/rss.py @@ -1,24 +1,24 @@ """ RSS parser for Evennia -This connects an RSS feed to an in-game Evennia channel, sending messages -to the channel whenever the feed updates. +This connects an RSS feed to an in-game Evennia channel, sending messages +to the channel whenever the feed updates. """ import re from twisted.internet import task -from django.conf import settings -from src.comms.models import ExternalChannelConnection, Channel +from django.conf import settings +from src.comms.models import ExternalChannelConnection, Channel from src.utils import logger, utils from src.scripts.models import ScriptDB -RSS_ENABLED = settings.RSS_ENABLED +RSS_ENABLED = settings.RSS_ENABLED RSS_UPDATE_INTERVAL = settings.RSS_UPDATE_INTERVAL INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0]) RETAG = re.compile(r'<[^>]*?>') -# holds rss readers they can be shut down at will. +# holds rss readers they can be shut down at will. RSS_READERS = {} def msg_info(message): @@ -35,8 +35,8 @@ if RSS_ENABLED: try: import feedparser except ImportError: - raise ImportError("RSS requirs python-feedparser to be installed. Install or set RSS_ENABLED=False.") - + raise ImportError("RSS requires python-feedparser to be installed. Install or set RSS_ENABLED=False.") + class RSSReader(object): """ Reader script used to connect to each individual RSS feed @@ -45,47 +45,47 @@ class RSSReader(object): """ The reader needs an rss url and It also needs an interval for how often it is to check for new updates (defaults - to 10 minutes) + to 10 minutes) """ self.key = key - self.url = url - self.interval = interval + self.url = url + self.interval = interval self.entries = {} # stored feeds - self.task = None - # first we do is to load the feed so we don't resend - # old entries whenever the reader starts. - self.update_feed() + self.task = None + # first we do is to load the feed so we don't resend + # old entries whenever the reader starts. + self.update_feed() # start runner self.start() - + def update_feed(self): "Read the url for new updated data and determine what's new." feed = feedparser.parse(self.url) new = [] for entry in (e for e in feed['entries'] if e['id'] not in self.entries): - txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']), entry['link'].replace('\n','').encode('utf-8')) + txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']), entry['link'].replace('\n','').encode('utf-8')) self.entries[entry['id']] = txt - new.append(txt) - return new + new.append(txt) + return new def update(self): """ Called every self.interval seconds - tries to get new feed entries, and if so, uses the appropriate ExternalChannelConnection to send the - data to subscribing channels. + data to subscribing channels. """ new = self.update_feed() - if not new: - return - conns = ExternalChannelConnection.objects.filter(db_external_key=self.key) - for conn in (conn for conn in conns if conn.channel): - for txt in new: + if not new: + return + conns = ExternalChannelConnection.objects.filter(db_external_key=self.key) + for conn in (conn for conn in conns if conn.channel): + for txt in new: conn.to_channel("%s:%s" % (conn.channel.key, txt)) - + def start(self): """ - Starting the update task and store a reference in the - global variable so it can be found and shut down later. + Starting the update task and store a reference in the + global variable so it can be found and shut down later. """ global RSS_READERS self.task = task.LoopingCall(self.update) @@ -95,7 +95,7 @@ class RSSReader(object): def build_connection_key(channel, url): "This is used to id the connection" if hasattr(channel, 'key'): - channel = channel.key + channel = channel.key return "rss_%s>%s" % (url, channel) def create_connection(channel, url, interval): @@ -106,19 +106,19 @@ def create_connection(channel, url, interval): new_channel = Channel.objects.filter(db_key=channel) if not new_channel: logger.log_errmsg("Cannot attach RSS->Evennia: Evennia Channel '%s' not found." % channel) - return False + return False channel = new_channel[0] key = build_connection_key(channel, url) old_conns = ExternalChannelConnection.objects.filter(db_external_key=key) if old_conns: - return False + return False config = "%s|%i" % (url, interval) # There is no sendback from evennia to the rss, so we need not define any sendback code. conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_config=config) - conn.save() + conn.save() connect_to_rss(conn) - return True + return True def delete_connection(channel, url): """ @@ -128,29 +128,29 @@ def delete_connection(channel, url): try: conn = ExternalChannelConnection.objects.get(db_external_key=key) except Exception: - return False + return False conn.delete() reader = RSS_READERS.get(key, None) - if reader and reader.task: + if reader and reader.task: reader.task.stop() - return True - + return True + def connect_to_rss(connection): """ Create the parser instance and connect to RSS feed and channel """ global RSS_READERS - key = utils.to_str(connection.external_key) + key = utils.to_str(connection.external_key) url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')] # Create reader (this starts the running task and stores a reference in RSS_TASKS) RSSReader(key, url, int(interval)) def connect_all(): """ - Activate all rss feed parsers + Activate all rss feed parsers """ if not RSS_ENABLED: - return + return for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith="rss_"): print "connecting RSS: %s" % connection connect_to_rss(connection) diff --git a/src/locks/lockhandler.py b/src/locks/lockhandler.py index 6c69012a7a..069b66fbb0 100644 --- a/src/locks/lockhandler.py +++ b/src/locks/lockhandler.py @@ -107,7 +107,10 @@ to any other identifier you can use. import re, inspect from django.conf import settings from src.utils import logger, utils +from django.utils.translation import ugettext as _ + __all__ = ("LockHandler", ) + # # Exception class # @@ -215,7 +218,7 @@ class LockHandler(object): funcname, rest = (part.strip().strip(')') for part in funcstring.split('(', 1)) func = _LOCKFUNCS.get(funcname, None) if not callable(func): - elist.append("Lock: function '%s' is not available." % funcstring) + elist.append(_("Lock: function '%s' is not available.") % funcstring) continue args = list(arg.strip() for arg in rest.split(',') if not '=' in arg) kwargs = dict([arg.split('=', 1) for arg in rest.split(',') if '=' in arg]) @@ -228,12 +231,12 @@ class LockHandler(object): evalstring = " ".join(_RE_OK.findall(evalstring)) eval(evalstring % tuple(True for func in funclist), {}, {}) except Exception: - elist.append("Lock: definition '%s' has syntax errors." % raw_lockstring) + elist.append(_("Lock: definition '%s' has syntax errors.") % raw_lockstring) continue if access_type in locks: duplicates += 1 - wlist.append("Lock: access type '%s' changed from '%s' to '%s' " % \ - (access_type, locks[access_type][2], raw_lockstring)) + wlist.append(_("Lock: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " % \ + {"access_type":access_type, "source":locks[access_type][2], "goal":raw_lockstring})) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) if wlist and self.log_obj: # a warning text was set, it's not an error, so only report if log_obj is available. @@ -266,17 +269,17 @@ class LockHandler(object): # sanity checks for lockdef in lockstring.split(';'): if not ':' in lockstring: - self._log_error("Lock: '%s' contains no colon (:)." % lockdef) + self._log_error(_("Lock: '%s' contains no colon (:).") % lockdef) return False access_type, rhs = [part.strip() for part in lockdef.split(':', 1)] if not access_type: - self._log_error("Lock: '%s' has no access_type (left-side of colon is empty)." % lockdef) + self._log_error(_("Lock: '%s' has no access_type (left-side of colon is empty).") % lockdef) return False if rhs.count('(') != rhs.count(')'): - self._log_error("Lock: '%s' has mismatched parentheses." % lockdef) + self._log_error(_("Lock: '%s' has mismatched parentheses.") % lockdef) return False if not _RE_FUNCS.findall(rhs): - self._log_error("Lock: '%s' has no valid lock functions." % lockdef) + self._log_error(_("Lock: '%s' has no valid lock functions.") % lockdef) return False # get the lock string storage_lockstring = self.obj.lock_storage diff --git a/src/scripts/scripthandler.py b/src/scripts/scripthandler.py index 750f0cf4ed..b91cf48750 100644 --- a/src/scripts/scripthandler.py +++ b/src/scripts/scripthandler.py @@ -9,6 +9,8 @@ from src.scripts.models import ScriptDB from src.utils import create from src.utils import logger +from django.utils.translation import ugettext as _ + class ScriptHandler(object): """ Implements the handler. This sits on each game object. @@ -38,11 +40,8 @@ class ScriptHandler(object): repeats = script.repeats try: next_repeat = script.time_until_next_repeat() except: next_repeat = "?" - string += "\n '%s' (%s/%s, %s repeats): %s" % (script.key, - next_repeat, - interval, - repeats, - script.desc) + string += _("\n '%(key)s' (%(next_repeat)s/%(interval)s, %(repeats)s repeats): %(desc)s") % \ + {"key":script.key, "next_repeat":next_repeat, "interval":interval,"repeats":repeats,"desc":script.desc} return string.strip() def add(self, scriptclass, key=None, autostart=True): diff --git a/src/scripts/scripts.py b/src/scripts/scripts.py index 9383eb1edd..9b494446ec 100644 --- a/src/scripts/scripts.py +++ b/src/scripts/scripts.py @@ -17,6 +17,7 @@ from src.typeclasses.models import _ATTRIBUTE_CACHE from src.scripts.models import ScriptDB from src.comms import channelhandler from src.utils import logger +from django.utils.translation import ugettext as _ __all__ = ("Script", "DoNothing", "CheckSessions", "ValidateScripts", "ValidateChannelHandler", "ClearAttributeCache") @@ -66,7 +67,8 @@ class ScriptClass(TypeClass): def _step_err_callback(self, e): "callback for runner errors" cname = self.__class__.__name__ - estring = "Script %s(#%i) of type '%s': at_repeat() error '%s'." % (self.key, self.dbid, cname, e.getErrorMessage()) + estring = _("Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'.") % \ + {"key":self.key, "dbid":self.dbid, "cname":cname, "err":e.getErrorMessage()} try: self.dbobj.db_obj.msg(estring) except Exception: @@ -392,14 +394,14 @@ class DoNothing(Script): def at_script_creation(self): "Setup the script" self.key = "sys_do_nothing" - self.desc = "This is an empty placeholder script." + self.desc = _("This is an empty placeholder script.") class CheckSessions(Script): "Check sessions regularly." def at_script_creation(self): "Setup the script" self.key = "sys_session_check" - self.desc = "Checks sessions so they are live." + self.desc = _("Checks sessions so they are live.") self.interval = 60 # repeat every 60 seconds self.persistent = True @@ -414,7 +416,7 @@ class ValidateScripts(Script): def at_script_creation(self): "Setup the script" self.key = "sys_scripts_validate" - self.desc = "Validates all scripts regularly." + self.desc = _("Validates all scripts regularly.") self.interval = 3600 # validate every hour. self.persistent = True @@ -428,7 +430,7 @@ class ValidateChannelHandler(Script): def at_script_creation(self): "Setup the script" self.key = "sys_channels_validate" - self.desc = "Updates the channel handler" + self.desc = _("Updates the channel handler") self.interval = 3700 # validate a little later than ValidateScripts self.persistent = True @@ -442,7 +444,7 @@ class ClearAttributeCache(Script): def at_script_creation(self): "Setup the script" self.key = "sys_cache_clear" - self.desc = "Clears the Attribute Cache" + self.desc = _("Clears the Attribute Cache") self.interval = 3600 * 2 self.persistent = True def at_repeat(self): diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 92f9415b4b..eff1603b8e 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -13,7 +13,6 @@ from src.server.models import ServerConfig from src.help.models import HelpEntry from src.utils import create -# i18n from django.utils.translation import ugettext as _ def create_config_values(): @@ -34,7 +33,7 @@ def create_objects(): Creates the #1 player and Limbo room. """ - print _(" Creating objects (Player #1 and Limbo room) ...") + print " Creating objects (Player #1 and Limbo room) ..." # Set the initial User's account object's username on the #1 object. # This object is pure django and only holds name, email and password. @@ -89,7 +88,7 @@ def create_channels(): """ Creates some sensible default channels. """ - print _(" Creating default channels ...") + print " Creating default channels ..." # public channel key, aliases, desc, locks = settings.CHANNEL_PUBLIC @@ -112,12 +111,11 @@ def import_MUX_help_files(): """ Imports the MUX help files. """ - print _(" Importing MUX help database (devel reference only) ...") + print " Importing MUX help database (devel reference only) ..." management.call_command('loaddata', '../src/help/mux_help_db.json', verbosity=0) # categorize the MUX help files into its own category. default_category = "MUX" - print _(" Moving imported help db to help category '%(default)s'." \ - % {'default': default_category}) + print " Moving imported help db to help category '%(default)s'." % {'default': default_category} HelpEntry.objects.all_to_category(default_category) def create_system_scripts(): @@ -127,7 +125,7 @@ def create_system_scripts(): """ from src.scripts import scripts - print _(" Creating and starting global scripts ...") + print " Creating and starting global scripts ..." # check so that all sessions are alive. script1 = create.create_script(scripts.CheckSessions) @@ -138,7 +136,7 @@ def create_system_scripts(): # clear the attribute cache regularly script4 = create.create_script(scripts.ClearAttributeCache) if not script1 or not script2 or not script3 or not script4: - print _(" Error creating system scripts.") + print " Error creating system scripts." def start_game_time(): """ @@ -147,7 +145,7 @@ def start_game_time(): the total run time of the server as well as its current uptime (the uptime can also be found directly from the server though). """ - print _(" Starting in-game time ...") + print " Starting in-game time ..." from src.utils import gametime gametime.init_gametime() @@ -170,20 +168,20 @@ def create_admin_media_links(): dpath = os.path.join(django.__path__[0], 'contrib', 'admin', 'static', 'admin') apath = os.path.join(settings.ADMIN_MEDIA_ROOT) if os.path.isdir(apath): - print _(" ADMIN_MEDIA_ROOT already exists. Ignored.") + print " ADMIN_MEDIA_ROOT already exists. Ignored." return if os.name == 'nt': - print _(" Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode).") + print " Admin-media files copied to ADMIN_MEDIA_ROOT (Windows mode)." os.mkdir(apath) os.system('xcopy "%s" "%s" /e /q /c' % (dpath, apath)) if os.name == 'posix': try: os.symlink(dpath, apath) - print _(" Admin-media symlinked to ADMIN_MEDIA_ROOT.") + print " Admin-media symlinked to ADMIN_MEDIA_ROOT." except OSError, e: - print _(" There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT:\n %s\n -> \n %s\n (%s)\n If you see issues, link manually." % (dpath, apath, e)) + print " There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT:\n %s\n -> \n %s\n (%s)\n If you see issues, link manually." % (dpath, apath, e) else: - print _(" Admin-media files should be copied manually to ADMIN_MEDIA_ROOT.") + print " Admin-media files should be copied manually to ADMIN_MEDIA_ROOT." def at_initial_setup(): """ @@ -199,7 +197,7 @@ def at_initial_setup(): mod = __import__(modname, fromlist=[None]) except (ImportError, ValueError): return - print _(" Running at_initial_setup() hook.") + print " Running at_initial_setup() hook." if mod.__dict__.get("at_initial_setup", None): mod.at_initial_setup() @@ -211,7 +209,7 @@ def reset_server(): It also checks so the warm-reset mechanism works as it should. """ from src.server.sessionhandler import SESSIONS - print _(" Initial setup complete. Resetting/reloading Server.") + print " Initial setup complete. Resetting/reloading Server." SESSIONS.server.shutdown(mode='reset') def handle_setup(last_step): diff --git a/src/server/models.py b/src/server/models.py index 2560a4e02a..6291c50527 100644 --- a/src/server/models.py +++ b/src/server/models.py @@ -18,9 +18,6 @@ from src.utils.idmapper.models import SharedMemoryModel from src.utils import logger, utils from src.server.manager import ServerConfigManager -# i18n -from django.utils.translation import ugettext as _ - #------------------------------------------------------------ # # ServerConfig @@ -88,7 +85,7 @@ class ServerConfig(SharedMemoryModel): "Setter. Allows for self.value = value" if utils.has_parent('django.db.models.base.Model', value): # we have to protect against storing db objects. - logger.log_errmsg(_("ServerConfig cannot store db objects! (%s)" % value)) + logger.log_errmsg("ServerConfig cannot store db objects! (%s)" % value) return self.db_value = pickle.dumps(value) self.save() diff --git a/src/server/portal.py b/src/server/portal.py index 885953fadd..4b4300fb2c 100644 --- a/src/server/portal.py +++ b/src/server/portal.py @@ -26,9 +26,6 @@ if os.name == 'nt': # For Windows we need to handle pid files manually. PORTAL_PIDFILE = os.path.join(settings.GAME_DIR, 'portal.pid') -# i18n -from django.utils.translation import ugettext as _ - #------------------------------------------------------------ # Evennia Portal settings #------------------------------------------------------------ @@ -103,7 +100,7 @@ class Portal(object): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Portal (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print ' %(servername)s Portal (%(version)s) started.' % {'servername': SERVERNAME, 'version': VERSION} if AMP_ENABLED: print " amp (Server): %s" % AMP_PORT if TELNET_ENABLED: @@ -135,7 +132,7 @@ class Portal(object): if mode == None: return f = open(PORTAL_RESTART, 'w') - print _("writing mode=%(mode)s to %(portal_restart)s") % {'mode': mode, 'portal_restart': PORTAL_RESTART} + print "writing mode=%(mode)s to %(portal_restart)s" % {'mode': mode, 'portal_restart': PORTAL_RESTART} f.write(str(mode)) f.close() diff --git a/src/server/server.py b/src/server/server.py index bfbfe9bb78..8e02547baa 100644 --- a/src/server/server.py +++ b/src/server/server.py @@ -172,7 +172,7 @@ class Evennia(object): if not last_initial_setup_step: # None is only returned if the config does not exist, # i.e. this is an empty DB that needs populating. - print _(' Server started for the first time. Setting defaults.') + print ' Server started for the first time. Setting defaults.' initial_setup.handle_setup(0) print '-'*50 elif int(last_initial_setup_step) >= 0: @@ -180,8 +180,8 @@ class Evennia(object): # modules and setup will resume from this step, retrying # the last failed module. When all are finished, the step # is set to -1 to show it does not need to be run again. - print _(' Resuming initial setup from step %(last)s.' % \ - {'last': last_initial_setup_step}) + print ' Resuming initial setup from step %(last)s.' % \ + {'last': last_initial_setup_step} initial_setup.handle_setup(int(last_initial_setup_step)) print '-'*50 @@ -207,7 +207,7 @@ class Evennia(object): """ Outputs server startup info to the terminal. """ - print _(' %(servername)s Server (%(version)s) started.') % {'servername': SERVERNAME, 'version': VERSION} + print ' %(servername)s Server (%(version)s) started.' % {'servername': SERVERNAME, 'version': VERSION} print ' amp (Portal): %s' % AMP_PORT def set_restart_mode(self, mode=None): diff --git a/src/server/ssh.py b/src/server/ssh.py index ec5f974b77..ab6f313537 100644 --- a/src/server/ssh.py +++ b/src/server/ssh.py @@ -28,9 +28,6 @@ from src.server import session from src.players.models import PlayerDB from src.utils import ansi, utils, logger -# i18n -from django.utils.translation import ugettext as _ - ENCODINGS = settings.ENCODINGS CTRL_C = '\x03' @@ -295,7 +292,7 @@ def getKeyPair(pubkeyfile, privkeyfile): if not (os.path.exists(pubkeyfile) and os.path.exists(privkeyfile)): # No keypair exists. Generate a new RSA keypair - print _(" Generating SSH RSA keypair ..."), + print " Generating SSH RSA keypair ...", from Crypto.PublicKey import RSA KEY_LENGTH = 1024 @@ -340,8 +337,8 @@ def makeFactory(configdict): factory.publicKeys = {'ssh-rsa': publicKey} factory.privateKeys = {'ssh-rsa': privateKey} except Exception, e: - print _(" getKeyPair error: %(e)s\n WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead.") % {'e': e} - print _(" If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools.") % {'pub': pubkeyfile, 'priv': privkeyfile} + print " getKeyPair error: %(e)s\n WARNING: Evennia could not auto-generate SSH keypair. Using conch default keys instead." % {'e': e} + print " If this error persists, create game/%(pub)s and game/%(priv)s yourself using third-party tools." % {'pub': pubkeyfile, 'priv': privkeyfile} factory.services = factory.services.copy() factory.services['ssh-userauth'] = ExtraInfoAuthServer diff --git a/src/server/ssl.py b/src/server/ssl.py index 433edd0273..b3064731e3 100644 --- a/src/server/ssl.py +++ b/src/server/ssl.py @@ -8,7 +8,7 @@ from twisted.internet import ssl as twisted_ssl try: import OpenSSL except ImportError: - print _(" SSL_ENABLED requires PyOpenSSL.") + print " SSL_ENABLED requires PyOpenSSL." sys.exit(5) from src.server.telnet import TelnetProtocol @@ -33,7 +33,7 @@ def verify_SSL_key_and_cert(keyfile, certfile): from Crypto.PublicKey import RSA from twisted.conch.ssh.keys import Key - print _(" Creating SSL key and certificate ... "), + print " Creating SSL key and certificate ... ", try: # create the RSA key and store it. @@ -42,8 +42,8 @@ def verify_SSL_key_and_cert(keyfile, certfile): keyString = rsaKey.toString(type="OPENSSH") file(keyfile, 'w+b').write(keyString) except Exception,e: - print _("rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key.") % {'e': e} - print _("If this error persists, create game/%(keyfile)s yourself using third-party tools.") % {'keyfile': keyfile} + print "rsaKey error: %(e)s\n WARNING: Evennia could not auto-generate SSL private key." % {'e': e} + print "If this error persists, create game/%(keyfile)s yourself using third-party tools." % {'keyfile': keyfile} sys.exit(5) # try to create the certificate @@ -55,12 +55,14 @@ def verify_SSL_key_and_cert(keyfile, certfile): try: err = subprocess.call(exestring)#, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, e: - print " %s\n" % e - print _(" Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s.") % {'cert': certfile} - print _(" A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid") % {'cert': certfile} - print _(" for your operating system.") - print _(" Example (linux, using the openssl program): ") - print " %s" % exestring + string = "\n".join([ + " %s\n" % e, + " Evennia's SSL context factory could not automatically create an SSL certificate game/%(cert)s." % {'cert': certfile}, + " A private key 'ssl.key' was already created. Please create %(cert)s manually using the commands valid" % {'cert': certfile}, + " for your operating system.", + " Example (linux, using the openssl program): ", + " %s" % exestring]) + print string sys.exit(5) print "done." diff --git a/src/utils/batchprocessors.py b/src/utils/batchprocessors.py index dc7bb59197..08fa056ff5 100644 --- a/src/utils/batchprocessors.py +++ b/src/utils/batchprocessors.py @@ -42,11 +42,11 @@ simple format. The engine runs each command in sequence, as if they had been run at the game prompt. Each evennia command must be delimited by a line comment to mark its -end. +end. #INSERT path.batchcmdfile - this as the first entry on a line will - import and run a batch.ev file in this position, as if it was - written in this file. + import and run a batch.ev file in this position, as if it was + written in this file. This way entire game worlds can be created and planned offline; it is especially useful in order to create long room descriptions where a @@ -54,11 +54,11 @@ real offline text editor is often much better than any online text editor or prompt. Example of batch.ev file: ----------------------------- +---------------------------- # batch file # all lines starting with # are comments; they also indicate -# that a command definition is over. +# that a command definition is over. @create box @@ -66,10 +66,10 @@ Example of batch.ev file: @set box/desc = A large box. -Inside are some scattered piles of clothing. +Inside are some scattered piles of clothing. -It seems the bottom of the box is a bit loose. +It seems the bottom of the box is a bit loose. # Again, this comment indicates the @set command is over. Note how # the description could be freely added. Excess whitespace on a line @@ -81,7 +81,7 @@ It seems the bottom of the box is a bit loose. # (Assuming #221 is a warehouse or something.) # (remember, this comment ends the @teleport command! Don'f forget it) -# Example of importing another file at this point. +# Example of importing another file at this point. #IMPORT examples.batch @drop box @@ -90,7 +90,7 @@ It seems the bottom of the box is a bit loose. # close the @drop command since it's the end of the file) ------------------------- -An example batch file is game/gamesrc/commands/examples/batch_example.ev. +An example batch file is game/gamesrc/commands/examples/batch_example.ev. ========================================================================== @@ -114,9 +114,9 @@ code words. automatically be pasted at the top of all code blocks. Observe that changes to these variables made in one block is not preserved between blocks! -#CODE +#CODE #CODE (info) -#CODE (info) objname1, objname1, ... - +#CODE (info) objname1, objname1, ... - This designates a code block that will be executed like a stand-alone piece of code together with any #HEADER defined. (info) text is used by the interactive mode to @@ -140,12 +140,12 @@ caller - the object executing the script Example batch.py file ----------------------------------- -#HEADER +#HEADER -import traceback +import traceback from django.config import settings from src.utils import create -from game.gamesrc.typeclasses import basetypes +from game.gamesrc.typeclasses import basetypes GOLD = 10 @@ -188,12 +188,12 @@ def read_batchfile(pythonpath, file_ending='.py'): Filename is considered to be the name of the batch file relative the directory specified in settings.py. - file_ending specify which batchfile ending should be + file_ending specify which batchfile ending should be assumed (.ev or .py). - """ + """ # open the file - if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.') + if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.') or pythonpath.startswith('contrib.')): abspaths = [] for basepath in settings.BASE_BATCHPROCESS_PATHS: @@ -202,24 +202,24 @@ def read_batchfile(pythonpath, file_ending='.py'): abspaths = [utils.pypath_to_realpath(pythonpath, file_ending)] fobj, lines, err = None, [], None for file_encoding in ENCODINGS: - # try different encodings, in order + # try different encodings, in order load_errors = [] for abspath in abspaths: - # try different paths, until we get a match - try: + # try different paths, until we get a match + try: # we read the file directly into unicode. fobj = codecs.open(abspath, 'r', encoding=file_encoding) except IOError: load_errors.append("Could not open batchfile '%s'." % abspath) - continue + continue break if not fobj: - continue + continue load_errors = [] - err =None + err =None # We have successfully found and opened the file. Now actually - # try to decode it using the given protocol. + # try to decode it using the given protocol. try: lines = fobj.readlines() except UnicodeDecodeError: @@ -230,19 +230,19 @@ def read_batchfile(pythonpath, file_ending='.py'): for lnum, line in enumerate(fobj): pass except UnicodeDecodeError, err: - # lnum starts from 0, so we add +1 line, + # lnum starts from 0, so we add +1 line, # besides the faulty line is never read # so we add another 1 (thus +2) to get - # the actual line number seen in an editor. - err.linenum = lnum + 2 + # the actual line number seen in an editor. + err.linenum = lnum + 2 fobj.close() # possibly try another encoding - continue + continue # if we get here, the encoding worked. Stop iteration. - break - if load_errors: + break + if load_errors: logger.log_errmsg("\n".join(load_errors)) - if err: + if err: return err else: return lines @@ -257,7 +257,7 @@ class BatchCommandProcessor(object): """ This class implements a batch-command processor. - """ + """ def parse_file(self, pythonpath): """ This parses the lines of a batchfile according to the following @@ -266,15 +266,15 @@ class BatchCommandProcessor(object): It is also a comment and any number of # can exist on subsequent lines (but not inside comments). 2) #INSERT at the beginning of a line imports another - batch-cmd file file and pastes it into the batch file as if - it was written there. + batch-cmd file file and pastes it into the batch file as if + it was written there. 3) Commands are placed alone at the beginning of a line and their arguments are considered to be everything following (on any number of lines) until the next comment line beginning with #. 4) Newlines are ignored in command definitions 5) A completely empty line in a command line definition is condered a newline (so two empty lines is a paragraph). - 6) Excess spaces and indents inside arguments are stripped. + 6) Excess spaces and indents inside arguments are stripped. """ @@ -287,7 +287,7 @@ class BatchCommandProcessor(object): if line.strip().startswith("#INSERT"): return "insert" elif line.strip()[0] == '#': - return "comment" + return "comment" else: return "commanddef" except IndexError: @@ -295,10 +295,10 @@ class BatchCommandProcessor(object): #read the indata, if possible. lines = read_batchfile(pythonpath, file_ending='.ev') - + #line = utils.to_unicode(line) if not lines: - return None + return None commands = [] curr_cmd = "" @@ -309,34 +309,34 @@ class BatchCommandProcessor(object): #parse all command definitions into a list. for line in lines: - + typ = identify_line(line) - + if typ == "commanddef": curr_cmd += line elif typ == "empty" and curr_cmd: curr_cmd += "\r\n" elif typ == "insert": - # note that we are not safeguarding for + # note that we are not safeguarding for # cyclic imports here! if curr_cmd: commands.append(curr_cmd.strip()) curr_cmd = "" - filename = line.lstrip("#INSERT").strip() + filename = line.lstrip("#INSERT").strip() insert_commands = self.parse_file(filename) if insert_commands == None: insert_commands = ["{rINSERT ERROR: %s{n" % filename] - commands.extend(insert_commands) + commands.extend(insert_commands) else: #comment if curr_cmd: - commands.append(curr_cmd.strip()) - curr_cmd = "" - if curr_cmd: + commands.append(curr_cmd.strip()) + curr_cmd = "" + if curr_cmd: commands.append(curr_cmd.strip()) #second round to clean up now merged line edges etc. reg2 = re.compile(r"[ \t\f\v]+") - commands = [reg2.sub(" ", c) for c in commands] + commands = [reg2.sub(" ", c) for c in commands] #remove eventual newline at the end of commands commands = [c.strip('\r\n') for c in commands] @@ -359,7 +359,7 @@ def tb_iter(tb): class BatchCodeProcessor(object): """ This implements a batch-code processor - + """ def parse_file(self, pythonpath): @@ -369,8 +369,8 @@ class BatchCodeProcessor(object): 1) Lines starting with #HEADER starts a header block (ends other blocks) 2) Lines starting with #CODE begins a code block (ends other blocks) - 3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ... - 4) Lines starting with #INSERT are on form #INSERT filename. + 3) #CODE headers may be of the following form: #CODE (info) objname, objname2, ... + 4) Lines starting with #INSERT are on form #INSERT filename. 3) All lines outside blocks are stripped. 4) All excess whitespace beginning/ending a block is stripped. @@ -379,9 +379,9 @@ class BatchCodeProcessor(object): # helper function def parse_line(line): """ - Identifies the line type: block command, comment, empty or normal code. + Identifies the line type: block command, comment, empty or normal code. - """ + """ parseline = line.strip() if parseline.startswith("#HEADER"): @@ -399,7 +399,7 @@ class BatchCodeProcessor(object): if info: info = info[0] line = line.replace(info, "") - objs = [o.strip() for o in line.split(",") if o.strip()] + objs = [o.strip() for o in line.split(",") if o.strip()] return ("codeheader", info, objs) elif parseline.startswith('#'): return ('comment', "", "%s" % line) @@ -422,25 +422,25 @@ class BatchCodeProcessor(object): in_code = False for line in lines: - # parse line + # parse line mode, info, line = parse_line(line) # try: - # print "::", in_header, in_code, mode, line.strip() + # print "::", in_header, in_code, mode, line.strip() # except: - # print "::", in_header, in_code, mode, line - if mode == 'insert': + # print "::", in_header, in_code, mode, line + if mode == 'insert': # recursive load of inserted code files - note that we # are not checking for cyclic imports! in_header = False in_code = False inserted_codes = self.parse_file(line) or [{'objs':"", 'info':line, 'code':""}] - for codedict in inserted_codes: - codedict["inserted"] = True + for codedict in inserted_codes: + codedict["inserted"] = True codes.extend(inserted_codes) elif mode == 'header': in_header = True in_code = False - elif mode == 'codeheader': + elif mode == 'codeheader': in_header = False in_code = True # the line is a list of object variable names @@ -468,9 +468,9 @@ class BatchCodeProcessor(object): # just check for errors. if not codedict['code']: codedict['code'] = "{r#INSERT ERROR: %s{n" % codedict['info'] - else: + else: objs = ", ".join(codedict["objs"]) - if objs: + if objs: objs = "[%s]" % objs codedict["code"] = "#CODE %s %s \n%s\n\n%s" % (codedict['info'], objs, @@ -486,7 +486,7 @@ class BatchCodeProcessor(object): """ # define the execution environment environ = "setup_environ(settings_module)" - environdict = {"setup_environ":setup_environ, + environdict = {"setup_environ":setup_environ, "settings_module":settings_module} if extra_environ: for key, value in extra_environ.items(): @@ -499,11 +499,11 @@ class BatchCodeProcessor(object): for obj in codedict['objs']: code += "\ntry: %s.delete()\nexcept: pass" % obj - # execute the block + # execute the block try: exec(code, environdict) except Exception: - etype, value, tb = sys.exc_info() + etype, value, tb = sys.exc_info() fname = tb_filename(tb) for tb in tb_iter(tb): @@ -512,15 +512,15 @@ class BatchCodeProcessor(object): lineno = tb.tb_lineno - 1 err = "" for iline, line in enumerate(code.split("\n")): - if iline == lineno: - err += "\n{w%02i{n: %s" % (iline + 1, line) - elif lineno - 5 < iline < lineno + 5: - err += "\n%02i: %s" % (iline + 1, line) + if iline == lineno: + err += "\n{w%02i{n: %s" % (iline + 1, line) + elif lineno - 5 < iline < lineno + 5: + err += "\n%02i: %s" % (iline + 1, line) - err += "\n".join(traceback.format_exception(etype, value, tb)) + err += "\n".join(traceback.format_exception(etype, value, tb)) #errlist = format_exc().split('\n') #if len(errlist) > 4: - # errlist = errlist[4:] + # errlist = errlist[4:] #err = "\n".join(" %s" % line for line in errlist if line) if debug: