Bug 1499886 - Add send-to-device snippet, right-to-left robustness and bug fixes to Activity Stream r=k88hudson

Differential Revision: https://phabricator.services.mozilla.com/D9045

--HG--
rename : browser/components/newtab/locales/ach/strings.properties => browser/components/newtab/locales-src/ach/strings.properties
rename : browser/components/newtab/locales/an/strings.properties => browser/components/newtab/locales-src/an/strings.properties
rename : browser/components/newtab/locales/ar/strings.properties => browser/components/newtab/locales-src/ar/strings.properties
rename : browser/components/newtab/locales/ast/strings.properties => browser/components/newtab/locales-src/ast/strings.properties
rename : browser/components/newtab/locales/az/strings.properties => browser/components/newtab/locales-src/az/strings.properties
rename : browser/components/newtab/locales/be/strings.properties => browser/components/newtab/locales-src/be/strings.properties
rename : browser/components/newtab/locales/bg/strings.properties => browser/components/newtab/locales-src/bg/strings.properties
rename : browser/components/newtab/locales/bn-BD/strings.properties => browser/components/newtab/locales-src/bn-BD/strings.properties
rename : browser/components/newtab/locales/bn-IN/strings.properties => browser/components/newtab/locales-src/bn-IN/strings.properties
rename : browser/components/newtab/locales/br/strings.properties => browser/components/newtab/locales-src/br/strings.properties
rename : browser/components/newtab/locales/bs/strings.properties => browser/components/newtab/locales-src/bs/strings.properties
rename : browser/components/newtab/locales/ca/strings.properties => browser/components/newtab/locales-src/ca/strings.properties
rename : browser/components/newtab/locales/cak/strings.properties => browser/components/newtab/locales-src/cak/strings.properties
rename : browser/components/newtab/locales/crh/strings.properties => browser/components/newtab/locales-src/crh/strings.properties
rename : browser/components/newtab/locales/cs/strings.properties => browser/components/newtab/locales-src/cs/strings.properties
rename : browser/components/newtab/locales/cy/strings.properties => browser/components/newtab/locales-src/cy/strings.properties
rename : browser/components/newtab/locales/da/strings.properties => browser/components/newtab/locales-src/da/strings.properties
rename : browser/components/newtab/locales/de/strings.properties => browser/components/newtab/locales-src/de/strings.properties
rename : browser/components/newtab/locales/dsb/strings.properties => browser/components/newtab/locales-src/dsb/strings.properties
rename : browser/components/newtab/locales/el/strings.properties => browser/components/newtab/locales-src/el/strings.properties
rename : browser/components/newtab/locales/en-CA/strings.properties => browser/components/newtab/locales-src/en-CA/strings.properties
rename : browser/components/newtab/locales/en-GB/strings.properties => browser/components/newtab/locales-src/en-GB/strings.properties
rename : browser/components/newtab/locales/en-US/strings.properties => browser/components/newtab/locales-src/en-US/strings.properties
rename : browser/components/newtab/locales/eo/strings.properties => browser/components/newtab/locales-src/eo/strings.properties
rename : browser/components/newtab/locales/es-AR/strings.properties => browser/components/newtab/locales-src/es-AR/strings.properties
rename : browser/components/newtab/locales/es-CL/strings.properties => browser/components/newtab/locales-src/es-CL/strings.properties
rename : browser/components/newtab/locales/es-ES/strings.properties => browser/components/newtab/locales-src/es-ES/strings.properties
rename : browser/components/newtab/locales/es-MX/strings.properties => browser/components/newtab/locales-src/es-MX/strings.properties
rename : browser/components/newtab/locales/et/strings.properties => browser/components/newtab/locales-src/et/strings.properties
rename : browser/components/newtab/locales/eu/strings.properties => browser/components/newtab/locales-src/eu/strings.properties
rename : browser/components/newtab/locales/fa/strings.properties => browser/components/newtab/locales-src/fa/strings.properties
rename : browser/components/newtab/locales/ff/strings.properties => browser/components/newtab/locales-src/ff/strings.properties
rename : browser/components/newtab/locales/fi/strings.properties => browser/components/newtab/locales-src/fi/strings.properties
rename : browser/components/newtab/locales/fr/strings.properties => browser/components/newtab/locales-src/fr/strings.properties
rename : browser/components/newtab/locales/fy-NL/strings.properties => browser/components/newtab/locales-src/fy-NL/strings.properties
rename : browser/components/newtab/locales/ga-IE/strings.properties => browser/components/newtab/locales-src/ga-IE/strings.properties
rename : browser/components/newtab/locales/gd/strings.properties => browser/components/newtab/locales-src/gd/strings.properties
rename : browser/components/newtab/locales/gl/strings.properties => browser/components/newtab/locales-src/gl/strings.properties
rename : browser/components/newtab/locales/gn/strings.properties => browser/components/newtab/locales-src/gn/strings.properties
rename : browser/components/newtab/locales/gu-IN/strings.properties => browser/components/newtab/locales-src/gu-IN/strings.properties
rename : browser/components/newtab/locales/he/strings.properties => browser/components/newtab/locales-src/he/strings.properties
rename : browser/components/newtab/locales/hi-IN/strings.properties => browser/components/newtab/locales-src/hi-IN/strings.properties
rename : browser/components/newtab/locales/hr/strings.properties => browser/components/newtab/locales-src/hr/strings.properties
rename : browser/components/newtab/locales/hsb/strings.properties => browser/components/newtab/locales-src/hsb/strings.properties
rename : browser/components/newtab/locales/hu/strings.properties => browser/components/newtab/locales-src/hu/strings.properties
rename : browser/components/newtab/locales/hy-AM/strings.properties => browser/components/newtab/locales-src/hy-AM/strings.properties
rename : browser/components/newtab/locales/ia/strings.properties => browser/components/newtab/locales-src/ia/strings.properties
rename : browser/components/newtab/locales/id/strings.properties => browser/components/newtab/locales-src/id/strings.properties
rename : browser/components/newtab/locales/is/strings.properties => browser/components/newtab/locales-src/is/strings.properties
rename : browser/components/newtab/locales/it/strings.properties => browser/components/newtab/locales-src/it/strings.properties
rename : browser/components/newtab/locales/ja-JP-mac/strings.properties => browser/components/newtab/locales-src/ja-JP-mac/strings.properties
rename : browser/components/newtab/locales/ja/strings.properties => browser/components/newtab/locales-src/ja/strings.properties
rename : browser/components/newtab/locales/ka/strings.properties => browser/components/newtab/locales-src/ka/strings.properties
rename : browser/components/newtab/locales/kab/strings.properties => browser/components/newtab/locales-src/kab/strings.properties
rename : browser/components/newtab/locales/kk/strings.properties => browser/components/newtab/locales-src/kk/strings.properties
rename : browser/components/newtab/locales/km/strings.properties => browser/components/newtab/locales-src/km/strings.properties
rename : browser/components/newtab/locales/kn/strings.properties => browser/components/newtab/locales-src/kn/strings.properties
rename : browser/components/newtab/locales/ko/strings.properties => browser/components/newtab/locales-src/ko/strings.properties
rename : browser/components/newtab/locales/lij/strings.properties => browser/components/newtab/locales-src/lij/strings.properties
rename : browser/components/newtab/locales/lo/strings.properties => browser/components/newtab/locales-src/lo/strings.properties
rename : browser/components/newtab/locales/lt/strings.properties => browser/components/newtab/locales-src/lt/strings.properties
rename : browser/components/newtab/locales/ltg/strings.properties => browser/components/newtab/locales-src/ltg/strings.properties
rename : browser/components/newtab/locales/lv/strings.properties => browser/components/newtab/locales-src/lv/strings.properties
rename : browser/components/newtab/locales/mai/strings.properties => browser/components/newtab/locales-src/mai/strings.properties
rename : browser/components/newtab/locales/mk/strings.properties => browser/components/newtab/locales-src/mk/strings.properties
rename : browser/components/newtab/locales/ml/strings.properties => browser/components/newtab/locales-src/ml/strings.properties
rename : browser/components/newtab/locales/mr/strings.properties => browser/components/newtab/locales-src/mr/strings.properties
rename : browser/components/newtab/locales/ms/strings.properties => browser/components/newtab/locales-src/ms/strings.properties
rename : browser/components/newtab/locales/my/strings.properties => browser/components/newtab/locales-src/my/strings.properties
rename : browser/components/newtab/locales/nb-NO/strings.properties => browser/components/newtab/locales-src/nb-NO/strings.properties
rename : browser/components/newtab/locales/ne-NP/strings.properties => browser/components/newtab/locales-src/ne-NP/strings.properties
rename : browser/components/newtab/locales/nl/strings.properties => browser/components/newtab/locales-src/nl/strings.properties
rename : browser/components/newtab/locales/nn-NO/strings.properties => browser/components/newtab/locales-src/nn-NO/strings.properties
rename : browser/components/newtab/locales/oc/strings.properties => browser/components/newtab/locales-src/oc/strings.properties
rename : browser/components/newtab/locales/pa-IN/strings.properties => browser/components/newtab/locales-src/pa-IN/strings.properties
rename : browser/components/newtab/locales/pl/strings.properties => browser/components/newtab/locales-src/pl/strings.properties
rename : browser/components/newtab/locales/pt-BR/strings.properties => browser/components/newtab/locales-src/pt-BR/strings.properties
rename : browser/components/newtab/locales/pt-PT/strings.properties => browser/components/newtab/locales-src/pt-PT/strings.properties
rename : browser/components/newtab/locales/rm/strings.properties => browser/components/newtab/locales-src/rm/strings.properties
rename : browser/components/newtab/locales/ro/strings.properties => browser/components/newtab/locales-src/ro/strings.properties
rename : browser/components/newtab/locales/ru/strings.properties => browser/components/newtab/locales-src/ru/strings.properties
rename : browser/components/newtab/locales/si/strings.properties => browser/components/newtab/locales-src/si/strings.properties
rename : browser/components/newtab/locales/sk/strings.properties => browser/components/newtab/locales-src/sk/strings.properties
rename : browser/components/newtab/locales/sl/strings.properties => browser/components/newtab/locales-src/sl/strings.properties
rename : browser/components/newtab/locales/sq/strings.properties => browser/components/newtab/locales-src/sq/strings.properties
rename : browser/components/newtab/locales/sr/strings.properties => browser/components/newtab/locales-src/sr/strings.properties
rename : browser/components/newtab/locales/sv-SE/strings.properties => browser/components/newtab/locales-src/sv-SE/strings.properties
rename : browser/components/newtab/locales/ta/strings.properties => browser/components/newtab/locales-src/ta/strings.properties
rename : browser/components/newtab/locales/te/strings.properties => browser/components/newtab/locales-src/te/strings.properties
rename : browser/components/newtab/locales/th/strings.properties => browser/components/newtab/locales-src/th/strings.properties
rename : browser/components/newtab/locales/tl/strings.properties => browser/components/newtab/locales-src/tl/strings.properties
rename : browser/components/newtab/locales/tr/strings.properties => browser/components/newtab/locales-src/tr/strings.properties
rename : browser/components/newtab/locales/uk/strings.properties => browser/components/newtab/locales-src/uk/strings.properties
rename : browser/components/newtab/locales/ur/strings.properties => browser/components/newtab/locales-src/ur/strings.properties
rename : browser/components/newtab/locales/uz/strings.properties => browser/components/newtab/locales-src/uz/strings.properties
rename : browser/components/newtab/locales/vi/strings.properties => browser/components/newtab/locales-src/vi/strings.properties
rename : browser/components/newtab/locales/zh-CN/strings.properties => browser/components/newtab/locales-src/zh-CN/strings.properties
rename : browser/components/newtab/locales/zh-TW/strings.properties => browser/components/newtab/locales-src/zh-TW/strings.properties
extra : moz-landing-system : lando
This commit is contained in:
Ed Lee 2018-10-18 05:00:47 +00:00
Родитель 055117366d
Коммит a8fe89d2f5
444 изменённых файлов: 1829 добавлений и 938 удалений

Просмотреть файл

@ -189,7 +189,7 @@ module.exports = {
"no-void": 2,
"no-warning-comments": 0, // TODO: Change to `1`?
"nonblock-statement-body-position": 2,
"object-curly-newline": [2, {"multiline": true}],
"object-curly-newline": [2, {"multiline": true, "consistent": true}],
"object-curly-spacing": [2, "never"],
"object-property-newline": [2, {"allowMultiplePropertiesPerLine": true}],
"one-var": [2, "never"],

Просмотреть файл

@ -17,7 +17,7 @@ rules:
mixins-before-declarations: [2, {exclude: [breakpoint, mq]}]
nesting-depth: [2, {max-depth: 4}]
no-debug: 1
no-disallowed-properties: [1, {properties: [text-transform]}]
no-disallowed-properties: [1, {properties: [margin-left, margin-right, text-transform]}]
no-duplicate-properties: 2
no-misspelled-properties: [2, {extra-properties: [-moz-context-properties]}]
no-url-domains: 0

Просмотреть файл

@ -1,2 +1,2 @@
# flod as main contact for string changes
locales/en-US/strings.properties @flodolo
locales-src/en-US/strings.properties @flodolo

Просмотреть файл

@ -1,4 +1,10 @@
exports.DEFAULT_LOCALE = "en-US";
if (!process.env.npm_lifecycle_event) {
throw Error("You should only run this from npm script contexts");
}
exports.DEFAULT_LOCALE = process.env.npm_package_config_default_locale;
exports.LOCALES_SOURCE_DIRECTORY = process.env.npm_package_config_locales_dir;
// This locales list is to find any similar locales that we can reuse strings
// instead of falling back to the default, e.g., use bn-BD strings for bn-IN.

Просмотреть файл

@ -7,7 +7,7 @@ const fetch = require("node-fetch");
/* globals cd, ls, mkdir, rm, ShellString */
require("shelljs/global");
const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
const {CENTRAL_LOCALES, DEFAULT_LOCALE, LOCALES_SOURCE_DIRECTORY} = require("./locales");
const L10N_CENTRAL = "https://hg.mozilla.org/l10n-central";
const PROPERTIES_PATH = "raw-file/default/browser/chrome/browser/activity-stream/newtab.properties";
const STRINGS_FILE = "strings.properties";
@ -74,9 +74,9 @@ async function saveProperties(locale) {
// Replace and update each locale's strings
async function updateLocales() {
console.log("Switching to and deleting existing l10n tree under: locales");
console.log(`Switching to and deleting existing l10n tree under: ${LOCALES_SOURCE_DIRECTORY}`);
cd("locales");
cd(LOCALES_SOURCE_DIRECTORY);
ls().forEach(dir => {
// Keep the default/source locale as it might have newer strings
if (dir !== DEFAULT_LOCALE) {

Просмотреть файл

@ -6,6 +6,7 @@ import {LocalizationProvider} from "fluent-react";
import {OnboardingMessage} from "./templates/OnboardingMessage/OnboardingMessage";
import React from "react";
import ReactDOM from "react-dom";
import {SendToDeviceSnippet} from "./templates/SendToDeviceSnippet/SendToDeviceSnippet";
import {SimpleSnippet} from "./templates/SimpleSnippet/SimpleSnippet";
import {SubmitFormSnippet} from "./templates/SubmitFormSnippet/SubmitFormSnippet";
@ -14,6 +15,7 @@ const SnippetComponents = {
simple_snippet: SimpleSnippet,
newsletter_snippet: props => <SubmitFormSnippet {...props} form_method="POST" />,
fxa_signup_snippet: props => <SubmitFormSnippet {...props} form_method="GET" />,
send_to_device_snippet: SendToDeviceSnippet,
};
const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
@ -129,7 +131,7 @@ export class ASRouterUISurface extends React.PureComponent {
if (action.type) {
ASRouterUtils.executeAction(action);
}
if (!this.state.message.content.do_not_autoblock) {
if (!this.state.message.content.do_not_autoblock && !event.target.dataset.do_not_autoblock) {
ASRouterUtils.blockById(this.state.message.id);
}
if (this.state.message.provider !== "preview") {

Просмотреть файл

@ -1,4 +1,5 @@
.ASRouterButton {
font-weight: bold;
white-space: nowrap;
border-radius: 4px;
border: 1px solid var(--newtab-border-secondary-color);
@ -14,7 +15,7 @@
}
&.primary {
border: 1px solid var(--newtab-border-primary-color);
border: 1px solid var(--newtab-button-primary-color);
background-color: var(--newtab-button-primary-color);
color: $grey-10;
}

Просмотреть файл

@ -21,9 +21,9 @@
.modalOverlayInner {
width: 960px;
height: 510px;
height: 570px;
position: fixed;
top: calc(50% - 255px); // halfway down minus half the height of the modal
top: calc(50% - 285px); // halfway down minus half the height of the modal
left: calc(50% - 480px); // halfway across minus half the width of the modal
background: $white;
box-shadow: 0 1px 15px 0 $black-30;
@ -95,9 +95,9 @@
.modalButton {
margin-top: 20px;
width: 150px;
min-width: 150px;
height: 30px;
padding: 4px 0 6px;
padding: 4px 30px 6px;
font-size: 15px;
&:focus,

Просмотреть файл

@ -17,7 +17,7 @@ const ALLOWED_TAGS = {
* Transform an object (tag name: {url}) into (tag name: anchor) where the url
* is used as href, in order to render links inside a Fluent.Localized component.
*/
export function convertLinks(links, sendClick) {
export function convertLinks(links, sendClick, autoBlock) {
if (links) {
return Object.keys(links).reduce((acc, linkTag) => {
const {action} = links[linkTag];
@ -25,9 +25,11 @@ export function convertLinks(links, sendClick) {
const url = action ? false : safeURI(links[linkTag].url);
acc[linkTag] = (<a href={url}
target={autoBlock === false ? "_blank" : ""}
data-metric={links[linkTag].metric}
data-action={action}
data-args={links[linkTag].args}
data-do_not_autoblock={autoBlock === false}
onClick={sendClick} />);
return acc;
}, {});
@ -44,7 +46,7 @@ export function RichText(props) {
throw new Error(`ASRouter: ${props.localization_id} is not a valid rich text property. If you want it to be processed, you need to add it to asrouter/rich-text-strings.js`);
}
return (
<Localized id={props.localization_id} {...ALLOWED_TAGS} {...convertLinks(props.links, props.sendClick)}>
<Localized id={props.localization_id} {...ALLOWED_TAGS} {...convertLinks(props.links, props.sendClick, props.autoBlock)}>
<span>{props.text}</span>
</Localized>
);

Просмотреть файл

@ -15,6 +15,10 @@
a {
cursor: pointer;
color: var(--newtab-link-primary-color);
[lwt-newtab-brighttext] & {
font-weight: bold;
}
}
.innerWrapper {

Просмотреть файл

@ -27,6 +27,7 @@ Please note that some targeting attributes require stricter controls on the tele
* [topFrecentSites](#topfrecentsites)
* [totalBookmarksCount](#totalbookmarkscount)
* [xpinstallEnabled](#xpinstallEnabled)
* [needsUpdate](#needsupdate)
## Detailed usage
@ -384,3 +385,11 @@ Pref used by system administrators to disallow add-ons from installed altogether
```ts
declare const xpinstallEnabled: boolean;
```
### `needsUpdate`
Does the client have the latest available version installed
```ts
declare const needsUpdate: boolean;
```

Просмотреть файл

@ -8,6 +8,7 @@ import {MessageContext} from "fluent";
const RICH_TEXT_CONFIG = {
"text": ["text", "scene1_text"],
"privacy_html": "scene2_privacy_html",
"disclaimer_html": "scene2_disclaimer_html",
};
export const RICH_TEXT_KEYS = Object.keys(RICH_TEXT_CONFIG);

Просмотреть файл

@ -100,13 +100,14 @@
> span > p {
color: $grey-60;
margin-top: 0;
height: 130px;
height: 180px;
margin-bottom: 12px;
font-size: 15px;
line-height: 22px;
@media(max-width: 650px) {
margin-bottom: 0;
height: 160px;
}
}
}
@ -123,13 +124,12 @@
// at 850px, the button shimmies down and to the right
@media(max-width: 850px) {
float: right;
margin-top: -60px;
margin-right: -10px;
margin-top: -105px;
margin-inline-end: -10px;
}
@media(max-width: 650px) {
float: none;
margin-top: 30px;
}
&:focus,
@ -143,12 +143,12 @@
&::before {
content: '';
height: 220px;
height: 230px;
width: 1px;
position: absolute;
background-color: $grey-30;
margin-top: 40px;
margin-left: 215px;
margin-inline-start: 215px;
// at 850px, the line goes from vertical to horizontal
@media(max-width: 850px) {

Просмотреть файл

@ -0,0 +1,37 @@
import {isEmailOrPhoneNumber} from "./isEmailOrPhoneNumber";
import React from "react";
import {SubmitFormSnippet} from "../SubmitFormSnippet/SubmitFormSnippet.jsx";
function validateInput(value, content) {
const type = isEmailOrPhoneNumber(value, content);
return type ? "" : "Must be an email or a phone number.";
}
function processFormData(input, message) {
const {content} = message;
const type = content.include_sms ? isEmailOrPhoneNumber(input.value, content) : "email";
const formData = new FormData();
let url;
if (type === "phone") {
url = "https://basket.mozilla.org/news/subscribe_sms/";
formData.append("mobile_number", input.value);
formData.append("msg_name", content.message_id_sms);
formData.append("country", content.country);
} else if (type === "email") {
url = "https://basket.mozilla.org/news/subscribe/";
formData.append("email", input.value);
formData.append("newsletters", content.message_id_email);
formData.append("source_url", encodeURIComponent(`https://snippets.mozilla.com/show/${message.id}`));
}
formData.append("lang", content.locale);
return {formData, url};
}
export const SendToDeviceSnippet = props => (
<SubmitFormSnippet {...props}
form_method="POST"
className="send_to_device_snippet"
inputType={props.content.include_sms ? "text" : "email"}
validateInput={props.content.include_sms ? validateInput : null}
processFormData={processFormData} />
);

Просмотреть файл

@ -0,0 +1,34 @@
/**
* Checks if a given string is an email or phone number or neither
* @param {string} val The user input
* @param {ASRMessageContent} content .content property on ASR message
* @returns {"email"|"phone"|""} The type of the input
*/
export function isEmailOrPhoneNumber(val, content) {
const {locale} = content;
// http://emailregex.com/
const email_re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const check_email = email_re.test(val);
let check_phone; // depends on locale
switch (locale) {
case "en-US":
case "en-CA":
// allow 10-11 digits in case user wants to enter country code
check_phone = val.length >= 10 && val.length <= 11 && !isNaN(val);
break;
case "de":
// allow between 2 and 12 digits for german phone numbers
check_phone = val.length >= 2 && val.length <= 12 && !isNaN(val);
break;
// this case should never be hit, but good to have a fallback just in case
default:
check_phone = !isNaN(val);
break;
}
if (check_email) {
return "email";
} else if (check_phone) {
return "phone";
}
return "";
}

Просмотреть файл

@ -16,9 +16,12 @@ export class SimpleSnippet extends React.PureComponent {
if (this.props.provider !== "preview") {
this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", id: this.props.UISurface});
}
const {button_url} = this.props.content;
// If button_url is defined handle it as OPEN_URL action
const type = this.props.content.button_action || (button_url && "OPEN_URL");
this.props.onAction({
type: this.props.content.button_action,
data: {args: this.props.content.button_action_args},
type,
data: {args: this.props.content.button_action_args || button_url},
});
if (!this.props.content.do_not_autoblock) {
this.props.onBlock();
@ -37,7 +40,7 @@ export class SimpleSnippet extends React.PureComponent {
renderButton() {
const {props} = this;
if (!props.content.button_action && !props.onButtonClick) {
if (!props.content.button_action && !props.onButtonClick && !props.content.button_url) {
return null;
}

Просмотреть файл

@ -43,6 +43,12 @@
"type": "string",
"description": "The type of action the button should trigger."
},
"button_url": {
"allOf": [
{"$ref": "#/definitions/link_url"},
{"description": "A url, button_label links to this"}
]
},
"button_action_args": {
"type": "string",
"description": "Additional parameters for button action, example which specific menu the button should open"
@ -95,7 +101,8 @@
"additionalProperties": false,
"required": ["text"],
"dependencies": {
"button_label": ["button_action"],
"button_action": ["button_label"],
"button_url": ["button_label"],
"button_color": ["button_label"],
"button_background_color": ["button_label"]
}

Просмотреть файл

@ -1,3 +1,4 @@
import {Button} from "../../components/Button/Button";
import React from "react";
import {RichText} from "../../components/RichText/RichText";
import {SimpleSnippet} from "../SimpleSnippet/SimpleSnippet";
@ -8,6 +9,7 @@ export class SubmitFormSnippet extends React.PureComponent {
super(props);
this.expandSnippet = this.expandSnippet.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onInputChange = this.onInputChange.bind(this);
this.state = {
expanded: false,
signupSubmitted: false,
@ -32,23 +34,24 @@ export class SubmitFormSnippet extends React.PureComponent {
return;
}
const fetchConfig = {
body: new FormData(this.refs.form),
method: "POST",
};
const {url, formData} = this.props.processFormData ?
this.props.processFormData(this.refs.mainInput, this.props) :
{url: this.refs.form.action, formData: new FormData(this.refs.form)};
try {
const fetchRequest = new Request(this.refs.form.action, fetchConfig);
const fetchRequest = new Request(url, {body: formData, method: "POST"});
const response = await fetch(fetchRequest);
json = await response.json();
} catch (err) {
console.log(err); // eslint-disable-line no-console
}
if (json && json.status === "ok") {
this.setState({signupSuccess: true, signupSubmitted: true});
this.props.onBlock({preventDismiss: true});
this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", value: "subscribe-success", id: "NEWTAB_FOOTER_BAR_CONTENT"});
} else {
console.error("There was a problem submitting the form", json || "[No JSON response]"); // eslint-disable-line no-console
this.setState({signupSuccess: false, signupSubmitted: true});
this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", value: "subscribe-error", id: "NEWTAB_FOOTER_BAR_CONTENT"});
}
@ -74,17 +77,32 @@ export class SubmitFormSnippet extends React.PureComponent {
return Object.keys(hidden_inputs).map((key, idx) => <input key={idx} type="hidden" name={key} value={hidden_inputs[key]} />);
}
renderDisclaimer() {
const {content} = this.props;
if (!content.scene2_disclaimer_html) {
return null;
}
return (<p className="disclaimerText">
<RichText text={content.scene2_disclaimer_html}
localization_id="disclaimer_html"
links={content.links}
autoBlock={false}
sendClick={this.props.sendClick} />
</p>);
}
renderFormPrivacyNotice() {
const {content} = this.props;
if (!content.scene2_privacy_html) {
return null;
}
return (<label className="privacy-notice" htmlFor="id_privacy">
return (<label className="privacyNotice" htmlFor="id_privacy">
<p>
<input type="checkbox" id="id_privacy" name="privacy" required="required" />
<span><RichText text={content.scene2_privacy_html}
localization_id="privacy_html"
links={content.links}
autoBlock={false}
sendClick={this.props.sendClick} />
</span>
</p>
@ -92,29 +110,53 @@ export class SubmitFormSnippet extends React.PureComponent {
}
renderSignupSubmitted() {
const message = this.state.signupSuccess ? this.props.content.success_text : this.props.content.error_text;
const onButtonClick = !this.state.signupSuccess ? this.expandSnippet : null;
const {content} = this.props;
const isSuccess = this.state.signupSuccess;
const successTitle = isSuccess && content.success_title;
const bodyText = isSuccess ? content.success_text : content.error_text;
const retryButtonText = content.scene1_button_label;
return (<SnippetBase {...this.props}><div className="submissionStatus">
{successTitle ? <h2 className="submitStatusTitle">{successTitle}</h2> : null}
<p>{bodyText}{isSuccess ? null : <Button onClick={this.expandSnippet}>{retryButtonText}</Button>}</p>
</div></SnippetBase>);
}
return (<SimpleSnippet className={this.props.className}
onButtonClick={onButtonClick}
provider={this.props.provider}
content={{button_label: this.props.content.scene1_button_label, text: message}} />);
onInputChange(event) {
if (!this.props.validateInput) {
return;
}
const hasError = this.props.validateInput(event.target.value, this.props.content);
event.target.setCustomValidity(hasError);
}
renderInput() {
const placholder = this.props.content.scene2_email_placeholder_text || this.props.content.scene2_input_placeholder;
return (<input
ref="mainInput"
type={this.props.inputType || "email"}
className="mainInput"
name="email"
required={true}
placeholder={placholder}
onChange={this.props.validateInput ? this.onInputChange : null}
autoFocus={true} />);
}
renderSignupView() {
const {content} = this.props;
return (<SnippetBase {...this.props} className="SubmitFormSnippet" footerDismiss={true}>
const containerClass = `SubmitFormSnippet ${this.props.className}`;
return (<SnippetBase {...this.props} className={containerClass} footerDismiss={true}>
{content.scene2_icon ? <div className="scene2Icon"><img src={content.scene2_icon} /></div> : null}
<div className="message">
<p>{content.scene2_text}</p>
</div>
<form action={content.form_action} method={this.props.form_method} onSubmit={this.handleSubmit} ref="form">
{this.renderHiddenFormInputs()}
<div>
<input type="email" name="email" required="required" placeholder={content.scene2_email_placeholder_text} autoFocus={true} />
{this.renderInput()}
<button type="submit" className="ASRouterButton primary" ref="formSubmitBtn">{content.scene2_button_label}</button>
</div>
{this.renderFormPrivacyNotice()}
{this.renderFormPrivacyNotice() || this.renderDisclaimer()}
</form>
</SnippetBase>);
}

Просмотреть файл

@ -19,9 +19,17 @@
}
},
"properties": {
"locale": {
"type": "string",
"description": "Two to five character string for the locale code"
},
"country": {
"type": "string",
"description": "Two character string for the country code (used for SMS)"
},
"scene1_title": {
"allof": [
{"$ref": "#/definitions/plaintext"},
{"$ref": "#/definitions/plainText"},
{"description": "snippet title displayed before snippet text"}
]
},
@ -31,6 +39,12 @@
{"description": "Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}
]
},
"scene2_title": {
"allOf": [
{"$ref": "#/definitions/plainText"},
{"description": "Title displayed before text in scene 2. Should be plain text."}
]
},
"scene2_text": {
"allOf": [
{"$ref": "#/definitions/richText"},
@ -49,6 +63,10 @@
"type": "string",
"description": "Endpoint to submit form data."
},
"success_title": {
"type": "string",
"description": "(send to device) Title shown before text on successful registration."
},
"success_text": {
"type": "string",
"description": "Message shown on successful registration."
@ -61,6 +79,10 @@
"type": "string",
"description": "Value to show while input is empty."
},
"scene2_input_placeholder": {
"type": "string",
"description": "(send to device) Value to show while input is empty."
},
"scene2_button_label": {
"type": "string",
"description": "Label for form submit button"
@ -69,10 +91,18 @@
"type": "string",
"description": "Information about how the form data is used."
},
"scene2_disclaimer_html": {
"type": "string",
"description": "(send to device) Html for disclaimer and link underneath input box."
},
"scene2_dismiss_button_text": {
"type": "string",
"description": "Label for the dismiss button when the sign-up form is expanded."
},
"scene2_icon": {
"type": "string",
"description": "(send to device) Image to display above the form. 98x98px. SVG or PNG preferred."
},
"hidden_inputs": {
"type": "object",
"description": "Each entry represents a hidden input, key is used as value for the name property."
@ -83,11 +113,11 @@
{"description": "Text for a button next to main snippet text that links to button_url. Requires button_url."}
]
},
"button_color": {
"scene1_button_color": {
"type": "string",
"description": "The text color of the button. Valid CSS color."
},
"button_background_color": {
"scene1_button_background_color": {
"type": "string",
"description": "The background color of the button. Valid CSS color."
},
@ -95,6 +125,18 @@
"type": "boolean",
"description": "Used to prevent blocking the snippet after the CTA (link or button) has been clicked"
},
"include_sms": {
"type": "boolean",
"description": "(send to device) Allow users to send an SMS message with the form?"
},
"message_id_sms": {
"type": "string",
"description": "(send to device) Newsletter/basket id representing the SMS message to be sent."
},
"message_id_email": {
"type": "string",
"description": "(send to device) Newsletter/basket id representing the email message to be sent. Must be a value from the 'Slug' column here: https://basket.mozilla.org/news/."
},
"links": {
"additionalProperties": {
"url": {

Просмотреть файл

@ -3,13 +3,29 @@
flex: 1 1 100%;
width: 100%;
&.send_to_device_snippet {
text-align: center;
.message {
font-size: 16px;
}
}
.ASRouterButton {
&.primary {
font-size: 15px;
flex: 1 1 0;
}
}
.scene2Icon {
width: 100%;
img {
width: 98px;
display: inline-block;
}
}
form {
display: flex;
flex-direction: column;
@ -20,24 +36,34 @@
font-size: 14px;
align-self: stretch;
flex: 0 0 100%;
p {
margin-top: 0;
}
}
.privacy-notice {
.privacyNotice {
color: var(--newtab-text-secondary-color);
flex: 0 0 100%;
p {
margin-bottom: 0;
}
}
.innerWrapper {
max-width: 670px;
flex-wrap: wrap;
justify-items: center;
padding-top: 40px;
padding-bottom: 40px;
}
.footer {
width: 100%;
margin: 0 auto;
text-align: right;
background: $grey-20;
background-color: var(--newtab-background-color);
padding: 10px 0;
.footer-content {
@ -49,11 +75,12 @@
}
input {
&[type='email'] {
&.mainInput {
border-radius: 3px;
background-color: var(--newtab-textbox-background-color);
border: $input-border;
padding: 0 8px;
height: 32px;
height: 100%;
font-size: 15px;
width: 50%;
@ -64,3 +91,13 @@
}
}
}
.submissionStatus {
text-align: center;
font-size: 14px;
padding: 20px 0;
.submitStatusTitle {
font-size: 20px;
}
}

Просмотреть файл

@ -1,7 +1,7 @@
import {actionCreators as ac, actionTypes as at} from "common/Actions.jsm";
import {FormattedMessage, injectIntl} from "react-intl";
import {cardContextTypes} from "./types";
import {connect} from "react-redux";
import {FormattedMessage} from "react-intl";
import {GetPlatformString} from "content-src/lib/link-menu-options";
import {LinkMenu} from "content-src/components/LinkMenu/LinkMenu";
import React from "react";
@ -245,7 +245,7 @@ export class _Card extends React.PureComponent {
</div>
</div>
</a>
{!props.placeholder && <button className="context-menu-button icon"
{!props.placeholder && <button className="context-menu-button icon" title={this.props.intl.formatMessage({id: "context_menu_title"})}
onClick={this.onMenuButtonClick}>
<span className="sr-only">{`Open context menu for ${link.title}`}</span>
</button>}
@ -264,5 +264,5 @@ export class _Card extends React.PureComponent {
}
}
_Card.defaultProps = {link: {}};
export const Card = connect(state => ({platform: state.Prefs.values.platform}))(_Card);
export const Card = connect(state => ({platform: state.Prefs.values.platform}))(injectIntl(_Card));
export const PlaceholderCard = props => <Card placeholder={true} className={props.className} />;

Просмотреть файл

@ -162,6 +162,7 @@ export class _CollapsibleSection extends React.PureComponent {
<div>
<button
className="context-menu-button icon"
title={this.props.intl.formatMessage({id: "context_menu_title"})}
onClick={this.onMenuButtonClick}
onMouseEnter={this.onMenuButtonMouseEnter}
onMouseLeave={this.onMenuButtonMouseLeave}>

Просмотреть файл

@ -1,9 +1,10 @@
.confirmation-dialog {
.modal {
box-shadow: 0 2px 2px 0 $black-10;
left: 50%;
margin-left: -200px;
left: 0;
margin: auto;
position: fixed;
right: 0;
top: 20%;
width: 400px;
}

Просмотреть файл

@ -279,7 +279,7 @@ export class TopSite extends React.PureComponent {
const title = link.label || link.hostname;
return (<TopSiteLink {...props} onClick={this.onLinkClick} onDragEvent={this.props.onDragEvent} className={`${props.className || ""}${isContextMenuOpen ? " active" : ""}`} title={title}>
<div>
<button className="context-menu-button icon" onClick={this.onMenuButtonClick}>
<button className="context-menu-button icon" title={this.props.intl.formatMessage({id: "context_menu_title"})} onClick={this.onMenuButtonClick}>
<span className="sr-only">
<FormattedMessage id="context_menu_button_sr" values={{title}} />
</span>

Просмотреть файл

@ -1405,9 +1405,10 @@ a.firstrun-link {
.confirmation-dialog .modal {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
left: 50%;
margin-left: -200px;
left: 0;
margin: auto;
position: fixed;
right: 0;
top: 20%;
width: 400px; }
@ -1893,6 +1894,7 @@ a.firstrun-link {
transform: scaleX(-1); }
.ASRouterButton {
font-weight: bold;
white-space: nowrap;
border-radius: 4px;
border: 1px solid var(--newtab-border-secondary-color);
@ -1905,7 +1907,7 @@ a.firstrun-link {
.tall .ASRouterButton {
margin-inline-start: 20px; }
.ASRouterButton.primary {
border: 1px solid var(--newtab-border-primary-color);
border: 1px solid var(--newtab-button-primary-color);
background-color: var(--newtab-button-primary-color);
color: #F9F9FA; }
.ASRouterButton.secondary {
@ -1930,6 +1932,8 @@ a.firstrun-link {
.SnippetBaseContainer a {
cursor: pointer;
color: var(--newtab-link-primary-color); }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer .innerWrapper {
margin: 0 auto;
display: flex;
@ -1999,9 +2003,9 @@ a.firstrun-link {
.modalOverlayInner {
width: 960px;
height: 510px;
height: 570px;
position: fixed;
top: calc(50% - 255px);
top: calc(50% - 285px);
left: calc(50% - 480px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
@ -2054,9 +2058,9 @@ a.firstrun-link {
position: sticky; } }
.modalOverlayInner .footer .modalButton {
margin-top: 20px;
width: 150px;
min-width: 150px;
height: 30px;
padding: 4px 0 6px;
padding: 4px 30px 6px;
font-size: 15px; }
.modalOverlayInner .footer .modalButton:focus, .modalOverlayInner .footer .modalButton.active, .modalOverlayInner .footer .modalButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
@ -2094,9 +2098,17 @@ a.firstrun-link {
flex-direction: column;
flex: 1 1 100%;
width: 100%; }
.SubmitFormSnippet.send_to_device_snippet {
text-align: center; }
.SubmitFormSnippet.send_to_device_snippet .message {
font-size: 16px; }
.SubmitFormSnippet .ASRouterButton.primary {
font-size: 15px;
flex: 1 1 0; }
.SubmitFormSnippet .scene2Icon {
width: 100%; }
.SubmitFormSnippet .scene2Icon img {
width: 98px;
display: inline-block; }
.SubmitFormSnippet form {
display: flex;
flex-direction: column;
@ -2105,35 +2117,49 @@ a.firstrun-link {
font-size: 14px;
align-self: stretch;
flex: 0 0 100%; }
.SubmitFormSnippet .privacy-notice {
.SubmitFormSnippet .message p {
margin-top: 0; }
.SubmitFormSnippet .privacyNotice {
color: var(--newtab-text-secondary-color);
flex: 0 0 100%; }
.SubmitFormSnippet .privacyNotice p {
margin-bottom: 0; }
.SubmitFormSnippet .innerWrapper {
max-width: 670px;
flex-wrap: wrap;
justify-items: center; }
justify-items: center;
padding-top: 40px;
padding-bottom: 40px; }
.SubmitFormSnippet .footer {
width: 100%;
margin: 0 auto;
text-align: right;
background: #EDEDF0;
background-color: var(--newtab-background-color);
padding: 10px 0; }
.SubmitFormSnippet .footer .footer-content {
margin: 0 auto;
max-width: 768px;
width: 100%;
text-align: right; }
.SubmitFormSnippet input[type='email'] {
.SubmitFormSnippet input.mainInput {
border-radius: 3px;
background-color: var(--newtab-textbox-background-color);
border: 1px solid var(--newtab-textbox-border);
padding: 0 8px;
height: 32px;
height: 100%;
font-size: 15px;
width: 50%; }
.SubmitFormSnippet input[type='email']:focus {
.SubmitFormSnippet input.mainInput:focus {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.submissionStatus {
text-align: center;
font-size: 14px;
padding: 20px 0; }
.submissionStatus .submitStatusTitle {
font-size: 20px; }
.onboardingMessageContainer {
display: grid;
grid-column-gap: 21px;
@ -2206,13 +2232,14 @@ a.firstrun-link {
.onboardingMessage .onboardingContent > span > p {
color: #4A4A4F;
margin-top: 0;
height: 130px;
height: 180px;
margin-bottom: 12px;
font-size: 15px;
line-height: 22px; }
@media (max-width: 650px) {
.onboardingMessage .onboardingContent > span > p {
margin-bottom: 0; } }
margin-bottom: 0;
height: 160px; } }
.onboardingMessage .onboardingButton {
background-color: rgba(12, 12, 13, 0.1);
border: 0;
@ -2224,23 +2251,22 @@ a.firstrun-link {
@media (max-width: 850px) {
.onboardingMessage .onboardingButton {
float: right;
margin-top: -60px;
margin-right: -10px; } }
margin-top: -105px;
margin-inline-end: -10px; } }
@media (max-width: 650px) {
.onboardingMessage .onboardingButton {
float: none;
margin-top: 30px; } }
float: none; } }
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.onboardingMessage::before {
content: '';
height: 220px;
height: 230px;
width: 1px;
position: absolute;
background-color: #D7D7DB;
margin-top: 40px;
margin-left: 215px; }
margin-inline-start: 215px; }
@media (max-width: 850px) {
.onboardingMessage::before {
content: none; } }

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1408,9 +1408,10 @@ a.firstrun-link {
.confirmation-dialog .modal {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
left: 50%;
margin-left: -200px;
left: 0;
margin: auto;
position: fixed;
right: 0;
top: 20%;
width: 400px; }
@ -1896,6 +1897,7 @@ a.firstrun-link {
transform: scaleX(-1); }
.ASRouterButton {
font-weight: bold;
white-space: nowrap;
border-radius: 4px;
border: 1px solid var(--newtab-border-secondary-color);
@ -1908,7 +1910,7 @@ a.firstrun-link {
.tall .ASRouterButton {
margin-inline-start: 20px; }
.ASRouterButton.primary {
border: 1px solid var(--newtab-border-primary-color);
border: 1px solid var(--newtab-button-primary-color);
background-color: var(--newtab-button-primary-color);
color: #F9F9FA; }
.ASRouterButton.secondary {
@ -1933,6 +1935,8 @@ a.firstrun-link {
.SnippetBaseContainer a {
cursor: pointer;
color: var(--newtab-link-primary-color); }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer .innerWrapper {
margin: 0 auto;
display: flex;
@ -2002,9 +2006,9 @@ a.firstrun-link {
.modalOverlayInner {
width: 960px;
height: 510px;
height: 570px;
position: fixed;
top: calc(50% - 255px);
top: calc(50% - 285px);
left: calc(50% - 480px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
@ -2057,9 +2061,9 @@ a.firstrun-link {
position: sticky; } }
.modalOverlayInner .footer .modalButton {
margin-top: 20px;
width: 150px;
min-width: 150px;
height: 30px;
padding: 4px 0 6px;
padding: 4px 30px 6px;
font-size: 15px; }
.modalOverlayInner .footer .modalButton:focus, .modalOverlayInner .footer .modalButton.active, .modalOverlayInner .footer .modalButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
@ -2097,9 +2101,17 @@ a.firstrun-link {
flex-direction: column;
flex: 1 1 100%;
width: 100%; }
.SubmitFormSnippet.send_to_device_snippet {
text-align: center; }
.SubmitFormSnippet.send_to_device_snippet .message {
font-size: 16px; }
.SubmitFormSnippet .ASRouterButton.primary {
font-size: 15px;
flex: 1 1 0; }
.SubmitFormSnippet .scene2Icon {
width: 100%; }
.SubmitFormSnippet .scene2Icon img {
width: 98px;
display: inline-block; }
.SubmitFormSnippet form {
display: flex;
flex-direction: column;
@ -2108,35 +2120,49 @@ a.firstrun-link {
font-size: 14px;
align-self: stretch;
flex: 0 0 100%; }
.SubmitFormSnippet .privacy-notice {
.SubmitFormSnippet .message p {
margin-top: 0; }
.SubmitFormSnippet .privacyNotice {
color: var(--newtab-text-secondary-color);
flex: 0 0 100%; }
.SubmitFormSnippet .privacyNotice p {
margin-bottom: 0; }
.SubmitFormSnippet .innerWrapper {
max-width: 670px;
flex-wrap: wrap;
justify-items: center; }
justify-items: center;
padding-top: 40px;
padding-bottom: 40px; }
.SubmitFormSnippet .footer {
width: 100%;
margin: 0 auto;
text-align: right;
background: #EDEDF0;
background-color: var(--newtab-background-color);
padding: 10px 0; }
.SubmitFormSnippet .footer .footer-content {
margin: 0 auto;
max-width: 768px;
width: 100%;
text-align: right; }
.SubmitFormSnippet input[type='email'] {
.SubmitFormSnippet input.mainInput {
border-radius: 3px;
background-color: var(--newtab-textbox-background-color);
border: 1px solid var(--newtab-textbox-border);
padding: 0 8px;
height: 32px;
height: 100%;
font-size: 15px;
width: 50%; }
.SubmitFormSnippet input[type='email']:focus {
.SubmitFormSnippet input.mainInput:focus {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.submissionStatus {
text-align: center;
font-size: 14px;
padding: 20px 0; }
.submissionStatus .submitStatusTitle {
font-size: 20px; }
.onboardingMessageContainer {
display: grid;
grid-column-gap: 21px;
@ -2209,13 +2235,14 @@ a.firstrun-link {
.onboardingMessage .onboardingContent > span > p {
color: #4A4A4F;
margin-top: 0;
height: 130px;
height: 180px;
margin-bottom: 12px;
font-size: 15px;
line-height: 22px; }
@media (max-width: 650px) {
.onboardingMessage .onboardingContent > span > p {
margin-bottom: 0; } }
margin-bottom: 0;
height: 160px; } }
.onboardingMessage .onboardingButton {
background-color: rgba(12, 12, 13, 0.1);
border: 0;
@ -2227,23 +2254,22 @@ a.firstrun-link {
@media (max-width: 850px) {
.onboardingMessage .onboardingButton {
float: right;
margin-top: -60px;
margin-right: -10px; } }
margin-top: -105px;
margin-inline-end: -10px; } }
@media (max-width: 650px) {
.onboardingMessage .onboardingButton {
float: none;
margin-top: 30px; } }
float: none; } }
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.onboardingMessage::before {
content: '';
height: 220px;
height: 230px;
width: 1px;
position: absolute;
background-color: #D7D7DB;
margin-top: 40px;
margin-left: 215px; }
margin-inline-start: 215px; }
@media (max-width: 850px) {
.onboardingMessage::before {
content: none; } }

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1405,9 +1405,10 @@ a.firstrun-link {
.confirmation-dialog .modal {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1);
left: 50%;
margin-left: -200px;
left: 0;
margin: auto;
position: fixed;
right: 0;
top: 20%;
width: 400px; }
@ -1893,6 +1894,7 @@ a.firstrun-link {
transform: scaleX(-1); }
.ASRouterButton {
font-weight: bold;
white-space: nowrap;
border-radius: 4px;
border: 1px solid var(--newtab-border-secondary-color);
@ -1905,7 +1907,7 @@ a.firstrun-link {
.tall .ASRouterButton {
margin-inline-start: 20px; }
.ASRouterButton.primary {
border: 1px solid var(--newtab-border-primary-color);
border: 1px solid var(--newtab-button-primary-color);
background-color: var(--newtab-button-primary-color);
color: #F9F9FA; }
.ASRouterButton.secondary {
@ -1930,6 +1932,8 @@ a.firstrun-link {
.SnippetBaseContainer a {
cursor: pointer;
color: var(--newtab-link-primary-color); }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer .innerWrapper {
margin: 0 auto;
display: flex;
@ -1999,9 +2003,9 @@ a.firstrun-link {
.modalOverlayInner {
width: 960px;
height: 510px;
height: 570px;
position: fixed;
top: calc(50% - 255px);
top: calc(50% - 285px);
left: calc(50% - 480px);
background: #FFF;
box-shadow: 0 1px 15px 0 rgba(0, 0, 0, 0.3);
@ -2054,9 +2058,9 @@ a.firstrun-link {
position: sticky; } }
.modalOverlayInner .footer .modalButton {
margin-top: 20px;
width: 150px;
min-width: 150px;
height: 30px;
padding: 4px 0 6px;
padding: 4px 30px 6px;
font-size: 15px; }
.modalOverlayInner .footer .modalButton:focus, .modalOverlayInner .footer .modalButton.active, .modalOverlayInner .footer .modalButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
@ -2094,9 +2098,17 @@ a.firstrun-link {
flex-direction: column;
flex: 1 1 100%;
width: 100%; }
.SubmitFormSnippet.send_to_device_snippet {
text-align: center; }
.SubmitFormSnippet.send_to_device_snippet .message {
font-size: 16px; }
.SubmitFormSnippet .ASRouterButton.primary {
font-size: 15px;
flex: 1 1 0; }
.SubmitFormSnippet .scene2Icon {
width: 100%; }
.SubmitFormSnippet .scene2Icon img {
width: 98px;
display: inline-block; }
.SubmitFormSnippet form {
display: flex;
flex-direction: column;
@ -2105,35 +2117,49 @@ a.firstrun-link {
font-size: 14px;
align-self: stretch;
flex: 0 0 100%; }
.SubmitFormSnippet .privacy-notice {
.SubmitFormSnippet .message p {
margin-top: 0; }
.SubmitFormSnippet .privacyNotice {
color: var(--newtab-text-secondary-color);
flex: 0 0 100%; }
.SubmitFormSnippet .privacyNotice p {
margin-bottom: 0; }
.SubmitFormSnippet .innerWrapper {
max-width: 670px;
flex-wrap: wrap;
justify-items: center; }
justify-items: center;
padding-top: 40px;
padding-bottom: 40px; }
.SubmitFormSnippet .footer {
width: 100%;
margin: 0 auto;
text-align: right;
background: #EDEDF0;
background-color: var(--newtab-background-color);
padding: 10px 0; }
.SubmitFormSnippet .footer .footer-content {
margin: 0 auto;
max-width: 768px;
width: 100%;
text-align: right; }
.SubmitFormSnippet input[type='email'] {
.SubmitFormSnippet input.mainInput {
border-radius: 3px;
background-color: var(--newtab-textbox-background-color);
border: 1px solid var(--newtab-textbox-border);
padding: 0 8px;
height: 32px;
height: 100%;
font-size: 15px;
width: 50%; }
.SubmitFormSnippet input[type='email']:focus {
.SubmitFormSnippet input.mainInput:focus {
border: 1px solid var(--newtab-textbox-focus-color);
box-shadow: var(--newtab-textbox-focus-boxshadow); }
.submissionStatus {
text-align: center;
font-size: 14px;
padding: 20px 0; }
.submissionStatus .submitStatusTitle {
font-size: 20px; }
.onboardingMessageContainer {
display: grid;
grid-column-gap: 21px;
@ -2206,13 +2232,14 @@ a.firstrun-link {
.onboardingMessage .onboardingContent > span > p {
color: #4A4A4F;
margin-top: 0;
height: 130px;
height: 180px;
margin-bottom: 12px;
font-size: 15px;
line-height: 22px; }
@media (max-width: 650px) {
.onboardingMessage .onboardingContent > span > p {
margin-bottom: 0; } }
margin-bottom: 0;
height: 160px; } }
.onboardingMessage .onboardingButton {
background-color: rgba(12, 12, 13, 0.1);
border: 0;
@ -2224,23 +2251,22 @@ a.firstrun-link {
@media (max-width: 850px) {
.onboardingMessage .onboardingButton {
float: right;
margin-top: -60px;
margin-right: -10px; } }
margin-top: -105px;
margin-inline-end: -10px; } }
@media (max-width: 650px) {
.onboardingMessage .onboardingButton {
float: none;
margin-top: 30px; } }
float: none; } }
.onboardingMessage .onboardingButton:focus, .onboardingMessage .onboardingButton.active, .onboardingMessage .onboardingButton:hover {
box-shadow: 0 0 0 5px #D7D7DB;
transition: box-shadow 150ms; }
.onboardingMessage::before {
content: '';
height: 220px;
height: 230px;
width: 1px;
position: absolute;
background-color: #D7D7DB;
margin-top: 40px;
margin-left: 215px; }
margin-inline-start: 215px; }
@media (max-width: 850px) {
.onboardingMessage::before {
content: none; } }

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -16,7 +16,9 @@ const DEFAULT_STATE = {
_devtoolsPref: DEVTOOLS_PREF,
};
const USER_PREFERENCES = {snippets: "browser.newtabpage.activity-stream.feeds.snippets"};
const USER_PREFERENCES = {
snippets: "browser.newtabpage.activity-stream.feeds.snippets",
};
const TEST_PROVIDER = {
id: "snippets_local_testing",

Просмотреть файл

@ -60,6 +60,48 @@ function CachedTargetingGetter(property, options = null, updateInterval = FRECEN
};
}
function CheckBrowserNeedsUpdate(updateInterval = FRECENT_SITES_UPDATE_INTERVAL) {
const UpdateChecker = Cc["@mozilla.org/updates/update-checker;1"].createInstance(Ci.nsIUpdateChecker);
const checker = {
_lastUpdated: 0,
_value: null,
// For testing. Avoid update check network call.
setUp(value) {
this._lastUpdated = Date.now();
this._value = value;
},
expire() {
this._lastUpdated = 0;
this._value = null;
},
get() {
return new Promise((resolve, reject) => {
const now = Date.now();
const updateServiceListener = {
onCheckComplete(request, updates, updateCount) {
checker._value = updateCount > 0;
resolve(checker._value);
},
onError(request, update) {
reject(request);
},
QueryInterface: ChromeUtils.generateQI(["nsIUpdateCheckListener"]),
};
if (now - this._lastUpdated >= updateInterval) {
UpdateChecker.checkForUpdates(updateServiceListener, true);
this._lastUpdated = now;
} else {
resolve(this._value);
}
});
},
};
return checker;
}
const QueryCache = {
expireAll() {
Object.keys(this.queries).forEach(query => {
@ -78,6 +120,7 @@ const QueryCache = {
}
),
TotalBookmarksCount: new CachedTargetingGetter("getTotalBookmarksCount"),
CheckBrowserNeedsUpdate: new CheckBrowserNeedsUpdate(),
},
};
@ -218,6 +261,9 @@ const TargetingGetters = {
get region() {
return Services.prefs.getStringPref(SEARCH_REGION_PREF, "");
},
get needsUpdate() {
return QueryCache.queries.CheckBrowserNeedsUpdate.get();
},
};
this.ASRouterTargeting = {

Просмотреть файл

@ -93,10 +93,10 @@ this.ManualMigration = class ManualMigration {
this.store.dispatch({type: at.MIGRATION_COMPLETED});
}
onAction(action) {
async onAction(action) {
switch (action.type) {
case at.PREFS_INITIAL_VALUES:
this.expireIfNecessary(action.data.migrationExpired);
await this.expireIfNecessary(action.data.migrationExpired);
break;
case at.MIGRATION_START:
MigrationUtils.showMigrationWizard(action._target.browser.ownerGlobal, [MigrationUtils.MIGRATION_ENTRYPOINT_NEWTAB]);

Просмотреть файл

@ -16,6 +16,17 @@ const MESSAGES = () => ([
"block_button_text": "Block",
},
},
{
"id": "SIMPLE_TEST_BUTTON_URL_1",
"template": "simple_snippet",
"content": {
"icon": TEST_ICON,
"button_label": "Get one now!",
"button_url": "https://www.mozilla.org/en-US/firefox/accounts",
"text": "Sync it, link it, take it with you. All this and more with a Firefox Account.",
"block_button_text": "Block",
},
},
{
"id": "SIMPLE_WITH_TITLE_TEST_1",
"template": "simple_snippet",
@ -36,9 +47,8 @@ const MESSAGES = () => ([
"scene1_title_icon": "",
"scene1_text": "Internet shutdowns, hackers, harassment &ndash; the health of the internet is on the line. Sign up and Mozilla will keep you updated on how you can help.",
"scene1_button_label": "Continue",
// TODO: Need to update schema
// "scene1_button_color": "#712b00",
// "scene1_button_background_color": "#ff9400",
"scene1_button_color": "#712b00",
"scene1_button_background_color": "#ff9400",
"scene2_dismiss_button_text": "Dismiss",
"scene2_text": "Sign up for the Mozilla newsletter and we will keep you updated on how you can help.",
"scene2_privacy_html": "I'm okay with Mozilla handling my info as explained in this <privacyLink>Privacy Notice</privacyLink>.",
@ -61,17 +71,15 @@ const MESSAGES = () => ([
"content": {
"scene1_icon": TEST_ICON,
"scene1_button_label": "Get connected with sync!",
// TODO: Need to update schema
// "scene1_button_color": "#712b00",
// "scene1_button_background_color": "#ff9400",
"scene1_button_color": "#712b00",
"scene1_button_background_color": "#ff9400",
"scene1_text": "Connect to Firefox by securely syncing passwords, bookmarks, and open tabs.",
"scene1_title": "Browser better.",
"scene1_title_icon": "",
"scene2_text": "Connect to your Firefox account to securely sync passwords, bookmarks, and open tabs.",
// TODO: needs to be added
// "scene2_title": "Title 123",
"scene2_title": "Title 123",
"scene2_email_placeholder_text": "Your email",
"scene2_button_label": "Continue",
"scene2_dismiss_button_text": "Dismiss",
@ -83,6 +91,42 @@ const MESSAGES = () => ([
"hidden_inputs": {},
},
},
{
id: "SNIPPETS_SEND_TO_DEVICE_TEST",
template: "send_to_device_snippet",
content: {
include_sms: true,
locale: "en-CA",
country: "us",
message_id_sms: "ff-mobilesn-download",
message_id_email: "download-firefox-mobile",
scene1_button_background_color: "#6200a4",
scene1_button_color: "#FFFFFF",
scene1_button_label: "Install now",
scene1_icon: TEST_ICON,
scene1_text: "Browse without compromise with Firefox Mobile.",
scene1_title: "Full-featured. Customizable. Lightning fast",
scene1_title_icon: "",
scene2_button_label: "Send",
scene2_disclaimer_html: "The intended recipient of the email must have consented. <privacyLink>Learn more.</privacyLink>",
scene2_dismiss_button_text: "Dismiss",
scene2_icon: TEST_ICON,
scene2_input_placeholder: "Your email address or phone number",
scene2_text: "Send Firefox to your phone and take a powerful independent browser with you.",
scene2_title: "",
error_text: "Oops, there was a problem.",
success_title: "Your download link was sent.",
success_text: "Check your device for the email message!",
links: {"privacyLink": {"url": "https://www.mozilla.org/privacy/websites/?sample_rate=0.001&snippet_name=7894"}},
// TODO: Not actually defined in the send to device schema
form_action: "https://basket.mozilla.org/subscribe.json",
hidden_inputs: {},
},
},
]);
const SnippetsTestMessageProvider = {

Просмотреть файл

@ -143,9 +143,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_more_reccommendations=Больш рэкамендацый
pocket_learn_more=Падрабязней
pocket_how_it_works=Як гэта працуе
pocket_cta_button=Атрымаць Pocket
pocket_cta_text=Захоўвайце ўлюбёныя гісторыі ў Pocket, і сілкуйце свой розум добрай чытанкай.
@ -196,7 +196,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

Просмотреть файл

@ -143,6 +143,8 @@ 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_how_it_works=কিভাবে এটা কাজ করে
highlights_empty_state=ব্রাউজি করা শুরু করুন, এবং কিছু গুরুত্বপূর্ণ নিবন্ধ, ভিডিও, এবং আপনি সম্প্রতি পরিদর্শন বা বুকমার্ক করেছেন এমন কিছু পৃষ্ঠা আমরা এখানে প্রদর্শন করব।
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
@ -191,7 +193,6 @@ firstrun_form_header=আপনার ই-মেইল লিখুন
firstrun_form_sub_header=Firefox সিঙ্ক চালিয়ে যেতে
firstrun_email_input_placeholder=ইমেইল
firstrun_invalid_input=কার্যকর ইমেইল আবশ্যক
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and

Просмотреть файл

@ -144,6 +144,12 @@ 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.
highlights_empty_state=Krogit da verdeiñ hag e tiskouezimp deoch pennadoù, videoioù ha pajennoù all gweladennet pe lakaet er sinedoù nevez zo.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
# in the space that would have shown a few stories, this is shown instead.
@ -173,6 +179,7 @@ section_menu_action_expand_section=Astenn ar gevrenn
section_menu_action_manage_section=Merañ ar gevrenn
section_menu_action_manage_webext=Merañ an askouezh
section_menu_action_add_topsite=Ouzhpennañ ul lec'hienn gwellañ din
section_menu_action_add_search_engine=Ouzhpennañ ul lusker klask
section_menu_action_move_up=Dilec'hiañ etrezek ar c'hrec'h
section_menu_action_move_down=Dilec'hiañ etrezek an traoñ
section_menu_action_privacy_notice=Evezhiadennoù a-fet buhez prevez
@ -201,4 +208,3 @@ firstrun_privacy_notice=evezhiadennoù a-fet buhez prevez
firstrun_continue_to_login=Kenderc'hel
firstrun_skip_login=Tremen ar bazenn-mañ
section_menu_action_add_search_engine=Ouzhpennañ ul lusker enklask

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Mostra més articles
pocket_more_reccommendations=Més recomanacions
pocket_learn_more=Més informació
pocket_how_it_works=Com funciona
pocket_cta_button=Obtén el Pocket
pocket_cta_text=Deseu els vostres articles preferits al Pocket i gaudiu d'altres recomanacions fascinants.

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Gweld Rhagor o Straeon
pocket_more_reccommendations=Rhagor o Argymhellion
pocket_learn_more=Dysgu Rhagor
pocket_how_it_works=Sut mae'n gweithio
pocket_cta_button=Defnyddio Pocket
pocket_cta_text=Cadw'r straeon rydych yn eu hoffi i Pocket a bwydo'ch meddwl á deunydd diddorol.

Просмотреть файл

@ -205,3 +205,6 @@ firstrun_privacy_notice=Privacy Notice
firstrun_continue_to_login=Continue
firstrun_skip_login=Skip this step
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
context_menu_title=Open menu

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Ver más historias
pocket_more_reccommendations=Más recomendaciones
pocket_learn_more=Conocer más
pocket_how_it_works=Cómo funciona
pocket_cta_button=Obtener Pocket
pocket_cta_text=Guarde las historias que quiera en Pocket y potencie su mente con lecturas fascinantes.

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Ver más historias
pocket_more_reccommendations=Más recomendaciones
pocket_learn_more=Aprender más
pocket_how_it_works=Cómo funciona
pocket_cta_button=Obtener Pocket
pocket_cta_text=Guarda las historias que amas en Pocket, y potencia tu mente con fascinantes lecturas.

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Ikusi istorio gehiago
pocket_more_reccommendations=Gomendio gehiago
pocket_learn_more=Argibide gehiago
pocket_how_it_works=Nola dabilen
pocket_cta_button=Eskuratu Pocket
pocket_cta_text=Gorde gogoko dituzun istorioak Pocket-en eta piztu zure gogoa irakurgai erakargarriekin.

Просмотреть файл

@ -143,9 +143,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_more_reccommendations=توصیه‌های بیشتر
pocket_learn_more=بیشتر بدانید
pocket_how_it_works=این چجوری کار میکنه
pocket_cta_button=دریافت پاکت
pocket_cta_text=داستان‌هایی را که دوست دارید در پاکت خود ذخیره کنید و ذهن خود را با خواندنی‌های جذاب پرورش دهید.
@ -196,7 +196,6 @@ firstrun_form_header=پست‌الکترونیکی خود را وارد کنید
firstrun_form_sub_header=برای فعال کردن همگام‌سازی فایرفاکس.
firstrun_email_input_placeholder=پست‌الکترونیکی
firstrun_invalid_input=رایانامهٔ معتبر لازم است
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and

Просмотреть файл

@ -143,9 +143,9 @@ pocket_read_more=Suositut aiheet:
# 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=Katso lisää juttuja
pocket_more_reccommendations=Lisää suosituksia
pocket_learn_more=Lue lisää
pocket_how_it_works=Kuinka se toimii
pocket_cta_button=Hanki Pocket
pocket_cta_text=Tallenna tykkäämäsi tekstit Pocketiin ja ravitse mieltäsi kiinnostavilla teksteillä.
@ -196,7 +196,6 @@ firstrun_form_header=Kirjoita sähköpostisi
firstrun_form_sub_header=jatkaaksesi Firefox Sync -palveluun.
firstrun_email_input_placeholder=Sähköposti
firstrun_invalid_input=Sähköpostiosoitteen täytyy olla kelvollinen
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Afficher plus darticles
pocket_more_reccommendations=Plus de recommandations
pocket_learn_more=En savoir plus
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.

Просмотреть файл

@ -177,7 +177,7 @@ section_menu_action_remove_section=Szakasz eltávolítása
section_menu_action_collapse_section=Szakasz összecsukása
section_menu_action_expand_section=Szakasz lenyitása
section_menu_action_manage_section=Szakasz kezelése
section_menu_action_manage_webext=Kiterjesztés kezelése
section_menu_action_manage_webext=Kiegészítő kezelése
section_menu_action_add_topsite=Hozzáadás a népszerű oldalakhoz
section_menu_action_add_search_engine=Keresőszolgáltatás hozzáadása
section_menu_action_move_up=Mozgatás felfelé

Просмотреть файл

@ -143,10 +143,11 @@ pocket_read_more=Topik Populer:
# 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=Lihat Cerita Lainnya
pocket_more_reccommendations=Rekomendasi Lainnya
pocket_learn_more=Pelajari Lebih Lanjut
pocket_how_it_works=Panduan
pocket_cta_button=Dapatkan Pocket
pocket_cta_text=Simpan cerita yang anda sukai di Pocket, dan dapatkan bacaan menarik untuk Anda.
highlights_empty_state=Mulai menjelajah, dan kami akan menampilkan beberapa artikel bagus, video, dan halaman lain yang baru saja Anda kunjungi atau termarkah di sini.
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
@ -195,7 +196,6 @@ firstrun_form_header=Masukkan surel Anda
firstrun_form_sub_header=Lanjutkan ke Firefox Sync.
firstrun_email_input_placeholder=Surel
firstrun_invalid_input=Surel harus valid
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Көбірек хикаяларды қарау
pocket_more_reccommendations=Көбірек ұсыныстар
pocket_learn_more=Көбірек білу
pocket_how_it_works=Ол қалай жұмыс істейді
pocket_cta_button=Pocket-ті алу
pocket_cta_text=Өзіңіз ұнатқан хикаяларды Pocket ішіне сақтап, миіңізді тамаша оқумен толықтырыңыз.

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=더 많은 이야기 보기
pocket_more_reccommendations=더 많은 추천
pocket_learn_more=자세히 보기
pocket_how_it_works=사용 방법
pocket_cta_button=Pocket 받기
pocket_cta_text=좋아하는 이야기를 Pocket에 저장하고 재미있게 읽어 보세요.

Просмотреть файл

@ -30,8 +30,8 @@ type_label_downloaded=ດາວໂຫຼດແລ້ວ
# bookmarks"
menu_action_bookmark=ບຸກມາກ
menu_action_remove_bookmark=ລຶບບຸກມາກອອກ
menu_action_open_new_window=ເປີດລີ້ງໃນຫນ້າຕ່າງໃຫມ່
menu_action_open_private_window=ເປີດໃນຫນ້າຕ່າງສ່ວນຕົວໃຫມ່
menu_action_open_new_window=ເປີດລີ້ງໃນວິນໂດໃຫມ່
menu_action_open_private_window=ເປີດໃນວິນໂດສ່ວນຕົວໃຫມ່
menu_action_dismiss=ຍົກເລີກ
menu_action_delete=ລຶບອອກຈາກປະຫວັດການນຳໃຊ້
menu_action_pin=ປັກໝຸດ
@ -168,7 +168,7 @@ manual_migration_import_button=ນຳເຂົ້າຕອນນີ້
# LOCALIZATION NOTE (error_fallback_default_*): This message and suggested
# action link are shown in each section of UI that fails to render
error_fallback_default_info=ໂອ້ຍ, ມີບາງສິ່ງບາງຢ່າງຜິດພາດໃນການໂຫລດເນື້ອຫານີ້.
error_fallback_default_refresh_suggestion=ຣີເຟຣຊຫນ້າເພື່ອລອງອີກຄັ້ງ.
error_fallback_default_refresh_suggestion=ຟື້ນຟູໜ້າເພື່ອລອງອີກຄັ້ງ.
# LOCALIZATION NOTE (section_menu_action_*). These strings are displayed in the section
# context menu and are meant as a call to action for the given section.

Просмотреть файл

@ -146,6 +146,7 @@ pocket_read_even_more=Rodyti daugiau straipsnių
pocket_more_reccommendations=Daugiau rekomendacijų
pocket_learn_more=Sužinoti daugiau
pocket_how_it_works=Kaip tai veikia
pocket_cta_button=Gauti „Pocket“
pocket_cta_text=Išsaugokite patinkančius straipsnius į „Pocket“, bei sužadinkite savo mintis stulbinančiomis istorijomis.

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше