зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1525452 - Add Message component, visibility capping and bug fixes to Activity Stream r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D18841 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d7fea3b29b
Коммит
8846c7f2ae
|
@ -47,6 +47,7 @@ function AboutNewTabService() {
|
|||
// More initialization happens here
|
||||
this.toggleActivityStream(true);
|
||||
this.initialized = true;
|
||||
this.alreadyRecordedTopsitesPainted = false;
|
||||
|
||||
if (IS_MAIN_PROCESS) {
|
||||
AboutNewTab.init();
|
||||
|
@ -331,6 +332,20 @@ AboutNewTabService.prototype = {
|
|||
this.notifyChange();
|
||||
},
|
||||
|
||||
maybeRecordTopsitesPainted(timestamp) {
|
||||
if (this.alreadyRecordedTopsitesPainted) {
|
||||
return;
|
||||
}
|
||||
|
||||
const SCALAR_KEY = "timestamps.about_home_topsites_first_paint";
|
||||
|
||||
let startupInfo = Services.startup.getStartupInfo();
|
||||
let processStartTs = startupInfo.process.getTime();
|
||||
let delta = Math.round(timestamp - processStartTs);
|
||||
Services.telemetry.scalarSet(SCALAR_KEY, delta);
|
||||
this.alreadyRecordedTopsitesPainted = true;
|
||||
},
|
||||
|
||||
uninit() {
|
||||
if (!this.initialized) {
|
||||
return;
|
||||
|
|
|
@ -45,8 +45,10 @@ for (const type of [
|
|||
"DISCOVERY_STREAM_FEEDS_UPDATE",
|
||||
"DISCOVERY_STREAM_LAYOUT_RESET",
|
||||
"DISCOVERY_STREAM_LAYOUT_UPDATE",
|
||||
"DISCOVERY_STREAM_OPT_OUT",
|
||||
"DISCOVERY_STREAM_SPOCS_ENDPOINT",
|
||||
"DISCOVERY_STREAM_SPOCS_UPDATE",
|
||||
"DISCOVERY_STREAM_SPOC_IMPRESSION",
|
||||
"DOWNLOAD_CHANGED",
|
||||
"FAKE_FOCUS_SEARCH",
|
||||
"FILL_SEARCH_TERM",
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
/* globals Services */
|
||||
"use strict";
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (typeof ChromeUtils !== "undefined") {
|
||||
// Use a var here instead of let outside to avoid creating a locally scoped
|
||||
// variable that hides the global, which we modify for testing.
|
||||
// eslint-disable-next-line no-var, vars-on-top
|
||||
var {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
}
|
||||
|
||||
let usablePerfObj;
|
||||
|
||||
/* istanbul ignore if */
|
||||
/* istanbul ignore else */
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
if (typeof Services !== "undefined") {
|
||||
// Borrow the high-resolution timer from the hidden window....
|
||||
// eslint-disable-next-line block-scoped-var
|
||||
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
|
||||
} else if (typeof performance !== "undefined") {
|
||||
// we must be running in content space
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
"properties": {
|
||||
"bucket_id": {
|
||||
"type": "string",
|
||||
"description": "Bucket identifier for the addon."
|
||||
"description": "A bucket identifier for the addon. This is used in order to anonymize telemetry for history-sensitive targeting."
|
||||
},
|
||||
"notification_text": {
|
||||
"description": "The text in the small blue chicklet that appears in the URL bar. This can be a reference to a localized string in Firefox or just a plain string.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -35,11 +36,11 @@
|
|||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
],
|
||||
"description": "Id of localized string or message override."
|
||||
]
|
||||
},
|
||||
"info_icon": {
|
||||
"type": "object",
|
||||
"description": "The small icon displayed in the top right corner of the pop-over. Should be 19x19px, svg or png. Defaults to a small question mark." ,
|
||||
"properties": {
|
||||
"label": {
|
||||
"oneOf": [
|
||||
|
@ -79,6 +80,7 @@
|
|||
}
|
||||
},
|
||||
"heading_text": {
|
||||
"description": "The larger heading text displayed in the pop-over. This can be a reference to a localized string in Firefox or just a plain string.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -94,10 +96,10 @@
|
|||
"required": ["string_id"],
|
||||
"description": "Id of localized string for extension doorhanger title"
|
||||
}
|
||||
],
|
||||
"description": "Id of localized string or message override."
|
||||
]
|
||||
},
|
||||
"addon": {
|
||||
"description": "Addon information including AMO URL.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
|
@ -119,6 +121,7 @@
|
|||
]
|
||||
},
|
||||
"icon": {
|
||||
"description": "The icon displayed in the pop-over. Should be 64x64px and png/svg.",
|
||||
"allOf": [
|
||||
{"$ref": "#/definitions/linkUrl"},
|
||||
{"description": "Addon icon"}
|
||||
|
@ -145,6 +148,7 @@
|
|||
"required": ["title", "author", "icon", "amo_url"]
|
||||
},
|
||||
"text": {
|
||||
"description": "The body text displayed in the pop-over. This can be a reference to a localized string in Firefox or just a plain string.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
|
@ -160,10 +164,10 @@
|
|||
},
|
||||
"required": ["string_id"]
|
||||
}
|
||||
],
|
||||
"description": "Id of localized string or message override."
|
||||
]
|
||||
},
|
||||
"buttons": {
|
||||
"description": "The label and functionality for the buttons in the pop-over.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"primary": {
|
||||
|
|
|
@ -3,6 +3,7 @@ import {addLocaleData, injectIntl, IntlProvider} from "react-intl";
|
|||
import {ASRouterAdmin} from "content-src/components/ASRouterAdmin/ASRouterAdmin";
|
||||
import {ConfirmDialog} from "content-src/components/ConfirmDialog/ConfirmDialog";
|
||||
import {connect} from "react-redux";
|
||||
import {DarkModeMessage} from "content-src/components/DarkModeMessage/DarkModeMessage";
|
||||
import {DiscoveryStreamBase} from "content-src/components/DiscoveryStreamBase/DiscoveryStreamBase";
|
||||
import {ErrorBoundary} from "content-src/components/ErrorBoundary/ErrorBoundary";
|
||||
import {ManualMigration} from "content-src/components/ManualMigration/ManualMigration";
|
||||
|
@ -186,6 +187,7 @@ export class BaseContent extends React.PureComponent {
|
|||
}
|
||||
{isDiscoveryStream ? (
|
||||
<ErrorBoundary className="borderless-error">
|
||||
{prefs.darkModeMessage && <DarkModeMessage />}
|
||||
<DiscoveryStreamBase />
|
||||
</ErrorBoundary>) : <Sections />}
|
||||
<PrefsButton onClick={this.openPreferences} />
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
|
||||
export class _DarkModeMessage extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSwitch = this.handleSwitch.bind(this);
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
}
|
||||
|
||||
handleSwitch() {
|
||||
// Switch to default new tab version
|
||||
this.props.dispatch(ac.AlsoToMain({type: at.DISCOVERY_STREAM_OPT_OUT}));
|
||||
}
|
||||
|
||||
handleCancel() {
|
||||
// Capture user consent and not show dark mode message in future
|
||||
this.props.dispatch(ac.SetPref("darkModeMessage", false));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<div className="ds-message-container">
|
||||
<p>
|
||||
<span className="icon icon-info" />
|
||||
<span>This version of New Tab doesn not support dark mode yet.</span>
|
||||
</p>
|
||||
<div className="ds-message-actions actions">
|
||||
<button onClick={this.handleCancel}>
|
||||
<span>Got it</span>
|
||||
</button>
|
||||
<button className="dismiss" onClick={this.handleSwitch}>
|
||||
<span>Use older version</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
|
||||
export const DarkModeMessage = connect()(_DarkModeMessage);
|
|
@ -0,0 +1,48 @@
|
|||
.ds-message-container {
|
||||
display: none;
|
||||
color: $grey-50;
|
||||
font-size: 13px;
|
||||
justify-content: center;
|
||||
margin: 0 auto 40px;
|
||||
width: 936px;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
line-height: 20px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
align-self: center;
|
||||
fill: var(--newtab-icon-secondary-color);
|
||||
margin-inline-end: 6px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.ds-message-actions {
|
||||
align-self: center;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
button {
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
margin-inline-start: 20px;
|
||||
padding: 0 20px;
|
||||
|
||||
&.dismiss {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.force-light-theme {
|
||||
&[lwt-newtab-brighttext] {
|
||||
.ds-message-container {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import {CardGrid} from "content-src/components/DiscoveryStreamComponents/CardGrid/CardGrid";
|
||||
import {connect} from "react-redux";
|
||||
import {DSMessage} from "content-src/components/DiscoveryStreamComponents/DSMessage/DSMessage";
|
||||
import {Hero} from "content-src/components/DiscoveryStreamComponents/Hero/Hero";
|
||||
import {HorizontalRule} from "content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule";
|
||||
import {ImpressionStats} from "content-src/components/DiscoveryStreamImpressionStats/ImpressionStats";
|
||||
|
@ -11,14 +12,14 @@ import {selectLayoutRender} from "content-src/lib/selectLayoutRender";
|
|||
import {TopSites} from "content-src/components/DiscoveryStreamComponents/TopSites/TopSites";
|
||||
|
||||
// According to the Pocket API endpoint specs, `component.properties.items` is a required property with following values:
|
||||
// - List 1-6 items
|
||||
// - List 1-12 items
|
||||
// - Hero 1-5 items
|
||||
// - CardGrid 1-8 items
|
||||
// - CardGrid 1-16 items
|
||||
// To enforce that, we define various maximium items for individual components as an extra check.
|
||||
// Note that these values are subject to the future changes of the specs.
|
||||
const MAX_ROWS_HERO = 5;
|
||||
const MAX_ROWS_LIST = 6;
|
||||
const MAX_ROWS_CARDGRID = 8;
|
||||
const MAX_ROWS_LIST = 12;
|
||||
const MAX_ROWS_CARDGRID = 16;
|
||||
|
||||
const ALLOWED_CSS_URL_PREFIXES = ["chrome://", "resource://", "https://img-getpocket.cdn.mozilla.net/"];
|
||||
const DUMMY_CSS_SELECTOR = "DUMMY#CSS.SELECTOR";
|
||||
|
@ -127,6 +128,15 @@ export class _DiscoveryStreamBase extends React.PureComponent {
|
|||
switch (component.type) {
|
||||
case "TopSites":
|
||||
return (<TopSites header={component.header} />);
|
||||
case "Message":
|
||||
return (
|
||||
<DSMessage
|
||||
title={component.header && component.header.title}
|
||||
subtitle={component.header && component.header.subtitle}
|
||||
link_text={component.header && component.header.link_text}
|
||||
link_url={component.header && component.header.link_url}
|
||||
icon={component.header && component.header.icon} />
|
||||
);
|
||||
case "SectionTitle":
|
||||
return (
|
||||
<SectionTitle
|
||||
|
|
|
@ -14,6 +14,7 @@ export class CardGrid extends React.PureComponent {
|
|||
|
||||
let cards = data.recommendations.slice(0, this.props.items).map((rec, index) => (
|
||||
<DSCard
|
||||
campaignId={rec.campaign_id}
|
||||
key={`dscard-${index}`}
|
||||
image_src={rec.image_src}
|
||||
title={rec.title}
|
||||
|
|
|
@ -1,12 +1,65 @@
|
|||
import {actionCreators as ac} from "common/Actions.jsm";
|
||||
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
|
||||
import React from "react";
|
||||
|
||||
const VISIBLE = "visible";
|
||||
const VISIBILITY_CHANGE_EVENT = "visibilitychange";
|
||||
const INTERSECTION_RATIO = 0.5;
|
||||
|
||||
export class DSCard extends React.PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.cardElementRef = this.cardElementRef.bind(this);
|
||||
this.onLinkClick = this.onLinkClick.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.document.visibilityState === VISIBLE) {
|
||||
this.setupIntersectionObserver();
|
||||
} else {
|
||||
this._onVisibilityChange = () => {
|
||||
if (this.props.document.visibilityState === VISIBLE) {
|
||||
this.setupIntersectionObserver();
|
||||
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
|
||||
}
|
||||
};
|
||||
this.props.document.addEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this._onVisibilityChange) {
|
||||
this.props.document.removeEventListener(VISIBILITY_CHANGE_EVENT, this._onVisibilityChange);
|
||||
}
|
||||
if (this._intersectionObserver) {
|
||||
this._intersectionObserver.unobserve(this.cardElement);
|
||||
}
|
||||
}
|
||||
|
||||
setupIntersectionObserver() {
|
||||
const options = {threshold: INTERSECTION_RATIO};
|
||||
this._intersectionObserver = new IntersectionObserver(entries => {
|
||||
for (let entry of entries) {
|
||||
if (entry.isIntersecting && entry.intersectionRatio >= INTERSECTION_RATIO) {
|
||||
this.dispatchSpocImpression();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, options);
|
||||
this._intersectionObserver.observe(this.cardElement);
|
||||
}
|
||||
|
||||
dispatchSpocImpression() {
|
||||
if (this.props.campaignId) {
|
||||
this.props.dispatch(ac.OnlyToMain({type: at.DISCOVERY_STREAM_SPOC_IMPRESSION, data: {campaignId: this.props.campaignId}}));
|
||||
}
|
||||
this._intersectionObserver.unobserve(this.cardElement);
|
||||
}
|
||||
|
||||
cardElementRef(element) {
|
||||
this.cardElement = element;
|
||||
}
|
||||
|
||||
onLinkClick(event) {
|
||||
if (this.props.dispatch) {
|
||||
this.props.dispatch(ac.UserEvent({
|
||||
|
@ -25,7 +78,7 @@ export class DSCard extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<a href={this.props.url} className="ds-card" onClick={this.onLinkClick}>
|
||||
<a href={this.props.url} className="ds-card" onClick={this.onLinkClick} ref={this.cardElementRef}>
|
||||
<div className="img-wrapper">
|
||||
<div className="img" style={{backgroundImage: `url(${this.props.image_src}`}} />
|
||||
</div>
|
||||
|
@ -48,3 +101,7 @@ export class DSCard extends React.PureComponent {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
DSCard.defaultProps = {
|
||||
document: global.document,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import React from "react";
|
||||
|
||||
export class DSMessage extends React.PureComponent {
|
||||
render() {
|
||||
let hasSubtitleAndOrLink = this.props.link_text && this.props.link_url;
|
||||
hasSubtitleAndOrLink = hasSubtitleAndOrLink || this.props.subtitle;
|
||||
|
||||
return (
|
||||
<div className="ds-message">
|
||||
{this.props.title && (
|
||||
<header className="title">
|
||||
{this.props.icon && (<img src={this.props.icon} />)}
|
||||
<span>{this.props.title}</span>
|
||||
</header>
|
||||
)}
|
||||
{ hasSubtitleAndOrLink && (
|
||||
<p className="subtitle">
|
||||
{this.props.subtitle && (<span>{this.props.subtitle}</span>)}
|
||||
{this.props.link_text && this.props.link_url && (<a href={this.props.link_url}>{this.props.link_text}</a>)}
|
||||
</p>
|
||||
)}
|
||||
<hr className="ds-hr" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
.ds-message {
|
||||
margin: 8px 0 0;
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 6px 0 0;
|
||||
}
|
||||
|
||||
span {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: $grey-90;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: $grey-50;
|
||||
margin: 0;
|
||||
|
||||
span::after {
|
||||
content: ' ';
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-hr {
|
||||
margin: 16px 0 8px;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ import {actionCreators as ac} from "common/Actions.jsm";
|
|||
import {DSCard} from "../DSCard/DSCard.jsx";
|
||||
import {List} from "../List/List.jsx";
|
||||
import React from "react";
|
||||
import {truncateText} from "content-src/lib/truncate-text";
|
||||
|
||||
export class Hero extends React.PureComponent {
|
||||
constructor(props) {
|
||||
|
@ -42,16 +41,17 @@ export class Hero extends React.PureComponent {
|
|||
// Note that `{index + 1}` is necessary below for telemetry since we treat heroRec as index 0.
|
||||
let cards = otherRecs.map((rec, index) => (
|
||||
<DSCard
|
||||
campaignId={rec.campaign_id}
|
||||
key={`dscard-${index}`}
|
||||
image_src={rec.image_src}
|
||||
title={truncateText(rec.title, 44)}
|
||||
title={rec.title}
|
||||
url={rec.url}
|
||||
id={rec.id}
|
||||
index={index + 1}
|
||||
type={this.props.type}
|
||||
dispatch={this.props.dispatch}
|
||||
context={truncateText(rec.context, 22)}
|
||||
source={truncateText(rec.domain, 22)} />
|
||||
context={rec.context}
|
||||
source={rec.domain} />
|
||||
));
|
||||
|
||||
let list = (
|
||||
|
@ -73,12 +73,12 @@ export class Hero extends React.PureComponent {
|
|||
<div className="img" style={{backgroundImage: `url(${heroRec.image_src})`}} />
|
||||
</div>
|
||||
<div className="meta">
|
||||
<header>{truncateText(heroRec.title, 28)}</header>
|
||||
<p>{truncateText(heroRec.excerpt, 114)}</p>
|
||||
<header>{heroRec.title}</header>
|
||||
<p>{heroRec.excerpt}</p>
|
||||
{heroRec.context ? (
|
||||
<p className="context">{truncateText(heroRec.context, 22)}</p>
|
||||
<p className="context">{heroRec.context}</p>
|
||||
) : (
|
||||
<p className="source">{truncateText(heroRec.domain, 22)}</p>
|
||||
<p className="source">{heroRec.domain}</p>
|
||||
)}
|
||||
</div>
|
||||
</a>
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {actionCreators as ac} from "common/Actions.jsm";
|
||||
import {connect} from "react-redux";
|
||||
import React from "react";
|
||||
import {truncateText} from "content-src/lib/truncate-text";
|
||||
|
||||
/**
|
||||
* @note exported for testing only
|
||||
|
@ -36,7 +35,7 @@ export class ListItem extends React.PureComponent {
|
|||
<a className="ds-list-item-link" href={this.props.url} onClick={this.onLinkClick}>
|
||||
<div className="ds-list-item-text">
|
||||
<div className="ds-list-item-title">{this.props.title}</div>
|
||||
{this.props.excerpt && <div className="ds-list-item-excerpt">{truncateText(this.props.excerpt, 90)}</div>}
|
||||
{this.props.excerpt && <div className="ds-list-item-excerpt">{this.props.excerpt}</div>}
|
||||
<div className="ds-list-item-info">{this.props.domain}</div>
|
||||
</div>
|
||||
<div className="ds-list-image" style={{backgroundImage: `url(${this.props.image_src})`}} />
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
export function truncateText(text = "", cap) {
|
||||
return text.substring(0, cap).trim() + (text.length > cap ? "…" : "");
|
||||
}
|
|
@ -145,6 +145,7 @@ input {
|
|||
@import '../components/PocketLoggedInCta/PocketLoggedInCta';
|
||||
@import '../components/MoreRecommendations/MoreRecommendations';
|
||||
@import '../components/DiscoveryStreamBase/DiscoveryStreamBase';
|
||||
@import '../components/DarkModeMessage/DarkModeMessage';
|
||||
|
||||
// Discovery Stream Components
|
||||
@import '../components/DiscoveryStreamComponents/CardGrid/CardGrid';
|
||||
|
@ -155,6 +156,7 @@ input {
|
|||
@import '../components/DiscoveryStreamComponents/SectionTitle/SectionTitle';
|
||||
@import '../components/DiscoveryStreamComponents/TopSites/TopSites';
|
||||
@import '../components/DiscoveryStreamComponents/DSCard/DSCard';
|
||||
@import '../components/DiscoveryStreamComponents/DSMessage/DSMessage';
|
||||
|
||||
// AS Router
|
||||
@import '../asrouter/components/Button/Button';
|
||||
|
|
|
@ -1831,6 +1831,39 @@ main {
|
|||
color: #0C0C0D;
|
||||
margin: 16px 0; }
|
||||
|
||||
.ds-message-container {
|
||||
display: none;
|
||||
color: #737373;
|
||||
font-size: 13px;
|
||||
justify-content: center;
|
||||
margin: 0 auto 40px;
|
||||
width: 936px; }
|
||||
.ds-message-container p {
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
line-height: 20px;
|
||||
display: flex; }
|
||||
.ds-message-container .icon {
|
||||
align-self: center;
|
||||
fill: var(--newtab-icon-secondary-color);
|
||||
margin-inline-end: 6px;
|
||||
width: 20px;
|
||||
height: 20px; }
|
||||
.ds-message-container .ds-message-actions {
|
||||
align-self: center;
|
||||
border: 0;
|
||||
padding: 0; }
|
||||
.ds-message-container .ds-message-actions button {
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
margin-inline-start: 20px;
|
||||
padding: 0 20px; }
|
||||
.ds-message-container .ds-message-actions button.dismiss {
|
||||
padding: 0; }
|
||||
|
||||
.force-light-theme[lwt-newtab-brighttext] .ds-message-container {
|
||||
display: flex; }
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px; }
|
||||
|
@ -2339,6 +2372,33 @@ main {
|
|||
.ds-card .context {
|
||||
color: #008EA4; }
|
||||
|
||||
.ds-message {
|
||||
margin: 8px 0 0; }
|
||||
.ds-message .title {
|
||||
display: flex;
|
||||
align-items: center; }
|
||||
.ds-message .title img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 6px 0 0; }
|
||||
.ds-message .title span {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D;
|
||||
font-weight: 600; }
|
||||
.ds-message .subtitle {
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: #737373;
|
||||
margin: 0; }
|
||||
.ds-message .subtitle span::after {
|
||||
content: ' '; }
|
||||
.ds-message .subtitle a:hover,
|
||||
.ds-message .subtitle a:focus {
|
||||
text-decoration: underline; }
|
||||
.ds-message .ds-hr {
|
||||
margin: 16px 0 8px; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1834,6 +1834,39 @@ main {
|
|||
color: #0C0C0D;
|
||||
margin: 16px 0; }
|
||||
|
||||
.ds-message-container {
|
||||
display: none;
|
||||
color: #737373;
|
||||
font-size: 13px;
|
||||
justify-content: center;
|
||||
margin: 0 auto 40px;
|
||||
width: 936px; }
|
||||
.ds-message-container p {
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
line-height: 20px;
|
||||
display: flex; }
|
||||
.ds-message-container .icon {
|
||||
align-self: center;
|
||||
fill: var(--newtab-icon-secondary-color);
|
||||
margin-inline-end: 6px;
|
||||
width: 20px;
|
||||
height: 20px; }
|
||||
.ds-message-container .ds-message-actions {
|
||||
align-self: center;
|
||||
border: 0;
|
||||
padding: 0; }
|
||||
.ds-message-container .ds-message-actions button {
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
margin-inline-start: 20px;
|
||||
padding: 0 20px; }
|
||||
.ds-message-container .ds-message-actions button.dismiss {
|
||||
padding: 0; }
|
||||
|
||||
.force-light-theme[lwt-newtab-brighttext] .ds-message-container {
|
||||
display: flex; }
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px; }
|
||||
|
@ -2342,6 +2375,33 @@ main {
|
|||
.ds-card .context {
|
||||
color: #008EA4; }
|
||||
|
||||
.ds-message {
|
||||
margin: 8px 0 0; }
|
||||
.ds-message .title {
|
||||
display: flex;
|
||||
align-items: center; }
|
||||
.ds-message .title img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 6px 0 0; }
|
||||
.ds-message .title span {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D;
|
||||
font-weight: 600; }
|
||||
.ds-message .subtitle {
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: #737373;
|
||||
margin: 0; }
|
||||
.ds-message .subtitle span::after {
|
||||
content: ' '; }
|
||||
.ds-message .subtitle a:hover,
|
||||
.ds-message .subtitle a:focus {
|
||||
text-decoration: underline; }
|
||||
.ds-message .ds-hr {
|
||||
margin: 16px 0 8px; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1831,6 +1831,39 @@ main {
|
|||
color: #0C0C0D;
|
||||
margin: 16px 0; }
|
||||
|
||||
.ds-message-container {
|
||||
display: none;
|
||||
color: #737373;
|
||||
font-size: 13px;
|
||||
justify-content: center;
|
||||
margin: 0 auto 40px;
|
||||
width: 936px; }
|
||||
.ds-message-container p {
|
||||
margin: 0;
|
||||
align-self: center;
|
||||
line-height: 20px;
|
||||
display: flex; }
|
||||
.ds-message-container .icon {
|
||||
align-self: center;
|
||||
fill: var(--newtab-icon-secondary-color);
|
||||
margin-inline-end: 6px;
|
||||
width: 20px;
|
||||
height: 20px; }
|
||||
.ds-message-container .ds-message-actions {
|
||||
align-self: center;
|
||||
border: 0;
|
||||
padding: 0; }
|
||||
.ds-message-container .ds-message-actions button {
|
||||
height: 24px;
|
||||
margin: 0;
|
||||
margin-inline-start: 20px;
|
||||
padding: 0 20px; }
|
||||
.ds-message-container .ds-message-actions button.dismiss {
|
||||
padding: 0; }
|
||||
|
||||
.force-light-theme[lwt-newtab-brighttext] .ds-message-container {
|
||||
display: flex; }
|
||||
|
||||
.ds-card-grid {
|
||||
display: grid;
|
||||
grid-gap: 24px; }
|
||||
|
@ -2339,6 +2372,33 @@ main {
|
|||
.ds-card .context {
|
||||
color: #008EA4; }
|
||||
|
||||
.ds-message {
|
||||
margin: 8px 0 0; }
|
||||
.ds-message .title {
|
||||
display: flex;
|
||||
align-items: center; }
|
||||
.ds-message .title img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 6px 0 0; }
|
||||
.ds-message .title span {
|
||||
line-height: 24px;
|
||||
font-size: 17px;
|
||||
color: #0C0C0D;
|
||||
font-weight: 600; }
|
||||
.ds-message .subtitle {
|
||||
line-height: 20px;
|
||||
font-size: 14px;
|
||||
color: #737373;
|
||||
margin: 0; }
|
||||
.ds-message .subtitle span::after {
|
||||
content: ' '; }
|
||||
.ds-message .subtitle a:hover,
|
||||
.ds-message .subtitle a:focus {
|
||||
text-decoration: underline; }
|
||||
.ds-message .ds-hr {
|
||||
margin: 16px 0 8px; }
|
||||
|
||||
.ASRouterButton {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -91,7 +91,7 @@ module.exports = function(config) {
|
|||
options: {
|
||||
plugins: [
|
||||
// Converts .jsm files into common-js modules
|
||||
["jsm-to-commonjs", {basePath: PATHS.resourcePathRegEx, replace: true}], // require("babel-plugin-jsm-to-commonjs")
|
||||
["jsm-to-commonjs", {basePath: PATHS.resourcePathRegEx, removeOtherImports: true, replace: true}], // require("babel-plugin-jsm-to-commonjs")
|
||||
["transform-async-to-module-method", {module: "co-task", method: "async"}], // require("babel-plugin-transform-async-to-module-method")
|
||||
"transform-es2015-modules-commonjs", // require("babel-plugin-transform-es2015-modules-commonjs")
|
||||
["transform-object-rest-spread", {"useBuiltIns": true}], // require("babel-plugin-transform-object-rest-spread")
|
||||
|
|
|
@ -246,9 +246,8 @@ const MessageLoaderUtils = {
|
|||
const aUri = Services.io.newURI(url);
|
||||
const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
|
||||
// AddonManager installation source associated to the addons installed from activitystream
|
||||
// (See Bug 1496167 for a rationale).
|
||||
const telemetryInfo = {source: "activitystream"};
|
||||
// AddonManager installation source associated to the addons installed from activitystream's CFR
|
||||
const telemetryInfo = {source: "amo"};
|
||||
const install = await AddonManager.getInstallForURL(aUri.spec, {telemetryInfo});
|
||||
await AddonManager.installAddonFromWebpage("application/x-xpinstall", browser,
|
||||
systemPrincipal, install);
|
||||
|
|
|
@ -287,6 +287,7 @@ this.AboutPreferences = class AboutPreferences {
|
|||
createAppend("hbox", discoveryGroup)
|
||||
.appendChild(contentDiscoveryButton)
|
||||
.addEventListener("click", async () => {
|
||||
this.store.dispatch({type: at.DISCOVERY_STREAM_OPT_OUT});
|
||||
const activeExperiments = await PreferenceExperiments.getAllActive();
|
||||
const experiment = activeExperiments.find(exp => exp.preferenceName === DISCOVERY_STREAM_CONFIG_PREF_NAME);
|
||||
// Unconditionally update the UI for a fast user response and in
|
||||
|
|
|
@ -222,6 +222,14 @@ const PREFS_CONFIG = new Map([
|
|||
layout_endpoint: "https://getpocket.com/v3/newtab/layout?version=1&consumer_key=40249-e88c401e1b1f2242d9e441c4&layout_variant=basic",
|
||||
}),
|
||||
}],
|
||||
["discoverystream.optOut.0", {
|
||||
title: "Opt out of new layout v0",
|
||||
value: false,
|
||||
}],
|
||||
["darkModeMessage", {
|
||||
title: "Boolean flag that decides whether to show the dark Mode message or not.",
|
||||
value: IS_NIGHTLY_OR_UNBRANDED_BUILD,
|
||||
}],
|
||||
]);
|
||||
|
||||
// Array of each feed's FEEDS_CONFIG factory and values to add to PREFS_CONFIG
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {actionTypes: at, actionCreators: ac} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm");
|
||||
const {PersistentCache} = ChromeUtils.import("resource://activity-stream/lib/PersistentCache.jsm");
|
||||
|
@ -14,7 +13,11 @@ const CACHE_KEY = "discovery_stream";
|
|||
const LAYOUT_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
|
||||
const COMPONENT_FEEDS_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
|
||||
const SPOCS_FEEDS_UPDATE_TIME = 30 * 60 * 1000; // 30 minutes
|
||||
const CONFIG_PREF_NAME = "browser.newtabpage.activity-stream.discoverystream.config";
|
||||
const MAX_LIFETIME_CAP = 500; // Guard against misconfiguration on the server
|
||||
const PREF_CONFIG = "discoverystream.config";
|
||||
const PREF_OPT_OUT = "discoverystream.optOut.0";
|
||||
const PREF_SHOW_SPONSORED = "showSponsored";
|
||||
const PREF_SPOC_IMPRESSIONS = "discoverystream.spoc.impressions";
|
||||
|
||||
this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
||||
constructor() {
|
||||
|
@ -32,41 +35,35 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
return this._prefCache.config;
|
||||
}
|
||||
try {
|
||||
this._prefCache.config = JSON.parse(Services.prefs.getStringPref(CONFIG_PREF_NAME, ""));
|
||||
this._prefCache.config = JSON.parse(this.store.getState().Prefs.values[PREF_CONFIG]);
|
||||
|
||||
// Modify the cached config with the user set opt-out for other consumers
|
||||
this._prefCache.config.enabled = this._prefCache.config.enabled &&
|
||||
!this.store.getState().Prefs.values[PREF_OPT_OUT];
|
||||
} catch (e) {
|
||||
// istanbul ignore next
|
||||
this._prefCache.config = {};
|
||||
// istanbul ignore next
|
||||
Cu.reportError(`Could not parse preference. Try resetting ${CONFIG_PREF_NAME} in about:config.`);
|
||||
Cu.reportError(`Could not parse preference. Try resetting ${PREF_CONFIG} in about:config.`);
|
||||
}
|
||||
return this._prefCache.config;
|
||||
}
|
||||
|
||||
get showSpocs() {
|
||||
// showSponsored is generally a use set spoc opt out,
|
||||
// show_spocs is generally a mozilla set value.
|
||||
return this.store.getState().Prefs.values.showSponsored && this.config.show_spocs;
|
||||
// Combine user-set sponsored opt-out with Mozilla-set config
|
||||
return this.store.getState().Prefs.values[PREF_SHOW_SPONSORED] && this.config.show_spocs;
|
||||
}
|
||||
|
||||
setupPrefs() {
|
||||
Services.prefs.addObserver(CONFIG_PREF_NAME, this);
|
||||
// Send the initial state of the pref on our reducer
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_CONFIG_SETUP, data: this.config}));
|
||||
}
|
||||
|
||||
uninitPrefs() {
|
||||
Services.prefs.removeObserver(CONFIG_PREF_NAME, this);
|
||||
// Reset in-memory cache
|
||||
this._prefCache = {};
|
||||
}
|
||||
|
||||
observe(aSubject, aTopic, aPrefName) {
|
||||
if (aPrefName === CONFIG_PREF_NAME) {
|
||||
this._prefCache.config = null;
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.DISCOVERY_STREAM_CONFIG_CHANGE, data: this.config}));
|
||||
}
|
||||
}
|
||||
|
||||
async fetchFromEndpoint(endpoint) {
|
||||
if (!endpoint) {
|
||||
Cu.reportError("Tried to fetch endpoint but none was configured.");
|
||||
|
@ -183,6 +180,8 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
lastUpdated: Date.now(),
|
||||
data: spocsResponse,
|
||||
};
|
||||
|
||||
this.cleanUpCampaignImpressionPref(spocs.data);
|
||||
await this.cache.set("spocs", spocs);
|
||||
} else {
|
||||
Cu.reportError("No response for spocs_endpoint prop");
|
||||
|
@ -203,11 +202,62 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
|
||||
data: {
|
||||
lastUpdated: spocs.lastUpdated,
|
||||
spocs: spocs.data,
|
||||
spocs: this.filterSpocs(spocs.data),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Filter spocs based on frequency caps
|
||||
filterSpocs(data) {
|
||||
if (data && data.spocs && data.spocs.length) {
|
||||
const {spocs} = data;
|
||||
const impressions = this.readImpressionsPref(PREF_SPOC_IMPRESSIONS);
|
||||
return {
|
||||
...data,
|
||||
spocs: spocs.filter(s => this.isBelowFrequencyCap(impressions, s)),
|
||||
};
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// Frequency caps are based on campaigns, which may include multiple spocs.
|
||||
// We currently support two types of frequency caps:
|
||||
// - lifetime: Indicates how many times spocs from a campaign can be shown in total
|
||||
// - period: Indicates how many times spocs from a campaign can be shown within a period
|
||||
//
|
||||
// So, for example, the feed configuration below defines that for campaign 1 no more
|
||||
// than 5 spocs can be shown in total, and no more than 2 per hour.
|
||||
// "campaign_id": 1,
|
||||
// "caps": {
|
||||
// "lifetime": 5,
|
||||
// "campaign": {
|
||||
// "count": 2,
|
||||
// "period": 3600
|
||||
// }
|
||||
// }
|
||||
isBelowFrequencyCap(impressions, spoc) {
|
||||
const campaignImpressions = impressions[spoc.campaign_id];
|
||||
if (!campaignImpressions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const lifetime = spoc.caps && spoc.caps.lifetime;
|
||||
|
||||
const lifeTimeCap = Math.min(lifetime || MAX_LIFETIME_CAP, MAX_LIFETIME_CAP);
|
||||
const lifeTimeCapExceeded = campaignImpressions.length >= lifeTimeCap;
|
||||
if (lifeTimeCapExceeded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const campaignCap = spoc.caps && spoc.caps.campaign;
|
||||
if (campaignCap) {
|
||||
const campaignCapExceeded = campaignImpressions
|
||||
.filter(i => (Date.now() - i) < (campaignCap.period * 1000)).length >= campaignCap.count;
|
||||
return !campaignCapExceeded;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async getComponentFeed(feedUrl) {
|
||||
const cachedData = await this.cache.get() || {};
|
||||
const {feeds} = cachedData;
|
||||
|
@ -277,6 +327,50 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
}
|
||||
}
|
||||
|
||||
recordCampaignImpression(campaignId) {
|
||||
let impressions = this.readImpressionsPref(PREF_SPOC_IMPRESSIONS);
|
||||
|
||||
const timeStamps = impressions[campaignId] || [];
|
||||
timeStamps.push(Date.now());
|
||||
impressions = {...impressions, [campaignId]: timeStamps};
|
||||
|
||||
this.writeImpressionsPref(PREF_SPOC_IMPRESSIONS, impressions);
|
||||
}
|
||||
|
||||
cleanUpCampaignImpressionPref(data) {
|
||||
if (data.spocs && data.spocs.length) {
|
||||
const campaignIds = data.spocs.map(s => `${s.campaign_id}`);
|
||||
this.cleanUpImpressionPref(id => !campaignIds.includes(id), PREF_SPOC_IMPRESSIONS);
|
||||
}
|
||||
}
|
||||
|
||||
writeImpressionsPref(pref, impressions) {
|
||||
this.store.dispatch(ac.SetPref(pref, JSON.stringify(impressions)));
|
||||
}
|
||||
|
||||
readImpressionsPref(pref) {
|
||||
const prefVal = this.store.getState().Prefs.values[pref];
|
||||
return prefVal ? JSON.parse(prefVal) : {};
|
||||
}
|
||||
|
||||
cleanUpImpressionPref(isExpired, pref) {
|
||||
const impressions = this.readImpressionsPref(pref);
|
||||
let changed = false;
|
||||
|
||||
Object
|
||||
.keys(impressions)
|
||||
.forEach(id => {
|
||||
if (isExpired(id)) {
|
||||
changed = true;
|
||||
delete impressions[id];
|
||||
}
|
||||
});
|
||||
|
||||
if (changed) {
|
||||
this.writeImpressionsPref(pref, impressions);
|
||||
}
|
||||
}
|
||||
|
||||
async onAction(action) {
|
||||
switch (action.type) {
|
||||
case at.INIT:
|
||||
|
@ -295,20 +389,60 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
|
|||
}
|
||||
break;
|
||||
case at.DISCOVERY_STREAM_CONFIG_SET_VALUE:
|
||||
Services.prefs.setStringPref(CONFIG_PREF_NAME, JSON.stringify({...this.config, [action.data.name]: action.data.value}));
|
||||
// Disable opt-out if we're explicitly trying to enable
|
||||
if (action.data.name === "enabled" && action.data.value) {
|
||||
this.store.dispatch(ac.SetPref(PREF_OPT_OUT, false));
|
||||
}
|
||||
|
||||
// Use the original string pref to then set a value instead of
|
||||
// this.config which has some modifications
|
||||
this.store.dispatch(ac.SetPref(PREF_CONFIG, JSON.stringify({
|
||||
...JSON.parse(this.store.getState().Prefs.values[PREF_CONFIG]),
|
||||
[action.data.name]: action.data.value,
|
||||
})));
|
||||
break;
|
||||
case at.DISCOVERY_STREAM_CONFIG_CHANGE:
|
||||
// When the config pref changes, load or unload data as needed.
|
||||
await this.onPrefChange();
|
||||
break;
|
||||
case at.DISCOVERY_STREAM_OPT_OUT:
|
||||
this.store.dispatch(ac.SetPref(PREF_OPT_OUT, true));
|
||||
break;
|
||||
case at.DISCOVERY_STREAM_SPOC_IMPRESSION:
|
||||
if (this.showSpocs) {
|
||||
this.recordCampaignImpression(action.data.campaignId);
|
||||
|
||||
const cachedData = await this.cache.get() || {};
|
||||
const {spocs} = cachedData;
|
||||
|
||||
this.store.dispatch(ac.AlsoToPreloaded({
|
||||
type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
|
||||
data: {
|
||||
lastUpdated: spocs.lastUpdated,
|
||||
spocs: this.filterSpocs(spocs.data),
|
||||
},
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case at.UNINIT:
|
||||
// When this feed is shutting down:
|
||||
this.uninitPrefs();
|
||||
break;
|
||||
case at.PREF_CHANGED:
|
||||
// Check if spocs was disabled. Remove them if they were.
|
||||
if (action.data.name === "showSponsored") {
|
||||
await this.loadSpocs();
|
||||
switch (action.data.name) {
|
||||
case PREF_CONFIG:
|
||||
case PREF_OPT_OUT:
|
||||
// Clear the cached config and broadcast the newly computed value
|
||||
this._prefCache.config = null;
|
||||
this.store.dispatch(ac.BroadcastToContent({
|
||||
type: at.DISCOVERY_STREAM_CONFIG_CHANGE,
|
||||
data: this.config,
|
||||
}));
|
||||
break;
|
||||
// Check if spocs was disabled. Remove them if they were.
|
||||
case PREF_SHOW_SPONSORED:
|
||||
await this.loadSpocs();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -622,6 +622,15 @@ this.TelemetryFeed = class TelemetryFeed {
|
|||
this.setLoadTriggerInfo(port);
|
||||
}
|
||||
|
||||
let timestamp = data.topsites_first_painted_ts;
|
||||
|
||||
if (timestamp &&
|
||||
session.page === "about:home" &&
|
||||
!HomePage.overridden &&
|
||||
Services.prefs.getIntPref("browser.startup.page") === 1) {
|
||||
aboutNewTabService.maybeRecordTopsitesPainted(timestamp);
|
||||
}
|
||||
|
||||
Object.assign(session.perf, data);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ const STORIES_NOW_THRESHOLD = 24 * 60 * 60 * 1000; // 24 hours
|
|||
const MIN_DOMAIN_AFFINITIES_UPDATE_TIME = 12 * 60 * 60 * 1000; // 12 hours
|
||||
const DEFAULT_RECS_EXPIRE_TIME = 60 * 60 * 1000; // 1 hour
|
||||
const SECTION_ID = "topstories";
|
||||
const IMPRESSION_SOURCE = "TOP_STORIES";
|
||||
const SPOC_IMPRESSION_TRACKING_PREF = "feeds.section.topstories.spoc.impressions";
|
||||
const REC_IMPRESSION_TRACKING_PREF = "feeds.section.topstories.rec.impressions";
|
||||
const OPTIONS_PREF = "feeds.section.topstories.options";
|
||||
|
@ -656,21 +657,27 @@ this.TopStoriesFeed = class TopStoriesFeed {
|
|||
}
|
||||
break;
|
||||
case at.TELEMETRY_IMPRESSION_STATS: {
|
||||
const payload = action.data;
|
||||
const viewImpression = !("click" in payload || "block" in payload || "pocket" in payload);
|
||||
if (payload.tiles && viewImpression) {
|
||||
if (this.shouldShowSpocs()) {
|
||||
payload.tiles.forEach(t => {
|
||||
if (this.spocCampaignMap.has(t.id)) {
|
||||
this.recordCampaignImpression(this.spocCampaignMap.get(t.id));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.personalized) {
|
||||
const topRecs = payload.tiles
|
||||
.filter(t => !this.spocCampaignMap.has(t.id))
|
||||
.map(t => t.id);
|
||||
this.recordTopRecImpressions(topRecs);
|
||||
// We want to make sure we only track impressions from Top Stories,
|
||||
// otherwise unexpected things that are not properly handled can happen.
|
||||
// Example: Impressions from spocs on Discovery Stream can cause the
|
||||
// Top Stories impressions pref to continuously grow, see bug #1523408
|
||||
if (action.data.source === IMPRESSION_SOURCE) {
|
||||
const payload = action.data;
|
||||
const viewImpression = !("click" in payload || "block" in payload || "pocket" in payload);
|
||||
if (payload.tiles && viewImpression) {
|
||||
if (this.shouldShowSpocs()) {
|
||||
payload.tiles.forEach(t => {
|
||||
if (this.spocCampaignMap.has(t.id)) {
|
||||
this.recordCampaignImpression(this.spocCampaignMap.get(t.id));
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.personalized) {
|
||||
const topRecs = payload.tiles
|
||||
.filter(t => !this.spocCampaignMap.has(t.id))
|
||||
.map(t => t.id);
|
||||
this.recordTopRecImpressions(topRecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -203,3 +203,4 @@ firstrun_skip_login=Kal citep man
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Yab jami ayera
|
||||
section_menu_action_add_search_engine=Med Ingin me Yeny
|
||||
|
|
|
@ -90,7 +90,12 @@ section_disclaimer_topstories_buttontext=حسنًا، فهمت
|
|||
# sidebar mozilla-central string for the panel that has preferences related to
|
||||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=محتوى فَيَرفُكس الرئيسي
|
||||
prefs_home_description=اختر المحتوى الذي تريد عرضه في شاشة فَيَرفُكس الرئيسية.
|
||||
prefs_home_description=اختر المحتوى الذي تريد عرضه في شاشة بداية فَيَرفُكس.
|
||||
|
||||
prefs_content_discovery_header=شاشة بداية فَيَرفُكس
|
||||
prefs_content_discovery_description=تتيح لك ميزة ”اكتشاف المحتوى“ في صفحة بداية فَيَرفُكس رؤية مقالات عالية الجودة لها علاقة بما تتابع، تأتيك من أرجاء الوِب.
|
||||
prefs_content_discovery_button=عطّل اكتشاف المحتوى
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +149,6 @@ pocket_read_more=المواضيع الشائعة:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=اعرض المزيد من الأخبار
|
||||
pocket_more_reccommendations=مقترحات أخرى
|
||||
pocket_learn_more=اطّلع على المزيد
|
||||
pocket_how_it_works=آلية العمل
|
||||
pocket_cta_button=نزِّل بوكِت
|
||||
pocket_cta_text=احفظ القصص التي تحبّها في بوكِت، وزوّد عقلك بمقالات رائعة.
|
||||
|
@ -209,3 +213,4 @@ firstrun_skip_login=تجاوز هذه الخطوة
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=افتح القائمة
|
||||
section_menu_action_add_search_engine=أضِف محرك بحث
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Bu addımı keç
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menyunu aç
|
||||
section_menu_action_add_search_engine=Axtarış mühərriyi əlavə et
|
||||
|
|
|
@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Зразумела
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Хатні экран Firefox
|
||||
prefs_home_description=Выберыце пажаданае змесціва для хатняга экрана Firefox.
|
||||
|
||||
prefs_content_discovery_header=Хатняя старонка Firefox
|
||||
prefs_content_discovery_description=Выяўленне змесціва на хатняй старонцы Firefox дазволіць вам знаходзіць высакаякасныя рэлевантныя артыкулы з усяго сеціва.
|
||||
prefs_content_discovery_button=Адключыць выяўленне змесціва
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +149,6 @@ pocket_read_more=Папулярныя тэмы:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Іншыя навіны
|
||||
pocket_more_reccommendations=Больш рэкамендацый
|
||||
pocket_learn_more=Падрабязней
|
||||
pocket_how_it_works=Як гэта працуе
|
||||
pocket_cta_button=Атрымаць Pocket
|
||||
pocket_cta_text=Захоўвайце ўлюбёныя гісторыі ў Pocket, і сілкуйце свой розум добрай чытанкай.
|
||||
|
@ -209,3 +213,4 @@ firstrun_skip_login=Прапусціць гэты крок
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Адкрыць меню
|
||||
section_menu_action_add_search_engine=Дадаць пашукавік
|
||||
|
|
|
@ -206,3 +206,4 @@ firstrun_privacy_notice=политиката за лични данни
|
|||
|
||||
firstrun_continue_to_login=Продължаване
|
||||
firstrun_skip_login=Пропускане
|
||||
section_menu_action_add_search_engine=Добавяне на търсеща машина
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_skip_login=এই ধাপটি বাদ দিন
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=মেনু খুলুন
|
||||
section_menu_action_add_search_engine=অনুসন্ধান ইঞ্জিন যোগ
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=ধাপটি উপেক্ষা করুন
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=মেনু খুলুন
|
||||
section_menu_action_add_search_engine=অনুসন্ধান ইঞ্জিন যোগ করুন
|
||||
|
|
|
@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=Mat eo, komprenet am eus
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Endalc'had Degemer Firefox
|
||||
prefs_home_description=Dibabit peseurt endalc'had a fell deoc'h kaout war ho skramm Firefox Degemer.
|
||||
|
||||
prefs_content_discovery_header=Degemer Firefox
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +147,6 @@ pocket_read_more=Danvezioù brudet:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Gwelet muioc'h a istorioù
|
||||
pocket_more_reccommendations=Erbedadennoù ouzhpenn
|
||||
pocket_learn_more=Gouzout hiroc'h
|
||||
pocket_how_it_works=Penaos ez a en-dro
|
||||
pocket_cta_button=Staliañ Pocket
|
||||
pocket_cta_text=Enrollit pennadoù a-zoare e Pocket ha magit ho spered gant lennadennoù boemus.
|
||||
|
@ -209,3 +211,4 @@ firstrun_skip_login=Tremen ar bazenn-mañ
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Digeriñ al lañser
|
||||
section_menu_action_add_search_engine=Ouzhpennañ ul lusker enklask
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Omet aquest pas
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Obre el menú
|
||||
section_menu_action_add_search_engine=Afegeix un motor de cerca
|
||||
|
|
|
@ -93,6 +93,8 @@ prefs_home_header=Etamab'äl pa ri Rutikirib'al Firefox
|
|||
prefs_home_description=Tacha' achike etamab'äl nawajo' pa ri Rutikirib'al Firefox ruwäch.
|
||||
|
||||
prefs_content_discovery_header=Rutikirib'al Firefox
|
||||
prefs_content_discovery_description=Content Discovery pa Rutikirib'al Firefox nuya' q'ij chawe richin ye'awïl nima'q taq cholna'oj ri nïm kejqalem pa ronojel ajk'amaya'l.
|
||||
prefs_content_discovery_button=Tichup Content Discovery
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
|
@ -211,3 +213,4 @@ firstrun_skip_login=Tixakalüx re jun ruxak re'
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Tijaq k'utüy samaj
|
||||
section_menu_action_add_search_engine=Titz'aqatisäx Kanob'äl
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Přeskočit tento krok
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Otevře nabídku
|
||||
section_menu_action_add_search_engine=Přidat vyhledávač
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Hepgor y cam hwn
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Agor y ddewislen
|
||||
section_menu_action_add_search_engine=Ychwanegu Peiriant Chwilio
|
||||
|
|
|
@ -218,7 +218,7 @@ firstrun_invalid_input=En gyldig mailadresse er påkrævet
|
|||
|
||||
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
||||
firstrun_extra_legal_links=Ved at fortsætte godkender du vores {terms} og {privacy}.
|
||||
firstrun_extra_legal_links=Ved at fortsætte accepterer du vores {terms} og vores {privacy}.
|
||||
firstrun_terms_of_service=tjenestevilkår
|
||||
firstrun_privacy_notice=privatlivspolitik
|
||||
|
||||
|
@ -227,3 +227,4 @@ firstrun_skip_login=Spring dette trin over
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Åbn menu
|
||||
section_menu_action_add_search_engine=Tilføj søgetjeneste
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_skip_login=Diesen Schritt überspringen
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menü öffnen
|
||||
section_menu_action_add_search_engine=Suchmaschine hinzufügen
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Toś ten kšac pśeskócyś
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Meni wócyniś
|
||||
section_menu_action_add_search_engine=Pytnicu pśidaś
|
||||
|
|
|
@ -212,3 +212,4 @@ firstrun_skip_login=Παράλειψη βήματος
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Άνοιγμα μενού
|
||||
section_menu_action_add_search_engine=Προσθήκη μηχανής αναζήτησης
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Skip this step
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Open menu
|
||||
section_menu_action_add_search_engine=Add Search Engine
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_skip_login=Skip this step
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Open menu
|
||||
section_menu_action_add_search_engine=Add Search Engine
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Pretersalti tiun ĉi paŝon
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Malfermi menuon
|
||||
section_menu_action_add_search_engine=Aldoni serĉilon
|
||||
|
|
|
@ -206,10 +206,11 @@ firstrun_invalid_input=Se requiere un correo electrónico válido
|
|||
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
||||
firstrun_extra_legal_links=Al proceder, acepta los {terms} y {privacy}.
|
||||
firstrun_terms_of_service=Términos del servicio
|
||||
firstrun_privacy_notice=Anuncio de privacidad
|
||||
firstrun_privacy_notice=Nota de privacidad
|
||||
|
||||
firstrun_continue_to_login=Continuar
|
||||
firstrun_skip_login=Saltear este paso
|
||||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menú
|
||||
section_menu_action_add_search_engine=Agregar buscador
|
||||
|
|
|
@ -211,3 +211,4 @@ firstrun_skip_login=Saltar este paso
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menú
|
||||
section_menu_action_add_search_engine=Añadir motor de búsqueda
|
||||
|
|
|
@ -93,6 +93,7 @@ prefs_home_header=Contenido de la página de inicio de Firefox
|
|||
prefs_home_description=Seleccione el contenido que desea en la pantalla de inicio de Firefox.
|
||||
|
||||
prefs_content_discovery_header=Página de inicio de Firefox
|
||||
prefs_content_discovery_description=Content Discovery en la página de inicio de Firefox le permite descubrir artículos de alta calidad y relevantes de toda la web.
|
||||
prefs_content_discovery_button=Desactivar Content Discovery
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
|
@ -212,3 +213,4 @@ firstrun_skip_login=Saltar este paso
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menú
|
||||
section_menu_action_add_search_engine=Añadir motor de búsqueda
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Saltar este paso
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menú
|
||||
section_menu_action_add_search_engine=Agregar motor de búsqueda
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Jäta see samm vahele
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Ava menüü
|
||||
section_menu_action_add_search_engine=Lisa otsingumootor
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Saltatu urrats hau
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Ireki menua
|
||||
section_menu_action_add_search_engine=Gehitu bilaketa-motorra
|
||||
|
|
|
@ -206,3 +206,4 @@ firstrun_skip_login=پرش از این مرحله
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=باز کردن منو
|
||||
section_menu_action_add_search_engine=افزودن موتور جستوجو
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Diw ngal daawal
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Uddit cuɓirgol
|
||||
section_menu_action_add_search_engine=Ɓeydu Masiŋ Njiilaw
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Ohita tämä vaihe
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Avaa valikko
|
||||
section_menu_action_add_search_engine=Lisää hakukone
|
||||
|
|
|
@ -148,7 +148,7 @@ pocket_read_more=Sujets populaires :
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Afficher plus d’articles
|
||||
pocket_more_reccommendations=Plus de recommandations
|
||||
pocket_how_it_works=Mode d'emploi
|
||||
pocket_how_it_works=Mode d’emploi
|
||||
pocket_cta_button=Installer Pocket
|
||||
pocket_cta_text=Enregistrez les articles que vous aimez dans Pocket, et stimulez votre imagination avec des lectures fascinantes.
|
||||
|
||||
|
@ -212,3 +212,4 @@ firstrun_skip_login=Ignorer cette étape
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Ouvrir le menu
|
||||
section_menu_action_add_search_engine=Ajouter ce moteur de recherche
|
||||
|
|
|
@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Oké, begrepen
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Ynhâld fan Firefox-startside
|
||||
prefs_home_description=Kies hokker ynhâld jo op jo Firefox-startside werjaan wolle.
|
||||
|
||||
prefs_content_discovery_header=Firefox Home
|
||||
prefs_content_discovery_description=Fia Content Discovery op de Firefox-startside kinne jo relevante artikelen op it hiele web mei hege kwaliteit fine.
|
||||
prefs_content_discovery_button=Content Discovery útskeakelje
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +149,6 @@ pocket_read_more=Populêre ûnderwerpen:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Mear ferhalen besjen
|
||||
pocket_more_reccommendations=Mear oanrekommandaasjes
|
||||
pocket_learn_more=Mear ynfo
|
||||
pocket_how_it_works=Hoe it wurket
|
||||
pocket_cta_button=Pocket brûke
|
||||
pocket_cta_text=Bewarje de ferhalen dy't jo ynteressant fine yn Pocket, en stimulearje jo tinzen mei boeiende lêsstof.
|
||||
|
@ -209,3 +213,4 @@ firstrun_skip_login=Dizze stap oerslaan
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menu iepenje
|
||||
section_menu_action_add_search_engine=Sykmasine tafoegje
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Leum seachad air seo
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Fosgail an clàr-taice
|
||||
section_menu_action_add_search_engine=Cuir einnsean-luirg ris
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Ignorar este paso
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menú
|
||||
section_menu_action_add_search_engine=Engadir buscador
|
||||
|
|
|
@ -211,3 +211,4 @@ firstrun_skip_login=Ehejánte kóva
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Eike poravorãme
|
||||
section_menu_action_add_search_engine=Embojuaju jehekaha mongu’eha
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=આ પગલું છોડી દો
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=મેનૂ ખોલો
|
||||
section_menu_action_add_search_engine=શોધ યંત્ર ઉમેરો
|
||||
|
|
|
@ -212,3 +212,4 @@ firstrun_skip_login=דילוג על שלב זה
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=פתיחת תפריט
|
||||
section_menu_action_add_search_engine=הוספת מנוע חיפוש
|
||||
|
|
|
@ -210,3 +210,4 @@ firstrun_skip_login=इस चरण को छोड़ दें
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=मेन्यू खोलें
|
||||
section_menu_action_add_search_engine=सर्च इंजन जोड़े
|
||||
|
|
|
@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=U redu, razumijem
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Firefox početni sadržaj
|
||||
prefs_home_description=Odaberite koji sadržaj želite na vašoj Firefox početnoj stranici.
|
||||
|
||||
prefs_content_discovery_header=Firefox početna stranica
|
||||
prefs_content_discovery_description=Otkrivanje sadržaja u Firefox početnoj stranici pomaže vam u otkrivanju visoko kvalitenih, relevantnih članaka diljem interneta.
|
||||
prefs_content_discovery_button=Uključite otkrivanje sadržaja
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -208,3 +213,4 @@ firstrun_skip_login=Preskočite ovaj korak
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Otvori izbornik
|
||||
section_menu_action_add_search_engine=Dodaj tražilicu
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Tutón krok přeskočić
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Meni wočinić
|
||||
section_menu_action_add_search_engine=Pytawu přidać
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Lépés kihagyása
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menü megnyitása
|
||||
section_menu_action_add_search_engine=Keresőszolgáltatás hozzáadása
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Saltar iste grado
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Aperir le menu
|
||||
section_menu_action_add_search_engine=Adder un motor de recerca
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Lewati langkah ini
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Buka menu
|
||||
section_menu_action_add_search_engine=Tambahkan Mesin Pencari
|
||||
|
|
|
@ -91,6 +91,10 @@ section_disclaimer_topstories_buttontext=Allt í lagi, ég skil
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Upphafssíða Firefox
|
||||
prefs_home_description=Veldu hvaða efni þú vilt á Firefox heimaskjánum þínum.
|
||||
|
||||
prefs_content_discovery_header=Upphafssíða Firefox
|
||||
prefs_content_discovery_button=Slökkva á efnisveitu
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -208,3 +212,4 @@ firstrun_skip_login=Sleppa þessu skrefi
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Opna valmynd
|
||||
section_menu_action_add_search_engine=Bæta við leitarvél
|
||||
|
|
|
@ -113,3 +113,4 @@ firstrun_privacy_notice=informativa sulla privacy
|
|||
firstrun_continue_to_login=Continua
|
||||
firstrun_skip_login=Ignora questo passaggio
|
||||
context_menu_title=Apri menu
|
||||
section_menu_action_add_search_engine=Aggiungi motore di ricerca
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_skip_login=この手順をスキップ
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=メニューを開きます
|
||||
section_menu_action_add_search_engine=検索エンジンを追加
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_skip_login=この手順をスキップ
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=メニューを開きます
|
||||
section_menu_action_add_search_engine=検索エンジンを追加
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=გამოტოვება
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=მენიუს გახსნა
|
||||
section_menu_action_add_search_engine=საძიებო სისტემის დამატება
|
||||
|
|
|
@ -93,6 +93,7 @@ prefs_home_header=Agbur agejdan Firefox
|
|||
prefs_home_description=Fren agbur i tebɣiḍ deg ugdil agejdan Firefox.
|
||||
|
||||
prefs_content_discovery_header=Asebter agejdan Firefox
|
||||
prefs_content_discovery_button=Sens asnirem n ubur
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
|
@ -211,3 +212,4 @@ firstrun_skip_login=Zgel amecwaṛ-agi
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Ldi umuɣ
|
||||
section_menu_action_add_search_engine=Rnu amsedday n unadi
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Бұл қадамды аттап кету
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Мәзірді ашу
|
||||
section_menu_action_add_search_engine=Іздеу жүйесін қосу
|
||||
|
|
|
@ -93,6 +93,8 @@ prefs_home_header=Firefox 홈 콘텐츠
|
|||
prefs_home_description=Firefox 홈 화면에 나올 콘텐츠를 선택하세요.
|
||||
|
||||
prefs_content_discovery_header=Firefox 홈
|
||||
prefs_content_discovery_description=Firefox 홈의 콘텐츠 탐색 기능을 사용하면 웹에 있는 고품질의 관련 문서를 탐색할 수 있습니다.
|
||||
prefs_content_discovery_button=콘텐츠 탐색 끄기
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
|
@ -211,3 +213,4 @@ firstrun_skip_login=단계 건너뛰기
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=메뉴 열기
|
||||
section_menu_action_add_search_engine=검색 엔진 추가
|
||||
|
|
|
@ -208,3 +208,4 @@ firstrun_privacy_notice=Informativa in sciâ privacy
|
|||
|
||||
firstrun_continue_to_login=Continoa
|
||||
firstrun_skip_login=Sata sto passo
|
||||
section_menu_action_add_search_engine=Azonzi motô de riçerca
|
||||
|
|
|
@ -207,3 +207,4 @@ firstrun_privacy_notice=ນະໂຍບາຍຄວາມເປັນສ່ວ
|
|||
|
||||
firstrun_continue_to_login=ສືບຕໍ່
|
||||
firstrun_skip_login=ຂ້າມຂັ້ນຕອນນີ້
|
||||
section_menu_action_add_search_engine=ເພີ່ມເຄື່ອງມືການຊອກຫາ
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Praleisti šį žingsnį
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Atverti meniu
|
||||
section_menu_action_add_search_engine=Pridėti ieškyklę
|
||||
|
|
|
@ -202,3 +202,4 @@ firstrun_privacy_notice=Privatuma pīzeime
|
|||
|
||||
firstrun_continue_to_login=Turpynōt
|
||||
firstrun_skip_login=Izlaist itū sūli
|
||||
section_menu_action_add_search_engine=Daīvīnōt mekleitōji
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Izlaist šo soli
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Atvērt izvēlni
|
||||
section_menu_action_add_search_engine=Pievienot meklētāju
|
||||
|
|
|
@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=ठीक आहे, समजले
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=फायरफॉक्स होम वरील मजकूर
|
||||
prefs_home_description=आपल्या फायरफॉक्सचा मुख्यपृष्ठवर आपल्याला कोणती माहिती पाहिजे ते निवडा.
|
||||
|
||||
prefs_content_discovery_header=Firefox मुख्यपृष्ठ
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -143,8 +146,9 @@ pocket_read_more=लोकप्रिय विषय:
|
|||
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=अधिक कथा पहा
|
||||
|
||||
pocket_learn_more=अधिक जाणा
|
||||
pocket_more_reccommendations=अधिक शिफारसी
|
||||
pocket_how_it_works=हे कसे कार्य करते
|
||||
pocket_cta_button=Pocket मिळवा
|
||||
|
||||
highlights_empty_state=ब्राउझिंग सुरू करा, आणि आम्ही आपल्याला इथे आपण अलीकडील भेट दिलेले किंवा वाचनखूण लावलेले उत्कृष्ठ लेख, व्हिडिओ, आणि इतर पृष्ठांपैकी काही दाखवू.
|
||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||
|
@ -193,7 +197,6 @@ firstrun_form_header=ईमेल प्रविष्ट करा
|
|||
firstrun_form_sub_header=Firefox Sync वर सुरू ठेवण्यासाठी
|
||||
|
||||
firstrun_email_input_placeholder=ईमेल
|
||||
|
||||
firstrun_invalid_input=वैध ईमेल आवश्यक
|
||||
|
||||
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||
|
@ -204,3 +207,7 @@ firstrun_privacy_notice=गोपनीयता सूचना
|
|||
|
||||
firstrun_continue_to_login=पुढे चला
|
||||
firstrun_skip_login=ही पायरी वगळा
|
||||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=मेनु उघडा
|
||||
section_menu_action_add_search_engine=शोध इंजीन जोडा
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Langkau langkah ini
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Buka menu
|
||||
section_menu_action_add_search_engine=Tambah Enjin Carian
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Hopp over dette trinnet
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Åpne meny
|
||||
section_menu_action_add_search_engine=Legg til søkemotor
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Deze stap overslaan
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menu openen
|
||||
section_menu_action_add_search_engine=Zoekmachine toevoegen
|
||||
|
|
|
@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=OK, eg forstår det!
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Innhald Firefox-startside
|
||||
prefs_home_description=Vel kva for innhald du vil ha på Firefox-startsida di.
|
||||
|
||||
prefs_content_discovery_header=Firefox startside
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +147,6 @@ pocket_read_more=Populære emne:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Vis fleire saker
|
||||
pocket_more_reccommendations=Fleire tilrådingar
|
||||
pocket_learn_more=Les meir
|
||||
pocket_how_it_works=Korleis det fungerar
|
||||
pocket_cta_button=Last ned Pocket
|
||||
pocket_cta_text=Lagre artiklane du synest er interessante i Pocket, og stimuler tankane dine med fasinerande lesemateriell.
|
||||
|
@ -209,3 +211,4 @@ firstrun_skip_login=Hopp over dette steget
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Opne meny
|
||||
section_menu_action_add_search_engine=Legg til søkjemotor
|
||||
|
|
|
@ -207,3 +207,4 @@ firstrun_skip_login=Passar aquesta etapa
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Dobrir lo menú
|
||||
section_menu_action_add_search_engine=Apondre un motor de recèrca
|
||||
|
|
|
@ -90,6 +90,9 @@ section_disclaimer_topstories_buttontext=ਠੀਕ ਹੈ, ਸਮਝ ਲਿਆ
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=ਫਾਇਰਫਾਕਸ ਮੁੱਖ ਪੰਨਾ
|
||||
prefs_home_description=ਉਹ ਸਮੱਗਰੀ ਚੁਣੋ ਜੋ ਤੁਸੀਂ ਆਪਣੇ ਫਾਇਰਫਾਕਸ ਮੁੱਖ ਪੰਨੇ 'ਤੇ ਚਾਹੁੰਦੇ ਹੋ।
|
||||
|
||||
prefs_content_discovery_header=ਫਾਇਰਫਾਕਸ ਮੁੱਖ ਸਫ਼ਾ
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -97,7 +100,7 @@ prefs_section_rows_option={num} ਕਤਾਰ;{num} ਕਤਾਰਾਂ
|
|||
prefs_search_header=ਵੈੱਬ ਖੋਜ
|
||||
prefs_topsites_description=ਤੁਹਾਡੇ ਵੱਲੋਂ ਸਭ ਤੋਂ ਵੱਧ ਵੇਖੀਆਂ ਸਾਈਟਾਂ
|
||||
prefs_topstories_description2=ਸਮੁੱਚੇ ਵੈੱਬ ਤੋਂ ਸ਼ਾਨਦਾਰ ਸਮੱਗਰੀ, ਤੁਹਾਡੇ ਲਈ ਵਿਅਕਤੀਗਤ ਹੈ
|
||||
prefs_topstories_options_sponsored_label=ਪ੍ਰਾਯੋਜਿਤ ਕਹਾਣੀਆਂ
|
||||
prefs_topstories_options_sponsored_label=ਸਪਾਂਸਰ ਕੀਤੀਆਂ ਕਹਾਣੀਆਂ
|
||||
prefs_topstories_sponsored_learn_more=ਹੋਰ ਜਾਣੋ
|
||||
prefs_highlights_description=ਉਹਨਾਂ ਸਾਈਟਾਂ ਦੀ ਚੋਣ ਕਰੋ ਜੋ ਤੁਸੀਂ ਸੁਰੱਖਿਅਤ ਜਾਂ ਵਿਜ਼ਿਟ ਕੀਤੀ ਹੈ
|
||||
prefs_highlights_options_visited_label=ਵੇਖੇ ਗਏ ਸਫੇ
|
||||
|
@ -129,7 +132,7 @@ topsites_form_image_url_label=URL ਕਸਟਮ ਚਿੱਤਰ
|
|||
topsites_form_url_placeholder=ਕੋਈ URL ਲਿਖੋ ਜਾਂ ਚੇਪੋ
|
||||
topsites_form_use_image_link=ਇੱਕ ਕਸਟਮ ਚਿੱਤਰ ਵਰਤੋ…
|
||||
# LOCALIZATION NOTE (topsites_form_*_button): These are verbs/actions.
|
||||
topsites_form_preview_button=ਪੂਰਵ ਦਰਸ਼ਨ
|
||||
topsites_form_preview_button=ਝਲਕ
|
||||
topsites_form_add_button=ਜੋੜੋ
|
||||
topsites_form_save_button=ਸੰਭਾਲੋ
|
||||
topsites_form_cancel_button=ਰੱਦ ਕਰੋ
|
||||
|
@ -143,7 +146,6 @@ pocket_read_more=ਪ੍ਰਸਿੱਧ ਵਿਸ਼ੇ:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=ਹੋਰ ਕਹਾਣੀਆਂ ਵੇਖੋ
|
||||
pocket_more_reccommendations=ਹੋਰ ਸਿਫਾਰਸ਼ਾਂ
|
||||
pocket_learn_more=ਹੋਰ ਸਿੱਖੋ
|
||||
pocket_how_it_works=ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦੀ ਹੈ
|
||||
pocket_cta_button=ਪਾਕੇਟ ਲਵੋ
|
||||
|
||||
|
@ -170,7 +172,7 @@ error_fallback_default_refresh_suggestion=ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ
|
|||
section_menu_action_remove_section=ਸੈਕਸ਼ਨ ਹਟਾਓ
|
||||
section_menu_action_collapse_section=ਸੈਕਸ਼ਨ ਨੂੰ ਸਮੇਟੋ
|
||||
section_menu_action_expand_section=ਸੈਕਸ਼ਨ ਦੀ ਫੈਲਾਓ
|
||||
section_menu_action_manage_section=ਸੈਕਸ਼ਨ ਦਾ ਪ੍ਰਬੰਧ ਕਰੋ
|
||||
section_menu_action_manage_section=ਸੈਕਸ਼ਨ ਦਾ ਬੰਦੋਬਸਤ
|
||||
section_menu_action_manage_webext=ਇਕਸਟੈਨਸ਼ਨਾਂ ਦਾ ਇੰਤਜ਼ਾਮ
|
||||
section_menu_action_add_topsite=ਚੋਟੀ ਦੀਆਂ ਸਾਈਟਾਂ ਜੋੜੋ
|
||||
section_menu_action_add_search_engine=ਖੋਜ ਇੰਜਣ ਜੋੜੋ
|
||||
|
@ -204,3 +206,4 @@ firstrun_skip_login=ਇਹ ਪਗ਼ ਛੱਡੋ
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=ਮੇਨੂ ਖੋਲ੍ਹੋ
|
||||
section_menu_action_add_search_engine=ਖੋਜ ਇੰਜਣ ਜੋੜੋ
|
||||
|
|
|
@ -125,3 +125,4 @@ firstrun_continue_to_login=Kontynuuj
|
|||
firstrun_skip_login=Pomiń
|
||||
|
||||
context_menu_title=Otwórz menu
|
||||
section_menu_action_add_search_engine=Dodaj wyszukiwarkę
|
||||
|
|
|
@ -100,7 +100,7 @@ prefs_content_discovery_button=Desativar descoberta de conteúdo
|
|||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
prefs_section_rows_option={num} linha;{num} linhas
|
||||
prefs_search_header=Pesquisa na web
|
||||
prefs_search_header=Pesquisar na web
|
||||
prefs_topsites_description=Os sites que você mais visita
|
||||
prefs_topstories_description2=Os melhores conteúdos disponíveis na Web, personalizados pra você
|
||||
prefs_topstories_options_sponsored_label=Histórias patrocinadas
|
||||
|
@ -213,3 +213,4 @@ firstrun_skip_login=Pular essa etapa
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menu
|
||||
section_menu_action_add_search_engine=Adicionar mecanismo de busca
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Saltar este passo
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Abrir menu
|
||||
section_menu_action_add_search_engine=Adicionar motor de pesquisa
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Sursiglir quest pass
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Avrir il menu
|
||||
section_menu_action_add_search_engine=Agiuntar questa maschina da tschertgar
|
||||
|
|
|
@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Ok, am înțeles
|
|||
# what is shown for the homepage, new windows, and new tabs.
|
||||
prefs_home_header=Conținutul paginii de start Firefox
|
||||
prefs_home_description=Alege ce conținut vrei pe ecranul de start Firefox.
|
||||
|
||||
prefs_content_discovery_header=Pagina de start Firefox
|
||||
prefs_content_discovery_description=Descoperirea de conținut din pagina de start Firefox îți permite să descoperi articole relevante de calitate înaltă de pe web.
|
||||
prefs_content_discovery_button=Dezactivează descoperirea de conținut
|
||||
|
||||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -144,7 +149,6 @@ pocket_read_more=Subiecte populare:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Vezi mai multe articole
|
||||
pocket_more_reccommendations=Mai multe recomandări
|
||||
pocket_learn_more=Află mai multe
|
||||
pocket_how_it_works=Cum funcționează
|
||||
pocket_cta_button=Obține Pocket
|
||||
pocket_cta_text=Salvează în Pocket articolele care ți-au plăcut și hrănește-ți mintea cu lecturi fascinante.
|
||||
|
@ -209,3 +213,4 @@ firstrun_skip_login=Omite acest pas
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Deschide meniul
|
||||
section_menu_action_add_search_engine=Adaugă motor de căutare
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Пропустить этот шаг
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Открыть меню
|
||||
section_menu_action_add_search_engine=Добавить поисковую систему
|
||||
|
|
|
@ -209,3 +209,4 @@ firstrun_skip_login=Preskočiť tento krok
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Otvorí ponuku
|
||||
section_menu_action_add_search_engine=Pridať vyhľadávací modul
|
||||
|
|
|
@ -213,3 +213,4 @@ firstrun_skip_login=Preskoči ta korak
|
|||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Odpri meni
|
||||
section_menu_action_add_search_engine=Dodaj iskalnik
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче