code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:28+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Vietnamese (http://www.transifex.com/gnu-social/gnu-social/language/vi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: vi\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Button text for submitting a poll response.
#. TRANS: Button text for submitting a revised answer.
#: forms/qnavote.php:118 forms/qnareviseanswer.php:119
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Form legend for showing the answer.
#. TRANS: Page title for and answer to a question.
#. TRANS: Page title after sending an answer.
#. TRANS: Page title for and answer to a question.
#: forms/qnashowanswer.php:113 actions/qnavote.php:63
#: actions/qnareviseanswer.php:161 actions/qnareviseanswer.php:203
#: actions/qnanewanswer.php:63
msgid "Answer"
msgstr ""

#. TRANS: Button text for marking an answer as "best".
#: forms/qnashowanswer.php:150
msgctxt "BUTTON"
msgid "Best"
msgstr ""

#. TRANS: Title for button text marking an answer as "best".
#: forms/qnashowanswer.php:154
msgid "Mark this answer as the best answer."
msgstr ""

#. TRANS: Field label for a new question.
#: forms/qnanewquestion.php:110
msgctxt "LABEL"
msgid "Title"
msgstr ""

#. TRANS: Field title for a new question.
#: forms/qnanewquestion.php:113
msgid "The title of your question."
msgstr ""

#. TRANS: Field label for question details.
#: forms/qnanewquestion.php:122
msgctxt "LABEL"
msgid "Description"
msgstr "Mô tả"

#. TRANS: Field title for question details.
#: forms/qnanewquestion.php:125
msgid "Your question in detail."
msgstr ""

#. TRANS: Button text for saving a new question.
#: forms/qnanewquestion.php:149
msgctxt "BUTTON"
msgid "Save"
msgstr "Lưu"

#. TRANS: Form legend for revising the answer.
#: forms/qnashowquestion.php:106
msgctxt "LEGEND"
msgid "Question"
msgstr ""

#. TRANS: Button text for closing a question.
#: forms/qnashowquestion.php:151
msgctxt "BUTTON"
msgid "Close"
msgstr ""

#. TRANS: Title for button text for closing a question.
#: forms/qnashowquestion.php:155
msgid "Close the question to no one can answer it anymore."
msgstr ""

#. TRANS: Field label.
#: forms/qnanewanswer.php:114
msgid "Enter your answer"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/qnanewanswer.php:125
msgctxt "BUTTON"
msgid "Answer"
msgstr ""

#. TRANS: Plugin description.
#: QnAPlugin.php:136
msgid "Question and Answers micro-app."
msgstr ""

#. TRANS: Application title.
#: QnAPlugin.php:143
msgctxt "TITLE"
msgid "Question"
msgstr ""

#. TRANS: Exception thrown when there are too many activity objects.
#: QnAPlugin.php:171
msgid "Too many activity objects."
msgstr ""

#. TRANS: Exception thrown when an incorrect object type is encountered.
#: QnAPlugin.php:178
msgid "Wrong type for object."
msgstr ""

#. TRANS: Exception thrown when answering a non-existing question.
#: QnAPlugin.php:197
msgid "Answer to unknown question."
msgstr ""

#. TRANS: Exception thrown when an object type is encountered that cannot be
#. handled.
#: QnAPlugin.php:203 QnAPlugin.php:233
msgid "Unknown object type."
msgstr ""

#. TRANS: Exception thrown when requesting a non-existing question notice.
#: QnAPlugin.php:240
msgid "Unknown question notice."
msgstr ""

#. TRANS: Placeholder value for a possible answer to a question
#. TRANS: by the logged in user.
#: QnAPlugin.php:368
msgid "Your answer..."
msgstr ""

#. TRANS: Link description for link to full notice text if it is longer than
#. TRANS: what will be dispplayed.
#: QnAPlugin.php:393
msgid "…"
msgstr ""

#. TRANS: Title for link that is an ellipsis in English.
#: QnAPlugin.php:398
msgid "more..."
msgstr ""

#. TRANS: Page title for close a question
#: actions/qnaclosequestion.php:63
msgid "Close question"
msgstr ""

#. TRANS: Client exception thrown trying to close a question when not logged
#. in
#: actions/qnaclosequestion.php:85
msgid "You must be logged in to close a question."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnaclosequestion.php:98 actions/qnavote.php:96
#: actions/qnanewanswer.php:101
msgid "Invalid or missing question."
msgstr ""

#. TRANS: Exception thrown trying to close another user's question.
#: actions/qnaclosequestion.php:136
msgid "You did not ask this question."
msgstr ""

#. TRANS: Page title after sending an answer.
#. TRANS: Page title after sending in a vote for a question or answer.
#. TRANS: Page title after sending an answer.
#: actions/qnaclosequestion.php:153 actions/qnavote.php:148
#: actions/qnanewanswer.php:158
msgid "Answers"
msgstr ""

#. TRANS: Client exception thrown trying to answer a question while not logged
#. in.
#: actions/qnavote.php:84 actions/qnareviseanswer.php:84
#: actions/qnanewanswer.php:85
msgid "You must be logged in to answer to a question."
msgstr ""

#. TRANS: Client exception thrown when requesting a non-existing answer.
#. TRANS: Did we used to have it, and it got deleted?
#: actions/qnashowanswer.php:68 actions/qnashowanswer.php:82
msgid "No such answer."
msgstr ""

#. TRANS: Client exception thrown when requesting an answer that has no
#. connected question.
#: actions/qnashowanswer.php:75
msgid "No question for this answer."
msgstr ""

#. TRANS: Client exception thrown when requesting answer data for a non-
#. existing user.
#. TRANS: Client exception thrown trying to view a question of a non-existing
#. user.
#: actions/qnashowanswer.php:89 actions/qnashowquestion.php:83
msgid "No such user."
msgstr "Không có user nào."

#. TRANS: Client exception thrown when requesting answer data for a user
#. without a profile.
#. TRANS: Server exception thrown trying to view a question for a user for
#. which the profile could not be loaded.
#: actions/qnashowanswer.php:96 actions/qnashowquestion.php:90
msgid "User without a profile."
msgstr ""

#. TRANS: Page title.
#. TRANS: %1$s is the user who answered a question, %2$s is the question.
#: actions/qnashowanswer.php:122
#, php-format
msgid "%1$s's answer to \"%2$s\""
msgstr ""

#. TRANS: Page title for revising a question
#: actions/qnareviseanswer.php:62
msgid "Revise answer"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnareviseanswer.php:97
msgid "Invalid or missing answer."
msgstr ""

#. TRANS: Form title for sending an answer.
#: actions/qnareviseanswer.php:241
msgctxt "TITLE"
msgid "Answer"
msgstr ""

#. TRANS: Title for Question page.
#: actions/qnanewquestion.php:62
msgid "New question"
msgstr ""

#. TRANS: Client exception thrown trying to create a Question while not logged
#. in.
#: actions/qnanewquestion.php:81
msgid "You must be logged in to post a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a question without a title.
#: actions/qnanewquestion.php:129
msgid "Question must have a title."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/qnanewquestion.php:154
msgid "Question posted"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question.
#: actions/qnashowquestion.php:68
msgid "No such question."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question
#. notice.
#: actions/qnashowquestion.php:76
msgid "No such question notice."
msgstr ""

#. TRANS: Page title for a question.
#. TRANS: %1$s is the nickname of the user who asked the question, %2$s is the
#. question.
#: actions/qnashowquestion.php:155
#, php-format
msgid "%1$s's question: %2$s"
msgstr ""

#. TRANS: Page title after an AJAX error occurs on the post answer page.
#: actions/qnanewanswer.php:224
msgid "Ajax Error"
msgstr ""

#. TRANS: Title for form to send answer to a question.
#: actions/qnanewanswer.php:247
msgctxt "TITLE"
msgid "Your answer"
msgstr ""

#. TRANS: Error message displayed when an answer has no content.
#. TRANS: Error message displayed when answer data is not present.
#: actions/qnanewanswer.php:344 lib/qnalistitem.php:118
msgid "Answer data is missing."
msgstr ""

#. TRANS: Exception thown when getting a question with a non-existing ID.
#. TRANS: %s is the non-existing question ID.
#: classes/QnA_Answer.php:146
#, php-format
msgid "No question with ID %s"
msgstr ""

#. TRANS: Exception thown when getting a profile with a non-existing ID.
#. TRANS: %s is the non-existing profile ID.
#. TRANS: Exception trown when getting a profile for a non-existing ID.
#. TRANS: %s is the provided profile ID.
#: classes/QnA_Answer.php:157 classes/QnA_Question.php:121
#, php-format
msgid "No profile with ID %s"
msgstr ""

#. TRANS: %s is the number of answer revisions.
#: classes/QnA_Answer.php:202
#, php-format
msgid "%s revision"
msgid_plural "%s revisions"
msgstr[0] ""

#. TRANS: Text for a question that was answered.
#. TRANS: %1$s is the user that answered, %2$s is the question title,
#. TRANS: %2$s is the answer content.
#: classes/QnA_Answer.php:222
#, php-format
msgid "%1$s answered the question \"%2$s\": %3$s"
msgstr ""

#. TRANS: Text for a question that was answered.
#. TRANS: %s is the question title.
#. TRANS: Rendered version of the notice content answering a question.
#. TRANS: %s a link to the question with question title as the link content.
#: classes/QnA_Answer.php:263 classes/QnA_Answer.php:270
#, php-format
msgid "answered \"%s\""
msgstr ""

#. TRANS: Number of given answers to a question.
#. TRANS: %s is the number of given answers.
#: classes/QnA_Question.php:208
#, php-format
msgid "%s answer"
msgid_plural "%s answers"
msgstr[0] ""

#. TRANS: Notification that a question cannot be answered anymore because it
#. is closed.
#: classes/QnA_Question.php:215
msgid "This question is closed."
msgstr ""

#. TRANS: Rendered version of the notice content creating a question.
#. TRANS: %s a link to the question as link description.
#: classes/QnA_Question.php:279
#, php-format
msgid "Question: %s"
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a question.
#. TRANS: %s is the unpexpected object type.
#: lib/qnalistitem.php:67
#, php-format
msgid "Unexpected type for QnA plugin: %s."
msgstr ""

#. TRANS: Error message displayed when question data is not present.
#: lib/qnalistitem.php:93
msgid "Question data is missing."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:28+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (http://www.transifex.com/gnu-social/gnu-social/language/zh/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Button text for submitting a poll response.
#. TRANS: Button text for submitting a revised answer.
#: forms/qnavote.php:118 forms/qnareviseanswer.php:119
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Form legend for showing the answer.
#. TRANS: Page title for and answer to a question.
#. TRANS: Page title after sending an answer.
#. TRANS: Page title for and answer to a question.
#: forms/qnashowanswer.php:113 actions/qnavote.php:63
#: actions/qnareviseanswer.php:161 actions/qnareviseanswer.php:203
#: actions/qnanewanswer.php:63
msgid "Answer"
msgstr ""

#. TRANS: Button text for marking an answer as "best".
#: forms/qnashowanswer.php:150
msgctxt "BUTTON"
msgid "Best"
msgstr ""

#. TRANS: Title for button text marking an answer as "best".
#: forms/qnashowanswer.php:154
msgid "Mark this answer as the best answer."
msgstr ""

#. TRANS: Field label for a new question.
#: forms/qnanewquestion.php:110
msgctxt "LABEL"
msgid "Title"
msgstr ""

#. TRANS: Field title for a new question.
#: forms/qnanewquestion.php:113
msgid "The title of your question."
msgstr ""

#. TRANS: Field label for question details.
#: forms/qnanewquestion.php:122
msgctxt "LABEL"
msgid "Description"
msgstr ""

#. TRANS: Field title for question details.
#: forms/qnanewquestion.php:125
msgid "Your question in detail."
msgstr ""

#. TRANS: Button text for saving a new question.
#: forms/qnanewquestion.php:149
msgctxt "BUTTON"
msgid "Save"
msgstr ""

#. TRANS: Form legend for revising the answer.
#: forms/qnashowquestion.php:106
msgctxt "LEGEND"
msgid "Question"
msgstr ""

#. TRANS: Button text for closing a question.
#: forms/qnashowquestion.php:151
msgctxt "BUTTON"
msgid "Close"
msgstr ""

#. TRANS: Title for button text for closing a question.
#: forms/qnashowquestion.php:155
msgid "Close the question to no one can answer it anymore."
msgstr ""

#. TRANS: Field label.
#: forms/qnanewanswer.php:114
msgid "Enter your answer"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/qnanewanswer.php:125
msgctxt "BUTTON"
msgid "Answer"
msgstr ""

#. TRANS: Plugin description.
#: QnAPlugin.php:136
msgid "Question and Answers micro-app."
msgstr ""

#. TRANS: Application title.
#: QnAPlugin.php:143
msgctxt "TITLE"
msgid "Question"
msgstr ""

#. TRANS: Exception thrown when there are too many activity objects.
#: QnAPlugin.php:171
msgid "Too many activity objects."
msgstr ""

#. TRANS: Exception thrown when an incorrect object type is encountered.
#: QnAPlugin.php:178
msgid "Wrong type for object."
msgstr ""

#. TRANS: Exception thrown when answering a non-existing question.
#: QnAPlugin.php:197
msgid "Answer to unknown question."
msgstr ""

#. TRANS: Exception thrown when an object type is encountered that cannot be
#. handled.
#: QnAPlugin.php:203 QnAPlugin.php:233
msgid "Unknown object type."
msgstr ""

#. TRANS: Exception thrown when requesting a non-existing question notice.
#: QnAPlugin.php:240
msgid "Unknown question notice."
msgstr ""

#. TRANS: Placeholder value for a possible answer to a question
#. TRANS: by the logged in user.
#: QnAPlugin.php:368
msgid "Your answer..."
msgstr ""

#. TRANS: Link description for link to full notice text if it is longer than
#. TRANS: what will be dispplayed.
#: QnAPlugin.php:393
msgid "…"
msgstr ""

#. TRANS: Title for link that is an ellipsis in English.
#: QnAPlugin.php:398
msgid "more..."
msgstr ""

#. TRANS: Page title for close a question
#: actions/qnaclosequestion.php:63
msgid "Close question"
msgstr ""

#. TRANS: Client exception thrown trying to close a question when not logged
#. in
#: actions/qnaclosequestion.php:85
msgid "You must be logged in to close a question."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnaclosequestion.php:98 actions/qnavote.php:96
#: actions/qnanewanswer.php:101
msgid "Invalid or missing question."
msgstr ""

#. TRANS: Exception thrown trying to close another user's question.
#: actions/qnaclosequestion.php:136
msgid "You did not ask this question."
msgstr ""

#. TRANS: Page title after sending an answer.
#. TRANS: Page title after sending in a vote for a question or answer.
#. TRANS: Page title after sending an answer.
#: actions/qnaclosequestion.php:153 actions/qnavote.php:148
#: actions/qnanewanswer.php:158
msgid "Answers"
msgstr ""

#. TRANS: Client exception thrown trying to answer a question while not logged
#. in.
#: actions/qnavote.php:84 actions/qnareviseanswer.php:84
#: actions/qnanewanswer.php:85
msgid "You must be logged in to answer to a question."
msgstr ""

#. TRANS: Client exception thrown when requesting a non-existing answer.
#. TRANS: Did we used to have it, and it got deleted?
#: actions/qnashowanswer.php:68 actions/qnashowanswer.php:82
msgid "No such answer."
msgstr ""

#. TRANS: Client exception thrown when requesting an answer that has no
#. connected question.
#: actions/qnashowanswer.php:75
msgid "No question for this answer."
msgstr ""

#. TRANS: Client exception thrown when requesting answer data for a non-
#. existing user.
#. TRANS: Client exception thrown trying to view a question of a non-existing
#. user.
#: actions/qnashowanswer.php:89 actions/qnashowquestion.php:83
msgid "No such user."
msgstr ""

#. TRANS: Client exception thrown when requesting answer data for a user
#. without a profile.
#. TRANS: Server exception thrown trying to view a question for a user for
#. which the profile could not be loaded.
#: actions/qnashowanswer.php:96 actions/qnashowquestion.php:90
msgid "User without a profile."
msgstr ""

#. TRANS: Page title.
#. TRANS: %1$s is the user who answered a question, %2$s is the question.
#: actions/qnashowanswer.php:122
#, php-format
msgid "%1$s's answer to \"%2$s\""
msgstr ""

#. TRANS: Page title for revising a question
#: actions/qnareviseanswer.php:62
msgid "Revise answer"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnareviseanswer.php:97
msgid "Invalid or missing answer."
msgstr ""

#. TRANS: Form title for sending an answer.
#: actions/qnareviseanswer.php:241
msgctxt "TITLE"
msgid "Answer"
msgstr ""

#. TRANS: Title for Question page.
#: actions/qnanewquestion.php:62
msgid "New question"
msgstr ""

#. TRANS: Client exception thrown trying to create a Question while not logged
#. in.
#: actions/qnanewquestion.php:81
msgid "You must be logged in to post a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a question without a title.
#: actions/qnanewquestion.php:129
msgid "Question must have a title."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/qnanewquestion.php:154
msgid "Question posted"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question.
#: actions/qnashowquestion.php:68
msgid "No such question."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question
#. notice.
#: actions/qnashowquestion.php:76
msgid "No such question notice."
msgstr ""

#. TRANS: Page title for a question.
#. TRANS: %1$s is the nickname of the user who asked the question, %2$s is the
#. question.
#: actions/qnashowquestion.php:155
#, php-format
msgid "%1$s's question: %2$s"
msgstr ""

#. TRANS: Page title after an AJAX error occurs on the post answer page.
#: actions/qnanewanswer.php:224
msgid "Ajax Error"
msgstr ""

#. TRANS: Title for form to send answer to a question.
#: actions/qnanewanswer.php:247
msgctxt "TITLE"
msgid "Your answer"
msgstr ""

#. TRANS: Error message displayed when an answer has no content.
#. TRANS: Error message displayed when answer data is not present.
#: actions/qnanewanswer.php:344 lib/qnalistitem.php:118
msgid "Answer data is missing."
msgstr ""

#. TRANS: Exception thown when getting a question with a non-existing ID.
#. TRANS: %s is the non-existing question ID.
#: classes/QnA_Answer.php:146
#, php-format
msgid "No question with ID %s"
msgstr ""

#. TRANS: Exception thown when getting a profile with a non-existing ID.
#. TRANS: %s is the non-existing profile ID.
#. TRANS: Exception trown when getting a profile for a non-existing ID.
#. TRANS: %s is the provided profile ID.
#: classes/QnA_Answer.php:157 classes/QnA_Question.php:121
#, php-format
msgid "No profile with ID %s"
msgstr ""

#. TRANS: %s is the number of answer revisions.
#: classes/QnA_Answer.php:202
#, php-format
msgid "%s revision"
msgid_plural "%s revisions"
msgstr[0] ""

#. TRANS: Text for a question that was answered.
#. TRANS: %1$s is the user that answered, %2$s is the question title,
#. TRANS: %2$s is the answer content.
#: classes/QnA_Answer.php:222
#, php-format
msgid "%1$s answered the question \"%2$s\": %3$s"
msgstr ""

#. TRANS: Text for a question that was answered.
#. TRANS: %s is the question title.
#. TRANS: Rendered version of the notice content answering a question.
#. TRANS: %s a link to the question with question title as the link content.
#: classes/QnA_Answer.php:263 classes/QnA_Answer.php:270
#, php-format
msgid "answered \"%s\""
msgstr ""

#. TRANS: Number of given answers to a question.
#. TRANS: %s is the number of given answers.
#: classes/QnA_Question.php:208
#, php-format
msgid "%s answer"
msgid_plural "%s answers"
msgstr[0] ""

#. TRANS: Notification that a question cannot be answered anymore because it
#. is closed.
#: classes/QnA_Question.php:215
msgid "This question is closed."
msgstr ""

#. TRANS: Rendered version of the notice content creating a question.
#. TRANS: %s a link to the question as link description.
#: classes/QnA_Question.php:279
#, php-format
msgid "Question: %s"
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a question.
#. TRANS: %s is the unpexpected object type.
#: lib/qnalistitem.php:67
#, php-format
msgid "Unexpected type for QnA plugin: %s."
msgstr ""

#. TRANS: Error message displayed when question data is not present.
#: lib/qnalistitem.php:93
msgid "Question data is missing."
msgstr ""

repo_name: andremichelle/gnu

license: mit


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:28+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/gnu-social/gnu-social/language/zh_CN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_CN\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Button text for submitting a poll response.
#. TRANS: Button text for submitting a revised answer.
#: forms/qnavote.php:118 forms/qnareviseanswer.php:119
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Form legend for showing the answer.
#. TRANS: Page title for and answer to a question.
#. TRANS: Page title after sending an answer.
#. TRANS: Page title for and answer to a question.
#: forms/qnashowanswer.php:113 actions/qnavote.php:63
#: actions/qnareviseanswer.php:161 actions/qnareviseanswer.php:203
#: actions/qnanewanswer.php:63
msgid "Answer"
msgstr ""

#. TRANS: Button text for marking an answer as "best".
#: forms/qnashowanswer.php:150
msgctxt "BUTTON"
msgid "Best"
msgstr ""

#. TRANS: Title for button text marking an answer as "best".
#: forms/qnashowanswer.php:154
msgid "Mark this answer as the best answer."
msgstr ""

#. TRANS: Field label for a new question.
#: forms/qnanewquestion.php:110
msgctxt "LABEL"
msgid "Title"
msgstr ""

#. TRANS: Field title for a new question.
#: forms/qnanewquestion.php:113
msgid "The title of your question."
msgstr ""

#. TRANS: Field label for question details.
#: forms/qnanewquestion.php:122
msgctxt "LABEL"
msgid "Description"
msgstr "描述"

#. TRANS: Field title for question details.
#: forms/qnanewquestion.php:125
msgid "Your question in detail."
msgstr ""

#. TRANS: Button text for saving a new question.
#: forms/qnanewquestion.php:149
msgctxt "BUTTON"
msgid "Save"
msgstr "保存"

#. TRANS: Form legend for revising the answer.
#: forms/qnashowquestion.php:106
msgctxt "LEGEND"
msgid "Question"
msgstr ""

#. TRANS: Button text for closing a question.
#: forms/qnashowquestion.php:151
msgctxt "BUTTON"
msgid "Close"
msgstr ""

#. TRANS: Title for button text for closing a question.
#: forms/qnashowquestion.php:155
msgid "Close the question to no one can answer it anymore."
msgstr ""

#. TRANS: Field label.
#: forms/qnanewanswer.php:114
msgid "Enter your answer"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/qnanewanswer.php:125
msgctxt "BUTTON"
msgid "Answer"
msgstr ""

#. TRANS: Plugin description.
#: QnAPlugin.php:136
msgid "Question and Answers micro-app."
msgstr ""

#. TRANS: Application title.
#: QnAPlugin.php:143
msgctxt "TITLE"
msgid "Question"
msgstr ""

#. TRANS: Exception thrown when there are too many activity objects.
#: QnAPlugin.php:171
msgid "Too many activity objects."
msgstr ""

#. TRANS: Exception thrown when an incorrect object type is encountered.
#: QnAPlugin.php:178
msgid "Wrong type for object."
msgstr ""

#. TRANS: Exception thrown when answering a non-existing question.
#: QnAPlugin.php:197
msgid "Answer to unknown question."
msgstr ""

#. TRANS: Exception thrown when an object type is encountered that cannot be
#. handled.
#: QnAPlugin.php:203 QnAPlugin.php:233
msgid "Unknown object type."
msgstr ""

#. TRANS: Exception thrown when requesting a non-existing question notice.
#: QnAPlugin.php:240
msgid "Unknown question notice."
msgstr ""

#. TRANS: Placeholder value for a possible answer to a question
#. TRANS: by the logged in user.
#: QnAPlugin.php:368
msgid "Your answer..."
msgstr ""

#. TRANS: Link description for link to full notice text if it is longer than
#. TRANS: what will be dispplayed.
#: QnAPlugin.php:393
msgid "…"
msgstr ""

#. TRANS: Title for link that is an ellipsis in English.
#: QnAPlugin.php:398
msgid "more..."
msgstr ""

#. TRANS: Page title for close a question
#: actions/qnaclosequestion.php:63
msgid "Close question"
msgstr ""

#. TRANS: Client exception thrown trying to close a question when not logged
#. in
#: actions/qnaclosequestion.php:85
msgid "You must be logged in to close a question."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnaclosequestion.php:98 actions/qnavote.php:96
#: actions/qnanewanswer.php:101
msgid "Invalid or missing question."
msgstr ""

#. TRANS: Exception thrown trying to close another user's question.
#: actions/qnaclosequestion.php:136
msgid "You did not ask this question."
msgstr ""

#. TRANS: Page title after sending an answer.
#. TRANS: Page title after sending in a vote for a question or answer.
#. TRANS: Page title after sending an answer.
#: actions/qnaclosequestion.php:153 actions/qnavote.php:148
#: actions/qnanewanswer.php:158
msgid "Answers"
msgstr ""

#. TRANS: Client exception thrown trying to answer a question while not logged
#. in.
#: actions/qnavote.php:84 actions/qnareviseanswer.php:84
#: actions/qnanewanswer.php:85
msgid "You must be logged in to answer to a question."
msgstr ""

#. TRANS: Client exception thrown when requesting a non-existing answer.
#. TRANS: Did we used to have it, and it got deleted?
#: actions/qnashowanswer.php:68 actions/qnashowanswer.php:82
msgid "No such answer."
msgstr ""

#. TRANS: Client exception thrown when requesting an answer that has no
#. connected question.
#: actions/qnashowanswer.php:75
msgid "No question for this answer."
msgstr ""

#. TRANS: Client exception thrown when requesting answer data for a non-
#. existing user.
#. TRANS: Client exception thrown trying to view a question of a non-existing
#. user.
#: actions/qnashowanswer.php:89 actions/qnashowquestion.php:83
msgid "No such user."
msgstr "没有这个用户。"

#. TRANS: Client exception thrown when requesting answer data for a user
#. without a profile.
#. TRANS: Server exception thrown trying to view a question for a user for
#. which the profile could not be loaded.
#: actions/qnashowanswer.php:96 actions/qnashowquestion.php:90
msgid "User without a profile."
msgstr ""

#. TRANS: Page title.
#. TRANS: %1$s is the user who answered a question, %2$s is the question.
#: actions/qnashowanswer.php:122
#, php-format
msgid "%1$s's answer to \"%2$s\""
msgstr ""

#. TRANS: Page title for revising a question
#: actions/qnareviseanswer.php:62
msgid "Revise answer"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnareviseanswer.php:97
msgid "Invalid or missing answer."
msgstr ""

#. TRANS: Form title for sending an answer.
#: actions/qnareviseanswer.php:241
msgctxt "TITLE"
msgid "Answer"
msgstr ""

#. TRANS: Title for Question page.
#: actions/qnanewquestion.php:62
msgid "New question"
msgstr ""

#. TRANS: Client exception thrown trying to create a Question while not logged
#. in.
#: actions/qnanewquestion.php:81
msgid "You must be logged in to post a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a question without a title.
#: actions/qnanewquestion.php:129
msgid "Question must have a title."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/qnanewquestion.php:154
msgid "Question posted"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question.
#: actions/qnashowquestion.php:68
msgid "No such question."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question
#. notice.
#: actions/qnashowquestion.php:76
msgid "No such question notice."
msgstr ""

#. TRANS: Page title for a question.
#. TRANS: %1$s is the nickname of the user who asked the question, %2$s is the
#. question.
#: actions/qnashowquestion.php:155
#, php-format
msgid "%1$s's question: %2$s"
msgstr ""

#. TRANS: Page title after an AJAX error occurs on the post answer page.
#: actions/qnanewanswer.php:224
msgid "Ajax Error"
msgstr "Ajax错误"

#. TRANS: Title for form to send answer to a question.
#: actions/qnanewanswer.php:247
msgctxt "TITLE"
msgid "Your answer"
msgstr ""

#. TRANS: Error message displayed when an answer has no content.
#. TRANS: Error message displayed when answer data is not present.
#: actions/qnanewanswer.php:344 lib/qnalistitem.php:118
msgid "Answer data is missing."
msgstr ""

#. TRANS: Exception thown when getting a question with a non-existing ID.
#. TRANS: %s is the non-existing question ID.
#: classes/QnA_Answer.php:146
#, php-format
msgid "No question with ID %s"
msgstr ""

#. TRANS: Exception thown when getting a profile with a non-existing ID.
#. TRANS: %s is the non-existing profile ID.
#. TRANS: Exception trown when getting a profile for a non-existing ID.
#. TRANS: %s is the provided profile ID.
#: classes/QnA_Answer.php:157 classes/QnA_Question.php:121
#, php-format
msgid "No profile with ID %s"
msgstr ""

#. TRANS: %s is the number of answer revisions.
#: classes/QnA_Answer.php:202
#, php-format
msgid "%s revision"
msgid_plural "%s revisions"
msgstr[0] ""

#. TRANS: Text for a question that was answered.
#. TRANS: %1$s is the user that answered, %2$s is the question title,
#. TRANS: %2$s is the answer content.
#: classes/QnA_Answer.php:222
#, php-format
msgid "%1$s answered the question \"%2$s\": %3$s"
msgstr ""

#. TRANS: Text for a question that was answered.
#. TRANS: %s is the question title.
#. TRANS: Rendered version of the notice content answering a question.
#. TRANS: %s a link to the question with question title as the link content.
#: classes/QnA_Answer.php:263 classes/QnA_Answer.php:270
#, php-format
msgid "answered \"%s\""
msgstr ""

#. TRANS: Number of given answers to a question.
#. TRANS: %s is the number of given answers.
#: classes/QnA_Question.php:208
#, php-format
msgid "%s answer"
msgid_plural "%s answers"
msgstr[0] ""

#. TRANS: Notification that a question cannot be answered anymore because it
#. is closed.
#: classes/QnA_Question.php:215
msgid "This question is closed."
msgstr ""

#. TRANS: Rendered version of the notice content creating a question.
#. TRANS: %s a link to the question as link description.
#: classes/QnA_Question.php:279
#, php-format
msgid "Question: %s"
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a question.
#. TRANS: %s is the unpexpected object type.
#: lib/qnalistitem.php:67
#, php-format
msgid "Unexpected type for QnA plugin: %s."
msgstr ""

#. TRANS: Error message displayed when question data is not present.
#: lib/qnalistitem.php:93
msgid "Question data is missing."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-05 16:28+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/gnu-social/gnu-social/language/zh_TW/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: zh_TW\n"
"Plural-Forms: nplurals=1; plural=0;\n"

#. TRANS: Button text for submitting a poll response.
#. TRANS: Button text for submitting a revised answer.
#: forms/qnavote.php:118 forms/qnareviseanswer.php:119
msgctxt "BUTTON"
msgid "Submit"
msgstr ""

#. TRANS: Form legend for showing the answer.
#. TRANS: Page title for and answer to a question.
#. TRANS: Page title after sending an answer.
#. TRANS: Page title for and answer to a question.
#: forms/qnashowanswer.php:113 actions/qnavote.php:63
#: actions/qnareviseanswer.php:161 actions/qnareviseanswer.php:203
#: actions/qnanewanswer.php:63
msgid "Answer"
msgstr ""

#. TRANS: Button text for marking an answer as "best".
#: forms/qnashowanswer.php:150
msgctxt "BUTTON"
msgid "Best"
msgstr ""

#. TRANS: Title for button text marking an answer as "best".
#: forms/qnashowanswer.php:154
msgid "Mark this answer as the best answer."
msgstr ""

#. TRANS: Field label for a new question.
#: forms/qnanewquestion.php:110
msgctxt "LABEL"
msgid "Title"
msgstr ""

#. TRANS: Field title for a new question.
#: forms/qnanewquestion.php:113
msgid "The title of your question."
msgstr ""

#. TRANS: Field label for question details.
#: forms/qnanewquestion.php:122
msgctxt "LABEL"
msgid "Description"
msgstr ""

#. TRANS: Field title for question details.
#: forms/qnanewquestion.php:125
msgid "Your question in detail."
msgstr ""

#. TRANS: Button text for saving a new question.
#: forms/qnanewquestion.php:149
msgctxt "BUTTON"
msgid "Save"
msgstr ""

#. TRANS: Form legend for revising the answer.
#: forms/qnashowquestion.php:106
msgctxt "LEGEND"
msgid "Question"
msgstr ""

#. TRANS: Button text for closing a question.
#: forms/qnashowquestion.php:151
msgctxt "BUTTON"
msgid "Close"
msgstr ""

#. TRANS: Title for button text for closing a question.
#: forms/qnashowquestion.php:155
msgid "Close the question to no one can answer it anymore."
msgstr ""

#. TRANS: Field label.
#: forms/qnanewanswer.php:114
msgid "Enter your answer"
msgstr ""

#. TRANS: Button text for submitting a poll response.
#: forms/qnanewanswer.php:125
msgctxt "BUTTON"
msgid "Answer"
msgstr ""

#. TRANS: Plugin description.
#: QnAPlugin.php:136
msgid "Question and Answers micro-app."
msgstr ""

#. TRANS: Application title.
#: QnAPlugin.php:143
msgctxt "TITLE"
msgid "Question"
msgstr ""

#. TRANS: Exception thrown when there are too many activity objects.
#: QnAPlugin.php:171
msgid "Too many activity objects."
msgstr ""

#. TRANS: Exception thrown when an incorrect object type is encountered.
#: QnAPlugin.php:178
msgid "Wrong type for object."
msgstr ""

#. TRANS: Exception thrown when answering a non-existing question.
#: QnAPlugin.php:197
msgid "Answer to unknown question."
msgstr ""

#. TRANS: Exception thrown when an object type is encountered that cannot be
#. handled.
#: QnAPlugin.php:203 QnAPlugin.php:233
msgid "Unknown object type."
msgstr ""

#. TRANS: Exception thrown when requesting a non-existing question notice.
#: QnAPlugin.php:240
msgid "Unknown question notice."
msgstr ""

#. TRANS: Placeholder value for a possible answer to a question
#. TRANS: by the logged in user.
#: QnAPlugin.php:368
msgid "Your answer..."
msgstr ""

#. TRANS: Link description for link to full notice text if it is longer than
#. TRANS: what will be dispplayed.
#: QnAPlugin.php:393
msgid "…"
msgstr ""

#. TRANS: Title for link that is an ellipsis in English.
#: QnAPlugin.php:398
msgid "more..."
msgstr ""

#. TRANS: Page title for close a question
#: actions/qnaclosequestion.php:63
msgid "Close question"
msgstr ""

#. TRANS: Client exception thrown trying to close a question when not logged
#. in
#: actions/qnaclosequestion.php:85
msgid "You must be logged in to close a question."
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnaclosequestion.php:98 actions/qnavote.php:96
#: actions/qnanewanswer.php:101
msgid "Invalid or missing question."
msgstr ""

#. TRANS: Exception thrown trying to close another user's question.
#: actions/qnaclosequestion.php:136
msgid "You did not ask this question."
msgstr ""

#. TRANS: Page title after sending an answer.
#. TRANS: Page title after sending in a vote for a question or answer.
#. TRANS: Page title after sending an answer.
#: actions/qnaclosequestion.php:153 actions/qnavote.php:148
#: actions/qnanewanswer.php:158
msgid "Answers"
msgstr ""

#. TRANS: Client exception thrown trying to answer a question while not logged
#. in.
#: actions/qnavote.php:84 actions/qnareviseanswer.php:84
#: actions/qnanewanswer.php:85
msgid "You must be logged in to answer to a question."
msgstr ""

#. TRANS: Client exception thrown when requesting a non-existing answer.
#. TRANS: Did we used to have it, and it got deleted?
#: actions/qnashowanswer.php:68 actions/qnashowanswer.php:82
msgid "No such answer."
msgstr ""

#. TRANS: Client exception thrown when requesting an answer that has no
#. connected question.
#: actions/qnashowanswer.php:75
msgid "No question for this answer."
msgstr ""

#. TRANS: Client exception thrown when requesting answer data for a non-
#. existing user.
#. TRANS: Client exception thrown trying to view a question of a non-existing
#. user.
#: actions/qnashowanswer.php:89 actions/qnashowquestion.php:83
msgid "No such user."
msgstr "無此使用者"

#. TRANS: Client exception thrown when requesting answer data for a user
#. without a profile.
#. TRANS: Server exception thrown trying to view a question for a user for
#. which the profile could not be loaded.
#: actions/qnashowanswer.php:96 actions/qnashowquestion.php:90
msgid "User without a profile."
msgstr ""

#. TRANS: Page title.
#. TRANS: %1$s is the user who answered a question, %2$s is the question.
#: actions/qnashowanswer.php:122
#, php-format
msgid "%1$s's answer to \"%2$s\""
msgstr ""

#. TRANS: Page title for revising a question
#: actions/qnareviseanswer.php:62
msgid "Revise answer"
msgstr ""

#. TRANS: Client exception thrown trying to respond to a non-existing
#. question.
#: actions/qnareviseanswer.php:97
msgid "Invalid or missing answer."
msgstr ""

#. TRANS: Form title for sending an answer.
#: actions/qnareviseanswer.php:241
msgctxt "TITLE"
msgid "Answer"
msgstr ""

#. TRANS: Title for Question page.
#: actions/qnanewquestion.php:62
msgid "New question"
msgstr ""

#. TRANS: Client exception thrown trying to create a Question while not logged
#. in.
#: actions/qnanewquestion.php:81
msgid "You must be logged in to post a question."
msgstr ""

#. TRANS: Client exception thrown trying to create a question without a title.
#: actions/qnanewquestion.php:129
msgid "Question must have a title."
msgstr ""

#. TRANS: Page title after sending a notice.
#: actions/qnanewquestion.php:154
msgid "Question posted"
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question.
#: actions/qnashowquestion.php:68
msgid "No such question."
msgstr ""

#. TRANS: Client exception thrown trying to view a non-existing question
#. notice.
#: actions/qnashowquestion.php:76
msgid "No such question notice."
msgstr ""

#. TRANS: Page title for a question.
#. TRANS: %1$s is the nickname of the user who asked the question, %2$s is the
#. question.
#: actions/qnashowquestion.php:155
#, php-format
msgid "%1$s's question: %2$s"
msgstr ""

#. TRANS: Page title after an AJAX error occurs on the post answer page.
#: actions/qnanewanswer.php:224
msgid "Ajax Error"
msgstr ""

#. TRANS: Title for form to send answer to a question.
#: actions/qnanewanswer.php:247
msgctxt "TITLE"
msgid "Your answer"
msgstr ""

#. TRANS: Error message displayed when an answer has no content.
#. TRANS: Error message displayed when answer data is not present.
#: actions/qnanewanswer.php:344 lib/qnalistitem.php:118
msgid "Answer data is missing."
msgstr ""

#. TRANS: Exception thown when getting a question with a non-existing ID.
#. TRANS: %s is the non-existing question ID.
#: classes/QnA_Answer.php:146
#, php-format
msgid "No question with ID %s"
msgstr ""

#. TRANS: Exception thown when getting a profile with a non-existing ID.
#. TRANS: %s is the non-existing profile ID.
#. TRANS: Exception trown when getting a profile for a non-existing ID.
#. TRANS: %s is the provided profile ID.
#: classes/QnA_Answer.php:157 classes/QnA_Question.php:121
#, php-format
msgid "No profile with ID %s"
msgstr ""

#. TRANS: %s is the number of answer revisions.
#: classes/QnA_Answer.php:202
#, php-format
msgid "%s revision"
msgid_plural "%s revisions"
msgstr[0] ""

#. TRANS: Text for a question that was answered.
#. TRANS: %1$s is the user that answered, %2$s is the question title,
#. TRANS: %2$s is the answer content.
#: classes/QnA_Answer.php:222
#, php-format
msgid "%1$s answered the question \"%2$s\": %3$s"
msgstr ""

#. TRANS: Text for a question that was answered.
#. TRANS: %s is the question title.
#. TRANS: Rendered version of the notice content answering a question.
#. TRANS: %s a link to the question with question title as the link content.
#: classes/QnA_Answer.php:263 classes/QnA_Answer.php:270
#, php-format
msgid "answered \"%s\""
msgstr ""

#. TRANS: Number of given answers to a question.
#. TRANS: %s is the number of given answers.
#: classes/QnA_Question.php:208
#, php-format
msgid "%s answer"
msgid_plural "%s answers"
msgstr[0] ""

#. TRANS: Notification that a question cannot be answered anymore because it
#. is closed.
#: classes/QnA_Question.php:215
msgid "This question is closed."
msgstr ""

#. TRANS: Rendered version of the notice content creating a question.
#. TRANS: %s a link to the question as link description.
#: classes/QnA_Question.php:279
#, php-format
msgid "Question: %s"
msgstr ""

#. TRANS: Exception thrown when performing an unexpected action on a question.
#. TRANS: %s is the unpexpected object type.
#: lib/qnalistitem.php:67
#, php-format
msgid "Unexpected type for QnA plugin: %s."
msgstr ""

#. TRANS: Error message displayed when question data is not present.
#: lib/qnalistitem.php:93
msgid "Question data is missing."
msgstr ""


code:
Several example plugins are included in the plugins/ directory. You
can enable a plugin with the following line in config.php:

```php
    addPlugin('Example', array('param1' => 'value1',
                               'param2' => 'value2'));
```

This will look for and load files named 'ExamplePlugin.php' or
'Example/ExamplePlugin.php' either in the plugins/ directory (for
plugins that ship with StatusNet) or in the local/ directory (for
plugins you write yourself or that you get from somewhere else) or
local/plugins/.

Plugins are documented in their own directories.

Additional information on using and developing plugins can be found
at the following locations:

* [Plugin Development](../DOCUMENTATION/DEVELOPERS/Plugins/README.md)
* [Community Plugins](https://git.gnu.io/gnu/gnu-social/wikis/GNU-Social-Community-Plugins)


code:
This plugin enables RSSCloud (http://rsscloud.org/) publishing and subscription
handling for RSS 2.0 profile feeds (i.e:
http://SITE/PATH/api/statuses/user_timeline/USERNAME.rss). When the plugin is
enabled, StatusNet acts as both the publisher and hub ('writer' and 'cloud' in
RSSCloud parlance), but only for local StatusNet feeds. It's not possible to use
it as a general purpose hub -- for instance you can't subscribe and get updates
to a Wordpress feed from StatusNet using this plugin.

To use the plugin, add the following to your config.php:

    addPlugin('RSSCloud');

Enabling the plugin will add a <cloud> element to your RSS 2.0 profile feeds
that looks like this:

    <cloud domain="SITE" port="80" path="/main/rsscloud/request_notify"
    registerProcedure="" protocol="http-post"/>

Aggregators may subscribe by sending a proper REST RSSCloud subscription request
(the optional 'domain' parameter with challenge is supported). Subscribing
aggregators will be notified ('pinged') when users they have subscribed to post
new notices. Currently, REST is the only protocol supported for notifications.

Deamon
------

There's also a daemon for offline processing of queued notices with RSSCloud
destinations, which will start automatically if/when you run
scripts/startdaemons.sh.

Notes
-----

- Again, only RSS 2.0 profile feeds may be subscribed to, and they have to be
  the ones with user names in them, like:
      http://SITE/PATH/api/statuses/user_timeline/USERNAME.rss
- Subscriptions are deleted after three notification failures in a row (not sure
  this is optimal).
- The plugin includes a dummy LoggingAggregator class that can be used for
  end-to-end testing.  You probably don't want to mess with it.

TODO
----

- Figure out why the RSSCloudSubcription can't ->delete() or ->update()
- Support pinging via XML-RPC and SOAP
- Automatically delete subscriptions? Point of reference: Dave's hub
  implementation auto-deletes them after 25 hours. WordPress never deletes them.
- Support additional feed URL addresses for the same feed (e.g.: by numeric ID,
  ?user_id=xxx, etc.)
- Support additional feeds that make sense (e.g: replies)?
- Possibly use "rssCloud" (like Dave) instead of "RSSCloud" everywhere

path: plugins/RSSCloud/README


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Plugin to support RSSCloud
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
   *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

define('RSSCLOUDPLUGIN_VERSION', '0.1.0');

/**
 * Plugin class for adding RSSCloud capabilities to StatusNet
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class RSSCloudPlugin extends Plugin
{
    /**
     * Our friend, the constructor
     *
     * @return void
     */
    function __construct()
    {
        parent::__construct();
    }

    /**
     * Setup the info for the subscription handler. Allow overriding
     * to point at another cloud hub (not currently used).
     *
     * @return void
     */
    function onInitializePlugin()
    {
        $this->domain   = common_config('rsscloud', 'domain');
        $this->port     = common_config('rsscloud', 'port');
        $this->path     = common_config('rsscloud', 'path');
        $this->funct    = common_config('rsscloud', 'function');
        $this->protocol = common_config('rsscloud', 'protocol');

        // set defaults

        $local_server = parse_url(common_path('main/rsscloud/request_notify'));

        if (empty($this->domain)) {
            $this->domain = $local_server['host'];
        }

        if (empty($this->port)) {
            $this->port = '80';
        }

        if (empty($this->path)) {
            $this->path = $local_server['path'];
        }

        if (empty($this->funct)) {
            $this->funct = '';
        }

        if (empty($this->protocol)) {
            $this->protocol = 'http-post';
        }
    }

    /**
     * Add RSSCloud-related paths to the router table
     *
     * Hook for RouterInitialized event.
     *
     * @param Mapper $m URL parser and mapper
     *
     * @return boolean hook return
     */
    function onRouterInitialized($m)
    {
        $m->connect('/main/rsscloud/request_notify',
                    array('action' => 'RSSCloudRequestNotify'));

        // XXX: This is just for end-to-end testing. Uncomment if you need to pretend
        //      to be a cloud hub for some reason.
        //$m->connect('/main/rsscloud/notify',
        //            array('action' => 'LoggingAggregator'));

        return true;
    }

    /**
     * Add a <cloud> element to the RSS feed (after the rss <channel>
     * element is started).
     *
     * @param Action $action the ApiAction
     *
     * @return void
     */
    function onStartApiRss($action)
    {
        if (get_class($action) == 'ApiTimelineUserAction') {

            $attrs = array('domain'            => $this->domain,
                           'port'              => $this->port,
                           'path'              => $this->path,
                           'registerProcedure' => $this->funct,
                           'protocol'          => $this->protocol);

            // Dipping into XMLWriter to avoid a full end element (</cloud>).

            $action->xw->startElement('cloud');
            foreach ($attrs as $name => $value) {
                $action->xw->writeAttribute($name, $value);
            }

            $action->xw->endElement();
        }
    }

    /**
     * Add an RSSCloud queue item for each notice
     *
     * @param Notice $notice      the notice
     * @param array  &$transports the list of transports (queues)
     *
     * @return boolean hook return
     */

    function onStartEnqueueNotice($notice, &$transports)
    {
        if ($notice->isLocal()) {
            array_push($transports, 'rsscloud');
        }
        return true;
    }

    /**
     * Create the rsscloud_subscription table if it's not
     * already in the DB
     *
     * @return boolean hook return
     */

    function onCheckSchema()
    {
        $schema = Schema::get();
        $schema->ensureTable('rsscloud_subscription',
            array(
                'fields' => array(
                    'subscribed' => array('type' => 'int', 'not null' => true),
                    'url' => array('type' => 'varchar', 'length' => '191', 'not null' => true),
                    'failures' => array('type' => 'int', 'not null' => true, 'default' => 0),
                    'created' => array('type' => 'datetime', 'not null' => true),
                    'modified' => array('type' => 'timestamp', 'not null' => true),
                ),
                'primary key' => array('subscribed', 'url'),
            ));
         return true;
    }

    /**
     * Register RSSCloud notice queue handler
     *
     * @param QueueManager $manager
     *
     * @return boolean hook return
     */
    function onEndInitializeQueueManager($manager)
    {
        $manager->connect('rsscloud', 'RSSCloudQueueHandler');
        return true;
    }

    function onPluginVersion(array &$versions)
    {
        $versions[] = array('name' => 'RSSCloud',
                            'version' => RSSCLOUDPLUGIN_VERSION,
                            'author' => 'Zach Copley',
                            'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/RSSCloud',
                            'rawdescription' =>
                            // TRANS: Plugin description.
                            _m('The RSSCloud plugin enables your StatusNet instance to publish ' .
                               'real-time updates for profile RSS feeds using the ' .
                               'RSSCloud protocol.'));

        return true;
    }
}


code:
<?php
/**
 * This test class pretends to be an RSS aggregator. It logs notifications
 * from the cloud.
 *
 * PHP version 5
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Dummy aggregator that acts as a proper notification handler. It
 * doesn't do anything but respond correctly when notified via
 * REST.  Mostly, this is just and action I used to develop the plugin
 * and easily test things end-to-end. I'm leaving it in here as it
 * may be useful for developing the plugin further.
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class LoggingAggregatorAction extends Action
{
    var $challenge = null;
    var $url       = null;

    /**
     * Initialization.
     *
     * @param array $args Web and URL arguments
     *
     * @return boolean false if user doesn't exist
     */
    function prepare(array $args = array())
    {
        parent::prepare($args);

        $this->url       = $this->arg('url');
        $this->challenge = $this->arg('challenge');

        common_debug("args = " . var_export($this->args, true));
        common_debug('url = ' . $this->url . ' challenge = ' . $this->challenge);

        return true;
    }

    /**
     * Handle the request
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle()
    {
        parent::handle();

        if (empty($this->url)) {
            // TRANS: Form validation error displayed when a URL parameter is missing.
            $this->showError(_m('A URL parameter is required.'));
            return;
        }

        if (!empty($this->challenge)) {
            // must be a GET
            if ($_SERVER['REQUEST_METHOD'] != 'GET') {
                // TRANS: Form validation error displayed when HTTP GET is not used.
                $this->showError(_m('This resource requires an HTTP GET.'));
                return;
            }

            header('Content-Type: text/xml');
            echo $this->challenge;
        } else {
            // must be a POST
            if ($_SERVER['REQUEST_METHOD'] != 'POST') {
                // TRANS: Form validation error displayed when HTTP POST is not used.
                $this->showError(_m('This resource requires an HTTP POST.'));
                return;
            }

            header('Content-Type: text/xml');
            Echo "<notifyResult success='true' msg='Thanks for the update.' />\n";
        }

        $this->ip = $_SERVER['REMOTE_ADDR'];

        common_log(LOG_INFO, 'RSSCloud Logging Aggregator - ' .
                   $this->ip . ' claims the feed at ' .
                   $this->url . ' has been updated.');
    }

    /**
     * Show an XML error when things go badly
     *
     * @param string $msg the error message
     *
     * @return void
     */
    function showError($msg)
    {
        header('HTTP/1.1 400 Bad Request');
        header('Content-Type: text/xml');
        echo "<?xml version='1.0'?>\n";
        echo "<notifyResult success='false' msg='$msg' />\n";
    }
}


code:
<?php
/**
 * Action to let RSSCloud aggregators request update notification when
 * user profile feeds change.
 *
 * PHP version 5
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
 * @link     http://status.net/
 *
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Action class to handle RSSCloud notification (subscription) requests
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class RSSCloudRequestNotifyAction extends Action
{
    /**
     * Initialization.
     *
     * @param array $args Web and URL arguments
     *
     * @return boolean false if user doesn't exist
     */
    function prepare(array $args = array())
    {
        parent::prepare($args);

        $this->ip   = $_SERVER['REMOTE_ADDR'];
        $this->port = $this->arg('port');
        $this->path = $this->arg('path');

        if ($this->path[0] != '/') {
            $this->path = '/' . $this->path;
        }

        $this->protocol  = $this->arg('protocol');
        $this->procedure = $this->arg('notifyProcedure');
        $this->domain    = $this->arg('domain');

        $this->feeds = $this->getFeeds();

        return true;
    }

    /**
     * Handle the request
     *
     * Checks for all the required parameters for a subscription,
     * validates that the feed being subscribed to is real, and then
     * saves the subsctiption.
     *
     * @param array $args $_REQUEST data (unused)
     *
     * @return void
     */
    function handle()
    {
        parent::handle();

        if ($_SERVER['REQUEST_METHOD'] != 'POST') {
            // TRANS: Form validation error displayed when POST is not used.
            $this->showResult(false, _m('Request must be POST.'));
            return;
        }

        $missing = array();

        if (empty($this->port)) {
            $missing[] = 'port';
        }

        if (empty($this->path)) {
            $missing[] = 'path';
        }

        if (empty($this->protocol)) {
            $missing[] = 'protocol';
        } else if (strtolower($this->protocol) != 'http-post') {
            // TRANS: Form validation error displayed when HTTP POST is not used.
            $msg = _m('Only HTTP POST notifications are supported at this time.');
            $this->showResult(false, $msg);
            return;
        }

        if (!isset($this->procedure)) {
            $missing[] = 'notifyProcedure';
        }

        if (!empty($missing)) {
            // TRANS: List separator.
            $separator = _m('SEPARATOR',', ');
            // TRANS: Form validation error displayed when a request body is missing expected parameters.
            // TRANS: %s is a list of parameters separated by a list separator (default: ", ").
            $msg = sprintf(_m('The following parameters were missing from the request body: %s.'),implode($separator, $missing));
            $this->showResult(false, $msg);
            return;
        }

        if (empty($this->feeds)) {
            // TRANS: Form validation error displayed when not providing any valid profile feed URLs.
            $msg = _m('You must provide at least one valid profile feed URL ' .
              '(url1, url2, url3 ... urlN).');
            $this->showResult(false, $msg);
            return;
        }

        // We have to validate everything before saving anything.
        // We only return one success or failure no matter how
        // many feeds the subscriber is trying to subscribe to
        foreach ($this->feeds as $feed) {
            if (!$this->validateFeed($feed)) {
                $nh = $this->getNotifyUrl();
                common_log(LOG_WARNING,
                           "RSSCloud plugin - $nh tried to subscribe to invalid feed: $feed");

                // TRANS: Form validation error displayed when not providing a valid feed URL.
                $msg = _m('Feed subscription failed: Not a valid feed.');
                $this->showResult(false, $msg);
                return;
            }

            if (!$this->testNotificationHandler($feed)) {
                // TRANS: Form validation error displayed when feed subscription failed.
                $msg = _m('Feed subscription failed: ' .
                'Notification handler does not respond correctly.');
                $this->showResult(false, $msg);
                return;
            }
        }

        foreach ($this->feeds as $feed) {
            $this->saveSubscription($feed);
        }

        // XXX: What to do about deleting stale subscriptions?
        // 25 hours seems harsh. WordPress doesn't ever remove
        // subscriptions.
        // TRANS: Success message after subscribing to one or more feeds.
        $msg = _m('Thanks for the subscription. ' .
          'When the feed(s) update(s), you will be notified.');

        $this->showResult(true, $msg);
    }

    /**
     * Validate that the requested feed is one we serve
     * up via RSSCloud.
     *
     * @param string $feed the feed in question
     *
     * @return void
     */
    function validateFeed($feed)
    {
        $user = $this->userFromFeed($feed);

        if (empty($user)) {
            return false;
        }

        return true;
    }

    /**
     * Pull all of the urls (url1, url2, url3...urlN) that
     * the subscriber wants to subscribe to.
     *
     * @return array $feeds the list of feeds
     */
    function getFeeds()
    {
        $feeds = array();

        while (list($key, $feed) = each($this->args)) {
            if (preg_match('/^url\d*$/', $key)) {
                $feeds[] = $feed;
            }
        }

        return $feeds;
    }

    /**
     * Test that a notification handler is there and is reponding
     * correctly.  This is called before adding a subscription.
     *
     * @param string $feed the feed to verify
     *
     * @return boolean success result
     */
    function testNotificationHandler($feed)
    {
        $notifyUrl = $this->getNotifyUrl();

        $notifier = new RSSCloudNotifier();

        if (isset($this->domain)) {
            // 'domain' param set, so we have to use GET and send a challenge
            common_log(LOG_INFO,
                       'RSSCloud plugin - Testing notification handler with challenge: ' .
                       $notifyUrl);
            return $notifier->challenge($notifyUrl, $feed);
        } else {
            common_log(LOG_INFO, 'RSSCloud plugin - Testing notification handler: ' .
                       $notifyUrl);

            return $notifier->postUpdate($notifyUrl, $feed);
        }
    }

    /**
     * Build the URL for the notification handler based on the
     * parameters passed in with the subscription request.
     *
     * @return string notification handler url
     */
    function getNotifyUrl()
    {
        if (isset($this->domain)) {
            return 'http://' . $this->domain . ':' . $this->port . $this->path;
        } else {
            return 'http://' . $this->ip . ':' . $this->port . $this->path;
        }
    }

    /**
     * Uses the nickname part of the subscribed feed URL to figure out
     * whethere there's really a user with such a feed.  Used to
     * validate feeds before adding a subscription.
     *
     * @param string $feed the feed in question
     *
     * @return boolean success
     */
    function userFromFeed($feed)
    {
        // We only do canonical RSS2 profile feeds (specified by ID), e.g.:
        // http://www.example.com/api/statuses/user_timeline/2.rss
        $path  = common_path('api/statuses/user_timeline/');
        $valid = '%^' . $path . '(?<id>.*)\.rss$%';

        if (preg_match($valid, $feed, $matches)) {
            $user = User::getKV('id', $matches['id']);
            if (!empty($user)) {
                return $user;
            }
        }

        return false;
    }

    /**
     * Save an RSSCloud subscription
     *
     * @param string $feed a valid profile feed
     *
     * @return boolean success result
     */
    function saveSubscription($feed)
    {
        $user = $this->userFromFeed($feed);

        $notifyUrl = $this->getNotifyUrl();

        $sub = RSSCloudSubscription::getSubscription($user->id, $notifyUrl);

        if ($sub) {
            common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl refreshed subscription" .
                         " to user $user->nickname (id: $user->id).");
        } else {
            $sub = new RSSCloudSubscription();

            $sub->subscribed = $user->id;
            $sub->url        = $notifyUrl;
            $sub->created    = common_sql_now();

            if (!$sub->insert()) {
                common_log_db_error($sub, 'INSERT', __FILE__);
                return false;
            }

            common_log(LOG_INFO, "RSSCloud plugin - $notifyUrl subscribed" .
                       " to user $user->nickname (id: $user->id)");
        }

        return true;
    }

    /**
     * Show an XML message indicating the subscription
     * was successful or failed.
     *
     * @param boolean $success whether it was good or bad
     * @param string  $msg     the message to output
     *
     * @return boolean success result
     */
    function showResult($success, $msg)
    {
        $this->startXML();
        $this->elementStart('notifyResult',
                            array('success' => ($success) ? 'true' : 'false',
                                  'msg'     => $msg));
        $this->endXML();
    }
}


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET') && !defined('LACONICA')) {
    exit(1);
}

/**
 * Table Definition for rsscloud_subscription
 */

require_once INSTALLDIR . '/classes/Memcached_DataObject.php';

class RSSCloudSubscription extends Memcached_DataObject {

    var $__table='rsscloud_subscription'; // table name
    var $subscribed;                      // int    primary key user id
    var $url;                             // string primary key
    var $failures;                        // int
    var $created;                         // datestamp()
    var $modified;                        // timestamp()   not_null default_CURRENT_TIMESTAMP

    static function getKV($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_Grp',$k,$v); }

    function table()
    {

        $db = $this->getDatabaseConnection();
        $dbtype = $db->phptype;

        $cols = array('subscribed' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
                      'url'        => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
                      'failures'   => DB_DATAOBJECT_INT,
                      'created'    => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
                      'modified'  => ($dbtype == 'mysql' || $dbtype == 'mysqli') ?
                      DB_DATAOBJECT_MYSQLTIMESTAMP + DB_DATAOBJECT_NOTNULL :
                      DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME
                      );

        return $cols;
    }

    function keys()
    {
        return array('subscribed' => 'N', 'url' => 'N');
    }

    static function getSubscription($subscribed, $url)
    {
        $sub = new RSSCloudSubscription();
        $sub->whereAdd("subscribed = $subscribed");
        $sub->whereAdd("url = '$url'");
        $sub->limit(1);

        if ($sub->find()) {
            $sub->fetch();
            return $sub;
        }

        return false;
    }
}


code:
<?php
/**
 * StatusNet, the distributed open-source microblogging tool
 *
 * Class to ping an rssCloud endpoint when a feed has been updated
 *
 * PHP version 5
 *
 * LICENCE: This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
   *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @category  Plugin
 * @package   StatusNet
 * @author    Zach Copley <zach@status.net>
 * @copyright 2009 StatusNet, Inc.
 * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link      http://status.net/
 */

if (!defined('STATUSNET')) {
    exit(1);
}

/**
 * Class for notifying cloud-enabled RSS aggregators that StatusNet
 * feeds have been updated.
 *
 * @category Plugin
 * @package  StatusNet
 * @author   Zach Copley <zach@status.net>
 * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
 * @link     http://status.net/
 */
class RSSCloudNotifier
{
    const MAX_FAILURES = 3;

    /**
     * Send an HTTP GET to the notification handler with a
     * challenge string to see if it repsonds correctly.
     *
     * @param string $endpoint URL of the notification handler
     * @param string $feed     the feed being subscribed to
     *
     * @return boolean success
     */
    function challenge($endpoint, $feed)
    {
        $code   = common_confirmation_code(128);
        $params = array('url' => $feed, 'challenge' => $code);
        $url    = $endpoint . '?' . http_build_query($params);

        try {
            $client   = new HTTPClient();
            $response = $client->get($url);
        } catch (Exception $e) {
            common_log(LOG_INFO,
                       'RSSCloud plugin - failure testing notify handler ' .
                       $endpoint . ' - '  . $e->getMessage());
            return false;
        }

        // Check response is betweet 200 and 299 and body contains challenge data

        $status = $response->getStatus();
        $body   = $response->getBody();

        if ($status >= 200 && $status < 300) {
            // NOTE: the spec says that the body must contain the string
            // challenge.  It doesn't say that the body must contain the
            // challenge string ONLY, although that seems to be the way
            // the other implementors have interpreted it.

            if (strpos($body, $code) !== false) {
                common_log(LOG_INFO, 'RSSCloud plugin - ' .
                           "success testing notify handler:  $endpoint");
                return true;
            } else {
                common_log(LOG_INFO, 'RSSCloud plugin - ' .
                          'challenge/repsonse failed for notify handler ' .
                           $endpoint);
                common_debug('body = ' . var_export($body, true));
                return false;
            }
        } else {
            common_log(LOG_INFO, 'RSSCloud plugin - ' .
                       "failure testing notify handler:  $endpoint " .
                       ' - got HTTP ' . $status);
            common_debug('body = ' . var_export($body, true));
            return false;
        }
    }

    /**
     * HTTP POST a notification that a feed has been updated
     * ('ping the cloud').
     *
     * @param String $endpoint URL of the notification handler
     * @param String $feed     the feed being subscribed to
     *
     * @return boolean success
     */
    function postUpdate($endpoint, $feed)
    {
        $headers  = array();
        $postdata = array('url' => $feed);

        try {
            $client   = new HTTPClient();
            $response = $client->post($endpoint, $headers, $postdata);
        } catch (Exception $e) {
            common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
                       $endpoint . ' that feed ' . $feed .
                       ' has changed: ' . $e->getMessage());
            return false;
        }

        $status = $response->getStatus();

        if ($status >= 200 && $status < 300) {
            common_log(LOG_INFO, 'RSSCloud plugin - success notifying ' .
                       $endpoint . ' that feed ' . $feed . ' has changed.');
            return true;
        } else {
            common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' .
                       $endpoint . ' that feed ' . $feed .
                       ' has changed: got HTTP ' . $status);
            return false;
        }
    }

    /**
     * Notify all subscribers to a profile feed that it has changed.
     *
     * @param Profile $profile the profile whose feed has been
     *        updated
     *
     * @return boolean success
     */
    function notify($profile)
    {
        $feed = common_path('api/statuses/user_timeline/') .
          $profile->id . '.rss';

        $cloudSub = new RSSCloudSubscription();

        $cloudSub->subscribed = $profile->id;

        if ($cloudSub->find()) {
            while ($cloudSub->fetch()) {
                $result = $this->postUpdate($cloudSub->url, $feed);
                if ($result == false) {
                    $this->handleFailure($cloudSub);
                }
            }
        }

        return true;
    }

    /**
     * Handle problems posting cloud notifications. Increment the failure
     * count, or delete the subscription if the maximum number of failures
     * is exceeded.
     *
     * XXX: Redo with proper DB_DataObject methods once I figure out what
     * what the problem is with pluginized DB_DataObjects. -Z
     *
     * @param RSSCloudSubscription $cloudSub the subscription in question
     *
     * @return boolean success
     */
    function handleFailure($cloudSub)
    {
        $failCnt = $cloudSub->failures + 1;

        if ($failCnt == self::MAX_FAILURES) {

            common_log(LOG_INFO,
                       'Deleting RSSCloud subcription ' .
                       '(max failure count reached), profile: ' .
                       $cloudSub->subscribed .
                       ' handler: ' .
                       $cloudSub->url);

            // XXX: WTF! ->delete() doesn't work. Clearly, there are some issues with
            // the DB_DataObject, or my understanding of it.  Have to drop into SQL.

            // $result = $cloudSub->delete();

            $qry = 'DELETE from rsscloud_subscription' .
              ' WHERE subscribed = ' . $cloudSub->subscribed .
              ' AND url = \'' . $cloudSub->url . '\'';

            $result = $cloudSub->query($qry);

            if (!$result) {
                common_log_db_error($cloudSub, 'DELETE', __FILE__);
                common_log(LOG_ERR, 'Could not delete RSSCloud subscription.');
            }
        } else {
            common_debug('Updating failure count on RSSCloud subscription. ' .
                         $failCnt);

            $failCnt = $cloudSub->failures + 1;

            // XXX: ->update() not working either, gar!

            $qry = 'UPDATE rsscloud_subscription' .
              ' SET failures = ' . $failCnt .
              ' WHERE subscribed = ' . $cloudSub->subscribed .
              ' AND url = \'' . $cloudSub->url . '\'';

            $result = $cloudSub->query($qry);

            if (!$result) {
                common_log_db_error($cloudsub, 'UPDATE', __FILE__);
                common_log(LOG_ERR,
                           'Could not update failure ' .
                           'count on RSSCloud subscription');
            }
        }
    }
}


code:
<?php
/*
 * StatusNet - the distributed open-source microblogging tool
 * Copyright (C) 2008, 2009, StatusNet, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }

class RSSCloudQueueHandler extends QueueHandler
{
    function transport()
    {
        return 'rsscloud';
    }

    function handle($notice)
    {
        try {
            $profile = $notice->getProfile();
        } catch (Exception $e) {
            common_log(LOG_ERR, "Dropping RSSCloud item for notice with bogus profile: " . $e->getMessage());
            return true;
        }
        $notifier = new RSSCloudNotifier();
        return $notifier->notify($profile);
    }
}


code:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-06-08 18:20+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the RSSCloud protocol."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default: ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Afrikaans (http://www.transifex.com/gnu-social/gnu-social/language/af/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: af\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (http://www.transifex.com/gnu-social/gnu-social/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr "و "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (Egypt) (http://www.transifex.com/gnu-social/gnu-social/language/ar_EG/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar_EG\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Asturian (http://www.transifex.com/gnu-social/gnu-social/language/ast/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ast\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ""

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""


code:
# Translation file for GNU social - the free software social networking platform
# Copyright (C) 2015 - 2019 Free Software Foundation, Inc http://www.fsf.org
# This file is under https://www.gnu.org/licenses/agpl v3 or later
#
# Translators:
msgid ""
msgstr ""
"Project-Id-Version: GNU social\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-02 17:47+0100\n"
"PO-Revision-Date: 2015-02-07 10:23+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Belarusian (Tarask) (http://www.transifex.com/gnu-social/gnu-social/language/be@tarask/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: be@tarask\n"
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"

#. TRANS: Plugin description.
#: RSSCloudPlugin.php:209
msgid ""
"The RSSCloud plugin enables your StatusNet instance to publish real-time "
"updates for profile RSS feeds using the <a "
"href=\"http://rsscloud.org/\">RSSCloud protocol</a>."
msgstr ""

#. TRANS: Form validation error displayed when a URL parameter is missing.
#: actions/loggingaggregator.php:86
msgid "A URL parameter is required."
msgstr ""

#. TRANS: Form validation error displayed when HTTP GET is not used.
#: actions/loggingaggregator.php:94
msgid "This resource requires an HTTP GET."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/loggingaggregator.php:104
msgid "This resource requires an HTTP POST."
msgstr ""

#. TRANS: Form validation error displayed when POST is not used.
#: actions/rsscloudrequestnotify.php:91
msgid "Request must be POST."
msgstr ""

#. TRANS: Form validation error displayed when HTTP POST is not used.
#: actions/rsscloudrequestnotify.php:109
msgid "Only HTTP POST notifications are supported at this time."
msgstr ""

#. TRANS: List separator.
#: actions/rsscloudrequestnotify.php:120
msgctxt "SEPARATOR"
msgid ", "
msgstr ", "

#. TRANS: Form validation error displayed when a request body is missing
#. expected parameters.
#. TRANS: %s is a list of parameters separated by a list separator (default:
#. ", ").
#: actions/rsscloudrequestnotify.php:123
#, php-format
msgid "The following parameters were missing from the request body: %s."
msgstr ""

#. TRANS: Form validation error displayed when not providing any valid profile
#. feed URLs.
#: actions/rsscloudrequestnotify.php:130
msgid ""
"You must provide at least one valid profile feed URL (url1, url2, url3 ... "
"urlN)."
msgstr ""

#. TRANS: Form validation error displayed when not providing a valid feed URL.
#: actions/rsscloudrequestnotify.php:146
msgid "Feed subscription failed: Not a valid feed."
msgstr ""

#. TRANS: Form validation error displayed when feed subscription failed.
#: actions/rsscloudrequestnotify.php:153
msgid ""
"Feed subscription failed: Notification handler does not respond correctly."
msgstr ""

#. TRANS: Success message after subscribing to one or more feeds.
#: actions/rsscloudrequestnotify.php:168
msgid ""
"Thanks for the subscription. When the feed(s) update(s), you will be "
"notified."
msgstr ""