diff --git a/daemon.py b/daemon.py index 23ba2a25..537cc644 100644 --- a/daemon.py +++ b/daemon.py @@ -12,6 +12,7 @@ import commentjson import json import time import base64 +import locale # used for mime decoding of message POST import email.parser # for saving images @@ -604,7 +605,8 @@ class PubServer(BaseHTTPRequestHandler): optionsLink=None if len(optionsList)>3: optionsLink=optionsList[3] - msg=htmlPersonOptions(self.server.baseDir, \ + msg=htmlPersonOptions(self.server.translate, \ + self.server.baseDir, \ self.server.domain, \ originPathStr, \ optionsActor, \ @@ -623,7 +625,7 @@ class PubServer(BaseHTTPRequestHandler): if htmlGET and '?rmshare=' in self.path: shareName=self.path.split('?rmshare=')[1] actor=self.server.httpPrefix+'://'+self.server.domainFull+self.path.split('?rmshare=')[0] - msg=htmlRemoveSharedItem(self.server.baseDir,actor,shareName).encode() + msg=htmlRemoveSharedItem(self.server.translate,self.server.baseDir,actor,shareName).encode() if not msg: self._redirect_headers(actor+'/inbox',cookie) self.server.GETbusy=False @@ -919,7 +921,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.GETbusy=False return hashtagStr= \ - htmlHashtagSearch(self.server.baseDir,hashtag,pageNumber, \ + htmlHashtagSearch(self.server.translate, \ + self.server.baseDir,hashtag,pageNumber, \ maxPostsInFeed,self.server.session, \ self.server.cachedWebfingers, \ self.server.personCache, \ @@ -939,7 +942,8 @@ class PubServer(BaseHTTPRequestHandler): if htmlGET and '/users/' in self.path: if self.path.endswith('/search'): # show the search screen - msg=htmlSearch(self.server.baseDir,self.path).encode() + msg=htmlSearch(self.server.translate, \ + self.server.baseDir,self.path).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.GETbusy=False @@ -949,7 +953,9 @@ class PubServer(BaseHTTPRequestHandler): if htmlGET and '/users/' in self.path: if self.path.endswith('/searchemoji'): # show the search screen - msg=htmlSearchEmojiTextEntry(self.server.baseDir,self.path).encode() + msg=htmlSearchEmojiTextEntry(self.server.translate, \ + self.server.baseDir, \ + self.path).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.GETbusy=False @@ -1189,7 +1195,7 @@ class PubServer(BaseHTTPRequestHandler): self.server.useTor) deleteStr= \ - htmlDeletePost(pageNumber, \ + htmlDeletePost(self.server.translate,pageNumber, \ self.server.session,self.server.baseDir, \ deleteUrl,self.server.httpPrefix, \ __version__,self.server.cachedWebfingers, \ @@ -1279,7 +1285,12 @@ class PubServer(BaseHTTPRequestHandler): self.path.endswith('/newdm') or \ self.path.endswith('/newreport') or \ self.path.endswith('/newshare')): - msg=htmlNewPost(self.server.baseDir,self.path,inReplyToUrl,replyToList,shareDescription,replyPageNumber).encode() + msg=htmlNewPost(self.server.translate, \ + self.server.baseDir, \ + self.path,inReplyToUrl, \ + replyToList, \ + shareDescription, \ + replyPageNumber).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.GETbusy=False @@ -1311,7 +1322,8 @@ class PubServer(BaseHTTPRequestHandler): postJsonObject['likes']={'items': []} if self._requestHTTP(): msg= \ - htmlIndividualPost(self.server.session, \ + htmlIndividualPost(self.server.translate, \ + self.server.session, \ self.server.cachedWebfingers,self.server.personCache, \ nickname,self.server.domain,self.server.port, \ authorized,postJsonObject, \ @@ -1361,7 +1373,8 @@ class PubServer(BaseHTTPRequestHandler): print('DEBUG: creating new session') self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlPostReplies(self.server.baseDir, \ + msg=htmlPostReplies(self.server.translate, \ + self.server.baseDir, \ self.server.session, \ self.server.cachedWebfingers, \ self.server.personCache, \ @@ -1406,7 +1419,8 @@ class PubServer(BaseHTTPRequestHandler): print('DEBUG: creating new session') self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlPostReplies(self.server.baseDir, \ + msg=htmlPostReplies(self.server.translate, \ + self.server.baseDir, \ self.server.session, \ self.server.cachedWebfingers, \ self.server.personCache, \ @@ -1440,7 +1454,8 @@ class PubServer(BaseHTTPRequestHandler): personLookup(self.server.domain,self.path.replace('/roles',''), \ self.server.baseDir) if getPerson: - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ True, \ @@ -1476,7 +1491,8 @@ class PubServer(BaseHTTPRequestHandler): personLookup(self.server.domain,self.path.replace('/skills',''), \ self.server.baseDir) if getPerson: - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ True, \ @@ -1533,7 +1549,8 @@ class PubServer(BaseHTTPRequestHandler): if postJsonObject.get('likes'): postJsonObject['likes']={'items': []} if self._requestHTTP(): - msg=htmlIndividualPost(self.server.baseDir, \ + msg=htmlIndividualPost(self.server.translate, \ + self.server.baseDir, \ self.server.session, \ self.server.cachedWebfingers,self.server.personCache, \ nickname,self.server.domain,self.server.port, \ @@ -1823,7 +1840,8 @@ class PubServer(BaseHTTPRequestHandler): print('DEBUG: creating new session') self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ authorized, \ @@ -1873,7 +1891,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ authorized, \ @@ -1921,7 +1940,8 @@ class PubServer(BaseHTTPRequestHandler): print('DEBUG: creating new session') self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ authorized, \ @@ -1952,7 +1972,8 @@ class PubServer(BaseHTTPRequestHandler): print('DEBUG: creating new session') self.server.session= \ createSession(self.server.domain,self.server.port,self.server.useTor) - msg=htmlProfile(self.server.projectVersion, \ + msg=htmlProfile(self.server.translate, \ + self.server.projectVersion, \ self.server.baseDir, \ self.server.httpPrefix, \ authorized, \ @@ -2755,7 +2776,8 @@ class PubServer(BaseHTTPRequestHandler): if searchStr.startswith('#'): # hashtag search hashtagStr= \ - htmlHashtagSearch(self.server.baseDir,searchStr[1:],1, \ + htmlHashtagSearch(self.server.translate, \ + self.server.baseDir,searchStr[1:],1, \ maxPostsInFeed,self.server.session, \ self.server.cachedWebfingers, \ self.server.personCache, \ @@ -2789,7 +2811,8 @@ class PubServer(BaseHTTPRequestHandler): self.server.port, \ self.server.useTor) profileStr= \ - htmlProfileAfterSearch(self.server.baseDir, \ + htmlProfileAfterSearch(self.server.translate, \ + self.server.baseDir, \ self.path.replace('/searchhandle',''), \ self.server.httpPrefix, \ nickname, \ @@ -3134,7 +3157,11 @@ class PubServer(BaseHTTPRequestHandler): if '&submitUnblock=' in optionsConfirmParams: if self.server.debug: print('Unblocking '+optionsActor) - msg=htmlUnblockConfirm(self.server.baseDir,originPathStr,optionsActor,optionsAvatarUrl).encode() + msg=htmlUnblockConfirm(self.server.translate, \ + self.server.baseDir, \ + originPathStr, \ + optionsActor, \ + optionsAvatarUrl).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.POSTbusy=False @@ -3142,7 +3169,11 @@ class PubServer(BaseHTTPRequestHandler): if '&submitFollow=' in optionsConfirmParams: if self.server.debug: print('Following '+optionsActor) - msg=htmlFollowConfirm(self.server.baseDir,originPathStr,optionsActor,optionsAvatarUrl).encode() + msg=htmlFollowConfirm(self.server.translate, \ + self.server.baseDir, \ + originPathStr, \ + optionsActor, \ + optionsAvatarUrl).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.POSTbusy=False @@ -3150,7 +3181,11 @@ class PubServer(BaseHTTPRequestHandler): if '&submitUnfollow=' in optionsConfirmParams: if self.server.debug: print('Unfollowing '+optionsActor) - msg=htmlUnfollowConfirm(self.server.baseDir,originPathStr,optionsActor,optionsAvatarUrl).encode() + msg=htmlUnfollowConfirm(self.server.translate, \ + self.server.baseDir, \ + originPathStr, \ + optionsActor, \ + optionsAvatarUrl).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.POSTbusy=False @@ -3159,7 +3194,11 @@ class PubServer(BaseHTTPRequestHandler): if self.server.debug: print('Sending DM to '+optionsActor) reportPath=self.path.replace('/personoptions','')+'/newdm' - msg=htmlNewPost(self.server.baseDir,reportPath,None,[optionsActor],None,pageNumber).encode() + msg=htmlNewPost(self.server.translate, \ + self.server.baseDir, \ + reportPath,None, \ + [optionsActor],None, \ + pageNumber).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.POSTbusy=False @@ -3168,7 +3207,10 @@ class PubServer(BaseHTTPRequestHandler): if self.server.debug: print('Reporting '+optionsActor) reportPath=self.path.replace('/personoptions','')+'/newreport' - msg=htmlNewPost(self.server.baseDir,reportPath,None,[],postUrl,pageNumber).encode() + msg=htmlNewPost(self.server.translate, \ + self.server.baseDir, \ + reportPath,None,[], \ + postUrl,pageNumber).encode() self._set_headers('text/html',len(msg),cookie) self.wfile.write(msg) self.server.POSTbusy=False @@ -3462,6 +3504,26 @@ def runDaemon(projectVersion, \ httpd = ThreadingHTTPServer(serverAddress, PubServerUnitTest) else: httpd = ThreadingHTTPServer(serverAddress, PubServer) + + # load translations dictionary + httpd.translate={} + if not unitTest: + if not os.path.isdir(baseDir+'/translations'): + print('ERROR: translations directory not found') + return + systemLanguage=locale.getdefaultlocale()[0] + if '_' in systemLanguage: + systemLanguage=systemLanguage.split('_')[0] + if '.' in systemLanguage: + systemLanguage=systemLanguage.split('.')[0] + translationsFile=baseDir+'/translations/'+systemLanguage+'.json' + if not os.path.isfile(translationsFile): + systemLanguage='en' + translationsFile=baseDir+'/translations/'+systemLanguage+'.json' + print('System language: '+systemLanguage) + with open(translationsFile, 'r') as fp: + httpd.translate=commentjson.load(fp) + httpd.outboxThread={} httpd.projectVersion=projectVersion # max POST size of 30M diff --git a/translations/en.json b/translations/en.json new file mode 100644 index 00000000..c9e1a759 --- /dev/null +++ b/translations/en.json @@ -0,0 +1,94 @@ +{ + "SHOW MORE": "SHOW MORE", + "Your browser does not support the video tag.": "Your browser does not support the video tag.", + "Your browser does not support the audio tag.": "Your browser does not support the audio tag.", + "Show profile": "Show profile", + "Show options for this person": "Show options for this person", + "Repeat this post": "Repeat this post", + "Undo the repeat": "Undo the repeat", + "Like this post": "Like this post", + "Undo the like": "Undo the like", + "Delete this post": "Delete this post", + "Reply to this post": "Reply to this post", + "Write your post text below.": "Write your post text below.", + "Write your reply to": "Write your reply to", + "this post": "this post", + "Write your report below.": "Write your report below.", + "This message only goes to moderators, even if it mentions other fediverse addresses.": "This message only goes to moderators, even if it mentions other fediverse addresses.", + "Also see": "Also see", + "Terms of Service": "Terms of Service", + "Enter the details for your shared item below.": "Enter the details for your shared item below.", + "Subject or Content Warning (optional)": "Subject or Content Warning (optional)", + "Write something": "Write something", + "Name of the shared item": "Name of the shared item", + "Description of the item being shared": "Description of the item being shared", + "Type of shared item. eg. hat": "Type of shared item. eg. hat", + "Category of shared item. eg. clothing": "Category of shared item. eg. clothing", + "Duration of listing in days": "Duration of listing in days", + "City or location of the shared item": "City or location of the shared item", + "Describe a shared item": "Describe a shared item", + "Public": "Public", + "Visible to anyone": "Visible to anyone", + "Unlisted": "Unlisted", + "Not on public timeline": "Not on public timeline", + "Followers": "Followers", + "Only to followers": "Only to followers", + "DM": "DM", + "Only to mentioned people": "Only to mentioned people", + "Report": "Report", + "Send to moderators": "Send to moderators", + "Search for emoji": "Search for emoji", + "Cancel": "Cancel", + "Submit": "Submit", + "Image description": "Image description", + "Item image": "Item image", + "Type": "Type", + "Category": "Category", + "Location": "Location", + "Login": "Login", + "Edit": "Edit", + "Switch to timeline view": "Switch to timeline view", + "Approve": "Approve", + "Deny": "Deny", + "Posts": "Posts", + "Following": "Following", + "Followers": "Followers", + "Roles": "Roles", + "Skills": "Skills", + "Shares": "Shares", + "Block": "Block", + "Unfollow": "Unfollow", + "Your browser does not support the audio element.": "Your browser does not support the audio element.", + "Your browser does not support the video element.": "Your browser does not support the video element.", + "Create a new post": "Create a new post", + "Create a new DM": "Create a new DM", + "Switch to profile view": "Switch to profile view", + "Inbox": "Inbox", + "Outbox": "Outbox", + "Search and follow": "Search and follow", + "Refresh": "Refresh", + "Nickname or URL. Block using *@domain or nickname@domain": "Nickname or URL. Block using *@domain or nickname@domain", + "Remove the above item": "Remove the above item", + "Remove": "Remove", + "Suspend the above account nickname": "Suspend the above account nickname", + "Suspend": "Suspend", + "Remove a suspension for an account nickname": "Remove a suspension for an account nickname", + "Unsuspend": "Unsuspend", + "Block an account on another instance": "Block an account on another instance", + "Unblock": "Unblock", + "Unblock an account on another instance": "Unblock an account on another instance", + "Information about current blocks/suspensions": "Information about current blocks/suspensions", + "Info": "Info", + "Remove": "Remove", + "Yes": "Yes", + "No": "No", + "Delete this post?": "Delete this post?", + "Follow": "Follow", + "Stop following": "Stop following", + "Options for": "Options for", + "View": "View", + "Stop blocking": "Stop blocking", + "Enter an emoji name to search for": "Enter an emoji name to search for", + "Enter an address, shared item, #hashtag, *skill or :emoji: to search for": "Enter an address, shared item, #hashtag, *skill or :emoji: to search for", + "Go Back": "Go Back" +} diff --git a/translations/fr.json b/translations/fr.json new file mode 100644 index 00000000..afc28d2b --- /dev/null +++ b/translations/fr.json @@ -0,0 +1,94 @@ +{ + "SHOW MORE": "MONTRE PLUS", + "Your browser does not support the video tag.": "Votre navigateur ne supporte pas le tag vidéo.", + "Your browser does not support the audio tag.": "Votre navigateur ne supporte pas la balise audio.", + "Show profile": "Montre le profile", + "Show options for this person": "Afficher les options pour cette personne", + "Repeat this post": "Répétez ce post", + "Undo the repeat": "Annuler la répétition", + "Like this post": "Comme ce poste", + "Undo the like": "Annuler le même", + "Delete this post": "Supprimer ce post", + "Reply to this post": "Répondre à ce post", + "Write your post text below.": "Entrez votre message ci-dessous.", + "Write your reply to": "Écrivez votre réponse à", + "this post": "ce post", + "Write your report below.": "Écrivez votre rapport ci-dessous.", + "This message only goes to moderators, even if it mentions other fediverse addresses.": "Ce message n’adresse que les modérateurs, même s’il mentionne d’autres adresses fedivers.", + "Also see": "Regarde aussi", + "Terms of Service": "Conditions d'utilisation", + "Enter the details for your shared item below.": "Entrez les détails de votre article partagé ci-dessous.", + "Subject or Content Warning (optional)": "Avertissement de sujet ou de contenu (facultatif)", + "Write something": "Écris quelque chose", + "Name of the shared item": "Nom de l'élément partagé", + "Description of the item being shared": "Description de l'élément en cours de partage", + "Type of shared item. eg. hat": "Type d'élément partagé. par exemple. chapeau", + "Category of shared item. eg. clothing": "Catégorie d'élément partagé. par exemple. Vêtements", + "Duration of listing in days": "Durée de la cotation en jours", + "City or location of the shared item": "Ville ou lieu de l'élément partagé", + "Describe a shared item": "Décrire un élément partagé", + "Public": "Publique", + "Visible to anyone": "Visible par n'importe qui", + "Unlisted": "Non répertorié", + "Not on public timeline": "Pas sur la chronologie publique", + "Followers": "Suiveuses", + "Only to followers": "Seulement aux adeptes", + "DM": "MD", + "Only to mentioned people": "Seulement aux personnes mentionnées", + "Report": "Rapport", + "Send to moderators": "Envoyer aux modérateurs", + "Search for emoji": "Recherche emoji", + "Cancel": "Annuler", + "Submit": "Soumettre", + "Image description": "Description de l'image", + "Item image": "Image de l'article", + "Type": "Type", + "Category": "Catégorie", + "Location": "Emplacement", + "Login": "S'identifier", + "Edit": "Modifier", + "Switch to timeline view": "Passer en vue chronologique", + "Approve": "Approuver", + "Deny": "Nier", + "Posts": "Des postes", + "Following": "Suivante", + "Followers": "Suiveuses", + "Roles": "Rôles", + "Skills": "Compétences", + "Shares": "Actions", + "Block": "Bloc", + "Unfollow": "Se désabonner", + "Your browser does not support the audio element.": "Votre navigateur ne supporte pas l'élément audio.", + "Your browser does not support the video element.": "Votre application ne supporte pas le format de l'élément vidéo.", + "Create a new post": "Créer un nouveau post", + "Create a new DM": "Créer un nouveau message direct", + "Switch to profile view": "Passer en vue de profil", + "Inbox": "Réception", + "Outbox": "Envoi", + "Search and follow": "Rechercher et suivre", + "Refresh": "Rafraîchir", + "Nickname or URL. Block using *@domain or nickname@domain": "Surnom ou URL. Bloquer en utilisant *@domain ou pseudo@domain", + "Remove the above item": "Supprimer l'élément ci-dessus", + "Remove": "Retirer", + "Suspend the above account nickname": "Suspendre le pseudo du compte ci-dessus", + "Suspend": "Suspendre", + "Remove a suspension for an account nickname": "Supprimer une suspension pour un pseudo de compte", + "Unsuspend": "Insuffler", + "Block an account on another instance": "Bloquer un compte sur une autre instance", + "Unblock": "Débloquer", + "Unblock an account on another instance": "Débloquer un compte sur une autre instance", + "Information about current blocks/suspensions": "Informations sur les blocs / suspensions en cours", + "Info": "Info", + "Remove": "Retirer", + "Yes": "Oui", + "No": "Non", + "Delete this post?": "Supprimer ce post?", + "Follow": "Suivre", + "Stop following": "Arrête de suivre", + "Options for": "Options pour", + "View": "Vue", + "Stop blocking": "Arrêtez le blocage", + "Enter an emoji name to search for": "Entrez un nom emoji à rechercher", + "Enter an address, shared item, #hashtag, *skill or :emoji: to search for": "Entrez une adresse, un objet partagé, #hashtag, * skill ou: emoji: à rechercher", + "Go Back": "Retourner" +} diff --git a/webinterface.py b/webinterface.py index 332e2e9f..5d98174b 100644 --- a/webinterface.py +++ b/webinterface.py @@ -221,7 +221,8 @@ def htmlModerationInfo(baseDir: str) -> str: infoForm+=htmlFooter() return infoForm -def htmlHashtagSearch(baseDir: str,hashtag: str,pageNumber: int,postsPerPage: int, +def htmlHashtagSearch(translate: {}, \ + baseDir: str,hashtag: str,pageNumber: int,postsPerPage: int, \ session,wfRequest: {},personCache: {}, \ httpPrefix: str,projectVersion: str) -> str: """Show a page containing search results for a hashtag @@ -272,7 +273,8 @@ def htmlHashtagSearch(baseDir: str,hashtag: str,pageNumber: int,postsPerPage: in index-=1 continue hashtagSearchForm+= \ - individualPostAsHtml(None,baseDir,session,wfRequest,personCache, \ + individualPostAsHtml(translate,None, \ + baseDir,session,wfRequest,personCache, \ nickname,domain,port,postJsonObject, \ None,True,False, \ httpPrefix,projectVersion, \ @@ -680,20 +682,23 @@ def htmlSuspended(baseDir: str) -> str: suspendedForm+=htmlFooter() return suspendedForm -def htmlNewPost(baseDir: str,path: str,inReplyTo: str,mentions: [],reportUrl: str,pageNumber: int) -> str: +def htmlNewPost(translate: {},baseDir: str, \ + path: str,inReplyTo: str, \ + mentions: [], \ + reportUrl: str,pageNumber: int) -> str: """New post screen """ replyStr='' if not path.endswith('/newshare'): if not path.endswith('/newreport'): if not inReplyTo: - newPostText='
Enter your post text below.
' + newPostText=''+translate['Write your post text below.']+'
' else: - newPostText='Enter your reply to this post below.
' + newPostText=''+translate['Write your reply to']+' '+translate['this post']+'
' replyStr='' else: newPostText= \ - 'Enter your report below.
' + ''+translate['Write your report below.']+'
' # custom report header with any additional instructions if os.path.isfile(baseDir+'/accounts/report.txt'): @@ -704,9 +709,9 @@ def htmlNewPost(baseDir: str,path: str,inReplyTo: str,mentions: [],reportUrl: st customReportText=customReportText.replace('','
') newPostText+=customReportText - newPostText+='
This message only goes to moderators, even if it mentions other fediverse addresses.
You can also refer to points within the Terms of Service if necessary.
' + newPostText+=''+translate['This message only goes to moderators, even if it mentions other fediverse addresses.']+'
'+translate['Also see']+' '+translate['Terms of Service']+'
' else: - newPostText='Enter the details for your shared item below.
' + newPostText=''+translate['Enter the details for your shared item below.']+'
' if os.path.isfile(baseDir+'/accounts/newpost.txt'): with open(baseDir+'/accounts/newpost.txt', 'r') as file: @@ -721,8 +726,8 @@ def htmlNewPost(baseDir: str,path: str,inReplyTo: str,mentions: [],reportUrl: st scopeIcon='scope_public.png' scopeDescription='Public' - placeholderSubject='Subject or Content Warning (optional)...' - placeholderMessage='Write something...' + placeholderSubject=translate['Subject or Content Warning (optional)']+'...' + placeholderMessage=translate['Write something']+'...' extraFields='' endpoint='newpost' if path.endswith('/newunlisted'): @@ -744,23 +749,23 @@ def htmlNewPost(baseDir: str,path: str,inReplyTo: str,mentions: [],reportUrl: st if path.endswith('/newshare'): scopeIcon='scope_share.png' scopeDescription='Shared Item' - placeholderSubject='Name of the shared item...' - placeholderMessage='Description of the item being shared...' + placeholderSubject=translate['Name of the shared item']+'...' + placeholderMessage=translate['Description of the item being shared']+'...' endpoint='newshare' extraFields= \ '