diff --git a/README.md b/README.md index a57451e00..dd04b096f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ You’ve installed Talk on your server, and you’re preparing to launch it on y ## Advanced Usage -For advanced configuration and usage of Talk, check out our [Configuration](https://docs.coralproject.net/talk/advanced-configuration/) and [Integration](https://docs.coralproject.net/talk/integrating/authentication/) how-tos. This covers topics in whih you will need dev support to fully customize and integrate Talk, such as SSO/authentication, creating and managing assets and articles, styling Talk with custom CSS, and setting up Notifications and SMTP support. +For advanced configuration and usage of Talk, check out our [Configuration](https://docs.coralproject.net/talk/advanced-configuration/) and [Integration](https://docs.coralproject.net/talk/integrating/authentication/) how-tos. This covers topics in which you will need dev support to fully customize and integrate Talk, such as SSO/authentication, creating and managing assets and articles, styling Talk with custom CSS, and setting up Notifications and SMTP support. ## Versions & Upgrading diff --git a/bin/cli-assets b/bin/cli-assets index 8242a02d6..d626ba094 100755 --- a/bin/cli-assets +++ b/bin/cli-assets @@ -219,6 +219,28 @@ async function rewrite(search, replace, options) { } } +/** + * debugAssetURL will scrape the given URL and print it's scraped values. + */ +async function debugAssetURL(url) { + try { + const meta = await scraper.scrape(url); + + const table = new Table({ head: ['Property', 'Value'] }); + + for (const [property, value] of Object.entries(meta)) { + table.push([property, value]); + } + + console.log(table.toString()); + + util.shutdown(0); + } catch (err) { + console.error(err); + util.shutdown(1); + } +} + //============================================================================== // Setting up the program command line arguments. //============================================================================== @@ -234,6 +256,13 @@ program .description('list all the assets in the database') .action(listAssets); +program + .command('debug [url]') + .description( + 'prints the scraped metadata that would be added to the given asset' + ) + .action(debugAssetURL); + program .command('refresh [age]') .description('queues the assets that exceed the age requested') diff --git a/client/coral-admin/src/routes/Configure/components/StreamSettings.js b/client/coral-admin/src/routes/Configure/components/StreamSettings.js index a470f5761..2526a3ab9 100644 --- a/client/coral-admin/src/routes/Configure/components/StreamSettings.js +++ b/client/coral-admin/src/routes/Configure/components/StreamSettings.js @@ -155,9 +155,19 @@ class StreamSettings extends React.Component { -

{t('configure.include_comment_stream_desc')}

+

+ {t('configure.code_of_conduct_summary_desc')} +   + + Code of Conduct Guide. + +

- Edit + {t('framework.edit')} )} diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 20aa4ce57..bf7964cf9 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -1,10 +1,5 @@ import * as actions from '../constants/auth'; -import jwtDecode from 'jwt-decode'; - -function cleanAuthData(localStorage) { - localStorage.removeItem('token'); - localStorage.removeItem('exp'); -} +import { setStorageAuthToken, clearStorageAuthToken } from '../services/auth'; export const checkLogin = () => ( dispatch, @@ -15,7 +10,7 @@ export const checkLogin = () => ( rest('/auth') .then(result => { if (!result.user) { - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); dispatch(checkLoginSuccess(null)); client.resetWebsocket(); return; @@ -32,7 +27,7 @@ export const checkLogin = () => ( .catch(error => { if (error.status && error.status === 401 && localStorage) { // Unauthorized. - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); client.resetWebsocket(); } else { console.error(error); @@ -58,8 +53,7 @@ export const setAuthToken = token => ( _, { localStorage, client } ) => { - localStorage.setItem('exp', jwtDecode(token).exp); - localStorage.setItem('token', token); + setStorageAuthToken(localStorage, token); // Dispatch the set auth token action. For some browsers and situations, we // may not be able to persist the auth token any other way. Keep it in redux! @@ -76,9 +70,7 @@ export const handleSuccessfulLogin = (user, token) => ( _, { client, localStorage, postMessage } ) => { - const { exp } = jwtDecode(token); - localStorage.setItem('exp', exp); - localStorage.setItem('token', token); + setStorageAuthToken(localStorage, token); // Send the message via the messages service to the window.opener if it // exists. @@ -117,7 +109,7 @@ export const logout = () => async ( } // Clear the auth data persisted to localStorage. - cleanAuthData(localStorage); + clearStorageAuthToken(localStorage); // Reset the websocket. client.resetWebsocket(); diff --git a/client/coral-framework/services/auth.js b/client/coral-framework/services/auth.js new file mode 100644 index 000000000..a23a6dd0d --- /dev/null +++ b/client/coral-framework/services/auth.js @@ -0,0 +1,11 @@ +import jwtDecode from 'jwt-decode'; + +export const setStorageAuthToken = (storage, token) => { + storage.setItem('exp', jwtDecode(token).exp); + storage.setItem('token', token); +}; + +export const clearStorageAuthToken = storage => { + storage.removeItem('token'); + storage.removeItem('exp'); +}; diff --git a/client/coral-framework/services/bootstrap.js b/client/coral-framework/services/bootstrap.js index c96893d4e..300cd3e70 100644 --- a/client/coral-framework/services/bootstrap.js +++ b/client/coral-framework/services/bootstrap.js @@ -22,6 +22,7 @@ import { } from 'coral-framework/services/storage'; import { createHistory } from 'coral-framework/services/history'; import { createIntrospection } from 'coral-framework/services/introspection'; +import { setStorageAuthToken } from 'coral-framework/services/auth'; import introspectionData from 'coral-framework/graphql/introspection.json'; import coreReducers from '../reducers'; import { checkLogin as checkLoginAction } from '../actions/auth'; @@ -46,7 +47,30 @@ const getAuthToken = (store, storage) => { // capable of storing the token in localStorage, then we would have // persisted it to the redux state. return state.config.auth_token || state.auth.token; - } else if (!bowser.safari && !bowser.ios && storage) { + } else if (location.hash && location.hash.startsWith('#access_token=')) { + // Check to see if the access token is living in the URL as a hash. + const token = location.hash.substring(14); + + history.replaceState( + {}, + document.title, + window.location.pathname + window.location.search + ); + + // Once we clear the hash above, this login method will not persist across + // refreshes. We will need to persist the token to storage if it's + // available. + if (storage) { + setStorageAuthToken(storage, token); + } + + return token; + } else if ( + !bowser.safari && + !bowser.ios && + storage && + storage.getItem('token') + ) { // Use local storage auth tokens where there's a stable api. return storage.getItem('token'); } diff --git a/client/coral-framework/services/i18n.js b/client/coral-framework/services/i18n.js index c4deca817..87d74b3f2 100644 --- a/client/coral-framework/services/i18n.js +++ b/client/coral-framework/services/i18n.js @@ -12,6 +12,7 @@ import 'moment/locale/da'; import 'moment/locale/de'; import 'moment/locale/es'; import 'moment/locale/fr'; +import 'moment/locale/it'; import 'moment/locale/nl'; import 'moment/locale/pt-br'; @@ -22,6 +23,7 @@ import daTA from 'timeago.js/locales/da'; import deTA from 'timeago.js/locales/de'; import esTA from 'timeago.js/locales/es'; import frTA from 'timeago.js/locales/fr'; +import itTA from 'timeago.js/locales/it'; import nlTA from 'timeago.js/locales/nl'; import pt_BRTA from 'timeago.js/locales/pt_BR'; import zh_CNTA from 'timeago.js/locales/zh_CN'; @@ -34,6 +36,7 @@ import da from '../../../locales/da.yml'; import de from '../../../locales/de.yml'; import es from '../../../locales/es.yml'; import fr from '../../../locales/fr.yml'; +import it from '../../../locales/it.yml'; import nl_NL from '../../../locales/nl_NL.yml'; import pt_BR from '../../../locales/pt_BR.yml'; import zh_CN from '../../../locales/zh_CN.yml'; @@ -61,6 +64,7 @@ export const translations = { ...de, ...es, ...fr, + ...it, ...nl_NL, ...pt_BR, ...zh_CN, @@ -106,6 +110,7 @@ export function setupTranslations() { ta.register('da', daTA); ta.register('de', deTA); ta.register('fr', frTA); + ta.register('it', itTA); ta.register('nl_NL', nlTA); ta.register('pt_BR', pt_BRTA); ta.register('zh_CN', zh_CNTA); diff --git a/docs/_config.yml b/docs/_config.yml index 3ad74d56b..57fe6d666 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -106,6 +106,8 @@ sidebar: url: /integrating/authentication/ - title: Asset Management url: /integrating/asset-management/ + - title: Asset Scraping + url: /integrating/asset-scraping/ - title: Configuring the Comment Stream url: /integrating/configuring-comment-stream/ - title: Configuring the Admin diff --git a/docs/source/03-07-product-guide-trust.md b/docs/source/03-07-product-guide-trust.md index aa0a89259..189869c08 100644 --- a/docs/source/03-07-product-guide-trust.md +++ b/docs/source/03-07-product-guide-trust.md @@ -7,7 +7,7 @@ Trust is a set of components within Talk that incorporate basic automated modera ## User Karma Score -Using Trust’s calculations, Talk will automatically hold back, move to the Reported queue, and tag with a 'History' marker, any comments by users who have an Unreliable karma score. (This is for sites who practice post-moderation. If you set pre-moderation of all comments sitewide, this feature has limited use.) +Using Trust’s calculations, Talk will automatically hold back, move to the Reported queue, and tag with a 'Karma' marker, any comments by users who have an Unreliable karma score. (This is for sites who practice post-moderation. If you set pre-moderation of all comments sitewide, this feature has limited use.) All users start out with a Neutral karma score (`0`). If they have a comment approved by a moderator, their score increases by `1`; if they have a comment rejected by a moderator, it decreases by `1`. When a commenter's score is labeled as Unreliable, their comments must be approved from the Reported queue before they are posted. Commenters are shown a message stating that a moderator will review their comment shortly. @@ -27,29 +27,3 @@ We strongly recommend not telling your community how this system works, or where If you see that a high proportion of first-time commenters on your site are abusive, you might want to change the threshhold to `0`, at least temporarily. You can configure your own Trust thresholds by using [TRUST_THRESHOLDS](/talk/advanced-configuration/#trust-thresholds) in your site configuration. - -## Reliable and Unreliable Flaggers - -Trust also calculates how reliable users are in terms of the comments they -report. This information is displayed to moderators in the User History drawer, -which is accessed by clicking on a user’s name in the Admin. Currently, no other action is taken based on this score. - -If a user's reports mostly match what moderators reject, their Report status -will display to moderators as Reliable in the user information drawer. If a -user's reports mostly differ from what moderators reject, their Report status -will show as Unreliable. - -If Talk doesn't have enough reports to make a call, or the reports even out, their -status is Neutral. - -Here are the default thresholds: - -```text --1 and lower: Unreliable -0 to +1: Neutral -+2 and higher: Reliable -``` -You can configure your own Trust thresholds by using [TRUST_THRESHOLDS](/talk/advanced-configuration/#trust-thresholds) in your -configuration. - -Note: Report Karma doesn't include reports of "I don't agree with this comment". diff --git a/docs/source/integrating/asset-scraping.md b/docs/source/integrating/asset-scraping.md new file mode 100644 index 000000000..5d524f062 --- /dev/null +++ b/docs/source/integrating/asset-scraping.md @@ -0,0 +1,44 @@ +--- +title: Asset Scraping +permalink: /integrating/asset-scraping/ +--- + +By default, Assets in Talk have their metadata scraped when they are loaded. +This provides the easiest way for newsrooms to integrate their CMS's into Talk +in a simple way. We use the following +[meta tags](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta) on +the target pages that allow us to extract some properties. + +| Asset Property | Selector | +|--------------------|----------| +| `title` | See [`metascraper-title`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-title/index.js) | +| `description` | See [`metascraper-description`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-description/index.js) | +| `image` | See [`metascraper-image`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-image/index.js) | +| `author` | See [`metascraper-author`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-author/index.js) | +| `publication_date` | See [`metascraper-date`](https://github.com/microlinkhq/metascraper/blob/dc664c37ea1b238b1e3e9d5342edfacc9027892c/packages/metascraper-date/index.js) | +| `modified_date` | `meta[property="article:modified"]` | +| `section` | `meta[property="article:section"]` | + +You can use the `./bin/cli assets debug ` to print the scraped metadata +from that URL. For example: + +```bash + $ ./bin/cli assets debug https://www.washingtonpost.com/technology/2018/10/30/apple-event-october-ipad-pro-macbook-air/ +┌──────────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Property │ Value │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ title │ Apple redesigns the iPad Pro, breathes new life in the MacBook Air │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ description │ Apple is unveiling new iPads and MacBooks at an event in New York starting at 10 a.m. Fowler is there and will report in with the news and hands-on analysis throughout the day. │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ image │ https://www.washingtonpost.com/resizer/JAwNQE2alL2JjiWrbXeJ46wZHqA=/1484x0/arc-anglerfish-washpost-prod-washpost.s3.amazonaws.com/public/G5TWBFW4LAI6RC5MX7QB7TODUY.jpg │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ author │ Geoffrey A. Fowler │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ publication_date │ 2018-10-30T10:40:00.000Z │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ modified_date │ │ +├──────────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤ +│ section │ │ +└──────────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +``` \ No newline at end of file diff --git a/jobs/scraper/index.js b/jobs/scraper/index.js index 77d429042..f918cddfc 100644 --- a/jobs/scraper/index.js +++ b/jobs/scraper/index.js @@ -3,59 +3,7 @@ const scraper = require('../../services/scraper'); const Assets = require('../../services/assets'); const { createLogger } = require('../../services/logging'); const logger = createLogger('jobs:scraper'); -const fetch = require('node-fetch'); const { merge } = require('lodash'); -const { version } = require('../../package.json'); -const { SCRAPER_HEADERS, SCRAPER_PROXY_URL } = require('../../config'); -const ProxyAgent = require('proxy-agent'); - -// Load the scraper with the rules. -const metascraper = require('metascraper').load([ - require('metascraper-title')(), - require('metascraper-description')(), - require('metascraper-image')(), - require('metascraper-author')(), - require('metascraper-date')(), - require('./rules/modified')(), - require('./rules/section')(), -]); - -let customHeaders = {}; -try { - customHeaders = JSON.parse(SCRAPER_HEADERS); -} catch (err) { - console.error('Cannot parse TALK_SCRAPER_HEADERS'); - throw err; -} - -// Parse the headers to be added to the scraper. -const headers = merge( - { - 'User-Agent': `Coral-Talk/${version}`, - }, - customHeaders -); - -// Add proxy configuration if exists. -const agent = SCRAPER_PROXY_URL ? new ProxyAgent(SCRAPER_PROXY_URL) : null; - -/** - * Scrapes the given asset for metadata. - */ -async function scrape({ url }) { - const res = await fetch(url, { - headers, - agent, - }); - const html = await res.text(); - - // Get the metadata from the scraped html. - const metadata = await metascraper({ - html, - url, - }); - return metadata; -} /** * Updates an Asset based on scraped asset metadata. @@ -64,16 +12,9 @@ function update(id, meta) { return Asset.update( { id }, { - $set: { - title: meta.title || '', - description: meta.description || '', - image: meta.image ? meta.image : '', - author: meta.author || '', - publication_date: meta.date || '', - modified_date: meta.modified || '', - section: meta.section || '', + $set: merge(meta, { scraped: new Date(), - }, + }), } ); } @@ -95,7 +36,7 @@ module.exports = () => { } // Scrape the metadata from the asset. - const meta = await scrape(asset); + const meta = await scraper.scrape(asset.url); log.info('Finished scraping'); diff --git a/locales/ar.yml b/locales/ar.yml index 40197aaf7..70fa87e9b 100644 --- a/locales/ar.yml +++ b/locales/ar.yml @@ -130,8 +130,8 @@ ar: enable_questionbox: 'اطرح سؤال على القراء' enable_questionbox_description: 'هذا السؤال سيظهر في الجزء العلوي من جدول التعليقات هذا. اسأل القراء عن مسألة معينة في المقال او اطرح أسئلة نقاشية.. الخ.' hours: ساعات - include_comment_stream: 'ادراج وصف جدول التعليقات للقراء' - include_comment_stream_desc: 'اكتب رسالة ليتم إضافتها إلى الجزء العلوي من جدول التعليقات. ضع موضوعا، اشمل القواعد الإرشادية للمجموعة .. الخ' + code_of_conduct_summary: 'ادراج وصف جدول التعليقات للقراء' + code_of_conduct_summary_desc: 'اكتب رسالة ليتم إضافتها إلى الجزء العلوي من جدول التعليقات. ضع موضوعا، اشمل القواعد الإرشادية للمجموعة .. الخ' include_question_here: 'اكتب سؤالك هنا:' include_text: 'ادرج النص هنا.' moderate: اشرف diff --git a/locales/da.yml b/locales/da.yml index 3804fc939..abcee5bfd 100644 --- a/locales/da.yml +++ b/locales/da.yml @@ -123,8 +123,8 @@ da: enable_questionbox: 'Stil et spørgsmål til læserne' enable_questionbox_description: 'Dette spørgsmål vises øverst i denne kommentarstrøm. Stil et spørgsmål til læserne om et bestemt problem i artiklen eller stil spørgsmål til diskussion mv.' hours: Timer - include_comment_stream: 'Inkluder kommentarstrømmens beskrivelse for læsere' - include_comment_stream_desc: 'Skriv en besked, der skal tilføjes øverst i din kommentarstrøm. Indsæt et emne der omfatter fællesskabsretningslinjer mv.' + code_of_conduct_summary: 'Inkluder kommentarstrømmens beskrivelse for læsere' + code_of_conduct_summary_desc: 'Skriv en besked, der skal tilføjes øverst i din kommentarstrøm. Indsæt et emne der omfatter fællesskabsretningslinjer mv.' include_question_here: 'Stil dit spørgsmål her:' include_text: 'Medtag din tekst her.' moderate: Moderat diff --git a/locales/de.yml b/locales/de.yml index 89368bddd..53e44f46a 100644 --- a/locales/de.yml +++ b/locales/de.yml @@ -132,8 +132,8 @@ de: enable_questionbox: 'Stellen Sie den Lesern eine Frage' enable_questionbox_description: 'Diese Frage erscheint am Anfang des Kommentarbereichs. Regen Sie eine Diskussion an.' hours: Stunden - include_comment_stream: 'Einleitung zum Kommentarbereich' - include_comment_stream_desc: 'Verfassen Sie eine Einleitung, die über jedem Kommentarbereich erscheint. Nützlich z.B. für Community-Richtlinien.' + code_of_conduct_summary: 'Einleitung zum Kommentarbereich' + code_of_conduct_summary_desc: 'Verfassen Sie eine Einleitung, die über jedem Kommentarbereich erscheint. Nützlich z.B. für Community-Richtlinien.' include_question_here: 'Stellen Sie Ihre Frage hier:' include_text: 'Fügen Sie Ihren Text hier ein.' moderate: Moderieren diff --git a/locales/en.yml b/locales/en.yml index 24d5eb780..41a036528 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -137,8 +137,8 @@ en: enable_questionbox: 'Ask Readers a Question' enable_questionbox_description: 'This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc.' hours: Hours - include_comment_stream: 'Include Comment Stream Description for Readers' - include_comment_stream_desc: 'Write a message to be added to the top of your comment stream. Pose a topic include community guidelines etc.' + code_of_conduct_summary: 'Summary of your Code of Conduct' + code_of_conduct_summary_desc: 'This message will appear above every comments stream on your site. Click here to learn more about writing a good code.' include_question_here: 'Write your question here:' include_text: 'Include your text here.' moderate: Moderate @@ -259,7 +259,7 @@ en: organization_contact_email: 'Organization email is not valid.' organization_name: 'Organization name must only contain letters or numbers.' password: 'Password must be at least 8 characters' - PAGE_NOT_AVAILABLE_ROLE: 'This page is for team use only. Please contact an administrator if you want to join this team.' + PAGE_NOT_AVAILABLE_ROLE: 'This page is for team use only. Please contact an administrator if you want to join this team.' PASSWORD_INCORRECT: 'Your current password was entered incorrectly' PASSWORD_LENGTH: 'Password is too short' PASSWORD_REQUIRED: 'Must input a password' @@ -318,6 +318,7 @@ en: comments: comments configure_stream: Configure content_not_available: 'This content is not available' + edit: Edit edit_name: button: Submit error: 'Usernames can contain letters numbers and _ only' diff --git a/locales/es.yml b/locales/es.yml index 5b319d302..1a393853b 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -4,19 +4,19 @@ es: view_options: 'Ver opciones' already_flagged_username: 'Usted ya reportó a este usuario.' bandialog: - are_you_sure: '¿Estás segura que quieres suspender a {0}?' - ban_user: '¿Quieres suspender el Usuario?' + are_you_sure: '¿Estás seguro que quieres suspender a {0}?' + ban_user: '¿Quieres suspender al Usuario?' banned_user: 'Usuario Suspendido' cancel: Cancelar - email_message_ban: "Estimado/a {0},\n\nUsted o alguien con acceso a su cuenta a violado los lineamientos de nuestra comunidad. Como consecuencia de esto, su cuenta fue bloqueada. No podrá realizar ni reportar más comentarios. Si usted piensa que esto ha sido un error, por favor contáctese con nosotros." + email_message_ban: "Estimado/a {0},\n\nUsted o alguien con acceso a su cuenta ha violado los lineamientos de nuestra comunidad. Como consecuencia de esto, su cuenta fue bloqueada. No podrá realizar ni reportar más comentarios. Si usted piensa que esto ha sido un error, por favor contáctese con nosotros." note: 'Nota: {0}' note_ban_user: 'Suspender a este usuario no le va a permitir (al usuario) borrar ni editar ni comentar.' note_reject_comment: 'Suspender a este usuario también va a colocar este comentario en la cola de Rechazados.' - notify_ban_description: 'Esto notificará al usuario por email que fueron suspendidos de la comunidad' + notify_ban_description: 'Esto notificará al usuario por correo electrónico que fueron suspendidos de la comunidad' notify_ban_headline: 'Notificar al usuario de la suspensión' send: Enviar write_a_message: 'Escribe un mensaje' - yes_ban_user: 'Si, Suspender al usuario' + yes_ban_user: 'Si, suspender al usuario' bio_offensive: 'Esta biografia es ofensiva' cancel: Cancelar characters_remaining: 'caracteres restantes' @@ -30,9 +30,9 @@ es: view_context: 'Ver contexto' comment_box: cancel: Cancelar - characters_remaining: 'carácteres restantes' + characters_remaining: 'caracteres restantes' comment: 'Publicar un comentario' - comment_post_banned_word: 'Tu comentario contiene una o más palabras que no están permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contacta a nuestro equipo de moderación.' + comment_post_banned_word: 'Tu comentario contiene una o más palabras que no están permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contactate a nuestro equipo de moderación.' comment_post_notif: 'Tu comentario ha sido publicado.' comment_post_notif_premod: 'Gracias por el comentario. Nuestro equipo de moderación va a revisarlo muy pronto.' name: Nombre @@ -40,7 +40,7 @@ es: reply: Responder comment_offensive: 'Este comentario es ofensivo' comment_plural: Comentarios - comment_post_banned_word: 'Tu comentario contiene una o más palabras que no están permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contacta a nuestro equipo de moderación.' + comment_post_banned_word: 'Tu comentario contiene una o más palabras que no están permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contactate con nuestro equipo de moderación.' comment_post_notif: 'Tu comentario ha sido publicado.' comment_post_notif_premod: 'Gracias por el comentario. Nuestro equipo de moderación va a revisarlo muy pronto.' comment_singular: Comentario @@ -57,40 +57,40 @@ es: account_creation_date: 'Fecha de creación de la cuenta' active: Activa admin: Administrator - ads_marketing: 'Esto parece ser un ad/marketing' + ads_marketing: 'Esto parece ser un publicidad/acción de comercialización' all: 'Todos' - are_you_sure: '¿Estás segura que quieres suspender a {0}?' + are_you_sure: '¿Estás seguro que quieres suspender a {0}?' ban_user: '¿Quieres suspender al Usuario?' banned: Suspendido - banned_user: 'Usuario Suspendido' + banned_user: 'Usuario suspendido' cancel: Cancelar commenter: Comentarista dont_like_username: 'No me gusta este nombre de usuario' - filter_users: 'Filter users' + filter_users: 'Filtrarr usuarios' filter_role: Rol - flaggedaccounts: 'Nombres de Usuario Reportados' + flaggedaccounts: 'Nombres de usuario reportados' flags: Reportes impersonating: Impersonando loading: 'Cargando resultados' moderator: Moderator newsroom_role: 'Rol en la redacción' - no_flagged_accounts: 'No hay ningún nombre de usario reportado en este momento.' + no_flagged_accounts: 'No hay ningún nombre de usuario reportado en este momento.' no_results: 'No se encontraron usuarios con ese nombre o correo.' offensive: Ofensivo other: Otro people: Gente role: 'Seleccionar rol...' select_status: 'Seleccionar estado...' - spam_ads: Spam/Publicidad + spam_ads: Correo basura/Publicidad staff: Personal status: Estado suspended: Suspendido username_and_email: 'Usuario y Correo' - yes_ban_user: 'Si, Suspendan el usuario' + yes_ban_user: 'Sí, suspendan el usuario' configure: - access_message: 'Usted debe ser un administrador para acceder a esta página. Encuentre a otro admin y actualice los permisos de su cuenta!' + access_message: 'Usted debe ser un administrador para acceder a esta página. Encuentre a otro administrador y actualice los permisos de su cuenta!' apply: Aplicar - banned_word_text: 'Comentarios que contengan estas palabras o frases, en mayusculas o minúsculas, serán automáticamente eliminados del hilo de comentario. Escribir una palabra y apretar Enter o Tabulador para agregarla. O pueden pegar una lista de palabras separadas por coma.' + banned_word_text: 'Comentarios que contengan estas palabras o frases, en mayúsculas o minúsculas, serán automáticamente eliminados del hilo de comentarios. Escribir una palabra y apretar Enter o Tabulador para agregarla. O pueden pegar una lista de palabras separadas por coma.' banned_words_title: 'Lista de palabras prohibidas' close: Cerrar close_after: 'Cerrar comentarios luego de' @@ -98,14 +98,14 @@ es: close_stream_configuration: 'Este hilo de comentario está en este momento cerrado. Al abrirlo, nuevos comentarios serán publicados y mostrados.' closed_comments_desc: 'Escribe un mensaje que será mostrado cuando los comentarios estén cerrados y no se acepten más comentarios.' closed_comments_label: 'Escribe un mensaje...' - closed_stream_settings: 'Mensaje que se muestra cuando no se aceptan más comentarios en el articulo' + closed_stream_settings: 'Mensaje que se muestra cuando no se aceptan más comentarios en el artículo' comment_count_error: 'Por favor escribir un número válido' comment_count_header: 'Limitar el largo del comentario' - comment_count_text_post: carácteres + comment_count_text_post: caracteres comment_count_text_pre: 'Los comentarios serán limitados a' comment_settings: Configuración comment_stream: 'Hilo de Comentarios' - comment_stream_will_close: 'El hilo de comentarios se cerrara' + comment_stream_will_close: 'El hilo de comentarios se cerrará' community: Comunidad configure: Configurar copy_and_paste: 'Copiar y pegar el código de más abajo en tu CMS para colocar la caja de comentarios en tus artículos' @@ -122,16 +122,16 @@ es: embed_comment_stream: 'Colocar Hilo de Comentarios' enable_pre_moderation: 'Permitir pre-moderación' enable_pre_moderation_text: 'Los moderadores deben aprobar todo comentario antes que sea publicado.' - enable_premod: 'Activar Pre Moderación' + enable_premod: 'Activar Pre-Moderación' enable_premod_description: 'Los y las moderadoras deben aprobar cualquier comentario antes de su publicación' - enable_premod_links: 'Pre-Moderar Comentarios que contienen Enlaces' + enable_premod_links: 'Pre-Moderar comentarios que contienen Enlaces' enable_premod_links_description: 'Los y las moderadoras deben aprobar cualquier comentario que contengan enlaces antes de su publicación.' enable_premod_links_text: 'Los moderadores deben aprobar todo comentario que contenga un enlace antes de que sea publicado.' enable_questionbox: 'Hacer una pregunta a los y las lectoras.' enable_questionbox_description: 'Esta pregunta aparecerá en la parte de arriba del hilo de comentarios.' hours: Horas - include_comment_stream: 'Incluir Descripción de Hilo de Comentarios para Lectores' - include_comment_stream_desc: 'Escribir un mensaje para ser incluido al principio del hilo de comentarios. Un tema planteado podría ser la guía de comunidad, etc.' + code_of_conduct_summary: 'Incluir Descripción de Hilo de Comentarios para Lectores' + code_of_conduct_summary_desc: 'Escribir un mensaje para ser incluido al principio del hilo de comentarios. Un tema planteado podría ser la guía de comunidad, etc.' include_question_here: 'Escribir la pregunta aquí.' include_text: 'Agregar tu texto aquí.' moderate: Moderar @@ -140,7 +140,7 @@ es: open_stream: 'Abrir Hilo de Comentarios' open_stream_configuration: 'Este hilo de comentarios está abierto. Al cerrarlo no se podrán publicar nuevos comentarios pero todos los comentarios anteriores aún serán mostrados.' organization_contact_email: 'Email de la Organización' - organization_info_copy: 'Nosotros usamos esta información en las notificaciones de email generadas por Talk. Esto conecta los mensajes de tu organización, y provee una forma para que los usuarios se comuniquen si tienen un inconveniente con su cuenta.' + organization_info_copy: 'Nosotros usamos esta información en las notificaciones de correo electrónico generadas por Talk. Esto conecta los mensajes de tu organización, y provee una forma para que los usuarios se comuniquen si tienen un inconveniente con su cuenta.' organization_info_copy_2: 'Recomendamos crear un email genérico (ej: community@yournewsroom.com) for this purpose. Esto significa que puede permanecer consistente con el tiempo y no expone un nombre que los usuarios puedan atacar si su cuenta fue bloqueada.' organization_information: 'Información de la Organización' organization_name: 'Nombre de la Organización' @@ -290,6 +290,7 @@ es: comments: comentarios configure_stream: 'Configurar' content_not_available: 'Este contenido no se encuentra disponible' + edit: Editar edit_name: button: Enviar error: 'Nombres de usuarios pueden solamente incluir letras, números y _' @@ -315,14 +316,14 @@ es: save: Guardar create: confirm_password: 'Confirmar Contraseña' - email: 'Dirección de correo' - organization_contact_email: 'Organización: Email de contacto' + email: 'Dirección de correo electrónico' + organization_contact_email: 'Organización: correo electrónico de contacto' password: Contraseña save: Guardar username: 'Nombre de Usuario' final: close: 'Cerrar este instalador' - description: '¡Gracias por instalar Talk! Enviamos un correo para verificar su dirección de correo. Mientras esta terminando de configurar su cuenta, ya puede comenzar a involucrarse con sus lectores.' + description: '¡Gracias por instalar Talk! Enviamos un correo para verificar su dirección de correo electrónico. Mientras esta terminando de configurar su cuenta, ya puede comenzar a involucrarse con sus lectores.' launch: 'Iniciar Talk' initial: description: 'Vamos a crear su comunidad Talk en unos pocos pasos.' diff --git a/locales/fi_FI.yml b/locales/fi_FI.yml index 54ff8f011..3c04c796a 100644 --- a/locales/fi_FI.yml +++ b/locales/fi_FI.yml @@ -123,8 +123,8 @@ fi_FI: enable_questionbox: 'Kysy lukijoilta' enable_questionbox_description: 'Tämä kysymys tulee näkymään kommenttiosion ylälaidassa. Kysy artikkelin aiheesta tai ohjaa keskustelua kysymyksen avulla.' hours: Tuntia - include_comment_stream: 'Sisällytä kommentoinnin kuvaus lukijoille' - include_comment_stream_desc: 'Kirjoita kommenttiosion yläreunassa näkyvä viesti. Aseta keskustelun aihe, sisällytä sääntöjä tms.' + code_of_conduct_summary: 'Sisällytä kommentoinnin kuvaus lukijoille' + code_of_conduct_summary_desc: 'Kirjoita kommenttiosion yläreunassa näkyvä viesti. Aseta keskustelun aihe, sisällytä sääntöjä tms.' include_question_here: 'Kirjoita kysymyksesi tähän:' include_text: 'Lisää teksti tähän.' moderate: Moderoi diff --git a/locales/fr.yml b/locales/fr.yml index f490fce64..11ddde892 100644 --- a/locales/fr.yml +++ b/locales/fr.yml @@ -127,8 +127,8 @@ fr: enable_questionbox: 'Posez une question aux lecteurs.' enable_questionbox_description: 'Cette question apparaîtra en haut de ce fil de commentaires. Demandez aux lecteurs de s''exprimer sur un sujet évoqué dans l''article ou posez les termes de la discussion, etc.' hours: Heures - include_comment_stream: 'Inclure la description du fil de commentaires pour les lecteurs' - include_comment_stream_desc: 'Écrivez un message à ajouter au haut de votre flux de commentaires. Publiez un sujet de discussion, avec des suggestion sur la tenue des débats, etc.' + code_of_conduct_summary: 'Inclure la description du fil de commentaires pour les lecteurs' + code_of_conduct_summary_desc: 'Écrivez un message à ajouter au haut de votre flux de commentaires. Publiez un sujet de discussion, avec des suggestion sur la tenue des débats, etc.' include_question_here: 'Écrivez votre question ici.' include_text: 'Entrez votre texte ici.' moderate: Modérer diff --git a/locales/it.yml b/locales/it.yml new file mode 100644 index 000000000..fa38cce63 --- /dev/null +++ b/locales/it.yml @@ -0,0 +1,574 @@ +it: + admin_sidebar: + sort_comments: 'Ordina Commenti' + view_options: 'Visualizza Opzioni' + already_flagged_username: 'Hai già segnalato questo username.' + bandialog: + are_you_sure: 'Sei sicuro di voler bloccare {0}?' + ban_user: 'Blocca Utente' + banned_user: 'Utenti bloccati' + cancel: Annulla + email_message_ban: "Caro {0},\n\nQualcuno che ha accesso al tuo account ha violato le nostre linee guida per la community. Di conseguenza, il tuo account è stato bloccato. Non potrai più commentare, apprezzare o segnalare commenti. Se ritieni questo sia un errore, contatta i nostri moderatori." + note: 'Nota: {0}' + note_ban_user: 'Bloccare questo utente non gli permetterà di commentare, interagire, o segnalare commenti.' + note_reject_comment: 'Bloccare questo utente inserirà inoltre questo commento tra quelli rifiutati.' + notify_ban_description: 'Questo notificherà l''utente, tramite email, che è stato bloccato dalla comunità.' + notify_ban_headline: 'Notifica l''utente della interdizione' + send: Invia + write_a_message: 'Scrivi un messaggio' + yes_ban_user: 'Si, blocca utente' + bio_offensive: 'Questa descrizione è offensiva' + cancel: Annulla + characters_remaining: 'caratteri rimanenti' + comment: + anon: Anonimo + ban_user: 'Blocca Utente' + comment: 'Pubblica un commento' + edited: Modificato + flagged: segnalato + undo_reject: Annulla + view_context: 'Visualizza il contesto' + comment_box: + cancel: Annulla + characters_remaining: 'caratteri rimanenti' + comment: 'Pubblica un commento' + comment_post_banned_word: 'Il tuo commento contiene una o più parole non permesse, non sarà quindi pubblicato. Se ritieni questo sia un errore, contatta i nostri moderatori.' + comment_post_notif: 'Il tuo commento è stato pubblicato.' + comment_post_notif_premod: 'Grazie per il tuo contributo. Il nostro team di moderatori revisionerà presto il tuo commento.' + name: Nome + post: Invia + reply: Rispondi + comment_history_blank: + info: 'La cronologia dei tuoi commenti apparirà qui' + title: 'Non hai pubblicato nessun commento' + comment_offensive: 'Questo commento è offensivo' + comment_plural: Commenti + comment_post_banned_word: 'Il tuo commento contiene una o più parole non permesse, non sarà quindi pubblicato. Se ritieni questo sia un errore, contatta i nostri moderatori.' + comment_post_notif: 'Il tuo commento è stato pubblicato.' + comment_post_notif_premod: 'Grazie per il tuo contributo. Il nostro team di moderatori revisionerà presto il tuo commento.' + comment_singular: Commento + common: + copy: Copia + copied: 'Copiato' + notsupported: 'Non supportato' + error: 'Si è verificato un errore.' + reaction: reazione + reactions: reazioni + reply: 'rispondi' # noun, singular + replies: 'risposte' + story: 'Storia' + community: + account_creation_date: 'Data creazione account' + active: Attivo + admin: Amministratore + ads_marketing: 'Questo sembra essere un annuncio pubblicitario' + all: 'Tutti' + are_you_sure: 'Sei sicuro di voler bloccare {0}?' + ban_user: 'Blocca Utente?' + banned: Bloccato + banned_user: 'Utente bloccato' + cancel: Annulla + commenter: Utente + dont_like_username: 'Username non adatto' + filter_users: 'Filtra utenti' + filter_role: Ruolo + flaggedaccounts: 'Username segnalati' + flags: Segnalazioni + impersonating: 'Impersonare' + loading: 'Caricamento risultati' + moderator: Moderatore + newsroom_role: 'Ruolo della sala stampa' + no_flagged_accounts: 'Nessun utente segnalato per ora.' + no_results: 'Nessun utente con quell''username o indirizzo email trovato.' + offensive: Offensivo + other: Altro + people: Persone + role: 'Seleziona ruolo...' + select_status: 'Seleziona status...' + spam_ads: Spam/pubblicità + staff: Staff + status: Status + suspended: Sospeso + username_and_email: 'Username e Email' + yes_ban_user: 'Si, blocca utente' + configure: + access_message: 'Devi essere amministratore per accedere alle configurazioni. Perfavore contatta un amministratore e chiedi di promuoverti!' + apply: Applica + banned_word_text: 'Commenti che contengono queste parole o frasi, che siano in maiuscolo o minuscolo, saranno automaticamente rimossi. Inserisci una parola e premi Invio o Tab per aggiungerla. Oppure aggiungi una lista di parole separate da virgole.' + banned_words_title: 'Lista di parole vietate' + close: Chiudi + close_after: 'Chiudi commenti successivi' + close_stream: 'Chiudi il thread dei commenti' + close_stream_configuration: 'Questo thread dei commenti è attualmente chiuso. Aprirlo per visulizzare nuovi commenti' + closed_comments_desc: 'Scrivi un messaggio da visualizzare quando il tuo thread dei commenti viene chiuso senza accettarne nuovi.' + closed_comments_label: 'Scrivi un messaggio...' + closed_stream_settings: 'Thread dei messaggi chiusi' + comment_count_error: 'Inserisci un numero valido.' + comment_count_header: 'Limite lunghezza commento' + comment_count_text_post: caratteri + comment_count_text_pre: 'I commenti saranno limitati a' + comment_settings: Impostazioni + comment_stream: 'Thread dei commenti' + comment_stream_will_close: 'Il thread dei commenti sarà chiuso' + community: Comunità + configure: Configura + copy_and_paste: 'Copia e incolla il codice qui sotto nel tuo CMS per includere il box dei commenti nei tuoi articoli' + custom_css_url: 'URL per il CSS personalizzato' + custom_css_url_desc: 'URL del CSS che sostituirà lo stile predefinito del thread dei commenti. Può essere interno o esterno.' + days: Giorni + description: 'Modifica le impostazioni dei commenti in questa storia.' + disable_commenting_desc: 'Scrivi il messaggio che sarà visualizzato quando i commenti saranno disattivati.' + disable_commenting_title: 'Disattiva tutti i commenti del sito' + domain_list_text: 'Inserisci i domini che vuoi autorizzare per Talk. Per esempio i tuoi ambienti di sviluppo, test o produzione (ex. localhost:3000 staging.domain.com domain.com).' + domain_list_title: 'Domain permessi' + edit_comment_timeframe_heading: 'Periodo di tempo disponibile per modificare i commenti' + edit_comment_timeframe_text_post: 'secondi per modificare i commenti.' + edit_comment_timeframe_text_pre: 'Gli utenti avranno' + edit_info: 'Modifica informazioni' + embed_comment_stream: 'Integra il thread dei commenti' + enable_pre_moderation: 'Abilita pre-moderazione' + enable_pre_moderation_text: 'I moderatori dovranno approvare tutti i commenti prima che vengano pubblicati.' + enable_premod: 'Abilita pre-moderazione' + enable_premod_description: 'I moderatori dovranno approvare tutti i commenti prima che vengano pubblicati.' + enable_premod_links: 'Pre-Modera commenti contenenti link' + enable_premod_links_description: 'I moderatori devono approvare tutti i commenti contenenti link prima di essere pubblicati.' + enable_premod_links_text: 'I moderatori devono approvare tutti i commenti contenenti link prima di essere pubblicati.' + enable_questionbox: 'Domanda qualcosa ai lettori' + enable_questionbox_description: 'Questa domanda apparirà sopra al thread dei commenti. Chiedi ai lettori cosa ne pensano dell''articolo o poni domande per iniziare una conversazione etc.' + hours: Ore + include_comment_stream: 'Includi la descrizione del thread dei commenti' + include_comment_stream_desc: 'Scrivi un messaggio che sarà aggiunto sopra il thread dei commenti. Poni una domanda, includi le linee guida della comunità etc.' + include_question_here: 'Scrivi la tua domanda di seguito:' + include_text: 'Includi il testo qui.' + moderate: Modera + moderation_settings: 'Impostazioni di moderazione' + open: Apri + open_stream: 'Apri il thread' + open_stream_configuration: 'Questo thread dei commenti è attualmente aperto. Chiudendolo non saranno più accettati nuovi commenti, mentre tutti i commenti precedenti continueranno ad essere visibili.' + organization_contact_email: 'Indirizzo email dell''organizzazione' + organization_info_copy: 'Utilizziamo queste informazioni nelle email di notifica generate da Talk. Questo connette i messaggi alla tua organizzazione, permettendo agli utenti di contattarti se riscontrano problemi con il loro account.' + organization_info_copy_2: 'Raccomandiamo di creare un indirizzo email generico (eg. community@yournewsroom.com) per questo scopo. Così da poter rimanere consistente nel tempo, senza rivelare il proprio nome che gli utenti potrebbero prendere di mira nel caso il loro account venga bloccato.' + organization_information: 'Informazioni dell''organizzazione' + organization_name: 'Nome dell''organizzazione' + suspect_or_forbidden_words_placeholder: 'Parola o frase' + product_guide_link: 'Guida all''uso del prodotto' + report_bug_or_feedback: 'Segnala un bug o lascia un feedback' + require_email_verification: 'Richiede la verifica dell''email' + require_email_verification_text: 'I nuovi utenti devono verificare la loro email prima di poter commentare' + save: Salva + save_changes: 'Salva le modifiche' + save_changes_dialog: + cancel: Annulla + copy: 'Hai apportato una o più modifiche senza salvare. Vuoi salvare o scartare le modifiche?' + discard: Scarta + save_settings: 'Salva impostazioni' + unsaved_changes: 'Modifiche non salvate' + shortcuts: Scorciatoie + sign_out: Esci + stories: Storie + stream_settings: 'Impostazioni thread dei commenti' + suspect_word_text: 'Commenti che contengono queste parole o frasi, che siano in maiuscolo o minuscolo, saranno evidenziate nel thread dei commenti. Inserisci una parola e premi Invio o Tab per aggiungerla. Oppure aggiungi una lista di parole separate da virgole.' + suspect_word_title: 'Lista delle parole indiziate' + tech_settings: 'Impostazioni tecniche' + title: 'Configura il thread dei commenti' + view_last_version: 'Visualizza ultima versione' + weeks: Settimane + wordlist: 'Parole vietate' + confirm_email: + click_to_confirm: 'Premi qui sotto per confermare il tuo indirizzo email.' + confirm: Conferma + email_confirmation: 'Conferma Email' + continue: Continua + createdisplay: + check_the_form: 'Modulo non valido. Ricontrolla i campi' + continue: 'Continua con lo stesso username di Facebook' + error_create: 'Errore nel cambiamento dell''username' + fake_comment_body: 'Questo è un commento esempio. I lettori possono condividere i loro pensieri e opinioni con le redazioni nella sezione dei commenti.' + fake_comment_date: '1 minuto fa' + if_you_dont_change_your_name: 'Se non modifichi il tuo username in questo momento, il tuo nome Facebook comparirà accanto a tutti i tuoi commenti.' + required_field: 'Campo obbligatorio' + save: Salva + special_characters: 'Gli username possono contenere solo lettere numeri e _' + username: Username + write_your_username: 'Modifica il tuo username' + your_username: 'Il tuo username appare in tutti i commenti che pubblichi.' + done: Finito + edit_comment: + body_input_label: 'Modifica questo commento' + edit_window_expired: 'Non puoi più modificare questo commento. Il periodo di tempo disponibile per modificarlo è terminato. Perchè non ne pubblichi uno nuovo?' + edit_window_expired_close: Chiudi + edit_window_timer_prefix: 'Modifica periodo di tempo: ' + minute: minuto + minutes_plural: minuti + save_button: 'Salva modifiche' + second: secondo + seconds_plural: secondi + email: + banned: + body: 'In conformità con le linee guida della comunità The Coral Project, il tuo account è stato bloccato. Non ti è più permesso commentare, segnalare o interagire con la nostra comunità.' + subject: 'Il tuo account è stato bloccato' + confirm: + confirm_email: 'Conferma Email' + has_been_requested: 'Una email di conferma è stata richiesta per i seguenti account:' + if_you_did_not: 'Se non sei stato tu a richiederla puoi tranquillamente ignorare questa email.' + subject: 'Email di conferma' + to_confirm: 'Per confermare l''account visita il seguente link:' + password_change: + body: "La password del tuo account è stata modificata.\n\nSe non sei stato tu a richiedere questa modifica, contattaci a {0}." + subject: '{0} password modificata' + password_reset: + if_you_did: 'Se sei stato tu,' + please_click: 'premi qui per reimpostare la password' + subject: 'Reimposta Password' + we_received_a_request: 'Abbiamo ricevuto una richiesta di reimpostare la password. Se non sei stato tu a richiedere la modifica puoi ignorare questa email.' + suspended: + subject: 'Il tuo account è stato sospeso' + embed_comments_tab: Commenti + embedlink: + copy: 'Copiato negli appunti' + copied: 'Copiato' + error: + ALREADY_EXISTS: 'Risorsa già esistente' + AUTHENTICATION: 'Si è verificato un errore durante il tentativo di autenticazione del tuo account.' + CANNOT_IGNORE_STAFF: 'Non puoi ignorare membri dello stuff.' + COMMENT_PARENT_NOT_VISIBLE: 'Il commento al quale stai rispondendo è stato rimosso o non esiste.' + COMMENT_TOO_SHORT: 'I commenti devono avere più di un carattere, ricontrolla il tuo commento e riprova.' + COMMENT_TOO_LONG: 'Il testo eccede il limite permesso.' + COMMENTING_CLOSED: 'I commenti sono stati chiusi.' + COMMENTING_DISABLED: 'Attualmente non è possibile commentare in questo sito.' + confirm_password: 'Le password non coincidono. Perfavore riprova.' + DELETION_NOT_SCHEDULED: 'L''eliminazione non è stata pianificata.' + EDIT_USERNAME_NOT_AUTHORIZED: 'Non hai l''autorizzazione per modificare il tuo username.' + EDIT_WINDOW_ENDED: 'Non puoi più modificare questo commento. Il periodo di tempo disponibile per farlo è terminato.' + email: 'Inserisci un indirizzo email valido.' + EMAIL_ALREADY_VERIFIED: 'Indirizzo email già verificato.' + EMAIL_IN_USE: 'Indirizzo email già in uso.' + email_not_verified: 'L''indirizzo email {0} non è verificato.' + EMAIL_NOT_VERIFIED: 'Indirizzo email non verificato.' + email_password: 'Email e/o password errate/a.' + EMAIL_REQUIRED: 'È richiesto un indirizzo email' + EMAIL_VERIFICATION_TOKEN_INVALID: 'Il token di verifica dell''e-mail non è valido.' + INCORRECT_PASSWORD: 'Password errata' + INVALID_ASSET_URL: 'URL non valido' + LOGIN_MAXIMUM_EXCEEDED: 'Hai effettuato troppi tentativi falliti. Si prega di attendere.' + network_error: 'Errore durante la connessione con il server. Controlla la tua connessione internet e riprova.' + NO_SPECIAL_CHARACTERS: 'L''username può contenere solo lettere numeri o _' + NOT_AUTHORIZED: 'Non sei autorizzato a compiere questa azione.' + NOT_FOUND: 'Risorsa non trovata' + organization_contact_email: 'L''email dell''organizzazione è invalida.' + organization_name: 'Il nome dell''organizzazione può contenere solo lettere o numeri.' + password: 'La password deve avere almeno 8 caratteri' + PAGE_NOT_AVAILABLE_ROLE: 'Questa pagina può essere utilizzata solo dal team. Contatta l''amministratore se vuoi entrare a far parte di questo team.' + PASSWORD_INCORRECT: 'La password inserita non è corretta' + PASSWORD_LENGTH: 'La password è troppo corta' + PASSWORD_REQUIRED: 'Inserire una password' + PASSWORD_RESET_TOKEN_INVALID: 'Il link per reimpostare la tua password non è valido.' + PROFANITY_ERROR: 'Gli username non devono contenere volgarità. Contatta l''amministratore se ritieni ci sia stato un errore.' + RATE_LIMIT_EXCEEDED: 'Limite di tentativi superato' + required_field: 'Questo campo è obbligatorio' + SAME_USERNAME_PROVIDED: 'Devi inserire un username diverso.' + temporarily_suspended: 'Il tuo account è attualmente sospeso. Sarà riattivato {0}. Contattaci se hai qualche domanda.' + unexpected: 'Si è verificato un errore imprevisto. Ci scusiamo!' + username: 'L''username può contenere solo lettere numeri o _' + USERNAME_IN_USE: 'Username già in uso' + USERNAME_REQUIRED: 'Inserire un username' + flag_comment: 'Segnala commento' + flag_reason: 'Motivi segnalazione (Opzionale)' + flag_reasons: + username: + impersonating: 'Questo utente sta impersonando' + nolike: 'Non mi piace il suo username' + offensive: 'Username offensivo' + other: Altro + spam: 'Sembra si tratti di pubblicità/marketing' + flag_username: 'Segnala username' + flagged_usernames: + notify_approved: '{0} username approvato {1}' + notify_changed: 'utente {0} ha cambiato il suo username in {1}' + notify_flagged: '{0} ha segnalato l''username {1}' + notify_rejected: '{0} ha rifiutato l''username {1}' + flags: + reasons: + comment: + banned_word: 'Parola vietata' + comment_noagree: Disaccordo + comment_offensive: Offensivo + comment_other: Altro + comment_spam: Spam + links: Link + suspect_word: 'Parola sospetta' + trust: Karma + user: + username_impersonating: Impersonificazione + username_nolike: 'Non mi piace' + username_offensive: Offensivo + username_other: Altro + username_spam: Spam + framework: + banned_account_body: 'Significa che non potrai votare, segnalare o scrivere commenti.' + banned_account_header: 'Il tuo account è attualmente bloccato.' + changed_name: + msg: 'Il tuo nuovo username è sotto esame da parte del nostro team di moderatori.' + comment: commento + comment_is_deleted: 'Questo utente ha eliminato il suo account.' + comment_is_hidden: 'Questo commento non è disponibile.' + comment_is_ignored: 'Questo commento è nascosto perchè hai ignorato questo utente.' + comment_is_rejected: 'Hai rifiutato questo commento.' + comments: commenti + configure_stream: Configura + content_not_available: 'Questo contenuto non è disponibile' + edit_name: + button: Invia + error: 'L''username può contenere solo lettere numeri o _' + label: 'Nuovo username' + msg: 'Il tuo account è attualmente sospeso perchè il tuo username è considerato inappropriato. Per ripristinare il tuo account inserisci un nuovo username. Contattaci se hai qualche domanda.' + my_comments: 'I miei commenti' + my_profile: 'Il mio profilo' + new_count: 'Visualizza {0} e {1}' + profile: Profilo + show_all_comments: 'Visualizza tutti i commenti' + show_all_replies: 'Visualizza tutte le risposte' + show_more_replies: 'Visualizza più risposte' + success_bio_update: 'La tua descrizione è stata aggiornata' + success_name_update: 'Il tuo username è stato aggiornato' + success_update_settings: 'Le modifiche apportate sono state applicate al thread dei commenti in questo articolo' + view_more_comments: 'visualizza più commenti' + view_reply: 'visualizza risposta' + from_settings_page: 'Dalla pagina del profilo puoi vedere la tua cronologia dei commenti.' + install: + add_organization: + description: 'Inserisci il nome della tua organizzazione. Questa apparirà nelle email di invito ai nuovi membri.' + label: 'Nome dell''organizzazione' + save: Salva + create: + confirm_password: 'Conferma password' + email: 'Indirizzo email' + organization_contact_email: 'Indirizzo email dell''organizzazione' + password: Password + save: Salva + username: Username + final: + close: 'Chiudi l''installer' + description: 'Grazie per aver installato Talk! Ti abbiamo inviato una email per verificare il tuo indirizzo email. Mentre termini la configurazione del tuo account, puoi iniziare a interagire con i tuoi lettori.' + launch: 'Avvia Talk' + initial: + description: 'Configura la tua comunità Talk in pochi passi.' + submit: Inizia + permitted_domains: + description: 'Inserisci i domini che vuoi autorizzare per Talk. Per esempio i tuoi ambienti di sviluppo, test o produzione (ex. localhost:3000 staging.domain.com domain.com).' + submit: 'Termina installazione' + title: 'Domini autorizzati' + like: 'Mi piace' + loading_results: 'Caricamento risultati' + login: + email_address: 'Indirizzo email' + forgot_password: 'Hai dimenticato la tua password?' + go_back: Indietro + sign_in: Accedi + sign_in_button: Accedi + sign_in_message: 'Accedi per interagire con la comunità.' + password: Password + reset_password_send_button: 'Reimposta Password' + request_passowrd: 'Richiedi una nuova password.' + team_sign_in: 'Accesso Team' + marketing: 'Sembra si tratti di pubblicità/marketing' + moderate_all_streams: 'Modera i commenti in Tutte le storie' + moderate_this_stream: 'Modera questo thread dei commenti' + modqueue: + account: 'segnalazioni dell''account' + actions: Azioni + all: tutto + all_streams: 'Tutti i thread di commenti' + approve: Approva + approved: Approvato + ban_user: Bloccato + ban_user_actions: 'Blocca utente' + billion: M + close: Chiudi + empty_queue: 'Non ci sono più commenti da moderare.' + flagged: contrassegnato + jump_to_queue: 'Vai a una determinata coda' + less_detail: 'Meno dettagli' + likes: 'mi piace' + million: m + mod_faster: 'Modera più velocemente con le scorciatoie da tastiera' + moderate: 'Modera →' + more_detail: 'Più dettagli' + navigation: Navigazione + new: Nuovo + newest_first: 'Nuovo primo' + next_comment: 'Vai al prossimo commento' + next_queue: 'Cambia coda' + notify_accepted: '{0} ha accettato il commento "{1}"' + notify_edited: '{0} ha modificato il commento "{1}"' + notify_flagged: '{0} ha contrassegnato il commento "{1}"' + notify_rejected: '{0} ha rifiutato il commento "{1}"' + notify_reset: '{0} ha ripristinato lo stato del commento "{1}"' + oldest_first: 'Primo più vecchio' + premod: pre-moderazione + prev_comment: 'Vai al commento precedente' + reject: Rifiuta + rejected: Rifiutato + reply: Rispondi + reported: Segnalato + select_stream: 'Seleziona thread dei commenti' + shift_key: ⇧ + shortcuts: Scorciatoie + show_shortcuts: 'Visualizza scorciatoie' + singleview: 'Modalità zen' + sort: Ordina + suspend: 'Sospendi utente' + system_withheld: 'Sistema bloccato' + thismenu: 'Apri questo menu' + thousand: k + toggle_search: 'Apri ricerca' + try_these: 'Prova queste' + view_more_shortcuts: 'Visualizza più scorciatoie' + my_comment_history: 'La mia cronologia di commenti' + name: Nome + no_agree_comment: 'Non concordo con questo commento' + no_like_bio: 'Non apprezzo questa descrizione' + no_like_username: 'Non apprezzo questo username' + other: Altro + password_reset: + change_password: 'Cambia password' + change_password_help: 'Inserisci una nuova password per accedere' + confirm_new_password: 'Conferma la nuova password' + mail_sent: 'Se hai già un account ti è stata inviata una email con un link per reimpostare la password' + new_password: 'Nuova password' + new_password_help: 'La password deve avere almeno 8 caratteri' + set_new_password: 'Cambia la tua password' + permalink: Condividi + personal_info: 'Questo commento contiene dati personali' + post: Pubblica + profile: Profilo + profile_settings: Impostazioni + reject_username: + description_notify: 'La sospensione di questo utente disabiliterà temporaneamente il loro account.' + description_reject: 'Sei sicuro di volere bloccare temporaneamente questo utente perchè {0}? Accettando sospenderai temporaneamente questo utente finché non riscriveranno il loro {0}.' + email_message_reject: 'Un''altro membro della comunità ha recentemente segnalato il tuo username consigliando una revisione. A causa del suo contenuto, il tuo username è stato rifiutato. Significa che non potrai più commentare, apprezzare o segnalare contenuti fino a quando non modificherai il tuo username. Inviaci una email per qualsiasi domanda o dubbio.' + no_cancel: 'Non annullare' + send: Invia + suspend_user: 'Sospendi utente' + title_notify: 'Avvisa l''utente della sua temporanea sospensione' + title_reject: 'Abbiamo notato che hai rifiutato un nome utente' + username: username + write_message: 'Scrivi un messaggio' + yes_suspend: 'Si, sospendi' + reject_username_dialog: + cancel: Annulla + description: 'Aiutaci a capire' + message: 'Motivi per la segnalazione (Opzionale)' + reason: Ragione + reject_username: 'Rifiuta username' + title: 'Rifiuta username' + reply: Rispondi + report: Segnala + report_notif: 'Grazie per aver segnalato questo commento. Il nostro team di moderatori è stato avvisato e lo revisionerà presto.' + report_notif_remove: 'La tua segnalazione è stata rimossa.' + reported: Segnalato + settings: + from_settings_page: 'Dalla pagina del profilo puoi vedere la tua cronologia dei commenti.' + my_comment_history: 'La mia cronologia dei commenti' + profile: Profilo + profile_settings: 'Impostazioni profilo' + sign_in: Accedi + to_access: 'per accedere al profilo' + user_no_comment: 'Non hai ancora pubblicato un commento. Partecipa alla conversazione!' + step_1_header: 'Segnala un problema' + step_2_header: 'Aiutaci a capire' + step_3_header: 'Grazie per la tua partecipazione' + stream: + all_comments: 'Tutti i commenti' + comment_not_found: 'Questo commento è stato rimosso o non esiste.' + no_comments: 'Non ci sono ancora commenti. Perchè non ne pubblichi uno?' + no_comments_and_closed: 'Non c''era alcun commento in questo articolo.' + temporarily_suspended: 'In conformità con le linee guida della comunità {0}, il tuo account è stato temporaneamente sospeso. Torna a partecipare alla conversazione {1}.' + streams: + all: Tutti + article: Storia + closed: Chiuso + empty_result: 'Questa ricerca non ha ottenuto risultati. Prova ad amplicare la tua ricerca.' + filter_streams: 'Filtra i thread dei commenti' + most_recent_stories: 'Storie più recenti' + newest: Nuovi + no_results: 'Nessun risultato' + oldest: Vecchi + open: Apri + pubdate: 'Data di pubblicazione' + search: Cerca + search_results: 'Risultati della ricerca' + sort_by: 'Ordina per' + status: 'Status del thread dei commenti' + stream_status: 'Status del thread dei commenti' + suspenduser: + cancel: Annulla + day: '{0} giorno' + days: '{0} giorni' + description_notify: 'La sospensione di questo utente disabiliterà temporaneamente il loro account.' + description_suspend: 'Stai sospendendo {0}. Questo commento sarà inserito tra quelli rifiutati, e {0} non potrà apprezzare, segnalare, rispondere o pubblicare fino al termine del periodo di sospensione.' + email_message_suspend: "Caro {0},\n\nIn conformità con le linee guida della comunità, il tuo account è stato temporaneamente sospenso. Durante il periodo di sospension non potrai commentare, segnalare o interagire con la comunità. Puoi tornare a partecipare dal {2}." + hour: '{0} ora' + hours: '{0} ore' + notify_suspend_until: 'L''utente {0} è stato temporaneamente sospeso. Questa sospensione finirà automaticamente {1}.' + one_hour: '1 ora' + select_duration: 'Seleziona la durata della sospensione' + send: Invia + suspend_user: 'Sospendi utente' + title_notify: 'Avvisa l''utente della sua temporanea sospensione' + title_suspend: 'Sospendi utente' + write_message: 'Scrivi un messaggio' + thank_you: 'Apprezziamo il tuo feedback. Un moderatore revisionerà la tua segnalazione.' + user: + bio_flags: 'segnalazioni per questa descrizione' + user_bio: 'Descrizione utente' + username_flags: 'segnalazioni per questo utente' + user_detail: + all: Tutti + ban: 'Blocca utente' + banned: Bloccato + email: Email + id: ID + karma: Karma + karma_docs_link: 'https://docs.coralproject.net/talk/trust/#user-karma-score' + learn_more: 'Maggiori informazioni' + member_since: 'Membro dal' + reject_rate: 'Tasso di rifiuto' + reject_username: 'Username rifiutato' + rejected: Rifiutato + remove_ban: 'Ban rimosso' + remove_suspension: 'Sospensione rimossa' + suspend: 'Utente sospeso' + suspended: Sospeso + total_comments: 'Commenti totali' + unreliable: Inaffidabile + user_history: 'Cronologia utente' + user_karma_score: 'Punteggio Karma dell''utente' + username: Username + username_needs_approval: 'L''username necessita di approvazione' + username_rejected: 'Username rifiutato' + user_history: + action: Azione + ban_removed: 'Ban rimosso' + date: Data + suspended: 'Sospeso, {0}' + suspension_removed: 'Sospensione rimossa' + system: Sistema + taken_by: 'Preso da' + user_banned: 'Utente bloccato' + username_status: 'Username {0}' + user_impersonating: 'Questo utente sta impersonando' + user_no_comment: 'Non hai ancora pubblicato un commento. Partecipa alla discussione!' + username_offensive: 'Questo username è offensivo' + validators: + confirm_email: 'Le email non coincidono. Perfavore riprova.' + confirm_password: 'Le password non coincidono. Perfavore riprova.' + required: 'Questo campo è obbligatorio' + verify_email: 'Inserisci un email valida.' + verify_organization_name: 'Il nome dell''organizzazione può contenere solo lettere o numeri.' + verify_password: 'La password deve contenere almeno 8 caratteri' + verify_username: 'Gli username possono contenere solo lettere numeri e _' + view_conversation: 'Visualizza conversazione' + your_account_has_been_banned: 'Il tuo account è stato bloccato.' + your_account_has_been_suspended: 'Il tuo account è stato temporaneamente sospeso.' + your_username_has_been_rejected: 'Il tuo account è stato sospeso perchè il tuo username è ritenuto inappropriato. Per ripristinare il tuo account inserisci un nuovo username.' diff --git a/locales/nl_NL.yml b/locales/nl_NL.yml index be1904b78..007d07cd7 100644 --- a/locales/nl_NL.yml +++ b/locales/nl_NL.yml @@ -123,8 +123,8 @@ nl_NL: enable_questionbox: 'Stel een vraag aan de lezers' enable_questionbox_description: 'Deze vraag zal bovenaan de conversatie verschijnen. Vraag lezers naar een probleem in het artikel, poneer discussie vragen, enzovoort.' hours: Uren - include_comment_stream: 'Neem conversatie beschrijving op voor lezers.' - include_comment_stream_desc: 'Schrijf een bericht voor boven je conversatie. Poneer een stelling, wijs op de community richtlijnen, etc.' + code_of_conduct_summary: 'Neem conversatie beschrijving op voor lezers.' + code_of_conduct_summary_desc: 'Schrijf een bericht voor boven je conversatie. Poneer een stelling, wijs op de community richtlijnen, etc.' include_question_here: 'Schrijf je vraag hier:' include_text: 'Schrijf hier je tekst.' moderate: Modereer diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml index 66273f137..2f11f8344 100644 --- a/locales/pt_BR.yml +++ b/locales/pt_BR.yml @@ -130,8 +130,8 @@ pt_BR: enable_questionbox: 'Faça uma pergunta aos leitores' enable_questionbox_description: 'Esta pergunta aparecerá no topo da lista de comentários. Pergunte aos leitores sobre um determinado problema no artigo, abra o assunto para discussão, etc.' hours: Horas - include_comment_stream: 'Incluir descrição da lista comentários para leitores' - include_comment_stream_desc: 'Escreva uma mensagem para adicionar ao topo do seu hilo de comentários. Posicionar um tópico, incluem diretrizes comunitárias, etc.' + code_of_conduct_summary: 'Incluir descrição da lista comentários para leitores' + code_of_conduct_summary_desc: 'Escreva uma mensagem para adicionar ao topo do seu hilo de comentários. Posicionar um tópico, incluem diretrizes comunitárias, etc.' include_question_here: 'Escreva sua pergunta aqui:' include_text: 'Inclua seu texto aqui:' moderate: Moderar @@ -209,7 +209,7 @@ pt_BR: to_confirm: 'Para confirmar a conta, visite este link: ' password_change: body: "A sua senha foi alterada.\n\nSe você não solicitou essa alteracão, por favor nos contate em {0}" - subject: '{0} password change' + subject: '{0} password change' password_reset: if_you_did: 'Se você solicitou isso, ' please_click: 'clique aqui para redefinir sua senha.' @@ -223,7 +223,7 @@ pt_BR: copied: 'Copiado' error: ALREADY_EXISTS: 'O recurso já existe' - AUTHENTICATION: ‘Ocorreu um erro durante a autenticação da sua conta’ + AUTHENTICATION: ‘Ocorreu um erro durante a autenticação da sua conta’ CANNOT_IGNORE_STAFF: 'Não é possível ignorar membros Staff.' COMMENT_PARENT_NOT_VISIBLE: 'O comentário que você está respondendo foi removido ou não existe.' COMMENT_TOO_SHORT: 'Seu comentário precisar ter mais de um caracter. Revise seu comentário e envie novamente' diff --git a/locales/zh_CN.yml b/locales/zh_CN.yml index c3a1b2249..aa983688a 100644 --- a/locales/zh_CN.yml +++ b/locales/zh_CN.yml @@ -114,8 +114,8 @@ zh_CN: enable_questionbox: 向读者提问 enable_questionbox_description: 该问题将在评论流顶部出现。可以就文章中特定内容发问,也可以设置一个讨论问题,等等。 hours: 小时 - include_comment_stream: 开启评论流描述 - include_comment_stream_desc: 填写将在评论流顶部出现的描述。可以写评论主题、社群指引方针,等等。 + code_of_conduct_summary: 开启评论流描述 + code_of_conduct_summary_desc: 填写将在评论流顶部出现的描述。可以写评论主题、社群指引方针,等等。 include_question_here: 此处输入问题: include_text: 此处输入文本。 moderate: 审查 diff --git a/locales/zh_TW.yml b/locales/zh_TW.yml index caa01ec62..208cfddc8 100644 --- a/locales/zh_TW.yml +++ b/locales/zh_TW.yml @@ -113,8 +113,8 @@ zh_TW: enable_questionbox: 向讀者提問 enable_questionbox_description: 該問題將會在評論流置頂。您可以詢問其他讀者有關文章中的具體時間或是提出討論等 hours: 小時 - include_comment_stream: 包含讀者的評論流描述 - include_comment_stream_desc: 留言將在您的評論流中置頂。發布一個社區規則等 + code_of_conduct_summary: 包含讀者的評論流描述 + code_of_conduct_summary_desc: 留言將在您的評論流中置頂。發布一個社區規則等 include_question_here: 請在此處輸入問題: include_text: 在此插入您的文本 moderate: 審核 diff --git a/plugins/talk-plugin-auth/client/translations.yml b/plugins/talk-plugin-auth/client/translations.yml index caae962bb..4ff4fb994 100644 --- a/plugins/talk-plugin-auth/client/translations.yml +++ b/plugins/talk-plugin-auth/client/translations.yml @@ -219,7 +219,7 @@ es: register: "Registrar" sign_up: "Registro" confirm_password: "Confirmar Contraseña" - username: "Nombre" + username: "Nombre de Usuario" already_have_an_account: "¿Ya tienes una cuenta?" recover_password: "Recuperar la contraseña" email_in_use: "Este correo se encuentra en uso" diff --git a/plugins/talk-plugin-toxic-comments/server/perspective.js b/plugins/talk-plugin-toxic-comments/server/perspective.js index 424543b2b..7966d3b36 100644 --- a/plugins/talk-plugin-toxic-comments/server/perspective.js +++ b/plugins/talk-plugin-toxic-comments/server/perspective.js @@ -10,7 +10,8 @@ const debug = require('debug')('talk:plugin:toxic-comments'); /** * Get scores from the perspective api - * @param {string} text text to be anaylized + * + * @param {string} text text to be analyzed * @return {object} object containing toxicity scores */ async function getScores(text) { @@ -43,13 +44,13 @@ async function getScores(text) { // If we get an error, just say it's not a toxic comment. if (data.error) { - debug('Recieved Error when submitting: %o', data.error); + debug('Received Error when submitting: %o', data.error); return { TOXICITY: { - summaryScore: 0.0, + summaryScore: null, }, SEVERE_TOXICITY: { - summaryScore: 0.0, + summaryScore: null, }, }; } @@ -66,6 +67,7 @@ async function getScores(text) { /** * Get toxicity probability + * * @param {object} scores scores as returned by `getScores` * @return {number} toxicity probability from 0 - 1.0 */ @@ -74,7 +76,9 @@ function getProbability(scores) { } /** - * isToxic determines if given probabilty or scores meets the toxicity threshold. + * isToxic determines if given probability or scores meets the toxicity + * threshold. + * * @param {object|number} scoresOrProbability scores or probability * @return {boolean} */ @@ -89,6 +93,7 @@ function isToxic(scoresOrProbability) { /** * maskKeyInError is a decorator that calls fn and masks the * API_KEY in errors before throwing. + * * @param {function} fn Function that returns a Promise * @return {function} decorated function */ diff --git a/services/moderation/phases/links.js b/services/moderation/phases/links.js index ec05834b6..c31cf0c13 100644 --- a/services/moderation/phases/links.js +++ b/services/moderation/phases/links.js @@ -11,7 +11,7 @@ module.exports = ( }, } ) => { - if (premodLinksEnable && linkify.test(comment.body)) { + if (premodLinksEnable && linkify.test(comment.body.replace(/\xAD/g, ''))) { // Add the flag related to Trust to the comment. return { status: 'SYSTEM_WITHHELD', diff --git a/services/scraper.js b/services/scraper.js deleted file mode 100644 index cfd845424..000000000 --- a/services/scraper.js +++ /dev/null @@ -1,33 +0,0 @@ -const kue = require('./kue'); - -/** - * Exposes a service object to allow operations to execute against the scraper. - * @type {Object} - */ -const scraper = { - /** - * Create the new Task kue singleton. - */ - task: new kue.Task({ - name: 'scraper', - }), - - /** - * Creates a new scraper job and scrapes the url when it gets processed. - */ - async create(ctx, id) { - ctx.log.info({ assetID: id }, 'Creating job'); - - const job = await scraper.task.create({ - title: `Scrape for asset ${id}`, - id: ctx.id, - asset_id: id, - }); - - ctx.log.info({ jobID: job.id, assetID: id }, 'Created job'); - - return job; - }, -}; - -module.exports = scraper; diff --git a/services/scraper/index.js b/services/scraper/index.js new file mode 100644 index 000000000..59faa8bf0 --- /dev/null +++ b/services/scraper/index.js @@ -0,0 +1,96 @@ +const fetch = require('node-fetch'); +const ProxyAgent = require('proxy-agent'); +const { merge } = require('lodash'); + +const { SCRAPER_HEADERS, SCRAPER_PROXY_URL } = require('../../config'); +const kue = require('../kue'); +const { version } = require('../../package.json'); + +// Load the scraper with the rules. +const metascraper = require('metascraper').load([ + require('metascraper-title')(), + require('metascraper-description')(), + require('metascraper-image')(), + require('metascraper-author')(), + require('metascraper-date')(), + require('./rules/modified')(), + require('./rules/section')(), +]); + +let customHeaders = {}; +try { + customHeaders = JSON.parse(SCRAPER_HEADERS); +} catch (err) { + console.error('Cannot parse TALK_SCRAPER_HEADERS'); + throw err; +} + +// Parse the headers to be added to the scraper. +const headers = merge( + { + 'User-Agent': `Coral-Talk/${version}`, + }, + customHeaders +); + +// Add proxy configuration if exists. +const agent = SCRAPER_PROXY_URL ? new ProxyAgent(SCRAPER_PROXY_URL) : null; + +/** + * Exposes a service object to allow operations to execute against the scraper. + * @type {Object} + */ +const scraper = { + /** + * Create the new Task kue singleton. + */ + task: new kue.Task({ + name: 'scraper', + }), + + /** + * Creates a new scraper job and scrapes the url when it gets processed. + */ + async create(ctx, id) { + ctx.log.info({ assetID: id }, 'Creating job'); + + const job = await scraper.task.create({ + title: `Scrape for asset ${id}`, + id: ctx.id, + asset_id: id, + }); + + ctx.log.info({ jobID: job.id, assetID: id }, 'Created job'); + + return job; + }, + + /** + * Scrapes the given asset for metadata. + */ + async scrape(url) { + const res = await fetch(url, { + headers, + agent, + }); + const html = await res.text(); + + // Get the metadata from the scraped html. + const meta = await metascraper({ + html, + url, + }); + + return { + title: meta.title || '', + description: meta.description || '', + image: meta.image ? meta.image : '', + author: meta.author || '', + publication_date: meta.date || '', + modified_date: meta.modified || '', + section: meta.section || '', + }; + }, +}; + +module.exports = scraper; diff --git a/jobs/scraper/rules/modified.js b/services/scraper/rules/modified.js similarity index 100% rename from jobs/scraper/rules/modified.js rename to services/scraper/rules/modified.js diff --git a/jobs/scraper/rules/section.js b/services/scraper/rules/section.js similarity index 100% rename from jobs/scraper/rules/section.js rename to services/scraper/rules/section.js diff --git a/views/account/password/reset.njk b/views/account/password/reset.njk index 6eee12dd0..bede0b9fc 100644 --- a/views/account/password/reset.njk +++ b/views/account/password/reset.njk @@ -8,7 +8,7 @@

{{ t('password_reset.set_new_password') }}

{{ t('password_reset.change_password_help') }}

-
+