1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-20 15:18:08 +02:00

Merge pull request #17115 from calixteman/mv_to_fluent

[api-minor] Move to Fluent for the localization (bug 1858715)
This commit is contained in:
calixteman 2023-10-19 13:40:50 +02:00 committed by GitHub
commit 5d8be99782
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
155 changed files with 1311 additions and 28684 deletions

View file

@ -112,7 +112,7 @@ class DefaultExternalServices {
throw new Error("Not implemented: createPreferences");
}
static createL10n(options) {
static async createL10n(options) {
throw new Error("Not implemented: createL10n");
}
@ -392,13 +392,12 @@ const PDFViewerApplication = {
* @private
*/
async _initializeL10n() {
this.l10n = this.externalServices.createL10n(
this.l10n = await this.externalServices.createL10n(
typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")
? { locale: AppOptions.get("locale") }
: null
);
const dir = await this.l10n.getDirection();
document.getElementsByTagName("html")[0].dir = dir;
document.getElementsByTagName("html")[0].dir = this.l10n.getDirection();
},
/**
@ -751,7 +750,7 @@ const PDFViewerApplication = {
if (!this.supportsDocumentFonts) {
AppOptions.set("disableFontFace", true);
this.l10n.get("web_fonts_disabled").then(msg => {
this.l10n.get("pdfjs-web-fonts-disabled").then(msg => {
console.warn(msg);
});
}
@ -896,7 +895,7 @@ const PDFViewerApplication = {
this.open({ url, length, originalUrl });
},
onError: err => {
this.l10n.get("loading_error").then(msg => {
this.l10n.get("pdfjs-loading-error").then(msg => {
this._documentError(msg, err);
});
},
@ -1100,13 +1099,13 @@ const PDFViewerApplication = {
return undefined; // Ignore errors for previously opened PDF files.
}
let key = "loading_error";
let key = "pdfjs-loading-error";
if (reason instanceof InvalidPDFException) {
key = "invalid_file_error";
key = "pdfjs-invalid-file-error";
} else if (reason instanceof MissingPDFException) {
key = "missing_file_error";
key = "pdfjs-missing-file-error";
} else if (reason instanceof UnexpectedResponseException) {
key = "unexpected_response_error";
key = "pdfjs-unexpected-response-error";
}
return this.l10n.get(key).then(msg => {
this._documentError(msg, { message: reason?.message });
@ -1446,7 +1445,7 @@ const PDFViewerApplication = {
this._initializeAutoPrint(pdfDocument, openActionPromise);
},
reason => {
this.l10n.get("loading_error").then(msg => {
this.l10n.get("pdfjs-loading-error").then(msg => {
this._documentError(msg, { message: reason?.message });
});
}
@ -1846,7 +1845,7 @@ const PDFViewerApplication = {
}
if (!this.supportsPrinting) {
this.l10n.get("printing_not_supported").then(msg => {
this.l10n.get("pdfjs-printing-not-supported").then(msg => {
this._otherError(msg);
});
return;
@ -1855,7 +1854,7 @@ const PDFViewerApplication = {
// The beforePrint is a sync method and we need to know layout before
// returning from this method. Ensure that we can get sizes of the pages.
if (!this.pdfViewer.pageViewsReady) {
this.l10n.get("printing_not_ready").then(msg => {
this.l10n.get("pdfjs-printing-not-ready").then(msg => {
// eslint-disable-next-line no-alert
window.alert(msg);
});
@ -2253,7 +2252,7 @@ if (typeof PDFJSDev === "undefined" || PDFJSDev.test("GENERIC")) {
throw new Error("file origin does not match viewer's");
}
} catch (ex) {
PDFViewerApplication.l10n.get("loading_error").then(msg => {
PDFViewerApplication.l10n.get("pdfjs-loading-error").then(msg => {
PDFViewerApplication._documentError(msg, { message: ex?.message });
});
throw ex;
@ -2320,7 +2319,7 @@ function webViewerPageRendered({ pageNumber, error }) {
}
if (error) {
PDFViewerApplication.l10n.get("rendering_error").then(msg => {
PDFViewerApplication.l10n.get("pdfjs-rendering-error").then(msg => {
PDFViewerApplication._otherError(msg, error);
});
}

View file

@ -435,7 +435,7 @@ class ChromeExternalServices extends DefaultExternalServices {
return new ChromePreferences();
}
static createL10n(options) {
static async createL10n(options) {
return new GenericL10n(navigator.language);
}

View file

@ -13,12 +13,11 @@
* limitations under the License.
*/
import "../extensions/firefox/tools/l10n.js";
import { DefaultExternalServices, PDFViewerApplication } from "./app.js";
import { isPdfFile, PDFDataRangeTransport, shadow } from "pdfjs-lib";
import { BasePreferences } from "./preferences.js";
import { DEFAULT_SCALE_VALUE } from "./ui_utils.js";
import { getL10nFallback } from "./l10n_utils.js";
import { L10n } from "./l10n.js";
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
throw new Error(
@ -182,28 +181,6 @@ class FirefoxPreferences extends BasePreferences {
}
}
class MozL10n {
constructor(mozL10n) {
this.mozL10n = mozL10n;
}
async getLanguage() {
return this.mozL10n.getLanguage();
}
async getDirection() {
return this.mozL10n.getDirection();
}
async get(key, args = null, fallback = getL10nFallback(key, args)) {
return this.mozL10n.get(key, args, fallback);
}
async translate(element) {
this.mozL10n.translate(element);
}
}
(function listenFindEvents() {
const events = [
"find",
@ -445,10 +422,12 @@ class FirefoxExternalServices extends DefaultExternalServices {
FirefoxCom.request("updateEditorStates", data);
}
static createL10n(options) {
const mozL10n = document.mozL10n;
// TODO refactor mozL10n.setExternalLocalizerServices
return new MozL10n(mozL10n);
static async createL10n(_options) {
const [localeProperties] = await Promise.all([
FirefoxCom.requestAsync("getLocaleProperties", null),
document.l10n.ready,
]);
return new L10n(localeProperties, document.l10n);
}
static createScripting(options) {
@ -499,15 +478,4 @@ class FirefoxExternalServices extends DefaultExternalServices {
}
PDFViewerApplication.externalServices = FirefoxExternalServices;
// l10n.js for Firefox extension expects services to be set.
document.mozL10n.setExternalLocalizerServices({
getLocale() {
return FirefoxCom.requestSync("getLocale", null);
},
getStrings(key) {
return FirefoxCom.requestSync("getStrings", null);
},
});
export { DownloadManager, FirefoxCom };

View file

@ -46,7 +46,7 @@ class GenericExternalServices extends DefaultExternalServices {
return new GenericPreferences();
}
static createL10n({ locale = "en-US" }) {
static async createL10n({ locale = "en-US" }) {
return new GenericL10n(locale);
}

View file

@ -15,63 +15,68 @@
/** @typedef {import("./interfaces").IL10n} IL10n */
import "../external/webL10n/l10n.js";
import { getL10nFallback } from "./l10n_utils.js";
const PARTIAL_LANG_CODES = {
en: "en-US",
es: "es-ES",
fy: "fy-NL",
ga: "ga-IE",
gu: "gu-IN",
hi: "hi-IN",
hy: "hy-AM",
nb: "nb-NO",
ne: "ne-NP",
nn: "nn-NO",
pa: "pa-IN",
pt: "pt-PT",
sv: "sv-SE",
zh: "zh-CN",
};
// Try to support "incompletely" specified language codes (see issue 13689).
function fixupLangCode(langCode) {
return PARTIAL_LANG_CODES[langCode?.toLowerCase()] || langCode;
}
import { FluentBundle, FluentResource } from "fluent-bundle";
import { DOMLocalization } from "fluent-dom";
import { L10n } from "./l10n.js";
/**
* @implements {IL10n}
*/
class GenericL10n {
class GenericL10n extends L10n {
constructor(lang) {
const { webL10n } = document;
this._lang = lang;
this._ready = new Promise((resolve, reject) => {
webL10n.setLanguage(fixupLangCode(lang), () => {
resolve(webL10n);
});
});
super({ lang });
this.setL10n(
new DOMLocalization(
[],
GenericL10n.#generateBundles.bind(
GenericL10n,
"en-US",
this.getLanguage()
)
)
);
}
async getLanguage() {
const l10n = await this._ready;
return l10n.getLanguage();
/**
* Generate the bundles for Fluent.
* @param {String} defaultLang - The fallback language to use for
* translations.
* @param {String} baseLang - The base language to use for translations.
*/
static async *#generateBundles(defaultLang, baseLang) {
const { baseURL, paths } = await this.#getPaths();
const langs =
baseLang === defaultLang ? [baseLang] : [baseLang, defaultLang];
for (const lang of langs) {
const bundle = await this.#createBundle(lang, baseURL, paths);
if (bundle) {
yield bundle;
}
}
}
async getDirection() {
const l10n = await this._ready;
return l10n.getDirection();
static async #createBundle(lang, baseURL, paths) {
const path = paths[lang];
if (!path) {
return null;
}
const url = new URL(path, baseURL);
const data = await fetch(url);
const text = await data.text();
const resource = new FluentResource(text);
const bundle = new FluentBundle(lang);
const errors = bundle.addResource(resource);
if (errors.length) {
console.error("L10n errors", errors);
}
return bundle;
}
async get(key, args = null, fallback = getL10nFallback(key, args)) {
const l10n = await this._ready;
return l10n.get(key, args, fallback);
}
async translate(element) {
const l10n = await this._ready;
return l10n.translate(element);
static async #getPaths() {
const { href } = document.querySelector(`link[type="application/l10n"]`);
const data = await fetch(href);
const paths = await data.json();
return { baseURL: href.replace(/[^/]*$/, "") || "./", paths };
}
}

View file

@ -179,14 +179,14 @@ class IDownloadManager {
*/
class IL10n {
/**
* @returns {Promise<string>} - Resolves to the current locale.
* @returns {string} - The current locale.
*/
async getLanguage() {}
getLanguage() {}
/**
* @returns {Promise<string>} - Resolves to 'rtl' or 'ltr'.
* @returns {string} - 'rtl' or 'ltr'.
*/
async getDirection() {}
getDirection() {}
/**
* Translates text identified by the key and adds/formats data using the args

105
web/l10n.js Normal file
View file

@ -0,0 +1,105 @@
/* Copyright 2023 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @typedef {import("./interfaces").IL10n} IL10n */
/**
* @implements {IL10n}
*/
class L10n {
#dir;
#lang;
#l10n;
constructor({ lang, isRTL }, l10n = null) {
this.#lang = L10n.#fixupLangCode(lang);
this.#l10n = l10n;
this.#dir = isRTL ?? L10n.#isRTL(this.#lang) ? "rtl" : "ltr";
}
setL10n(l10n) {
this.#l10n = l10n;
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) {
document.l10n = l10n;
}
}
/** @inheritdoc */
getLanguage() {
return this.#lang;
}
/** @inheritdoc */
getDirection() {
return this.#dir;
}
/** @inheritdoc */
async get(ids, args = null, fallback) {
if (Array.isArray(ids)) {
ids = ids.map(id => ({ id }));
const messages = await this.#l10n.formatMessages(ids);
return messages.map(message => message.value);
}
const messages = await this.#l10n.formatMessages([
{
id: ids,
args,
},
]);
return messages?.[0].value || fallback;
}
/** @inheritdoc */
async translate(element) {
try {
this.#l10n.connectRoot(element);
await this.#l10n.translateRoots();
} catch {
// Element is under an existing root, so there is no need to add it again.
}
}
static #fixupLangCode(langCode) {
// Try to support "incompletely" specified language codes (see issue 13689).
const PARTIAL_LANG_CODES = {
en: "en-US",
es: "es-ES",
fy: "fy-NL",
ga: "ga-IE",
gu: "gu-IN",
hi: "hi-IN",
hy: "hy-AM",
nb: "nb-NO",
ne: "ne-NP",
nn: "nn-NO",
pa: "pa-IN",
pt: "pt-PT",
sv: "sv-SE",
zh: "zh-CN",
};
return PARTIAL_LANG_CODES[langCode?.toLowerCase()] || langCode;
}
static #isRTL(lang) {
const shortCode = lang.split("-", 1)[0];
return ["ar", "he", "fa", "ps", "ur"].includes(shortCode);
}
}
export { L10n };

View file

@ -21,102 +21,102 @@
*/
/**
* A subset of the l10n strings in the `l10n/en-US/viewer.properties` file.
* A subset of the l10n strings in the `l10n/en-US/viewer.ftl` file.
*/
const DEFAULT_L10N_STRINGS = {
of_pages: "of {{pagesCount}}",
page_of_pages: "({{pageNumber}} of {{pagesCount}})",
"pdfjs-of-pages": "of { $pagesCount }",
"pdfjs-page-of-pages": "({ $pageNumber } of { $pagesCount })",
document_properties_kb: "{{size_kb}} KB ({{size_b}} bytes)",
document_properties_mb: "{{size_mb}} MB ({{size_b}} bytes)",
document_properties_date_string: "{{date}}, {{time}}",
document_properties_page_size_unit_inches: "in",
document_properties_page_size_unit_millimeters: "mm",
document_properties_page_size_orientation_portrait: "portrait",
document_properties_page_size_orientation_landscape: "landscape",
document_properties_page_size_name_a3: "A3",
document_properties_page_size_name_a4: "A4",
document_properties_page_size_name_letter: "Letter",
document_properties_page_size_name_legal: "Legal",
document_properties_page_size_dimension_string:
"{{width}} × {{height}} {{unit}} ({{orientation}})",
document_properties_page_size_dimension_name_string:
"{{width}} × {{height}} {{unit}} ({{name}}, {{orientation}})",
document_properties_linearized_yes: "Yes",
document_properties_linearized_no: "No",
"pdfjs-document-properties-kb": "{ $size-kb } KB ({ $size-b } bytes)",
"pdfjs-document-properties-mb": "{ $size-mb } MB ({ $size-b } bytes)",
"pdfjs-document-properties-date-string": "{ $date }, { $time }",
"pdfjs-document-properties-page-size-unit-inches": "in",
"pdfjs-document-properties-page-size-unit-millimeters": "mm",
"pdfjs-document-properties-page-size-orientation-portrait": "portrait",
"pdfjs-document-properties-page-size-orientation-landscape": "landscape",
"pdfjs-document-properties-page-size-name-a3": "A3",
"pdfjs-document-properties-page-size-name-a4": "A4",
"pdfjs-document-properties-page-size-name-letter": "Letter",
"pdfjs-document-properties-page-size-name-legal": "Legal",
"pdfjs-document-properties-page-size-dimension-string":
"{ $width } × { $height } { $unit } ({ $orientation })",
"pdfjs-document-properties-page-size-dimension-name-string":
"{ $width } × { $height } { $unit } ({ $name }, { $orientation })",
"pdfjs-document-properties-linearized-yes": "Yes",
"pdfjs-document-properties-linearized-no": "No",
additional_layers: "Additional Layers",
page_landmark: "Page {{page}}",
thumb_page_title: "Page {{page}}",
thumb_page_canvas: "Thumbnail of Page {{page}}",
"pdfjs-additional-layers": "Additional Layers",
"pdfjs-page-landmark": "Page { $page }",
"pdfjs-thumb-page-title": "Page { $page }",
"pdfjs-thumb-page-canvas": "Thumbnail of Page { $page }",
find_reached_top: "Reached top of document, continued from bottom",
find_reached_bottom: "Reached end of document, continued from top",
"find_match_count[one]": "{{current}} of {{total}} match",
"find_match_count[other]": "{{current}} of {{total}} matches",
"find_match_count_limit[one]": "More than {{limit}} match",
"find_match_count_limit[other]": "More than {{limit}} matches",
find_not_found: "Phrase not found",
"pdfjs-find-reached-top": "Reached top of document, continued from bottom",
"pdfjs-find-reached-bottom": "Reached end of document, continued from top",
"pdfjs-find-match-count[one]": "{ $current } of { $total } match",
"pdfjs-find-match-count[other]": "{ $current } of { $total } matches",
"pdfjs-find-match-count-limit[one]": "More than { $limit } match",
"pdfjs-find-match-count-limit[other]": "More than { $limit } matches",
"pdfjs-find-not-found": "Phrase not found",
page_scale_width: "Page Width",
page_scale_fit: "Page Fit",
page_scale_auto: "Automatic Zoom",
page_scale_actual: "Actual Size",
page_scale_percent: "{{scale}}%",
"pdfjs-page-scale-width": "Page Width",
"pdfjs-page-scale-fit": "Page Fit",
"pdfjs-page-scale-auto": "Automatic Zoom",
"pdfjs-page-scale-actual": "Actual Size",
"pdfjs-page-scale-percent": "{ $scale }%",
loading_error: "An error occurred while loading the PDF.",
invalid_file_error: "Invalid or corrupted PDF file.",
missing_file_error: "Missing PDF file.",
unexpected_response_error: "Unexpected server response.",
rendering_error: "An error occurred while rendering the page.",
"pdfjs-loading-error": "An error occurred while loading the PDF.",
"pdfjs-invalid-file-error": "Invalid or corrupted PDF file.",
"pdfjs-missing-file-error": "Missing PDF file.",
"pdfjs-unexpected-response-error": "Unexpected server response.",
"pdfjs-rendering-error": "An error occurred while rendering the page.",
annotation_date_string: "{{date}}, {{time}}",
"pdfjs-annotation-date-string": "{ $date }, { $time }",
printing_not_supported:
"pdfjs-printing-not-supported":
"Warning: Printing is not fully supported by this browser.",
printing_not_ready: "Warning: The PDF is not fully loaded for printing.",
web_fonts_disabled:
"pdfjs-printing-not-ready":
"Warning: The PDF is not fully loaded for printing.",
"pdfjs-web-fonts-disabled":
"Web fonts are disabled: unable to use embedded PDF fonts.",
free_text2_default_content: "Start typing…",
editor_free_text2_aria_label: "Text Editor",
editor_ink2_aria_label: "Draw Editor",
editor_ink_canvas_aria_label: "User-created image",
editor_alt_text_button_label: "Alt text",
editor_alt_text_edit_button_label: "Edit alt text",
editor_alt_text_decorative_tooltip: "Marked as decorative",
editor_resizer_label_topLeft: "Top left corner — resize",
editor_resizer_label_topMiddle: "Top middle — resize",
editor_resizer_label_topRight: "Top right corner — resize",
editor_resizer_label_middleRight: "Middle right — resize",
editor_resizer_label_bottomRight: "Bottom right corner — resize",
editor_resizer_label_bottomMiddle: "Bottom middle — resize",
editor_resizer_label_bottomLeft: "Bottom left corner — resize",
editor_resizer_label_middleLeft: "Middle left — resize",
"pdfjs-free-text-default-content": "Start typing…",
"pdfjs-editor-alt-text-button-label": "Alt text",
"pdfjs-editor-alt-text-edit-button-label": "Edit alt text",
"pdfjs-editor-alt-text-decorative-tooltip": "Marked as decorative",
"pdfjs-editor-resizer-label-top-left": "Top left corner — resize",
"pdfjs-editor-resizer-label-top-middle": "Top middle — resize",
"pdfjs-editor-resizer-label-top-right": "Top right corner — resize",
"pdfjs-editor-resizer-label-middle-right": "Middle right — resize",
"pdfjs-editor-resizer-label-bottom-right": "Bottom right corner — resize",
"pdfjs-editor-resizer-label-bottom-middle": "Bottom middle — resize",
"pdfjs-editor-resizer-label-bottom-left": "Bottom left corner — resize",
"pdfjs-editor-resizer-label-middle-left": "Middle left — resize",
};
if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) {
DEFAULT_L10N_STRINGS.print_progress_percent = "{{progress}}%";
DEFAULT_L10N_STRINGS.print_progress_percent = "{ $progress }%";
}
function getL10nFallback(key, args) {
switch (key) {
case "find_match_count":
key = `find_match_count[${args.total === 1 ? "one" : "other"}]`;
case "pdfjs-find-match-count":
key = `pdfjs-find-match-count[${args.total === 1 ? "one" : "other"}]`;
break;
case "find_match_count_limit":
key = `find_match_count_limit[${args.limit === 1 ? "one" : "other"}]`;
case "pdfjs-find-match-count-limit":
key = `pdfjs-find-match-count-limit[${
args.limit === 1 ? "one" : "other"
}]`;
break;
}
return DEFAULT_L10N_STRINGS[key] || "";
}
// Replaces {{arguments}} with their values.
// Replaces { $arguments } with their values.
function formatL10nValue(text, args) {
if (!args) {
return text;
}
return text.replaceAll(/\{\{\s*(\w+)\s*\}\}/g, (all, name) => {
return name in args ? args[name] : "{{" + name + "}}";
return text.replaceAll(/\{\s*$(\w+)\s*\}/g, (all, name) => {
return name in args ? args[name] : "{$" + name + "}";
});
}
@ -125,11 +125,11 @@ function formatL10nValue(text, args) {
* @implements {IL10n}
*/
const NullL10n = {
async getLanguage() {
getLanguage() {
return "en-us";
},
async getDirection() {
getDirection() {
return "ltr";
},
@ -140,4 +140,4 @@ const NullL10n = {
async translate(element) {},
};
export { getL10nFallback, NullL10n };
export { NullL10n };

View file

@ -85,7 +85,7 @@ class PasswordPrompt {
this.input.focus();
}
this.label.textContent = await this.l10n.get(
`password_${passwordIncorrect ? "invalid" : "label"}`
`pdfjs-password-${passwordIncorrect ? "invalid" : "label"}`
);
}

View file

@ -28,8 +28,8 @@ const US_PAGE_NAMES = {
"8.5x14": "Legal",
};
const METRIC_PAGE_NAMES = {
"297x420": "A3",
"210x297": "A4",
"297x420": "a-three",
"210x297": "a-four",
};
function getPageName(size, isPortrait, pageNames) {
@ -83,10 +83,7 @@ class PDFDocumentProperties {
this._pagesRotation = evt.pagesRotation;
});
this._isNonMetricLocale = true; // The default viewer locale is 'en-us'.
l10n.getLanguage().then(locale => {
this._isNonMetricLocale = NON_METRIC_LOCALES.includes(locale);
});
this._isNonMetricLocale = NON_METRIC_LOCALES.includes(l10n.getLanguage());
}
/**
@ -236,7 +233,7 @@ class PDFDocumentProperties {
if (!kb) {
return undefined;
}
return this.l10n.get(`document_properties_${mb >= 1 ? "mb" : "kb"}`, {
return this.l10n.get(`pdfjs-document-properties-${mb >= 1 ? "mb" : "kb"}`, {
size_mb: mb >= 1 && (+mb.toPrecision(3)).toLocaleString(),
size_kb: mb < 1 && (+kb.toPrecision(3)).toLocaleString(),
size_b: fileSize.toLocaleString(),
@ -310,23 +307,25 @@ class PDFDocumentProperties {
const [{ width, height }, unit, name, orientation] = await Promise.all([
this._isNonMetricLocale ? sizeInches : sizeMillimeters,
this.l10n.get(
`document_properties_page_size_unit_${
`pdfjs-document-properties-page-size-unit-${
this._isNonMetricLocale ? "inches" : "millimeters"
}`
),
rawName &&
this.l10n.get(
`document_properties_page_size_name_${rawName.toLowerCase()}`
`pdfjs-document-properties-page-size-name-${rawName.toLowerCase()}`
),
this.l10n.get(
`document_properties_page_size_orientation_${
`pdfjs-document-properties-page-size-orientation-${
isPortrait ? "portrait" : "landscape"
}`
),
]);
return this.l10n.get(
`document_properties_page_size_dimension_${name ? "name_" : ""}string`,
`pdfjs-document-properties-page-size-dimension-${
name ? "name-" : ""
}string`,
{
width: width.toLocaleString(),
height: height.toLocaleString(),
@ -342,7 +341,7 @@ class PDFDocumentProperties {
if (!dateObject) {
return undefined;
}
return this.l10n.get("document_properties_date_string", {
return this.l10n.get("pdfjs-document-properties-date-string", {
date: dateObject.toLocaleDateString(),
time: dateObject.toLocaleTimeString(),
});
@ -350,7 +349,7 @@ class PDFDocumentProperties {
#parseLinearization(isLinearized) {
return this.l10n.get(
`document_properties_linearized_${isLinearized ? "yes" : "no"}`
`pdfjs-document-properties-linearized-${isLinearized ? "yes" : "no"}`
);
}
}

View file

@ -119,11 +119,13 @@ class PDFFindBar {
status = "pending";
break;
case FindState.NOT_FOUND:
findMsg = this.l10n.get("find_not_found");
findMsg = this.l10n.get("pdfjs-find-not-found");
status = "notFound";
break;
case FindState.WRAPPED:
findMsg = this.l10n.get(`find_reached_${previous ? "top" : "bottom"}`);
findMsg = this.l10n.get(
`pdfjs-find-reached-${previous ? "top" : "bottom"}`
);
break;
}
this.findField.setAttribute("data-status", status);
@ -143,25 +145,10 @@ class PDFFindBar {
let matchCountMsg = Promise.resolve("");
if (total > 0) {
if (total > limit) {
let key = "find_match_count_limit";
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
// TODO: Remove this hard-coded `[other]` form once plural support has
// been implemented in the mozilla-central specific `l10n.js` file.
key += "[other]";
}
matchCountMsg = this.l10n.get(key, { limit });
} else {
let key = "find_match_count";
if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("MOZCENTRAL")) {
// TODO: Remove this hard-coded `[other]` form once plural support has
// been implemented in the mozilla-central specific `l10n.js` file.
key += "[other]";
}
matchCountMsg = this.l10n.get(key, { current, total });
}
matchCountMsg =
total > limit
? this.l10n.get("pdfjs-find-match-count-limit", { limit })
: this.l10n.get("pdfjs-find-match-count", { current, total });
}
matchCountMsg.then(msg => {
this.findResultsCount.textContent = msg;

View file

@ -94,7 +94,7 @@ class PDFLayerViewer extends BaseTreeViewer {
element.textContent = this._normalizeTextContent(name);
return;
}
element.textContent = await this.l10n.get("additional_layers");
element.setAttribute("data-l10n-id", "pdfjs-additional-layers");
element.style.fontStyle = "italic";
}

View file

@ -182,7 +182,7 @@ class PDFPageView {
div.className = "page";
div.setAttribute("data-page-number", this.id);
div.setAttribute("role", "region");
this.l10n.get("page_landmark", { page: this.id }).then(msg => {
this.l10n.get("pdfjs-page-landmark", { page: this.id }).then(msg => {
div.setAttribute("aria-label", msg);
});
this.div = div;

View file

@ -297,7 +297,7 @@ function renderProgress(index, total, l10n) {
const progressBar = dialog.querySelector("progress");
const progressPerc = dialog.querySelector(".relative-progress");
progressBar.value = progress;
l10n.get("print_progress_percent", { progress }).then(msg => {
l10n.get("pdfjs-print-progress-percent", { progress }).then(msg => {
progressPerc.textContent = msg;
});
}

View file

@ -113,9 +113,7 @@ class PDFSidebar {
this.eventBus = eventBus;
this.l10n = l10n;
l10n.getDirection().then(dir => {
this.#isRTL = dir === "rtl";
});
this.#isRTL = l10n.getDirection() === "rtl";
this.#addEventListeners();
}
@ -303,9 +301,8 @@ class PDFSidebar {
#showUINotification() {
this.toggleButton.setAttribute(
"data-l10n-id",
"toggle_sidebar_notification2"
"pdfjs-toggle-sidebar-notification-button"
);
this.l10n.translate(this.toggleButton);
if (!this.isOpen) {
// Only show the notification on the `toggleButton` if the sidebar is
@ -322,8 +319,10 @@ class PDFSidebar {
}
if (reset) {
this.toggleButton.setAttribute("data-l10n-id", "toggle_sidebar");
this.l10n.translate(this.toggleButton);
this.toggleButton.setAttribute(
"data-l10n-id",
"pdfjs-toggle-sidebar-button"
);
}
}

View file

@ -424,13 +424,13 @@ class PDFThumbnailView {
}
get _thumbPageTitle() {
return this.l10n.get("thumb_page_title", {
return this.l10n.get("pdfjs-thumb-page-title", {
page: this.pageLabel ?? this.id,
});
}
get _thumbPageCanvas() {
return this.l10n.get("thumb_page_canvas", {
return this.l10n.get("pdfjs-thumb-page-canvas", {
page: this.pageLabel ?? this.id,
});
}

View file

@ -267,7 +267,7 @@ class Toolbar {
items.pageNumber.type = "text";
} else {
items.pageNumber.type = "number";
this.l10n.get("of_pages", { pagesCount }).then(msg => {
this.l10n.get("pdfjs-of-pages", { pagesCount }).then(msg => {
items.numPages.textContent = msg;
});
}
@ -276,9 +276,11 @@ class Toolbar {
if (this.hasPageLabels) {
items.pageNumber.value = this.pageLabel;
this.l10n.get("page_of_pages", { pageNumber, pagesCount }).then(msg => {
items.numPages.textContent = msg;
});
this.l10n
.get("pdfjs-page-of-pages", { pageNumber, pagesCount })
.then(msg => {
items.numPages.textContent = msg;
});
} else {
items.pageNumber.value = pageNumber;
}
@ -290,7 +292,9 @@ class Toolbar {
items.zoomIn.disabled = pageScale >= MAX_SCALE;
this.l10n
.get("page_scale_percent", { scale: Math.round(pageScale * 10000) / 100 })
.get("pdfjs-page-scale-percent", {
scale: Math.round(pageScale * 10000) / 100,
})
.then(msg => {
let predefinedValueFound = false;
for (const option of items.scaleSelect.options) {
@ -321,11 +325,11 @@ class Toolbar {
async #adjustScaleWidth() {
const { items, l10n } = this;
const predefinedValuesPromise = Promise.all([
l10n.get("page_scale_auto"),
l10n.get("page_scale_actual"),
l10n.get("page_scale_fit"),
l10n.get("page_scale_width"),
const predefinedValuesPromise = l10n.get([
"pdfjs-page-scale-auto",
"pdfjs-page-scale-actual",
"pdfjs-page-scale-fit",
"pdfjs-page-scale-width",
]);
await animationStarted;

View file

@ -32,12 +32,13 @@ See https://github.com/adobe-type-tools/cmap-resources
<!--#if MOZCENTRAL-->
<!--<link rel="stylesheet" href="resource://pdf.js/web/viewer.css">-->
<!--<link rel="localization" href="toolkit/pdfviewer/viewer.ftl"/>-->
<!--#else-->
<link rel="stylesheet" href="viewer-geckoview.css">
<!--#endif-->
<!--#if !MOZCENTRAL-->
<link rel="resource" type="application/l10n" href="locale/locale.properties">
<link rel="resource" type="application/l10n" href="locale/locale.json">
<!--#endif-->
<!--#if !MOZCENTRAL-->
@ -48,6 +49,10 @@ See https://github.com/adobe-type-tools/cmap-resources
"pdfjs-lib": "../src/pdf.js",
"pdfjs-web/": "./",
"fluent-bundle": "../node_modules/@fluent/bundle/esm/index.js",
"fluent-dom": "../node_modules/@fluent/dom/esm/index.js",
"cached-iterable": "../node_modules/cached-iterable/src/index.mjs",
"display-fetch_stream": "../src/display/fetch_stream.js",
"display-l10n_utils": "../src/display/stubs.js",
"display-network": "../src/display/network.js",
@ -85,11 +90,11 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="mainContainer">
<div id="floatingToolbar">
<button id="download" class="toolbarButton" title="Download" tabindex="31" data-l10n-id="download_button">
<span data-l10n-id="download_button_label">Download</span>
<button id="download" class="toolbarButton" title="Download" tabindex="31" data-l10n-id="pdfjs-download-button">
<span data-l10n-id="pdfjs-download-button-label">Download</span>
</button>
<button id="openInApp" class="toolbarButton" title="Open in app" tabindex="32" data-l10n-id="open_in_app">
<span data-l10n-id="open_in_app_label">Open in app</span>
<button id="openInApp" class="toolbarButton" title="Open in app" tabindex="32" data-l10n-id="pdfjs-open-in-app-button">
<span data-l10n-id="pdfjs-open-in-app-button-label">Open in app</span>
</button>
</div>
@ -101,14 +106,14 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="dialogContainer">
<dialog id="passwordDialog">
<div class="row">
<label for="password" id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</label>
<label for="password" id="passwordText" data-l10n-id="pdfjs-password-label">Enter the password to open this PDF file:</label>
</div>
<div class="row">
<input type="password" id="password" class="toolbarField">
</div>
<div class="buttonRow">
<button id="passwordCancel" class="dialogButton"><span data-l10n-id="password_cancel">Cancel</span></button>
<button id="passwordSubmit" class="dialogButton"><span data-l10n-id="password_ok">OK</span></button>
<button id="passwordCancel" class="dialogButton"><span data-l10n-id="pdfjs-password-cancel-button">Cancel</span></button>
<button id="passwordSubmit" class="dialogButton"><span data-l10n-id="pdfjs-password-ok-button">OK</span></button>
</div>
</dialog>
</div> <!-- dialogContainer -->

View file

@ -1,4 +1,4 @@
<!-- This snippet is used in the Chromium extension (included from viewer.html) -->
<base href="/content/web/">
<link rel="resource" type="application/l10n" href="locale/locale.properties">
<link rel="resource" type="application/l10n" href="locale/locale.json">
<script src="../build/pdf.mjs" type="module"></script>

View file

@ -1,3 +1,3 @@
<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="locale/locale.properties">
<link rel="resource" type="application/l10n" href="locale/locale.json">
<script src="../build/pdf.mjs" type="module"></script>

View file

@ -39,6 +39,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<!--#if MOZCENTRAL-->
<!--<link rel="stylesheet" href="resource://pdf.js/web/viewer.css">-->
<!--<link rel="localization" href="toolkit/pdfviewer/viewer.ftl"/>-->
<!--#else-->
<link rel="stylesheet" href="viewer.css">
<!--#endif-->
@ -48,7 +49,7 @@ See https://github.com/adobe-type-tools/cmap-resources
<!--#elif !MOZCENTRAL-->
<!--<script src="viewer.mjs" type="module"></script>-->
<!--#elif /* Development mode. */-->
<link rel="resource" type="application/l10n" href="locale/locale.properties">
<link rel="resource" type="application/l10n" href="locale/locale.json">
<script type="importmap">
{
@ -57,6 +58,10 @@ See https://github.com/adobe-type-tools/cmap-resources
"pdfjs-lib": "../src/pdf.js",
"pdfjs-web/": "./",
"fluent-bundle": "../node_modules/@fluent/bundle/esm/index.js",
"fluent-dom": "../node_modules/@fluent/dom/esm/index.js",
"cached-iterable": "../node_modules/cached-iterable/src/index.mjs",
"display-fetch_stream": "../src/display/fetch_stream.js",
"display-l10n_utils": "../src/display/stubs.js",
"display-network": "../src/display/network.js",
@ -92,17 +97,17 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="toolbarSidebar">
<div id="toolbarSidebarLeft">
<div id="sidebarViewButtons" class="splitToolbarButton toggled" role="radiogroup">
<button id="viewThumbnail" class="toolbarButton toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="thumbs" role="radio" aria-checked="true" aria-controls="thumbnailView">
<span data-l10n-id="thumbs_label">Thumbnails</span>
<button id="viewThumbnail" class="toolbarButton toggled" title="Show Thumbnails" tabindex="2" data-l10n-id="pdfjs-thumbs-button" role="radio" aria-checked="true" aria-controls="thumbnailView">
<span data-l10n-id="pdfjs-thumbs-button-label">Thumbnails</span>
</button>
<button id="viewOutline" class="toolbarButton" title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3" data-l10n-id="document_outline" role="radio" aria-checked="false" aria-controls="outlineView">
<span data-l10n-id="document_outline_label">Document Outline</span>
<button id="viewOutline" class="toolbarButton" title="Show Document Outline (double-click to expand/collapse all items)" tabindex="3" data-l10n-id="pdfjs-document-outline-button" role="radio" aria-checked="false" aria-controls="outlineView">
<span data-l10n-id="pdfjs-document-outline-button-label">Document Outline</span>
</button>
<button id="viewAttachments" class="toolbarButton" title="Show Attachments" tabindex="4" data-l10n-id="attachments" role="radio" aria-checked="false" aria-controls="attachmentsView">
<span data-l10n-id="attachments_label">Attachments</span>
<button id="viewAttachments" class="toolbarButton" title="Show Attachments" tabindex="4" data-l10n-id="pdfjs-attachments-button" role="radio" aria-checked="false" aria-controls="attachmentsView">
<span data-l10n-id="pdfjs-attachments-button-label">Attachments</span>
</button>
<button id="viewLayers" class="toolbarButton" title="Show Layers (double-click to reset all layers to the default state)" tabindex="5" data-l10n-id="layers" role="radio" aria-checked="false" aria-controls="layersView">
<span data-l10n-id="layers_label">Layers</span>
<button id="viewLayers" class="toolbarButton" title="Show Layers (double-click to reset all layers to the default state)" tabindex="5" data-l10n-id="pdfjs-layers-button" role="radio" aria-checked="false" aria-controls="layersView">
<span data-l10n-id="pdfjs-layers-button-label">Layers</span>
</button>
</div>
</div>
@ -111,8 +116,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="outlineOptionsContainer" class="hidden">
<div class="verticalToolbarSeparator"></div>
<button id="currentOutlineItem" class="toolbarButton" disabled="disabled" title="Find Current Outline Item" tabindex="6" data-l10n-id="current_outline_item">
<span data-l10n-id="current_outline_item_label">Current Outline Item</span>
<button id="currentOutlineItem" class="toolbarButton" disabled="disabled" title="Find Current Outline Item" tabindex="6" data-l10n-id="pdfjs-current-outline-item-button">
<span data-l10n-id="pdfjs-current-outline-item-button-label">Current Outline Item</span>
</button>
</div>
</div>
@ -133,29 +138,29 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="mainContainer">
<div class="findbar hidden doorHanger" id="findbar">
<div id="findbarInputContainer">
<input id="findInput" class="toolbarField" title="Find" placeholder="Find in document…" tabindex="91" data-l10n-id="find_input" aria-invalid="false">
<input id="findInput" class="toolbarField" title="Find" placeholder="Find in document…" tabindex="91" data-l10n-id="pdfjs-find-input" aria-invalid="false">
<div class="splitToolbarButton">
<button id="findPrevious" class="toolbarButton" title="Find the previous occurrence of the phrase" tabindex="92" data-l10n-id="find_previous">
<span data-l10n-id="find_previous_label">Previous</span>
<button id="findPrevious" class="toolbarButton" title="Find the previous occurrence of the phrase" tabindex="92" data-l10n-id="pdfjs-find-previous-button">
<span data-l10n-id="pdfjs-find-previous-button-label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button id="findNext" class="toolbarButton" title="Find the next occurrence of the phrase" tabindex="93" data-l10n-id="find_next">
<span data-l10n-id="find_next_label">Next</span>
<button id="findNext" class="toolbarButton" title="Find the next occurrence of the phrase" tabindex="93" data-l10n-id="pdfjs-find-next-button">
<span data-l10n-id="pdfjs-find-next-button-label">Next</span>
</button>
</div>
</div>
<div id="findbarOptionsOneContainer">
<input type="checkbox" id="findHighlightAll" class="toolbarField" tabindex="94">
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="find_highlight">Highlight All</label>
<label for="findHighlightAll" class="toolbarLabel" data-l10n-id="pdfjs-find-highlight-checkbox">Highlight All</label>
<input type="checkbox" id="findMatchCase" class="toolbarField" tabindex="95">
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="find_match_case_label">Match Case</label>
<label for="findMatchCase" class="toolbarLabel" data-l10n-id="pdfjs-find-match-case-checkbox-label">Match Case</label>
</div>
<div id="findbarOptionsTwoContainer">
<input type="checkbox" id="findMatchDiacritics" class="toolbarField" tabindex="96">
<label for="findMatchDiacritics" class="toolbarLabel" data-l10n-id="find_match_diacritics_label">Match Diacritics</label>
<label for="findMatchDiacritics" class="toolbarLabel" data-l10n-id="pdfjs-find-match-diacritics-checkbox-label">Match Diacritics</label>
<input type="checkbox" id="findEntireWord" class="toolbarField" tabindex="97">
<label for="findEntireWord" class="toolbarLabel" data-l10n-id="find_entire_word_label">Whole Words</label>
<label for="findEntireWord" class="toolbarLabel" data-l10n-id="pdfjs-find-entire-word-checkbox-label">Whole Words</label>
</div>
<div id="findbarMessageContainer" aria-live="polite">
@ -167,11 +172,11 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="editorParamsToolbar hidden doorHangerRight" id="editorFreeTextParamsToolbar">
<div class="editorParamsToolbarContainer">
<div class="editorParamsSetter">
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="editor_free_text_color">Color</label>
<label for="editorFreeTextColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-color-input">Color</label>
<input type="color" id="editorFreeTextColor" class="editorParamsColor" tabindex="100">
</div>
<div class="editorParamsSetter">
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="editor_free_text_size">Size</label>
<label for="editorFreeTextFontSize" class="editorParamsLabel" data-l10n-id="pdfjs-editor-free-text-size-input">Size</label>
<input type="range" id="editorFreeTextFontSize" class="editorParamsSlider" value="10" min="5" max="100" step="1" tabindex="101">
</div>
</div>
@ -180,15 +185,15 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="editorParamsToolbar hidden doorHangerRight" id="editorInkParamsToolbar">
<div class="editorParamsToolbarContainer">
<div class="editorParamsSetter">
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="editor_ink_color">Color</label>
<label for="editorInkColor" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-color-input">Color</label>
<input type="color" id="editorInkColor" class="editorParamsColor" tabindex="102">
</div>
<div class="editorParamsSetter">
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="editor_ink_thickness">Thickness</label>
<label for="editorInkThickness" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-thickness-input">Thickness</label>
<input type="range" id="editorInkThickness" class="editorParamsSlider" value="1" min="1" max="20" step="1" tabindex="103">
</div>
<div class="editorParamsSetter">
<label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="editor_ink_opacity">Opacity</label>
<label for="editorInkOpacity" class="editorParamsLabel" data-l10n-id="pdfjs-editor-ink-opacity-input">Opacity</label>
<input type="range" id="editorInkOpacity" class="editorParamsSlider" value="100" min="1" max="100" step="1" tabindex="104">
</div>
</div>
@ -196,8 +201,8 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="editorParamsToolbar hidden doorHangerRight" id="editorStampParamsToolbar">
<div class="editorParamsToolbarContainer">
<button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="105" data-l10n-id="editor_stamp_add_image">
<span data-l10n-id="editor_stamp_add_image_label">Add image</span>
<button id="editorStampAddImage" class="secondaryToolbarButton" title="Add image" tabindex="105" data-l10n-id="pdfjs-editor-stamp-add-image-button">
<span data-l10n-id="pdfjs-editor-stamp-add-image-button-label">Add image</span>
</button>
</div>
</div>
@ -205,17 +210,17 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="secondaryToolbar" class="secondaryToolbar hidden doorHangerRight">
<div id="secondaryToolbarButtonContainer">
<!--#if GENERIC-->
<button id="secondaryOpenFile" class="secondaryToolbarButton visibleLargeView" title="Open File" tabindex="51" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
<button id="secondaryOpenFile" class="secondaryToolbarButton visibleLargeView" title="Open File" tabindex="51" data-l10n-id="pdfjs-open-file-button">
<span data-l10n-id="pdfjs-open-file-button-label">Open</span>
</button>
<!--#endif-->
<button id="secondaryPrint" class="secondaryToolbarButton visibleMediumView" title="Print" tabindex="52" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
<button id="secondaryPrint" class="secondaryToolbarButton visibleMediumView" title="Print" tabindex="52" data-l10n-id="pdfjs-print-button">
<span data-l10n-id="pdfjs-print-button-label">Print</span>
</button>
<button id="secondaryDownload" class="secondaryToolbarButton visibleMediumView" title="Save" tabindex="53" data-l10n-id="save">
<span data-l10n-id="save_label">Save</span>
<button id="secondaryDownload" class="secondaryToolbarButton visibleMediumView" title="Save" tabindex="53" data-l10n-id="pdfjs-save-button">
<span data-l10n-id="pdfjs-save-button-label">Save</span>
</button>
<!--#if GENERIC-->
@ -224,78 +229,78 @@ See https://github.com/adobe-type-tools/cmap-resources
<!-- <div class="horizontalToolbarSeparator visibleMediumView"></div>-->
<!--#endif-->
<button id="presentationMode" class="secondaryToolbarButton" title="Switch to Presentation Mode" tabindex="54" data-l10n-id="presentation_mode">
<span data-l10n-id="presentation_mode_label">Presentation Mode</span>
<button id="presentationMode" class="secondaryToolbarButton" title="Switch to Presentation Mode" tabindex="54" data-l10n-id="pdfjs-presentation-mode-button">
<span data-l10n-id="pdfjs-presentation-mode-button-label">Presentation Mode</span>
</button>
<a href="#" id="viewBookmark" class="secondaryToolbarButton" title="Current Page (View URL from Current Page)" tabindex="55" data-l10n-id="bookmark1">
<span data-l10n-id="bookmark1_label">Current Page</span>
<a href="#" id="viewBookmark" class="secondaryToolbarButton" title="Current Page (View URL from Current Page)" tabindex="55" data-l10n-id="pdfjs-bookmark-button">
<span data-l10n-id="pdfjs-bookmark-button-label">Current Page</span>
</a>
<div id="viewBookmarkSeparator" class="horizontalToolbarSeparator"></div>
<button id="firstPage" class="secondaryToolbarButton" title="Go to First Page" tabindex="56" data-l10n-id="first_page">
<span data-l10n-id="first_page_label">Go to First Page</span>
<button id="firstPage" class="secondaryToolbarButton" title="Go to First Page" tabindex="56" data-l10n-id="pdfjs-first-page-button">
<span data-l10n-id="pdfjs-first-page-button-label">Go to First Page</span>
</button>
<button id="lastPage" class="secondaryToolbarButton" title="Go to Last Page" tabindex="57" data-l10n-id="last_page">
<span data-l10n-id="last_page_label">Go to Last Page</span>
<button id="lastPage" class="secondaryToolbarButton" title="Go to Last Page" tabindex="57" data-l10n-id="pdfjs-last-page-button">
<span data-l10n-id="pdfjs-last-page-button-label">Go to Last Page</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<button id="pageRotateCw" class="secondaryToolbarButton" title="Rotate Clockwise" tabindex="58" data-l10n-id="page_rotate_cw">
<span data-l10n-id="page_rotate_cw_label">Rotate Clockwise</span>
<button id="pageRotateCw" class="secondaryToolbarButton" title="Rotate Clockwise" tabindex="58" data-l10n-id="pdfjs-page-rotate-cw-button">
<span data-l10n-id="pdfjs-page-rotate-cw-button-label">Rotate Clockwise</span>
</button>
<button id="pageRotateCcw" class="secondaryToolbarButton" title="Rotate Counterclockwise" tabindex="59" data-l10n-id="page_rotate_ccw">
<span data-l10n-id="page_rotate_ccw_label">Rotate Counterclockwise</span>
<button id="pageRotateCcw" class="secondaryToolbarButton" title="Rotate Counterclockwise" tabindex="59" data-l10n-id="pdfjs-page-rotate-ccw-button">
<span data-l10n-id="pdfjs-page-rotate-ccw-button-label">Rotate Counterclockwise</span>
</button>
<div class="horizontalToolbarSeparator"></div>
<div id="cursorToolButtons" role="radiogroup">
<button id="cursorSelectTool" class="secondaryToolbarButton toggled" title="Enable Text Selection Tool" tabindex="60" data-l10n-id="cursor_text_select_tool" role="radio" aria-checked="true">
<span data-l10n-id="cursor_text_select_tool_label">Text Selection Tool</span>
<button id="cursorSelectTool" class="secondaryToolbarButton toggled" title="Enable Text Selection Tool" tabindex="60" data-l10n-id="pdfjs-cursor-text-select-tool-button" role="radio" aria-checked="true">
<span data-l10n-id="pdfjs-cursor-text-select-tool-button-label">Text Selection Tool</span>
</button>
<button id="cursorHandTool" class="secondaryToolbarButton" title="Enable Hand Tool" tabindex="61" data-l10n-id="cursor_hand_tool" role="radio" aria-checked="false">
<span data-l10n-id="cursor_hand_tool_label">Hand Tool</span>
<button id="cursorHandTool" class="secondaryToolbarButton" title="Enable Hand Tool" tabindex="61" data-l10n-id="pdfjs-cursor-hand-tool-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-cursor-hand-tool-button-label">Hand Tool</span>
</button>
</div>
<div class="horizontalToolbarSeparator"></div>
<div id="scrollModeButtons" role="radiogroup">
<button id="scrollPage" class="secondaryToolbarButton" title="Use Page Scrolling" tabindex="62" data-l10n-id="scroll_page" role="radio" aria-checked="false">
<span data-l10n-id="scroll_page_label">Page Scrolling</span>
<button id="scrollPage" class="secondaryToolbarButton" title="Use Page Scrolling" tabindex="62" data-l10n-id="pdfjs-scroll-page-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-scroll-page-button-label">Page Scrolling</span>
</button>
<button id="scrollVertical" class="secondaryToolbarButton toggled" title="Use Vertical Scrolling" tabindex="63" data-l10n-id="scroll_vertical" role="radio" aria-checked="true">
<span data-l10n-id="scroll_vertical_label" >Vertical Scrolling</span>
<button id="scrollVertical" class="secondaryToolbarButton toggled" title="Use Vertical Scrolling" tabindex="63" data-l10n-id="pdfjs-scroll-vertical-button" role="radio" aria-checked="true">
<span data-l10n-id="pdfjs-scroll-vertical-button-label" >Vertical Scrolling</span>
</button>
<button id="scrollHorizontal" class="secondaryToolbarButton" title="Use Horizontal Scrolling" tabindex="64" data-l10n-id="scroll_horizontal" role="radio" aria-checked="false">
<span data-l10n-id="scroll_horizontal_label">Horizontal Scrolling</span>
<button id="scrollHorizontal" class="secondaryToolbarButton" title="Use Horizontal Scrolling" tabindex="64" data-l10n-id="pdfjs-scroll-horizontal-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-scroll-horizontal-button-label">Horizontal Scrolling</span>
</button>
<button id="scrollWrapped" class="secondaryToolbarButton" title="Use Wrapped Scrolling" tabindex="65" data-l10n-id="scroll_wrapped" role="radio" aria-checked="false">
<span data-l10n-id="scroll_wrapped_label">Wrapped Scrolling</span>
<button id="scrollWrapped" class="secondaryToolbarButton" title="Use Wrapped Scrolling" tabindex="65" data-l10n-id="pdfjs-scroll-wrapped-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-scroll-wrapped-button-label">Wrapped Scrolling</span>
</button>
</div>
<div class="horizontalToolbarSeparator"></div>
<div id="spreadModeButtons" role="radiogroup">
<button id="spreadNone" class="secondaryToolbarButton toggled" title="Do not join page spreads" tabindex="66" data-l10n-id="spread_none" role="radio" aria-checked="true">
<span data-l10n-id="spread_none_label">No Spreads</span>
<button id="spreadNone" class="secondaryToolbarButton toggled" title="Do not join page spreads" tabindex="66" data-l10n-id="pdfjs-spread-none-button" role="radio" aria-checked="true">
<span data-l10n-id="pdfjs-spread-none-button-label">No Spreads</span>
</button>
<button id="spreadOdd" class="secondaryToolbarButton" title="Join page spreads starting with odd-numbered pages" tabindex="67" data-l10n-id="spread_odd" role="radio" aria-checked="false">
<span data-l10n-id="spread_odd_label">Odd Spreads</span>
<button id="spreadOdd" class="secondaryToolbarButton" title="Join page spreads starting with odd-numbered pages" tabindex="67" data-l10n-id="pdfjs-spread-odd-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-spread-odd-button-label">Odd Spreads</span>
</button>
<button id="spreadEven" class="secondaryToolbarButton" title="Join page spreads starting with even-numbered pages" tabindex="68" data-l10n-id="spread_even" role="radio" aria-checked="false">
<span data-l10n-id="spread_even_label">Even Spreads</span>
<button id="spreadEven" class="secondaryToolbarButton" title="Join page spreads starting with even-numbered pages" tabindex="68" data-l10n-id="pdfjs-spread-even-button" role="radio" aria-checked="false">
<span data-l10n-id="pdfjs-spread-even-button-label">Even Spreads</span>
</button>
</div>
<div class="horizontalToolbarSeparator"></div>
<button id="documentProperties" class="secondaryToolbarButton" title="Document Properties…" tabindex="69" data-l10n-id="document_properties" aria-controls="documentPropertiesDialog">
<span data-l10n-id="document_properties_label">Document Properties…</span>
<button id="documentProperties" class="secondaryToolbarButton" title="Document Properties…" tabindex="69" data-l10n-id="pdfjs-document-properties-button" aria-controls="documentPropertiesDialog">
<span data-l10n-id="pdfjs-document-properties-button-label">Document Properties…</span>
</button>
</div>
</div> <!-- secondaryToolbar -->
@ -304,85 +309,85 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="toolbarContainer">
<div id="toolbarViewer">
<div id="toolbarViewerLeft">
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="11" data-l10n-id="toggle_sidebar" aria-expanded="false" aria-controls="sidebarContainer">
<span data-l10n-id="toggle_sidebar_label">Toggle Sidebar</span>
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="11" data-l10n-id="pdfjs-toggle-sidebar-button" aria-expanded="false" aria-controls="sidebarContainer">
<span data-l10n-id="pdfjs-toggle-sidebar-button-label">Toggle Sidebar</span>
</button>
<div class="toolbarButtonSpacer"></div>
<button id="viewFind" class="toolbarButton" title="Find in Document" tabindex="12" data-l10n-id="findbar" aria-expanded="false" aria-controls="findbar">
<span data-l10n-id="findbar_label">Find</span>
<button id="viewFind" class="toolbarButton" title="Find in Document" tabindex="12" data-l10n-id="pdfjs-findbar-button" aria-expanded="false" aria-controls="findbar">
<span data-l10n-id="pdfjs-findbar-button-label">Find</span>
</button>
<div class="splitToolbarButton hiddenSmallView">
<button class="toolbarButton" title="Previous Page" id="previous" tabindex="13" data-l10n-id="previous">
<span data-l10n-id="previous_label">Previous</span>
<button class="toolbarButton" title="Previous Page" id="previous" tabindex="13" data-l10n-id="pdfjs-previous-button">
<span data-l10n-id="pdfjs-previous-button-label">Previous</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button class="toolbarButton" title="Next Page" id="next" tabindex="14" data-l10n-id="next">
<span data-l10n-id="next_label">Next</span>
<button class="toolbarButton" title="Next Page" id="next" tabindex="14" data-l10n-id="pdfjs-next-button">
<span data-l10n-id="pdfjs-next-button-label">Next</span>
</button>
</div>
<input type="number" id="pageNumber" class="toolbarField" title="Page" value="1" min="1" tabindex="15" data-l10n-id="page" autocomplete="off">
<input type="number" id="pageNumber" class="toolbarField" title="Page" value="1" min="1" tabindex="15" data-l10n-id="pdfjs-page-input" autocomplete="off">
<span id="numPages" class="toolbarLabel"></span>
</div>
<div id="toolbarViewerRight">
<!--#if GENERIC-->
<button id="openFile" class="toolbarButton hiddenLargeView" title="Open File" tabindex="31" data-l10n-id="open_file">
<span data-l10n-id="open_file_label">Open</span>
<button id="openFile" class="toolbarButton hiddenLargeView" title="Open File" tabindex="31" data-l10n-id="pdfjs-open-file-button">
<span data-l10n-id="pdfjs-open-file-button-label">Open</span>
</button>
<!--#endif-->
<button id="print" class="toolbarButton hiddenMediumView" title="Print" tabindex="32" data-l10n-id="print">
<span data-l10n-id="print_label">Print</span>
<button id="print" class="toolbarButton hiddenMediumView" title="Print" tabindex="32" data-l10n-id="pdfjs-print-button">
<span data-l10n-id="pdfjs-print-button-label">Print</span>
</button>
<button id="download" class="toolbarButton hiddenMediumView" title="Save" tabindex="33" data-l10n-id="save">
<span data-l10n-id="save_label">Save</span>
<button id="download" class="toolbarButton hiddenMediumView" title="Save" tabindex="33" data-l10n-id="pdfjs-save-button">
<span data-l10n-id="pdfjs-save-button-label">Save</span>
</button>
<div class="verticalToolbarSeparator hiddenMediumView"></div>
<div id="editorModeButtons" class="splitToolbarButton toggled" role="radiogroup">
<button id="editorFreeText" class="toolbarButton" disabled="disabled" title="Text" role="radio" aria-checked="false" aria-controls="editorFreeTextParamsToolbar" tabindex="34" data-l10n-id="editor_free_text2">
<span data-l10n-id="editor_free_text2_label">Text</span>
<button id="editorFreeText" class="toolbarButton" disabled="disabled" title="Text" role="radio" aria-checked="false" aria-controls="editorFreeTextParamsToolbar" tabindex="34" data-l10n-id="pdfjs-editor-free-text-button">
<span data-l10n-id="pdfjs-editor-free-text-button-label">Text</span>
</button>
<button id="editorInk" class="toolbarButton" disabled="disabled" title="Draw" role="radio" aria-checked="false" aria-controls="editorInkParamsToolbar" tabindex="35" data-l10n-id="editor_ink2">
<span data-l10n-id="editor_ink2_label">Draw</span>
<button id="editorInk" class="toolbarButton" disabled="disabled" title="Draw" role="radio" aria-checked="false" aria-controls="editorInkParamsToolbar" tabindex="35" data-l10n-id="pdfjs-editor-ink-button">
<span data-l10n-id="pdfjs-editor-ink-button-label">Draw</span>
</button>
<button id="editorStamp" class="toolbarButton hidden" disabled="disabled" title="Add or edit images" role="radio" aria-checked="false" aria-controls="editorStampParamsToolbar" tabindex="36" data-l10n-id="editor_stamp1">
<span data-l10n-id="editor_stamp1_label">Add or edit images</span>
<button id="editorStamp" class="toolbarButton hidden" disabled="disabled" title="Add or edit images" role="radio" aria-checked="false" aria-controls="editorStampParamsToolbar" tabindex="36" data-l10n-id="pdfjs-editor-stamp-button">
<span data-l10n-id="pdfjs-editor-stamp-button-label">Add or edit images</span>
</button>
</div>
<div id="editorModeSeparator" class="verticalToolbarSeparator"></div>
<button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="48" data-l10n-id="tools" aria-expanded="false" aria-controls="secondaryToolbar">
<span data-l10n-id="tools_label">Tools</span>
<button id="secondaryToolbarToggle" class="toolbarButton" title="Tools" tabindex="48" data-l10n-id="pdfjs-tools-button" aria-expanded="false" aria-controls="secondaryToolbar">
<span data-l10n-id="pdfjs-tools-button-label">Tools</span>
</button>
</div>
<div id="toolbarViewerMiddle">
<div class="splitToolbarButton">
<button id="zoomOut" class="toolbarButton" title="Zoom Out" tabindex="21" data-l10n-id="zoom_out">
<span data-l10n-id="zoom_out_label">Zoom Out</span>
<button id="zoomOut" class="toolbarButton" title="Zoom Out" tabindex="21" data-l10n-id="pdfjs-zoom-out-button">
<span data-l10n-id="pdfjs-zoom-out-button-label">Zoom Out</span>
</button>
<div class="splitToolbarButtonSeparator"></div>
<button id="zoomIn" class="toolbarButton" title="Zoom In" tabindex="22" data-l10n-id="zoom_in">
<span data-l10n-id="zoom_in_label">Zoom In</span>
<button id="zoomIn" class="toolbarButton" title="Zoom In" tabindex="22" data-l10n-id="pdfjs-zoom-in-button">
<span data-l10n-id="pdfjs-zoom-in-button-label">Zoom In</span>
</button>
</div>
<span id="scaleSelectContainer" class="dropdownToolbarButton">
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="zoom">
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="page_scale_auto">Automatic Zoom</option>
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="page_scale_actual">Actual Size</option>
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="page_scale_fit">Page Fit</option>
<option id="pageWidthOption" title="" value="page-width" data-l10n-id="page_scale_width">Page Width</option>
<select id="scaleSelect" title="Zoom" tabindex="23" data-l10n-id="pdfjs-zoom-select">
<option id="pageAutoOption" title="" value="auto" selected="selected" data-l10n-id="pdfjs-page-scale-auto">Automatic Zoom</option>
<option id="pageActualOption" title="" value="page-actual" data-l10n-id="pdfjs-page-scale-actual">Actual Size</option>
<option id="pageFitOption" title="" value="page-fit" data-l10n-id="pdfjs-page-scale-fit">Page Fit</option>
<option id="pageWidthOption" title="" value="page-width" data-l10n-id="pdfjs-page-scale-width">Page Width</option>
<option id="customScaleOption" title="" value="custom" disabled="disabled" hidden="true"></option>
<option title="" value="0.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 50 }'>50%</option>
<option title="" value="0.75" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 75 }'>75%</option>
<option title="" value="1" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 100 }'>100%</option>
<option title="" value="1.25" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 125 }'>125%</option>
<option title="" value="1.5" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 150 }'>150%</option>
<option title="" value="2" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 200 }'>200%</option>
<option title="" value="3" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 300 }'>300%</option>
<option title="" value="4" data-l10n-id="page_scale_percent" data-l10n-args='{ "scale": 400 }'>400%</option>
<option title="" value="0.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 50 }'>50%</option>
<option title="" value="0.75" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 75 }'>75%</option>
<option title="" value="1" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 100 }'>100%</option>
<option title="" value="1.25" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 125 }'>125%</option>
<option title="" value="1.5" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 150 }'>150%</option>
<option title="" value="2" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 200 }'>200%</option>
<option title="" value="3" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 300 }'>300%</option>
<option title="" value="4" data-l10n-id="pdfjs-page-scale-percent" data-l10n-args='{ "scale": 400 }'>400%</option>
</select>
</span>
</div>
@ -404,85 +409,85 @@ See https://github.com/adobe-type-tools/cmap-resources
<div id="dialogContainer">
<dialog id="passwordDialog">
<div class="row">
<label for="password" id="passwordText" data-l10n-id="password_label">Enter the password to open this PDF file:</label>
<label for="password" id="passwordText" data-l10n-id="pdfjs-password-label">Enter the password to open this PDF file:</label>
</div>
<div class="row">
<input type="password" id="password" class="toolbarField">
</div>
<div class="buttonRow">
<button id="passwordCancel" class="dialogButton"><span data-l10n-id="password_cancel">Cancel</span></button>
<button id="passwordSubmit" class="dialogButton"><span data-l10n-id="password_ok">OK</span></button>
<button id="passwordCancel" class="dialogButton"><span data-l10n-id="pdfjs-password-cancel-button">Cancel</span></button>
<button id="passwordSubmit" class="dialogButton"><span data-l10n-id="pdfjs-password-ok-button">OK</span></button>
</div>
</dialog>
<dialog id="documentPropertiesDialog">
<div class="row">
<span id="fileNameLabel" data-l10n-id="document_properties_file_name">File name:</span>
<span id="fileNameLabel" data-l10n-id="pdfjs-document-properties-file-name">File name:</span>
<p id="fileNameField" aria-labelledby="fileNameLabel">-</p>
</div>
<div class="row">
<span id="fileSizeLabel" data-l10n-id="document_properties_file_size">File size:</span>
<span id="fileSizeLabel" data-l10n-id="pdfjs-document-properties-file-size">File size:</span>
<p id="fileSizeField" aria-labelledby="fileSizeLabel">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span id="titleLabel" data-l10n-id="document_properties_title">Title:</span>
<span id="titleLabel" data-l10n-id="pdfjs-document-properties-title">Title:</span>
<p id="titleField" aria-labelledby="titleLabel">-</p>
</div>
<div class="row">
<span id="authorLabel" data-l10n-id="document_properties_author">Author:</span>
<span id="authorLabel" data-l10n-id="pdfjs-document-properties-author">Author:</span>
<p id="authorField" aria-labelledby="authorLabel">-</p>
</div>
<div class="row">
<span id="subjectLabel" data-l10n-id="document_properties_subject">Subject:</span>
<span id="subjectLabel" data-l10n-id="pdfjs-document-properties-subject">Subject:</span>
<p id="subjectField" aria-labelledby="subjectLabel">-</p>
</div>
<div class="row">
<span id="keywordsLabel" data-l10n-id="document_properties_keywords">Keywords:</span>
<span id="keywordsLabel" data-l10n-id="pdfjs-document-properties-keywords">Keywords:</span>
<p id="keywordsField" aria-labelledby="keywordsLabel">-</p>
</div>
<div class="row">
<span id="creationDateLabel" data-l10n-id="document_properties_creation_date">Creation Date:</span>
<span id="creationDateLabel" data-l10n-id="pdfjs-document-properties-creation-date">Creation Date:</span>
<p id="creationDateField" aria-labelledby="creationDateLabel">-</p>
</div>
<div class="row">
<span id="modificationDateLabel" data-l10n-id="document_properties_modification_date">Modification Date:</span>
<span id="modificationDateLabel" data-l10n-id="pdfjs-document-properties-modification-date">Modification Date:</span>
<p id="modificationDateField" aria-labelledby="modificationDateLabel">-</p>
</div>
<div class="row">
<span id="creatorLabel" data-l10n-id="document_properties_creator">Creator:</span>
<span id="creatorLabel" data-l10n-id="pdfjs-document-properties-creator">Creator:</span>
<p id="creatorField" aria-labelledby="creatorLabel">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span id="producerLabel" data-l10n-id="document_properties_producer">PDF Producer:</span>
<span id="producerLabel" data-l10n-id="pdfjs-document-properties-producer">PDF Producer:</span>
<p id="producerField" aria-labelledby="producerLabel">-</p>
</div>
<div class="row">
<span id="versionLabel" data-l10n-id="document_properties_version">PDF Version:</span>
<span id="versionLabel" data-l10n-id="pdfjs-document-properties-version">PDF Version:</span>
<p id="versionField" aria-labelledby="versionLabel">-</p>
</div>
<div class="row">
<span id="pageCountLabel" data-l10n-id="document_properties_page_count">Page Count:</span>
<span id="pageCountLabel" data-l10n-id="pdfjs-document-properties-page-count">Page Count:</span>
<p id="pageCountField" aria-labelledby="pageCountLabel">-</p>
</div>
<div class="row">
<span id="pageSizeLabel" data-l10n-id="document_properties_page_size">Page Size:</span>
<span id="pageSizeLabel" data-l10n-id="pdfjs-document-properties-page-size">Page Size:</span>
<p id="pageSizeField" aria-labelledby="pageSizeLabel">-</p>
</div>
<div class="separator"></div>
<div class="row">
<span id="linearizedLabel" data-l10n-id="document_properties_linearized">Fast Web View:</span>
<span id="linearizedLabel" data-l10n-id="pdfjs-document-properties-linearized">Fast Web View:</span>
<p id="linearizedField" aria-labelledby="linearizedLabel">-</p>
</div>
<div class="buttonRow">
<button id="documentPropertiesClose" class="dialogButton"><span data-l10n-id="document_properties_close">Close</span></button>
<button id="documentPropertiesClose" class="dialogButton"><span data-l10n-id="pdfjs-document-properties-close-button">Close</span></button>
</div>
</dialog>
<dialog id="altTextDialog" aria-labelledby="dialogLabel" aria-describedby="dialogDescription">
<div id="altTextContainer">
<div id="overallDescription">
<span id="dialogLabel" data-l10n-id="editor_alt_text_dialog_label" class="title">Choose an option</span>
<span id="dialogDescription" data-l10n-id="editor_alt_text_dialog_description">
<span id="dialogLabel" data-l10n-id="pdfjs-editor-alt-text-dialog-label" class="title">Choose an option</span>
<span id="dialogDescription" data-l10n-id="pdfjs-editor-alt-text-dialog-description">
Alt text (alternative text) helps when people cant see the image or when it doesnt load.
</span>
</div>
@ -490,48 +495,48 @@ See https://github.com/adobe-type-tools/cmap-resources
<div class="radio">
<div class="radioButton">
<input type="radio" id="descriptionButton" name="altTextOption" tabindex="0" aria-describedby="descriptionAreaLabel" checked>
<label for="descriptionButton" data-l10n-id="editor_alt_text_add_description_label">Add a description</label>
<label for="descriptionButton" data-l10n-id="pdfjs-editor-alt-text-add-description-label">Add a description</label>
</div>
<div class="radioLabel">
<span id="descriptionAreaLabel" data-l10n-id="editor_alt_text_add_description_description">
<span id="descriptionAreaLabel" data-l10n-id="pdfjs-editor-alt-text-add-description-description">
Aim for 1-2 sentences that describe the subject, setting, or actions.
</span>
</div>
</div>
<div class="descriptionArea">
<textarea id="descriptionTextarea" placeholder="For example, “A young man sits down at a table to eat a meal”" aria-labelledby="descriptionAreaLabel" data-l10n-id="editor_alt_text_textarea" tabindex="0"></textarea>
<textarea id="descriptionTextarea" placeholder="For example, “A young man sits down at a table to eat a meal”" aria-labelledby="descriptionAreaLabel" data-l10n-id="pdfjs-editor-alt-text-textarea" tabindex="0"></textarea>
</div>
</div>
<div id="markAsDecorative">
<div class="radio">
<div class="radioButton">
<input type="radio" id="decorativeButton" name="altTextOption" aria-describedby="decorativeLabel">
<label for="decorativeButton" data-l10n-id="editor_alt_text_mark_decorative_label">Mark as decorative</label>
<label for="decorativeButton" data-l10n-id="pdfjs-editor-alt-text-mark-decorative-label">Mark as decorative</label>
</div>
<div class="radioLabel">
<span id="decorativeLabel" data-l10n-id="editor_alt_text_mark_decorative_description">
<span id="decorativeLabel" data-l10n-id="pdfjs-editor-alt-text-mark-decorative-description">
This is used for ornamental images, like borders or watermarks.
</span>
</div>
</div>
</div>
<div id="buttons">
<button id="altTextCancel" tabindex="0"><span data-l10n-id="editor_alt_text_cancel_button">Cancel</span></button>
<button id="altTextSave" tabindex="0"><span data-l10n-id="editor_alt_text_save_button">Save</span></button>
<button id="altTextCancel" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-cancel-button">Cancel</span></button>
<button id="altTextSave" tabindex="0"><span data-l10n-id="pdfjs-editor-alt-text-save-button">Save</span></button>
</div>
</div>
</dialog>
<!--#if !MOZCENTRAL-->
<dialog id="printServiceDialog" style="min-width: 200px;">
<div class="row">
<span data-l10n-id="print_progress_message">Preparing document for printing…</span>
<span data-l10n-id="pdfjs-print-progress-message">Preparing document for printing…</span>
</div>
<div class="row">
<progress value="0" max="100"></progress>
<span data-l10n-id="print_progress_percent" data-l10n-args='{ "progress": 0 }' class="relative-progress">0%</span>
<span data-l10n-id="pdfjs-print-progress-percent" data-l10n-args='{ "progress": 0 }' class="relative-progress">0%</span>
</div>
<div class="buttonRow">
<button id="printCancel" class="dialogButton"><span data-l10n-id="print_progress_close">Cancel</span></button>
<button id="printCancel" class="dialogButton"><span data-l10n-id="pdfjs-print-progress-close-button">Cancel</span></button>
</div>
</dialog>
<!--#endif-->